Split utils into machine_util and binary_util modules

This commit is contained in:
sBubshait 2024-06-11 22:40:36 +01:00
parent a42576b4ed
commit c4e3493fdc
9 changed files with 153 additions and 120 deletions

View File

@ -1,12 +1,14 @@
#include <stdlib.h>
#include <stdio.h>
#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);

View File

@ -0,0 +1,57 @@
/** Binary Util */
#include <assert.h>
#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;
}

View File

@ -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

View File

@ -1,19 +1,7 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "decode.h"
#include "emulator.h"
// Retrieve the bits between positions 'lsb' (inclusive) and 'msb' (exclusive) from a given word
// as a new zero-extended word.
static word getBits(word wrd, uint8_t lsb, uint8_t msb) {
// Ensure LSB and MSB are within range of word size, and in the correct order
assert(lsb < msb && msb <= WORD_BITS);
wrd &= ((dword) 1 << msb) - 1;
return wrd >> lsb;
}
#include "binary_util.h"
// Given a binary word, return its internal representation as an a64instruction struct encoding the same
// information.

View File

@ -2,6 +2,8 @@
#include <assert.h>
#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;

View File

@ -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);
}
}

View File

@ -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

View File

@ -2,7 +2,9 @@
#include <stdint.h>
#include <inttypes.h>
#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);
}

View File

@ -3,9 +3,6 @@
#include <stdio.h>
#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);