diff --git a/src/Makefile b/src/Makefile index 2fe219c..071143f 100755 --- a/src/Makefile +++ b/src/Makefile @@ -7,7 +7,7 @@ CFLAGS ?= -std=c17 -g\ .PHONY: all clean -all: assemble emulate +all: assemble assemble: assemble.o parser.o fileio.o emulate: emulate.o diff --git a/src/assemble.c b/src/assemble.c index 42302b3..c6b19fd 100644 --- a/src/assemble.c +++ b/src/assemble.c @@ -6,6 +6,8 @@ #include "parser.h" #include "encode.c" +static symbol_table *firstPass(a64inst_instruction *instructions, int lineCount); + int main(int argc, char **argv) { // Check the arguments if (argc < 3) { @@ -21,7 +23,7 @@ int main(int argc, char **argv) { a64inst_instruction *instructions = parse(source, lineCount); // First Pass: Create the symbol table - st *table = firstPass(instructions, lineCount); + symbol_table *table = firstPass(instructions, lineCount); // Second Pass: Encode the instructions into binary word *binary = encode(instructions, lineCount, table); @@ -33,3 +35,17 @@ int main(int argc, char **argv) { return EXIT_SUCCESS; } + +static symbol_table *firstPass(a64inst_instruction *instructions, int lineCount) { + symbol_table *table = st_init(); + int labelCount = 0; + + for (int i = 0; i < lineCount; i++) { + a64inst_instruction inst = instructions[i]; + if (inst.type == a64inst_LABEL) { + st_insert(table, inst.data.LabelData.label, 4 * (i - (labelCount++))); + } + } + + return table; +} diff --git a/src/decode.c b/src/decode.c deleted file mode 100644 index ce69c35..0000000 --- a/src/decode.c +++ /dev/null @@ -1,169 +0,0 @@ -#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; -} - -// Given a binary word, return its internal representation as an a64instruction struct encoding the same -// information. -a64inst_instruction *decode(word wrd) { - - a64inst_instruction *inst = malloc(sizeof(a64inst_instruction)); - if (inst == NULL) { - fprintf(stderr, "Ran out of memory while attempting to decode an instruction!\n"); - exit(1); - } - - word typeId = getBits(wrd, TYPE_ID_LSB, TYPE_ID_MSB); - // Halt interpretation - if (wrd == HALT_WORD) { - inst->type = a64inst_HALT; - - // Data Processing Immediate interpretation - } else if (typeId == DP_IMM_ID) { - inst->type = a64inst_DPIMMEDIATE; - inst->data.DPImmediateData.regType = getBits(wrd, DP_WIDTH_LSB, DP_WIDTH_MSB); - inst->data.DPImmediateData.processOp = getBits(wrd, DP_OP_LSB, DP_OP_MSB); - inst->data.DPImmediateData.dest = getBits(wrd, DP_DEST_LSB, DP_DEST_MSB); - - switch(getBits(wrd, DP_IMM_OPTYPE_LSB, DP_IMM_OPTYPE_MSB)) { - - case DP_IMM_OPTYPE_ARITHM: - inst->data.DPImmediateData.DPIOpType = a64inst_DPI_ARITHM; - inst->data.DPImmediateData.processOpData.arithmData.shiftImmediate = getBits(wrd, DP_IMM_ARITHM_SHIFTFLAG_LSB, DP_IMM_ARITHM_SHIFTFLAG_MSB); - inst->data.DPImmediateData.processOpData.arithmData.immediate = getBits(wrd, DP_IMM_ARITHM_IMMVAL_LSB, DP_IMM_ARITHM_IMMVAL_MSB); - inst->data.DPImmediateData.processOpData.arithmData.src = getBits(wrd, DP_IMM_ARITHM_DEST_LSB, DP_IMM_ARITHM_DEST_MSB); - break; - - case DP_IMM_OPTYPE_WIDEMOV: - inst->data.DPImmediateData.DPIOpType = a64inst_DPI_WIDEMOV; - inst->data.DPImmediateData.processOpData.wideMovData.shiftScalar = getBits(wrd, DP_IMM_WIDEMOV_SHIFTSCALAR_LSB, DP_IMM_WIDEMOV_SHIFTSCALAR_MSB); - inst->data.DPImmediateData.processOpData.wideMovData.immediate = getBits(wrd, DP_IMM_WIDEMOV_IMMVAL_LSB, DP_IMM_WIDEMOV_IMMVAL_MSB); - break; - - default: - fprintf(stderr, "Unknown immediate data processing operation type found!\n"); - exit(1); - break; - } - - } else if (typeId == BRANCH_ID) { - inst->type = a64inst_BRANCH; - word branchTypeFlag = getBits(wrd, BRANCH_TYPE_LSB, BRANCH_TYPE_MSB); - - inst->data.BranchData.BranchType = branchTypeFlag; - - switch (branchTypeFlag) { - case a64inst_UNCONDITIONAL: - inst->data.BranchData.processOpData.unconditionalData.unconditionalOffset = getBits(wrd, BRANCH_UNCONDITIONAL_OFFSET_LSB, BRANCH_UNCONDITIONAL_OFFSET_MSB); - break; - - case a64inst_CONDITIONAL: - inst->data.BranchData.processOpData.conditionalData.offset = getBits(wrd, BRANCH_CONDITIONAL_OFFSET_LSB, BRANCH_CONDITIONAL_OFFSET_MSB); - - word conditionFlag = getBits(wrd, BRANCH_CONDITIONAL_COND_LSB, BRANCH_CONDITIONAL_COND_MSB); - - if(conditionFlag <= 1 || (conditionFlag >= 10 && conditionFlag <= 14)) { - inst->data.BranchData.processOpData.conditionalData.cond = conditionFlag; - } else { - fprintf(stderr, "Unknown condition detected!\n"); - exit(1); - } - - break; - - case a64inst_REGISTER: - inst->data.BranchData.processOpData.registerData.src = getBits(wrd, BRANCH_REGISTER_SRC_LSB, BRANCH_REGISTER_SRC_MSB); - break; - - default: - fprintf(stderr, "Undefined branch type detected!\n"); - exit(1); - break; - } - - // TODO: Some minor code duplication between DPR and DPI data interpretation - // Data Processing Register interpretation - } else if (getBits(wrd, DP_REG_LSB, DP_REG_MSB) == 1) { - inst->type = a64inst_DPREGISTER; - inst->data.DPRegisterData.regType = getBits(wrd, DP_WIDTH_LSB, DP_WIDTH_MSB); - inst->data.DPRegisterData.processOp = getBits(wrd, DP_OP_LSB, DP_OP_MSB); - inst->data.DPRegisterData.dest = getBits(wrd, DP_DEST_LSB, DP_DEST_MSB); - inst->data.DPRegisterData.src1 = getBits(wrd, DP_REG_SRC1_LSB, DP_REG_SRC1_MSB); - inst->data.DPRegisterData.src2 = getBits(wrd, DP_REG_SRC2_LSB, DP_REG_SRC2_MSB); - inst->data.DPRegisterData.DPROpType = getBits(wrd, DP_REG_OPTYPE_LSB, DP_REG_OPTYPE_MSB); - - a64inst_DPRegister_ArithmLogicData *arithmLogicData = &inst->data.DPRegisterData.processOpData.arithmLogicData; - - arithmLogicData->type = getBits(wrd, DP_REG_ARITHMLOGIC_ARITHMFLAG_LSB, DP_REG_ARITHMLOGIC_ARITHMFLAG_MSB); - arithmLogicData->shiftType = getBits(wrd, DP_REG_ARITHMLOGIC_SHIFTTYPE_LSB, DP_REG_ARITHMLOGIC_SHIFTTYPE_MSB); - arithmLogicData->negShiftedSrc2 = getBits(wrd, DP_REG_ARITHMLOGIC_NEGSRC2FLAG_LSB, DP_REG_ARITHMLOGIC_NEGSRC2FLAG_MSB); - - switch(inst->data.DPRegisterData.DPROpType) { - - case a64inst_DPR_ARITHMLOGIC: - if (arithmLogicData->type == a64inst_DPR_ARITHM && (arithmLogicData->negShiftedSrc2 || arithmLogicData->shiftType == a64inst_ROR)) { - fprintf(stderr, "Attempting to decode arithmetic DPR instruction with invalid format!\n"); - } - arithmLogicData->shiftAmount = getBits(wrd, DP_REG_ARITHMLOGIC_SHIFTAMOUNT_LSB, DP_REG_ARITHMLOGIC_SHIFTAMOUNT_MSB); - break; - - case a64inst_DPR_MULTIPLY:; - if (!(inst->data.DPRegisterData.processOp == DP_REG_MULTIPLY_PROCESSOP && - arithmLogicData->type == DP_REG_MULTIPLY_ARITHMFLAG && - arithmLogicData->shiftType == DP_REG_MULTIPLY_SHIFTTYPE && - arithmLogicData->negShiftedSrc2 == DP_REG_MULTIPLY_NEGSRC2FLAG)) { - fprintf(stderr, "Attempting to decode multiply DPR instruction with invalid format!\n"); - } - inst->data.DPRegisterData.processOpData.multiplydata.summand = getBits(wrd, DP_REG_MULTIPLY_SUMMAND_LSB, DP_REG_MULTIPLY_SUMMAND_MSB); - inst->data.DPRegisterData.processOpData.multiplydata.negProd = getBits(wrd, DP_REG_MULTIPLY_NEGPROD_LSB, DP_REG_MULTIPLY_NEGPROD_MSB); - break; - } - - } else { - // Load and Store, or unknown - // Ignore unknown for now - inst->type = a64inst_SINGLETRANSFER; - inst->data.SingleTransferData.regType = getBits(wrd, SDT_REGTYPE_FLAG_LSB, SDT_REGTYPE_FLAG_MSB); - inst->data.SingleTransferData.target = getBits(wrd, SDT_TARGET_REG_LSB, SDT_TARGET_REG_MSB); - - // TODO: Assert that the instruction is a Single Transfer indeed. - - if(getBits(wrd, SDT_OPTYPE_FLAG_LSB, SDT_OPTYPE_FLAG_MSB) == a64inst_SINGLE_TRANSFER_SINGLE_DATA_TRANSFER) { - // Single Data Transfer - inst->data.SingleTransferData.SingleTransferOpType = a64inst_SINGLE_TRANSFER_SINGLE_DATA_TRANSFER; - inst->data.SingleTransferData.processOpData.singleDataTransferData.transferType = getBits(wrd, SDT_TRANSFER_TYPE_LSB, SDT_TRANSFER_TYPE_MSB); - inst->data.SingleTransferData.processOpData.singleDataTransferData.base = getBits(wrd, SDT_BASE_REG_LSB, SDT_BASE_REG_MSB); - if (getBits(wrd, SDT_UNSIGNED_FLAG_LSB, SDT_UNSIGNED_FLAG_MSB) == 1) { - // Unsigned offset - inst->data.SingleTransferData.processOpData.singleDataTransferData.addressingMode = a64inst_UNSIGNED_OFFSET; - inst->data.SingleTransferData.processOpData.singleDataTransferData.a64inst_addressingModeData.unsignedOffset = getBits(wrd, SDT_OFFSET_LSB, SDT_OFFSET_MSB); - } else if (getBits(wrd, SDT_REGISTER_FLAG_LSB, SDT_REGISTER_FLAG_MSB) == 1) { - // Register Offset - inst->data.SingleTransferData.processOpData.singleDataTransferData.addressingMode = a64inst_REGISTER_OFFSET; - inst->data.SingleTransferData.processOpData.singleDataTransferData.a64inst_addressingModeData.offsetReg = getBits(wrd, SDT_REGISTER_REG_LSB, SDT_REGISTER_REG_MSB); - } else { - // Pre-Indexed or Post-Indexed - inst->data.SingleTransferData.processOpData.singleDataTransferData.addressingMode = getBits(wrd, SDT_INDEXED_ADDRMODE_LSB, SDT_INDEXED_ADDRMODE_MSB); - inst->data.SingleTransferData.processOpData.singleDataTransferData.a64inst_addressingModeData.indexedOffset = getBits(wrd, SDT_INDEXED_OFFSET_LSB, SDT_INDEXED_OFFSET_MSB); - } - } else { - // Load Literal - inst->data.SingleTransferData.SingleTransferOpType = a64inst_SINGLE_TRANSFER_LOAD_LITERAL; - inst->data.SingleTransferData.processOpData.loadLiteralData.offset = getBits(wrd, SDT_LOAD_LITERAL_OFFSET_LSB, SDT_LOAD_LITERAL_OFFSET_MSB); - } - } - - return inst; -} diff --git a/src/decode.h b/src/decode.h deleted file mode 100644 index d509ae1..0000000 --- a/src/decode.h +++ /dev/null @@ -1,96 +0,0 @@ -#include "global.h" -#include "a64instruction/a64instruction.h" - -#define HALT_WORD 0x8a000000 - -#define TYPE_ID_LSB 26 -#define TYPE_ID_MSB 29 -#define DP_IMM_ID 4 -#define BRANCH_ID 5 - -#define DP_REG_LSB 25 -#define DP_REG_MSB 26 - -#define DP_WIDTH_LSB 31 -#define DP_WIDTH_MSB 32 -#define DP_OP_LSB 29 -#define DP_OP_MSB 31 -#define DP_DEST_LSB 0 -#define DP_DEST_MSB 5 - -#define DP_IMM_OPTYPE_LSB 23 -#define DP_IMM_OPTYPE_MSB 26 -#define DP_IMM_OPTYPE_ARITHM 2 -#define DP_IMM_OPTYPE_WIDEMOV 5 -#define DP_IMM_ARITHM_SHIFTFLAG_LSB 22 -#define DP_IMM_ARITHM_SHIFTFLAG_MSB 23 -#define DP_IMM_ARITHM_IMMVAL_LSB 10 -#define DP_IMM_ARITHM_IMMVAL_MSB 22 -#define DP_IMM_ARITHM_DEST_LSB 5 -#define DP_IMM_ARITHM_DEST_MSB 10 -#define DP_IMM_WIDEMOV_SHIFTSCALAR_LSB 21 -#define DP_IMM_WIDEMOV_SHIFTSCALAR_MSB 23 -#define DP_IMM_WIDEMOV_IMMVAL_LSB 5 -#define DP_IMM_WIDEMOV_IMMVAL_MSB 21 - -#define DP_REG_SRC1_LSB 5 -#define DP_REG_SRC1_MSB 10 -#define DP_REG_SRC2_LSB 16 -#define DP_REG_SRC2_MSB 21 -#define DP_REG_OPTYPE_LSB 28 -#define DP_REG_OPTYPE_MSB 29 -#define DP_REG_ARITHMLOGIC_ARITHMFLAG_LSB 24 -#define DP_REG_ARITHMLOGIC_ARITHMFLAG_MSB 25 -#define DP_REG_ARITHMLOGIC_SHIFTTYPE_LSB 22 -#define DP_REG_ARITHMLOGIC_SHIFTTYPE_MSB 24 -#define DP_REG_ARITHMLOGIC_NEGSRC2FLAG_LSB 21 -#define DP_REG_ARITHMLOGIC_NEGSRC2FLAG_MSB 22 -#define DP_REG_ARITHMLOGIC_SHIFTAMOUNT_LSB 10 -#define DP_REG_ARITHMLOGIC_SHIFTAMOUNT_MSB 16 -#define DP_REG_MULTIPLY_SUMMAND_LSB 10 -#define DP_REG_MULTIPLY_SUMMAND_MSB 15 -#define DP_REG_MULTIPLY_NEGPROD_LSB 15 -#define DP_REG_MULTIPLY_NEGPROD_MSB 16 -// Defines the values for fields used for arithmetic/logic DPR instructions -// that are necessary to indicate a multiplication instruction -#define DP_REG_MULTIPLY_PROCESSOP 0 -#define DP_REG_MULTIPLY_ARITHMFLAG 1 -#define DP_REG_MULTIPLY_SHIFTTYPE 0 -#define DP_REG_MULTIPLY_NEGSRC2FLAG 0 - -#define SDT_OPTYPE_FLAG_LSB 31 -#define SDT_OPTYPE_FLAG_MSB 32 -#define SDT_REGTYPE_FLAG_LSB 30 -#define SDT_REGTYPE_FLAG_MSB 31 -#define SDT_TARGET_REG_LSB 0 -#define SDT_TARGET_REG_MSB 5 - -#define SDT_BASE_REG_LSB 5 -#define SDT_BASE_REG_MSB 10 -#define SDT_OFFSET_LSB 10 -#define SDT_OFFSET_MSB 22 -#define SDT_TRANSFER_TYPE_LSB 22 -#define SDT_TRANSFER_TYPE_MSB 23 -#define SDT_UNSIGNED_FLAG_LSB 24 -#define SDT_UNSIGNED_FLAG_MSB 25 -#define SDT_REGISTER_FLAG_LSB 21 -#define SDT_REGISTER_FLAG_MSB 22 -#define SDT_REGISTER_REG_LSB 16 -#define SDT_REGISTER_REG_MSB 21 -#define SDT_INDEXED_ADDRMODE_LSB 11 -#define SDT_INDEXED_ADDRMODE_MSB 12 -#define SDT_INDEXED_OFFSET_LSB 12 -#define SDT_INDEXED_OFFSET_MSB 21 -#define SDT_LOAD_LITERAL_OFFSET_LSB 5 -#define SDT_LOAD_LITERAL_OFFSET_MSB 24 - -#define BRANCH_TYPE_LSB 30 -#define BRANCH_TYPE_MSB 32 -#define BRANCH_UNCONDITIONAL_OFFSET_LSB 0 -#define BRANCH_UNCONDITIONAL_OFFSET_MSB 26 -#define BRANCH_REGISTER_SRC_LSB 5 -#define BRANCH_REGISTER_SRC_MSB 10 -#define BRANCH_CONDITIONAL_COND_LSB 0 -#define BRANCH_CONDITIONAL_COND_MSB 4 -#define BRANCH_CONDITIONAL_OFFSET_LSB 5 -#define BRANCH_CONDITIONAL_OFFSET_MSB 24 diff --git a/src/emulate.c b/src/emulate.c deleted file mode 100644 index 4c7f42e..0000000 --- a/src/emulate.c +++ /dev/null @@ -1,67 +0,0 @@ -#include -#include -#include "a64instruction/a64instruction.h" -#include "emulator.h" -#include "fileio.h" -#include "global.h" -#include "print.h" -#include "decode.h" -#include "execute.h" - -int main(int arg, char **argv){ - return EXIT_SUCCESS; -} - -/* -extern a64inst_instruction *decode(word w); - -int main(int argc, char **argv) { - - // Check the arguments - if (argc == 1) { - fprintf(stderr, "Error: An object file is required. Syntax: ./emulate []"); - return EXIT_FAILURE; - } - - FILE *out = stdout; - if (argc > 2) { - out = fopen(argv[2], "w"); - if (out == NULL) { - fprintf(stderr, "Error: Could not open file %s\n", argv[2]); - return EXIT_FAILURE; - } - } - - // Initialising the machine state - Machine state = {0}; - state.memory = fileio_loadBin(argv[1], MEMORY_SIZE); - state.conditionCodes = (PState){0, 1, 0, 0}; - state.pc = 0x0; - - - // Fetch-decode-execute cycle - word wrd; - a64inst_instruction *inst; - do { - - // Step 1: Fetch instruction at PC's address - wrd = readWord(state.memory, state.pc); - - // Step 2: Decode instruction to internal representation - inst = decode(wrd); - - // Step 3: Update processor state to reflect executing the instruction, and increment PC - execute(&state, inst); - - if (inst->type != a64inst_BRANCH) - state.pc += sizeof(word); - } while (inst->type != a64inst_HALT); - - state.pc -= sizeof(word); - - printState(&state, out); - free(state.memory); - - return EXIT_SUCCESS; -} -*/ diff --git a/src/emulator.h b/src/emulator.h deleted file mode 100644 index facbfd7..0000000 --- a/src/emulator.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef __EMULATOR__ -#define __EMULATOR__ -#include "global.h" -#include - -/************************************ - * DEFINITIONS - ************************************/ - -#define BYTE_BITS 8 -#define WORD_BITS (BYTE_BITS * sizeof(word)) -#define DWORD_BITS (BYTE_BITS * sizeof(dword)) - -/************************************ - * STRUCTS - ************************************/ - -typedef struct { - bool Negative; - bool Zero; - bool Carry; - bool Overflow; -} PState; - -typedef struct { - dword registers[REGISTER_COUNT]; - dword pc; - byte *memory; - PState conditionCodes; -} Machine; - -#endif diff --git a/src/encode.c b/src/encode.c index 22173dc..847585c 100644 --- a/src/encode.c +++ b/src/encode.c @@ -3,7 +3,6 @@ #include "a64instruction/a64instruction.h" #include "symboltable.c" #include -#include #define HALT_BINARY 2315255808 @@ -26,21 +25,19 @@ void setBits(word* wrd, uint8_t lsb, uint8_t msb, word value) { *wrd |= (value << lsb) & mask; } -int calculateLabelOffset(char *label, int wordArrIndex, symboltable *st){ - int labelAddress = st.get(label); - int currInstrAddr = wordArrIndex * 4; - int totalOffset = labelAddress - currInstrAddr; - return totalOffset; +static int getLabelOffset(symbol_table* table, char* label, int currentIndex) { + address target = st_get(table, label); + return target - (currentIndex * 4); } // Generates assembled code based on the two-pass assembly method -word encodeBranch(a64inst_instruction *instr, int wordArrIndex) { +word encodeBranch(a64inst_instruction *instr) { word wrd = 0; switch (instr->data.BranchData.BranchType) { case a64inst_UNCONDITIONAL: setBits(&wrd, 26, 30, 0x5); - setBits(&wrd, 25, 0, instr->data.BranchData.processOpData.unconditionalData.unconditionalOffset); + setBits(&wrd, 0, 25, instr->data.BranchData.processOpData.unconditionalData.unconditionalOffset); break; case a64inst_REGISTER: @@ -58,20 +55,6 @@ word encodeBranch(a64inst_instruction *instr, int wordArrIndex) { return wrd; } -st* firstPass(a64inst_instruction instrs[], int numInstrs) { - // TODO: - // -iterate over instructions, adding to symbol table - // create symbol table and map labels to addresses/lines - st *table = (st*)malloc(sizeof(st)); - for (int i = 0; i < numInstrs; i++) { - // discuss defining a LABEL type - if (instrs[i].type == a64inst_LABEL) { - st_add(*table, &(instrs[i].data.LabelData.label), &i); - } - } - return table; -} - word encodeDPImmediate(a64inst_instruction inst) { word wrd = 0; @@ -182,11 +165,7 @@ word encodeLoadLiteral(a64inst_instruction cI) { return wrd; } -word *encode(a64inst_instruction insts[], int instCount, st* table) { - // TODO: - // iterate over instructions again, this time replacing labels - // with values from symbol table - // after a line has had all the values replaced, assemble it and append +word *encode(a64inst_instruction insts[], int instCount, symbol_table* table) { word *arr = (word*)malloc(sizeof(word) * instCount); int index = 0; for (int i = 0; i < instCount; i++) { @@ -220,7 +199,7 @@ word *encode(a64inst_instruction insts[], int instCount, st* table) { // Labels are handled in the first pass and used for addressing. break; case a64inst_BRANCH: - arr[index] = encodeBranch(&inst, index); + arr[index] = encodeBranch(&inst); index++; default: break; diff --git a/src/execute.h b/src/execute.h deleted file mode 100644 index 8b691e6..0000000 --- a/src/execute.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __EXECUTE__ -#define __EXECUTE__ -#include "a64instruction/a64instruction.h" -#include "emulator.h" - -void execute(Machine *state, a64inst_instruction *inst); -#endif diff --git a/src/print.c b/src/print.c deleted file mode 100644 index 1d1d4a2..0000000 --- a/src/print.c +++ /dev/null @@ -1,58 +0,0 @@ -#include -#include -#include -#include -#include "print.h" -#include "emulator.h" - -#define UNSET_CONDITION_CODE_CHAR '-' - -// Prints the current machine state into the provided stream -void printState(Machine *state, FILE *stream) { - printRegisters(state, stream); - printMemory(state, stream); -} - -// Prints the current machine registers into the provided stream -void printRegisters(Machine *state, FILE *stream) { - fprintf(stream, "Registers:\n"); - for (int i = 0; i < REGISTER_COUNT; i++) { - fprintf(stream, "X%02d\t= %016" PRIx64 "\n", i, state->registers[i]); - } - fprintf(stream, "PC\t= %016" PRIx64 "\n", state->pc); - fprintf(stream, "PSTATE\t: %c%c%c%c", state->conditionCodes.Negative ? 'N' : UNSET_CONDITION_CODE_CHAR, - state->conditionCodes.Zero ? 'Z' : UNSET_CONDITION_CODE_CHAR, - state->conditionCodes.Carry ? 'C' : 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; -} - -// 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); - if (data != 0) { - fprintf(stream, "0x%08x: %08x\n", addr, data); - } - } -} diff --git a/src/print.h b/src/print.h deleted file mode 100644 index 404e947..0000000 --- a/src/print.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __PRINT__ -#define __PRINT__ -#include -#include "emulator.h" - -word readWord(byte *memory, uint32_t address); -dword readDoubleWord(byte *memory, uint32_t address); -void printState(Machine *state, FILE *stream); -void printRegisters(Machine *state, FILE *stream); -void printMemory(Machine *state, FILE *stream); - -#endif diff --git a/src/symboltable.c b/src/symboltable.c index a4c99e1..e93c84a 100644 --- a/src/symboltable.c +++ b/src/symboltable.c @@ -1,48 +1,74 @@ #include +#include +#include +#include "symboltable.h" -typedef struct st st; -typedef struct node node; // forward declaration - -typedef struct node { - const void* key; - void* value; - node* prev; - node* next; -} node; - -struct st { - node* head; - node* tail; -}; - -// add new node to the end -void st_add(st table, void* key, void* value) { - node n = {key, value, table.tail}; - if (table.head == NULL) { - table.head = &n; - table.tail = &n; +symbol_table *st_init(void) { + symbol_table *st = malloc(sizeof(symbol_table)); + if (st == NULL) { + fprintf(stderr, "Failed to allocate memory for symbol table\n"); + exit(EXIT_FAILURE); } - else { - (*(table.tail)).next = &n; - table.tail = &n; - } + + st->table = malloc(INITIAL_CAPACITY * sizeof(symbol_table_map)); + if (st->table == NULL) { + fprintf(stderr, "Failed to allocate memory for table\n"); + exit(EXIT_FAILURE); + } + + st->size = 0; + st->capacity = INITIAL_CAPACITY; + + return st; } -void* nodeSearch(node* n, void* key) { - if (n != NULL) { - if ((*n).key == key) { - return (*n).value; - } - else { - return nodeSearch((*n).next, key); +/* Grows the symbol table by a factor of GROWTH_FACTOR *only if the table is full*. + */ +static void grow(symbol_table *st) { + if (st->size == st->capacity) { + st->capacity *= GROWTH_FACTOR; + st->table = realloc(st->table, st->capacity * sizeof(symbol_table_map)); + if (st->table == NULL) { + fprintf(stderr, "Failed to reallocate memory for table\n"); + exit(EXIT_FAILURE); } } - else { - return NULL; - } } -// returns the pointer to key of the specified node, or null, if it does not exist -void* st_search(st table, void* key) { - return nodeSearch(table.head, key); +void st_insert(symbol_table *st, char *label, address addr) { + // If full, grow the table + grow(st); + + // Insert the new entry to the end of the table + symbol_table_map *entry = &st->table[st->size]; + entry->label = label; + entry->address = addr; + + st->size++; +} + +bool st_contains(symbol_table *st, char *label) { + for (int i = 0; i < st->size; i++) { + if (strcmp(st->table[i].label, label) == 0) { + return true; + } + } + + return false; +} + +address st_get(symbol_table *st, char *label) { + for (int i = 0; i < st->size; i++) { + if (strcmp(st->table[i].label, label) == 0) { + return st->table[i].address; + } + } + + fprintf(stderr, "Label %s not found in symbol table\n", label); + exit(EXIT_FAILURE); +} + +void st_free(symbol_table *st) { + free(st->table); + free(st); } diff --git a/src/symboltable.h b/src/symboltable.h new file mode 100644 index 0000000..ba8b21c --- /dev/null +++ b/src/symboltable.h @@ -0,0 +1,27 @@ +#include +#include +#include + +#define INITIAL_CAPACITY 5 +#define GROWTH_FACTOR 2 + +typedef uint32_t address; + +typedef struct { + char *label; + address address; +} symbol_table_map; + +typedef struct { + symbol_table_map* table; + int size; + int capacity; +} symbol_table; + +symbol_table *st_init(void); + +void st_insert(symbol_table *st, char *label, address addr); + +bool st_contains(symbol_table *st, char *label); + +address st_get(symbol_table *st, char *label); diff --git a/src/tokeniser.c b/src/tokeniser.c index 7cec970..6e37d1a 100644 --- a/src/tokeniser.c +++ b/src/tokeniser.c @@ -1,5 +1,6 @@ // Tokeniser.c #include +#include #include #include #include @@ -9,6 +10,25 @@ #define MAX_OPERAND_COUNT 4 #define OPERAND_DELIMITER ", " +char *trim(char *str) { + while (isspace(*str)) { + str++; + } + + if (*str == '\0') { + return str; + } + + char *end = str + strlen(str) - 1; + while (end > str && isspace(*end)) { + end--; + } + + end[1] = '\0'; + + return str; +} + char **tokenise(char *line, int *numTokens) { char **tokens = malloc(MAX_TOKEN_COUNT * sizeof(char *));\ if (!tokens) { @@ -16,6 +36,8 @@ char **tokenise(char *line, int *numTokens) { exit(EXIT_FAILURE); } + line = trim(line); + *numTokens = 0; char *token = strtok(line, " "); assert(token != NULL); @@ -23,7 +45,10 @@ char **tokenise(char *line, int *numTokens) { tokens[(*numTokens)++] = token; char *operandStart = strtok(NULL, ""); - assert(operandStart != NULL); + if (operandStart == NULL) { + // No operands. Return the instruction token. + return tokens; + } bool inBracket = false; char *currentToken = operandStart; @@ -48,11 +73,6 @@ char **tokenise(char *line, int *numTokens) { if (*currentToken != '\0') { tokens[*numTokens] = currentToken; - - if (tokens[*numTokens][strlen(tokens[*numTokens]) - 1] == '\n') { - tokens[*numTokens][strlen(tokens[*numTokens]) - 1] = '\0'; - } - (*numTokens)++; }