From 32b4cab78eca46e219d2b85e4e79983c1fbc02df Mon Sep 17 00:00:00 2001 From: sBubshait Date: Wed, 29 May 2024 13:27:03 +0100 Subject: [PATCH 001/103] Add Object File Loader (objectloader) --- src/emulator/defs.h | 26 ++++++++++++++++++++++++++ src/emulator/objectloader.c | 34 ++++++++++++++++++++++++++++++++++ src/emulator/objectloader.h | 15 +++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 src/emulator/defs.h create mode 100644 src/emulator/objectloader.c create mode 100644 src/emulator/objectloader.h diff --git a/src/emulator/defs.h b/src/emulator/defs.h new file mode 100644 index 0000000..62cd9e5 --- /dev/null +++ b/src/emulator/defs.h @@ -0,0 +1,26 @@ +/** + ******************************************************************************** + * @file defs.h + * @brief Defines global constants and types used in the emulator. + ******************************************************************************** + */ + +#ifndef DEFS_H +#define DEFS_H +#include "../global.h" +#include + +/************************************ + * MACROS AND CONSTANTS + ************************************/ +#define EXIT_FAILURE 1 +#define EXIT_SUCCESS 0 + +/************************************ + * TYPEDEFS + ************************************/ + +typedef uint8_t Byte; + + + #endif \ No newline at end of file diff --git a/src/emulator/objectloader.c b/src/emulator/objectloader.c new file mode 100644 index 0000000..533d146 --- /dev/null +++ b/src/emulator/objectloader.c @@ -0,0 +1,34 @@ +/** + ******************************************************************************** + * @file objectloader.c + * @brief Object file loader for the emulator + ******************************************************************************** + */ + +#include +#include +#include +#include "objectloader.h" +#include "defs.h" + +void loadObjectFile(const char *filename, Byte *memoryAddress) { + FILE *file = fopen(filename, "rb"); + + // Check if the file exists + if (file == NULL) { + fprintf(stderr, "Error: Could not open file %s\n", filename); + exit(EXIT_FAILURE); + } + + // Load the object file into memory (or as much as possible) + size_t bytesRead = fread(memoryAddress, MEMORY_SIZE, 1, file); + if (bytesRead == 0) { + if (feof(file)) + exit(EXIT_SUCCESS); + + fprintf(stderr, "Error: Could not read from file %s\n", filename); + exit(EXIT_FAILURE); + } + + fclose(file); +} \ No newline at end of file diff --git a/src/emulator/objectloader.h b/src/emulator/objectloader.h new file mode 100644 index 0000000..c08cfaa --- /dev/null +++ b/src/emulator/objectloader.h @@ -0,0 +1,15 @@ +/** + * @file objectloader.h + * @brief Object file loader for the emulator + */ + +#include +#include "defs.h" + +/** + * @brief Loads an object file into memory starting at memoryAddress. + * + * @param filename The name of the file to be read + * @param memoryAddress The memory address to load the object file into + */ +void loadObjectFile(const char *filename, Byte *memoryAddress); \ No newline at end of file From f70ab669d69070f056c3cff1b4c4c1099475635a Mon Sep 17 00:00:00 2001 From: sBubshait Date: Wed, 29 May 2024 14:26:51 +0100 Subject: [PATCH 002/103] Update objectloader for consistency --- src/emulator/objectloader.c | 2 +- src/emulator/objectloader.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/emulator/objectloader.c b/src/emulator/objectloader.c index 533d146..da5889b 100644 --- a/src/emulator/objectloader.c +++ b/src/emulator/objectloader.c @@ -11,7 +11,7 @@ #include "objectloader.h" #include "defs.h" -void loadObjectFile(const char *filename, Byte *memoryAddress) { +void loadObjectFile(const char *filename, byte *memoryAddress) { FILE *file = fopen(filename, "rb"); // Check if the file exists diff --git a/src/emulator/objectloader.h b/src/emulator/objectloader.h index c08cfaa..21f0302 100644 --- a/src/emulator/objectloader.h +++ b/src/emulator/objectloader.h @@ -12,4 +12,4 @@ * @param filename The name of the file to be read * @param memoryAddress The memory address to load the object file into */ -void loadObjectFile(const char *filename, Byte *memoryAddress); \ No newline at end of file +void loadObjectFile(const char *filename, byte *memoryAddress); \ No newline at end of file From d7f56e47f79baa742bf1702c7f8d2969310e2adb Mon Sep 17 00:00:00 2001 From: sBubshait Date: Wed, 29 May 2024 14:27:52 +0100 Subject: [PATCH 003/103] Update defs.h: Define Machine, PSTATE --- src/emulator/defs.h | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/emulator/defs.h b/src/emulator/defs.h index 62cd9e5..5eca223 100644 --- a/src/emulator/defs.h +++ b/src/emulator/defs.h @@ -9,18 +9,30 @@ #define DEFS_H #include "../global.h" #include +#include /************************************ * MACROS AND CONSTANTS ************************************/ #define EXIT_FAILURE 1 -#define EXIT_SUCCESS 0 +#define HALT_INSTRUCTION 0x8a000000; /************************************ * TYPEDEFS ************************************/ - -typedef uint8_t Byte; +typedef uint8_t byte; +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; #endif \ No newline at end of file From 4710c729388c0de2fe3df19885abaa79cd4d45be Mon Sep 17 00:00:00 2001 From: sBubshait Date: Wed, 29 May 2024 14:30:35 +0100 Subject: [PATCH 004/103] Update emulate.c to read binary file and initalise state --- src/emulate.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/emulate.c b/src/emulate.c index e2ad1c8..0868d32 100755 --- a/src/emulate.c +++ b/src/emulate.c @@ -1,5 +1,53 @@ #include +#include +#include +#include "emulator/defs.h" +#include "emulator/objectloader.h" int main(int argc, char **argv) { + + // 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; + } + } + + // Allocate Memory for the machine + Machine *state = malloc(sizeof(Machine)); + + // Read the binary file into the memory of the machine. + loadObjectFile(argv[1], state->memory); + + // Initialise memory state + memset(state->registers, 0, sizeof(state->registers)); + memset(state->memory, 0, sizeof(state->memory)); + state->PC = 0x0; + state->conditionCodes = (PSTATE){0, 0, 0, 0}; + + // Start Execution Cycle. + /** + * PIPELINE: WHILE(): + * FETCH() + * DECODE() + * EXECUTE() + */ + + /** + * PRINT_STATE(); + */ + + /** + * FREE MEMORY!!! + */ + return EXIT_SUCCESS; } From de40227d08f47946904a074a9408d35a8a3cbd1b Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Thu, 30 May 2024 14:17:43 +0100 Subject: [PATCH 005/103] 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 006/103] 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 007/103] 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 008/103] 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 009/103] 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 010/103] 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 011/103] 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 012/103] 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 013/103] 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 014/103] 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 015/103] 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 016/103] 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 017/103] 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 018/103] 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 019/103] 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 020/103] 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 021/103] 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 022/103] 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 023/103] 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 024/103] 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 025/103] 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 026/103] 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 027/103] 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 028/103] 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 029/103] 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 030/103] 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 031/103] 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 032/103] 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 033/103] 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 034/103] 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 035/103] 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 036/103] 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 037/103] 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 038/103] 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 039/103] 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 040/103] 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 041/103] 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 042/103] 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 043/103] 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 044/103] 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 045/103] 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 046/103] 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 047/103] 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 048/103] 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 049/103] 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 050/103] 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 051/103] 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 052/103] 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 053/103] 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 054/103] 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 055/103] 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 056/103] 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 057/103] 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 058/103] 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 059/103] 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 060/103] 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 061/103] 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 062/103] 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 063/103] 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 064/103] 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 065/103] 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 066/103] 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 067/103] 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 068/103] 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 069/103] 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 070/103] 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 071/103] 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 072/103] 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 073/103] 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 074/103] 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 075/103] 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 076/103] 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 077/103] 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 078/103] 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 079/103] 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 080/103] 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 081/103] 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 082/103] 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 083/103] 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 084/103] 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 085/103] 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 086/103] 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 087/103] 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); From 46da019131566cf3a744d83385692486feab1946 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Fri, 7 Jun 2024 17:54:09 +0100 Subject: [PATCH 088/103] Remove No longer used files --- src/emulator/defs.h | 38 ------------------------------------- src/emulator/objectloader.c | 34 --------------------------------- src/emulator/objectloader.h | 15 --------------- 3 files changed, 87 deletions(-) delete mode 100644 src/emulator/defs.h delete mode 100644 src/emulator/objectloader.c delete mode 100644 src/emulator/objectloader.h diff --git a/src/emulator/defs.h b/src/emulator/defs.h deleted file mode 100644 index 5eca223..0000000 --- a/src/emulator/defs.h +++ /dev/null @@ -1,38 +0,0 @@ -/** - ******************************************************************************** - * @file defs.h - * @brief Defines global constants and types used in the emulator. - ******************************************************************************** - */ - -#ifndef DEFS_H -#define DEFS_H -#include "../global.h" -#include -#include - -/************************************ - * MACROS AND CONSTANTS - ************************************/ -#define EXIT_FAILURE 1 -#define HALT_INSTRUCTION 0x8a000000; - -/************************************ - * TYPEDEFS - ************************************/ -typedef uint8_t byte; -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; - - - #endif \ No newline at end of file diff --git a/src/emulator/objectloader.c b/src/emulator/objectloader.c deleted file mode 100644 index da5889b..0000000 --- a/src/emulator/objectloader.c +++ /dev/null @@ -1,34 +0,0 @@ -/** - ******************************************************************************** - * @file objectloader.c - * @brief Object file loader for the emulator - ******************************************************************************** - */ - -#include -#include -#include -#include "objectloader.h" -#include "defs.h" - -void loadObjectFile(const char *filename, byte *memoryAddress) { - FILE *file = fopen(filename, "rb"); - - // Check if the file exists - if (file == NULL) { - fprintf(stderr, "Error: Could not open file %s\n", filename); - exit(EXIT_FAILURE); - } - - // Load the object file into memory (or as much as possible) - size_t bytesRead = fread(memoryAddress, MEMORY_SIZE, 1, file); - if (bytesRead == 0) { - if (feof(file)) - exit(EXIT_SUCCESS); - - fprintf(stderr, "Error: Could not read from file %s\n", filename); - exit(EXIT_FAILURE); - } - - fclose(file); -} \ No newline at end of file diff --git a/src/emulator/objectloader.h b/src/emulator/objectloader.h deleted file mode 100644 index 21f0302..0000000 --- a/src/emulator/objectloader.h +++ /dev/null @@ -1,15 +0,0 @@ -/** - * @file objectloader.h - * @brief Object file loader for the emulator - */ - -#include -#include "defs.h" - -/** - * @brief Loads an object file into memory starting at memoryAddress. - * - * @param filename The name of the file to be read - * @param memoryAddress The memory address to load the object file into - */ -void loadObjectFile(const char *filename, byte *memoryAddress); \ No newline at end of file From a42576b4ed18613e70a54957c378b83c5c2ad00e Mon Sep 17 00:00:00 2001 From: sBubshait Date: Fri, 7 Jun 2024 18:08:33 +0100 Subject: [PATCH 089/103] Restructing, keeping all emulator modules in emulator directory --- src/Makefile | 5 ++--- src/emulate.c | 12 ++++++------ src/{ => emulator/a64instruction}/a64instruction.h | 0 .../a64instruction}/a64instruction_Branch.h | 2 +- .../a64instruction}/a64instruction_DP.h | 0 .../a64instruction}/a64instruction_DPImmediate.h | 0 .../a64instruction}/a64instruction_DPRegister.h | 0 .../a64instruction}/a64instruction_Directive.h | 2 +- .../a64instruction}/a64instruction_Label.h | 0 .../a64instruction}/a64instruction_SingleTransfer.h | 2 +- .../a64instruction}/a64instruction_global.h | 0 src/{ => emulator}/decode.c | 0 src/{ => emulator}/decode.h | 4 ++-- src/{ => emulator}/emulator.h | 2 +- src/{ => emulator}/execute.c | 0 src/{ => emulator}/execute.h | 2 +- src/{ => emulator}/fileio.c | 2 +- src/{ => emulator}/fileio.h | 2 +- src/{ => emulator}/print.c | 1 - src/{ => emulator}/print.h | 0 test.sh | 0 21 files changed, 17 insertions(+), 19 deletions(-) rename src/{ => emulator/a64instruction}/a64instruction.h (100%) rename src/{ => emulator/a64instruction}/a64instruction_Branch.h (97%) rename src/{ => emulator/a64instruction}/a64instruction_DP.h (100%) rename src/{ => emulator/a64instruction}/a64instruction_DPImmediate.h (100%) rename src/{ => emulator/a64instruction}/a64instruction_DPRegister.h (100%) rename src/{ => emulator/a64instruction}/a64instruction_Directive.h (69%) rename src/{ => emulator/a64instruction}/a64instruction_Label.h (100%) rename src/{ => emulator/a64instruction}/a64instruction_SingleTransfer.h (97%) rename src/{ => emulator/a64instruction}/a64instruction_global.h (100%) rename src/{ => emulator}/decode.c (100%) rename src/{ => emulator}/decode.h (97%) rename src/{ => emulator}/emulator.h (96%) rename src/{ => emulator}/execute.c (100%) rename src/{ => emulator}/execute.h (74%) rename src/{ => emulator}/fileio.c (98%) rename src/{ => emulator}/fileio.h (87%) rename src/{ => emulator}/print.c (99%) rename src/{ => emulator}/print.h (100%) mode change 100644 => 100755 test.sh diff --git a/src/Makefile b/src/Makefile index 7106e44..dd827a8 100755 --- a/src/Makefile +++ b/src/Makefile @@ -10,8 +10,7 @@ CFLAGS ?= -std=c17 -g\ all: assemble emulate assemble: assemble.o -emulate: emulate.o +emulate: emulate.o emulator/fileio.o emulator/execute.o emulator/decode.o emulator/print.o clean: - $(RM) *.o assemble emulate - + $(RM) *.o assemble emulate emulator/fileio.o emulator/execute.o emulator/decode.o emulator/print.o diff --git a/src/emulate.c b/src/emulate.c index 82245e9..83c58d7 100755 --- a/src/emulate.c +++ b/src/emulate.c @@ -1,12 +1,12 @@ #include #include -#include "a64instruction.h" -#include "emulator.h" -#include "fileio.h" +#include "emulator/a64instruction/a64instruction.h" +#include "emulator/emulator.h" +#include "emulator/fileio.h" #include "global.h" -#include "print.h" -#include "decode.h" -#include "execute.h" +#include "emulator/print.h" +#include "emulator/decode.h" +#include "emulator/execute.h" extern a64inst_instruction *decode(word w); diff --git a/src/a64instruction.h b/src/emulator/a64instruction/a64instruction.h similarity index 100% rename from src/a64instruction.h rename to src/emulator/a64instruction/a64instruction.h diff --git a/src/a64instruction_Branch.h b/src/emulator/a64instruction/a64instruction_Branch.h similarity index 97% rename from src/a64instruction_Branch.h rename to src/emulator/a64instruction/a64instruction_Branch.h index b732d6d..7cfc7e8 100644 --- a/src/a64instruction_Branch.h +++ b/src/emulator/a64instruction/a64instruction_Branch.h @@ -1,6 +1,6 @@ #include #include "a64instruction_global.h" -#include "global.h" +#include "../../global.h" typedef enum { a64inst_UNCONDITIONAL = 0, diff --git a/src/a64instruction_DP.h b/src/emulator/a64instruction/a64instruction_DP.h similarity index 100% rename from src/a64instruction_DP.h rename to src/emulator/a64instruction/a64instruction_DP.h diff --git a/src/a64instruction_DPImmediate.h b/src/emulator/a64instruction/a64instruction_DPImmediate.h similarity index 100% rename from src/a64instruction_DPImmediate.h rename to src/emulator/a64instruction/a64instruction_DPImmediate.h diff --git a/src/a64instruction_DPRegister.h b/src/emulator/a64instruction/a64instruction_DPRegister.h similarity index 100% rename from src/a64instruction_DPRegister.h rename to src/emulator/a64instruction/a64instruction_DPRegister.h diff --git a/src/a64instruction_Directive.h b/src/emulator/a64instruction/a64instruction_Directive.h similarity index 69% rename from src/a64instruction_Directive.h rename to src/emulator/a64instruction/a64instruction_Directive.h index 5c70dd4..88a6536 100644 --- a/src/a64instruction_Directive.h +++ b/src/emulator/a64instruction/a64instruction_Directive.h @@ -1,4 +1,4 @@ -#include "global.h" +#include "../../global.h" typedef struct { dword value; diff --git a/src/a64instruction_Label.h b/src/emulator/a64instruction/a64instruction_Label.h similarity index 100% rename from src/a64instruction_Label.h rename to src/emulator/a64instruction/a64instruction_Label.h diff --git a/src/a64instruction_SingleTransfer.h b/src/emulator/a64instruction/a64instruction_SingleTransfer.h similarity index 97% rename from src/a64instruction_SingleTransfer.h rename to src/emulator/a64instruction/a64instruction_SingleTransfer.h index f661116..1b6e2b7 100644 --- a/src/a64instruction_SingleTransfer.h +++ b/src/emulator/a64instruction/a64instruction_SingleTransfer.h @@ -1,6 +1,6 @@ #include #include "a64instruction_global.h" -#include "global.h" +#include "../../global.h" typedef enum { a64inst_SINGLE_TRANSFER_SINGLE_DATA_TRANSFER = 1, diff --git a/src/a64instruction_global.h b/src/emulator/a64instruction/a64instruction_global.h similarity index 100% rename from src/a64instruction_global.h rename to src/emulator/a64instruction/a64instruction_global.h diff --git a/src/decode.c b/src/emulator/decode.c similarity index 100% rename from src/decode.c rename to src/emulator/decode.c diff --git a/src/decode.h b/src/emulator/decode.h similarity index 97% rename from src/decode.h rename to src/emulator/decode.h index 132130e..5af7046 100644 --- a/src/decode.h +++ b/src/emulator/decode.h @@ -1,5 +1,5 @@ -#include "global.h" -#include "a64instruction.h" +#include "../global.h" +#include "a64instruction/a64instruction.h" #define HALT_WORD 0x8a000000 diff --git a/src/emulator.h b/src/emulator/emulator.h similarity index 96% rename from src/emulator.h rename to src/emulator/emulator.h index facbfd7..3a1e67d 100644 --- a/src/emulator.h +++ b/src/emulator/emulator.h @@ -1,6 +1,6 @@ #ifndef __EMULATOR__ #define __EMULATOR__ -#include "global.h" +#include "../global.h" #include /************************************ diff --git a/src/execute.c b/src/emulator/execute.c similarity index 100% rename from src/execute.c rename to src/emulator/execute.c diff --git a/src/execute.h b/src/emulator/execute.h similarity index 74% rename from src/execute.h rename to src/emulator/execute.h index fcf39ec..8b691e6 100644 --- a/src/execute.h +++ b/src/emulator/execute.h @@ -1,6 +1,6 @@ #ifndef __EXECUTE__ #define __EXECUTE__ -#include "a64instruction.h" +#include "a64instruction/a64instruction.h" #include "emulator.h" void execute(Machine *state, a64inst_instruction *inst); diff --git a/src/fileio.c b/src/emulator/fileio.c similarity index 98% rename from src/fileio.c rename to src/emulator/fileio.c index 1dcdd77..41df962 100644 --- a/src/fileio.c +++ b/src/emulator/fileio.c @@ -2,7 +2,7 @@ #include #include #include "fileio.h" -#include "global.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, diff --git a/src/fileio.h b/src/emulator/fileio.h similarity index 87% rename from src/fileio.h rename to src/emulator/fileio.h index a2d4262..47aa858 100644 --- a/src/fileio.h +++ b/src/emulator/fileio.h @@ -1,7 +1,7 @@ #ifndef __FILEIO__ #define __FILEIO__ #include -#include "global.h" +#include "../global.h" #define EXIT_FAILURE 1 diff --git a/src/print.c b/src/emulator/print.c similarity index 99% rename from src/print.c rename to src/emulator/print.c index 88ed6f9..0ec5210 100644 --- a/src/print.c +++ b/src/emulator/print.c @@ -1,7 +1,6 @@ #include #include #include -#include #include "print.h" #include "emulator.h" diff --git a/src/print.h b/src/emulator/print.h similarity index 100% rename from src/print.h rename to src/emulator/print.h diff --git a/test.sh b/test.sh old mode 100644 new mode 100755 From c4e3493fdc52965656d7aa8f4e29e987089ab452 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Tue, 11 Jun 2024 22:40:36 +0100 Subject: [PATCH 090/103] Split utils into machine_util and binary_util modules --- src/emulate.c | 4 +- src/emulator/binary_util.c | 57 ++++++++++++++++++++++++++ src/emulator/binary_util.h | 20 ++++++++++ src/emulator/decode.c | 14 +------ src/emulator/execute.c | 79 ++----------------------------------- src/emulator/machine_util.c | 50 +++++++++++++++++++++++ src/emulator/machine_util.h | 16 ++++++++ src/emulator/print.c | 30 ++------------ src/emulator/print.h | 3 -- 9 files changed, 153 insertions(+), 120 deletions(-) create mode 100644 src/emulator/binary_util.c create mode 100644 src/emulator/binary_util.h create mode 100644 src/emulator/machine_util.c create mode 100644 src/emulator/machine_util.h diff --git a/src/emulate.c b/src/emulate.c index 83c58d7..94f9254 100755 --- a/src/emulate.c +++ b/src/emulate.c @@ -1,12 +1,14 @@ #include #include #include "emulator/a64instruction/a64instruction.h" +#include "emulator/a64instruction/a64instruction_global.h" #include "emulator/emulator.h" #include "emulator/fileio.h" #include "global.h" #include "emulator/print.h" #include "emulator/decode.h" #include "emulator/execute.h" +#include "emulator/machine_util.h" extern a64inst_instruction *decode(word w); @@ -40,7 +42,7 @@ int main(int argc, char **argv) { do { // Step 1: Fetch instruction at PC's address - wrd = readWord(state.memory, state.pc); + wrd = readMemory(state.memory, state.pc, a64inst_W); // Step 2: Decode instruction to internal representation inst = decode(wrd); diff --git a/src/emulator/binary_util.c b/src/emulator/binary_util.c new file mode 100644 index 0000000..78bf11d --- /dev/null +++ b/src/emulator/binary_util.c @@ -0,0 +1,57 @@ +/** Binary Util */ +#include +#include "binary_util.h" + +word getBits(word wrd, uint8_t lsb, uint8_t msb) { + + // Ensure LSB and MSB are within range of word size, and in the correct order + assert(lsb < msb && msb <= WORD_BITS); + + wrd &= ((dword) 1 << msb) - 1; + return wrd >> lsb; +} + +dword max(dword a, dword b) { + return a > b ? a : b; +} + +dword truncateValue(dword value, a64inst_regType regType) { + if (regType == a64inst_X) { + return value; + } else { + return (word)value; + //return value & (dword)(((dword)1 << WORD_BITS) - 1); + } +} + +// Sign extend a given value to a 64-bit signed integer given the number of bits +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); + } +} + +// Returns the position of the MSB of the given register type +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 +uint8_t getMSB(dword value, a64inst_regType regType) { + return (value >> getMSBPos(regType)) & 1u; +} diff --git a/src/emulator/binary_util.h b/src/emulator/binary_util.h new file mode 100644 index 0000000..97763a0 --- /dev/null +++ b/src/emulator/binary_util.h @@ -0,0 +1,20 @@ +#ifndef __BINARY_UTIL__ +#define __BINARY_UTIL__ + +#include "emulator.h" +#include "a64instruction/a64instruction_global.h" + + +word getBits(word wrd, uint8_t lsb, uint8_t msb); + +dword max(dword a, dword b); + +dword truncateValue(dword value, a64inst_regType regType); + +int64_t signExtend(dword value, unsigned int n); + +dword getMSBPos(a64inst_regType regType); + +uint8_t getMSB(dword value, a64inst_regType regType); + +#endif diff --git a/src/emulator/decode.c b/src/emulator/decode.c index ce69c35..17970af 100644 --- a/src/emulator/decode.c +++ b/src/emulator/decode.c @@ -1,19 +1,7 @@ -#include #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. -static word getBits(word wrd, uint8_t lsb, uint8_t msb) { - - // Ensure LSB and MSB are within range of word size, and in the correct order - assert(lsb < msb && msb <= WORD_BITS); - - wrd &= ((dword) 1 << msb) - 1; - return wrd >> lsb; -} +#include "binary_util.h" // Given a binary word, return its internal representation as an a64instruction struct encoding the same // information. diff --git a/src/emulator/execute.c b/src/emulator/execute.c index d5e60a6..e2de20c 100644 --- a/src/emulator/execute.c +++ b/src/emulator/execute.c @@ -2,6 +2,8 @@ #include #include "execute.h" #include "print.h" +#include "binary_util.h" +#include "machine_util.h" // Defines the maximum value that can be held in a register #define MAX_REG_VAL ((1 << DWORD_BITS) - 1) @@ -19,76 +21,6 @@ void execute_SDT(Machine *state, a64inst_instruction *inst); void execute_Branch(Machine *state, a64inst_instruction *inst); void executeMultiply(Machine *state, a64inst_instruction *inst); -// Return maximum of two dwords -static dword max(dword a, dword b) { - return a > b ? a : b; -} - -// Truncate a given value to the size of a word or dword depending on the register type -static dword truncateValue(dword value, a64inst_regType regType) { - if (regType == a64inst_X) { - return value; - } else { - return (word)value; - //return value & (dword)(((dword)1 << WORD_BITS) - 1); - } -} - -// Sign extend a given value to a 64-bit signed integer given the number of bits -static int64_t signExtend(dword value, unsigned int n) { - if (n == 0 || n >= 64) { - // If n_bits is 0 or greater than or equal to 64, return the value as is - return (int64_t)value; - } - - uint64_t sign_bit_mask = (uint64_t)1 << (n - 1); - - // Mask to isolate the n-bit value - uint64_t n_bit_mask = (sign_bit_mask << 1) - 1; - - // Check if the sign bit is set - if (value & sign_bit_mask) { - // Sign bit is set, extend the sign - return (int64_t)(value | ~n_bit_mask); - } else { - // Sign bit is not set, return the value as is - return (int64_t)(value & n_bit_mask); - } -} - -// Read from processor register, ensuring that a valid register specifier is given -// and accounting for the case where the zero register is accessed. Truncate -// the 32 most significant bits stored in the R register when reading W register. -static dword readRegister(Machine *state, a64inst_regSpecifier reg, a64inst_regType regType) { - assert(reg <= REGISTER_COUNT); - if (reg == ZERO_REGISTER) { - return 0; - } else { - return truncateValue(state->registers[reg], regType); - } -} - -// TODO: - -// Write to a processor register, ensuring that a valid register specifier is given -// and truncating the value being written when it can't fit in the specified register -static void writeRegister(Machine *state, a64inst_regSpecifier reg, a64inst_regType regType, dword value) { - assert(reg <= REGISTER_COUNT); - if (reg != ZERO_REGISTER) { - state->registers[reg] = truncateValue(value, regType); - } -} - -// Returns the position of the MSB of the given register type -inline static dword getMSBPos(a64inst_regType regType) { - return (regType ? DWORD_BITS : WORD_BITS) - 1; -} - -// Returns the MSB of the given value assuming it's of the size stored in the given register type -inline static uint8_t getMSB(dword value, a64inst_regType regType) { - return (value >> getMSBPos(regType)) & 1u; -} - // Updates N and Z condition codes given the machine and a result value static void updateCondNZ(Machine *state, dword result, a64inst_regType regType) { state->conditionCodes.Negative = getMSB(result, regType); @@ -383,12 +315,7 @@ void execute_SDT(Machine *state, a64inst_instruction *inst) { } 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); - } + state->registers[inst->data.SingleTransferData.target] = readMemory(state->memory, address, inst->data.SingleTransferData.regType); // Update base register if post indexed bool isSDT = inst->data.SingleTransferData.SingleTransferOpType == a64inst_SINGLE_TRANSFER_SINGLE_DATA_TRANSFER; diff --git a/src/emulator/machine_util.c b/src/emulator/machine_util.c new file mode 100644 index 0000000..9288c7b --- /dev/null +++ b/src/emulator/machine_util.c @@ -0,0 +1,50 @@ +/** Machine Util */ +#include "assert.h" +#include "machine_util.h" +#include "a64instruction/a64instruction_global.h" +#include "../global.h" +#include "emulator.h" +#include "binary_util.h" + +// Returns the dword starting at address. The value is truncated if regType is a 64-bit register. +dword readMemory(byte *memory, uint32_t address, a64inst_regType regType) { + dword result = 0; + int bytesPerWord = (regType == a64inst_W ? WORD_BITS : DWORD_BITS) / BYTE_BITS - 1; + for (int i = 0; i <= bytesPerWord; i++) { + if (regType == a64inst_W) { + result |= (word) memory[address + i] << (BYTE_BITS * i); + } else { + result |= (dword) memory[address + i] << (BYTE_BITS * i); + } + } + 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); + } +} + +// 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. +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); + } +} + +// 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 +void writeRegister(Machine *state, a64inst_regSpecifier reg, a64inst_regType regType, dword value) { + assert(reg <= REGISTER_COUNT); + if (reg != ZERO_REGISTER) { + state->registers[reg] = truncateValue(value, regType); + } +} diff --git a/src/emulator/machine_util.h b/src/emulator/machine_util.h new file mode 100644 index 0000000..90688e8 --- /dev/null +++ b/src/emulator/machine_util.h @@ -0,0 +1,16 @@ +#ifndef __MACHINE_UTIL__ +#define __MACHINE_UTIL__ +#include "../global.h" +#include "a64instruction/a64instruction_global.h" +#include "emulator.h" + + +dword readMemory(byte *memory, uint32_t address, a64inst_regType regType); + +void storeMemory(byte *memory, uint32_t address, dword data); + +dword readRegister(Machine *state, a64inst_regSpecifier reg, a64inst_regType regType); + +void writeRegister(Machine *state, a64inst_regSpecifier reg, a64inst_regType regType, dword value); + +#endif diff --git a/src/emulator/print.c b/src/emulator/print.c index 0ec5210..217535b 100644 --- a/src/emulator/print.c +++ b/src/emulator/print.c @@ -2,7 +2,9 @@ #include #include #include "print.h" +#include "a64instruction/a64instruction_global.h" #include "emulator.h" +#include "machine_util.h" #define UNSET_CONDITION_CODE_CHAR '-' @@ -25,39 +27,13 @@ void printRegisters(Machine *state, FILE *stream) { state->conditionCodes.Overflow ? 'V' : UNSET_CONDITION_CODE_CHAR); } -// Returns the word starting at the provided address -word readWord(byte *memory, uint32_t address) { - word result = 0; - int bytesPerWord = WORD_BITS / BYTE_BITS - 1; - for (int i = 0; i <= bytesPerWord; i++) - result |= (word) memory[address + i] << (BYTE_BITS * i); - return result; -} - -// Returns the double word starting at the provided address -dword readDoubleWord(byte *memory, uint32_t address) { - dword result = 0; - int bytesPerDword = DWORD_BITS / BYTE_BITS - 1; - for (int i = 0; i <= bytesPerDword; i++) - result |= (dword) memory[address + i] << (BYTE_BITS * i); - return result; -} - -// 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"); // print memory 4 byte aligned for (int addr = 0; addr < MEMORY_SIZE; addr+= 4) { - word data = readWord(state->memory, addr); + word data = readMemory(state->memory, addr, a64inst_W); if (data != 0) { fprintf(stream, "0x%08x: %08x\n", addr, data); } diff --git a/src/emulator/print.h b/src/emulator/print.h index 5a64a4e..35001d9 100644 --- a/src/emulator/print.h +++ b/src/emulator/print.h @@ -3,9 +3,6 @@ #include #include "emulator.h" -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); From 954be5f8f45cc6ca50bb19d67d7574e267c3fe30 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Wed, 12 Jun 2024 15:55:15 +0100 Subject: [PATCH 091/103] Update structure to a binary and machine util and a64inst modules --- src/emulate.c | 4 ++-- src/emulator/decode.c | 2 +- src/emulator/decode.h | 2 +- src/emulator/emulator.h | 8 -------- src/emulator/execute.c | 2 +- src/emulator/execute.h | 2 +- src/emulator/machine_util.c | 4 ++-- src/emulator/machine_util.h | 2 +- src/emulator/print.c | 2 +- src/global.h | 9 +++++++++ src/{emulator => shared}/a64instruction/a64instruction.h | 0 .../a64instruction/a64instruction_Branch.h | 1 - .../a64instruction/a64instruction_DP.h | 0 .../a64instruction/a64instruction_DPImmediate.h | 0 .../a64instruction/a64instruction_DPRegister.h | 0 .../a64instruction/a64instruction_Directive.h | 2 +- .../a64instruction/a64instruction_Label.h | 0 .../a64instruction/a64instruction_SingleTransfer.h | 1 - .../a64instruction/a64instruction_global.h | 1 + src/{emulator => shared}/binary_util.c | 0 src/{emulator => shared}/binary_util.h | 3 +-- 21 files changed, 22 insertions(+), 23 deletions(-) rename src/{emulator => shared}/a64instruction/a64instruction.h (100%) rename src/{emulator => shared}/a64instruction/a64instruction_Branch.h (97%) rename src/{emulator => shared}/a64instruction/a64instruction_DP.h (100%) rename src/{emulator => shared}/a64instruction/a64instruction_DPImmediate.h (100%) rename src/{emulator => shared}/a64instruction/a64instruction_DPRegister.h (100%) rename src/{emulator => shared}/a64instruction/a64instruction_Directive.h (61%) rename src/{emulator => shared}/a64instruction/a64instruction_Label.h (100%) rename src/{emulator => shared}/a64instruction/a64instruction_SingleTransfer.h (97%) rename src/{emulator => shared}/a64instruction/a64instruction_global.h (92%) rename src/{emulator => shared}/binary_util.c (100%) rename src/{emulator => shared}/binary_util.h (94%) diff --git a/src/emulate.c b/src/emulate.c index 94f9254..ba6bbea 100755 --- a/src/emulate.c +++ b/src/emulate.c @@ -1,7 +1,7 @@ #include #include -#include "emulator/a64instruction/a64instruction.h" -#include "emulator/a64instruction/a64instruction_global.h" +#include "shared/a64instruction/a64instruction.h" +#include "shared/a64instruction/a64instruction_global.h" #include "emulator/emulator.h" #include "emulator/fileio.h" #include "global.h" diff --git a/src/emulator/decode.c b/src/emulator/decode.c index 17970af..ad09429 100644 --- a/src/emulator/decode.c +++ b/src/emulator/decode.c @@ -1,7 +1,7 @@ #include #include #include "decode.h" -#include "binary_util.h" +#include "../shared/binary_util.h" // Given a binary word, return its internal representation as an a64instruction struct encoding the same // information. diff --git a/src/emulator/decode.h b/src/emulator/decode.h index 5af7046..b5982be 100644 --- a/src/emulator/decode.h +++ b/src/emulator/decode.h @@ -1,5 +1,5 @@ #include "../global.h" -#include "a64instruction/a64instruction.h" +#include "../shared/a64instruction/a64instruction.h" #define HALT_WORD 0x8a000000 diff --git a/src/emulator/emulator.h b/src/emulator/emulator.h index 3a1e67d..69d1408 100644 --- a/src/emulator/emulator.h +++ b/src/emulator/emulator.h @@ -3,14 +3,6 @@ #include "../global.h" #include -/************************************ - * DEFINITIONS - ************************************/ - -#define BYTE_BITS 8 -#define WORD_BITS (BYTE_BITS * sizeof(word)) -#define DWORD_BITS (BYTE_BITS * sizeof(dword)) - /************************************ * STRUCTS ************************************/ diff --git a/src/emulator/execute.c b/src/emulator/execute.c index e2de20c..fddd50f 100644 --- a/src/emulator/execute.c +++ b/src/emulator/execute.c @@ -2,7 +2,7 @@ #include #include "execute.h" #include "print.h" -#include "binary_util.h" +#include "../shared/binary_util.h" #include "machine_util.h" // Defines the maximum value that can be held in a register diff --git a/src/emulator/execute.h b/src/emulator/execute.h index 8b691e6..be82de6 100644 --- a/src/emulator/execute.h +++ b/src/emulator/execute.h @@ -1,6 +1,6 @@ #ifndef __EXECUTE__ #define __EXECUTE__ -#include "a64instruction/a64instruction.h" +#include "../shared/a64instruction/a64instruction.h" #include "emulator.h" void execute(Machine *state, a64inst_instruction *inst); diff --git a/src/emulator/machine_util.c b/src/emulator/machine_util.c index 9288c7b..9db8525 100644 --- a/src/emulator/machine_util.c +++ b/src/emulator/machine_util.c @@ -1,10 +1,10 @@ /** Machine Util */ #include "assert.h" #include "machine_util.h" -#include "a64instruction/a64instruction_global.h" +#include "../shared/a64instruction/a64instruction_global.h" #include "../global.h" #include "emulator.h" -#include "binary_util.h" +#include "../shared/binary_util.h" // Returns the dword starting at address. The value is truncated if regType is a 64-bit register. dword readMemory(byte *memory, uint32_t address, a64inst_regType regType) { diff --git a/src/emulator/machine_util.h b/src/emulator/machine_util.h index 90688e8..89733e6 100644 --- a/src/emulator/machine_util.h +++ b/src/emulator/machine_util.h @@ -1,7 +1,7 @@ #ifndef __MACHINE_UTIL__ #define __MACHINE_UTIL__ #include "../global.h" -#include "a64instruction/a64instruction_global.h" +#include "../shared/a64instruction/a64instruction_global.h" #include "emulator.h" diff --git a/src/emulator/print.c b/src/emulator/print.c index 217535b..457aa7e 100644 --- a/src/emulator/print.c +++ b/src/emulator/print.c @@ -2,7 +2,7 @@ #include #include #include "print.h" -#include "a64instruction/a64instruction_global.h" +#include "../shared/a64instruction/a64instruction_global.h" #include "emulator.h" #include "machine_util.h" diff --git a/src/global.h b/src/global.h index 1cf226e..5d792e4 100644 --- a/src/global.h +++ b/src/global.h @@ -9,6 +9,11 @@ #define __GLOBAL__ #include + +/************************************ + * DEFINITIONS + ************************************/ + // Number of General Purpose Registers. #define REGISTER_COUNT 31 // Register identifier interpreted as the 'zero register' @@ -27,4 +32,8 @@ typedef uint32_t word; // Double word is a 64-bit unsigned integer. typedef uint64_t dword; +#define BYTE_BITS 8 +#define WORD_BITS (BYTE_BITS * sizeof(word)) +#define DWORD_BITS (BYTE_BITS * sizeof(dword)) + #endif diff --git a/src/emulator/a64instruction/a64instruction.h b/src/shared/a64instruction/a64instruction.h similarity index 100% rename from src/emulator/a64instruction/a64instruction.h rename to src/shared/a64instruction/a64instruction.h diff --git a/src/emulator/a64instruction/a64instruction_Branch.h b/src/shared/a64instruction/a64instruction_Branch.h similarity index 97% rename from src/emulator/a64instruction/a64instruction_Branch.h rename to src/shared/a64instruction/a64instruction_Branch.h index 7cfc7e8..d280973 100644 --- a/src/emulator/a64instruction/a64instruction_Branch.h +++ b/src/shared/a64instruction/a64instruction_Branch.h @@ -1,6 +1,5 @@ #include #include "a64instruction_global.h" -#include "../../global.h" typedef enum { a64inst_UNCONDITIONAL = 0, diff --git a/src/emulator/a64instruction/a64instruction_DP.h b/src/shared/a64instruction/a64instruction_DP.h similarity index 100% rename from src/emulator/a64instruction/a64instruction_DP.h rename to src/shared/a64instruction/a64instruction_DP.h diff --git a/src/emulator/a64instruction/a64instruction_DPImmediate.h b/src/shared/a64instruction/a64instruction_DPImmediate.h similarity index 100% rename from src/emulator/a64instruction/a64instruction_DPImmediate.h rename to src/shared/a64instruction/a64instruction_DPImmediate.h diff --git a/src/emulator/a64instruction/a64instruction_DPRegister.h b/src/shared/a64instruction/a64instruction_DPRegister.h similarity index 100% rename from src/emulator/a64instruction/a64instruction_DPRegister.h rename to src/shared/a64instruction/a64instruction_DPRegister.h diff --git a/src/emulator/a64instruction/a64instruction_Directive.h b/src/shared/a64instruction/a64instruction_Directive.h similarity index 61% rename from src/emulator/a64instruction/a64instruction_Directive.h rename to src/shared/a64instruction/a64instruction_Directive.h index 88a6536..fa2faaa 100644 --- a/src/emulator/a64instruction/a64instruction_Directive.h +++ b/src/shared/a64instruction/a64instruction_Directive.h @@ -1,4 +1,4 @@ -#include "../../global.h" +#include "./a64instruction_global.h" typedef struct { dword value; diff --git a/src/emulator/a64instruction/a64instruction_Label.h b/src/shared/a64instruction/a64instruction_Label.h similarity index 100% rename from src/emulator/a64instruction/a64instruction_Label.h rename to src/shared/a64instruction/a64instruction_Label.h diff --git a/src/emulator/a64instruction/a64instruction_SingleTransfer.h b/src/shared/a64instruction/a64instruction_SingleTransfer.h similarity index 97% rename from src/emulator/a64instruction/a64instruction_SingleTransfer.h rename to src/shared/a64instruction/a64instruction_SingleTransfer.h index 1b6e2b7..3e3da2b 100644 --- a/src/emulator/a64instruction/a64instruction_SingleTransfer.h +++ b/src/shared/a64instruction/a64instruction_SingleTransfer.h @@ -1,6 +1,5 @@ #include #include "a64instruction_global.h" -#include "../../global.h" typedef enum { a64inst_SINGLE_TRANSFER_SINGLE_DATA_TRANSFER = 1, diff --git a/src/emulator/a64instruction/a64instruction_global.h b/src/shared/a64instruction/a64instruction_global.h similarity index 92% rename from src/emulator/a64instruction/a64instruction_global.h rename to src/shared/a64instruction/a64instruction_global.h index ff748a6..629843d 100644 --- a/src/emulator/a64instruction/a64instruction_global.h +++ b/src/shared/a64instruction/a64instruction_global.h @@ -1,6 +1,7 @@ #ifndef __A64INSTRUCTION_GLOBAL__ #define __A64INSTRUCTION_GLOBAL__ #include +#include "../../global.h" // Specifies the register being referred to typedef uint8_t a64inst_regSpecifier; diff --git a/src/emulator/binary_util.c b/src/shared/binary_util.c similarity index 100% rename from src/emulator/binary_util.c rename to src/shared/binary_util.c diff --git a/src/emulator/binary_util.h b/src/shared/binary_util.h similarity index 94% rename from src/emulator/binary_util.h rename to src/shared/binary_util.h index 97763a0..8438ef9 100644 --- a/src/emulator/binary_util.h +++ b/src/shared/binary_util.h @@ -1,10 +1,9 @@ #ifndef __BINARY_UTIL__ #define __BINARY_UTIL__ -#include "emulator.h" +#include "../global.h" #include "a64instruction/a64instruction_global.h" - word getBits(word wrd, uint8_t lsb, uint8_t msb); dword max(dword a, dword b); From e302b21d0e0a1126449357238b1d8db273acd8c1 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Wed, 12 Jun 2024 16:19:03 +0100 Subject: [PATCH 092/103] Updated testing script to fix bug with moving file w/ S --- test.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test.sh b/test.sh index 7bb96e7..49939c8 100755 --- a/test.sh +++ b/test.sh @@ -2,9 +2,9 @@ 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 +git clone git@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 @@ -15,10 +15,10 @@ echo "Running the test suite..." echo "Test Suite Completed" cd .. -# printf "%s " "Press enter to continue" -# read ans +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 +echo "Done" From a009f43e8356896efd80330f68f24d3b0d308bfb Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Wed, 12 Jun 2024 17:09:07 +0100 Subject: [PATCH 093/103] Fixed overflow calculation to account for signed numbers w/ S --- src/emulator/execute.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/emulator/execute.c b/src/emulator/execute.c index fddd50f..2aec368 100644 --- a/src/emulator/execute.c +++ b/src/emulator/execute.c @@ -49,12 +49,12 @@ static void executeDPImmediate(Machine *state, a64inst_instruction *inst) { dword result; case(a64inst_ADDS): - result = srcVal + arithmImm; + result = truncateValue(srcVal + arithmImm, regType); writeRegister(state, dest, regType, result); updateCondNZ(state, result, regType); - state->conditionCodes.Overflow = max(srcVal, arithmImm) > result; - state->conditionCodes.Carry = state->conditionCodes.Overflow; + state->conditionCodes.Overflow = getMSB(srcVal, regType) == getMSB(arithmImm, regType) && getMSB(result, regType) != getMSB(srcVal, regType); + state->conditionCodes.Carry = max(truncateValue(srcVal, regType), truncateValue(arithmImm, regType)) > result; break; case(a64inst_ADD): @@ -177,12 +177,12 @@ static void executeDPRegister(Machine *state, a64inst_instruction *inst) { switch(inst->data.DPRegisterData.processOp) { case(a64inst_ADDS): - result = src1Val + src2Val; + result = truncateValue(src1Val + src2Val, regType); writeRegister(state, dest, regType, result); updateCondNZ(state, result, regType); - state->conditionCodes.Overflow = max(src1Val, src2Val) > result; - state->conditionCodes.Carry = state->conditionCodes.Overflow; + state->conditionCodes.Overflow = getMSB(src1Val, regType) == getMSB(src2Val, regType) && getMSB(result, regType) != getMSB(src1Val, regType); + state->conditionCodes.Carry = max(truncateValue(src1Val, regType), truncateValue(src2Val, regType)) > result; break; case(a64inst_ADD): From 9a6d15ce1c42473f983e4d08c0f2c0558d642f6c Mon Sep 17 00:00:00 2001 From: sBubshait Date: Wed, 12 Jun 2024 17:11:01 +0100 Subject: [PATCH 094/103] Fix Branch Bug to fix infinite loop --- src/emulator/execute.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/emulator/execute.c b/src/emulator/execute.c index 2aec368..6fb39af 100644 --- a/src/emulator/execute.c +++ b/src/emulator/execute.c @@ -371,6 +371,8 @@ void execute_Branch(Machine *state, a64inst_instruction *inst) { case a64inst_CONDITIONAL: if (isConditionMet(state, inst->data.BranchData.processOpData.conditionalData.cond)) { state->pc += signExtend(inst->data.BranchData.processOpData.conditionalData.offset * 4, 19); + } else { + state->pc += sizeof(word); } break; } From 64a9d728067dbba2921ad2791c93b8e2e789af43 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Wed, 12 Jun 2024 17:44:12 +0100 Subject: [PATCH 095/103] Change structure of execute module w/ S --- src/emulator/execute.c | 85 ++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 45 deletions(-) diff --git a/src/emulator/execute.c b/src/emulator/execute.c index 6fb39af..e13b7df 100644 --- a/src/emulator/execute.c +++ b/src/emulator/execute.c @@ -19,7 +19,42 @@ // Prototypes void execute_SDT(Machine *state, a64inst_instruction *inst); void execute_Branch(Machine *state, a64inst_instruction *inst); -void executeMultiply(Machine *state, a64inst_instruction *inst); +static void executeDPImmediate(Machine *state, a64inst_instruction *inst); +static void executeDPRegister(Machine *state, a64inst_instruction *inst); + +void execute(Machine *state, a64inst_instruction *inst) { + + switch (inst->type) { + + // Halt the program + case a64inst_HALT: + break; + + // Execute a data processing immediate instruction + case a64inst_DPIMMEDIATE: + executeDPImmediate(state, inst); + break; + + // Execute a branch instruction + case a64inst_BRANCH: + execute_Branch(state, inst); + break; + + // Execute a data processing register instruction + case a64inst_DPREGISTER: + executeDPRegister(state, inst); + break; + + case a64inst_SINGLETRANSFER: + execute_SDT(state, inst); + break; + + // Unknown instruction + default: + break; + } + +} // Updates N and Z condition codes given the machine and a result value static void updateCondNZ(Machine *state, dword result, a64inst_regType regType) { @@ -241,7 +276,10 @@ static void executeDPRegister(Machine *state, a64inst_instruction *inst) { break; // Execute a multiply register data processing instruction - case a64inst_DPR_MULTIPLY: + case a64inst_DPR_MULTIPLY:; + 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); break; // Unknown instruction detected! @@ -251,43 +289,6 @@ static void executeDPRegister(Machine *state, a64inst_instruction *inst) { } } -void execute(Machine *state, a64inst_instruction *inst) { - - switch (inst->type) { - - // Halt the program - case a64inst_HALT: - break; - - // Execute a data processing immediate instruction - case a64inst_DPIMMEDIATE: - executeDPImmediate(state, inst); - break; - - // Execute a branch instruction - case a64inst_BRANCH: - execute_Branch(state, inst); - break; - - // Execute a data processing register instruction - case a64inst_DPREGISTER: - if (inst->data.DPRegisterData.DPROpType == a64inst_DPR_MULTIPLY) - executeMultiply(state, inst); - else - executeDPRegister(state, inst); - break; - - case a64inst_SINGLETRANSFER: - execute_SDT(state, inst); - break; - - // Unknown instruction - default: - break; - } - -} - void execute_SDT(Machine *state, a64inst_instruction *inst) { word address; bool isLoad; @@ -377,9 +378,3 @@ 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 297ec154364f8d6f9c7902756ebf5e4067933f13 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Wed, 12 Jun 2024 17:47:37 +0100 Subject: [PATCH 096/103] Change name and signature of helper functions to be consistent w/ S --- src/emulator/execute.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/emulator/execute.c b/src/emulator/execute.c index e13b7df..37f89e7 100644 --- a/src/emulator/execute.c +++ b/src/emulator/execute.c @@ -17,8 +17,8 @@ #define DPI_WIDEMOV_SHIFT 16 // Prototypes -void execute_SDT(Machine *state, a64inst_instruction *inst); -void execute_Branch(Machine *state, a64inst_instruction *inst); +static void executeSDT(Machine *state, a64inst_instruction *inst); +static void executeBranch(Machine *state, a64inst_instruction *inst); static void executeDPImmediate(Machine *state, a64inst_instruction *inst); static void executeDPRegister(Machine *state, a64inst_instruction *inst); @@ -37,7 +37,7 @@ void execute(Machine *state, a64inst_instruction *inst) { // Execute a branch instruction case a64inst_BRANCH: - execute_Branch(state, inst); + executeBranch(state, inst); break; // Execute a data processing register instruction @@ -46,7 +46,7 @@ void execute(Machine *state, a64inst_instruction *inst) { break; case a64inst_SINGLETRANSFER: - execute_SDT(state, inst); + executeSDT(state, inst); break; // Unknown instruction @@ -289,7 +289,7 @@ static void executeDPRegister(Machine *state, a64inst_instruction *inst) { } } -void execute_SDT(Machine *state, a64inst_instruction *inst) { +static void executeSDT(Machine *state, a64inst_instruction *inst) { word address; bool isLoad; if (inst->data.SingleTransferData.SingleTransferOpType == a64inst_SINGLE_TRANSFER_LOAD_LITERAL) { @@ -359,7 +359,7 @@ static bool isConditionMet(Machine* state, a64inst_ConditionType cond) { } } -void execute_Branch(Machine *state, a64inst_instruction *inst) { +static void executeBranch(Machine *state, a64inst_instruction *inst) { switch (inst->data.BranchData.BranchType) { case a64inst_UNCONDITIONAL: state->pc += signExtend(inst->data.BranchData.processOpData.unconditionalData.unconditionalOffset * 4, 26); From 24fd0c4ad60d387e6c77f7ded058db5c8648547f Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Wed, 12 Jun 2024 18:42:32 +0100 Subject: [PATCH 097/103] Changed execute function to use function pointer array w/ S --- src/emulator/execute.c | 51 +++++++++++++++++------------------------- 1 file changed, 20 insertions(+), 31 deletions(-) diff --git a/src/emulator/execute.c b/src/emulator/execute.c index 37f89e7..abb6e0e 100644 --- a/src/emulator/execute.c +++ b/src/emulator/execute.c @@ -16,44 +16,33 @@ // instruction if the shift flag is enabled. #define DPI_WIDEMOV_SHIFT 16 +// Type definition for a pointer to a function that executes a particular type +// of a64instruction (requires pointer to the processor state to update, and a +// pointer to the instruction struct to execute). +typedef void (*executeFunction)(Machine *, a64inst_instruction *); + // Prototypes static void executeSDT(Machine *state, a64inst_instruction *inst); static void executeBranch(Machine *state, a64inst_instruction *inst); static void executeDPImmediate(Machine *state, a64inst_instruction *inst); static void executeDPRegister(Machine *state, a64inst_instruction *inst); +// Halt function definition +static void executeHalt(Machine *state, a64inst_instruction *inst) { /*NOP*/ } + +// Define a constant array mapping instruction type enum values to their +// corresponding execute functions +const executeFunction EXECUTE_FUNCTIONS[] = + {&executeDPImmediate, + &executeDPRegister, + &executeSDT, + &executeSDT, + &executeBranch, + &executeHalt}; + +// Main execute function void execute(Machine *state, a64inst_instruction *inst) { - - switch (inst->type) { - - // Halt the program - case a64inst_HALT: - break; - - // Execute a data processing immediate instruction - case a64inst_DPIMMEDIATE: - executeDPImmediate(state, inst); - break; - - // Execute a branch instruction - case a64inst_BRANCH: - executeBranch(state, inst); - break; - - // Execute a data processing register instruction - case a64inst_DPREGISTER: - executeDPRegister(state, inst); - break; - - case a64inst_SINGLETRANSFER: - executeSDT(state, inst); - break; - - // Unknown instruction - default: - break; - } - + EXECUTE_FUNCTIONS[inst->type](state, inst); } // Updates N and Z condition codes given the machine and a result value From 5013abfe000e744398846eac98e8f9b395250d04 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Wed, 12 Jun 2024 19:07:41 +0100 Subject: [PATCH 098/103] Update decode, Restructure and add helper function --- src/emulator/decode.c | 299 ++++++++++++++++++++++++------------------ src/emulator/decode.h | 4 +- 2 files changed, 172 insertions(+), 131 deletions(-) diff --git a/src/emulator/decode.c b/src/emulator/decode.c index ad09429..3fbaaa6 100644 --- a/src/emulator/decode.c +++ b/src/emulator/decode.c @@ -1,157 +1,198 @@ +/** @file decode.c + * @brief Decode Function from binary words to internal representation structs. + * + * This defines the decode function which takes a binary word (uint32_t) and + * decodes it into an a64inst_instruction conveying the same information. + * + * @author Saleh Bubshait + * @author Themis Demetriades + */ + #include #include #include "decode.h" #include "../shared/binary_util.h" -// Given a binary word, return its internal representation as an a64instruction struct encoding the same -// information. +#define getField(fieldname) getBits(wrd, fieldname##_LSB, fieldname##_MSB) + +/************************************ + * PROTOTYPES + ************************************/ + +static void decodeDPI(word wrd, a64inst_instruction *inst); +static void decodeBranch(word wrd, a64inst_instruction *inst); +static void decodeDPRegister(word wrd, a64inst_instruction *inst); +static void decodeSingleTransfer(word wrd, a64inst_instruction *inst); + +/** @brief The main decode function. Takes a word (uint32_t) representing the + * instruction and decodes it into an a64inst_instruction struct. + * @param wrd The word (uint32_t) to be decoded in binary. + * @return a pointer to the heap-allocated a64inst_instruction struct + * representing the decoded instruction if successful. + */ 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); + fprintf(stderr, "Error: Could not allocate memory for an instruction\n"); + exit(EXIT_FAILURE); } - word typeId = getBits(wrd, TYPE_ID_LSB, TYPE_ID_MSB); - // Halt interpretation + word typeId = getField(TYPE_ID); + if (wrd == HALT_WORD) { inst->type = a64inst_HALT; - // Data Processing Immediate interpretation } else if (typeId == DP_IMM_ID) { inst->type = a64inst_DPIMMEDIATE; - inst->data.DPImmediateData.regType = getBits(wrd, DP_WIDTH_LSB, DP_WIDTH_MSB); - inst->data.DPImmediateData.processOp = getBits(wrd, DP_OP_LSB, DP_OP_MSB); - inst->data.DPImmediateData.dest = getBits(wrd, DP_DEST_LSB, DP_DEST_MSB); - - switch(getBits(wrd, DP_IMM_OPTYPE_LSB, DP_IMM_OPTYPE_MSB)) { - - case DP_IMM_OPTYPE_ARITHM: - inst->data.DPImmediateData.DPIOpType = a64inst_DPI_ARITHM; - inst->data.DPImmediateData.processOpData.arithmData.shiftImmediate = getBits(wrd, DP_IMM_ARITHM_SHIFTFLAG_LSB, DP_IMM_ARITHM_SHIFTFLAG_MSB); - inst->data.DPImmediateData.processOpData.arithmData.immediate = getBits(wrd, DP_IMM_ARITHM_IMMVAL_LSB, DP_IMM_ARITHM_IMMVAL_MSB); - inst->data.DPImmediateData.processOpData.arithmData.src = getBits(wrd, DP_IMM_ARITHM_DEST_LSB, DP_IMM_ARITHM_DEST_MSB); - break; - - case DP_IMM_OPTYPE_WIDEMOV: - inst->data.DPImmediateData.DPIOpType = a64inst_DPI_WIDEMOV; - inst->data.DPImmediateData.processOpData.wideMovData.shiftScalar = getBits(wrd, DP_IMM_WIDEMOV_SHIFTSCALAR_LSB, DP_IMM_WIDEMOV_SHIFTSCALAR_MSB); - inst->data.DPImmediateData.processOpData.wideMovData.immediate = getBits(wrd, DP_IMM_WIDEMOV_IMMVAL_LSB, DP_IMM_WIDEMOV_IMMVAL_MSB); - break; - - default: - fprintf(stderr, "Unknown immediate data processing operation type found!\n"); - exit(1); - break; - } + decodeDPI(wrd, inst); } else if (typeId == BRANCH_ID) { inst->type = a64inst_BRANCH; - word branchTypeFlag = getBits(wrd, BRANCH_TYPE_LSB, BRANCH_TYPE_MSB); - - inst->data.BranchData.BranchType = branchTypeFlag; + decodeBranch(wrd, inst); - switch (branchTypeFlag) { - case a64inst_UNCONDITIONAL: - inst->data.BranchData.processOpData.unconditionalData.unconditionalOffset = getBits(wrd, BRANCH_UNCONDITIONAL_OFFSET_LSB, BRANCH_UNCONDITIONAL_OFFSET_MSB); - break; - - case a64inst_CONDITIONAL: - inst->data.BranchData.processOpData.conditionalData.offset = getBits(wrd, BRANCH_CONDITIONAL_OFFSET_LSB, BRANCH_CONDITIONAL_OFFSET_MSB); - - word conditionFlag = getBits(wrd, BRANCH_CONDITIONAL_COND_LSB, BRANCH_CONDITIONAL_COND_MSB); - - if(conditionFlag <= 1 || (conditionFlag >= 10 && conditionFlag <= 14)) { - inst->data.BranchData.processOpData.conditionalData.cond = conditionFlag; - } else { - fprintf(stderr, "Unknown condition detected!\n"); - exit(1); - } - - break; - - case a64inst_REGISTER: - inst->data.BranchData.processOpData.registerData.src = getBits(wrd, BRANCH_REGISTER_SRC_LSB, BRANCH_REGISTER_SRC_MSB); - break; - - default: - fprintf(stderr, "Undefined branch type detected!\n"); - exit(1); - break; - } - - // TODO: Some minor code duplication between DPR and DPI data interpretation - // Data Processing Register interpretation - } else if (getBits(wrd, DP_REG_LSB, DP_REG_MSB) == 1) { + } else if (getField(DP_REG_FLAG) == 1) { inst->type = a64inst_DPREGISTER; - inst->data.DPRegisterData.regType = getBits(wrd, DP_WIDTH_LSB, DP_WIDTH_MSB); - inst->data.DPRegisterData.processOp = getBits(wrd, DP_OP_LSB, DP_OP_MSB); - inst->data.DPRegisterData.dest = getBits(wrd, DP_DEST_LSB, DP_DEST_MSB); - inst->data.DPRegisterData.src1 = getBits(wrd, DP_REG_SRC1_LSB, DP_REG_SRC1_MSB); - inst->data.DPRegisterData.src2 = getBits(wrd, DP_REG_SRC2_LSB, DP_REG_SRC2_MSB); - inst->data.DPRegisterData.DPROpType = getBits(wrd, DP_REG_OPTYPE_LSB, DP_REG_OPTYPE_MSB); - - a64inst_DPRegister_ArithmLogicData *arithmLogicData = &inst->data.DPRegisterData.processOpData.arithmLogicData; - - arithmLogicData->type = getBits(wrd, DP_REG_ARITHMLOGIC_ARITHMFLAG_LSB, DP_REG_ARITHMLOGIC_ARITHMFLAG_MSB); - arithmLogicData->shiftType = getBits(wrd, DP_REG_ARITHMLOGIC_SHIFTTYPE_LSB, DP_REG_ARITHMLOGIC_SHIFTTYPE_MSB); - arithmLogicData->negShiftedSrc2 = getBits(wrd, DP_REG_ARITHMLOGIC_NEGSRC2FLAG_LSB, DP_REG_ARITHMLOGIC_NEGSRC2FLAG_MSB); - - switch(inst->data.DPRegisterData.DPROpType) { - - case a64inst_DPR_ARITHMLOGIC: - if (arithmLogicData->type == a64inst_DPR_ARITHM && (arithmLogicData->negShiftedSrc2 || arithmLogicData->shiftType == a64inst_ROR)) { - fprintf(stderr, "Attempting to decode arithmetic DPR instruction with invalid format!\n"); - } - arithmLogicData->shiftAmount = getBits(wrd, DP_REG_ARITHMLOGIC_SHIFTAMOUNT_LSB, DP_REG_ARITHMLOGIC_SHIFTAMOUNT_MSB); - break; - - case a64inst_DPR_MULTIPLY:; - if (!(inst->data.DPRegisterData.processOp == DP_REG_MULTIPLY_PROCESSOP && - arithmLogicData->type == DP_REG_MULTIPLY_ARITHMFLAG && - arithmLogicData->shiftType == DP_REG_MULTIPLY_SHIFTTYPE && - arithmLogicData->negShiftedSrc2 == DP_REG_MULTIPLY_NEGSRC2FLAG)) { - fprintf(stderr, "Attempting to decode multiply DPR instruction with invalid format!\n"); - } - inst->data.DPRegisterData.processOpData.multiplydata.summand = getBits(wrd, DP_REG_MULTIPLY_SUMMAND_LSB, DP_REG_MULTIPLY_SUMMAND_MSB); - inst->data.DPRegisterData.processOpData.multiplydata.negProd = getBits(wrd, DP_REG_MULTIPLY_NEGPROD_LSB, DP_REG_MULTIPLY_NEGPROD_MSB); - break; - } + decodeDPRegister(wrd, inst); } else { - // Load and Store, or unknown - // Ignore unknown for now inst->type = a64inst_SINGLETRANSFER; - inst->data.SingleTransferData.regType = getBits(wrd, SDT_REGTYPE_FLAG_LSB, SDT_REGTYPE_FLAG_MSB); - inst->data.SingleTransferData.target = getBits(wrd, SDT_TARGET_REG_LSB, SDT_TARGET_REG_MSB); - - // TODO: Assert that the instruction is a Single Transfer indeed. - - if(getBits(wrd, SDT_OPTYPE_FLAG_LSB, SDT_OPTYPE_FLAG_MSB) == a64inst_SINGLE_TRANSFER_SINGLE_DATA_TRANSFER) { - // Single Data Transfer - inst->data.SingleTransferData.SingleTransferOpType = a64inst_SINGLE_TRANSFER_SINGLE_DATA_TRANSFER; - inst->data.SingleTransferData.processOpData.singleDataTransferData.transferType = getBits(wrd, SDT_TRANSFER_TYPE_LSB, SDT_TRANSFER_TYPE_MSB); - inst->data.SingleTransferData.processOpData.singleDataTransferData.base = getBits(wrd, SDT_BASE_REG_LSB, SDT_BASE_REG_MSB); - if (getBits(wrd, SDT_UNSIGNED_FLAG_LSB, SDT_UNSIGNED_FLAG_MSB) == 1) { - // Unsigned offset - inst->data.SingleTransferData.processOpData.singleDataTransferData.addressingMode = a64inst_UNSIGNED_OFFSET; - inst->data.SingleTransferData.processOpData.singleDataTransferData.a64inst_addressingModeData.unsignedOffset = getBits(wrd, SDT_OFFSET_LSB, SDT_OFFSET_MSB); - } else if (getBits(wrd, SDT_REGISTER_FLAG_LSB, SDT_REGISTER_FLAG_MSB) == 1) { - // Register Offset - inst->data.SingleTransferData.processOpData.singleDataTransferData.addressingMode = a64inst_REGISTER_OFFSET; - inst->data.SingleTransferData.processOpData.singleDataTransferData.a64inst_addressingModeData.offsetReg = getBits(wrd, SDT_REGISTER_REG_LSB, SDT_REGISTER_REG_MSB); - } else { - // Pre-Indexed or Post-Indexed - inst->data.SingleTransferData.processOpData.singleDataTransferData.addressingMode = getBits(wrd, SDT_INDEXED_ADDRMODE_LSB, SDT_INDEXED_ADDRMODE_MSB); - inst->data.SingleTransferData.processOpData.singleDataTransferData.a64inst_addressingModeData.indexedOffset = getBits(wrd, SDT_INDEXED_OFFSET_LSB, SDT_INDEXED_OFFSET_MSB); - } - } else { - // Load Literal - inst->data.SingleTransferData.SingleTransferOpType = a64inst_SINGLE_TRANSFER_LOAD_LITERAL; - inst->data.SingleTransferData.processOpData.loadLiteralData.offset = getBits(wrd, SDT_LOAD_LITERAL_OFFSET_LSB, SDT_LOAD_LITERAL_OFFSET_MSB); - } + decodeSingleTransfer(wrd, inst); } return inst; } + +/************************************ + * HELPER FUNCTIONS + ************************************/ + +static void decodeDPI(word wrd, a64inst_instruction *inst) { + inst->data.DPImmediateData.regType = getField(DP_WIDTH); + inst->data.DPImmediateData.processOp = getField(DP_OP); + inst->data.DPImmediateData.dest = getField(DP_DEST); + + switch(getField(DP_IMM_OPTYPE)) { + + case DP_IMM_OPTYPE_ARITHM: + inst->data.DPImmediateData.DPIOpType = a64inst_DPI_ARITHM; + inst->data.DPImmediateData.processOpData.arithmData.shiftImmediate = getField(DP_IMM_ARITHM_SHIFTFLAG); + inst->data.DPImmediateData.processOpData.arithmData.immediate = getField(DP_IMM_ARITHM_IMMVAL); + inst->data.DPImmediateData.processOpData.arithmData.src = getField(DP_IMM_ARITHM_DEST); + break; + + case DP_IMM_OPTYPE_WIDEMOV: + inst->data.DPImmediateData.DPIOpType = a64inst_DPI_WIDEMOV; + inst->data.DPImmediateData.processOpData.wideMovData.shiftScalar = getField(DP_IMM_WIDEMOV_SHIFTSCALAR); + inst->data.DPImmediateData.processOpData.wideMovData.immediate = getField(DP_IMM_WIDEMOV_IMMVAL); + break; + + default: + fprintf(stderr, "Unknown immediate data processing operation type found!\n"); + exit(1); + break; + } +} + +static void decodeBranch(word wrd, a64inst_instruction *inst) { + word branchTypeFlag = getField(BRANCH_TYPE); + inst->data.BranchData.BranchType = branchTypeFlag; + + switch (branchTypeFlag) { + case a64inst_UNCONDITIONAL: + inst->data.BranchData.processOpData.unconditionalData.unconditionalOffset = getField(BRANCH_UNCONDITIONAL_OFFSET); + break; + + case a64inst_CONDITIONAL: + inst->data.BranchData.processOpData.conditionalData.offset = getField(BRANCH_CONDITIONAL_OFFSET); + + word conditionFlag = getField(BRANCH_CONDITIONAL_COND); + + if(conditionFlag <= 1 || (conditionFlag >= 10 && conditionFlag <= 14)) { + inst->data.BranchData.processOpData.conditionalData.cond = conditionFlag; + + } else { + fprintf(stderr, "Unknown condition detected!\n"); + exit(1); + } + + break; + + case a64inst_REGISTER: + inst->data.BranchData.processOpData.registerData.src = getField(BRANCH_REGISTER_SRC); + break; + + default: + fprintf(stderr, "Undefined branch type detected!\n"); + exit(1); + break; + } +} + +static void decodeDPRegister(word wrd, a64inst_instruction *inst) { + inst->data.DPRegisterData.regType = getField(DP_WIDTH); + inst->data.DPRegisterData.processOp = getField(DP_OP); + inst->data.DPRegisterData.dest = getField(DP_DEST); + inst->data.DPRegisterData.src1 = getField(DP_REG_SRC1); + inst->data.DPRegisterData.src2 = getField(DP_REG_SRC2); + inst->data.DPRegisterData.DPROpType = getField(DP_REG_OPTYPE); + + a64inst_DPRegister_ArithmLogicData *arithmLogicData = &inst->data.DPRegisterData.processOpData.arithmLogicData; + + arithmLogicData->type = getField(DP_REG_ARITHMLOGIC_ARITHMFLAG); + arithmLogicData->shiftType = getField(DP_REG_ARITHMLOGIC_SHIFTTYPE); + arithmLogicData->negShiftedSrc2 = getField(DP_REG_ARITHMLOGIC_NEGSRC2FLAG); + + switch(inst->data.DPRegisterData.DPROpType) { + + case a64inst_DPR_ARITHMLOGIC: + if (arithmLogicData->type == a64inst_DPR_ARITHM && (arithmLogicData->negShiftedSrc2 || arithmLogicData->shiftType == a64inst_ROR)) { + fprintf(stderr, "Attempting to decode arithmetic DPR instruction with invalid format!\n"); + } + arithmLogicData->shiftAmount = getField(DP_REG_ARITHMLOGIC_SHIFTAMOUNT); + break; + + case a64inst_DPR_MULTIPLY:; + if (!(inst->data.DPRegisterData.processOp == DP_REG_MULTIPLY_PROCESSOP && + arithmLogicData->type == DP_REG_MULTIPLY_ARITHMFLAG && + arithmLogicData->shiftType == DP_REG_MULTIPLY_SHIFTTYPE && + arithmLogicData->negShiftedSrc2 == DP_REG_MULTIPLY_NEGSRC2FLAG)) { + fprintf(stderr, "Attempting to decode multiply DPR instruction with invalid format!\n"); + } + inst->data.DPRegisterData.processOpData.multiplydata.summand = getField(DP_REG_MULTIPLY_SUMMAND); + inst->data.DPRegisterData.processOpData.multiplydata.negProd = getField(DP_REG_MULTIPLY_NEGPROD); + break; + } +} + +static void decodeSingleTransfer(word wrd, a64inst_instruction *inst) { + inst->data.SingleTransferData.regType = getField(SDT_REGTYPE_FLAG); + inst->data.SingleTransferData.target = getField(SDT_TARGET_REG); + + bool singleTransferOptype = getField(SDT_OPTYPE_FLAG); + if(singleTransferOptype == a64inst_SINGLE_TRANSFER_SINGLE_DATA_TRANSFER) { + // Single Data Transfer + inst->data.SingleTransferData.SingleTransferOpType = a64inst_SINGLE_TRANSFER_SINGLE_DATA_TRANSFER; + inst->data.SingleTransferData.processOpData.singleDataTransferData.transferType = getField(SDT_TRANSFER_TYPE); + inst->data.SingleTransferData.processOpData.singleDataTransferData.base = getField(SDT_BASE_REG); + + if (getField(SDT_UNSIGNED_FLAG) == 1) { + // Unsigned offset + inst->data.SingleTransferData.processOpData.singleDataTransferData.addressingMode = a64inst_UNSIGNED_OFFSET; + inst->data.SingleTransferData.processOpData.singleDataTransferData.a64inst_addressingModeData.unsignedOffset = getField(SDT_OFFSET); + } else if (getField(SDT_REGISTER_FLAG) == 1) { + // Register Offset + inst->data.SingleTransferData.processOpData.singleDataTransferData.addressingMode = a64inst_REGISTER_OFFSET; + inst->data.SingleTransferData.processOpData.singleDataTransferData.a64inst_addressingModeData.offsetReg = getField(SDT_REGISTER_REG); + } else { + // Pre-Indexed or Post-Indexed + inst->data.SingleTransferData.processOpData.singleDataTransferData.addressingMode = getField(SDT_INDEXED_ADDRMODE); + inst->data.SingleTransferData.processOpData.singleDataTransferData.a64inst_addressingModeData.indexedOffset = getField(SDT_INDEXED_OFFSET); + } + + } else { + // Load Literal + inst->data.SingleTransferData.SingleTransferOpType = a64inst_SINGLE_TRANSFER_LOAD_LITERAL; + inst->data.SingleTransferData.processOpData.loadLiteralData.offset = getField(SDT_LOAD_LITERAL_OFFSET); + } +} diff --git a/src/emulator/decode.h b/src/emulator/decode.h index b5982be..d3d4330 100644 --- a/src/emulator/decode.h +++ b/src/emulator/decode.h @@ -8,8 +8,8 @@ #define DP_IMM_ID 4 #define BRANCH_ID 5 -#define DP_REG_LSB 25 -#define DP_REG_MSB 26 +#define DP_REG_FLAG_LSB 25 +#define DP_REG_FLAG_MSB 26 #define DP_WIDTH_LSB 31 #define DP_WIDTH_MSB 32 From 98a5c8a93c8cdba5ad51dd7665ac1fad7c8b4b3c Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Wed, 12 Jun 2024 19:15:33 +0100 Subject: [PATCH 099/103] Add comment explaining getField macro in decode w/ S --- src/emulator/decode.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/emulator/decode.c b/src/emulator/decode.c index 3fbaaa6..78dcbac 100644 --- a/src/emulator/decode.c +++ b/src/emulator/decode.c @@ -13,6 +13,8 @@ #include "decode.h" #include "../shared/binary_util.h" +// Macro that calls getBit() for a bitfield whose constants follow the format +// FIELDNAME_LSB and FIELDNAME_MSB, storing the result in the variable wrd #define getField(fieldname) getBits(wrd, fieldname##_LSB, fieldname##_MSB) /************************************ From 9dc460a04709eae1a7c18f07b7442074d70428f7 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Wed, 12 Jun 2024 19:28:48 +0100 Subject: [PATCH 100/103] Change directory structure of files w/ S --- src/Makefile | 4 ++-- src/{shared => }/a64instruction/a64instruction.h | 0 src/{shared => }/a64instruction/a64instruction_Branch.h | 0 src/{shared => }/a64instruction/a64instruction_DP.h | 0 src/{shared => }/a64instruction/a64instruction_DPImmediate.h | 0 src/{shared => }/a64instruction/a64instruction_DPRegister.h | 0 src/{shared => }/a64instruction/a64instruction_Directive.h | 0 src/{shared => }/a64instruction/a64instruction_Label.h | 0 .../a64instruction/a64instruction_SingleTransfer.h | 0 src/{shared => }/a64instruction/a64instruction_global.h | 2 +- src/emulator/decode.c | 2 +- src/emulator/decode.h | 2 +- src/{shared => util}/binary_util.c | 0 src/{shared => util}/binary_util.h | 2 +- src/{emulator => util}/fileio.c | 0 src/{emulator => util}/fileio.h | 0 16 files changed, 6 insertions(+), 6 deletions(-) rename src/{shared => }/a64instruction/a64instruction.h (100%) rename src/{shared => }/a64instruction/a64instruction_Branch.h (100%) rename src/{shared => }/a64instruction/a64instruction_DP.h (100%) rename src/{shared => }/a64instruction/a64instruction_DPImmediate.h (100%) rename src/{shared => }/a64instruction/a64instruction_DPRegister.h (100%) rename src/{shared => }/a64instruction/a64instruction_Directive.h (100%) rename src/{shared => }/a64instruction/a64instruction_Label.h (100%) rename src/{shared => }/a64instruction/a64instruction_SingleTransfer.h (100%) rename src/{shared => }/a64instruction/a64instruction_global.h (92%) rename src/{shared => util}/binary_util.c (100%) rename src/{shared => util}/binary_util.h (87%) rename src/{emulator => util}/fileio.c (100%) rename src/{emulator => util}/fileio.h (100%) diff --git a/src/Makefile b/src/Makefile index dd827a8..3a1441a 100755 --- a/src/Makefile +++ b/src/Makefile @@ -10,7 +10,7 @@ CFLAGS ?= -std=c17 -g\ all: assemble emulate assemble: assemble.o -emulate: emulate.o emulator/fileio.o emulator/execute.o emulator/decode.o emulator/print.o +emulate: emulate.o util/fileio.o emulator/execute.o emulator/decode.o emulator/print.o emulator/machine_util.o util/binary_util.o clean: - $(RM) *.o assemble emulate emulator/fileio.o emulator/execute.o emulator/decode.o emulator/print.o + $(RM) *.o assemble emulate emulator/execute.o emulator/decode.o diff --git a/src/shared/a64instruction/a64instruction.h b/src/a64instruction/a64instruction.h similarity index 100% rename from src/shared/a64instruction/a64instruction.h rename to src/a64instruction/a64instruction.h diff --git a/src/shared/a64instruction/a64instruction_Branch.h b/src/a64instruction/a64instruction_Branch.h similarity index 100% rename from src/shared/a64instruction/a64instruction_Branch.h rename to src/a64instruction/a64instruction_Branch.h diff --git a/src/shared/a64instruction/a64instruction_DP.h b/src/a64instruction/a64instruction_DP.h similarity index 100% rename from src/shared/a64instruction/a64instruction_DP.h rename to src/a64instruction/a64instruction_DP.h diff --git a/src/shared/a64instruction/a64instruction_DPImmediate.h b/src/a64instruction/a64instruction_DPImmediate.h similarity index 100% rename from src/shared/a64instruction/a64instruction_DPImmediate.h rename to src/a64instruction/a64instruction_DPImmediate.h diff --git a/src/shared/a64instruction/a64instruction_DPRegister.h b/src/a64instruction/a64instruction_DPRegister.h similarity index 100% rename from src/shared/a64instruction/a64instruction_DPRegister.h rename to src/a64instruction/a64instruction_DPRegister.h diff --git a/src/shared/a64instruction/a64instruction_Directive.h b/src/a64instruction/a64instruction_Directive.h similarity index 100% rename from src/shared/a64instruction/a64instruction_Directive.h rename to src/a64instruction/a64instruction_Directive.h diff --git a/src/shared/a64instruction/a64instruction_Label.h b/src/a64instruction/a64instruction_Label.h similarity index 100% rename from src/shared/a64instruction/a64instruction_Label.h rename to src/a64instruction/a64instruction_Label.h diff --git a/src/shared/a64instruction/a64instruction_SingleTransfer.h b/src/a64instruction/a64instruction_SingleTransfer.h similarity index 100% rename from src/shared/a64instruction/a64instruction_SingleTransfer.h rename to src/a64instruction/a64instruction_SingleTransfer.h diff --git a/src/shared/a64instruction/a64instruction_global.h b/src/a64instruction/a64instruction_global.h similarity index 92% rename from src/shared/a64instruction/a64instruction_global.h rename to src/a64instruction/a64instruction_global.h index 629843d..b50ab67 100644 --- a/src/shared/a64instruction/a64instruction_global.h +++ b/src/a64instruction/a64instruction_global.h @@ -1,7 +1,7 @@ #ifndef __A64INSTRUCTION_GLOBAL__ #define __A64INSTRUCTION_GLOBAL__ #include -#include "../../global.h" +#include "../global.h" // Specifies the register being referred to typedef uint8_t a64inst_regSpecifier; diff --git a/src/emulator/decode.c b/src/emulator/decode.c index 78dcbac..39fde3b 100644 --- a/src/emulator/decode.c +++ b/src/emulator/decode.c @@ -11,7 +11,7 @@ #include #include #include "decode.h" -#include "../shared/binary_util.h" +#include "../util/binary_util.h" // Macro that calls getBit() for a bitfield whose constants follow the format // FIELDNAME_LSB and FIELDNAME_MSB, storing the result in the variable wrd diff --git a/src/emulator/decode.h b/src/emulator/decode.h index d3d4330..668e06e 100644 --- a/src/emulator/decode.h +++ b/src/emulator/decode.h @@ -1,5 +1,5 @@ #include "../global.h" -#include "../shared/a64instruction/a64instruction.h" +#include "../a64instruction/a64instruction.h" #define HALT_WORD 0x8a000000 diff --git a/src/shared/binary_util.c b/src/util/binary_util.c similarity index 100% rename from src/shared/binary_util.c rename to src/util/binary_util.c diff --git a/src/shared/binary_util.h b/src/util/binary_util.h similarity index 87% rename from src/shared/binary_util.h rename to src/util/binary_util.h index 8438ef9..2fc0439 100644 --- a/src/shared/binary_util.h +++ b/src/util/binary_util.h @@ -2,7 +2,7 @@ #define __BINARY_UTIL__ #include "../global.h" -#include "a64instruction/a64instruction_global.h" +#include "../a64instruction/a64instruction_global.h" word getBits(word wrd, uint8_t lsb, uint8_t msb); diff --git a/src/emulator/fileio.c b/src/util/fileio.c similarity index 100% rename from src/emulator/fileio.c rename to src/util/fileio.c diff --git a/src/emulator/fileio.h b/src/util/fileio.h similarity index 100% rename from src/emulator/fileio.h rename to src/util/fileio.h From 94ef67a0a9c23c4cb87fdb77164c68206495fedc Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Fri, 14 Jun 2024 14:47:33 +0100 Subject: [PATCH 101/103] Changed include paths to reflect new project structure --- src/emulate.c | 6 +++--- src/emulator/execute.c | 2 +- src/emulator/execute.h | 2 +- src/emulator/machine_util.c | 4 ++-- src/emulator/machine_util.h | 2 +- src/emulator/print.c | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/emulate.c b/src/emulate.c index ba6bbea..fc508a0 100755 --- a/src/emulate.c +++ b/src/emulate.c @@ -1,9 +1,9 @@ #include #include -#include "shared/a64instruction/a64instruction.h" -#include "shared/a64instruction/a64instruction_global.h" +#include "a64instruction/a64instruction.h" +#include "a64instruction/a64instruction_global.h" #include "emulator/emulator.h" -#include "emulator/fileio.h" +#include "util/fileio.h" #include "global.h" #include "emulator/print.h" #include "emulator/decode.h" diff --git a/src/emulator/execute.c b/src/emulator/execute.c index abb6e0e..b1a6663 100644 --- a/src/emulator/execute.c +++ b/src/emulator/execute.c @@ -2,7 +2,7 @@ #include #include "execute.h" #include "print.h" -#include "../shared/binary_util.h" +#include "../util/binary_util.h" #include "machine_util.h" // Defines the maximum value that can be held in a register diff --git a/src/emulator/execute.h b/src/emulator/execute.h index be82de6..3acc17b 100644 --- a/src/emulator/execute.h +++ b/src/emulator/execute.h @@ -1,6 +1,6 @@ #ifndef __EXECUTE__ #define __EXECUTE__ -#include "../shared/a64instruction/a64instruction.h" +#include "../a64instruction/a64instruction.h" #include "emulator.h" void execute(Machine *state, a64inst_instruction *inst); diff --git a/src/emulator/machine_util.c b/src/emulator/machine_util.c index 9db8525..3a27c89 100644 --- a/src/emulator/machine_util.c +++ b/src/emulator/machine_util.c @@ -1,10 +1,10 @@ /** Machine Util */ #include "assert.h" #include "machine_util.h" -#include "../shared/a64instruction/a64instruction_global.h" +#include "../a64instruction/a64instruction_global.h" #include "../global.h" #include "emulator.h" -#include "../shared/binary_util.h" +#include "../util/binary_util.h" // Returns the dword starting at address. The value is truncated if regType is a 64-bit register. dword readMemory(byte *memory, uint32_t address, a64inst_regType regType) { diff --git a/src/emulator/machine_util.h b/src/emulator/machine_util.h index 89733e6..14306dc 100644 --- a/src/emulator/machine_util.h +++ b/src/emulator/machine_util.h @@ -1,7 +1,7 @@ #ifndef __MACHINE_UTIL__ #define __MACHINE_UTIL__ #include "../global.h" -#include "../shared/a64instruction/a64instruction_global.h" +#include "../a64instruction/a64instruction_global.h" #include "emulator.h" diff --git a/src/emulator/print.c b/src/emulator/print.c index 457aa7e..36c7632 100644 --- a/src/emulator/print.c +++ b/src/emulator/print.c @@ -2,7 +2,7 @@ #include #include #include "print.h" -#include "../shared/a64instruction/a64instruction_global.h" +#include "../a64instruction/a64instruction_global.h" #include "emulator.h" #include "machine_util.h" From 9f31c6306be73904b21f32154575c1eb71b4223b Mon Sep 17 00:00:00 2001 From: sBubshait Date: Sat, 15 Jun 2024 02:08:29 +0100 Subject: [PATCH 102/103] Update util files for documentation --- src/util/binary_util.c | 12 +++++++----- src/util/binary_util.h | 43 ++++++++++++++++++++++++++++++++++++++++++ src/util/fileio.c | 11 +++++++---- src/util/fileio.h | 19 ++++++++++++++++++- 4 files changed, 75 insertions(+), 10 deletions(-) diff --git a/src/util/binary_util.c b/src/util/binary_util.c index 78bf11d..68d8e38 100644 --- a/src/util/binary_util.c +++ b/src/util/binary_util.c @@ -1,4 +1,10 @@ -/** Binary Util */ +/** @file binary_util.c + * @brief Implementation of utility functions for binary manipulation. + * + * @author Saleh Bubshait + * @author Themis Demetriades + */ + #include #include "binary_util.h" @@ -20,11 +26,9 @@ dword truncateValue(dword value, a64inst_regType regType) { return value; } else { return (word)value; - //return value & (dword)(((dword)1 << WORD_BITS) - 1); } } -// Sign extend a given value to a 64-bit signed integer given the number of bits 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 @@ -46,12 +50,10 @@ int64_t signExtend(dword value, unsigned int n) { } } -// Returns the position of the MSB of the given register type 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 uint8_t getMSB(dword value, a64inst_regType regType) { return (value >> getMSBPos(regType)) & 1u; } diff --git a/src/util/binary_util.h b/src/util/binary_util.h index 2fc0439..2b9bc15 100644 --- a/src/util/binary_util.h +++ b/src/util/binary_util.h @@ -1,19 +1,62 @@ +/** @file binary_util.h + * @brief Utility functions for binary manipulation. + * + * @author Saleh Bubshait + * @author Themis Demetriades + */ #ifndef __BINARY_UTIL__ #define __BINARY_UTIL__ #include "../global.h" #include "../a64instruction/a64instruction_global.h" +/** @brief Extracts the bits between the given indices from a word as an + * unsigned integer, uint32_t (word). + * + * @param wrd The input word (uint32_t) to extract bits from. + * @param lsb The index of the least significant bit to extract. + * @param msb The index of the most significant bit to extract. + * @return The extracted bits as a word. + */ word getBits(word wrd, uint8_t lsb, uint8_t msb); +/** @brief Returns the maximum of two given two double words (uint64_t). + * + * @param a The first double word. + * @param b The second double word. + * @return The maximum of the two given double words. + */ dword max(dword a, dword b); +/** @brief Truncates a given value to the size of the given register type. + * + * @param value The value to truncate. + * @param regType The register type to truncate the value to. + * @return The truncated value. + */ dword truncateValue(dword value, a64inst_regType regType); +/** @brief Sign extend a n-bit given value to a signed integer. + * + * @param value The value to sign extend. + * @param n The number of bits of the signed value. E.g., 16 for simm16. + */ int64_t signExtend(dword value, unsigned int n); +/** @brief Returns the position of the most significant bit of the given register type. + * + * @param regType The register type to get the most significant bit position of. + * @return The position of the most significant bit. This is either 31 or 63. + */ dword getMSBPos(a64inst_regType regType); +/** @brief Returns the most significant bit of the given value assuming it's of + * the size stored in the given register type. + * + * @param value The value to get the most significant bit of. + * @param regType The register type to get the most significant bit of. + * @return The most significant bit of the given value. + */ uint8_t getMSB(dword value, a64inst_regType regType); #endif diff --git a/src/util/fileio.c b/src/util/fileio.c index 41df962..c427c09 100644 --- a/src/util/fileio.c +++ b/src/util/fileio.c @@ -1,13 +1,16 @@ +/** @file fileio.c + * @brief Implementation of file input/output functions. + * + * @author Saleh Bubshait + * @author Themis Demetriades + */ + #include #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. */ - byte *fileio_loadBin(const char *filePath, size_t memorySize) { FILE *file = fopen(filePath, "rb"); if (file == NULL) { diff --git a/src/util/fileio.h b/src/util/fileio.h index 47aa858..fc36a23 100644 --- a/src/util/fileio.h +++ b/src/util/fileio.h @@ -1,3 +1,10 @@ +/** @file fileio.h + * @brief File input/output functions, used in both the emulator and assembler. + * + * @author Saleh Bubshait + * @author Themis Demetriades + */ + #ifndef __FILEIO__ #define __FILEIO__ #include @@ -5,5 +12,15 @@ #define EXIT_FAILURE 1 -extern byte *fileio_loadBin(const char *filePath, size_t memorySize); +/** @brief Loads a binary file located at filePath to memory, taking up a block + * of exactly memorySize bytes. + * If memorySize is insufficient to store the entire file, an appropriate error + * is reported. Excess memory is set to 0 bit values. + * + * @param filePath The path to the binary file to load. + * @param memorySize The size of the memory block to allocate. + * @return The starting address of the data loaded from the file. + */ +byte *fileio_loadBin(const char *filePath, size_t memorySize); + #endif From 98196c457827b1aa61806ee63c167daf425ffccb Mon Sep 17 00:00:00 2001 From: sBubshait Date: Sat, 15 Jun 2024 02:27:01 +0100 Subject: [PATCH 103/103] Document all emulate files --- src/emulate.c | 9 +++ src/emulator/decode.c | 106 ++++++++++++++++++++++++++++++++-- src/emulator/decode.h | 111 ++++++------------------------------ src/emulator/emulator.h | 8 +++ src/emulator/execute.c | 13 ++++- src/emulator/execute.h | 6 ++ src/emulator/machine_util.c | 18 +++--- src/emulator/machine_util.h | 41 ++++++++++++- src/emulator/print.c | 14 ++++- src/emulator/print.h | 38 ++++++++++++ 10 files changed, 252 insertions(+), 112 deletions(-) diff --git a/src/emulate.c b/src/emulate.c index fc508a0..631d1f0 100755 --- a/src/emulate.c +++ b/src/emulate.c @@ -1,3 +1,11 @@ +/** @file emulate.c + * @brief The main file for the ARMv8 emulator. Reads a binary file and outputs + * the state of the machine after executing the instructions in the file. + * + * @author Saleh Bubshait + * @author Themis Demetriades + */ + #include #include #include "a64instruction/a64instruction.h" @@ -20,6 +28,7 @@ int main(int argc, char **argv) { return EXIT_FAILURE; } + // If a second argument is provided, use it as output file instead of stdout. FILE *out = stdout; if (argc > 2) { out = fopen(argv[2], "w"); diff --git a/src/emulator/decode.c b/src/emulator/decode.c index 39fde3b..569c63b 100644 --- a/src/emulator/decode.c +++ b/src/emulator/decode.c @@ -17,6 +17,102 @@ // FIELDNAME_LSB and FIELDNAME_MSB, storing the result in the variable wrd #define getField(fieldname) getBits(wrd, fieldname##_LSB, fieldname##_MSB) +/************************************ + * CONSTANTS + ************************************/ + +#define HALT_WORD 0x8a000000 + +#define TYPE_ID_LSB 26 +#define TYPE_ID_MSB 29 +#define DP_IMM_ID 4 +#define BRANCH_ID 5 + +#define DP_REG_FLAG_LSB 25 +#define DP_REG_FLAG_MSB 26 + +#define DP_WIDTH_LSB 31 +#define DP_WIDTH_MSB 32 +#define DP_OP_LSB 29 +#define DP_OP_MSB 31 +#define DP_DEST_LSB 0 +#define DP_DEST_MSB 5 + +#define DP_IMM_OPTYPE_LSB 23 +#define DP_IMM_OPTYPE_MSB 26 +#define DP_IMM_OPTYPE_ARITHM 2 +#define DP_IMM_OPTYPE_WIDEMOV 5 +#define DP_IMM_ARITHM_SHIFTFLAG_LSB 22 +#define DP_IMM_ARITHM_SHIFTFLAG_MSB 23 +#define DP_IMM_ARITHM_IMMVAL_LSB 10 +#define DP_IMM_ARITHM_IMMVAL_MSB 22 +#define DP_IMM_ARITHM_DEST_LSB 5 +#define DP_IMM_ARITHM_DEST_MSB 10 +#define DP_IMM_WIDEMOV_SHIFTSCALAR_LSB 21 +#define DP_IMM_WIDEMOV_SHIFTSCALAR_MSB 23 +#define DP_IMM_WIDEMOV_IMMVAL_LSB 5 +#define DP_IMM_WIDEMOV_IMMVAL_MSB 21 + +#define DP_REG_SRC1_LSB 5 +#define DP_REG_SRC1_MSB 10 +#define DP_REG_SRC2_LSB 16 +#define DP_REG_SRC2_MSB 21 +#define DP_REG_OPTYPE_LSB 28 +#define DP_REG_OPTYPE_MSB 29 +#define DP_REG_ARITHMLOGIC_ARITHMFLAG_LSB 24 +#define DP_REG_ARITHMLOGIC_ARITHMFLAG_MSB 25 +#define DP_REG_ARITHMLOGIC_SHIFTTYPE_LSB 22 +#define DP_REG_ARITHMLOGIC_SHIFTTYPE_MSB 24 +#define DP_REG_ARITHMLOGIC_NEGSRC2FLAG_LSB 21 +#define DP_REG_ARITHMLOGIC_NEGSRC2FLAG_MSB 22 +#define DP_REG_ARITHMLOGIC_SHIFTAMOUNT_LSB 10 +#define DP_REG_ARITHMLOGIC_SHIFTAMOUNT_MSB 16 +#define DP_REG_MULTIPLY_SUMMAND_LSB 10 +#define DP_REG_MULTIPLY_SUMMAND_MSB 15 +#define DP_REG_MULTIPLY_NEGPROD_LSB 15 +#define DP_REG_MULTIPLY_NEGPROD_MSB 16 +#define DP_REG_MULTIPLY_PROCESSOP 0 +#define DP_REG_MULTIPLY_ARITHMFLAG 1 +#define DP_REG_MULTIPLY_SHIFTTYPE 0 +#define DP_REG_MULTIPLY_NEGSRC2FLAG 0 + +#define SDT_OPTYPE_FLAG_LSB 31 +#define SDT_OPTYPE_FLAG_MSB 32 +#define SDT_REGTYPE_FLAG_LSB 30 +#define SDT_REGTYPE_FLAG_MSB 31 +#define SDT_TARGET_REG_LSB 0 +#define SDT_TARGET_REG_MSB 5 + +#define SDT_BASE_REG_LSB 5 +#define SDT_BASE_REG_MSB 10 +#define SDT_OFFSET_LSB 10 +#define SDT_OFFSET_MSB 22 +#define SDT_TRANSFER_TYPE_LSB 22 +#define SDT_TRANSFER_TYPE_MSB 23 +#define SDT_UNSIGNED_FLAG_LSB 24 +#define SDT_UNSIGNED_FLAG_MSB 25 +#define SDT_REGISTER_FLAG_LSB 21 +#define SDT_REGISTER_FLAG_MSB 22 +#define SDT_REGISTER_REG_LSB 16 +#define SDT_REGISTER_REG_MSB 21 +#define SDT_INDEXED_ADDRMODE_LSB 11 +#define SDT_INDEXED_ADDRMODE_MSB 12 +#define SDT_INDEXED_OFFSET_LSB 12 +#define SDT_INDEXED_OFFSET_MSB 21 +#define SDT_LOAD_LITERAL_OFFSET_LSB 5 +#define SDT_LOAD_LITERAL_OFFSET_MSB 24 + +#define BRANCH_TYPE_LSB 30 +#define BRANCH_TYPE_MSB 32 +#define BRANCH_UNCONDITIONAL_OFFSET_LSB 0 +#define BRANCH_UNCONDITIONAL_OFFSET_MSB 26 +#define BRANCH_REGISTER_SRC_LSB 5 +#define BRANCH_REGISTER_SRC_MSB 10 +#define BRANCH_CONDITIONAL_COND_LSB 0 +#define BRANCH_CONDITIONAL_COND_MSB 4 +#define BRANCH_CONDITIONAL_OFFSET_LSB 5 +#define BRANCH_CONDITIONAL_OFFSET_MSB 24 + /************************************ * PROTOTYPES ************************************/ @@ -26,12 +122,10 @@ static void decodeBranch(word wrd, a64inst_instruction *inst); static void decodeDPRegister(word wrd, a64inst_instruction *inst); static void decodeSingleTransfer(word wrd, a64inst_instruction *inst); -/** @brief The main decode function. Takes a word (uint32_t) representing the - * instruction and decodes it into an a64inst_instruction struct. - * @param wrd The word (uint32_t) to be decoded in binary. - * @return a pointer to the heap-allocated a64inst_instruction struct - * representing the decoded instruction if successful. - */ +/************************************ + * FUNCTIONS + ************************************/ + a64inst_instruction *decode(word wrd) { a64inst_instruction *inst = malloc(sizeof(a64inst_instruction)); diff --git a/src/emulator/decode.h b/src/emulator/decode.h index 668e06e..964e5fc 100644 --- a/src/emulator/decode.h +++ b/src/emulator/decode.h @@ -1,96 +1,21 @@ +/** @file decode.h + * @brief Decode Function from binary words to a special internal + * representation of instructions, a64inst_instruction. + * + * This defines the decode function which takes a binary word (uint32_t) and + * decodes it into an a64inst_instruction conveying the same information. + * + * @author Saleh Bubshait + * @author Themis Demetriades + */ + #include "../global.h" #include "../a64instruction/a64instruction.h" -#define HALT_WORD 0x8a000000 - -#define TYPE_ID_LSB 26 -#define TYPE_ID_MSB 29 -#define DP_IMM_ID 4 -#define BRANCH_ID 5 - -#define DP_REG_FLAG_LSB 25 -#define DP_REG_FLAG_MSB 26 - -#define DP_WIDTH_LSB 31 -#define DP_WIDTH_MSB 32 -#define DP_OP_LSB 29 -#define DP_OP_MSB 31 -#define DP_DEST_LSB 0 -#define DP_DEST_MSB 5 - -#define DP_IMM_OPTYPE_LSB 23 -#define DP_IMM_OPTYPE_MSB 26 -#define DP_IMM_OPTYPE_ARITHM 2 -#define DP_IMM_OPTYPE_WIDEMOV 5 -#define DP_IMM_ARITHM_SHIFTFLAG_LSB 22 -#define DP_IMM_ARITHM_SHIFTFLAG_MSB 23 -#define DP_IMM_ARITHM_IMMVAL_LSB 10 -#define DP_IMM_ARITHM_IMMVAL_MSB 22 -#define DP_IMM_ARITHM_DEST_LSB 5 -#define DP_IMM_ARITHM_DEST_MSB 10 -#define DP_IMM_WIDEMOV_SHIFTSCALAR_LSB 21 -#define DP_IMM_WIDEMOV_SHIFTSCALAR_MSB 23 -#define DP_IMM_WIDEMOV_IMMVAL_LSB 5 -#define DP_IMM_WIDEMOV_IMMVAL_MSB 21 - -#define DP_REG_SRC1_LSB 5 -#define DP_REG_SRC1_MSB 10 -#define DP_REG_SRC2_LSB 16 -#define DP_REG_SRC2_MSB 21 -#define DP_REG_OPTYPE_LSB 28 -#define DP_REG_OPTYPE_MSB 29 -#define DP_REG_ARITHMLOGIC_ARITHMFLAG_LSB 24 -#define DP_REG_ARITHMLOGIC_ARITHMFLAG_MSB 25 -#define DP_REG_ARITHMLOGIC_SHIFTTYPE_LSB 22 -#define DP_REG_ARITHMLOGIC_SHIFTTYPE_MSB 24 -#define DP_REG_ARITHMLOGIC_NEGSRC2FLAG_LSB 21 -#define DP_REG_ARITHMLOGIC_NEGSRC2FLAG_MSB 22 -#define DP_REG_ARITHMLOGIC_SHIFTAMOUNT_LSB 10 -#define DP_REG_ARITHMLOGIC_SHIFTAMOUNT_MSB 16 -#define DP_REG_MULTIPLY_SUMMAND_LSB 10 -#define DP_REG_MULTIPLY_SUMMAND_MSB 15 -#define DP_REG_MULTIPLY_NEGPROD_LSB 15 -#define DP_REG_MULTIPLY_NEGPROD_MSB 16 -// Defines the values for fields used for arithmetic/logic DPR instructions -// that are necessary to indicate a multiplication instruction -#define DP_REG_MULTIPLY_PROCESSOP 0 -#define DP_REG_MULTIPLY_ARITHMFLAG 1 -#define DP_REG_MULTIPLY_SHIFTTYPE 0 -#define DP_REG_MULTIPLY_NEGSRC2FLAG 0 - -#define SDT_OPTYPE_FLAG_LSB 31 -#define SDT_OPTYPE_FLAG_MSB 32 -#define SDT_REGTYPE_FLAG_LSB 30 -#define SDT_REGTYPE_FLAG_MSB 31 -#define SDT_TARGET_REG_LSB 0 -#define SDT_TARGET_REG_MSB 5 - -#define SDT_BASE_REG_LSB 5 -#define SDT_BASE_REG_MSB 10 -#define SDT_OFFSET_LSB 10 -#define SDT_OFFSET_MSB 22 -#define SDT_TRANSFER_TYPE_LSB 22 -#define SDT_TRANSFER_TYPE_MSB 23 -#define SDT_UNSIGNED_FLAG_LSB 24 -#define SDT_UNSIGNED_FLAG_MSB 25 -#define SDT_REGISTER_FLAG_LSB 21 -#define SDT_REGISTER_FLAG_MSB 22 -#define SDT_REGISTER_REG_LSB 16 -#define SDT_REGISTER_REG_MSB 21 -#define SDT_INDEXED_ADDRMODE_LSB 11 -#define SDT_INDEXED_ADDRMODE_MSB 12 -#define SDT_INDEXED_OFFSET_LSB 12 -#define SDT_INDEXED_OFFSET_MSB 21 -#define SDT_LOAD_LITERAL_OFFSET_LSB 5 -#define SDT_LOAD_LITERAL_OFFSET_MSB 24 - -#define BRANCH_TYPE_LSB 30 -#define BRANCH_TYPE_MSB 32 -#define BRANCH_UNCONDITIONAL_OFFSET_LSB 0 -#define BRANCH_UNCONDITIONAL_OFFSET_MSB 26 -#define BRANCH_REGISTER_SRC_LSB 5 -#define BRANCH_REGISTER_SRC_MSB 10 -#define BRANCH_CONDITIONAL_COND_LSB 0 -#define BRANCH_CONDITIONAL_COND_MSB 4 -#define BRANCH_CONDITIONAL_OFFSET_LSB 5 -#define BRANCH_CONDITIONAL_OFFSET_MSB 24 +/** @brief The main decode function. Takes a word (uint32_t) representing the + * instruction and decodes it into an a64inst_instruction struct. + * @param wrd The word (uint32_t) to be decoded in binary. + * @return a pointer to the heap-allocated a64inst_instruction struct + * representing the decoded instruction if successful. + */ +a64inst_instruction *decode(word wrd); diff --git a/src/emulator/emulator.h b/src/emulator/emulator.h index 69d1408..33a92b0 100644 --- a/src/emulator/emulator.h +++ b/src/emulator/emulator.h @@ -1,3 +1,11 @@ +/** @file emulator.h + * @brief Structures to represent the state of the ARMv8 machine to be used + * in the emulator. + * + * @author Saleh Bubshait + * @author Themis Demetriades + */ + #ifndef __EMULATOR__ #define __EMULATOR__ #include "../global.h" diff --git a/src/emulator/execute.c b/src/emulator/execute.c index b1a6663..2ac3316 100644 --- a/src/emulator/execute.c +++ b/src/emulator/execute.c @@ -1,3 +1,14 @@ +/** @file execute.c + * @brief Implementation of the execute function for the ARMv8 emulator. + * + * This defines the execute function which takes a pointer to the machine state + * and a pointer to an a64inst_instruction struct and executes the instruction + * updating the machine state accordingly. + * + * @author Saleh Bubshait + * @author Themis Demetriades + */ + #include #include #include "execute.h" @@ -40,7 +51,7 @@ const executeFunction EXECUTE_FUNCTIONS[] = &executeBranch, &executeHalt}; -// Main execute function + void execute(Machine *state, a64inst_instruction *inst) { EXECUTE_FUNCTIONS[inst->type](state, inst); } diff --git a/src/emulator/execute.h b/src/emulator/execute.h index 3acc17b..f9aafec 100644 --- a/src/emulator/execute.h +++ b/src/emulator/execute.h @@ -3,5 +3,11 @@ #include "../a64instruction/a64instruction.h" #include "emulator.h" +/** @brief Executes the given instruction on the given machine state. + * Updates the machine state to reflect the execution of the instruction. + * + * @param state The machine state to execute the instruction on. + * @param inst The instruction to execute. + */ void execute(Machine *state, a64inst_instruction *inst); #endif diff --git a/src/emulator/machine_util.c b/src/emulator/machine_util.c index 3a27c89..7899114 100644 --- a/src/emulator/machine_util.c +++ b/src/emulator/machine_util.c @@ -1,4 +1,13 @@ -/** Machine Util */ +/** @file machine_util.c + * @brief Implementation of utility functions for manipulating the machine state. + * + * This defines utility functions for reading and writing memory and registers, + * which are used by the emulator to execute instructions. + * + * @author Saleh Bubshait + * @author Themis Demetriades + */ + #include "assert.h" #include "machine_util.h" #include "../a64instruction/a64instruction_global.h" @@ -6,7 +15,6 @@ #include "emulator.h" #include "../util/binary_util.h" -// Returns the dword starting at address. The value is truncated if regType is a 64-bit register. dword readMemory(byte *memory, uint32_t address, a64inst_regType regType) { dword result = 0; int bytesPerWord = (regType == a64inst_W ? WORD_BITS : DWORD_BITS) / BYTE_BITS - 1; @@ -20,7 +28,6 @@ dword readMemory(byte *memory, uint32_t address, a64inst_regType regType) { 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++) { @@ -28,9 +35,6 @@ void storeMemory(byte *memory, uint32_t address, dword data) { } } -// 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. dword readRegister(Machine *state, a64inst_regSpecifier reg, a64inst_regType regType) { assert(reg <= REGISTER_COUNT); if (reg == ZERO_REGISTER) { @@ -40,8 +44,6 @@ dword readRegister(Machine *state, a64inst_regSpecifier reg, a64inst_regType reg } } -// 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 void writeRegister(Machine *state, a64inst_regSpecifier reg, a64inst_regType regType, dword value) { assert(reg <= REGISTER_COUNT); if (reg != ZERO_REGISTER) { diff --git a/src/emulator/machine_util.h b/src/emulator/machine_util.h index 14306dc..047287e 100644 --- a/src/emulator/machine_util.h +++ b/src/emulator/machine_util.h @@ -1,16 +1,55 @@ +/** @file machine_util.h + * @brief Utility functions for manipulating the machine state. + * + * This defines utility functions for reading and writing memory and registers, + * which are used by the emulator to execute instructions. + * + * @author Saleh Bubshait + * @author Themis Demetriades + */ + #ifndef __MACHINE_UTIL__ #define __MACHINE_UTIL__ #include "../global.h" #include "../a64instruction/a64instruction_global.h" #include "emulator.h" - +/** @brief Reads a (double) word from memory starting at the given address. + * If regType is a64inst_W, the value is truncated to 32 bits. + * + * @param memory The starting address byte-addressable memory block. + * @param address The address to read from. + * @param regType The register type to truncate the value to if necessary. + * @return The (double) word read from memory. + */ dword readMemory(byte *memory, uint32_t address, a64inst_regType regType); +/** @brief Stores a double word into memory starting at the given address. + * + * @param memory The starting address byte-addressable memory block. + * @param address The address to store the data at. + * @param data The double word to store. + */ void storeMemory(byte *memory, uint32_t address, dword data); +/** @brief Reads a register from the machine state. + * If regType is a64inst_W, the value is truncated to 32 bits. + * + * @param state The machine state to read the register from. + * @param reg The register specifier to read. + * @param regType The register type to truncate the value to if necessary. + * @return The value stored in the register, truncated if necessary. + */ dword readRegister(Machine *state, a64inst_regSpecifier reg, a64inst_regType regType); +/** @brief Writes a value to a register in the machine state. + * If regType is a64inst_W, the value is truncated to 32 bits. + * + * @param state The machine state to write the register to. + * @param reg The register specifier to write to. + * @param regType The register type to truncate the value to if necessary. + * @param value The value to write to the register. + */ void writeRegister(Machine *state, a64inst_regSpecifier reg, a64inst_regType regType, dword value); #endif diff --git a/src/emulator/print.c b/src/emulator/print.c index 36c7632..978a74a 100644 --- a/src/emulator/print.c +++ b/src/emulator/print.c @@ -1,3 +1,14 @@ +/** @file print.c + * @brief Implementation of functions to print the machine state. + * + * The function prints the current machine state, including the registers, + * memory and condition codes. This is used to print the final state machine + * in the emulator after all instructions have been executed. + * + * @author Saleh Bubshait + * @author Themis Demetriades + */ + #include #include #include @@ -8,13 +19,11 @@ #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++) { @@ -27,7 +36,6 @@ void printRegisters(Machine *state, FILE *stream) { state->conditionCodes.Overflow ? 'V' : UNSET_CONDITION_CODE_CHAR); } -// 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/emulator/print.h b/src/emulator/print.h index 35001d9..9d946fd 100644 --- a/src/emulator/print.h +++ b/src/emulator/print.h @@ -1,10 +1,48 @@ +/** @file print.h + * @brief Functions to print the machine state, inc registers and memory. + * + * The function prints the current machine state, including the registers, + * memory and condition codes. This is used to print the final state machine + * in the emulator after all instructions have been executed. + * + * @author Saleh Bubshait + * @author Themis Demetriades + */ + #ifndef __PRINT__ #define __PRINT__ #include #include "emulator.h" +/** @brief Prints the current machine state into the provided stream. + * + * @param state The machine state to print. + * @param stream The stream to print the state to. + * + * @see printRegisters + * @see printMemory + */ void printState(Machine *state, FILE *stream); + +/** @brief Prints the current machine registers into the provided stream. + * The registers are printed in the format "Xn = value" where n is the register + * number and value is the value stored in the register, in hexadecimal. The + * program counter (PC) and condition codes are also printed. SP is ignored. + * + * @param state The machine state to print the registers of. + * @param stream The stream to print the registers to. + */ void printRegisters(Machine *state, FILE *stream); + +/** @brief Prints all non-zero memory locations into the provided stream. + * The memory is printed in the format "0xaddress: data" where address is the + * memory address and data is the data stored at that address, in hexadecimal. + * Memory locations are printed 4 bytes at a time. + * Note. Only non-zero memory locations are printed! + * + * @param state The machine state to print the memory of. + * @param stream The stream to print the memory to. + */ void printMemory(Machine *state, FILE *stream); #endif