From a50bda3703efd666c22d26bf2e72e05a62f8bc30 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Thu, 30 May 2024 13:20:58 +0100 Subject: [PATCH 01/84] Update global, add word and dword --- src/global.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/global.h b/src/global.h index e827bcb..138e11a 100644 --- a/src/global.h +++ b/src/global.h @@ -5,8 +5,8 @@ ******************************************************************************** */ -#ifndef GLOBAL_H -#define GLOBAL_H +#ifndef __GLOBAL__ +#define __GLOBAL__ #include // Number of General Purpose Registers. @@ -18,7 +18,11 @@ // Length of the instruction in bits. #define INSTRUCTION_SIZE 32 -// Define the word type to be a 64-bit unsigned integer. -typedef uint64_t word; +// A byte is an 8-bit unsigned integer in this architecture. +typedef uint8_t byte; +// A word is a 32-bit unsigned integer in this architecture. +typedef uint32_t word; +// Double word is a 64-bit unsigned integer. +typedef uint64_t dword; #endif \ No newline at end of file From de40227d08f47946904a074a9408d35a8a3cbd1b Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Thu, 30 May 2024 14:17:43 +0100 Subject: [PATCH 02/84] Add binary file loading w/ S --- src/fileio.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ src/fileio.h | 9 +++++++++ 2 files changed, 56 insertions(+) create mode 100644 src/fileio.c create mode 100644 src/fileio.h diff --git a/src/fileio.c b/src/fileio.c new file mode 100644 index 0000000..b8c0574 --- /dev/null +++ b/src/fileio.c @@ -0,0 +1,47 @@ +#include +#include +#include +#include "fileio.h" + +/* Loads a binary file located at filePath to memory, taking up a block of exactly memorySize bytes, + and returns the starting address of the data. If memorySize is insufficient to store the entire file, + an appropriate error is reported. Excess memory is set to 0 bit values. */ + +word *fileio_loadBin(const char *filePath, size_t memorySize) { + FILE *file = fopen(filePath, "rb"); + if (file == NULL) { + fprintf(stderr, "Couldn't open %s!\n", filePath); + exit(EXIT_FAILURE); + } + + word *fileData = malloc(memorySize); + if (fileData == NULL) { + fprintf(stderr, "Ran out of memory attempting to load %s!\n", filePath); + exit(EXIT_FAILURE); + } + + // Loop while reading from the file yields data. Only terminates if EOF is reached or ERROR occurs. + // Explicitly deal with attempting to write too much data to memory block, rather than allow segfault. + const size_t wordCount = memorySize/sizeof(word); + int i = 0; + while (fread(fileData + i, sizeof(word), 1, file)) { + if (i >= wordCount) { + fprintf(stderr, "Attempting to load binary %s to memory of smaller size %zu!\n", filePath, memorySize); + exit(EXIT_FAILURE); + } + + i++; + } + + if (ferror(file)) { + fprintf(stderr, "Encountered error attempting to read %s!\n", filePath); + exit(EXIT_FAILURE); + } + assert(fclose(file) != EOF); + + // If part of memory block was left uninitialized, initialize it to zero. + if (i < wordCount) { + memset(fileData + i, 0, (wordCount - i) * sizeof(word)); + } + return fileData; +} diff --git a/src/fileio.h b/src/fileio.h new file mode 100644 index 0000000..8a439bf --- /dev/null +++ b/src/fileio.h @@ -0,0 +1,9 @@ +#ifndef __FILEIO__ +#define __FILEIO__ +#include +#include "global.h" + +#define EXIT_FAILURE 1 + +extern word *fileio_loadBin(const char *filePath, size_t memorySize); +#endif From 41ca0b3ffa99a1194856962c1eb12eefe25e0487 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Thu, 30 May 2024 14:20:31 +0100 Subject: [PATCH 03/84] Update emulate to check args, w/ T --- src/emulate.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/emulate.c b/src/emulate.c index e2ad1c8..3bbb3d7 100755 --- a/src/emulate.c +++ b/src/emulate.c @@ -1,5 +1,23 @@ #include +#include int main(int argc, char **argv) { - return EXIT_SUCCESS; + + // Check the arguments + if (argc == 1) { + fprintf(stderr, "Error: An object file is required. Syntax: ./emulate []"); + 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; + } + } + + + } From e2e97bbff963085427ffa2160d5cb44a56c481e6 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Thu, 30 May 2024 14:43:07 +0100 Subject: [PATCH 04/84] Add data types for internal instructions w/ S --- src/a64instruction.h | 21 ++++++++++++ src/a64instruction_DPImmediate.h | 57 ++++++++++++++++++++++++++++++++ src/a64instruction_global.h | 4 +++ 3 files changed, 82 insertions(+) create mode 100644 src/a64instruction.h create mode 100644 src/a64instruction_DPImmediate.h create mode 100644 src/a64instruction_global.h diff --git a/src/a64instruction.h b/src/a64instruction.h new file mode 100644 index 0000000..aaab669 --- /dev/null +++ b/src/a64instruction.h @@ -0,0 +1,21 @@ +#include "a64instruction_DPImmediate.h" + +// 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). +typedef enum { + a64inst_DPImmediate, + a64inst_DPRegister, + a64inst_SingleTransfer, + a64inst_LoadLiteral, + a64inst_Branch, + a64inst_Halt +} a64inst_type; + + +// Structure the holds the type and operand data of an instruction +typedef struct { + a64inst_type type; + union { + a64inst_DPImmediateData DPImmediateData; + } data; +} a64inst_instruction; diff --git a/src/a64instruction_DPImmediate.h b/src/a64instruction_DPImmediate.h new file mode 100644 index 0000000..b504772 --- /dev/null +++ b/src/a64instruction_DPImmediate.h @@ -0,0 +1,57 @@ +#include +#include "a64instruction_global.h" + +// Denotes the type of data processing operation +typedef enum { + a64inst_arithm, + a64inst_wideMov +} a64inst_DPIOpType; + +// Denotes the type of register being referred to +typedef enum { + a64inst_W = 0, + a64inst_R = 1 +} a64inst_regType; + +// Denotes the type of arithmetic operations supported by the architecture +typedef enum { + a64inst_add = 0, + a64inst_adds = 1, + a64inst_sub = 2, + a64inst_subs = 3 +} a64inst_arithmOp; + +// Denotes the type of wide move operations supported by the architecture +typedef enum { + a64inst_movn = 0, + a64inst_undefined = 1, + a64inst_movz = 2, + a64inst_movk = 3 +} a64inst_wideMovOp; + +// Holds data specific to arithmetic data processing instructions +typedef struct { + bool shiftImmediate; + uint16_t immediate; + a64inst_regSpecifier src; +} a64inst_DPImmediate_ArithmData; + +// Holds data specific to wide move data processing instructions +typedef struct { + int x; //TEMPORARY FOR COMPILATION! +} a64inst_DPImmediate_WideMovData; + +// Holds data for immediate data processing instructions +typedef struct { + a64inst_DPIOpType DPIOpType; + a64inst_regType regType; + union { + a64inst_arithmOp arithmOp; + a64inst_wideMovOp movOp; + } processOpId; + union { + a64inst_DPImmediate_ArithmData arithmData; + a64inst_DPImmediate_WideMovData wideMovData; + } processOpData; + a64inst_regSpecifier dest; +} a64inst_DPImmediateData; diff --git a/src/a64instruction_global.h b/src/a64instruction_global.h new file mode 100644 index 0000000..421a838 --- /dev/null +++ b/src/a64instruction_global.h @@ -0,0 +1,4 @@ +#include + +// Specifies the register being referred to +typedef uint8_t a64inst_regSpecifier; From 4b10d18e268eac22b827eb22bd88df75044599fb Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Thu, 30 May 2024 14:57:36 +0100 Subject: [PATCH 05/84] Add helper getBits() for decode w/ S --- src/decode.c | 26 ++++++++++++++++++++++++++ src/decode.h | 4 ++++ 2 files changed, 30 insertions(+) create mode 100644 src/decode.c create mode 100644 src/decode.h diff --git a/src/decode.c b/src/decode.c new file mode 100644 index 0000000..f258122 --- /dev/null +++ b/src/decode.c @@ -0,0 +1,26 @@ +#include +#include +#include +#include "decode.h" + +#define BYTE_BITS 8 + +// 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 < BYTE_BITS); + + wrd &= (1 << msb) - 1; + return wrd >> lsb; +} + +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); + } +} diff --git a/src/decode.h b/src/decode.h new file mode 100644 index 0000000..75f2655 --- /dev/null +++ b/src/decode.h @@ -0,0 +1,4 @@ +#include "global.h" +#include "a64instruction.h" + +a64inst_instruction *decode(word w); \ No newline at end of file From 74bf3ed910c596a5d70f29c6561262f15b87f989 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Thu, 30 May 2024 15:02:00 +0100 Subject: [PATCH 06/84] Add emulate constants and machine state, w/ T --- src/decode.c | 2 -- src/emulator.h | 24 ++++++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 src/emulator.h diff --git a/src/decode.c b/src/decode.c index f258122..a1f7819 100644 --- a/src/decode.c +++ b/src/decode.c @@ -3,8 +3,6 @@ #include #include "decode.h" -#define BYTE_BITS 8 - // 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) { diff --git a/src/emulator.h b/src/emulator.h new file mode 100644 index 0000000..b4ea4bf --- /dev/null +++ b/src/emulator.h @@ -0,0 +1,24 @@ +#include "global.h" + +/************************************ + * DEFINITIONS + ************************************/ + #define BYTE_BITS 8 + +/************************************ + * STRUCTS + ************************************/ + +typedef struct { + bool Negative; + bool Zero; + bool Carry; + bool Overflow; +} PState; + +typedef struct { + word registers[REGISTER_COUNT]; + word pc; + byte memory[MEMORY_SIZE]; + PState conditionCodes; +} Machine; \ No newline at end of file From c07cbd12c98ccfc46d5ef9758faf1426746b4693 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Thu, 30 May 2024 15:05:11 +0100 Subject: [PATCH 07/84] Move BYTE_BITS definition to decode.h, w/ T --- src/decode.h | 2 ++ src/emulator.h | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/decode.h b/src/decode.h index 75f2655..a76bcdd 100644 --- a/src/decode.h +++ b/src/decode.h @@ -1,4 +1,6 @@ #include "global.h" #include "a64instruction.h" +#define BYTE_BITS 8 + a64inst_instruction *decode(word w); \ No newline at end of file diff --git a/src/emulator.h b/src/emulator.h index b4ea4bf..34601ea 100644 --- a/src/emulator.h +++ b/src/emulator.h @@ -3,7 +3,6 @@ /************************************ * DEFINITIONS ************************************/ - #define BYTE_BITS 8 /************************************ * STRUCTS From 497cd7ce3b5c09b9fce9f624a7015e65b18c2953 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Thu, 30 May 2024 15:21:24 +0100 Subject: [PATCH 08/84] Add instruction type classification to decode, w/ T --- src/decode.c | 19 +++++++++++++++++++ src/decode.h | 7 +++++++ 2 files changed, 26 insertions(+) diff --git a/src/decode.c b/src/decode.c index a1f7819..77c47b7 100644 --- a/src/decode.c +++ b/src/decode.c @@ -21,4 +21,23 @@ a64inst_instruction *decode(word wrd) { fprintf(stderr, "Ran out of memory while attempting to decode an instruction!\n"); exit(1); } + + word DPImmFlag = getBits(wrd, DATA_PROCESSING_DPIMM_LSB, DATA_PROCESSING_DPIMM_MSB); + if (wrd == HALT_WORD) { + inst->type = a64inst_Halt; + + } else if (DPImmFlag == 0) { + inst->type = a64inst_DPImmediate; + + }else if (DPImmFlag == 1) { + inst->type = a64inst_Branch; + + } else if (getBits(wrd, DATA_PROCESSING_DPReg_LSB, DATA_PROCESSING_DPReg_MSB) == 1) { + inst->type = a64inst_DPRegister; + + } else { + // Load and Store, or unknown + } + + } diff --git a/src/decode.h b/src/decode.h index a76bcdd..c24c235 100644 --- a/src/decode.h +++ b/src/decode.h @@ -2,5 +2,12 @@ #include "a64instruction.h" #define BYTE_BITS 8 +#define HALT_WORD 0x8a000000 + +#define DATA_PROCESSING_DPIMM_LSB 26 +#define DATA_PROCESSING_DPIMM_MSB 29 + +#define DATA_PROCESSING_DPReg_LSB 25 +#define DATA_PROCESSING_DPReg_MSB 26 a64inst_instruction *decode(word w); \ No newline at end of file From 94815c838cecaa84d15599dd54f5125fb1645fdc Mon Sep 17 00:00:00 2001 From: sBubshait Date: Thu, 30 May 2024 15:24:28 +0100 Subject: [PATCH 09/84] Add execute.c, w/ T --- src/execute.c | 23 +++++++++++++++++++++++ src/execute.h | 3 +++ 2 files changed, 26 insertions(+) create mode 100644 src/execute.c create mode 100644 src/execute.h diff --git a/src/execute.c b/src/execute.c new file mode 100644 index 0000000..e1ebbf9 --- /dev/null +++ b/src/execute.c @@ -0,0 +1,23 @@ +#include "execute.h" + +void execute(a64inst_instruction inst) { + + switch (inst.type) { + case a64inst_Halt: + // Halt the program + break; + case a64inst_DPImmediate: + // Execute a data processing immediate instruction + break; + case a64inst_Branch: + // Execute a branch instruction + break; + case a64inst_DPRegister: + // Execute a data processing register instruction + break; + default: + // Unknown instruction + break; + } + +} \ No newline at end of file diff --git a/src/execute.h b/src/execute.h new file mode 100644 index 0000000..fd9da37 --- /dev/null +++ b/src/execute.h @@ -0,0 +1,3 @@ +#include "a64instruction.h" + +void execute(a64inst_instruction inst); \ No newline at end of file From 3ce2d8d0f276a6d2727daaa29930b248abef8945 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Fri, 31 May 2024 16:46:59 +0100 Subject: [PATCH 10/84] Add Branch internal structure, w/ T --- src/a64instruction_Branch.h | 41 +++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/a64instruction_Branch.h diff --git a/src/a64instruction_Branch.h b/src/a64instruction_Branch.h new file mode 100644 index 0000000..1681768 --- /dev/null +++ b/src/a64instruction_Branch.h @@ -0,0 +1,41 @@ +#include +#include "a64instruction_global.h" +#include "global.h" + +typedef enum { + a64inst_UNCONDITIONAL = 0, + a64inst_REGISTER = 1, + a64inst_CONDITIONAL = 2 +} a64inst_BranchType; + +typedef struct { + word unconditionalOffset; +} a64inst_Branch_UnconditionalData; + +typedef struct { + a64inst_regSpecifier src; +} a64inst_Branch_RegisterData; + +typedef enum { + EQ = 0, // Equal + NE = 1, // Not Equal + GE = 10, // Signed greater or equal + LT = 11, // Signed less than + GT = 12, // Signed greater than + LE = 13, // signed less than or equal + AL = 14 // Always +} a64inst_ConditionType; //a64inst_Branch_ConditionType? + +typedef struct { + a64inst_ConditionType cond; + word offset; +} a64inst_Branch_ConditionalData; + +typedef struct { + a64inst_BranchType BranchType; + union { + a64inst_Branch_UnconditionalData unconditionalData; + a64inst_Branch_RegisterData registerData; + a64inst_Branch_ConditionalData conditionalData; + } processOpData; +} a64inst_BranchData; From d4ff1ee40e2a322e9f835d02ad3ba8d8f05d64aa Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Fri, 31 May 2024 17:11:43 +0100 Subject: [PATCH 11/84] Update instruction enums to capital w/ S --- src/a64instruction.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/a64instruction.h b/src/a64instruction.h index aaab669..f0f617f 100644 --- a/src/a64instruction.h +++ b/src/a64instruction.h @@ -1,21 +1,21 @@ #include "a64instruction_DPImmediate.h" - +#include "a64instruction_Branch.h" // 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). typedef enum { - a64inst_DPImmediate, - a64inst_DPRegister, - a64inst_SingleTransfer, - a64inst_LoadLiteral, - a64inst_Branch, - a64inst_Halt + a64inst_DPIMMEDIATE, + a64inst_DPREGISTER, + a64inst_SINGLETRANSFER, + a64inst_LOADLITERAL, + a64inst_BRANCH, + a64inst_HALT } a64inst_type; - // Structure the holds the type and operand data of an instruction typedef struct { a64inst_type type; union { a64inst_DPImmediateData DPImmediateData; + a64inst_BranchData BranchData; } data; } a64inst_instruction; From 2e0668aefdbf508c2c739b3d15326dd450346d24 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Fri, 31 May 2024 17:13:42 +0100 Subject: [PATCH 12/84] Update decode fix capitalisation, w/ T --- src/decode.c | 10 +++++----- src/decode.h | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/decode.c b/src/decode.c index 77c47b7..9ee999d 100644 --- a/src/decode.c +++ b/src/decode.c @@ -24,16 +24,16 @@ a64inst_instruction *decode(word wrd) { word DPImmFlag = getBits(wrd, DATA_PROCESSING_DPIMM_LSB, DATA_PROCESSING_DPIMM_MSB); if (wrd == HALT_WORD) { - inst->type = a64inst_Halt; + inst->type = a64inst_HALT; } else if (DPImmFlag == 0) { - inst->type = a64inst_DPImmediate; + inst->type = a64inst_DPIMMEDIATE; }else if (DPImmFlag == 1) { - inst->type = a64inst_Branch; + inst->type = a64inst_BRANCH; - } else if (getBits(wrd, DATA_PROCESSING_DPReg_LSB, DATA_PROCESSING_DPReg_MSB) == 1) { - inst->type = a64inst_DPRegister; + } else if (getBits(wrd, DATA_PROCESSING_DPREG_LSB, DATA_PROCESSING_DPREG_MSB) == 1) { + inst->type = a64inst_DPREGISTER; } else { // Load and Store, or unknown diff --git a/src/decode.h b/src/decode.h index c24c235..7eaa2fa 100644 --- a/src/decode.h +++ b/src/decode.h @@ -7,7 +7,7 @@ #define DATA_PROCESSING_DPIMM_LSB 26 #define DATA_PROCESSING_DPIMM_MSB 29 -#define DATA_PROCESSING_DPReg_LSB 25 -#define DATA_PROCESSING_DPReg_MSB 26 +#define DATA_PROCESSING_DPREG_LSB 25 +#define DATA_PROCESSING_DPREG_MSB 26 a64inst_instruction *decode(word w); \ No newline at end of file From 34eee8599e6896f187739d2a41ddb9e17aaa358b Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Fri, 31 May 2024 17:25:51 +0100 Subject: [PATCH 13/84] Move register type struct to global header w/ S --- src/a64instruction_global.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/a64instruction_global.h b/src/a64instruction_global.h index 421a838..489fe06 100644 --- a/src/a64instruction_global.h +++ b/src/a64instruction_global.h @@ -1,4 +1,14 @@ +#ifndef __A64INSTRUCTION_GLOBAL__ +#define __A64INSTRUCTION_GLOBAL__ #include // Specifies the register being referred to typedef uint8_t a64inst_regSpecifier; + +// Denotes the type of register being referred to +typedef enum { + a64inst_W = 0, + a64inst_R = 1 +} a64inst_regType; + +#endif From d6148f6d34854cb5456b9f500312748669ab61f5 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Fri, 31 May 2024 17:30:19 +0100 Subject: [PATCH 14/84] Add data structure for DP instructions w/ S --- src/a64instruction_DP.h | 7 ++++ src/a64instruction_DPImmediate.h | 36 +++++++------------- src/a64instruction_DPRegister.h | 58 ++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 24 deletions(-) create mode 100644 src/a64instruction_DP.h create mode 100644 src/a64instruction_DPRegister.h diff --git a/src/a64instruction_DP.h b/src/a64instruction_DP.h new file mode 100644 index 0000000..113f589 --- /dev/null +++ b/src/a64instruction_DP.h @@ -0,0 +1,7 @@ +// Denotes the type of arithmetic operations supported by the architecture +typedef enum { + a64inst_ADD = 0, + a64inst_ADDS = 1, + a64inst_SUB = 2, + a64inst_SUBS = 3 +} a64inst_arithmOp; diff --git a/src/a64instruction_DPImmediate.h b/src/a64instruction_DPImmediate.h index b504772..2c02c2f 100644 --- a/src/a64instruction_DPImmediate.h +++ b/src/a64instruction_DPImmediate.h @@ -1,50 +1,38 @@ #include #include "a64instruction_global.h" +#include "a64instruction_DP.h" // Denotes the type of data processing operation typedef enum { - a64inst_arithm, - a64inst_wideMov + a64inst_DPI_ARITHM, + a64inst_DPI_WIDEMOV } a64inst_DPIOpType; -// Denotes the type of register being referred to -typedef enum { - a64inst_W = 0, - a64inst_R = 1 -} a64inst_regType; - -// Denotes the type of arithmetic operations supported by the architecture -typedef enum { - a64inst_add = 0, - a64inst_adds = 1, - a64inst_sub = 2, - a64inst_subs = 3 -} a64inst_arithmOp; - // Denotes the type of wide move operations supported by the architecture typedef enum { - a64inst_movn = 0, - a64inst_undefined = 1, - a64inst_movz = 2, - a64inst_movk = 3 + a64inst_MOVN = 0, + a64inst_UNDEFINED = 1, + a64inst_MOVZ = 2, + a64inst_MOVK = 3 } a64inst_wideMovOp; -// Holds data specific to arithmetic data processing instructions +// Holds data specific to arithmetic immediate data processing instructions typedef struct { bool shiftImmediate; uint16_t immediate; a64inst_regSpecifier src; } a64inst_DPImmediate_ArithmData; -// Holds data specific to wide move data processing instructions +// Holds data specific to wide move immediate data processing instructions typedef struct { - int x; //TEMPORARY FOR COMPILATION! + uint8_t shiftScalar; + uint16_t immediate; } a64inst_DPImmediate_WideMovData; // Holds data for immediate data processing instructions typedef struct { - a64inst_DPIOpType DPIOpType; a64inst_regType regType; + a64inst_DPIOpType DPIOpType; union { a64inst_arithmOp arithmOp; a64inst_wideMovOp movOp; diff --git a/src/a64instruction_DPRegister.h b/src/a64instruction_DPRegister.h new file mode 100644 index 0000000..d0252ee --- /dev/null +++ b/src/a64instruction_DPRegister.h @@ -0,0 +1,58 @@ +#include +#include "a64instruction_global.h" +#include "a64instruction_DP.h" + +// Denotes the type of data processing operation +typedef enum { + a64inst_DPR_ARITHMLOGIC, + a64inst_DPR_MULTIPLY +} a64inst_DPROpType; + +// Denotes the logical operations supported by the architecture +typedef enum { + a64inst_AND = 0, + a64inst_OR = 1, + a64inst_XOR = 2, + a64inst_AND_FLAGGED = 3 +} a64inst_logicOp; + +// Denotes the different kinds of shifts supported by the architecture +typedef enum { + a64inst_LSL = 0, + a64inst_LSR = 1, + a64inst_ASR = 2, + a64inst_ROR = 3 +} a64inst_ShiftType; + +// Holds data specific to arithmetic/logic register data processing instructions +typedef struct { + enum { + a64inst_DPR_ARITHM = 0, + a64inst_DPR_LOGIC = 1 + } type; + a64inst_ShiftType shiftType; + bool negShiftedSrc2; // Guaranteed to be 0 for arithmetic instructions +} a64inst_DPRegister_ArithmLogicData; + +// Holds data specific to multiply register data processing instructions +typedef struct { + bool negProd; + a64inst_regSpecifier summand; +} a64inst_DPRegister_MultiplyData; + +// Holds data for register data processing instructions +typedef struct { + a64inst_regType regType; + a64inst_DPROpType DPROpType; + union { + a64inst_logicOp logicOp; + a64inst_arithmOp arithmOp; + } processOpId; + a64inst_regSpecifier src2; + union { + a64inst_DPRegister_ArithmLogicData arithmLogicData; + a64inst_DPRegister_MultiplyData multiplydata; + } processOpData; + a64inst_regSpecifier src1; + a64inst_regSpecifier dest; +} a64inst_DPRegisterData; From 23d0e826a41db6bef4134f43a9f91e7510d11b12 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Fri, 31 May 2024 17:32:03 +0100 Subject: [PATCH 15/84] Add ADS for single transf instructions w/ S --- src/a64instruction_SingleTransfer.h | 46 +++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/a64instruction_SingleTransfer.h diff --git a/src/a64instruction_SingleTransfer.h b/src/a64instruction_SingleTransfer.h new file mode 100644 index 0000000..150437b --- /dev/null +++ b/src/a64instruction_SingleTransfer.h @@ -0,0 +1,46 @@ +#include +#include "a64instruction_global.h" +#include "global.h" + +typedef enum { + a64inst_SINGLE_TRANSFER_SINGLE_DATA_TRANSFER, + a64inst_SINGLE_TRANSFER_LOAD_LITERAL +} a64inst_SingleTransferType; + +typedef enum { + a64inst_STORE, + a64inst_LOAD +} a64inst_TransferType; + +typedef enum { + a64inst_REGISTER_OFFSET, + a64inst_PRE_INDEXED, + a64inst_POST_INDEXED, + a64inst_UNSIGNED_OFFSET +} a64inst_AddressingMode; + +typedef struct { + a64inst_TransferType transferType; + a64inst_regSpecifier base; + a64inst_AddressingMode addressingMode; + // I think the following is better than another level of nesting. + union { + a64inst_regSpecifier offsetReg; + word preIndexedOffset; + word postIndexedOffset; + word unsignedOffset; + } a64inst_addressingModeData; +} a64inst_SingleDataTransferData; + +typedef struct { + word offset; +} a64inst_LoadLiteralData; + +typedef struct { + a64inst_regSpecifier target; + a64inst_regType regType; + union { + a64inst_SingleDataTransferData singleDataTransferData; + a64inst_LoadLiteralData loadLiteralData; + } processOpData; +} a64inst_SingleTransferData; \ No newline at end of file From d7c23e7bf0d409cd0c4539c223871f421c1b3320 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Fri, 31 May 2024 17:45:02 +0100 Subject: [PATCH 16/84] Add decode for Branch Instructions, w/ T --- src/decode.c | 36 ++++++++++++++++++++++++++++++++++-- src/decode.h | 19 +++++++++++++++---- 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/src/decode.c b/src/decode.c index 9ee999d..a607e18 100644 --- a/src/decode.c +++ b/src/decode.c @@ -22,7 +22,7 @@ a64inst_instruction *decode(word wrd) { exit(1); } - word DPImmFlag = getBits(wrd, DATA_PROCESSING_DPIMM_LSB, DATA_PROCESSING_DPIMM_MSB); + word DPImmFlag = getBits(wrd, BRANCH_CONDITIONAL_COND_LSB, BRANCH_CONDITIONAL_COND_MSB); if (wrd == HALT_WORD) { inst->type = a64inst_HALT; @@ -31,8 +31,40 @@ a64inst_instruction *decode(word wrd) { }else if (DPImmFlag == 1) { inst->type = a64inst_BRANCH; + word branchTypeFlag = getBits(wrd, BRANCH_TYPE_LSB, BRANCH_TYPE_MSB); + + inst->data.BranchData.BranchType = branchTypeFlag; - } else if (getBits(wrd, DATA_PROCESSING_DPREG_LSB, DATA_PROCESSING_DPREG_MSB) == 1) { + 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, "Error: 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; + } + + } else if (getBits(wrd, DATA_PROCESSING_REG_LSB, DATA_PROCESSING_REG_MSB) == 1) { inst->type = a64inst_DPREGISTER; } else { diff --git a/src/decode.h b/src/decode.h index 7eaa2fa..280d473 100644 --- a/src/decode.h +++ b/src/decode.h @@ -4,10 +4,21 @@ #define BYTE_BITS 8 #define HALT_WORD 0x8a000000 -#define DATA_PROCESSING_DPIMM_LSB 26 -#define DATA_PROCESSING_DPIMM_MSB 29 +#define DATA_PROCESSING_IMM_LSB 26 +#define DATA_PROCESSING_IMM_MSB 29 -#define DATA_PROCESSING_DPREG_LSB 25 -#define DATA_PROCESSING_DPREG_MSB 26 +#define DATA_PROCESSING_REG_LSB 25 +#define DATA_PROCESSING_REG_MSB 26 + +#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 a64inst_instruction *decode(word w); \ No newline at end of file From bfb8bfdace1faacb0f0ca12224abf68cc5215b52 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Fri, 31 May 2024 17:59:34 +0100 Subject: [PATCH 17/84] Add internal structure for Single Transfer, w/ T --- src/a64instruction_SingleTransfer.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/a64instruction_SingleTransfer.h b/src/a64instruction_SingleTransfer.h index 150437b..120f173 100644 --- a/src/a64instruction_SingleTransfer.h +++ b/src/a64instruction_SingleTransfer.h @@ -21,24 +21,26 @@ typedef enum { typedef struct { a64inst_TransferType transferType; - a64inst_regSpecifier base; a64inst_AddressingMode addressingMode; - // I think the following is better than another level of nesting. + union { a64inst_regSpecifier offsetReg; - word preIndexedOffset; - word postIndexedOffset; - word unsignedOffset; + uint16_t preIndexedOffset; + uint16_t postIndexedOffset; + uint16_t unsignedOffset; } a64inst_addressingModeData; + + a64inst_regSpecifier base; } a64inst_SingleDataTransferData; typedef struct { - word offset; + uint32_t offset; } a64inst_LoadLiteralData; typedef struct { - a64inst_regSpecifier target; + a64inst_SingleTransferType SingleTransferOpType; a64inst_regType regType; + a64inst_regSpecifier target; union { a64inst_SingleDataTransferData singleDataTransferData; a64inst_LoadLiteralData loadLiteralData; From 074de73e8ec5698ceefa46e3f021306e16208735 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Sun, 2 Jun 2024 20:57:49 +0100 Subject: [PATCH 18/84] Add decode for DP immediate instructions w/ S# --- src/a64instruction_DPImmediate.h | 5 +--- src/decode.c | 46 +++++++++++++++++++++++++------- src/decode.h | 33 +++++++++++++++++++---- 3 files changed, 66 insertions(+), 18 deletions(-) diff --git a/src/a64instruction_DPImmediate.h b/src/a64instruction_DPImmediate.h index 2c02c2f..8b5e68c 100644 --- a/src/a64instruction_DPImmediate.h +++ b/src/a64instruction_DPImmediate.h @@ -33,10 +33,7 @@ typedef struct { typedef struct { a64inst_regType regType; a64inst_DPIOpType DPIOpType; - union { - a64inst_arithmOp arithmOp; - a64inst_wideMovOp movOp; - } processOpId; + unsigned int processOp; union { a64inst_DPImmediate_ArithmData arithmData; a64inst_DPImmediate_WideMovData wideMovData; diff --git a/src/decode.c b/src/decode.c index a607e18..3610811 100644 --- a/src/decode.c +++ b/src/decode.c @@ -8,12 +8,14 @@ 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 < BYTE_BITS); + assert(lsb < msb && msb <= WORD_BITS); wrd &= (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)); @@ -22,14 +24,40 @@ a64inst_instruction *decode(word wrd) { exit(1); } - word DPImmFlag = getBits(wrd, BRANCH_CONDITIONAL_COND_LSB, BRANCH_CONDITIONAL_COND_MSB); + word typeId = getBits(wrd, TYPE_ID_LSB, TYPE_ID_MSB); + // Halt interpretation if (wrd == HALT_WORD) { inst->type = a64inst_HALT; - - } else if (DPImmFlag == 0) { - inst->type = a64inst_DPIMMEDIATE; - }else if (DPImmFlag == 1) { + // Data Processing Immediate interpretation + } else if (typeId == DP_IMM_ID) { + inst->type = a64inst_DPIMMEDIATE; + inst->data.DPImmediateData.regType = getBits(wrd, DP_IMM_WIDTH_LSB, DP_IMM_WIDTH_MSB); + inst->data.DPImmediateData.processOp = getBits(wrd, DP_IMM_OP_LSB, DP_IMM_OP_MSB); + inst->data.DPImmediateData.dest = getBits(wrd, DP_IMM_DEST_LSB, DP_IMM_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); @@ -48,7 +76,7 @@ a64inst_instruction *decode(word wrd) { if(conditionFlag <= 1 || (conditionFlag >= 10 && conditionFlag <= 14)) { inst->data.BranchData.processOpData.conditionalData.cond = conditionFlag; } else { - fprintf(stderr, "Error: Unknown condition detected.\n"); + fprintf(stderr, "Unknown condition detected!\n"); exit(1); } @@ -64,12 +92,12 @@ a64inst_instruction *decode(word wrd) { break; } - } else if (getBits(wrd, DATA_PROCESSING_REG_LSB, DATA_PROCESSING_REG_MSB) == 1) { + } else if (getBits(wrd, DP_REG_LSB, DP_REG_MSB) == 1) { inst->type = a64inst_DPREGISTER; } else { // Load and Store, or unknown } - + return inst; } diff --git a/src/decode.h b/src/decode.h index 280d473..6494f0f 100644 --- a/src/decode.h +++ b/src/decode.h @@ -1,14 +1,37 @@ #include "global.h" #include "a64instruction.h" -#define BYTE_BITS 8 +#define WORD_BITS 32 #define HALT_WORD 0x8a000000 -#define DATA_PROCESSING_IMM_LSB 26 -#define DATA_PROCESSING_IMM_MSB 29 +#define TYPE_ID_LSB 26 +#define TYPE_ID_MSB 29 +#define DP_IMM_ID 4 +#define BRANCH_ID 5 -#define DATA_PROCESSING_REG_LSB 25 -#define DATA_PROCESSING_REG_MSB 26 +#define DP_REG_LSB 25 +#define DP_REG_MSB 26 + +#define DP_IMM_WIDTH_LSB 31 +#define DP_IMM_WIDTH_MSB 32 +#define DP_IMM_OP_LSB 29 +#define DP_IMM_OP_MSB 31 +#define DP_IMM_DEST_LSB 0 +#define DP_IMM_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 BRANCH_TYPE_LSB 30 #define BRANCH_TYPE_MSB 32 From 480294da629d1aac51d8727361d59e070e76e6b6 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Sun, 2 Jun 2024 20:59:33 +0100 Subject: [PATCH 19/84] Update Single Transfer Internal Structure, w/ T --- src/a64instruction_SingleTransfer.h | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/a64instruction_SingleTransfer.h b/src/a64instruction_SingleTransfer.h index 120f173..7b2524b 100644 --- a/src/a64instruction_SingleTransfer.h +++ b/src/a64instruction_SingleTransfer.h @@ -3,8 +3,8 @@ #include "global.h" typedef enum { - a64inst_SINGLE_TRANSFER_SINGLE_DATA_TRANSFER, - a64inst_SINGLE_TRANSFER_LOAD_LITERAL + a64inst_SINGLE_TRANSFER_SINGLE_DATA_TRANSFER = 1, + a64inst_SINGLE_TRANSFER_LOAD_LITERAL = 0 } a64inst_SingleTransferType; typedef enum { @@ -13,10 +13,10 @@ typedef enum { } a64inst_TransferType; typedef enum { - a64inst_REGISTER_OFFSET, - a64inst_PRE_INDEXED, - a64inst_POST_INDEXED, - a64inst_UNSIGNED_OFFSET + a64inst_REGISTER_OFFSET = 2, + a64inst_PRE_INDEXED = 1, + a64inst_POST_INDEXED = 0, + a64inst_UNSIGNED_OFFSET = 3 } a64inst_AddressingMode; typedef struct { @@ -25,8 +25,7 @@ typedef struct { union { a64inst_regSpecifier offsetReg; - uint16_t preIndexedOffset; - uint16_t postIndexedOffset; + uint16_t indexedOffset; uint16_t unsignedOffset; } a64inst_addressingModeData; From 4f324da0e9e9d039cc099f3d0e8569ed80daae70 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Sun, 2 Jun 2024 21:02:24 +0100 Subject: [PATCH 20/84] Update file io to byte addressable, w/ T --- src/fileio.c | 15 ++++++++------- src/fileio.h | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/fileio.c b/src/fileio.c index b8c0574..1dcdd77 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -2,19 +2,20 @@ #include #include #include "fileio.h" +#include "global.h" /* Loads a binary file located at filePath to memory, taking up a block of exactly memorySize bytes, and returns the starting address of the data. If memorySize is insufficient to store the entire file, an appropriate error is reported. Excess memory is set to 0 bit values. */ -word *fileio_loadBin(const char *filePath, size_t memorySize) { +byte *fileio_loadBin(const char *filePath, size_t memorySize) { FILE *file = fopen(filePath, "rb"); if (file == NULL) { fprintf(stderr, "Couldn't open %s!\n", filePath); exit(EXIT_FAILURE); } - word *fileData = malloc(memorySize); + byte *fileData = malloc(memorySize); if (fileData == NULL) { fprintf(stderr, "Ran out of memory attempting to load %s!\n", filePath); exit(EXIT_FAILURE); @@ -22,10 +23,10 @@ word *fileio_loadBin(const char *filePath, size_t memorySize) { // Loop while reading from the file yields data. Only terminates if EOF is reached or ERROR occurs. // Explicitly deal with attempting to write too much data to memory block, rather than allow segfault. - const size_t wordCount = memorySize/sizeof(word); + const size_t byteCount = memorySize/sizeof(byte); int i = 0; - while (fread(fileData + i, sizeof(word), 1, file)) { - if (i >= wordCount) { + 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); exit(EXIT_FAILURE); } @@ -40,8 +41,8 @@ word *fileio_loadBin(const char *filePath, size_t memorySize) { assert(fclose(file) != EOF); // If part of memory block was left uninitialized, initialize it to zero. - if (i < wordCount) { - memset(fileData + i, 0, (wordCount - i) * sizeof(word)); + if (i < byteCount) { + memset(fileData + i, 0, (byteCount - i) * sizeof(byte)); } return fileData; } diff --git a/src/fileio.h b/src/fileio.h index 8a439bf..a2d4262 100644 --- a/src/fileio.h +++ b/src/fileio.h @@ -5,5 +5,5 @@ #define EXIT_FAILURE 1 -extern word *fileio_loadBin(const char *filePath, size_t memorySize); +extern byte *fileio_loadBin(const char *filePath, size_t memorySize); #endif From a0a51f472c89c10903fa3c998850aeddc4e96cf7 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Sun, 2 Jun 2024 21:06:08 +0100 Subject: [PATCH 21/84] Add single transfer decoding, w/ T --- src/a64instruction.h | 3 +++ src/decode.c | 30 ++++++++++++++++++++++++++++++ src/decode.h | 26 ++++++++++++++++++++++++++ 3 files changed, 59 insertions(+) diff --git a/src/a64instruction.h b/src/a64instruction.h index f0f617f..31fc602 100644 --- a/src/a64instruction.h +++ b/src/a64instruction.h @@ -1,5 +1,7 @@ #include "a64instruction_DPImmediate.h" #include "a64instruction_Branch.h" +#include "a64instruction_SingleTransfer.h" + // 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). typedef enum { @@ -17,5 +19,6 @@ typedef struct { union { a64inst_DPImmediateData DPImmediateData; a64inst_BranchData BranchData; + a64inst_SingleTransferData SingleTransferData; } data; } a64inst_instruction; diff --git a/src/decode.c b/src/decode.c index 3610811..3f13a5f 100644 --- a/src/decode.c +++ b/src/decode.c @@ -97,6 +97,36 @@ a64inst_instruction *decode(word wrd) { } else { // Load and Store, or unknown + // Ignore unknown for now + inst->type = a64inst_SINGLETRANSFER; + inst->data.SingleTransferData.regType = getBits(wrd, SINGLE_TRANSFER_REGTYPE_FLAG_LSB, SINGLE_TRANSFER_REGTYPE_FLAG_MSB); + inst->data.SingleTransferData.target = getBits(wrd, SINGLE_TRANSFER_TARGET_REG_LSB, SINGLE_TRANSFER_TARGET_REG_MSB); + + // TODO: Assert that the instruction is a Single Transfer indeed. + + if(getBits(wrd, SINGLE_TRANSFER_OPTYPE_FLAG_LSB, SINGLE_TRANSFER_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, SINGLE_DATA_TRANSFER_TRANSFER_TYPE_LSB, SINGLE_DATA_TRANSFER_TRANSFER_TYPE_MSB); + inst->data.SingleTransferData.processOpData.singleDataTransferData.base = getBits(wrd, SINGLE_DATA_TRANSFER_BASE_REG_LSB, SINGLE_DATA_TRANSFER_BASE_REG_MSB); + if (getBits(wrd, SINGLE_DATA_TRANSFER_UNSIGNED_FLAG_LSB, SINGLE_DATA_TRANSFER_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, SINGLE_DATA_TRANSFER_OFFSET_LSB, SINGLE_DATA_TRANSFER_OFFSET_MSB); + } else if (getBits(wrd, SINGLE_DATA_TRANSFER_REGISTER_FLAG_LSB, SINGLE_DATA_TRANSFER_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, SINGLE_DATA_TRANSFER_REGISTER_REG_LSB, SINGLE_DATA_TRANSFER_REGISTER_REG_MSB); + } else { + // Pre-Indexed or Post-Indexed + inst->data.SingleTransferData.processOpData.singleDataTransferData.addressingMode = getBits(wrd, SINGLE_DATA_TRANSFER_INDEXED_ADDRMODE_LSB, SINGLE_DATA_TRANSFER_INDEXED_ADDRMODE_MSB); + inst->data.SingleTransferData.processOpData.singleDataTransferData.a64inst_addressingModeData.indexedOffset = getBits(wrd, SINGLE_DATA_TRANSFER_INDEXED_OFFSET_LSB, SINGLE_DATA_TRANSFER_INDEXED_OFFSET_MSB); + } + } else { + // Load Literal + inst->data.SingleTransferData.SingleTransferOpType = a64inst_SINGLE_TRANSFER_LOAD_LITERAL; + inst->data.SingleTransferData.processOpData.loadLiteralData.offset = getBits(wrd, SINGLE_DATA_TRANSFER_LOAD_LITERAL_OFFSET_LSB, SINGLE_DATA_TRANSFER_LOAD_LITERAL_OFFSET_MSB); + } } return inst; diff --git a/src/decode.h b/src/decode.h index 6494f0f..a141a8f 100644 --- a/src/decode.h +++ b/src/decode.h @@ -33,6 +33,32 @@ #define DP_IMM_WIDEMOV_IMMVAL_LSB 5 #define DP_IMM_WIDEMOV_IMMVAL_MSB 21 +#define SINGLE_TRANSFER_OPTYPE_FLAG_LSB 31 +#define SINGLE_TRANSFER_OPTYPE_FLAG_MSB 32 +#define SINGLE_TRANSFER_REGTYPE_FLAG_LSB 30 +#define SINGLE_TRANSFER_REGTYPE_FLAG_MSB 31 +#define SINGLE_TRANSFER_TARGET_REG_LSB 0 +#define SINGLE_TRANSFER_TARGET_REG_MSB 5 + +#define SINGLE_DATA_TRANSFER_BASE_REG_LSB 5 +#define SINGLE_DATA_TRANSFER_BASE_REG_MSB 10 +#define SINGLE_DATA_TRANSFER_OFFSET_LSB 10 +#define SINGLE_DATA_TRANSFER_OFFSET_MSB 22 +#define SINGLE_DATA_TRANSFER_TRANSFER_TYPE_LSB 22 +#define SINGLE_DATA_TRANSFER_TRANSFER_TYPE_MSB 23 +#define SINGLE_DATA_TRANSFER_UNSIGNED_FLAG_LSB 24 +#define SINGLE_DATA_TRANSFER_UNSIGNED_FLAG_MSB 25 +#define SINGLE_DATA_TRANSFER_REGISTER_FLAG_LSB 21 +#define SINGLE_DATA_TRANSFER_REGISTER_FLAG_MSB 22 +#define SINGLE_DATA_TRANSFER_REGISTER_REG_LSB 16 +#define SINGLE_DATA_TRANSFER_REGISTER_REG_MSB 21 +#define SINGLE_DATA_TRANSFER_INDEXED_ADDRMODE_LSB 11 +#define SINGLE_DATA_TRANSFER_INDEXED_ADDRMODE_MSB 12 +#define SINGLE_DATA_TRANSFER_INDEXED_OFFSET_LSB 12 +#define SINGLE_DATA_TRANSFER_INDEXED_OFFSET_MSB 21 +#define SINGLE_DATA_TRANSFER_LOAD_LITERAL_OFFSET_LSB 5 +#define SINGLE_DATA_TRANSFER_LOAD_LITERAL_OFFSET_MSB 24 + #define BRANCH_TYPE_LSB 30 #define BRANCH_TYPE_MSB 32 #define BRANCH_UNCONDITIONAL_OFFSET_LSB 0 From eea0faac88a97d67ff7c293642cdec4043192018 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Sun, 2 Jun 2024 21:06:54 +0100 Subject: [PATCH 22/84] Add test script to run test suite --- test.sh | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 test.sh diff --git a/test.sh b/test.sh new file mode 100644 index 0000000..7bb96e7 --- /dev/null +++ b/test.sh @@ -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" \ No newline at end of file From 6bc15b7faf902fcc99de4b4a56fd97cc24864353 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Sun, 2 Jun 2024 21:24:48 +0100 Subject: [PATCH 23/84] Add priting utility for emulator output, w/ T --- src/emulator.h | 9 ++++++++- src/print.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ src/print.h | 6 ++++++ 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 src/print.c create mode 100644 src/print.h diff --git a/src/emulator.h b/src/emulator.h index 34601ea..f6a3cb2 100644 --- a/src/emulator.h +++ b/src/emulator.h @@ -1,9 +1,14 @@ +#ifndef __EMULATOR__ +#define __EMULATOR__ #include "global.h" /************************************ * DEFINITIONS ************************************/ +#define BYTE_BITS 8 +#define WORD_BITS 32 + /************************************ * STRUCTS ************************************/ @@ -20,4 +25,6 @@ typedef struct { word pc; byte memory[MEMORY_SIZE]; PState conditionCodes; -} Machine; \ No newline at end of file +} Machine; + +#endif diff --git a/src/print.c b/src/print.c new file mode 100644 index 0000000..c12322e --- /dev/null +++ b/src/print.c @@ -0,0 +1,49 @@ +#include +#include +#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= %u\n", i, state->registers[i]); + } + fprintf(stream, "PC\t= %u\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 +// Converts 4 bytes into one word +word readWord(Machine *state, word address) { + word result = 0; + int bytesPerWord = WORD_BITS / BYTE_BITS - 1; + for (int i = 0; i <= bytesPerWord; i++) + result |= (word) state->memory[address + i] << (BYTE_BITS * (bytesPerWord - 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, addr); + if (data != 0) { + fprintf(stream, "0x%08x: 0x%08x\n", addr, data); + } + } + +} diff --git a/src/print.h b/src/print.h new file mode 100644 index 0000000..f344731 --- /dev/null +++ b/src/print.h @@ -0,0 +1,6 @@ +#include +#include "emulator.h" + +void printState(Machine *state, FILE *stream); +void printRegisters(Machine *state, FILE *stream); +void printMemory(Machine *state, FILE *stream); From 78d1f5588f299f370e1b7cbef14a45a5614b7d9d Mon Sep 17 00:00:00 2001 From: sBubshait Date: Sun, 2 Jun 2024 21:45:57 +0100 Subject: [PATCH 24/84] Update read word to be utility func, w/ T --- src/print.c | 8 ++++---- src/print.h | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/print.c b/src/print.c index c12322e..f70eb86 100644 --- a/src/print.c +++ b/src/print.c @@ -1,4 +1,5 @@ #include +#include #include #include "print.h" #include "emulator.h" @@ -25,12 +26,11 @@ void printRegisters(Machine *state, FILE *stream) { } // Returns the word starting at the provided address -// Converts 4 bytes into one word -word readWord(Machine *state, word 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) state->memory[address + i] << (BYTE_BITS * (bytesPerWord - i)); + result |= (word) memory[address + i] << (BYTE_BITS * (bytesPerWord - i)); return result; } @@ -40,7 +40,7 @@ void printMemory(Machine *state, FILE *stream) { // print memory 4 byte aligned for (int addr = 0; addr < MEMORY_SIZE; addr+= 4) { - word data = readWord(state, addr); + word data = readWord(state->memory, addr); if (data != 0) { fprintf(stream, "0x%08x: 0x%08x\n", addr, data); } diff --git a/src/print.h b/src/print.h index f344731..f3a411f 100644 --- a/src/print.h +++ b/src/print.h @@ -1,6 +1,7 @@ #include #include "emulator.h" +word readWord(byte *memory, uint32_t address); void printState(Machine *state, FILE *stream); void printRegisters(Machine *state, FILE *stream); void printMemory(Machine *state, FILE *stream); From 46c1b42c53a4e5123fab3727131a16a3b82cb5d3 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Sun, 2 Jun 2024 21:46:34 +0100 Subject: [PATCH 25/84] Add the overall emulation pipeline, w/ T --- src/a64instruction.h | 4 ++++ src/decode.h | 2 -- src/emulate.c | 29 +++++++++++++++++++++++++++++ src/emulator.h | 3 ++- src/execute.c | 12 ++++++------ src/execute.h | 6 +++++- 6 files changed, 46 insertions(+), 10 deletions(-) diff --git a/src/a64instruction.h b/src/a64instruction.h index 31fc602..463e75a 100644 --- a/src/a64instruction.h +++ b/src/a64instruction.h @@ -1,3 +1,5 @@ +#ifndef __A64INSTRUCTION__ +#define __A64INSTRUCTION__ #include "a64instruction_DPImmediate.h" #include "a64instruction_Branch.h" #include "a64instruction_SingleTransfer.h" @@ -22,3 +24,5 @@ typedef struct { a64inst_SingleTransferData SingleTransferData; } data; } a64inst_instruction; + +#endif diff --git a/src/decode.h b/src/decode.h index a141a8f..09a1c55 100644 --- a/src/decode.h +++ b/src/decode.h @@ -69,5 +69,3 @@ #define BRANCH_CONDITIONAL_COND_MSB 4 #define BRANCH_CONDITIONAL_OFFSET_LSB 5 #define BRANCH_CONDITIONAL_OFFSET_MSB 24 - -a64inst_instruction *decode(word w); \ No newline at end of file diff --git a/src/emulate.c b/src/emulate.c index 3bbb3d7..54b0d68 100755 --- a/src/emulate.c +++ b/src/emulate.c @@ -1,5 +1,12 @@ #include #include +#include "emulator.h" +#include "fileio.h" +#include "print.h" +#include "decode.h" +#include "execute.h" + +extern a64inst_instruction *decode(word w); int main(int argc, char **argv) { @@ -18,6 +25,28 @@ int main(int argc, char **argv) { } } + // 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; + // get + a64inst_instruction *inst; + do { + + word instruction = readWord(state, state->pc); + inst = decode(instruction); + execute(state, inst); + + state->pc += 1; + + } while (inst->type != a64inst_HALT); + + printState(state, out); + + free(state->memory); + + return EXIT_SUCCESS; } diff --git a/src/emulator.h b/src/emulator.h index f6a3cb2..59942df 100644 --- a/src/emulator.h +++ b/src/emulator.h @@ -1,6 +1,7 @@ #ifndef __EMULATOR__ #define __EMULATOR__ #include "global.h" +#include /************************************ * DEFINITIONS @@ -23,7 +24,7 @@ typedef struct { typedef struct { word registers[REGISTER_COUNT]; word pc; - byte memory[MEMORY_SIZE]; + byte *memory; PState conditionCodes; } Machine; diff --git a/src/execute.c b/src/execute.c index e1ebbf9..d0c2c5e 100644 --- a/src/execute.c +++ b/src/execute.c @@ -1,18 +1,18 @@ #include "execute.h" -void execute(a64inst_instruction inst) { +void execute(Machine *state, a64inst_instruction *inst) { - switch (inst.type) { - case a64inst_Halt: + switch (inst->type) { + case a64inst_HALT: // Halt the program break; - case a64inst_DPImmediate: + case a64inst_DPIMMEDIATE: // Execute a data processing immediate instruction break; - case a64inst_Branch: + case a64inst_BRANCH: // Execute a branch instruction break; - case a64inst_DPRegister: + case a64inst_DPREGISTER: // Execute a data processing register instruction break; default: diff --git a/src/execute.h b/src/execute.h index fd9da37..fcf39ec 100644 --- a/src/execute.h +++ b/src/execute.h @@ -1,3 +1,7 @@ +#ifndef __EXECUTE__ +#define __EXECUTE__ #include "a64instruction.h" +#include "emulator.h" -void execute(a64inst_instruction inst); \ No newline at end of file +void execute(Machine *state, a64inst_instruction *inst); +#endif From fd3ef3453cb4f6810aa4fdd3b2e07417f4e7a7b6 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Sun, 2 Jun 2024 21:52:14 +0100 Subject: [PATCH 26/84] Improved style of main emulate loop w/ S --- src/emulate.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/emulate.c b/src/emulate.c index 54b0d68..dc61a34 100755 --- a/src/emulate.c +++ b/src/emulate.c @@ -31,21 +31,23 @@ int main(int argc, char **argv) { state->conditionCodes = (PState){0, 1, 0, 0}; state->pc = 0x0; - // get + // Fetch-decode-execute cycle + word wrd; a64inst_instruction *inst; - do { - word instruction = readWord(state, state->pc); - inst = decode(instruction); - execute(state, inst); + // Step 1: Fetch instruction at PC's address + wrd = readWord(state, 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); state->pc += 1; - } while (inst->type != a64inst_HALT); printState(state, out); - free(state->memory); return EXIT_SUCCESS; From 65ba8339c664074505698a83691d2dbfec5963e5 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Sun, 2 Jun 2024 21:53:42 +0100 Subject: [PATCH 27/84] Fixed bug with main emulate loop w/ S --- src/emulate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/emulate.c b/src/emulate.c index dc61a34..6720dd0 100755 --- a/src/emulate.c +++ b/src/emulate.c @@ -37,7 +37,7 @@ int main(int argc, char **argv) { do { // Step 1: Fetch instruction at PC's address - wrd = readWord(state, state->pc); + wrd = readWord(state->memory, state->pc); // Step 2: Decode instruction to internal representation inst = decode(wrd); From 7224903ea6411684999e0c7d9acf4f04b219ae8b Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Sun, 2 Jun 2024 21:55:40 +0100 Subject: [PATCH 28/84] Improved style of emulate function w/ S --- src/execute.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/execute.c b/src/execute.c index d0c2c5e..6622812 100644 --- a/src/execute.c +++ b/src/execute.c @@ -3,20 +3,25 @@ void execute(Machine *state, a64inst_instruction *inst) { switch (inst->type) { + + // Halt the program case a64inst_HALT: - // Halt the program break; + + // Execute a data processing immediate instruction case a64inst_DPIMMEDIATE: - // Execute a data processing immediate instruction break; + + // Execute a branch instruction case a64inst_BRANCH: - // Execute a branch instruction break; + + // Execute a data processing register instruction case a64inst_DPREGISTER: - // Execute a data processing register instruction break; + + // Unknown instruction default: - // Unknown instruction break; } From 9af558a831010c0b2f2ea95864bdc82f5aee996b Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Mon, 3 Jun 2024 13:34:29 +0100 Subject: [PATCH 29/84] Updated machine struct to simulate 64bit registers --- src/emulator.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/emulator.h b/src/emulator.h index 59942df..5a78365 100644 --- a/src/emulator.h +++ b/src/emulator.h @@ -8,7 +8,7 @@ ************************************/ #define BYTE_BITS 8 -#define WORD_BITS 32 +#define WORD_BITS (BYTE_BITS * sizeof(word)) /************************************ * STRUCTS @@ -22,8 +22,8 @@ typedef struct { } PState; typedef struct { - word registers[REGISTER_COUNT]; - word pc; + dword registers[REGISTER_COUNT]; + dword pc; byte *memory; PState conditionCodes; } Machine; From 34119916dec0478b5c8dc27ec4bc8182428b9122 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Mon, 3 Jun 2024 14:37:08 +0100 Subject: [PATCH 30/84] Added constant for number of bits in a dword w/ S --- src/emulator.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/emulator.h b/src/emulator.h index 5a78365..facbfd7 100644 --- a/src/emulator.h +++ b/src/emulator.h @@ -9,6 +9,7 @@ #define BYTE_BITS 8 #define WORD_BITS (BYTE_BITS * sizeof(word)) +#define DWORD_BITS (BYTE_BITS * sizeof(dword)) /************************************ * STRUCTS From 63ba75fab668a263e8671ecc0554fb232610de62 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Mon, 3 Jun 2024 14:37:59 +0100 Subject: [PATCH 31/84] Add function for executing DPI instructions w/ S --- src/execute.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/src/execute.c b/src/execute.c index 6622812..3e8c57f 100644 --- a/src/execute.c +++ b/src/execute.c @@ -1,5 +1,88 @@ #include "execute.h" +// The number of bits to shift the immediate value in an immediate data processing instruction +// if the shift flag is enabled. +#define DPI_ARITHM_SHIFT 12 + +// 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_R) { + return value + } else { + //return value & ~(dword)((1 << WORD_BITS) - 1) + return value & (1 << WORD_BITS) - 1 + } +} + +// 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); + } +} + +// Read from 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 dword writeRegister(Machine *state, a64inst_regSpecifier reg, a64inst_regType regType, dword value) { + state->registers[reg] = truncateValue(value, regType); +} + +// Execute a data processing immediate instruction +static void executeDPImmediate(Machine *state, a64inst_instruction *inst) { + assert(inst->type == a64inst_DPIMMEDIATE); + switch(inst->data.DPImmediateData.DPIOpType) { + + a64inst_regType regType = inst->data.DPImmediateData.regType; + word *dest = state->registers + inst->data.DPImmediateData.dest; + + // Execute an arithmetic 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 immediate = inst->data.DPImmediateData.processOpData.arithmData.immediate; + dword srcVal = state->registers[inst->data.DPImmediateData.processOpData.arithmData.src]; + if (inst->data.DPImmediateData.processOpData.arithmData.shiftImmediate) { + immediate = truncateValue(immediate << DPI_ARITHM_SHIFT, regType); + } + + switch(inst->data.DPImmediateData.processOp) { + + case(a64inst_ADDS): + // Fall through + + case(a64inst_ADD): + *dest = truncateValue(srcVal + immediate, regType); + break; + + case(a64inst_SUBS): + // Fall through + + case(a64inst_SUB): + *dest = truncateValue(srcVal - immediate, regType); + break; + + // Unknown opcode detected! + default: + break; + } + + break; + + // Execute a wide move data processing instruction + case a64inst_DPI_WIDEMOV: + break; + + // Unknown instruction detected! + default: + break; + } +} + void execute(Machine *state, a64inst_instruction *inst) { switch (inst->type) { From 07b2410a8639f0dcf740732b0cab6a3835b2d372 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Mon, 3 Jun 2024 14:38:37 +0100 Subject: [PATCH 32/84] Added zero register specifier constant w/ S --- src/global.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/global.h b/src/global.h index 138e11a..d3d015c 100644 --- a/src/global.h +++ b/src/global.h @@ -11,6 +11,8 @@ // Number of General Purpose Registers. #define REGISTER_COUNT 31 +// Register identifier interpreted as the 'zero register' +#define ZERO_REGISTER 31 // Size of the memory in bytes. #define MEMORY_SIZE 2097152 // Length of the memory address in bits. From 10d89ecf91980f43356e61a86436866b4b978057 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Mon, 3 Jun 2024 14:44:07 +0100 Subject: [PATCH 33/84] Add read double word utility, w/ T --- src/print.c | 9 +++++++++ src/print.h | 1 + 2 files changed, 10 insertions(+) diff --git a/src/print.c b/src/print.c index f70eb86..874357d 100644 --- a/src/print.c +++ b/src/print.c @@ -34,6 +34,15 @@ word readWord(byte *memory, uint32_t address) { 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 * (bytesPerDword - 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"); diff --git a/src/print.h b/src/print.h index f3a411f..c84a3ea 100644 --- a/src/print.h +++ b/src/print.h @@ -2,6 +2,7 @@ #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); From 14733b9660009241c7c32a1afdc0b81ae995ac5c Mon Sep 17 00:00:00 2001 From: sBubshait Date: Mon, 3 Jun 2024 14:47:50 +0100 Subject: [PATCH 34/84] Add execute for SDT instructions, w/ T --- src/execute.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++--- src/execute.h | 1 + 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/src/execute.c b/src/execute.c index 3e8c57f..78e0efd 100644 --- a/src/execute.c +++ b/src/execute.c @@ -4,13 +4,16 @@ // if the shift flag is enabled. #define DPI_ARITHM_SHIFT 12 +// Prototypes +void execute_SDT(Machine *state, a64inst_instruction *inst); + // 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_R) { - return value + return value; } else { //return value & ~(dword)((1 << WORD_BITS) - 1) - return value & (1 << WORD_BITS) - 1 + return value & (1 << WORD_BITS) - 1; } } @@ -18,7 +21,7 @@ static dword truncateValue(dword value, a64inst_regType regType) { // 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) + assert(reg <= REGISTER_COUNT); if (reg == ZERO_REGISTER) { return 0; } else { @@ -103,9 +106,59 @@ void execute(Machine *state, a64inst_instruction *inst) { case a64inst_DPREGISTER: 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; + address *= 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 { + 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); + } + } + } \ No newline at end of file diff --git a/src/execute.h b/src/execute.h index fcf39ec..debc341 100644 --- a/src/execute.h +++ b/src/execute.h @@ -2,6 +2,7 @@ #define __EXECUTE__ #include "a64instruction.h" #include "emulator.h" +#include "print.c" void execute(Machine *state, a64inst_instruction *inst); #endif From 736122276b87c915d773fe7c349f0c61e2972e3b Mon Sep 17 00:00:00 2001 From: sBubshait Date: Mon, 3 Jun 2024 16:14:41 +0100 Subject: [PATCH 35/84] Update print to account for unsigned int, w/ T --- src/print.c | 5 +++-- src/print.h | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/print.c b/src/print.c index 874357d..c4e4f6c 100644 --- a/src/print.c +++ b/src/print.c @@ -1,5 +1,6 @@ #include #include +#include #include #include "print.h" #include "emulator.h" @@ -16,9 +17,9 @@ void printState(Machine *state, FILE *stream) { void printRegisters(Machine *state, FILE *stream) { fprintf(stream, "Registers:\n"); for (int i = 0; i < REGISTER_COUNT; i++) { - fprintf(stream, "X%02d\t= %u\n", i, state->registers[i]); + fprintf(stream, "X%02d\t= %" PRIu64 "\n", i, state->registers[i]); } - fprintf(stream, "PC\t= %u\n", state->pc); + fprintf(stream, "PC\t= %" PRIu64 "\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, diff --git a/src/print.h b/src/print.h index c84a3ea..404e947 100644 --- a/src/print.h +++ b/src/print.h @@ -1,3 +1,5 @@ +#ifndef __PRINT__ +#define __PRINT__ #include #include "emulator.h" @@ -6,3 +8,5 @@ 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 From 8b98a0002f4eaacbebd08f8ccd9bac81da268e9e Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Mon, 3 Jun 2024 16:17:15 +0100 Subject: [PATCH 36/84] Removed repeated definition of WORD_BITS w/ S --- src/decode.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/decode.h b/src/decode.h index 09a1c55..d8c454a 100644 --- a/src/decode.h +++ b/src/decode.h @@ -1,7 +1,6 @@ #include "global.h" #include "a64instruction.h" -#define WORD_BITS 32 #define HALT_WORD 0x8a000000 #define TYPE_ID_LSB 26 From 4c04f44286a50c04445d0a3b546be3f73e889073 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Mon, 3 Jun 2024 17:29:45 +0100 Subject: [PATCH 37/84] Fixed endian-ness of readWord functions w/ S --- src/print.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/print.c b/src/print.c index c4e4f6c..3021356 100644 --- a/src/print.c +++ b/src/print.c @@ -31,7 +31,7 @@ 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 * (bytesPerWord - i)); + result |= (word) memory[address + i] << (BYTE_BITS * i); return result; } @@ -40,7 +40,7 @@ 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 * (bytesPerDword - i)); + result |= (dword) memory[address + i] << (BYTE_BITS * i); return result; } @@ -55,5 +55,4 @@ void printMemory(Machine *state, FILE *stream) { fprintf(stream, "0x%08x: 0x%08x\n", addr, data); } } - } From 679c84a0751adbcc6e57d1ca3b0cd986c28d323a Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Mon, 3 Jun 2024 17:36:19 +0100 Subject: [PATCH 38/84] Moved WORD_BITS constant to global header w/ S --- src/decode.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/decode.c b/src/decode.c index 3f13a5f..d3fd0d6 100644 --- a/src/decode.c +++ b/src/decode.c @@ -2,6 +2,7 @@ #include #include #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. From 84586b476805fe74156e79af9ffa8bae6334c7d2 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Mon, 3 Jun 2024 17:38:04 +0100 Subject: [PATCH 39/84] Add function for executing DPI arithm instructions w/ S --- src/execute.c | 56 ++++++++++++++++++++++++++++++++++++++++----------- src/execute.h | 1 - 2 files changed, 44 insertions(+), 13 deletions(-) diff --git a/src/execute.c b/src/execute.c index 78e0efd..4e0f608 100644 --- a/src/execute.c +++ b/src/execute.c @@ -1,4 +1,9 @@ +#include #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 immediate data processing instruction // if the shift flag is enabled. @@ -7,13 +12,18 @@ // Prototypes void execute_SDT(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_R) { return value; } else { //return value & ~(dword)((1 << WORD_BITS) - 1) - return value & (1 << WORD_BITS) - 1; + return value & (((dword)1 << WORD_BITS) - 1); } } @@ -31,20 +41,27 @@ static dword readRegister(Machine *state, a64inst_regSpecifier reg, a64inst_regT // Read from 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 dword writeRegister(Machine *state, a64inst_regSpecifier reg, a64inst_regType regType, dword value) { +static void writeRegister(Machine *state, a64inst_regSpecifier reg, a64inst_regType regType, dword value) { state->registers[reg] = truncateValue(value, 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 = result & ((1 << (regType ? DWORD_BITS : WORD_BITS)) - 1); + 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) { - - a64inst_regType regType = inst->data.DPImmediateData.regType; - word *dest = state->registers + inst->data.DPImmediateData.dest; - + // Execute an arithmetic data processing instruction - case a64inst_DPI_ARITHM: + case a64inst_DPI_ARITHM:; // If shift flag is enabled, logical left shift by the number of bits specified by the architecture dword immediate = inst->data.DPImmediateData.processOpData.arithmData.immediate; @@ -54,26 +71,39 @@ static void executeDPImmediate(Machine *state, a64inst_instruction *inst) { } switch(inst->data.DPImmediateData.processOp) { + dword result; case(a64inst_ADDS): - // Fall through + result = srcVal + immediate; + writeRegister(state, dest, regType, result); + + updateCondNZ(state, result, regType); + state->conditionCodes.Overflow = max(srcVal, immediate) > result; + state->conditionCodes.Carry = state->conditionCodes.Overflow; + break; case(a64inst_ADD): - *dest = truncateValue(srcVal + immediate, regType); + writeRegister(state, dest, regType, srcVal + immediate); break; case(a64inst_SUBS): - // Fall through + result = srcVal - immediate; + writeRegister(state, dest, regType, result); + + updateCondNZ(state, result, regType); + state->conditionCodes.Overflow = srcVal < result; + state->conditionCodes.Carry = state->conditionCodes.Overflow; + break; case(a64inst_SUB): - *dest = truncateValue(srcVal - immediate, regType); + writeRegister(state, dest, regType, srcVal - immediate); break; // Unknown opcode detected! default: + fprintf(stderr, "Unknown opcode detected in a DPI arithmetic instruction!\n"); break; } - break; // Execute a wide move data processing instruction @@ -96,6 +126,7 @@ void execute(Machine *state, a64inst_instruction *inst) { // Execute a data processing immediate instruction case a64inst_DPIMMEDIATE: + executeDPImmediate(state, inst); break; // Execute a branch instruction @@ -104,6 +135,7 @@ void execute(Machine *state, a64inst_instruction *inst) { // Execute a data processing register instruction case a64inst_DPREGISTER: + readRegister(state, 0, 0); //FOR COMPILATION PURPOSES break; case a64inst_SINGLETRANSFER: diff --git a/src/execute.h b/src/execute.h index debc341..fcf39ec 100644 --- a/src/execute.h +++ b/src/execute.h @@ -2,7 +2,6 @@ #define __EXECUTE__ #include "a64instruction.h" #include "emulator.h" -#include "print.c" void execute(Machine *state, a64inst_instruction *inst); #endif From 9c299b3be075c567cb21378d6ca14d7a624cd4ad Mon Sep 17 00:00:00 2001 From: sBubshait Date: Mon, 3 Jun 2024 17:43:21 +0100 Subject: [PATCH 40/84] Add execute branch instruction, w/ T --- src/execute.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/src/execute.c b/src/execute.c index 4e0f608..b5ad72a 100644 --- a/src/execute.c +++ b/src/execute.c @@ -11,6 +11,7 @@ // Prototypes void execute_SDT(Machine *state, a64inst_instruction *inst); +void execute_Branch(Machine *state, a64inst_instruction *inst); // Return maximum of two dwords static dword max(dword a, dword b) { @@ -27,6 +28,28 @@ static dword truncateValue(dword value, a64inst_regType regType) { } } +// 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. @@ -131,6 +154,7 @@ void execute(Machine *state, a64inst_instruction *inst) { // Execute a branch instruction case a64inst_BRANCH: + execute_Branch(state, inst); break; // Execute a data processing register instruction @@ -193,4 +217,41 @@ void execute_SDT(Machine *state, a64inst_instruction *inst) { } } -} \ No newline at end of file +} + +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; + } +} + +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; + } +} From 3a20190f4fe210213465ba7b1f01b342632f25e0 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Mon, 3 Jun 2024 17:45:07 +0100 Subject: [PATCH 41/84] Add new line in end of files, w/ T --- src/a64instruction_SingleTransfer.h | 2 +- src/global.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/a64instruction_SingleTransfer.h b/src/a64instruction_SingleTransfer.h index 7b2524b..f661116 100644 --- a/src/a64instruction_SingleTransfer.h +++ b/src/a64instruction_SingleTransfer.h @@ -44,4 +44,4 @@ typedef struct { a64inst_SingleDataTransferData singleDataTransferData; a64inst_LoadLiteralData loadLiteralData; } processOpData; -} a64inst_SingleTransferData; \ No newline at end of file +} a64inst_SingleTransferData; diff --git a/src/global.h b/src/global.h index d3d015c..1cf226e 100644 --- a/src/global.h +++ b/src/global.h @@ -27,4 +27,4 @@ typedef uint32_t word; // Double word is a 64-bit unsigned integer. typedef uint64_t dword; -#endif \ No newline at end of file +#endif From 5fd5c512e641fb87dd0a244948d8c4a10403f52b Mon Sep 17 00:00:00 2001 From: sBubshait Date: Mon, 3 Jun 2024 17:55:54 +0100 Subject: [PATCH 42/84] Fix emulate to properly initialise state, w/ T --- src/emulate.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/emulate.c b/src/emulate.c index 6720dd0..df2f471 100755 --- a/src/emulate.c +++ b/src/emulate.c @@ -2,6 +2,7 @@ #include #include "emulator.h" #include "fileio.h" +#include "global.h" #include "print.h" #include "decode.h" #include "execute.h" @@ -26,10 +27,11 @@ int main(int argc, char **argv) { } // 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; + 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; @@ -37,18 +39,21 @@ int main(int argc, char **argv) { do { // Step 1: Fetch instruction at PC's address - wrd = readWord(state->memory, state->pc); + 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); - state->pc += 1; + execute(&state, inst); + + state.pc += sizeof(word); } while (inst->type != a64inst_HALT); - printState(state, out); - free(state->memory); + state.pc -= sizeof(word); + + printState(&state, out); + free(state.memory); return EXIT_SUCCESS; } From d9276899e4ce0be4ef32abc400512ebe73f2eab2 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Mon, 3 Jun 2024 18:14:04 +0100 Subject: [PATCH 43/84] Fixed register print representation and condition func check w/ S --- src/execute.c | 4 ++++ src/print.c | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/execute.c b/src/execute.c index b5ad72a..755a0f9 100644 --- a/src/execute.c +++ b/src/execute.c @@ -1,3 +1,4 @@ +#include #include #include "execute.h" #include "print.h" @@ -235,6 +236,9 @@ static bool isConditionMet(Machine* state, a64inst_ConditionType cond) { return state->conditionCodes.Zero || (state->conditionCodes.Negative != state->conditionCodes.Overflow); case AL: return true; + default: + fprintf(stderr, "Unknown condition specified!\n"); + exit(1); } } diff --git a/src/print.c b/src/print.c index 3021356..430f594 100644 --- a/src/print.c +++ b/src/print.c @@ -17,9 +17,9 @@ void printState(Machine *state, FILE *stream) { void printRegisters(Machine *state, FILE *stream) { fprintf(stream, "Registers:\n"); for (int i = 0; i < REGISTER_COUNT; i++) { - fprintf(stream, "X%02d\t= %" PRIu64 "\n", i, state->registers[i]); + fprintf(stream, "X%02d\t= %016x\n", i, (unsigned int)state->registers[i]); } - fprintf(stream, "PC\t= %" PRIu64 "\n", state->pc); + fprintf(stream, "PC\t= %016x\n", (unsigned int)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, From 851a54a51ea30cced44b780a10a25a1c613e2000 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Mon, 3 Jun 2024 19:35:21 +0100 Subject: [PATCH 44/84] Complete DPI execute function w/ S --- src/execute.c | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/src/execute.c b/src/execute.c index 755a0f9..3afa99c 100644 --- a/src/execute.c +++ b/src/execute.c @@ -6,10 +6,14 @@ // 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 immediate data processing instruction -// if the shift flag is enabled. +// 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); @@ -126,12 +130,37 @@ static void executeDPImmediate(Machine *state, a64inst_instruction *inst) { // Unknown opcode detected! default: fprintf(stderr, "Unknown opcode detected in a DPI arithmetic instruction!\n"); - break; + break; } break; // Execute a wide move data processing instruction - case a64inst_DPI_WIDEMOV: + case a64inst_DPI_WIDEMOV:; + uint8_t shiftScalar = inst->data.DPImmediateData.processOpData.wideMovData.shiftScalar; + uint16_t immediate = inst->data.DPImmediateData.processOpData.wideMovData.immediate; + + // NOTE: Not checking that shiftScalar has valid value for 32bit registers. Possibly add explicit error. + immediate = truncateValue(shiftScalar * DPI_WIDEMOV_SHIFT, regType); + switch(inst->data.DPImmediateData.processOp) { + + case(a64inst_MOVN): + writeRegister(state, dest, regType, ~immediate); + break; + + case(a64inst_MOVZ): + writeRegister(state, dest, regType, immediate); + break; + + case(a64inst_MOVK):; + dword result = readRegister(state, dest, regType); + result = (result & ~(((1 << DPI_WIDEMOV_SHIFT) - 1) << shiftScalar)) | immediate; + writeRegister(state, dest, regType, result); + break; + + default: + fprintf(stderr, "Unknown opcode detected in a DPI wide move instruction!\n"); + break; + } break; // Unknown instruction detected! From 20557a14eb24ca5e884de210720c6a235af4bb21 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Mon, 3 Jun 2024 20:34:14 +0100 Subject: [PATCH 45/84] Fix emulate so not increment PC if branch inst, w/ T --- src/emulate.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/emulate.c b/src/emulate.c index df2f471..82245e9 100755 --- a/src/emulate.c +++ b/src/emulate.c @@ -1,5 +1,6 @@ #include #include +#include "a64instruction.h" #include "emulator.h" #include "fileio.h" #include "global.h" @@ -47,7 +48,8 @@ int main(int argc, char **argv) { // Step 3: Update processor state to reflect executing the instruction, and increment PC execute(&state, inst); - state.pc += sizeof(word); + if (inst->type != a64inst_BRANCH) + state.pc += sizeof(word); } while (inst->type != a64inst_HALT); state.pc -= sizeof(word); From 5afcb8ef63785039075decfd678c2bfa3da61f3a Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Mon, 3 Jun 2024 20:40:05 +0100 Subject: [PATCH 46/84] Fix redeclaration of variable in execute w/ S --- src/execute.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/execute.c b/src/execute.c index 3afa99c..31d31aa 100644 --- a/src/execute.c +++ b/src/execute.c @@ -92,30 +92,30 @@ static void executeDPImmediate(Machine *state, a64inst_instruction *inst) { case a64inst_DPI_ARITHM:; // If shift flag is enabled, logical left shift by the number of bits specified by the architecture - dword immediate = inst->data.DPImmediateData.processOpData.arithmData.immediate; + 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) { - immediate = truncateValue(immediate << DPI_ARITHM_SHIFT, regType); + arithmImm = truncateValue(arithmImm << DPI_ARITHM_SHIFT, regType); } switch(inst->data.DPImmediateData.processOp) { dword result; case(a64inst_ADDS): - result = srcVal + immediate; + result = srcVal + arithmImm; writeRegister(state, dest, regType, result); updateCondNZ(state, result, regType); - state->conditionCodes.Overflow = max(srcVal, immediate) > result; + state->conditionCodes.Overflow = max(srcVal, arithmImm) > result; state->conditionCodes.Carry = state->conditionCodes.Overflow; break; case(a64inst_ADD): - writeRegister(state, dest, regType, srcVal + immediate); + writeRegister(state, dest, regType, srcVal + arithmImm); break; case(a64inst_SUBS): - result = srcVal - immediate; + result = srcVal - arithmImm; writeRegister(state, dest, regType, result); updateCondNZ(state, result, regType); @@ -124,7 +124,7 @@ static void executeDPImmediate(Machine *state, a64inst_instruction *inst) { break; case(a64inst_SUB): - writeRegister(state, dest, regType, srcVal - immediate); + writeRegister(state, dest, regType, srcVal - arithmImm); break; // Unknown opcode detected! @@ -137,23 +137,23 @@ static void executeDPImmediate(Machine *state, a64inst_instruction *inst) { // Execute a wide move data processing instruction case a64inst_DPI_WIDEMOV:; uint8_t shiftScalar = inst->data.DPImmediateData.processOpData.wideMovData.shiftScalar; - uint16_t immediate = inst->data.DPImmediateData.processOpData.wideMovData.immediate; + uint16_t wideMovImm = inst->data.DPImmediateData.processOpData.wideMovData.immediate; // NOTE: Not checking that shiftScalar has valid value for 32bit registers. Possibly add explicit error. - immediate = truncateValue(shiftScalar * DPI_WIDEMOV_SHIFT, regType); + wideMovImm = truncateValue(shiftScalar * DPI_WIDEMOV_SHIFT, regType); switch(inst->data.DPImmediateData.processOp) { case(a64inst_MOVN): - writeRegister(state, dest, regType, ~immediate); + writeRegister(state, dest, regType, ~wideMovImm); break; case(a64inst_MOVZ): - writeRegister(state, dest, regType, immediate); + writeRegister(state, dest, regType, wideMovImm); break; case(a64inst_MOVK):; dword result = readRegister(state, dest, regType); - result = (result & ~(((1 << DPI_WIDEMOV_SHIFT) - 1) << shiftScalar)) | immediate; + result = (result & ~(((1 << DPI_WIDEMOV_SHIFT) - 1) << shiftScalar)) | wideMovImm; writeRegister(state, dest, regType, result); break; From b19649192ae7f9a14658369b017dd2e5d23d6fac Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Mon, 3 Jun 2024 20:49:21 +0100 Subject: [PATCH 47/84] Fix bug with execute immediate value not being shifted w/ S --- src/execute.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/execute.c b/src/execute.c index 31d31aa..f82b97f 100644 --- a/src/execute.c +++ b/src/execute.c @@ -140,7 +140,7 @@ static void executeDPImmediate(Machine *state, a64inst_instruction *inst) { uint16_t wideMovImm = inst->data.DPImmediateData.processOpData.wideMovData.immediate; // NOTE: Not checking that shiftScalar has valid value for 32bit registers. Possibly add explicit error. - wideMovImm = truncateValue(shiftScalar * DPI_WIDEMOV_SHIFT, regType); + wideMovImm = truncateValue(wideMovImm << (shiftScalar * DPI_WIDEMOV_SHIFT), regType); switch(inst->data.DPImmediateData.processOp) { case(a64inst_MOVN): From 900091f7989070ce8dd4fe43364093dcdd821d14 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Mon, 3 Jun 2024 21:47:14 +0100 Subject: [PATCH 48/84] Fix getBits Bug when wanted bit is last bit, w/ T --- src/decode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/decode.c b/src/decode.c index d3fd0d6..a5b9277 100644 --- a/src/decode.c +++ b/src/decode.c @@ -11,7 +11,7 @@ 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 &= (1 << msb) - 1; + wrd &= ((dword) 1 << msb) - 1; return wrd >> lsb; } From d9562521caf4a189d4243c87bad0e55ee11d1998 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Mon, 3 Jun 2024 22:13:46 +0100 Subject: [PATCH 49/84] Fix print format bug, it used to only print lower 32 bits, w/ T --- src/print.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/print.c b/src/print.c index 430f594..e0b8eb4 100644 --- a/src/print.c +++ b/src/print.c @@ -17,9 +17,9 @@ void printState(Machine *state, FILE *stream) { void printRegisters(Machine *state, FILE *stream) { fprintf(stream, "Registers:\n"); for (int i = 0; i < REGISTER_COUNT; i++) { - fprintf(stream, "X%02d\t= %016x\n", i, (unsigned int)state->registers[i]); + fprintf(stream, "X%02d\t= %016llx\n", i, state->registers[i]); } - fprintf(stream, "PC\t= %016x\n", (unsigned int)state->pc); + fprintf(stream, "PC\t= %016llx\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, @@ -52,7 +52,7 @@ void printMemory(Machine *state, FILE *stream) { for (int addr = 0; addr < MEMORY_SIZE; addr+= 4) { word data = readWord(state->memory, addr); if (data != 0) { - fprintf(stream, "0x%08x: 0x%08x\n", addr, data); + fprintf(stream, "0x%08x: %08x\n", addr, data); } } } From d290201004f510036ab88d1d7729bec3664e8789 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Mon, 3 Jun 2024 22:30:07 +0100 Subject: [PATCH 50/84] Fix print bug, fix portability issue, w/ T --- src/print.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/print.c b/src/print.c index e0b8eb4..c23f25b 100644 --- a/src/print.c +++ b/src/print.c @@ -17,9 +17,9 @@ void printState(Machine *state, FILE *stream) { void printRegisters(Machine *state, FILE *stream) { fprintf(stream, "Registers:\n"); for (int i = 0; i < REGISTER_COUNT; i++) { - fprintf(stream, "X%02d\t= %016llx\n", i, state->registers[i]); + fprintf(stream, "X%02d\t= %016" PRIu64 "\n", i, state->registers[i]); } - fprintf(stream, "PC\t= %016llx\n", state->pc); + fprintf(stream, "PC\t= %016" PRIu64 "\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, From be6b0cf4299b5dd6b08048071d3a41749a4fceaf Mon Sep 17 00:00:00 2001 From: sBubshait Date: Mon, 3 Jun 2024 22:33:40 +0100 Subject: [PATCH 51/84] Fix Bug in Print.c to print Hex instead of decimal, w/ T --- src/print.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/print.c b/src/print.c index c23f25b..1d1d4a2 100644 --- a/src/print.c +++ b/src/print.c @@ -17,9 +17,9 @@ void printState(Machine *state, FILE *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" PRIu64 "\n", i, state->registers[i]); + fprintf(stream, "X%02d\t= %016" PRIx64 "\n", i, state->registers[i]); } - fprintf(stream, "PC\t= %016" PRIu64 "\n", state->pc); + 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, From efc8c087f901ae2756cde2026c3d109f1f759c9f Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Mon, 3 Jun 2024 22:37:58 +0100 Subject: [PATCH 52/84] Fixed bug with size of immediate values for emulator w/ S --- src/execute.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/execute.c b/src/execute.c index f82b97f..4171063 100644 --- a/src/execute.c +++ b/src/execute.c @@ -29,7 +29,7 @@ static dword truncateValue(dword value, a64inst_regType regType) { return value; } else { //return value & ~(dword)((1 << WORD_BITS) - 1) - return value & (((dword)1 << WORD_BITS) - 1); + return value & (dword)(((dword)1 << WORD_BITS) - 1); } } @@ -67,10 +67,15 @@ static dword readRegister(Machine *state, a64inst_regSpecifier reg, a64inst_regT } } -// Read from processor register, ensuring that a valid register specifier is given +// 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) { - state->registers[reg] = truncateValue(value, regType); + assert(reg <= REGISTER_COUNT); + if (regType == a64inst_R) { + state->registers[reg] = truncateValue(value, regType); + } else { + *(word*)(state->registers + reg) = (word)truncateValue(value, regType); + } } // Updates N and Z condition codes given the machine and a result value @@ -137,9 +142,10 @@ static void executeDPImmediate(Machine *state, a64inst_instruction *inst) { // Execute a wide move data processing instruction case a64inst_DPI_WIDEMOV:; uint8_t shiftScalar = inst->data.DPImmediateData.processOpData.wideMovData.shiftScalar; - uint16_t wideMovImm = inst->data.DPImmediateData.processOpData.wideMovData.immediate; + 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) { From c6574b72f87001c34ef76b5bf58831c26bb5dad5 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Mon, 3 Jun 2024 22:40:31 +0100 Subject: [PATCH 53/84] Fix Bug In Unsigned Offset SDT, multiply correctly, w/ T --- src/execute.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/execute.c b/src/execute.c index 4171063..55f69e6 100644 --- a/src/execute.c +++ b/src/execute.c @@ -221,8 +221,7 @@ void execute_SDT(Machine *state, a64inst_instruction *inst) { 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; - address *= inst->data.SingleTransferData.regType == a64inst_W ? 4 : 8; + 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]; From d6b551c190926873794ca23e5013ffc598445784 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Tue, 4 Jun 2024 13:24:31 +0100 Subject: [PATCH 54/84] Fix function that updates N and Z flags of processor w/ S --- src/execute.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/execute.c b/src/execute.c index 55f69e6..8271719 100644 --- a/src/execute.c +++ b/src/execute.c @@ -80,7 +80,9 @@ static void writeRegister(Machine *state, a64inst_regSpecifier reg, a64inst_regT // 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 = result & ((1 << (regType ? DWORD_BITS : WORD_BITS)) - 1); + size_t msb = (regType ? DWORD_BITS : WORD_BITS) - 1; + + state->conditionCodes.Negative = result >> msb; state->conditionCodes.Zero = result == 0; } @@ -243,7 +245,7 @@ void execute_SDT(Machine *state, a64inst_instruction *inst) { } else { state->registers[inst->data.SingleTransferData.target] = readDoubleWord(state->memory, address); } - }else { + } else { if (inst->data.SingleTransferData.regType == a64inst_W) { // 32 bit access state->registers[inst->data.SingleTransferData.target] = readWord(state->memory, address); From bb6fa95adea0145356f12a42a9dad44e12f8e987 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Tue, 4 Jun 2024 15:09:53 +0100 Subject: [PATCH 55/84] Add DPR type instruction data to IR of a64 instructions --- src/a64instruction.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/a64instruction.h b/src/a64instruction.h index 463e75a..b2c75cf 100644 --- a/src/a64instruction.h +++ b/src/a64instruction.h @@ -1,6 +1,7 @@ #ifndef __A64INSTRUCTION__ #define __A64INSTRUCTION__ #include "a64instruction_DPImmediate.h" +#include "a64instruction_DPRegister.h" #include "a64instruction_Branch.h" #include "a64instruction_SingleTransfer.h" @@ -20,6 +21,7 @@ typedef struct { a64inst_type type; union { a64inst_DPImmediateData DPImmediateData; + a64inst_DPRegisterData DPRegisterData; a64inst_BranchData BranchData; a64inst_SingleTransferData SingleTransferData; } data; From 2402e3d2680229672a8e6ffe8f90ce19fcc00217 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Tue, 4 Jun 2024 15:41:58 +0100 Subject: [PATCH 56/84] Update DPR type instruction IR operand field name --- src/a64instruction_DPRegister.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/a64instruction_DPRegister.h b/src/a64instruction_DPRegister.h index d0252ee..401f225 100644 --- a/src/a64instruction_DPRegister.h +++ b/src/a64instruction_DPRegister.h @@ -47,7 +47,7 @@ typedef struct { union { a64inst_logicOp logicOp; a64inst_arithmOp arithmOp; - } processOpId; + } processOp; a64inst_regSpecifier src2; union { a64inst_DPRegister_ArithmLogicData arithmLogicData; From ff2568045543cfebb678371b8e69a2dd9132d592 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Wed, 5 Jun 2024 14:00:49 +0100 Subject: [PATCH 57/84] Update names of decode SDT constants to follow style --- src/decode.c | 24 ++++++++++++------------ src/decode.h | 48 ++++++++++++++++++++++++------------------------ 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/decode.c b/src/decode.c index a5b9277..f7161f9 100644 --- a/src/decode.c +++ b/src/decode.c @@ -100,33 +100,33 @@ a64inst_instruction *decode(word wrd) { // Load and Store, or unknown // Ignore unknown for now inst->type = a64inst_SINGLETRANSFER; - inst->data.SingleTransferData.regType = getBits(wrd, SINGLE_TRANSFER_REGTYPE_FLAG_LSB, SINGLE_TRANSFER_REGTYPE_FLAG_MSB); - inst->data.SingleTransferData.target = getBits(wrd, SINGLE_TRANSFER_TARGET_REG_LSB, SINGLE_TRANSFER_TARGET_REG_MSB); + 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, SINGLE_TRANSFER_OPTYPE_FLAG_LSB, SINGLE_TRANSFER_OPTYPE_FLAG_MSB) == a64inst_SINGLE_TRANSFER_SINGLE_DATA_TRANSFER) { + 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, SINGLE_DATA_TRANSFER_TRANSFER_TYPE_LSB, SINGLE_DATA_TRANSFER_TRANSFER_TYPE_MSB); - inst->data.SingleTransferData.processOpData.singleDataTransferData.base = getBits(wrd, SINGLE_DATA_TRANSFER_BASE_REG_LSB, SINGLE_DATA_TRANSFER_BASE_REG_MSB); - if (getBits(wrd, SINGLE_DATA_TRANSFER_UNSIGNED_FLAG_LSB, SINGLE_DATA_TRANSFER_UNSIGNED_FLAG_MSB) == 1) { + 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, SINGLE_DATA_TRANSFER_OFFSET_LSB, SINGLE_DATA_TRANSFER_OFFSET_MSB); - } else if (getBits(wrd, SINGLE_DATA_TRANSFER_REGISTER_FLAG_LSB, SINGLE_DATA_TRANSFER_REGISTER_FLAG_MSB) == 1) { + 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, SINGLE_DATA_TRANSFER_REGISTER_REG_LSB, SINGLE_DATA_TRANSFER_REGISTER_REG_MSB); + 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, SINGLE_DATA_TRANSFER_INDEXED_ADDRMODE_LSB, SINGLE_DATA_TRANSFER_INDEXED_ADDRMODE_MSB); - inst->data.SingleTransferData.processOpData.singleDataTransferData.a64inst_addressingModeData.indexedOffset = getBits(wrd, SINGLE_DATA_TRANSFER_INDEXED_OFFSET_LSB, SINGLE_DATA_TRANSFER_INDEXED_OFFSET_MSB); + 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, SINGLE_DATA_TRANSFER_LOAD_LITERAL_OFFSET_LSB, SINGLE_DATA_TRANSFER_LOAD_LITERAL_OFFSET_MSB); + inst->data.SingleTransferData.processOpData.loadLiteralData.offset = getBits(wrd, SDT_LOAD_LITERAL_OFFSET_LSB, SDT_LOAD_LITERAL_OFFSET_MSB); } } diff --git a/src/decode.h b/src/decode.h index d8c454a..6741c95 100644 --- a/src/decode.h +++ b/src/decode.h @@ -32,31 +32,31 @@ #define DP_IMM_WIDEMOV_IMMVAL_LSB 5 #define DP_IMM_WIDEMOV_IMMVAL_MSB 21 -#define SINGLE_TRANSFER_OPTYPE_FLAG_LSB 31 -#define SINGLE_TRANSFER_OPTYPE_FLAG_MSB 32 -#define SINGLE_TRANSFER_REGTYPE_FLAG_LSB 30 -#define SINGLE_TRANSFER_REGTYPE_FLAG_MSB 31 -#define SINGLE_TRANSFER_TARGET_REG_LSB 0 -#define SINGLE_TRANSFER_TARGET_REG_MSB 5 +#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 SINGLE_DATA_TRANSFER_BASE_REG_LSB 5 -#define SINGLE_DATA_TRANSFER_BASE_REG_MSB 10 -#define SINGLE_DATA_TRANSFER_OFFSET_LSB 10 -#define SINGLE_DATA_TRANSFER_OFFSET_MSB 22 -#define SINGLE_DATA_TRANSFER_TRANSFER_TYPE_LSB 22 -#define SINGLE_DATA_TRANSFER_TRANSFER_TYPE_MSB 23 -#define SINGLE_DATA_TRANSFER_UNSIGNED_FLAG_LSB 24 -#define SINGLE_DATA_TRANSFER_UNSIGNED_FLAG_MSB 25 -#define SINGLE_DATA_TRANSFER_REGISTER_FLAG_LSB 21 -#define SINGLE_DATA_TRANSFER_REGISTER_FLAG_MSB 22 -#define SINGLE_DATA_TRANSFER_REGISTER_REG_LSB 16 -#define SINGLE_DATA_TRANSFER_REGISTER_REG_MSB 21 -#define SINGLE_DATA_TRANSFER_INDEXED_ADDRMODE_LSB 11 -#define SINGLE_DATA_TRANSFER_INDEXED_ADDRMODE_MSB 12 -#define SINGLE_DATA_TRANSFER_INDEXED_OFFSET_LSB 12 -#define SINGLE_DATA_TRANSFER_INDEXED_OFFSET_MSB 21 -#define SINGLE_DATA_TRANSFER_LOAD_LITERAL_OFFSET_LSB 5 -#define SINGLE_DATA_TRANSFER_LOAD_LITERAL_OFFSET_MSB 24 +#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 From 93031e82e0459a6add4b68c32c363a190b561945 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Wed, 5 Jun 2024 16:38:13 +0100 Subject: [PATCH 58/84] Complete decode for DPR instructions and complete their IR --- src/a64instruction_DP.h | 5 +++++ src/a64instruction_DPRegister.h | 10 ++++----- src/decode.c | 38 ++++++++++++++++++++++++++++++--- src/decode.h | 38 +++++++++++++++++++++++++++------ 4 files changed, 76 insertions(+), 15 deletions(-) diff --git a/src/a64instruction_DP.h b/src/a64instruction_DP.h index 113f589..8ffb1f7 100644 --- a/src/a64instruction_DP.h +++ b/src/a64instruction_DP.h @@ -1,3 +1,6 @@ +#ifndef __A64INSTRUCTION_DP__ +#define __A64INSTRUCTION_DP__ + // Denotes the type of arithmetic operations supported by the architecture typedef enum { a64inst_ADD = 0, @@ -5,3 +8,5 @@ typedef enum { a64inst_SUB = 2, a64inst_SUBS = 3 } a64inst_arithmOp; + +#endif diff --git a/src/a64instruction_DPRegister.h b/src/a64instruction_DPRegister.h index 401f225..d82510a 100644 --- a/src/a64instruction_DPRegister.h +++ b/src/a64instruction_DPRegister.h @@ -4,8 +4,8 @@ // Denotes the type of data processing operation typedef enum { - a64inst_DPR_ARITHMLOGIC, - a64inst_DPR_MULTIPLY + a64inst_DPR_ARITHMLOGIC = 0, + a64inst_DPR_MULTIPLY = 1 } a64inst_DPROpType; // Denotes the logical operations supported by the architecture @@ -31,6 +31,7 @@ typedef struct { a64inst_DPR_LOGIC = 1 } type; a64inst_ShiftType shiftType; + uint8_t shiftAmount; bool negShiftedSrc2; // Guaranteed to be 0 for arithmetic instructions } a64inst_DPRegister_ArithmLogicData; @@ -44,10 +45,7 @@ typedef struct { typedef struct { a64inst_regType regType; a64inst_DPROpType DPROpType; - union { - a64inst_logicOp logicOp; - a64inst_arithmOp arithmOp; - } processOp; + uint8_t processOp; a64inst_regSpecifier src2; union { a64inst_DPRegister_ArithmLogicData arithmLogicData; diff --git a/src/decode.c b/src/decode.c index f7161f9..6c969d8 100644 --- a/src/decode.c +++ b/src/decode.c @@ -33,9 +33,9 @@ a64inst_instruction *decode(word wrd) { // Data Processing Immediate interpretation } else if (typeId == DP_IMM_ID) { inst->type = a64inst_DPIMMEDIATE; - inst->data.DPImmediateData.regType = getBits(wrd, DP_IMM_WIDTH_LSB, DP_IMM_WIDTH_MSB); - inst->data.DPImmediateData.processOp = getBits(wrd, DP_IMM_OP_LSB, DP_IMM_OP_MSB); - inst->data.DPImmediateData.dest = getBits(wrd, DP_IMM_DEST_LSB, DP_IMM_DEST_MSB); + 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)) { @@ -93,8 +93,40 @@ a64inst_instruction *decode(word wrd) { 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: + 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 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 diff --git a/src/decode.h b/src/decode.h index 6741c95..132130e 100644 --- a/src/decode.h +++ b/src/decode.h @@ -11,12 +11,13 @@ #define DP_REG_LSB 25 #define DP_REG_MSB 26 -#define DP_IMM_WIDTH_LSB 31 -#define DP_IMM_WIDTH_MSB 32 -#define DP_IMM_OP_LSB 29 -#define DP_IMM_OP_MSB 31 -#define DP_IMM_DEST_LSB 0 -#define DP_IMM_DEST_MSB 5 +#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 @@ -32,6 +33,31 @@ #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 From 8b0bb1888b46d1b2f5c69233660ae3f419ec706d Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Wed, 5 Jun 2024 20:00:25 +0100 Subject: [PATCH 59/84] Changed constant name for 64 bit register type w/ S --- src/a64instruction_global.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/a64instruction_global.h b/src/a64instruction_global.h index 489fe06..ff748a6 100644 --- a/src/a64instruction_global.h +++ b/src/a64instruction_global.h @@ -8,7 +8,7 @@ typedef uint8_t a64inst_regSpecifier; // Denotes the type of register being referred to typedef enum { a64inst_W = 0, - a64inst_R = 1 + a64inst_X = 1 } a64inst_regType; #endif From 024044afc74da74d9c7be232355573caf004ce81 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Wed, 5 Jun 2024 20:11:56 +0100 Subject: [PATCH 60/84] Add decode and execute structure for DPI instructions w/ S --- src/decode.c | 5 +- src/execute.c | 167 ++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 153 insertions(+), 19 deletions(-) diff --git a/src/decode.c b/src/decode.c index 6c969d8..7634753 100644 --- a/src/decode.c +++ b/src/decode.c @@ -113,6 +113,9 @@ a64inst_instruction *decode(word wrd) { 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; @@ -121,7 +124,7 @@ a64inst_instruction *decode(word wrd) { arithmLogicData.type == DP_REG_MULTIPLY_ARITHMFLAG && arithmLogicData.shiftType == DP_REG_MULTIPLY_SHIFTTYPE && arithmLogicData.negShiftedSrc2 == DP_REG_MULTIPLY_NEGSRC2FLAG)) { - fprintf(stderr, "Attempting to decode multiply instruction with invalid format!\n"); + 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); diff --git a/src/execute.c b/src/execute.c index 8271719..42846b3 100644 --- a/src/execute.c +++ b/src/execute.c @@ -25,11 +25,11 @@ static dword max(dword a, dword 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_R) { + if (regType == a64inst_X) { return value; } else { - //return value & ~(dword)((1 << WORD_BITS) - 1) - return value & (dword)(((dword)1 << WORD_BITS) - 1); + return (word)value; + //return value & (dword)(((dword)1 << WORD_BITS) - 1); } } @@ -67,35 +67,40 @@ static dword readRegister(Machine *state, a64inst_regSpecifier reg, a64inst_regT } } +// 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. +// 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 (regType == a64inst_R) { - state->registers[reg] = truncateValue(value, regType); - } else { - *(word*)(state->registers + reg) = (word)truncateValue(value, regType); - } + 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) { - size_t msb = (regType ? DWORD_BITS : WORD_BITS) - 1; - - state->conditionCodes.Negative = result >> msb; + 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 data processing instruction + // 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 @@ -106,8 +111,8 @@ static void executeDPImmediate(Machine *state, a64inst_instruction *inst) { } switch(inst->data.DPImmediateData.processOp) { + dword result; - case(a64inst_ADDS): result = srcVal + arithmImm; writeRegister(state, dest, regType, result); @@ -131,6 +136,7 @@ static void executeDPImmediate(Machine *state, a64inst_instruction *inst) { break; case(a64inst_SUB): + printf("wag1\n"); writeRegister(state, dest, regType, srcVal - arithmImm); break; @@ -141,7 +147,7 @@ static void executeDPImmediate(Machine *state, a64inst_instruction *inst) { } break; - // Execute a wide move data processing instruction + // 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; @@ -173,6 +179,131 @@ static void executeDPImmediate(Machine *state, a64inst_instruction *inst) { // 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: + src2Val = truncateValue((int64_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; + } + + 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 = src1Val < result; + state->conditionCodes.Carry = state->conditionCodes.Overflow; + 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; } } @@ -197,7 +328,7 @@ void execute(Machine *state, a64inst_instruction *inst) { // Execute a data processing register instruction case a64inst_DPREGISTER: - readRegister(state, 0, 0); //FOR COMPILATION PURPOSES + executeDPRegister(state, inst); break; case a64inst_SINGLETRANSFER: From 9ea494acfc87e6dda4070acc27594e3cf31de07e Mon Sep 17 00:00:00 2001 From: sBubshait Date: Wed, 5 Jun 2024 20:14:12 +0100 Subject: [PATCH 61/84] Fix branch enum numbering to match the spec, w/ T --- src/a64instruction_Branch.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/a64instruction_Branch.h b/src/a64instruction_Branch.h index 1681768..b732d6d 100644 --- a/src/a64instruction_Branch.h +++ b/src/a64instruction_Branch.h @@ -4,8 +4,8 @@ typedef enum { a64inst_UNCONDITIONAL = 0, - a64inst_REGISTER = 1, - a64inst_CONDITIONAL = 2 + a64inst_REGISTER = 3, + a64inst_CONDITIONAL = 1 } a64inst_BranchType; typedef struct { From 379dedc6ce4dfeaeef3c5287a904025e7fe33bdb Mon Sep 17 00:00:00 2001 From: sBubshait Date: Wed, 5 Jun 2024 20:25:47 +0100 Subject: [PATCH 62/84] Add execution of Multiply DP Register Instructions, w/ T --- src/execute.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/execute.c b/src/execute.c index 42846b3..9edeb74 100644 --- a/src/execute.c +++ b/src/execute.c @@ -17,6 +17,7 @@ // 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) { @@ -328,7 +329,10 @@ void execute(Machine *state, a64inst_instruction *inst) { // Execute a data processing register instruction case a64inst_DPREGISTER: - executeDPRegister(state, inst); + if (inst->data.DPRegisterData.DPROpType == a64inst_DPR_MULTIPLY) + executeMultiply(state, inst); + else + executeDPRegister(state, inst); break; case a64inst_SINGLETRANSFER: @@ -426,3 +430,9 @@ void execute_Branch(Machine *state, a64inst_instruction *inst) { 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); +} From 120b492a488da9e31f9b4c3df5fa2881c03b7847 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Wed, 5 Jun 2024 20:54:22 +0100 Subject: [PATCH 63/84] Added structs to represent labels and directives for assembler --- src/a64instruction.h | 8 +++++++- src/a64instruction_Directive.h | 5 +++++ src/a64instruction_Label.h | 3 +++ 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 src/a64instruction_Directive.h create mode 100644 src/a64instruction_Label.h diff --git a/src/a64instruction.h b/src/a64instruction.h index b2c75cf..c12584c 100644 --- a/src/a64instruction.h +++ b/src/a64instruction.h @@ -4,6 +4,8 @@ #include "a64instruction_DPRegister.h" #include "a64instruction_Branch.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. // Each type is defined by the format of the instruction's operand(s). @@ -13,7 +15,9 @@ typedef enum { a64inst_SINGLETRANSFER, a64inst_LOADLITERAL, a64inst_BRANCH, - a64inst_HALT + a64inst_HALT, + a64inst_LABEL, + a64inst_DIRECTIVE } a64inst_type; // Structure the holds the type and operand data of an instruction @@ -24,6 +28,8 @@ typedef struct { a64inst_DPRegisterData DPRegisterData; a64inst_BranchData BranchData; a64inst_SingleTransferData SingleTransferData; + a64inst_LabelData LabelData; + a64inst_DirectiveData DirectiveData; } data; } a64inst_instruction; diff --git a/src/a64instruction_Directive.h b/src/a64instruction_Directive.h new file mode 100644 index 0000000..797b9c3 --- /dev/null +++ b/src/a64instruction_Directive.h @@ -0,0 +1,5 @@ +include "global.h" + +typedef struct { + dword value; +} a64inst_DirectiveData; \ No newline at end of file diff --git a/src/a64instruction_Label.h b/src/a64instruction_Label.h new file mode 100644 index 0000000..b80979e --- /dev/null +++ b/src/a64instruction_Label.h @@ -0,0 +1,3 @@ +typedef struct { + char* label; +} a64inst_LabelData; \ No newline at end of file From b3ccee44bbb19371c6daaa8324f3ea64de708fbb Mon Sep 17 00:00:00 2001 From: sBubshait Date: Wed, 5 Jun 2024 21:23:52 +0100 Subject: [PATCH 64/84] Change enum values in DP Register to match the spec, w/ T --- src/a64instruction_DPRegister.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/a64instruction_DPRegister.h b/src/a64instruction_DPRegister.h index d82510a..ecf2f2c 100644 --- a/src/a64instruction_DPRegister.h +++ b/src/a64instruction_DPRegister.h @@ -27,8 +27,8 @@ typedef enum { // Holds data specific to arithmetic/logic register data processing instructions typedef struct { enum { - a64inst_DPR_ARITHM = 0, - a64inst_DPR_LOGIC = 1 + a64inst_DPR_ARITHM = 1, + a64inst_DPR_LOGIC = 0 } type; a64inst_ShiftType shiftType; uint8_t shiftAmount; From 5bb7d8615650a4743d963a755861a9ac518f719c Mon Sep 17 00:00:00 2001 From: sBubshait Date: Wed, 5 Jun 2024 21:30:41 +0100 Subject: [PATCH 65/84] Fix syntax, add new line in end of file and # before include, w/ T --- src/a64instruction_Directive.h | 4 ++-- src/a64instruction_Label.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/a64instruction_Directive.h b/src/a64instruction_Directive.h index 797b9c3..5c70dd4 100644 --- a/src/a64instruction_Directive.h +++ b/src/a64instruction_Directive.h @@ -1,5 +1,5 @@ -include "global.h" +#include "global.h" typedef struct { dword value; -} a64inst_DirectiveData; \ No newline at end of file +} a64inst_DirectiveData; diff --git a/src/a64instruction_Label.h b/src/a64instruction_Label.h index b80979e..b1d26e9 100644 --- a/src/a64instruction_Label.h +++ b/src/a64instruction_Label.h @@ -1,3 +1,3 @@ typedef struct { char* label; -} a64inst_LabelData; \ No newline at end of file +} a64inst_LabelData; From 14fbb7e4fca2b1fff92ab61744b55d10141b6772 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Wed, 5 Jun 2024 21:31:41 +0100 Subject: [PATCH 66/84] Fix Bug: Struct was not being changed because it wasn't a ptr, w/ T --- src/decode.c | 18 +++++++++--------- src/execute.c | 10 +++++----- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/decode.c b/src/decode.c index 7634753..ce69c35 100644 --- a/src/decode.c +++ b/src/decode.c @@ -104,26 +104,26 @@ a64inst_instruction *decode(word wrd) { 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; + 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); + 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)) { + 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); + 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)) { + 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); diff --git a/src/execute.c b/src/execute.c index 9edeb74..837dd0c 100644 --- a/src/execute.c +++ b/src/execute.c @@ -200,9 +200,9 @@ static void executeDPRegister(Machine *state, a64inst_instruction *inst) { 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) { + 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); @@ -217,7 +217,7 @@ static void executeDPRegister(Machine *state, a64inst_instruction *inst) { break; case a64inst_ROR: - if (arithmLogicData.type != a64inst_DPR_LOGIC) { + 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); @@ -229,7 +229,7 @@ static void executeDPRegister(Machine *state, a64inst_instruction *inst) { } dword result; - switch(arithmLogicData.type) { + switch(arithmLogicData->type) { case a64inst_DPR_ARITHM: switch(inst->data.DPRegisterData.processOp) { From 294b03ddde39c997a5635b61f9173717d317fb04 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Wed, 5 Jun 2024 22:21:32 +0100 Subject: [PATCH 67/84] Added ability to write to zero register (discard) w/ S --- src/execute.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/execute.c b/src/execute.c index 837dd0c..ef5763b 100644 --- a/src/execute.c +++ b/src/execute.c @@ -74,7 +74,9 @@ static dword readRegister(Machine *state, a64inst_regSpecifier reg, a64inst_regT // 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); - state->registers[reg] = truncateValue(value, regType); + if (reg != ZERO_REGISTER) { + state->registers[reg] = truncateValue(value, regType); + } } // Returns the position of the MSB of the given register type From cc62168d43d0c2fceabc2d972a2d5cd187467382 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Wed, 5 Jun 2024 22:23:51 +0100 Subject: [PATCH 68/84] Remove debugging code w/ S --- src/execute.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/execute.c b/src/execute.c index ef5763b..d49878c 100644 --- a/src/execute.c +++ b/src/execute.c @@ -139,7 +139,6 @@ static void executeDPImmediate(Machine *state, a64inst_instruction *inst) { break; case(a64inst_SUB): - printf("wag1\n"); writeRegister(state, dest, regType, srcVal - arithmImm); break; From dd472117aa4002952d90c7110a3f61ae8fb237f2 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Wed, 5 Jun 2024 22:50:04 +0100 Subject: [PATCH 69/84] Add negation for second operand in DPR instructions w/ S --- src/execute.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/execute.c b/src/execute.c index d49878c..0506370 100644 --- a/src/execute.c +++ b/src/execute.c @@ -203,6 +203,9 @@ static void executeDPRegister(Machine *state, a64inst_instruction *inst) { // Apply shift to value held in second register a64inst_DPRegister_ArithmLogicData *arithmLogicData = &inst->data.DPRegisterData.processOpData.arithmLogicData; uint8_t shiftAmount = arithmLogicData->shiftAmount; + if (arithmLogicData->negShiftedSrc2) { + src2Val = ~src2Val; + } switch(arithmLogicData->shiftType) { case a64inst_LSL: @@ -214,7 +217,11 @@ static void executeDPRegister(Machine *state, a64inst_instruction *inst) { break; case a64inst_ASR: - src2Val = truncateValue((int64_t)src2Val >> shiftAmount, regType); + if (regType == a64inst_X) { + src2Val = truncateValue((int64_t)src2Val >> shiftAmount, regType); + } else { + src2Val = truncateValue((int32_t)src2Val >> shiftAmount, regType); + } break; case a64inst_ROR: From 75a8d79bb45f0b095f6946bd096f057c840f100b Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Wed, 5 Jun 2024 23:19:53 +0100 Subject: [PATCH 70/84] Changed order of operations for DPR logic instructions w/ S --- src/execute.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/execute.c b/src/execute.c index 0506370..86aa33c 100644 --- a/src/execute.c +++ b/src/execute.c @@ -203,9 +203,6 @@ static void executeDPRegister(Machine *state, a64inst_instruction *inst) { // Apply shift to value held in second register a64inst_DPRegister_ArithmLogicData *arithmLogicData = &inst->data.DPRegisterData.processOpData.arithmLogicData; uint8_t shiftAmount = arithmLogicData->shiftAmount; - if (arithmLogicData->negShiftedSrc2) { - src2Val = ~src2Val; - } switch(arithmLogicData->shiftType) { case a64inst_LSL: @@ -236,6 +233,11 @@ static void executeDPRegister(Machine *state, a64inst_instruction *inst) { break; } + // Negate second operand if negShiftedSrc2 flag is enabled + if (arithmLogicData->negShiftedSrc2) { + src2Val = truncateValue(~src2Val, regType); + } + dword result; switch(arithmLogicData->type) { From a3dd8094372a7e6210b1f2792fe8746254f1a9c4 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Wed, 5 Jun 2024 23:30:20 +0100 Subject: [PATCH 71/84] Update execute, implemented the store instrs, w/ T --- src/execute.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/execute.c b/src/execute.c index 86aa33c..9c8734b 100644 --- a/src/execute.c +++ b/src/execute.c @@ -391,11 +391,11 @@ void execute_SDT(Machine *state, a64inst_instruction *inst) { state->registers[inst->data.SingleTransferData.target] = readDoubleWord(state->memory, address); } } else { - 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); + *(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); } } From 40c5fac9f66992a8d1db9b55bb5c6c174f819b6a Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Wed, 5 Jun 2024 23:43:36 +0100 Subject: [PATCH 72/84] Fixed bug with movk overwriting wrong bits w/ S --- src/execute.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/execute.c b/src/execute.c index 9c8734b..24e002d 100644 --- a/src/execute.c +++ b/src/execute.c @@ -169,7 +169,7 @@ static void executeDPImmediate(Machine *state, a64inst_instruction *inst) { case(a64inst_MOVK):; dword result = readRegister(state, dest, regType); - result = (result & ~(((1 << DPI_WIDEMOV_SHIFT) - 1) << shiftScalar)) | wideMovImm; + result = (result & ~(((1 << DPI_WIDEMOV_SHIFT) - 1) << shiftScalar * DPI_WIDEMOV_SHIFT)) | wideMovImm; writeRegister(state, dest, regType, result); break; From 7b1e6314a7974967789dc987bc693671d285fd96 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Wed, 5 Jun 2024 23:58:56 +0100 Subject: [PATCH 73/84] Fix Subs handling of carry PSTATE condition code, w/ T --- src/execute.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/execute.c b/src/execute.c index 24e002d..dc0d4d8 100644 --- a/src/execute.c +++ b/src/execute.c @@ -263,7 +263,7 @@ static void executeDPRegister(Machine *state, a64inst_instruction *inst) { updateCondNZ(state, result, regType); state->conditionCodes.Overflow = src1Val < result; - state->conditionCodes.Carry = state->conditionCodes.Overflow; + state->conditionCodes.Carry = src1Val >= src2Val; break; case(a64inst_SUB): From 95c74964b3e7d3efbf49777a8318866a464b4a98 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Thu, 6 Jun 2024 00:35:48 +0100 Subject: [PATCH 74/84] Fix movk to not overwrite entire register for large scalars w/ S --- src/execute.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/execute.c b/src/execute.c index dc0d4d8..cc5d0ba 100644 --- a/src/execute.c +++ b/src/execute.c @@ -169,7 +169,7 @@ static void executeDPImmediate(Machine *state, a64inst_instruction *inst) { case(a64inst_MOVK):; dword result = readRegister(state, dest, regType); - result = (result & ~(((1 << DPI_WIDEMOV_SHIFT) - 1) << shiftScalar * DPI_WIDEMOV_SHIFT)) | wideMovImm; + result = (result & ~(((1lu << DPI_WIDEMOV_SHIFT) - 1) << shiftScalar * DPI_WIDEMOV_SHIFT)) | wideMovImm; writeRegister(state, dest, regType, result); break; From d73111515e9b1f353d849664b7527824116f34d8 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Thu, 6 Jun 2024 00:47:06 +0100 Subject: [PATCH 75/84] Fix Overflow handling in Subtraction DP Register, w/ T --- src/execute.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/execute.c b/src/execute.c index cc5d0ba..fc436af 100644 --- a/src/execute.c +++ b/src/execute.c @@ -262,7 +262,7 @@ static void executeDPRegister(Machine *state, a64inst_instruction *inst) { writeRegister(state, dest, regType, result); updateCondNZ(state, result, regType); - state->conditionCodes.Overflow = src1Val < result; + state->conditionCodes.Overflow = getMSB(src1Val, regType) != getMSB(src2Val, regType) && getMSB(src1Val, regType) != getMSB(result, regType); state->conditionCodes.Carry = src1Val >= src2Val; break; From 460b19aaf4b1ba1f605a032c266488a20b9fdb84 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Thu, 6 Jun 2024 13:19:36 +0100 Subject: [PATCH 76/84] Fix ROR shift logic --- src/execute.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/execute.c b/src/execute.c index fc436af..7ad18da 100644 --- a/src/execute.c +++ b/src/execute.c @@ -225,7 +225,7 @@ static void executeDPRegister(Machine *state, a64inst_instruction *inst) { 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); + src2Val = truncateValue(src2Val >> shiftAmount | src2Val << (getMSBPos(regType) - shiftAmount + 1), regType); break; default: From c2844ce0ec2bb12da13c50e1e4f373d84884d714 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Thu, 6 Jun 2024 13:30:47 +0100 Subject: [PATCH 77/84] Fix V amd C flags for DPI subs instruction --- src/execute.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/execute.c b/src/execute.c index 7ad18da..1f37999 100644 --- a/src/execute.c +++ b/src/execute.c @@ -134,8 +134,8 @@ static void executeDPImmediate(Machine *state, a64inst_instruction *inst) { writeRegister(state, dest, regType, result); updateCondNZ(state, result, regType); - state->conditionCodes.Overflow = srcVal < result; - state->conditionCodes.Carry = state->conditionCodes.Overflow; + state->conditionCodes.Overflow = getMSB(srcVal, regType) != getMSB(arithmImm, regType) && getMSB(arithmImm, regType) == getMSB(result, regType); + state->conditionCodes.Carry = srcVal >= arithmImm; break; case(a64inst_SUB): @@ -262,7 +262,7 @@ static void executeDPRegister(Machine *state, a64inst_instruction *inst) { 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.Overflow = getMSB(src1Val, regType) != getMSB(src2Val, regType) && getMSB(src2Val, regType) == getMSB(result, regType); state->conditionCodes.Carry = src1Val >= src2Val; break; From 77cea8730a4a629d31192d55c9ef63a3a6c93680 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Thu, 6 Jun 2024 13:47:01 +0100 Subject: [PATCH 78/84] Fix getMSB function to only return 0 or 1 --- src/execute.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/execute.c b/src/execute.c index 1f37999..428e661 100644 --- a/src/execute.c +++ b/src/execute.c @@ -86,7 +86,7 @@ inline static dword getMSBPos(a64inst_regType regType) { // 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); + return (value >> getMSBPos(regType)) & 1u; } // Updates N and Z condition codes given the machine and a result value From 16efa0b3c8e55865348b4e3f566912b6f5f71dbd Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Thu, 6 Jun 2024 13:53:28 +0100 Subject: [PATCH 79/84] Replaced type used in execute to be platform independent --- src/execute.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/execute.c b/src/execute.c index 428e661..d59f336 100644 --- a/src/execute.c +++ b/src/execute.c @@ -169,7 +169,7 @@ static void executeDPImmediate(Machine *state, a64inst_instruction *inst) { case(a64inst_MOVK):; dword result = readRegister(state, dest, regType); - result = (result & ~(((1lu << DPI_WIDEMOV_SHIFT) - 1) << shiftScalar * DPI_WIDEMOV_SHIFT)) | wideMovImm; + result = (result & ~((((dword)1 << DPI_WIDEMOV_SHIFT) - 1) << shiftScalar * DPI_WIDEMOV_SHIFT)) | wideMovImm; writeRegister(state, dest, regType, result); break; From 059a3e747c4b813f84418600782387f0aa6224f5 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Thu, 6 Jun 2024 16:25:17 +0100 Subject: [PATCH 80/84] Paranthesis for ROR instruction for readability --- src/execute.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/execute.c b/src/execute.c index d59f336..4ef7512 100644 --- a/src/execute.c +++ b/src/execute.c @@ -225,7 +225,7 @@ static void executeDPRegister(Machine *state, a64inst_instruction *inst) { 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 + 1), regType); + src2Val = truncateValue((src2Val >> shiftAmount) | (src2Val << (getMSBPos(regType) + 1 - shiftAmount)), regType); break; default: From efca820fbf6567fc609073d3da19f1edfc7ff46b Mon Sep 17 00:00:00 2001 From: sBubshait Date: Thu, 6 Jun 2024 16:29:50 +0100 Subject: [PATCH 81/84] Fix Bug: Sign Extend SDT instrs instead of unsigned --- src/execute.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/execute.c b/src/execute.c index 4ef7512..2d60bef 100644 --- a/src/execute.c +++ b/src/execute.c @@ -362,7 +362,7 @@ void execute_SDT(Machine *state, a64inst_instruction *inst) { if (inst->data.SingleTransferData.SingleTransferOpType == a64inst_SINGLE_TRANSFER_LOAD_LITERAL) { // Load Literal isLoad = true; - address = state->pc + inst->data.SingleTransferData.processOpData.loadLiteralData.offset * 4; + address = state->pc + signExtend(inst->data.SingleTransferData.processOpData.loadLiteralData.offset, 19) * 4; } else { address = state->registers[inst->data.SingleTransferData.processOpData.singleDataTransferData.base]; isLoad = inst->data.SingleTransferData.processOpData.singleDataTransferData.transferType == a64inst_LOAD; @@ -374,7 +374,7 @@ void execute_SDT(Machine *state, a64inst_instruction *inst) { 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; + address += signExtend(inst->data.SingleTransferData.processOpData.singleDataTransferData.a64inst_addressingModeData.indexedOffset, 9); state->registers[inst->data.SingleTransferData.processOpData.singleDataTransferData.base] = address; break; case a64inst_POST_INDEXED: @@ -395,7 +395,8 @@ void execute_SDT(Machine *state, a64inst_instruction *inst) { // 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); + dword result = address + signExtend(inst->data.SingleTransferData.processOpData.singleDataTransferData.a64inst_addressingModeData.indexedOffset, 9); + writeRegister(state, inst->data.SingleTransferData.processOpData.singleDataTransferData.base, inst->data.SingleTransferData.regType == a64inst_W, result); } } From 4689aba219048002e7135a45694fbd445a679732 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Thu, 6 Jun 2024 16:31:59 +0100 Subject: [PATCH 82/84] Fix Bug: Fixed Post Indexed SDT to save AFTER the transfer --- src/execute.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/execute.c b/src/execute.c index 2d60bef..180487e 100644 --- a/src/execute.c +++ b/src/execute.c @@ -378,7 +378,6 @@ void execute_SDT(Machine *state, a64inst_instruction *inst) { 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; } } @@ -396,7 +395,7 @@ void execute_SDT(Machine *state, a64inst_instruction *inst) { // Update base register if post indexed if (inst->data.SingleTransferData.processOpData.singleDataTransferData.addressingMode == a64inst_POST_INDEXED) { dword result = address + signExtend(inst->data.SingleTransferData.processOpData.singleDataTransferData.a64inst_addressingModeData.indexedOffset, 9); - writeRegister(state, inst->data.SingleTransferData.processOpData.singleDataTransferData.base, inst->data.SingleTransferData.regType == a64inst_W, result); + writeRegister(state, inst->data.SingleTransferData.processOpData.singleDataTransferData.base, inst->data.SingleTransferData.regType, result); } } From b16fe2bee34fd0addbdda7f99369e165c19b76e0 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Thu, 6 Jun 2024 16:34:38 +0100 Subject: [PATCH 83/84] Fixed Bug: Struct Undefined Behaviour Due to Unguarded Access --- src/execute.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/execute.c b/src/execute.c index 180487e..8ce5e79 100644 --- a/src/execute.c +++ b/src/execute.c @@ -389,11 +389,19 @@ void execute_SDT(Machine *state, a64inst_instruction *inst) { } else { state->registers[inst->data.SingleTransferData.target] = readDoubleWord(state->memory, address); } + + // Update base register if post indexed + bool isSDT = inst->data.SingleTransferData.SingleTransferOpType == a64inst_SINGLE_TRANSFER_SINGLE_DATA_TRANSFER; + if (isSDT && inst->data.SingleTransferData.processOpData.singleDataTransferData.addressingMode == a64inst_POST_INDEXED) { + dword result = address + signExtend(inst->data.SingleTransferData.processOpData.singleDataTransferData.a64inst_addressingModeData.indexedOffset, 9); + writeRegister(state, inst->data.SingleTransferData.processOpData.singleDataTransferData.base, inst->data.SingleTransferData.regType, result); + } } 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) { + bool isSDT = inst->data.SingleTransferData.SingleTransferOpType == a64inst_SINGLE_TRANSFER_SINGLE_DATA_TRANSFER; + if (isSDT && inst->data.SingleTransferData.processOpData.singleDataTransferData.addressingMode == a64inst_POST_INDEXED) { dword result = address + signExtend(inst->data.SingleTransferData.processOpData.singleDataTransferData.a64inst_addressingModeData.indexedOffset, 9); writeRegister(state, inst->data.SingleTransferData.processOpData.singleDataTransferData.base, inst->data.SingleTransferData.regType, result); } From 8893b62a187870181cdbb1c7c974d1a58f2046f1 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Thu, 6 Jun 2024 16:38:01 +0100 Subject: [PATCH 84/84] Add storeMemory utility function and used it to fix a prev bug --- src/execute.c | 2 +- src/print.c | 8 ++++++++ src/print.h | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/execute.c b/src/execute.c index 8ce5e79..d5e60a6 100644 --- a/src/execute.c +++ b/src/execute.c @@ -397,7 +397,7 @@ void execute_SDT(Machine *state, a64inst_instruction *inst) { writeRegister(state, inst->data.SingleTransferData.processOpData.singleDataTransferData.base, inst->data.SingleTransferData.regType, result); } } else { - *(word *)(state->memory + address) = state->registers[inst->data.SingleTransferData.target]; + storeMemory(state->memory, address, state->registers[inst->data.SingleTransferData.target]); // Update base register if post indexed bool isSDT = inst->data.SingleTransferData.SingleTransferOpType == a64inst_SINGLE_TRANSFER_SINGLE_DATA_TRANSFER; diff --git a/src/print.c b/src/print.c index 1d1d4a2..88ed6f9 100644 --- a/src/print.c +++ b/src/print.c @@ -44,6 +44,14 @@ dword readDoubleWord(byte *memory, uint32_t address) { return result; } +// Store into memory starting at address the given dword. +void storeMemory(byte *memory, uint32_t address, dword data) { + int bytesPerDword = DWORD_BITS / BYTE_BITS - 1; + for (int i = 0; i <= bytesPerDword; i++) { + memory[address + i] = (byte)((data >> (BYTE_BITS * i)) & 0xFF); + } +} + // Prints all non-zero memory locations into the provided stream void printMemory(Machine *state, FILE *stream) { fprintf(stream, "\nNon-zero memory:\n"); diff --git a/src/print.h b/src/print.h index 404e947..5a64a4e 100644 --- a/src/print.h +++ b/src/print.h @@ -5,6 +5,7 @@ word readWord(byte *memory, uint32_t address); dword readDoubleWord(byte *memory, uint32_t address); +void storeMemory(byte *memory, uint32_t address, dword data); void printState(Machine *state, FILE *stream); void printRegisters(Machine *state, FILE *stream); void printMemory(Machine *state, FILE *stream);