Merge branch 'Assembler-G' into 'assembler'
Assembler g See merge request lab2324_summer/armv8_43!3
This commit is contained in:
commit
c616b6d70e
@ -1,8 +1,11 @@
|
|||||||
#ifndef __A64INSTRUCTION__
|
#ifndef __A64INSTRUCTION__
|
||||||
#define __A64INSTRUCTION__
|
#define __A64INSTRUCTION__
|
||||||
#include "a64instruction_DPImmediate.h"
|
#include "a64instruction_DPImmediate.h"
|
||||||
|
#include "a64instruction_DPRegister.h"
|
||||||
#include "a64instruction_Branch.h"
|
#include "a64instruction_Branch.h"
|
||||||
#include "a64instruction_SingleTransfer.h"
|
#include "a64instruction_SingleTransfer.h"
|
||||||
|
#include "a64instruction_Label.h"
|
||||||
|
#include "a64instruction_Directive.h"
|
||||||
|
|
||||||
// Define the types of instructions in subset of the AArch64 Instruction Set implemented.
|
// Define the types of instructions in subset of the AArch64 Instruction Set implemented.
|
||||||
// Each type is defined by the format of the instruction's operand(s).
|
// Each type is defined by the format of the instruction's operand(s).
|
||||||
@ -12,7 +15,9 @@ typedef enum {
|
|||||||
a64inst_SINGLETRANSFER,
|
a64inst_SINGLETRANSFER,
|
||||||
a64inst_LOADLITERAL,
|
a64inst_LOADLITERAL,
|
||||||
a64inst_BRANCH,
|
a64inst_BRANCH,
|
||||||
a64inst_HALT
|
a64inst_HALT,
|
||||||
|
a64inst_LABEL,
|
||||||
|
a64inst_DIRECTIVE
|
||||||
} a64inst_type;
|
} a64inst_type;
|
||||||
|
|
||||||
// Structure the holds the type and operand data of an instruction
|
// Structure the holds the type and operand data of an instruction
|
||||||
@ -20,8 +25,11 @@ typedef struct {
|
|||||||
a64inst_type type;
|
a64inst_type type;
|
||||||
union {
|
union {
|
||||||
a64inst_DPImmediateData DPImmediateData;
|
a64inst_DPImmediateData DPImmediateData;
|
||||||
|
a64inst_DPRegisterData DPRegisterData;
|
||||||
a64inst_BranchData BranchData;
|
a64inst_BranchData BranchData;
|
||||||
a64inst_SingleTransferData SingleTransferData;
|
a64inst_SingleTransferData SingleTransferData;
|
||||||
|
a64inst_LabelData LabelData;
|
||||||
|
a64inst_DirectiveData DirectiveData;
|
||||||
} data;
|
} data;
|
||||||
} a64inst_instruction;
|
} a64inst_instruction;
|
||||||
|
|
||||||
|
|||||||
@ -4,8 +4,8 @@
|
|||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
a64inst_UNCONDITIONAL = 0,
|
a64inst_UNCONDITIONAL = 0,
|
||||||
a64inst_REGISTER = 1,
|
a64inst_REGISTER = 3,
|
||||||
a64inst_CONDITIONAL = 2
|
a64inst_CONDITIONAL = 1
|
||||||
} a64inst_BranchType;
|
} a64inst_BranchType;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
|
#ifndef __A64INSTRUCTION_DP__
|
||||||
|
#define __A64INSTRUCTION_DP__
|
||||||
|
|
||||||
// Denotes the type of arithmetic operations supported by the architecture
|
// Denotes the type of arithmetic operations supported by the architecture
|
||||||
typedef enum {
|
typedef enum {
|
||||||
a64inst_ADD = 0,
|
a64inst_ADD = 0,
|
||||||
@ -5,3 +8,5 @@ typedef enum {
|
|||||||
a64inst_SUB = 2,
|
a64inst_SUB = 2,
|
||||||
a64inst_SUBS = 3
|
a64inst_SUBS = 3
|
||||||
} a64inst_arithmOp;
|
} a64inst_arithmOp;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@ -4,8 +4,8 @@
|
|||||||
|
|
||||||
// Denotes the type of data processing operation
|
// Denotes the type of data processing operation
|
||||||
typedef enum {
|
typedef enum {
|
||||||
a64inst_DPR_ARITHMLOGIC,
|
a64inst_DPR_ARITHMLOGIC = 0,
|
||||||
a64inst_DPR_MULTIPLY
|
a64inst_DPR_MULTIPLY = 1
|
||||||
} a64inst_DPROpType;
|
} a64inst_DPROpType;
|
||||||
|
|
||||||
// Denotes the logical operations supported by the architecture
|
// Denotes the logical operations supported by the architecture
|
||||||
@ -27,10 +27,11 @@ typedef enum {
|
|||||||
// Holds data specific to arithmetic/logic register data processing instructions
|
// Holds data specific to arithmetic/logic register data processing instructions
|
||||||
typedef struct {
|
typedef struct {
|
||||||
enum {
|
enum {
|
||||||
a64inst_DPR_ARITHM = 0,
|
a64inst_DPR_ARITHM = 1,
|
||||||
a64inst_DPR_LOGIC = 1
|
a64inst_DPR_LOGIC = 0
|
||||||
} type;
|
} type;
|
||||||
a64inst_ShiftType shiftType;
|
a64inst_ShiftType shiftType;
|
||||||
|
uint8_t shiftAmount;
|
||||||
bool negShiftedSrc2; // Guaranteed to be 0 for arithmetic instructions
|
bool negShiftedSrc2; // Guaranteed to be 0 for arithmetic instructions
|
||||||
} a64inst_DPRegister_ArithmLogicData;
|
} a64inst_DPRegister_ArithmLogicData;
|
||||||
|
|
||||||
@ -44,10 +45,7 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
a64inst_regType regType;
|
a64inst_regType regType;
|
||||||
a64inst_DPROpType DPROpType;
|
a64inst_DPROpType DPROpType;
|
||||||
union {
|
uint8_t processOp;
|
||||||
a64inst_logicOp logicOp;
|
|
||||||
a64inst_arithmOp arithmOp;
|
|
||||||
} processOpId;
|
|
||||||
a64inst_regSpecifier src2;
|
a64inst_regSpecifier src2;
|
||||||
union {
|
union {
|
||||||
a64inst_DPRegister_ArithmLogicData arithmLogicData;
|
a64inst_DPRegister_ArithmLogicData arithmLogicData;
|
||||||
|
|||||||
5
src/a64instruction_Directive.h
Normal file
5
src/a64instruction_Directive.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#include "global.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
word value;
|
||||||
|
} a64inst_DirectiveData;
|
||||||
3
src/a64instruction_Label.h
Normal file
3
src/a64instruction_Label.h
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
typedef struct {
|
||||||
|
char* label;
|
||||||
|
} a64inst_LabelData;
|
||||||
@ -8,7 +8,7 @@ typedef uint8_t a64inst_regSpecifier;
|
|||||||
// Denotes the type of register being referred to
|
// Denotes the type of register being referred to
|
||||||
typedef enum {
|
typedef enum {
|
||||||
a64inst_W = 0,
|
a64inst_W = 0,
|
||||||
a64inst_R = 1
|
a64inst_X = 1
|
||||||
} a64inst_regType;
|
} a64inst_regType;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
169
src/decode.c
Normal file
169
src/decode.c
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "decode.h"
|
||||||
|
#include "emulator.h"
|
||||||
|
|
||||||
|
// Retrieve the bits between positions 'lsb' (inclusive) and 'msb' (exclusive) from a given word
|
||||||
|
// as a new zero-extended word.
|
||||||
|
static word getBits(word wrd, uint8_t lsb, uint8_t msb) {
|
||||||
|
|
||||||
|
// Ensure LSB and MSB are within range of word size, and in the correct order
|
||||||
|
assert(lsb < msb && msb <= WORD_BITS);
|
||||||
|
|
||||||
|
wrd &= ((dword) 1 << msb) - 1;
|
||||||
|
return wrd >> lsb;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given a binary word, return its internal representation as an a64instruction struct encoding the same
|
||||||
|
// information.
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
word typeId = getBits(wrd, TYPE_ID_LSB, TYPE_ID_MSB);
|
||||||
|
// Halt interpretation
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (typeId == BRANCH_ID) {
|
||||||
|
inst->type = a64inst_BRANCH;
|
||||||
|
word branchTypeFlag = getBits(wrd, BRANCH_TYPE_LSB, BRANCH_TYPE_MSB);
|
||||||
|
|
||||||
|
inst->data.BranchData.BranchType = branchTypeFlag;
|
||||||
|
|
||||||
|
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) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
} 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return inst;
|
||||||
|
}
|
||||||
96
src/decode.h
Normal file
96
src/decode.h
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
#include "global.h"
|
||||||
|
#include "a64instruction.h"
|
||||||
|
|
||||||
|
#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_LSB 25
|
||||||
|
#define DP_REG_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
|
||||||
|
// Defines the values for fields used for arithmetic/logic DPR instructions
|
||||||
|
// that are necessary to indicate a multiplication instruction
|
||||||
|
#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
|
||||||
@ -1,5 +1,61 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "a64instruction.h"
|
||||||
|
#include "emulator.h"
|
||||||
|
#include "fileio.h"
|
||||||
|
#include "global.h"
|
||||||
|
#include "print.h"
|
||||||
|
#include "decode.h"
|
||||||
|
#include "execute.h"
|
||||||
|
|
||||||
|
extern a64inst_instruction *decode(word w);
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
|
|
||||||
|
// Check the arguments
|
||||||
|
if (argc == 1) {
|
||||||
|
fprintf(stderr, "Error: An object file is required. Syntax: ./emulate <file_in> [<file_out>]");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *out = stdout;
|
||||||
|
if (argc > 2) {
|
||||||
|
out = fopen(argv[2], "w");
|
||||||
|
if (out == NULL) {
|
||||||
|
fprintf(stderr, "Error: Could not open file %s\n", argv[2]);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialising the machine state
|
||||||
|
Machine state = {0};
|
||||||
|
state.memory = fileio_loadBin(argv[1], MEMORY_SIZE);
|
||||||
|
state.conditionCodes = (PState){0, 1, 0, 0};
|
||||||
|
state.pc = 0x0;
|
||||||
|
|
||||||
|
|
||||||
|
// Fetch-decode-execute cycle
|
||||||
|
word wrd;
|
||||||
|
a64inst_instruction *inst;
|
||||||
|
do {
|
||||||
|
|
||||||
|
// Step 1: Fetch instruction at PC's address
|
||||||
|
wrd = readWord(state.memory, state.pc);
|
||||||
|
|
||||||
|
// Step 2: Decode instruction to internal representation
|
||||||
|
inst = decode(wrd);
|
||||||
|
|
||||||
|
// Step 3: Update processor state to reflect executing the instruction, and increment PC
|
||||||
|
execute(&state, inst);
|
||||||
|
|
||||||
|
if (inst->type != a64inst_BRANCH)
|
||||||
|
state.pc += sizeof(word);
|
||||||
|
} while (inst->type != a64inst_HALT);
|
||||||
|
|
||||||
|
state.pc -= sizeof(word);
|
||||||
|
|
||||||
|
printState(&state, out);
|
||||||
|
free(state.memory);
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
32
src/emulator.h
Normal file
32
src/emulator.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#ifndef __EMULATOR__
|
||||||
|
#define __EMULATOR__
|
||||||
|
#include "global.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
/************************************
|
||||||
|
* DEFINITIONS
|
||||||
|
************************************/
|
||||||
|
|
||||||
|
#define BYTE_BITS 8
|
||||||
|
#define WORD_BITS (BYTE_BITS * sizeof(word))
|
||||||
|
#define DWORD_BITS (BYTE_BITS * sizeof(dword))
|
||||||
|
|
||||||
|
/************************************
|
||||||
|
* STRUCTS
|
||||||
|
************************************/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool Negative;
|
||||||
|
bool Zero;
|
||||||
|
bool Carry;
|
||||||
|
bool Overflow;
|
||||||
|
} PState;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
dword registers[REGISTER_COUNT];
|
||||||
|
dword pc;
|
||||||
|
byte *memory;
|
||||||
|
PState conditionCodes;
|
||||||
|
} Machine;
|
||||||
|
|
||||||
|
#endif
|
||||||
448
src/execute.c
Normal file
448
src/execute.c
Normal file
@ -0,0 +1,448 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include "execute.h"
|
||||||
|
#include "print.h"
|
||||||
|
|
||||||
|
// Defines the maximum value that can be held in a register
|
||||||
|
#define MAX_REG_VAL ((1 << DWORD_BITS) - 1)
|
||||||
|
|
||||||
|
// The number of bits to shift the immediate value in an arithmetic immediate data processing
|
||||||
|
// instruction if the shift flag is enabled.
|
||||||
|
#define DPI_ARITHM_SHIFT 12
|
||||||
|
|
||||||
|
// The number of bits to shift the immediate value in a wide move immediate data processing
|
||||||
|
// instruction if the shift flag is enabled.
|
||||||
|
#define DPI_WIDEMOV_SHIFT 16
|
||||||
|
|
||||||
|
// Prototypes
|
||||||
|
void execute_SDT(Machine *state, a64inst_instruction *inst);
|
||||||
|
void execute_Branch(Machine *state, a64inst_instruction *inst);
|
||||||
|
void executeMultiply(Machine *state, a64inst_instruction *inst);
|
||||||
|
|
||||||
|
// Return maximum of two dwords
|
||||||
|
static dword max(dword a, dword b) {
|
||||||
|
return a > b ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Truncate a given value to the size of a word or dword depending on the register type
|
||||||
|
static dword truncateValue(dword value, a64inst_regType regType) {
|
||||||
|
if (regType == a64inst_X) {
|
||||||
|
return value;
|
||||||
|
} else {
|
||||||
|
return (word)value;
|
||||||
|
//return value & (dword)(((dword)1 << WORD_BITS) - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign extend a given value to a 64-bit signed integer given the number of bits
|
||||||
|
static int64_t signExtend(dword value, unsigned int n) {
|
||||||
|
if (n == 0 || n >= 64) {
|
||||||
|
// If n_bits is 0 or greater than or equal to 64, return the value as is
|
||||||
|
return (int64_t)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t sign_bit_mask = (uint64_t)1 << (n - 1);
|
||||||
|
|
||||||
|
// Mask to isolate the n-bit value
|
||||||
|
uint64_t n_bit_mask = (sign_bit_mask << 1) - 1;
|
||||||
|
|
||||||
|
// Check if the sign bit is set
|
||||||
|
if (value & sign_bit_mask) {
|
||||||
|
// Sign bit is set, extend the sign
|
||||||
|
return (int64_t)(value | ~n_bit_mask);
|
||||||
|
} else {
|
||||||
|
// Sign bit is not set, return the value as is
|
||||||
|
return (int64_t)(value & n_bit_mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read from processor register, ensuring that a valid register specifier is given
|
||||||
|
// and accounting for the case where the zero register is accessed. Truncate
|
||||||
|
// the 32 most significant bits stored in the R register when reading W register.
|
||||||
|
static dword readRegister(Machine *state, a64inst_regSpecifier reg, a64inst_regType regType) {
|
||||||
|
assert(reg <= REGISTER_COUNT);
|
||||||
|
if (reg == ZERO_REGISTER) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return truncateValue(state->registers[reg], regType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
|
||||||
|
// Write to a processor register, ensuring that a valid register specifier is given
|
||||||
|
// and truncating the value being written when it can't fit in the specified register
|
||||||
|
static void writeRegister(Machine *state, a64inst_regSpecifier reg, a64inst_regType regType, dword value) {
|
||||||
|
assert(reg <= REGISTER_COUNT);
|
||||||
|
if (reg != ZERO_REGISTER) {
|
||||||
|
state->registers[reg] = truncateValue(value, regType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the position of the MSB of the given register type
|
||||||
|
inline static dword getMSBPos(a64inst_regType regType) {
|
||||||
|
return (regType ? DWORD_BITS : WORD_BITS) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the MSB of the given value assuming it's of the size stored in the given register type
|
||||||
|
inline static uint8_t getMSB(dword value, a64inst_regType regType) {
|
||||||
|
return value >> getMSBPos(regType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updates N and Z condition codes given the machine and a result value
|
||||||
|
static void updateCondNZ(Machine *state, dword result, a64inst_regType regType) {
|
||||||
|
state->conditionCodes.Negative = getMSB(result, regType);
|
||||||
|
state->conditionCodes.Zero = result == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute a data processing immediate instruction
|
||||||
|
static void executeDPImmediate(Machine *state, a64inst_instruction *inst) {
|
||||||
|
assert(inst->type == a64inst_DPIMMEDIATE);
|
||||||
|
|
||||||
|
a64inst_regType regType = inst->data.DPImmediateData.regType;
|
||||||
|
a64inst_regSpecifier dest = inst->data.DPImmediateData.dest;
|
||||||
|
switch(inst->data.DPImmediateData.DPIOpType) {
|
||||||
|
|
||||||
|
// Execute an arithmetic immediate data processing instruction
|
||||||
|
case a64inst_DPI_ARITHM:;
|
||||||
|
|
||||||
|
// If shift flag is enabled, logical left shift by the number of bits specified by the architecture
|
||||||
|
dword arithmImm = inst->data.DPImmediateData.processOpData.arithmData.immediate;
|
||||||
|
dword srcVal = state->registers[inst->data.DPImmediateData.processOpData.arithmData.src];
|
||||||
|
if (inst->data.DPImmediateData.processOpData.arithmData.shiftImmediate) {
|
||||||
|
arithmImm = truncateValue(arithmImm << DPI_ARITHM_SHIFT, regType);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(inst->data.DPImmediateData.processOp) {
|
||||||
|
|
||||||
|
dword result;
|
||||||
|
case(a64inst_ADDS):
|
||||||
|
result = srcVal + arithmImm;
|
||||||
|
writeRegister(state, dest, regType, result);
|
||||||
|
|
||||||
|
updateCondNZ(state, result, regType);
|
||||||
|
state->conditionCodes.Overflow = max(srcVal, arithmImm) > result;
|
||||||
|
state->conditionCodes.Carry = state->conditionCodes.Overflow;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case(a64inst_ADD):
|
||||||
|
writeRegister(state, dest, regType, srcVal + arithmImm);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case(a64inst_SUBS):
|
||||||
|
result = srcVal - arithmImm;
|
||||||
|
writeRegister(state, dest, regType, result);
|
||||||
|
|
||||||
|
updateCondNZ(state, result, regType);
|
||||||
|
state->conditionCodes.Overflow = srcVal < result;
|
||||||
|
state->conditionCodes.Carry = state->conditionCodes.Overflow;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case(a64inst_SUB):
|
||||||
|
writeRegister(state, dest, regType, srcVal - arithmImm);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Unknown opcode detected!
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Unknown opcode detected in a DPI arithmetic instruction!\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Execute a wide move immediate data processing instruction
|
||||||
|
case a64inst_DPI_WIDEMOV:;
|
||||||
|
uint8_t shiftScalar = inst->data.DPImmediateData.processOpData.wideMovData.shiftScalar;
|
||||||
|
dword wideMovImm = inst->data.DPImmediateData.processOpData.wideMovData.immediate;
|
||||||
|
|
||||||
|
// NOTE: Not checking that shiftScalar has valid value for 32bit registers. Possibly add explicit error.
|
||||||
|
//printf("%x\n", wideMovImm << (shiftScalar * DPI_WIDEMOV_SHIFT) & );
|
||||||
|
wideMovImm = truncateValue(wideMovImm << (shiftScalar * DPI_WIDEMOV_SHIFT), regType);
|
||||||
|
switch(inst->data.DPImmediateData.processOp) {
|
||||||
|
|
||||||
|
case(a64inst_MOVN):
|
||||||
|
writeRegister(state, dest, regType, ~wideMovImm);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case(a64inst_MOVZ):
|
||||||
|
writeRegister(state, dest, regType, wideMovImm);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case(a64inst_MOVK):;
|
||||||
|
dword result = readRegister(state, dest, regType);
|
||||||
|
result = (result & ~(((1lu << DPI_WIDEMOV_SHIFT) - 1) << shiftScalar * DPI_WIDEMOV_SHIFT)) | wideMovImm;
|
||||||
|
writeRegister(state, dest, regType, result);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Unknown opcode detected in a DPI wide move instruction!\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Unknown instruction detected!
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Attempting to execute instruction with unknown DPI operand type!\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute a data processing register instruction
|
||||||
|
static void executeDPRegister(Machine *state, a64inst_instruction *inst) {
|
||||||
|
assert(inst->type == a64inst_DPREGISTER);
|
||||||
|
|
||||||
|
a64inst_regType regType = inst->data.DPRegisterData.regType;
|
||||||
|
a64inst_regSpecifier dest = inst->data.DPRegisterData.dest;
|
||||||
|
dword src1Val = readRegister(state, inst->data.DPRegisterData.src1, regType);
|
||||||
|
dword src2Val = readRegister(state, inst->data.DPRegisterData.src2, regType);
|
||||||
|
|
||||||
|
switch(inst->data.DPRegisterData.DPROpType) {
|
||||||
|
|
||||||
|
// Execute an arithmetic or logic register data processing instruction
|
||||||
|
case a64inst_DPR_ARITHMLOGIC:;
|
||||||
|
|
||||||
|
// Apply shift to value held in second register
|
||||||
|
a64inst_DPRegister_ArithmLogicData *arithmLogicData = &inst->data.DPRegisterData.processOpData.arithmLogicData;
|
||||||
|
uint8_t shiftAmount = arithmLogicData->shiftAmount;
|
||||||
|
switch(arithmLogicData->shiftType) {
|
||||||
|
|
||||||
|
case a64inst_LSL:
|
||||||
|
src2Val = truncateValue(src2Val << shiftAmount, regType);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case a64inst_LSR:
|
||||||
|
src2Val = truncateValue(src2Val >> shiftAmount, regType);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case a64inst_ASR:
|
||||||
|
if (regType == a64inst_X) {
|
||||||
|
src2Val = truncateValue((int64_t)src2Val >> shiftAmount, regType);
|
||||||
|
} else {
|
||||||
|
src2Val = truncateValue((int32_t)src2Val >> shiftAmount, regType);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case a64inst_ROR:
|
||||||
|
if (arithmLogicData->type != a64inst_DPR_LOGIC) {
|
||||||
|
fprintf(stderr, "Attempting to perform ROR shift on non-logic register data processing instruction!\n");
|
||||||
|
}
|
||||||
|
src2Val = truncateValue(src2Val >> shiftAmount | src2Val << (getMSBPos(regType) - shiftAmount), regType);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Attempting to execute arithmetic/logic register data processing instruction with invalid shift type!\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Negate second operand if negShiftedSrc2 flag is enabled
|
||||||
|
if (arithmLogicData->negShiftedSrc2) {
|
||||||
|
src2Val = truncateValue(~src2Val, regType);
|
||||||
|
}
|
||||||
|
|
||||||
|
dword result;
|
||||||
|
switch(arithmLogicData->type) {
|
||||||
|
|
||||||
|
case a64inst_DPR_ARITHM:
|
||||||
|
switch(inst->data.DPRegisterData.processOp) {
|
||||||
|
|
||||||
|
case(a64inst_ADDS):
|
||||||
|
result = src1Val + src2Val;
|
||||||
|
writeRegister(state, dest, regType, result);
|
||||||
|
|
||||||
|
updateCondNZ(state, result, regType);
|
||||||
|
state->conditionCodes.Overflow = max(src1Val, src2Val) > result;
|
||||||
|
state->conditionCodes.Carry = state->conditionCodes.Overflow;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case(a64inst_ADD):
|
||||||
|
writeRegister(state, dest, regType, src1Val + src2Val);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case(a64inst_SUBS):
|
||||||
|
result = src1Val - src2Val;
|
||||||
|
writeRegister(state, dest, regType, result);
|
||||||
|
|
||||||
|
updateCondNZ(state, result, regType);
|
||||||
|
state->conditionCodes.Overflow = getMSB(src1Val, regType) != getMSB(src2Val, regType) && getMSB(src1Val, regType) != getMSB(result, regType);
|
||||||
|
state->conditionCodes.Carry = src1Val >= src2Val;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case(a64inst_SUB):
|
||||||
|
writeRegister(state, dest, regType, src1Val - src2Val);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Unknown opcode detected!
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Unknown opcode detected in a DPI arithmetic instruction!\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case a64inst_DPR_LOGIC:
|
||||||
|
switch(inst->data.DPRegisterData.processOp) {
|
||||||
|
|
||||||
|
case a64inst_AND:
|
||||||
|
writeRegister(state, dest, regType, src1Val & src2Val);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case a64inst_OR:
|
||||||
|
writeRegister(state, dest, regType, src1Val | src2Val);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case a64inst_XOR:
|
||||||
|
writeRegister(state, dest, regType, src1Val ^ src2Val);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case a64inst_AND_FLAGGED:;
|
||||||
|
result = src1Val & src2Val;
|
||||||
|
writeRegister(state, dest, regType, result);
|
||||||
|
state->conditionCodes.Overflow = 0;
|
||||||
|
state->conditionCodes.Carry = 0;
|
||||||
|
updateCondNZ(state, result, regType);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Attempting to execute an instruction with an unknown DPR arithmetic or logic subtype!\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Execute a multiply register data processing instruction
|
||||||
|
case a64inst_DPR_MULTIPLY:
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Unknown instruction detected!
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Attempting to execute instruction with unknown DPR operand type!\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void execute(Machine *state, a64inst_instruction *inst) {
|
||||||
|
|
||||||
|
switch (inst->type) {
|
||||||
|
|
||||||
|
// Halt the program
|
||||||
|
case a64inst_HALT:
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Execute a data processing immediate instruction
|
||||||
|
case a64inst_DPIMMEDIATE:
|
||||||
|
executeDPImmediate(state, inst);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Execute a branch instruction
|
||||||
|
case a64inst_BRANCH:
|
||||||
|
execute_Branch(state, inst);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Execute a data processing register instruction
|
||||||
|
case a64inst_DPREGISTER:
|
||||||
|
if (inst->data.DPRegisterData.DPROpType == a64inst_DPR_MULTIPLY)
|
||||||
|
executeMultiply(state, inst);
|
||||||
|
else
|
||||||
|
executeDPRegister(state, inst);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case a64inst_SINGLETRANSFER:
|
||||||
|
execute_SDT(state, inst);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Unknown instruction
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void execute_SDT(Machine *state, a64inst_instruction *inst) {
|
||||||
|
word address;
|
||||||
|
bool isLoad;
|
||||||
|
if (inst->data.SingleTransferData.SingleTransferOpType == a64inst_SINGLE_TRANSFER_LOAD_LITERAL) {
|
||||||
|
// Load Literal
|
||||||
|
isLoad = true;
|
||||||
|
address = state->pc + inst->data.SingleTransferData.processOpData.loadLiteralData.offset * 4;
|
||||||
|
} else {
|
||||||
|
address = state->registers[inst->data.SingleTransferData.processOpData.singleDataTransferData.base];
|
||||||
|
isLoad = inst->data.SingleTransferData.processOpData.singleDataTransferData.transferType == a64inst_LOAD;
|
||||||
|
switch (inst->data.SingleTransferData.processOpData.singleDataTransferData.addressingMode) {
|
||||||
|
case a64inst_UNSIGNED_OFFSET:
|
||||||
|
address += inst->data.SingleTransferData.processOpData.singleDataTransferData.a64inst_addressingModeData.unsignedOffset * (inst->data.SingleTransferData.regType == a64inst_W ? 4 : 8);
|
||||||
|
break;
|
||||||
|
case a64inst_REGISTER_OFFSET:
|
||||||
|
address += state->registers[inst->data.SingleTransferData.processOpData.singleDataTransferData.a64inst_addressingModeData.offsetReg];
|
||||||
|
break;
|
||||||
|
case a64inst_PRE_INDEXED:
|
||||||
|
address += inst->data.SingleTransferData.processOpData.singleDataTransferData.a64inst_addressingModeData.indexedOffset;
|
||||||
|
state->registers[inst->data.SingleTransferData.processOpData.singleDataTransferData.base] = address;
|
||||||
|
break;
|
||||||
|
case a64inst_POST_INDEXED:
|
||||||
|
state->registers[inst->data.SingleTransferData.processOpData.singleDataTransferData.base] = address + inst->data.SingleTransferData.processOpData.singleDataTransferData.a64inst_addressingModeData.indexedOffset;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLoad) {
|
||||||
|
if (inst->data.SingleTransferData.regType == a64inst_W) {
|
||||||
|
// 32 bit access
|
||||||
|
state->registers[inst->data.SingleTransferData.target] = readWord(state->memory, address);
|
||||||
|
} else {
|
||||||
|
state->registers[inst->data.SingleTransferData.target] = readDoubleWord(state->memory, address);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*(word *)(state->memory + address) = state->registers[inst->data.SingleTransferData.target];
|
||||||
|
|
||||||
|
// Update base register if post indexed
|
||||||
|
if (inst->data.SingleTransferData.processOpData.singleDataTransferData.addressingMode == a64inst_POST_INDEXED) {
|
||||||
|
writeRegister(state, inst->data.SingleTransferData.processOpData.singleDataTransferData.base, inst->data.SingleTransferData.regType == a64inst_W, address + inst->data.SingleTransferData.processOpData.singleDataTransferData.a64inst_addressingModeData.indexedOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isConditionMet(Machine* state, a64inst_ConditionType cond) {
|
||||||
|
switch(cond) {
|
||||||
|
case EQ:
|
||||||
|
return state->conditionCodes.Zero;
|
||||||
|
case NE:
|
||||||
|
return !state->conditionCodes.Zero;
|
||||||
|
case GE:
|
||||||
|
return state->conditionCodes.Negative == state->conditionCodes.Overflow;
|
||||||
|
case LT:
|
||||||
|
return state->conditionCodes.Negative != state->conditionCodes.Overflow;
|
||||||
|
case GT:
|
||||||
|
return !state->conditionCodes.Zero && (state->conditionCodes.Negative == state->conditionCodes.Overflow);
|
||||||
|
case LE:
|
||||||
|
return state->conditionCodes.Zero || (state->conditionCodes.Negative != state->conditionCodes.Overflow);
|
||||||
|
case AL:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Unknown condition specified!\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void execute_Branch(Machine *state, a64inst_instruction *inst) {
|
||||||
|
switch (inst->data.BranchData.BranchType) {
|
||||||
|
case a64inst_UNCONDITIONAL:
|
||||||
|
state->pc += signExtend(inst->data.BranchData.processOpData.unconditionalData.unconditionalOffset * 4, 26);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case a64inst_REGISTER:
|
||||||
|
state->pc = state->registers[inst->data.BranchData.processOpData.registerData.src];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case a64inst_CONDITIONAL:
|
||||||
|
if (isConditionMet(state, inst->data.BranchData.processOpData.conditionalData.cond)) {
|
||||||
|
state->pc += signExtend(inst->data.BranchData.processOpData.conditionalData.offset * 4, 19);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void executeMultiply(Machine *state, a64inst_instruction *inst) {
|
||||||
|
dword product = state->registers[inst->data.DPRegisterData.src1] * state->registers[inst->data.DPRegisterData.src2];
|
||||||
|
dword sum = readRegister(state, inst->data.DPRegisterData.processOpData.multiplydata.summand, inst->data.DPRegisterData.regType) + (inst->data.DPRegisterData.processOpData.multiplydata.negProd ? -product : product);
|
||||||
|
writeRegister(state, inst->data.DPRegisterData.dest, inst->data.DPRegisterData.regType, sum);
|
||||||
|
}
|
||||||
7
src/execute.h
Normal file
7
src/execute.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#ifndef __EXECUTE__
|
||||||
|
#define __EXECUTE__
|
||||||
|
#include "a64instruction.h"
|
||||||
|
#include "emulator.h"
|
||||||
|
|
||||||
|
void execute(Machine *state, a64inst_instruction *inst);
|
||||||
|
#endif
|
||||||
72
src/fileio.c
72
src/fileio.c
@ -1,62 +1,48 @@
|
|||||||
|
#include <assert.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "fileio.h"
|
||||||
|
#include "global.h"
|
||||||
|
|
||||||
//validates inputted charlist as valid filename against expected extension
|
/* Loads a binary file located at filePath to memory, taking up a block of exactly memorySize bytes,
|
||||||
int isValidFileFormat(char filename[], char expectedExtension[]){
|
and returns the starting address of the data. If memorySize is insufficient to store the entire file,
|
||||||
int *pointLoc = strrchr(filename, '.');
|
an appropriate error is reported. Excess memory is set to 0 bit values. */
|
||||||
|
|
||||||
if(pointLoc != NULL){
|
byte *fileio_loadBin(const char *filePath, size_t memorySize) {
|
||||||
if(strcmp(pointLoc, expectedExtension)==0){
|
FILE *file = fopen(filePath, "rb");
|
||||||
return(1);
|
if (file == NULL) {
|
||||||
}
|
fprintf(stderr, "Couldn't open %s!\n", filePath);
|
||||||
}
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
//writes a list of words (list of binary instructions) to a named output file
|
|
||||||
int writeBinaryFile(word instrs[], char outputFile[]){
|
|
||||||
|
|
||||||
if (!isValidFileFormat(filename, "bin")){
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE *fp;
|
byte *fileData = malloc(memorySize);
|
||||||
|
if (fileData == NULL) {
|
||||||
fp = fopen(outputFile, "wb");
|
fprintf(stderr, "Ran out of memory attempting to load %s!\n", filePath);
|
||||||
|
|
||||||
if(fp == NULL){
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
fwrite(instrs, sizeof(word), sizeof(instrs), fp);
|
// Loop while reading from the file yields data. Only terminates if EOF is reached or ERROR occurs.
|
||||||
fclose(fp);
|
// Explicitly deal with attempting to write too much data to memory block, rather than allow segfault.
|
||||||
|
const size_t byteCount = memorySize/sizeof(byte);
|
||||||
exit(EXIT_SUCCESS);
|
int i = 0;
|
||||||
}
|
while (fread(fileData + i, sizeof(byte), 1, file)) {
|
||||||
|
if (i >= byteCount) {
|
||||||
|
fprintf(stderr, "Attempting to load binary %s to memory of smaller size %zu!\n", filePath, memorySize);
|
||||||
//reads assembly file of "inputFile" name, and passes
|
|
||||||
//each line into a parser
|
|
||||||
//TODO: allocate whole file in memory, line-by-line
|
|
||||||
int readAssemblyFile(char inputFile[]) {
|
|
||||||
if (!isValidFileFormat(filename, "s")){
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE *fp;
|
i++;
|
||||||
char savedLine[sizeof(a64inst_instruction)];
|
}
|
||||||
|
|
||||||
fp = fopen(inputFile, "r");
|
if (ferror(file)) {
|
||||||
|
fprintf(stderr, "Encountered error attempting to read %s!\n", filePath);
|
||||||
if(fp == NULL){
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
assert(fclose(file) != EOF);
|
||||||
|
|
||||||
while (fgets(savedLine, MAX_ASM_LINE_LENGTH-1, fp) != NULL) {
|
// If part of memory block was left uninitialized, initialize it to zero.
|
||||||
// removes newline char before saving them
|
if (i < byteCount) {
|
||||||
savedLine[strcspn(savedLine, "\n")] = 0;
|
memset(fileData + i, 0, (byteCount - i) * sizeof(byte));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
return fileData;
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
}
|
||||||
9
src/fileio.h
Normal file
9
src/fileio.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#ifndef __FILEIO__
|
||||||
|
#define __FILEIO__
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "global.h"
|
||||||
|
|
||||||
|
#define EXIT_FAILURE 1
|
||||||
|
|
||||||
|
extern byte *fileio_loadBin(const char *filePath, size_t memorySize);
|
||||||
|
#endif
|
||||||
@ -11,6 +11,8 @@
|
|||||||
|
|
||||||
// Number of General Purpose Registers.
|
// Number of General Purpose Registers.
|
||||||
#define REGISTER_COUNT 31
|
#define REGISTER_COUNT 31
|
||||||
|
// Register identifier interpreted as the 'zero register'
|
||||||
|
#define ZERO_REGISTER 31
|
||||||
// Size of the memory in bytes.
|
// Size of the memory in bytes.
|
||||||
#define MEMORY_SIZE 2097152
|
#define MEMORY_SIZE 2097152
|
||||||
// Length of the memory address in bits.
|
// Length of the memory address in bits.
|
||||||
|
|||||||
58
src/print.c
Normal file
58
src/print.c
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "print.h"
|
||||||
|
#include "emulator.h"
|
||||||
|
|
||||||
|
#define UNSET_CONDITION_CODE_CHAR '-'
|
||||||
|
|
||||||
|
// Prints the current machine state into the provided stream
|
||||||
|
void printState(Machine *state, FILE *stream) {
|
||||||
|
printRegisters(state, stream);
|
||||||
|
printMemory(state, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints the current machine registers into the provided stream
|
||||||
|
void printRegisters(Machine *state, FILE *stream) {
|
||||||
|
fprintf(stream, "Registers:\n");
|
||||||
|
for (int i = 0; i < REGISTER_COUNT; i++) {
|
||||||
|
fprintf(stream, "X%02d\t= %016" PRIx64 "\n", i, state->registers[i]);
|
||||||
|
}
|
||||||
|
fprintf(stream, "PC\t= %016" PRIx64 "\n", state->pc);
|
||||||
|
fprintf(stream, "PSTATE\t: %c%c%c%c", state->conditionCodes.Negative ? 'N' : UNSET_CONDITION_CODE_CHAR,
|
||||||
|
state->conditionCodes.Zero ? 'Z' : UNSET_CONDITION_CODE_CHAR,
|
||||||
|
state->conditionCodes.Carry ? 'C' : UNSET_CONDITION_CODE_CHAR,
|
||||||
|
state->conditionCodes.Overflow ? 'V' : UNSET_CONDITION_CODE_CHAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the word starting at the provided address
|
||||||
|
word readWord(byte *memory, uint32_t address) {
|
||||||
|
word result = 0;
|
||||||
|
int bytesPerWord = WORD_BITS / BYTE_BITS - 1;
|
||||||
|
for (int i = 0; i <= bytesPerWord; i++)
|
||||||
|
result |= (word) memory[address + i] << (BYTE_BITS * i);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the double word starting at the provided address
|
||||||
|
dword readDoubleWord(byte *memory, uint32_t address) {
|
||||||
|
dword result = 0;
|
||||||
|
int bytesPerDword = DWORD_BITS / BYTE_BITS - 1;
|
||||||
|
for (int i = 0; i <= bytesPerDword; i++)
|
||||||
|
result |= (dword) memory[address + i] << (BYTE_BITS * i);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints all non-zero memory locations into the provided stream
|
||||||
|
void printMemory(Machine *state, FILE *stream) {
|
||||||
|
fprintf(stream, "\nNon-zero memory:\n");
|
||||||
|
|
||||||
|
// print memory 4 byte aligned
|
||||||
|
for (int addr = 0; addr < MEMORY_SIZE; addr+= 4) {
|
||||||
|
word data = readWord(state->memory, addr);
|
||||||
|
if (data != 0) {
|
||||||
|
fprintf(stream, "0x%08x: %08x\n", addr, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/print.h
Normal file
12
src/print.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#ifndef __PRINT__
|
||||||
|
#define __PRINT__
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "emulator.h"
|
||||||
|
|
||||||
|
word readWord(byte *memory, uint32_t address);
|
||||||
|
dword readDoubleWord(byte *memory, uint32_t address);
|
||||||
|
void printState(Machine *state, FILE *stream);
|
||||||
|
void printRegisters(Machine *state, FILE *stream);
|
||||||
|
void printMemory(Machine *state, FILE *stream);
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -19,9 +19,15 @@ struct st {
|
|||||||
// add new node to the end
|
// add new node to the end
|
||||||
void st_add(st table, void* key, void* value) {
|
void st_add(st table, void* key, void* value) {
|
||||||
node n = {key, value, table.tail};
|
node n = {key, value, table.tail};
|
||||||
|
if (table.head == NULL) {
|
||||||
|
table.head = &n;
|
||||||
|
table.tail = &n;
|
||||||
|
}
|
||||||
|
else {
|
||||||
(*(table.tail)).next = &n;
|
(*(table.tail)).next = &n;
|
||||||
table.tail = &n;
|
table.tail = &n;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// returns the pointer to key of the specified node, or null, if it does not exist
|
// returns the pointer to key of the specified node, or null, if it does not exist
|
||||||
void* st_search(st table, void* key) {
|
void* st_search(st table, void* key) {
|
||||||
@ -1,15 +1,8 @@
|
|||||||
|
# include "global.h"
|
||||||
|
# include "a64instruction.h"
|
||||||
|
# include "symboltable.h"
|
||||||
//generates assembled code based on two pass assembly method
|
//generates assembled code based on two pass assembly method
|
||||||
|
|
||||||
void generateSymbolTable(a64inst_instruction instrs[], int numInstrs){
|
|
||||||
//TODO:
|
|
||||||
//generate symbol table based on inputted assembly code and labels
|
|
||||||
for(int i=0; i<numInstrs; i++){
|
|
||||||
// discuss defining a LABEL type
|
|
||||||
if(instrs[i]->type==LABEL){
|
|
||||||
// symbol table stuff here
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
word assembleBranch(a64inst_instruction *instr, int ){
|
word assembleBranch(a64inst_instruction *instr, int ){
|
||||||
word binInstr = 0;
|
word binInstr = 0;
|
||||||
@ -39,15 +32,192 @@ word assembleBranch(a64inst_instruction *instr, int ){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void firstPass(a64inst_instruction instrs[], int numInstrs){
|
st* firstPass(a64inst_instruction instrs[], int numInstrs){
|
||||||
//TODO:
|
//TODO:
|
||||||
// -iterate over instructions, adding to symbol table
|
// -iterate over instructions, adding to symbol table
|
||||||
// create symbol table and map labels to addresses/lines
|
// create symbol table and map labels to addresses/lines
|
||||||
|
struct st table;
|
||||||
|
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 dpi(a64inst_instruction cI) {
|
||||||
|
word out = 0;
|
||||||
|
a64inst_DPImmediateData data = cI.data.DPImmediateData;
|
||||||
|
//sf
|
||||||
|
out += data.regType*(2^31);
|
||||||
|
out += data.processOp*(2^29);
|
||||||
|
out += 2^28;
|
||||||
|
// if arithmetic
|
||||||
|
if (data.DPIOpType == a64inst_DPI_ARITHM) {
|
||||||
|
out += 2^24;
|
||||||
|
// shift
|
||||||
|
if (data.processOpData.arithmData.shiftImmediate){
|
||||||
|
out += 2^22;
|
||||||
|
}
|
||||||
|
out += data.processOpData.arithmData.immediate*(2^10);
|
||||||
|
out += data.processOpData.arithmData.src*(2^5);
|
||||||
|
}
|
||||||
|
// if wide move
|
||||||
|
else {
|
||||||
|
out += 5*(2^23);
|
||||||
|
// hw
|
||||||
|
out += data.processOpData.wideMovData.shiftScalar*(2^21);
|
||||||
|
out += data.processOpData.wideMovData.immediate*(2^5);
|
||||||
|
}
|
||||||
|
// destination register
|
||||||
|
out += data.dest;
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
void secondPass(a64inst_instruction instrs[], int numInstrs){
|
word dpr(a64inst_instruction cI) {
|
||||||
|
word out = 0;
|
||||||
|
a64inst_DPRegisterData data = cI.data.DPRegisterData;
|
||||||
|
// sf
|
||||||
|
int sf = data.regType;
|
||||||
|
// bits 27-25
|
||||||
|
out += 5*(2^25);
|
||||||
|
int m = data.DPROpType;
|
||||||
|
int opc = 0;
|
||||||
|
int opr = 0;
|
||||||
|
int rm = 0;
|
||||||
|
int operand = 0;
|
||||||
|
int rn = 0;
|
||||||
|
int rd = 0;
|
||||||
|
// multiply
|
||||||
|
if (m == 1) {
|
||||||
|
//opc = 0;
|
||||||
|
opr = 8;
|
||||||
|
if (data.processOpData.multiplydata.negProd) {
|
||||||
|
operand += 32;
|
||||||
|
}
|
||||||
|
operand += data.processOpData.multiplydata.summand;
|
||||||
|
}
|
||||||
|
// arithmetic and logical
|
||||||
|
else {
|
||||||
|
// shift
|
||||||
|
opr += 2*data.processOpData.arithmLogicData.shiftType;
|
||||||
|
// arithmetic
|
||||||
|
if (data.processOpData.arithmLogicData.type == 1){
|
||||||
|
opr += 8;
|
||||||
|
}
|
||||||
|
// logical
|
||||||
|
else {
|
||||||
|
if (data.processOpData.arithmLogicData.negShiftedSrc2) {
|
||||||
|
opr += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
operand += data.processOpData.arithmLogicData.shiftAmount;
|
||||||
|
}
|
||||||
|
rm += data.src1;
|
||||||
|
rn += data.src2;
|
||||||
|
rd += data.dest;
|
||||||
|
out += sf*(2^31);
|
||||||
|
out += opc * (2^29);
|
||||||
|
out += m* (2^28);
|
||||||
|
out += opr * (2^21);
|
||||||
|
out += rm * (2^16);
|
||||||
|
out += operand * 1024;
|
||||||
|
out += rn * 32;
|
||||||
|
out += rd;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
word sts(a64inst_instruction cI) {
|
||||||
|
a64inst_SingleTransferData data = cI.data.SingleTransferData;
|
||||||
|
word out = 0;
|
||||||
|
a64inst_SingleDataTransferData data2 = data.processOpData.singleDataTransferData;
|
||||||
|
// this deals with every bit in the 31-23 range apart from sf and U
|
||||||
|
out += (512+128+64+32)*(2^23);
|
||||||
|
int sf = data.regType;
|
||||||
|
int u = 0;
|
||||||
|
int l = data2.transferType;
|
||||||
|
int offset = 0;
|
||||||
|
int xn = data2.base;
|
||||||
|
int rt = data.target;
|
||||||
|
switch (data2.addressingMode) {
|
||||||
|
// register offset
|
||||||
|
case 2:
|
||||||
|
offset += 2074 + 64*data2.a64inst_addressingModeData.offsetReg;
|
||||||
|
break;
|
||||||
|
// unsigned offset
|
||||||
|
case 3:
|
||||||
|
offset += data2.a64inst_addressingModeData.unsignedOffset;
|
||||||
|
u = 1;
|
||||||
|
break;
|
||||||
|
// pre/post indexed
|
||||||
|
default:
|
||||||
|
offset = 1 + data2.addressingMode*2 + data2.a64inst_addressingModeData.indexedOffset*4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
out += sf*(2^30);
|
||||||
|
out += u*(2^22);
|
||||||
|
out += offset*1024;
|
||||||
|
out += xn * 32;
|
||||||
|
out += rt;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
word ldl(a64inst_instruction cI) {
|
||||||
|
word out = 3*(2^27);
|
||||||
|
a64inst_SingleTransferData data = cI.data.SingleTransferData;
|
||||||
|
int sf = data.regType;
|
||||||
|
int simm19 = data.processOpData.loadLiteralData.offset;
|
||||||
|
int rt = data.target;
|
||||||
|
out += sf * (2^30);
|
||||||
|
out += simm19*32;
|
||||||
|
out += rt;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void secondPass(a64inst_instruction instrs[], int numInstrs, st* table, word arr[]){
|
||||||
//TODO:
|
//TODO:
|
||||||
// iterate over instructions again, this time replacing labels
|
// iterate over instructions again, this time replacing labels
|
||||||
// with values from symbol table
|
// with values from symbol table
|
||||||
// after a line has had all the values replaced, assemble it and append
|
// after a line has had all the values replaced, assemble it and append
|
||||||
|
int index = 0;
|
||||||
|
int lbl = 0;
|
||||||
|
for (int i=0; i<numInstrs; i++) {
|
||||||
|
a64inst_instruction cI = instrs[i];
|
||||||
|
switch (cI.type) {
|
||||||
|
case a64inst_DPIMMEDIATE:
|
||||||
|
arr[index] = dpi(cI);
|
||||||
|
index++;
|
||||||
|
break;
|
||||||
|
case a64inst_DPREGISTER:
|
||||||
|
arr[index] = dpr(cI);
|
||||||
|
index++;
|
||||||
|
break;
|
||||||
|
case a64inst_SINGLETRANSFER:
|
||||||
|
arr[index] = sts(cI);
|
||||||
|
index++;
|
||||||
|
break;
|
||||||
|
case a64inst_LOADLITERAL:
|
||||||
|
arr[index] = ldl(cI);
|
||||||
|
index++;
|
||||||
|
break;
|
||||||
|
case a64inst_DIRECTIVE:
|
||||||
|
arr[index] = cI.data.DirectiveData.value;
|
||||||
|
index++;
|
||||||
|
break;
|
||||||
|
case a64inst_HALT:
|
||||||
|
arr[index] = 69*(2^25);
|
||||||
|
index++;
|
||||||
|
break;
|
||||||
|
case a64inst_LABEL:
|
||||||
|
lbl++;
|
||||||
|
break;
|
||||||
|
case a64inst_BRANCH:
|
||||||
|
arr[index] = assembleBranch(&cI, table, lbl);
|
||||||
|
index++;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
24
test.sh
Normal file
24
test.sh
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
echo "Trying to compile the program..."
|
||||||
|
make -C src
|
||||||
|
|
||||||
|
echo "Fetching the test suite..."
|
||||||
|
git clone https://gitlab.doc.ic.ac.uk/teaching-fellows/armv8_testsuite.git
|
||||||
|
mkdir armv8_testsuite/solution
|
||||||
|
cp -R src/. ./armv8_testsuite/solution
|
||||||
|
cd armv8_testsuite
|
||||||
|
python3 -m pip install -r requirements.txt
|
||||||
|
./install
|
||||||
|
|
||||||
|
echo "Running the test suite..."
|
||||||
|
./run -s
|
||||||
|
|
||||||
|
echo "Test Suite Completed"
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
# printf "%s " "Press enter to continue"
|
||||||
|
# read ans
|
||||||
|
|
||||||
|
echo "Cleaning Up..."
|
||||||
|
make -C src clean
|
||||||
|
rm -rf armv8_testsuite
|
||||||
|
echo "Done"
|
||||||
Loading…
Reference in New Issue
Block a user