mirror of
https://github.com/pound-emu/pound.git
synced 2025-12-18 19:36:57 +00:00
jit: Add more foundational code
Strengthens the decoder's foundation but does not yet implement the core instruction lookup table logic or the public arm32_decode API. These will be addressed in future patches. Signed-off-by: Ronald Caesar <github43132@proton.me>
This commit is contained in:
parent
09da076aaf
commit
7aac83b2f2
4 changed files with 138 additions and 17 deletions
|
|
@ -4,7 +4,7 @@ target_sources(jit PRIVATE
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/decoder/arm32.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/decoder/arm32.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(jit PRIVATE common)
|
target_link_libraries(jit PRIVATE common host)
|
||||||
|
|
||||||
target_include_directories(jit PUBLIC
|
target_include_directories(jit PUBLIC
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,134 @@
|
||||||
#include "arm32.h"
|
#include "arm32.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include "common/passert.h"
|
||||||
|
|
||||||
|
#define LOG_MODULE "jit"
|
||||||
|
#include "common/logging.h"
|
||||||
|
|
||||||
namespace pound::jit::decoder
|
namespace pound::jit::decoder
|
||||||
{
|
{
|
||||||
|
/* Increase value as more instructions get implemented */
|
||||||
|
#define INSTRUCTION_ARRAY_CAPACITY 4
|
||||||
arm32_decoder_t g_arm32_decoder = {};
|
arm32_decoder_t g_arm32_decoder = {};
|
||||||
|
|
||||||
void arm32_add_instruction(arm32_decoder_t* decoder, const char* nane, arm32_opcode_t mask, arm32_opcode_t expected,
|
/*
|
||||||
arm32_handler_fn handler)
|
* ============================================================================
|
||||||
{
|
* Foward Declarations
|
||||||
}
|
* ============================================================================
|
||||||
|
*/
|
||||||
|
void arm32_add_instruction(arm32_decoder_t* decoder, const char* name, const char* bitstring, arm32_handler_fn handler);
|
||||||
|
void arm32_ADD_imm_handler(arm32_decoder_t* decoder, arm32_instruction_t instruction);
|
||||||
|
|
||||||
void arm32_ADD_imm_handler(arm32_decoder_t* decoder, arm32_instruction_t instruction) {}
|
void arm32_parse_bitstring(const char* bitstring, uint32_t* mask, uint32_t* expected);
|
||||||
|
void arm32_grow_instructions_array(arm32_decoder_t* decoder, size_t new_capacity);
|
||||||
|
|
||||||
void arm32_init(arm32_decoder_t* decoder)
|
/*
|
||||||
|
* ============================================================================
|
||||||
|
* Public Functions
|
||||||
|
* ============================================================================
|
||||||
|
*/
|
||||||
|
void arm32_init(pound::host::memory::arena_t allocator, arm32_decoder_t* decoder)
|
||||||
{
|
{
|
||||||
#define INST(fn, name, bitstring) arm32_add_instruction(decoder, name, 0, 0, &arm32_##fn##_handler);
|
PVM_ASSERT(nullptr != decoder);
|
||||||
|
PVM_ASSERT(nullptr != allocator.data);
|
||||||
|
|
||||||
|
(void)memset(decoder, 0, sizeof(arm32_decoder_t));
|
||||||
|
decoder->allocator = allocator;
|
||||||
|
|
||||||
|
/* Setup Instructions array.*/
|
||||||
|
size_t instructions_array_size = INSTRUCTION_ARRAY_CAPACITY * sizeof(arm32_instruction_info_t);
|
||||||
|
PVM_ASSERT(instructions_array_size <= decoder->allocator.capacity);
|
||||||
|
LOG_TRACE("Growing instructions array to %d bytes", instructions_array_size);
|
||||||
|
|
||||||
|
void* new_ptr = pound::host::memory::arena_allocate(&decoder->allocator, instructions_array_size);
|
||||||
|
PVM_ASSERT(nullptr != new_ptr);
|
||||||
|
|
||||||
|
decoder->instructions = (arm32_instruction_info_t*)new_ptr;
|
||||||
|
decoder->instruction_capacity = INSTRUCTION_ARRAY_CAPACITY;
|
||||||
|
|
||||||
|
/* Add all Arm32 instructions */
|
||||||
|
#define INST(fn, name, bitstring) arm32_add_instruction(decoder, name, bitstring, &arm32_##fn##_handler);
|
||||||
#include "./arm32.inc"
|
#include "./arm32.inc"
|
||||||
#undef INST
|
#undef INST
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void arm32_add_instruction(arm32_decoder_t* decoder, const char* name, const char* bitstring, arm32_handler_fn handler)
|
||||||
|
{
|
||||||
|
PVM_ASSERT(nullptr != decoder);
|
||||||
|
PVM_ASSERT(nullptr != decoder->allocator.data);
|
||||||
|
PVM_ASSERT(nullptr != name);
|
||||||
|
PVM_ASSERT(nullptr != bitstring);
|
||||||
|
PVM_ASSERT(decoder->instruction_count < decoder->instruction_capacity);
|
||||||
|
|
||||||
|
LOG_TRACE("Adding '%s' instruction to lookup table.", name);
|
||||||
|
arm32_opcode_t mask = 0;
|
||||||
|
arm32_opcode_t expected = 0;
|
||||||
|
arm32_parse_bitstring(bitstring, &mask, &expected);
|
||||||
|
|
||||||
|
LOG_TRACE("Mask: %x", mask);
|
||||||
|
LOG_TRACE("Expected: %x", expected);
|
||||||
|
|
||||||
|
arm32_instruction_info_t* info = &decoder->instructions[decoder->instruction_count];
|
||||||
|
info->name = name;
|
||||||
|
info->mask = mask;
|
||||||
|
info->expected = expected;
|
||||||
|
info->handler = handler;
|
||||||
|
|
||||||
|
/* Calculate priority based on number of fixed bits. */
|
||||||
|
info->priority = 0;
|
||||||
|
for (int i = 0; i < 32; ++i)
|
||||||
|
{
|
||||||
|
if ((mask >> i) & 1)
|
||||||
|
{
|
||||||
|
++info->priority;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
++decoder->instruction_count;
|
||||||
|
|
||||||
|
/* TODO(GloriousTacoo:jit): Add instruction to lookup table. */
|
||||||
|
}
|
||||||
|
void arm32_ADD_imm_handler(arm32_decoder_t* decoder, arm32_instruction_t instruction) {}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================================
|
||||||
|
* Private Functions
|
||||||
|
* ============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
void arm32_parse_bitstring(const char* bitstring, uint32_t* mask, uint32_t* expected)
|
||||||
|
{
|
||||||
|
PVM_ASSERT(nullptr != bitstring);
|
||||||
|
PVM_ASSERT(nullptr != mask);
|
||||||
|
PVM_ASSERT(nullptr != expected);
|
||||||
|
PVM_ASSERT(32 == strlen(bitstring));
|
||||||
|
|
||||||
|
*mask = 0;
|
||||||
|
*expected = 0;
|
||||||
|
uint8_t instruction_size_bits = 32;
|
||||||
|
for (int i = 0; (i < instruction_size_bits) && (bitstring[i] != '\0'); ++i)
|
||||||
|
{
|
||||||
|
uint32_t bit_position = 31 - i;
|
||||||
|
switch (bitstring[i])
|
||||||
|
{
|
||||||
|
case '0':
|
||||||
|
*mask |= (1U << bit_position);
|
||||||
|
break;
|
||||||
|
case '1':
|
||||||
|
*mask |= (1U << bit_position);
|
||||||
|
*expected |= (1U << bit_position);
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
case 'n':
|
||||||
|
case 'd':
|
||||||
|
case 'r':
|
||||||
|
case 'v':
|
||||||
|
case 's':
|
||||||
|
case 'S':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PVM_ASSERT_MSG(false, "Invalid bitstring character: %c", bitstring[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} // namespace pound::jit::decoder
|
} // namespace pound::jit::decoder
|
||||||
|
|
|
||||||
|
|
@ -3,30 +3,31 @@
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include "host/memory/arena.h"
|
||||||
|
|
||||||
namespace pound::jit::decoder
|
namespace pound::jit::decoder
|
||||||
{
|
{
|
||||||
typedef uint32_t arm32_opcode_t;
|
typedef uint32_t arm32_opcode_t;
|
||||||
typedef uint32_t arm32_instruction_t;
|
typedef uint32_t arm32_instruction_t;
|
||||||
|
|
||||||
typedef struct arm32_instruction_info arm32_instruction_info_t;
|
|
||||||
typedef struct arm32_decoder arm32_decoder_t;
|
typedef struct arm32_decoder arm32_decoder_t;
|
||||||
|
|
||||||
extern arm32_decoder_t g_arm32_decoder;
|
|
||||||
|
|
||||||
typedef void (*arm32_handler_fn)(arm32_decoder_t* decoder, arm32_instruction_t instruction);
|
typedef void (*arm32_handler_fn)(arm32_decoder_t* decoder, arm32_instruction_t instruction);
|
||||||
|
|
||||||
struct a32_instruction_info
|
typedef struct
|
||||||
{
|
{
|
||||||
const char* name;
|
const char* name;
|
||||||
arm32_opcode_t mask;
|
arm32_opcode_t mask;
|
||||||
arm32_opcode_t expected;
|
arm32_opcode_t expected;
|
||||||
arm32_handler_fn handler;
|
arm32_handler_fn handler;
|
||||||
uint8_t priority; /* Higher = more specific */
|
|
||||||
};
|
/* Use to order instructions in the lookup table. The more specific
|
||||||
|
* instructions are checked first */
|
||||||
|
uint8_t priority;
|
||||||
|
} arm32_instruction_info_t;
|
||||||
|
|
||||||
struct arm32_decoder
|
struct arm32_decoder
|
||||||
{
|
{
|
||||||
|
pound::host::memory::arena_t allocator;
|
||||||
arm32_instruction_info_t* instructions;
|
arm32_instruction_info_t* instructions;
|
||||||
size_t instruction_count;
|
size_t instruction_count;
|
||||||
size_t instruction_capacity;
|
size_t instruction_capacity;
|
||||||
|
|
@ -39,9 +40,11 @@ struct arm32_decoder
|
||||||
} lookup_table[4096]; /* 2^12 entries. */
|
} lookup_table[4096]; /* 2^12 entries. */
|
||||||
};
|
};
|
||||||
|
|
||||||
void arm32_init(arm32_decoder_t* decoder);
|
extern arm32_decoder_t g_arm32_decoder;
|
||||||
|
|
||||||
void arm32_add_instruction(arm32_decoder_t* decoder, const char* nane, arm32_opcode_t mask, arm32_opcode_t expected,
|
void arm32_init(pound::host::memory::arena_t allocator, arm32_decoder_t* decoder);
|
||||||
|
|
||||||
|
void arm32_add_instruction(arm32_decoder_t* decoder, const char* name, arm32_opcode_t mask, arm32_opcode_t expected,
|
||||||
arm32_handler_fn handler);
|
arm32_handler_fn handler);
|
||||||
void arm32_ADD_imm_handler(arm32_decoder_t* decoder, arm32_instruction_t instruction);
|
void arm32_ADD_imm_handler(arm32_decoder_t* decoder, arm32_instruction_t instruction);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
#include "common/passert.h"
|
#include "common/passert.h"
|
||||||
#include "frontend/gui.h"
|
#include "frontend/gui.h"
|
||||||
#include "host/memory/arena.h"
|
#include "host/memory/arena.h"
|
||||||
|
#include "jit/decoder/arm32.h"
|
||||||
|
|
||||||
#include <SDL3/SDL_opengl.h>
|
#include <SDL3/SDL_opengl.h>
|
||||||
#include "frontend/color.h"
|
#include "frontend/color.h"
|
||||||
|
|
@ -18,6 +19,8 @@
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
pound::host::memory::arena_t arena = pound::host::memory::arena_init(256);
|
||||||
|
pound::jit::decoder::arm32_init(arena, £::jit::decoder::g_arm32_decoder);
|
||||||
#if 0
|
#if 0
|
||||||
gui::window_t window = {.data = nullptr, .gl_context = nullptr};
|
gui::window_t window = {.data = nullptr, .gl_context = nullptr};
|
||||||
(void)gui::window_init(&window, "Pound Emulator", 640, 480);
|
(void)gui::window_init(&window, "Pound Emulator", 640, 480);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue