diff --git a/src/emulator/decode.c b/src/emulator/decode.c index ad09429..3fbaaa6 100644 --- a/src/emulator/decode.c +++ b/src/emulator/decode.c @@ -1,157 +1,198 @@ +/** @file decode.c + * @brief Decode Function from binary words to internal representation structs. + * + * This defines the decode function which takes a binary word (uint32_t) and + * decodes it into an a64inst_instruction conveying the same information. + * + * @author Saleh Bubshait + * @author Themis Demetriades + */ + #include #include #include "decode.h" #include "../shared/binary_util.h" -// Given a binary word, return its internal representation as an a64instruction struct encoding the same -// information. +#define getField(fieldname) getBits(wrd, fieldname##_LSB, fieldname##_MSB) + +/************************************ + * PROTOTYPES + ************************************/ + +static void decodeDPI(word wrd, a64inst_instruction *inst); +static void decodeBranch(word wrd, a64inst_instruction *inst); +static void decodeDPRegister(word wrd, a64inst_instruction *inst); +static void decodeSingleTransfer(word wrd, a64inst_instruction *inst); + +/** @brief The main decode function. Takes a word (uint32_t) representing the + * instruction and decodes it into an a64inst_instruction struct. + * @param wrd The word (uint32_t) to be decoded in binary. + * @return a pointer to the heap-allocated a64inst_instruction struct + * representing the decoded instruction if successful. + */ 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); + fprintf(stderr, "Error: Could not allocate memory for an instruction\n"); + exit(EXIT_FAILURE); } - word typeId = getBits(wrd, TYPE_ID_LSB, TYPE_ID_MSB); - // Halt interpretation + word typeId = getField(TYPE_ID); + 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; - } + decodeDPI(wrd, inst); } else if (typeId == BRANCH_ID) { inst->type = a64inst_BRANCH; - word branchTypeFlag = getBits(wrd, BRANCH_TYPE_LSB, BRANCH_TYPE_MSB); - - inst->data.BranchData.BranchType = branchTypeFlag; + decodeBranch(wrd, inst); - 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) { + } else if (getField(DP_REG_FLAG) == 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; - } + decodeDPRegister(wrd, inst); } 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); - } + decodeSingleTransfer(wrd, inst); } return inst; } + +/************************************ + * HELPER FUNCTIONS + ************************************/ + +static void decodeDPI(word wrd, a64inst_instruction *inst) { + inst->data.DPImmediateData.regType = getField(DP_WIDTH); + inst->data.DPImmediateData.processOp = getField(DP_OP); + inst->data.DPImmediateData.dest = getField(DP_DEST); + + switch(getField(DP_IMM_OPTYPE)) { + + case DP_IMM_OPTYPE_ARITHM: + inst->data.DPImmediateData.DPIOpType = a64inst_DPI_ARITHM; + inst->data.DPImmediateData.processOpData.arithmData.shiftImmediate = getField(DP_IMM_ARITHM_SHIFTFLAG); + inst->data.DPImmediateData.processOpData.arithmData.immediate = getField(DP_IMM_ARITHM_IMMVAL); + inst->data.DPImmediateData.processOpData.arithmData.src = getField(DP_IMM_ARITHM_DEST); + break; + + case DP_IMM_OPTYPE_WIDEMOV: + inst->data.DPImmediateData.DPIOpType = a64inst_DPI_WIDEMOV; + inst->data.DPImmediateData.processOpData.wideMovData.shiftScalar = getField(DP_IMM_WIDEMOV_SHIFTSCALAR); + inst->data.DPImmediateData.processOpData.wideMovData.immediate = getField(DP_IMM_WIDEMOV_IMMVAL); + break; + + default: + fprintf(stderr, "Unknown immediate data processing operation type found!\n"); + exit(1); + break; + } +} + +static void decodeBranch(word wrd, a64inst_instruction *inst) { + word branchTypeFlag = getField(BRANCH_TYPE); + inst->data.BranchData.BranchType = branchTypeFlag; + + switch (branchTypeFlag) { + case a64inst_UNCONDITIONAL: + inst->data.BranchData.processOpData.unconditionalData.unconditionalOffset = getField(BRANCH_UNCONDITIONAL_OFFSET); + break; + + case a64inst_CONDITIONAL: + inst->data.BranchData.processOpData.conditionalData.offset = getField(BRANCH_CONDITIONAL_OFFSET); + + word conditionFlag = getField(BRANCH_CONDITIONAL_COND); + + 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 = getField(BRANCH_REGISTER_SRC); + break; + + default: + fprintf(stderr, "Undefined branch type detected!\n"); + exit(1); + break; + } +} + +static void decodeDPRegister(word wrd, a64inst_instruction *inst) { + inst->data.DPRegisterData.regType = getField(DP_WIDTH); + inst->data.DPRegisterData.processOp = getField(DP_OP); + inst->data.DPRegisterData.dest = getField(DP_DEST); + inst->data.DPRegisterData.src1 = getField(DP_REG_SRC1); + inst->data.DPRegisterData.src2 = getField(DP_REG_SRC2); + inst->data.DPRegisterData.DPROpType = getField(DP_REG_OPTYPE); + + a64inst_DPRegister_ArithmLogicData *arithmLogicData = &inst->data.DPRegisterData.processOpData.arithmLogicData; + + arithmLogicData->type = getField(DP_REG_ARITHMLOGIC_ARITHMFLAG); + arithmLogicData->shiftType = getField(DP_REG_ARITHMLOGIC_SHIFTTYPE); + arithmLogicData->negShiftedSrc2 = getField(DP_REG_ARITHMLOGIC_NEGSRC2FLAG); + + 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 = getField(DP_REG_ARITHMLOGIC_SHIFTAMOUNT); + 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 = getField(DP_REG_MULTIPLY_SUMMAND); + inst->data.DPRegisterData.processOpData.multiplydata.negProd = getField(DP_REG_MULTIPLY_NEGPROD); + break; + } +} + +static void decodeSingleTransfer(word wrd, a64inst_instruction *inst) { + inst->data.SingleTransferData.regType = getField(SDT_REGTYPE_FLAG); + inst->data.SingleTransferData.target = getField(SDT_TARGET_REG); + + bool singleTransferOptype = getField(SDT_OPTYPE_FLAG); + if(singleTransferOptype == 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 = getField(SDT_TRANSFER_TYPE); + inst->data.SingleTransferData.processOpData.singleDataTransferData.base = getField(SDT_BASE_REG); + + if (getField(SDT_UNSIGNED_FLAG) == 1) { + // Unsigned offset + inst->data.SingleTransferData.processOpData.singleDataTransferData.addressingMode = a64inst_UNSIGNED_OFFSET; + inst->data.SingleTransferData.processOpData.singleDataTransferData.a64inst_addressingModeData.unsignedOffset = getField(SDT_OFFSET); + } else if (getField(SDT_REGISTER_FLAG) == 1) { + // Register Offset + inst->data.SingleTransferData.processOpData.singleDataTransferData.addressingMode = a64inst_REGISTER_OFFSET; + inst->data.SingleTransferData.processOpData.singleDataTransferData.a64inst_addressingModeData.offsetReg = getField(SDT_REGISTER_REG); + } else { + // Pre-Indexed or Post-Indexed + inst->data.SingleTransferData.processOpData.singleDataTransferData.addressingMode = getField(SDT_INDEXED_ADDRMODE); + inst->data.SingleTransferData.processOpData.singleDataTransferData.a64inst_addressingModeData.indexedOffset = getField(SDT_INDEXED_OFFSET); + } + + } else { + // Load Literal + inst->data.SingleTransferData.SingleTransferOpType = a64inst_SINGLE_TRANSFER_LOAD_LITERAL; + inst->data.SingleTransferData.processOpData.loadLiteralData.offset = getField(SDT_LOAD_LITERAL_OFFSET); + } +} diff --git a/src/emulator/decode.h b/src/emulator/decode.h index b5982be..d3d4330 100644 --- a/src/emulator/decode.h +++ b/src/emulator/decode.h @@ -8,8 +8,8 @@ #define DP_IMM_ID 4 #define BRANCH_ID 5 -#define DP_REG_LSB 25 -#define DP_REG_MSB 26 +#define DP_REG_FLAG_LSB 25 +#define DP_REG_FLAG_MSB 26 #define DP_WIDTH_LSB 31 #define DP_WIDTH_MSB 32