295 lines
11 KiB
C
295 lines
11 KiB
C
/** @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 <stdio.h>
|
|
#include <stdlib.h>
|
|
#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);
|
|
}
|
|
}
|