diff --git a/src/assemble.c b/src/assemble.c old mode 100755 new mode 100644 index 0a8687d..d0321a4 --- a/src/assemble.c +++ b/src/assemble.c @@ -23,11 +23,11 @@ int main(int argc, char **argv) { // First Pass: Create the symbol table st *table = firstPass(instructions, lineCount); - // Second Pass: Assemble the instructions - word *binary = secondPass(instructions, lineCount, table); // 1000 is just a temp fix. + // Second Pass: Encode the instructions into binary + word *binary = encode(instructions, lineCount, table); // Write the binary to the output file - writeBinaryFile(binary, argv[2], lineCount); // 1000 is just a temp fix. + writeBinaryFile(binary, argv[2], lineCount); /* TODO: FREE MEMORY!! */ diff --git a/src/encode.c b/src/encode.c new file mode 100644 index 0000000..8fc716d --- /dev/null +++ b/src/encode.c @@ -0,0 +1,224 @@ +#include +#include "global.h" +#include "a64instruction/a64instruction.h" +#include "symboltable.c" +#include +#include + +#define HALT_BINARY 2315255808 + +// write the provided value to the bits in the range [lsb, msb) {inclusive, exclusive} to the word. +// Does not modify any other bits in the word. +void setBits(word* wrd, uint8_t lsb, uint8_t msb, word value) { + // Ensure LSB and MSB are within range of word size, and in the correct order + assert(lsb < msb && msb <= 32); + + // Create a mask with 1s in the range [lsb, msb) and 0s elsewhere + word mask = 0; + for (uint8_t i = lsb; i < msb; i++) { + mask |= 1 << i; + } + + // Clear the bits in the range [lsb, msb) in the word + *wrd &= ~mask; + + // Set the bits in the range [lsb, msb) to the value + *wrd |= (value << lsb) & mask; +} + + +// Generates assembled code based on the two-pass assembly method +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); + break; + + case a64inst_REGISTER: + setBits(&wrd, 16, 32, 0xD61F); + setBits(&wrd, 5, 10, instr->data.BranchData.processOpData.registerData.src); + break; + + case a64inst_CONDITIONAL: + setBits(&wrd, 26, 32, 0x15); + setBits(&wrd, 5, 24, instr->data.BranchData.processOpData.conditionalData.offset); + setBits(&wrd, 0, 4, instr->data.BranchData.processOpData.conditionalData.cond); + break; + } + + 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; + + a64inst_DPImmediateData data = inst.data.DPImmediateData; + + setBits(&wrd, 31, 32, data.regType); // sf + setBits(&wrd, 29, 31, data.processOp); // opc + setBits(&wrd, 28, 29, 0x1); // constant value + setBits(&wrd, 0, 5, data.dest); // rd + + if (data.DPIOpType == a64inst_DPI_ARITHM) { + setBits(&wrd, 23, 26, 0x2); //opi + setBits(&wrd, 5, 10, data.processOpData.arithmData.src); // rn + setBits(&wrd, 22, 23, data.processOpData.arithmData.shiftImmediate); // sh + setBits(&wrd, 10, 22, data.processOpData.arithmData.immediate); // imm12 + } + // if wide move + else { + setBits(&wrd, 23, 26, 0x5); //opi + // TODO: Check the following line, is it shiftScalar?: + setBits(&wrd, 21, 23, data.processOpData.wideMovData.shiftScalar); // hw + setBits(&wrd, 5, 21, data.processOpData.wideMovData.immediate); // imm16 + } + + return wrd; +} + +word encodeDPRegister(a64inst_instruction inst) { + word wrd = 0; + + a64inst_DPRegisterData data = inst.data.DPRegisterData; + setBits(&wrd, 31, 32, data.regType); // sf + setBits(&wrd, 29, 31, data.processOp); // opc + setBits(&wrd, 28, 28, data.DPROpType); // M + setBits(&wrd, 25 ,28, 0x5); + setBits(&wrd, 16, 21, data.src2); // src2 + setBits(&wrd, 5, 10, data.src1); // src1 + setBits(&wrd, 0, 5, data.dest); // src2 + + if (data.DPROpType == a64inst_DPR_MULTIPLY) { + setBits(&wrd, 21, 31, 0xD8); + setBits(&wrd, 15, 16, data.processOpData.multiplydata.negProd); + setBits(&wrd, 10, 15, data.processOpData.multiplydata.summand); + + } else { + // Arithmetic Logic Instruction + setBits(&wrd, 22, 24, data.processOpData.arithmLogicData.shiftType); + setBits(&wrd, 10, 16, data.processOpData.arithmLogicData.shiftAmount); + + if (data.processOpData.arithmLogicData.type == a64inst_DPR_ARITHM) { + // Arithmetic + setBits(&wrd, 24, 25, 0x1); // bit 24 + } else { + setBits(&wrd, 21, 22, data.processOpData.arithmLogicData.negShiftedSrc2); + } + + } + + return wrd; + +} + +word encodeSingleDataTransfer(a64inst_instruction inst) { + word wrd = 0; + + a64inst_SingleTransferData data = inst.data.SingleTransferData; + a64inst_SingleDataTransferData data2 = data.processOpData.singleDataTransferData; + + setBits(&wrd, 22, 32, 0x2E0); + setBits(&wrd, 30, 31, data.regType); + setBits(&wrd, 24, 25, data2.addressingMode == a64inst_UNSIGNED_OFFSET); + setBits(&wrd, 22, 23, data2.transferType); + setBits(&wrd, 5, 10, data2.base); + setBits(&wrd, 0, 5, data.target); + + switch (data2.addressingMode) { + // register offset + case a64inst_REGISTER_OFFSET: + setBits(&wrd, 21, 22, 1); + setBits(&wrd, 10, 16, 0x1A); + setBits(&wrd, 16, 21, data2.a64inst_addressingModeData.offsetReg); + break; + // unsigned offset + case a64inst_UNSIGNED_OFFSET: + setBits(&wrd, 10, 22, data2.a64inst_addressingModeData.unsignedOffset); + break; + // pre/post indexed + default: + setBits(&wrd, 21, 22, 0); + setBits(&wrd, 11, 12, data2.addressingMode == a64inst_PRE_INDEXED); + setBits(&wrd, 10, 11, 1); + setBits(&wrd, 12, 21, data2.a64inst_addressingModeData.indexedOffset); + break; + } + + return wrd; +} + +word encodeLoadLiteral(a64inst_instruction cI) { + word wrd = 0; + + a64inst_SingleTransferData data = cI.data.SingleTransferData; + setBits(&wrd, 24, 32, 0x18); + setBits(&wrd, 30, 31, data.regType); + setBits(&wrd, 5, 24, data.processOpData.loadLiteralData.offset); + setBits(&wrd, 0, 5, data.target); + + 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 *arr = (word*)malloc(sizeof(word) * instCount); + int index = 0; + for (int i = 0; i < instCount; i++) { + a64inst_instruction inst = insts[i]; + switch (inst.type) { + case a64inst_DPIMMEDIATE: + arr[index] = encodeDPImmediate(inst); + index++; + break; + case a64inst_DPREGISTER: + arr[index] = encodeDPRegister(inst); + index++; + break; + case a64inst_SINGLETRANSFER: + arr[index] = encodeSingleDataTransfer(inst); + index++; + break; + case a64inst_LOADLITERAL: + arr[index] = encodeLoadLiteral(inst); + index++; + break; + case a64inst_DIRECTIVE: + arr[index] = inst.data.DirectiveData.value; + index++; + break; + case a64inst_HALT: + arr[index] = HALT_BINARY; + index++; + break; + case a64inst_LABEL: + // Labels are handled in the first pass and used for addressing. + break; + case a64inst_BRANCH: + arr[index] = encodeBranch(&inst); + index++; + default: + break; + } + } + return arr; +}