Split utils into machine_util and binary_util modules
This commit is contained in:
parent
a42576b4ed
commit
c4e3493fdc
@ -1,12 +1,14 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "emulator/a64instruction/a64instruction.h"
|
#include "emulator/a64instruction/a64instruction.h"
|
||||||
|
#include "emulator/a64instruction/a64instruction_global.h"
|
||||||
#include "emulator/emulator.h"
|
#include "emulator/emulator.h"
|
||||||
#include "emulator/fileio.h"
|
#include "emulator/fileio.h"
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "emulator/print.h"
|
#include "emulator/print.h"
|
||||||
#include "emulator/decode.h"
|
#include "emulator/decode.h"
|
||||||
#include "emulator/execute.h"
|
#include "emulator/execute.h"
|
||||||
|
#include "emulator/machine_util.h"
|
||||||
|
|
||||||
extern a64inst_instruction *decode(word w);
|
extern a64inst_instruction *decode(word w);
|
||||||
|
|
||||||
@ -40,7 +42,7 @@ int main(int argc, char **argv) {
|
|||||||
do {
|
do {
|
||||||
|
|
||||||
// Step 1: Fetch instruction at PC's address
|
// Step 1: Fetch instruction at PC's address
|
||||||
wrd = readWord(state.memory, state.pc);
|
wrd = readMemory(state.memory, state.pc, a64inst_W);
|
||||||
|
|
||||||
// Step 2: Decode instruction to internal representation
|
// Step 2: Decode instruction to internal representation
|
||||||
inst = decode(wrd);
|
inst = decode(wrd);
|
||||||
|
|||||||
57
src/emulator/binary_util.c
Normal file
57
src/emulator/binary_util.c
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/** Binary Util */
|
||||||
|
#include <assert.h>
|
||||||
|
#include "binary_util.h"
|
||||||
|
|
||||||
|
word getBits(word wrd, uint8_t lsb, uint8_t msb) {
|
||||||
|
|
||||||
|
// Ensure LSB and MSB are within range of word size, and in the correct order
|
||||||
|
assert(lsb < msb && msb <= WORD_BITS);
|
||||||
|
|
||||||
|
wrd &= ((dword) 1 << msb) - 1;
|
||||||
|
return wrd >> lsb;
|
||||||
|
}
|
||||||
|
|
||||||
|
dword max(dword a, dword b) {
|
||||||
|
return a > b ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
|
dword truncateValue(dword value, a64inst_regType regType) {
|
||||||
|
if (regType == a64inst_X) {
|
||||||
|
return value;
|
||||||
|
} else {
|
||||||
|
return (word)value;
|
||||||
|
//return value & (dword)(((dword)1 << WORD_BITS) - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign extend a given value to a 64-bit signed integer given the number of bits
|
||||||
|
int64_t signExtend(dword value, unsigned int n) {
|
||||||
|
if (n == 0 || n >= 64) {
|
||||||
|
// If n_bits is 0 or greater than or equal to 64, return the value as is
|
||||||
|
return (int64_t)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t sign_bit_mask = (uint64_t)1 << (n - 1);
|
||||||
|
|
||||||
|
// Mask to isolate the n-bit value
|
||||||
|
uint64_t n_bit_mask = (sign_bit_mask << 1) - 1;
|
||||||
|
|
||||||
|
// Check if the sign bit is set
|
||||||
|
if (value & sign_bit_mask) {
|
||||||
|
// Sign bit is set, extend the sign
|
||||||
|
return (int64_t)(value | ~n_bit_mask);
|
||||||
|
} else {
|
||||||
|
// Sign bit is not set, return the value as is
|
||||||
|
return (int64_t)(value & n_bit_mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the position of the MSB of the given register type
|
||||||
|
dword getMSBPos(a64inst_regType regType) {
|
||||||
|
return (regType ? DWORD_BITS : WORD_BITS) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the MSB of the given value assuming it's of the size stored in the given register type
|
||||||
|
uint8_t getMSB(dword value, a64inst_regType regType) {
|
||||||
|
return (value >> getMSBPos(regType)) & 1u;
|
||||||
|
}
|
||||||
20
src/emulator/binary_util.h
Normal file
20
src/emulator/binary_util.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#ifndef __BINARY_UTIL__
|
||||||
|
#define __BINARY_UTIL__
|
||||||
|
|
||||||
|
#include "emulator.h"
|
||||||
|
#include "a64instruction/a64instruction_global.h"
|
||||||
|
|
||||||
|
|
||||||
|
word getBits(word wrd, uint8_t lsb, uint8_t msb);
|
||||||
|
|
||||||
|
dword max(dword a, dword b);
|
||||||
|
|
||||||
|
dword truncateValue(dword value, a64inst_regType regType);
|
||||||
|
|
||||||
|
int64_t signExtend(dword value, unsigned int n);
|
||||||
|
|
||||||
|
dword getMSBPos(a64inst_regType regType);
|
||||||
|
|
||||||
|
uint8_t getMSB(dword value, a64inst_regType regType);
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -1,19 +1,7 @@
|
|||||||
#include <assert.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "decode.h"
|
#include "decode.h"
|
||||||
#include "emulator.h"
|
#include "binary_util.h"
|
||||||
|
|
||||||
// Retrieve the bits between positions 'lsb' (inclusive) and 'msb' (exclusive) from a given word
|
|
||||||
// as a new zero-extended word.
|
|
||||||
static word getBits(word wrd, uint8_t lsb, uint8_t msb) {
|
|
||||||
|
|
||||||
// Ensure LSB and MSB are within range of word size, and in the correct order
|
|
||||||
assert(lsb < msb && msb <= WORD_BITS);
|
|
||||||
|
|
||||||
wrd &= ((dword) 1 << msb) - 1;
|
|
||||||
return wrd >> lsb;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Given a binary word, return its internal representation as an a64instruction struct encoding the same
|
// Given a binary word, return its internal representation as an a64instruction struct encoding the same
|
||||||
// information.
|
// information.
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include "execute.h"
|
#include "execute.h"
|
||||||
#include "print.h"
|
#include "print.h"
|
||||||
|
#include "binary_util.h"
|
||||||
|
#include "machine_util.h"
|
||||||
|
|
||||||
// Defines the maximum value that can be held in a register
|
// Defines the maximum value that can be held in a register
|
||||||
#define MAX_REG_VAL ((1 << DWORD_BITS) - 1)
|
#define MAX_REG_VAL ((1 << DWORD_BITS) - 1)
|
||||||
@ -19,76 +21,6 @@ void execute_SDT(Machine *state, a64inst_instruction *inst);
|
|||||||
void execute_Branch(Machine *state, a64inst_instruction *inst);
|
void execute_Branch(Machine *state, a64inst_instruction *inst);
|
||||||
void executeMultiply(Machine *state, a64inst_instruction *inst);
|
void executeMultiply(Machine *state, a64inst_instruction *inst);
|
||||||
|
|
||||||
// Return maximum of two dwords
|
|
||||||
static dword max(dword a, dword b) {
|
|
||||||
return a > b ? a : b;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Truncate a given value to the size of a word or dword depending on the register type
|
|
||||||
static dword truncateValue(dword value, a64inst_regType regType) {
|
|
||||||
if (regType == a64inst_X) {
|
|
||||||
return value;
|
|
||||||
} else {
|
|
||||||
return (word)value;
|
|
||||||
//return value & (dword)(((dword)1 << WORD_BITS) - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sign extend a given value to a 64-bit signed integer given the number of bits
|
|
||||||
static int64_t signExtend(dword value, unsigned int n) {
|
|
||||||
if (n == 0 || n >= 64) {
|
|
||||||
// If n_bits is 0 or greater than or equal to 64, return the value as is
|
|
||||||
return (int64_t)value;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t sign_bit_mask = (uint64_t)1 << (n - 1);
|
|
||||||
|
|
||||||
// Mask to isolate the n-bit value
|
|
||||||
uint64_t n_bit_mask = (sign_bit_mask << 1) - 1;
|
|
||||||
|
|
||||||
// Check if the sign bit is set
|
|
||||||
if (value & sign_bit_mask) {
|
|
||||||
// Sign bit is set, extend the sign
|
|
||||||
return (int64_t)(value | ~n_bit_mask);
|
|
||||||
} else {
|
|
||||||
// Sign bit is not set, return the value as is
|
|
||||||
return (int64_t)(value & n_bit_mask);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read from processor register, ensuring that a valid register specifier is given
|
|
||||||
// and accounting for the case where the zero register is accessed. Truncate
|
|
||||||
// the 32 most significant bits stored in the R register when reading W register.
|
|
||||||
static dword readRegister(Machine *state, a64inst_regSpecifier reg, a64inst_regType regType) {
|
|
||||||
assert(reg <= REGISTER_COUNT);
|
|
||||||
if (reg == ZERO_REGISTER) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return truncateValue(state->registers[reg], regType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO:
|
|
||||||
|
|
||||||
// Write to a processor register, ensuring that a valid register specifier is given
|
|
||||||
// and truncating the value being written when it can't fit in the specified register
|
|
||||||
static void writeRegister(Machine *state, a64inst_regSpecifier reg, a64inst_regType regType, dword value) {
|
|
||||||
assert(reg <= REGISTER_COUNT);
|
|
||||||
if (reg != ZERO_REGISTER) {
|
|
||||||
state->registers[reg] = truncateValue(value, regType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the position of the MSB of the given register type
|
|
||||||
inline static dword getMSBPos(a64inst_regType regType) {
|
|
||||||
return (regType ? DWORD_BITS : WORD_BITS) - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the MSB of the given value assuming it's of the size stored in the given register type
|
|
||||||
inline static uint8_t getMSB(dword value, a64inst_regType regType) {
|
|
||||||
return (value >> getMSBPos(regType)) & 1u;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Updates N and Z condition codes given the machine and a result value
|
// Updates N and Z condition codes given the machine and a result value
|
||||||
static void updateCondNZ(Machine *state, dword result, a64inst_regType regType) {
|
static void updateCondNZ(Machine *state, dword result, a64inst_regType regType) {
|
||||||
state->conditionCodes.Negative = getMSB(result, regType);
|
state->conditionCodes.Negative = getMSB(result, regType);
|
||||||
@ -383,12 +315,7 @@ void execute_SDT(Machine *state, a64inst_instruction *inst) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isLoad) {
|
if (isLoad) {
|
||||||
if (inst->data.SingleTransferData.regType == a64inst_W) {
|
state->registers[inst->data.SingleTransferData.target] = readMemory(state->memory, address, inst->data.SingleTransferData.regType);
|
||||||
// 32 bit access
|
|
||||||
state->registers[inst->data.SingleTransferData.target] = readWord(state->memory, address);
|
|
||||||
} else {
|
|
||||||
state->registers[inst->data.SingleTransferData.target] = readDoubleWord(state->memory, address);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update base register if post indexed
|
// Update base register if post indexed
|
||||||
bool isSDT = inst->data.SingleTransferData.SingleTransferOpType == a64inst_SINGLE_TRANSFER_SINGLE_DATA_TRANSFER;
|
bool isSDT = inst->data.SingleTransferData.SingleTransferOpType == a64inst_SINGLE_TRANSFER_SINGLE_DATA_TRANSFER;
|
||||||
|
|||||||
50
src/emulator/machine_util.c
Normal file
50
src/emulator/machine_util.c
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/** Machine Util */
|
||||||
|
#include "assert.h"
|
||||||
|
#include "machine_util.h"
|
||||||
|
#include "a64instruction/a64instruction_global.h"
|
||||||
|
#include "../global.h"
|
||||||
|
#include "emulator.h"
|
||||||
|
#include "binary_util.h"
|
||||||
|
|
||||||
|
// Returns the dword starting at address. The value is truncated if regType is a 64-bit register.
|
||||||
|
dword readMemory(byte *memory, uint32_t address, a64inst_regType regType) {
|
||||||
|
dword result = 0;
|
||||||
|
int bytesPerWord = (regType == a64inst_W ? WORD_BITS : DWORD_BITS) / BYTE_BITS - 1;
|
||||||
|
for (int i = 0; i <= bytesPerWord; i++) {
|
||||||
|
if (regType == a64inst_W) {
|
||||||
|
result |= (word) memory[address + i] << (BYTE_BITS * i);
|
||||||
|
} else {
|
||||||
|
result |= (dword) memory[address + i] << (BYTE_BITS * i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store into memory starting at address the given dword.
|
||||||
|
void storeMemory(byte *memory, uint32_t address, dword data) {
|
||||||
|
int bytesPerDword = DWORD_BITS / BYTE_BITS - 1;
|
||||||
|
for (int i = 0; i <= bytesPerDword; i++) {
|
||||||
|
memory[address + i] = (byte)((data >> (BYTE_BITS * i)) & 0xFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read from processor register, ensuring that a valid register specifier is given
|
||||||
|
// and accounting for the case where the zero register is accessed. Truncate
|
||||||
|
// the 32 most significant bits stored in the R register when reading W register.
|
||||||
|
dword readRegister(Machine *state, a64inst_regSpecifier reg, a64inst_regType regType) {
|
||||||
|
assert(reg <= REGISTER_COUNT);
|
||||||
|
if (reg == ZERO_REGISTER) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return truncateValue(state->registers[reg], regType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write to a processor register, ensuring that a valid register specifier is given
|
||||||
|
// and truncating the value being written when it can't fit in the specified register
|
||||||
|
void writeRegister(Machine *state, a64inst_regSpecifier reg, a64inst_regType regType, dword value) {
|
||||||
|
assert(reg <= REGISTER_COUNT);
|
||||||
|
if (reg != ZERO_REGISTER) {
|
||||||
|
state->registers[reg] = truncateValue(value, regType);
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/emulator/machine_util.h
Normal file
16
src/emulator/machine_util.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#ifndef __MACHINE_UTIL__
|
||||||
|
#define __MACHINE_UTIL__
|
||||||
|
#include "../global.h"
|
||||||
|
#include "a64instruction/a64instruction_global.h"
|
||||||
|
#include "emulator.h"
|
||||||
|
|
||||||
|
|
||||||
|
dword readMemory(byte *memory, uint32_t address, a64inst_regType regType);
|
||||||
|
|
||||||
|
void storeMemory(byte *memory, uint32_t address, dword data);
|
||||||
|
|
||||||
|
dword readRegister(Machine *state, a64inst_regSpecifier reg, a64inst_regType regType);
|
||||||
|
|
||||||
|
void writeRegister(Machine *state, a64inst_regSpecifier reg, a64inst_regType regType, dword value);
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -2,7 +2,9 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include "print.h"
|
#include "print.h"
|
||||||
|
#include "a64instruction/a64instruction_global.h"
|
||||||
#include "emulator.h"
|
#include "emulator.h"
|
||||||
|
#include "machine_util.h"
|
||||||
|
|
||||||
#define UNSET_CONDITION_CODE_CHAR '-'
|
#define UNSET_CONDITION_CODE_CHAR '-'
|
||||||
|
|
||||||
@ -25,39 +27,13 @@ void printRegisters(Machine *state, FILE *stream) {
|
|||||||
state->conditionCodes.Overflow ? 'V' : UNSET_CONDITION_CODE_CHAR);
|
state->conditionCodes.Overflow ? 'V' : UNSET_CONDITION_CODE_CHAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the word starting at the provided address
|
|
||||||
word readWord(byte *memory, uint32_t address) {
|
|
||||||
word result = 0;
|
|
||||||
int bytesPerWord = WORD_BITS / BYTE_BITS - 1;
|
|
||||||
for (int i = 0; i <= bytesPerWord; i++)
|
|
||||||
result |= (word) memory[address + i] << (BYTE_BITS * i);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the double word starting at the provided address
|
|
||||||
dword readDoubleWord(byte *memory, uint32_t address) {
|
|
||||||
dword result = 0;
|
|
||||||
int bytesPerDword = DWORD_BITS / BYTE_BITS - 1;
|
|
||||||
for (int i = 0; i <= bytesPerDword; i++)
|
|
||||||
result |= (dword) memory[address + i] << (BYTE_BITS * i);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store into memory starting at address the given dword.
|
|
||||||
void storeMemory(byte *memory, uint32_t address, dword data) {
|
|
||||||
int bytesPerDword = DWORD_BITS / BYTE_BITS - 1;
|
|
||||||
for (int i = 0; i <= bytesPerDword; i++) {
|
|
||||||
memory[address + i] = (byte)((data >> (BYTE_BITS * i)) & 0xFF);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prints all non-zero memory locations into the provided stream
|
// Prints all non-zero memory locations into the provided stream
|
||||||
void printMemory(Machine *state, FILE *stream) {
|
void printMemory(Machine *state, FILE *stream) {
|
||||||
fprintf(stream, "\nNon-zero memory:\n");
|
fprintf(stream, "\nNon-zero memory:\n");
|
||||||
|
|
||||||
// print memory 4 byte aligned
|
// print memory 4 byte aligned
|
||||||
for (int addr = 0; addr < MEMORY_SIZE; addr+= 4) {
|
for (int addr = 0; addr < MEMORY_SIZE; addr+= 4) {
|
||||||
word data = readWord(state->memory, addr);
|
word data = readMemory(state->memory, addr, a64inst_W);
|
||||||
if (data != 0) {
|
if (data != 0) {
|
||||||
fprintf(stream, "0x%08x: %08x\n", addr, data);
|
fprintf(stream, "0x%08x: %08x\n", addr, data);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,9 +3,6 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "emulator.h"
|
#include "emulator.h"
|
||||||
|
|
||||||
word readWord(byte *memory, uint32_t address);
|
|
||||||
dword readDoubleWord(byte *memory, uint32_t address);
|
|
||||||
void storeMemory(byte *memory, uint32_t address, dword data);
|
|
||||||
void printState(Machine *state, FILE *stream);
|
void printState(Machine *state, FILE *stream);
|
||||||
void printRegisters(Machine *state, FILE *stream);
|
void printRegisters(Machine *state, FILE *stream);
|
||||||
void printMemory(Machine *state, FILE *stream);
|
void printMemory(Machine *state, FILE *stream);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user