201 lines
6.7 KiB
C
201 lines
6.7 KiB
C
/** @file encode.c
|
|
* @brief A function to encode the internal representation of ARMv8
|
|
* instructions, a64inst_instruction, into binary.
|
|
*
|
|
* @author Ethan Dias Alberto
|
|
* @author George Niedringhaus
|
|
* @author Saleh Bubshait
|
|
*/
|
|
|
|
#include "symboltable.h"
|
|
#include <stdlib.h>
|
|
#include "../util/binary_util.h"
|
|
#include "encode.h"
|
|
|
|
#define HALT_BINARY 2315255808
|
|
|
|
static int getLabelOffset(symbol_table* table, char* label, int currentIndex, int n_bits) {
|
|
address target = st_get(table, label);
|
|
return signExtend((unsigned int) (target - currentIndex), n_bits);
|
|
}
|
|
|
|
// Generates assembled code based on the two-pass assembly method
|
|
static word encodeBranch(a64inst_instruction *instr, int index, symbol_table *st) {
|
|
word wrd = 0;
|
|
|
|
switch (instr->data.BranchData.BranchType) {
|
|
case a64inst_UNCONDITIONAL:
|
|
setBits(&wrd, 26, 29, 0x5);
|
|
setBits(&wrd, 0, 26, getLabelOffset(st, instr->data.BranchData.processOpData.unconditionalData.label, index, 26));
|
|
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, getLabelOffset(st, instr->data.BranchData.processOpData.conditionalData.label, index, 19));
|
|
setBits(&wrd, 0, 4, instr->data.BranchData.processOpData.conditionalData.cond);
|
|
break;
|
|
}
|
|
|
|
return wrd;
|
|
}
|
|
|
|
static 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
|
|
uint8_t hw = data.processOpData.wideMovData.shiftScalar / 16;
|
|
setBits(&wrd, 21, 23, hw); // hw
|
|
setBits(&wrd, 5, 21, data.processOpData.wideMovData.immediate); // imm16
|
|
}
|
|
|
|
return wrd;
|
|
}
|
|
|
|
static 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, 29, 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;
|
|
|
|
}
|
|
|
|
static 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;
|
|
}
|
|
|
|
static word encodeLoadLiteral(a64inst_instruction cI, int arrIndex, symbol_table *st) {
|
|
word wrd = 0;
|
|
|
|
a64inst_SingleTransferData data = cI.data.SingleTransferData;
|
|
setBits(&wrd, 24, 32, 0x18);
|
|
setBits(&wrd, 30, 31, data.regType);
|
|
char *label = data.processOpData.loadLiteralData.label;
|
|
int offset = getLabelOffset(st, label, arrIndex, 19);
|
|
setBits(&wrd, 5, 24, offset);
|
|
setBits(&wrd, 0, 5, data.target);
|
|
|
|
return wrd;
|
|
}
|
|
|
|
word *encode(a64inst_instruction insts[], int instCount, symbol_table* st) {
|
|
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, st);
|
|
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, st);
|
|
index++;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return arr;
|
|
}
|