diff --git a/CMakeLists.txt b/CMakeLists.txt index fd0b72f..08fb491 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,7 +97,6 @@ add_executable(Pound add_subdirectory(3rd_Party) add_subdirectory(src/common) -add_subdirectory(src/frontend) add_subdirectory(src/host) add_subdirectory(src/jit) add_subdirectory(src/pvm) @@ -110,7 +109,7 @@ add_subdirectory(src/targets/switch1/hardware) include(TestBigEndian) TEST_BIG_ENDIAN(WORDS_BIGENDIAN) -list(APPEND POUND_PROJECT_TARGETS common frontend host pvm) +list(APPEND POUND_PROJECT_TARGETS common host pvm) foreach(TARGET ${POUND_PROJECT_TARGETS}) # Apply Endianness definitions to all our targets. if(WORDS_BIGENDIAN) @@ -149,7 +148,6 @@ set_property(TARGET Pound PROPERTY CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE TR target_link_libraries(Pound PRIVATE common - frontend host jit pvm diff --git a/src/jit/decoder/arm32.cpp b/src/jit/decoder/arm32.cpp index 460eb12..de9bc42 100644 --- a/src/jit/decoder/arm32.cpp +++ b/src/jit/decoder/arm32.cpp @@ -9,7 +9,15 @@ namespace pound::jit::decoder { /* Increase value as more instructions get implemented */ #define INSTRUCTION_ARRAY_CAPACITY 4 -arm32_decoder_t g_arm32_decoder = {}; + +typedef struct +{ + uint16_t* hash_table; + uint8_t* collision_map; + uint16_t hash_shift; + uint16_t hash_mask; + uint16_t table_size; +} arm32_perfect_hash_t; /* * ============================================================================ @@ -18,6 +26,7 @@ arm32_decoder_t g_arm32_decoder = {}; */ 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_SUB_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); @@ -50,8 +59,67 @@ void arm32_init(pound::host::memory::arena_t allocator, arm32_decoder_t* decoder #define INST(fn, name, bitstring) arm32_add_instruction(decoder, name, bitstring, &arm32_##fn##_handler); #include "./arm32.inc" #undef INST + + LOG_TRACE("Initializing perfect hash parameters for %zu instructions", decoder->instruction_count); + + /* Start with table size as next power of 2 >= count * 2 */ + uint16_t table_size = 1U; + while (table_size < decoder->instruction_count * 2) + { + table_size <<= 1U; + } + + uint16_t mask = table_size - 1; + size_t slots_used_size = table_size * sizeof(bool); + bool* slots_used = (bool*)pound::host::memory::arena_allocate(&decoder->allocator, slots_used_size); + PVM_ASSERT(nullptr != slots_used); + LOG_TRACE("Growing perfevt hash slots used array to %d bytes", slots_used_size); + + uint16_t shift = 0; + bool perfect_hash_generated = false; + for (; shift < 16; ++shift) + { + bool collision_free = true; + (void)memset(slots_used, false, slots_used_size); + + for (size_t i = 0; i < decoder->instruction_count; ++i) + { + // FIX: Improved hash seed generation + uint32_t value = decoder->instructions[i].mask ^ decoder->instructions[i].expected; + value = ((value >> 16) ^ value) * 0x45d9f3b; + value = ((value >> 16) ^ value) * 0x45d9f3b; + value = (value >> 16) ^ value; + uint32_t hash_seed = value; + uint16_t hash = ((hash_seed >> shift) & mask); + + if (true == slots_used[hash]) + { + LOG_TRACE("COLLISION DETECTED at slot %u for shift %u", hash, shift); + collision_free = false; + break; + } + slots_used[hash] = true; + } + if (true == collision_free) + { + LOG_TRACE("COLLISION-FREE HASH found for shift %u", shift); + perfect_hash_generated = true; + break; + } + } + + PVM_ASSERT_MSG(true == perfect_hash_generated, "Failed to generate perfect hash - no collision-free hash found"); + LOG_TRACE("Perfect hash parameters: shift=%u, mask=0x%04x, table_size=%u", shift, mask, table_size); + + /* TODO(GloriousTacoo:jit): Generate hash table. */ } +/* + * ============================================================================ + * Private Functions + * ============================================================================ + */ + void arm32_add_instruction(arm32_decoder_t* decoder, const char* name, const char* bitstring, arm32_handler_fn handler) { PVM_ASSERT(nullptr != decoder); @@ -81,23 +149,13 @@ void arm32_add_instruction(arm32_decoder_t* decoder, const char* name, const cha } ++decoder->instruction_count; - LOG_TRACE("========================================"); LOG_TRACE("Instruction Registered: %s", info->name); LOG_TRACE("Mask: 0x%08X", info->mask); LOG_TRACE("Expected: 0x%08X", info->expected); LOG_TRACE("Priority: %d", info->priority); - LOG_TRACE("========================================"); - - - /* 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_SUB_imm_handler(arm32_decoder_t* decoder, arm32_instruction_t instruction) {} void arm32_parse_bitstring(const char* bitstring, uint32_t* mask, uint32_t* expected) { @@ -109,7 +167,7 @@ void arm32_parse_bitstring(const char* bitstring, uint32_t* mask, uint32_t* expe *mask = 0; *expected = 0; uint8_t instruction_size_bits = 32; - for (int i = 0; (i < instruction_size_bits) && (bitstring[i] != '\0'); ++i) + for (unsigned int i = 0; (i < instruction_size_bits) && (bitstring[i] != '\0'); ++i) { uint32_t bit_position = 31 - i; switch (bitstring[i]) @@ -134,5 +192,4 @@ void arm32_parse_bitstring(const char* bitstring, uint32_t* mask, uint32_t* expe } } } - } // namespace pound::jit::decoder diff --git a/src/jit/decoder/arm32.h b/src/jit/decoder/arm32.h index c984d45..6bc1a01 100644 --- a/src/jit/decoder/arm32.h +++ b/src/jit/decoder/arm32.h @@ -31,23 +31,10 @@ struct arm32_decoder arm32_instruction_info_t* instructions; size_t instruction_count; size_t instruction_capacity; - - struct - { - arm32_instruction_info_t** bucket; - size_t count; - size_t capacity; - } lookup_table[4096]; /* 2^12 entries. */ }; extern arm32_decoder_t g_arm32_decoder; 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); - - -} // namespace pound::jit::decoder -#endif // POUND_JIT_DECODER_ARM32_H \ No newline at end of file +} +#endif // POUND_JIT_DECODER_ARM32_H diff --git a/src/jit/decoder/arm32.inc b/src/jit/decoder/arm32.inc index f435120..122992c 100644 --- a/src/jit/decoder/arm32.inc +++ b/src/jit/decoder/arm32.inc @@ -64,7 +64,7 @@ INST(ADD_imm, "ADD (imm)", "cccc0010100Snnnnddddrrrrvvvvvvvv") // v1 //INST(SBC_imm, "SBC (imm)", "cccc0010110Snnnnddddrrrrvvvvvvvv") // v1 //INST(SBC_reg, "SBC (reg)", "cccc0000110Snnnnddddvvvvvrr0mmmm") // v1 //INST(SBC_rsr, "SBC (rsr)", "cccc0000110Snnnnddddssss0rr1mmmm") // v1 -//INST(SUB_imm, "SUB (imm)", "cccc0010010Snnnnddddrrrrvvvvvvvv") // v1 +INST(SUB_imm, "SUB (imm)", "cccc0010010Snnnnddddrrrrvvvvvvvv") // v1 //INST(SUB_reg, "SUB (reg)", "cccc0000010Snnnnddddvvvvvrr0mmmm") // v1 //INST(SUB_rsr, "SUB (rsr)", "cccc0000010Snnnnddddssss0rr1mmmm") // v1 //INST(TEQ_imm, "TEQ (imm)", "cccc00110011nnnn0000rrrrvvvvvvvv") // v1 diff --git a/src/main.cpp b/src/main.cpp index 7ec5b90..5fbb8d6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -20,7 +20,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); + pound::jit::decoder::arm32_decoder_t decoder = {}; + pound::jit::decoder::arm32_init(arena, &decoder); #if 0 gui::window_t window = {.data = nullptr, .gl_context = nullptr}; (void)gui::window_init(&window, "Pound Emulator", 640, 480);