diff --git a/src/emulate.c b/src/emulate.c index 83c58d7..94f9254 100755 --- a/src/emulate.c +++ b/src/emulate.c @@ -1,12 +1,14 @@ #include #include #include "emulator/a64instruction/a64instruction.h" +#include "emulator/a64instruction/a64instruction_global.h" #include "emulator/emulator.h" #include "emulator/fileio.h" #include "global.h" #include "emulator/print.h" #include "emulator/decode.h" #include "emulator/execute.h" +#include "emulator/machine_util.h" extern a64inst_instruction *decode(word w); @@ -40,7 +42,7 @@ int main(int argc, char **argv) { do { // 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 inst = decode(wrd); diff --git a/src/emulator/binary_util.c b/src/emulator/binary_util.c new file mode 100644 index 0000000..78bf11d --- /dev/null +++ b/src/emulator/binary_util.c @@ -0,0 +1,57 @@ +/** Binary Util */ +#include +#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; +} diff --git a/src/emulator/binary_util.h b/src/emulator/binary_util.h new file mode 100644 index 0000000..97763a0 --- /dev/null +++ b/src/emulator/binary_util.h @@ -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 diff --git a/src/emulator/decode.c b/src/emulator/decode.c index ce69c35..17970af 100644 --- a/src/emulator/decode.c +++ b/src/emulator/decode.c @@ -1,19 +1,7 @@ -#include #include #include #include "decode.h" -#include "emulator.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; -} +#include "binary_util.h" // Given a binary word, return its internal representation as an a64instruction struct encoding the same // information. diff --git a/src/emulator/execute.c b/src/emulator/execute.c index d5e60a6..e2de20c 100644 --- a/src/emulator/execute.c +++ b/src/emulator/execute.c @@ -2,6 +2,8 @@ #include #include "execute.h" #include "print.h" +#include "binary_util.h" +#include "machine_util.h" // Defines the maximum value that can be held in a register #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 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 static void updateCondNZ(Machine *state, dword result, a64inst_regType regType) { state->conditionCodes.Negative = getMSB(result, regType); @@ -383,12 +315,7 @@ void execute_SDT(Machine *state, a64inst_instruction *inst) { } if (isLoad) { - if (inst->data.SingleTransferData.regType == a64inst_W) { - // 32 bit access - state->registers[inst->data.SingleTransferData.target] = readWord(state->memory, address); - } else { - state->registers[inst->data.SingleTransferData.target] = readDoubleWord(state->memory, address); - } + state->registers[inst->data.SingleTransferData.target] = readMemory(state->memory, address, inst->data.SingleTransferData.regType); // Update base register if post indexed bool isSDT = inst->data.SingleTransferData.SingleTransferOpType == a64inst_SINGLE_TRANSFER_SINGLE_DATA_TRANSFER; diff --git a/src/emulator/machine_util.c b/src/emulator/machine_util.c new file mode 100644 index 0000000..9288c7b --- /dev/null +++ b/src/emulator/machine_util.c @@ -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); + } +} diff --git a/src/emulator/machine_util.h b/src/emulator/machine_util.h new file mode 100644 index 0000000..90688e8 --- /dev/null +++ b/src/emulator/machine_util.h @@ -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 diff --git a/src/emulator/print.c b/src/emulator/print.c index 0ec5210..217535b 100644 --- a/src/emulator/print.c +++ b/src/emulator/print.c @@ -2,7 +2,9 @@ #include #include #include "print.h" +#include "a64instruction/a64instruction_global.h" #include "emulator.h" +#include "machine_util.h" #define UNSET_CONDITION_CODE_CHAR '-' @@ -25,39 +27,13 @@ void printRegisters(Machine *state, FILE *stream) { 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 void printMemory(Machine *state, FILE *stream) { fprintf(stream, "\nNon-zero memory:\n"); // print memory 4 byte aligned 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) { fprintf(stream, "0x%08x: %08x\n", addr, data); } diff --git a/src/emulator/print.h b/src/emulator/print.h index 5a64a4e..35001d9 100644 --- a/src/emulator/print.h +++ b/src/emulator/print.h @@ -3,9 +3,6 @@ #include #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 printRegisters(Machine *state, FILE *stream); void printMemory(Machine *state, FILE *stream);