Restructre first pass, Reimplement symboltable

This commit is contained in:
sBubshait 2024-06-14 20:04:08 +01:00
parent fd165aae47
commit 59871d7a0e
13 changed files with 142 additions and 515 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -1,169 +0,0 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#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;
}

View File

@ -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

View File

@ -1,67 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#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 <file_in> [<file_out>]");
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;
}
*/

View File

@ -1,32 +0,0 @@
#ifndef __EMULATOR__
#define __EMULATOR__
#include "global.h"
#include <stdbool.h>
/************************************
* 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

View File

@ -3,7 +3,6 @@
#include "a64instruction/a64instruction.h"
#include "symboltable.c"
#include <stdlib.h>
#include <limits.h>
#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;

View File

@ -1,7 +0,0 @@
#ifndef __EXECUTE__
#define __EXECUTE__
#include "a64instruction/a64instruction.h"
#include "emulator.h"
void execute(Machine *state, a64inst_instruction *inst);
#endif

View File

@ -1,58 +0,0 @@
#include <stdbool.h>
#include <stdint.h>
#include <inttypes.h>
#include <string.h>
#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);
}
}
}

View File

@ -1,12 +0,0 @@
#ifndef __PRINT__
#define __PRINT__
#include <stdio.h>
#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

View File

@ -1,48 +1,74 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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);
}

27
src/symboltable.h Normal file
View File

@ -0,0 +1,27 @@
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#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);

View File

@ -1,5 +1,6 @@
// Tokeniser.c
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -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)++;
}