diff --git a/src/jit/CMakeLists.txt b/src/jit/CMakeLists.txt index 44fa8e4..e46eee3 100644 --- a/src/jit/CMakeLists.txt +++ b/src/jit/CMakeLists.txt @@ -4,7 +4,7 @@ target_sources(jit PRIVATE ${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 ${CMAKE_CURRENT_SOURCE_DIR} diff --git a/src/jit/decoder/arm32.cpp b/src/jit/decoder/arm32.cpp index 24e8238..2434a59 100644 --- a/src/jit/decoder/arm32.cpp +++ b/src/jit/decoder/arm32.cpp @@ -1,19 +1,134 @@ #include "arm32.h" +#include +#include "common/passert.h" + +#define LOG_MODULE "jit" +#include "common/logging.h" + namespace pound::jit::decoder { +/* Increase value as more instructions get implemented */ +#define INSTRUCTION_ARRAY_CAPACITY 4 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" #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 diff --git a/src/jit/decoder/arm32.h b/src/jit/decoder/arm32.h index 134f46a..7b2f79d 100644 --- a/src/jit/decoder/arm32.h +++ b/src/jit/decoder/arm32.h @@ -3,30 +3,31 @@ #include #include +#include "host/memory/arena.h" namespace pound::jit::decoder { typedef uint32_t arm32_opcode_t; typedef uint32_t arm32_instruction_t; -typedef struct arm32_instruction_info arm32_instruction_info_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); -struct a32_instruction_info +typedef struct { const char* name; arm32_opcode_t mask; arm32_opcode_t expected; 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 { + pound::host::memory::arena_t allocator; arm32_instruction_info_t* instructions; size_t instruction_count; size_t instruction_capacity; @@ -39,9 +40,11 @@ struct arm32_decoder } 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); void arm32_ADD_imm_handler(arm32_decoder_t* decoder, arm32_instruction_t instruction); diff --git a/src/main.cpp b/src/main.cpp index e5b1576..7ec5b90 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,6 +9,7 @@ #include "common/passert.h" #include "frontend/gui.h" #include "host/memory/arena.h" +#include "jit/decoder/arm32.h" #include #include "frontend/color.h" @@ -18,6 +19,8 @@ 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 gui::window_t window = {.data = nullptr, .gl_context = nullptr}; (void)gui::window_init(&window, "Pound Emulator", 640, 480);