/** @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 "../util/binary_util.h" // Macro that calls getBit() for a bitfield whose constants follow the format // FIELDNAME_LSB and FIELDNAME_MSB, storing the result in the variable wrd #define getField(fieldname) getBits(wrd, fieldname##_LSB, fieldname##_MSB) /************************************ * CONSTANTS ************************************/ #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_FLAG_LSB 25 #define DP_REG_FLAG_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 #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 /************************************ * 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); /************************************ * FUNCTIONS ************************************/ a64inst_instruction *decode(word wrd) { a64inst_instruction *inst = malloc(sizeof(a64inst_instruction)); if (inst == NULL) { fprintf(stderr, "Error: Could not allocate memory for an instruction\n"); exit(EXIT_FAILURE); } word typeId = getField(TYPE_ID); if (wrd == HALT_WORD) { inst->type = a64inst_HALT; } else if (typeId == DP_IMM_ID) { inst->type = a64inst_DPIMMEDIATE; decodeDPI(wrd, inst); } else if (typeId == BRANCH_ID) { inst->type = a64inst_BRANCH; decodeBranch(wrd, inst); } else if (getField(DP_REG_FLAG) == 1) { inst->type = a64inst_DPREGISTER; decodeDPRegister(wrd, inst); } else { inst->type = a64inst_SINGLETRANSFER; 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); } }