From 6cca3fbe8b9beca6b9e245f84457651cca858e28 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Wed, 9 Sep 2026 01:50:20 -0400 Subject: [PATCH] decoder seems to be working, need to make a serializer next. --- code/8086/decoder.c | 70 ++++++++++++++++++++++++++---------------- code/8086/decoder.h | 62 ++++++++++++++++++++----------------- code/duffle/dsl.h | 7 +++-- code/duffle/files.h | 2 +- code/part_1/sim_8086.c | 34 +++++++++++++++++--- perfaware.proj | 4 +-- scripts/build.ps1 | 4 +-- 7 files changed, 116 insertions(+), 67 deletions(-) diff --git a/code/8086/decoder.c b/code/8086/decoder.c index c0f152a..541c6af 100644 --- a/code/8086/decoder.c +++ b/code/8086/decoder.c @@ -33,7 +33,7 @@ typedef Struct_(X8616_DecodePlex) { U2 dispatch; U1 plan_idx; - X8616_DecodePlan const* plan; + X8616_DecodePlan* plan; U1 opcode; U1 post_opcode; @@ -80,6 +80,23 @@ typedef Struct_(X8616_DecodePlex) { FI_ U2 x8616_decode_u2(U1_R bytes) { return C_(U2, bytes[0] | u2_(bytes[1] << 8)); } +internal X8616_OpcodePrefix +x8616_decode_opcode(X8616_DecodePlan const* plan, U1 opcode) +{ + U1 field_mask = 0; + if (plan->flags & x8616_plan_has_d) field_mask |= u1_(1u << plan->d_shift); + if (plan->flags & x8616_plan_has_w) field_mask |= u1_(1u << plan->w_shift); + if (plan->flags & x8616_plan_has_s) field_mask |= u1_(1u << plan->s_shift); + if (plan->flags & x8616_plan_has_v) field_mask |= u1_(1u << plan->v_shift); + if (plan->flags & x8616_plan_has_z) field_mask |= u1_(1u << plan->z_shift); + if (plan->flags & x8616_plan_has_reg) field_mask |= u1_(0b111u << plan->reg_shift); + if (plan->flags & x8616_plan_has_sr) field_mask |= u1_(0b11u << plan->sr_shift); + if (field_mask == 0) return 0; + U1 stem_mask = u1_(~field_mask); + if (stem_mask == 0) return 0; + return C_(X8616_OpcodePrefix, (opcode & stem_mask) >> count_trailing_zeros_u4(stem_mask)); +} + internal void x8616_decode_apply_prefix(X8616_DecodePlex_R plex, X8616_DecodePlan_R plan, U1 opcode) { plex->prefixes.count += 1; @@ -107,7 +124,7 @@ x8616_decode_one_plex(X8616_DecodePlex* plex) U2 prefix_dispatch = x8616_decode_dispatch[prefix_opcode]; if (prefix_dispatch == false || (prefix_dispatch & X8616_DECODE_AUX_BIT)) break; - X8616_DecodePlan const* prefix_plan = x8616_decode_plans + prefix_dispatch; + X8616_DecodePlan_R prefix_plan = x8616_decode_plans + prefix_dispatch; if ((prefix_plan->flags & x8616_plan_is_prefix) == false) break; x8616_decode_apply_prefix(plex, prefix_plan, prefix_opcode); @@ -228,7 +245,6 @@ x8616_decode_one_plex(X8616_DecodePlex* plex) plex->instruction.prefixes = plex->prefixes; plex->instruction.op = x8616_op_invalid; plex->instruction.decode_flags = (plex->encoding_invalid ? x8616_decode_invalid : 0) | (plex->classification_truncated ? x8616_decode_truncated : 0); - plex->instruction.opcode = plex->opcode; plex->instruction.size = u1_(prefix_at + invalid_body_size); plex->instruction.size_required = plex->instruction.size; return plex->instruction.size; @@ -303,39 +319,39 @@ x8616_decode_one_plex(X8616_DecodePlex* plex) X8616_DecodedOperand* source = plex->operand_source; - source[x8616_operand_reg_modrm].flags = x8616_decoded_operand_register; - source[x8616_operand_reg_modrm].width = plex->width; - source[x8616_operand_reg_modrm].reg = plex->reg; + source[x8616_operand_reg_modrm].flags = x8616_decoded_operand_register; + source[x8616_operand_reg_modrm].width = plex->width; + source[x8616_operand_reg_modrm].reg.r16 = C_(X8616_Reg16, plex->reg); - source[x8616_operand_reg_opcode].flags = x8616_decoded_operand_register; - source[x8616_operand_reg_opcode].width = plex->width; - source[x8616_operand_reg_opcode].reg = plex->reg_opcode; + source[x8616_operand_reg_opcode].flags = x8616_decoded_operand_register; + source[x8616_operand_reg_opcode].width = plex->width; + source[x8616_operand_reg_opcode].reg.r16 = C_(X8616_Reg16, plex->reg_opcode); source[x8616_operand_segment_modrm].flags = x8616_decoded_operand_segment; source[x8616_operand_segment_modrm].width = x8616_width_word; - source[x8616_operand_segment_modrm].segment = plex->sr_modrm; + source[x8616_operand_segment_modrm].segment = C_(X8616_Segment, plex->sr_modrm); source[x8616_operand_segment_opcode].flags = x8616_decoded_operand_segment; source[x8616_operand_segment_opcode].width = x8616_width_word; - source[x8616_operand_segment_opcode].segment = plex->sr_opcode; + source[x8616_operand_segment_opcode].segment = C_(X8616_Segment, plex->sr_opcode); - source[x8616_operand_acc].flags = x8616_decoded_operand_register | x8616_decoded_operand_implicit; - source[x8616_operand_acc].width = plex->width; - source[x8616_operand_acc].reg = 0; + source[x8616_operand_acc].flags = x8616_decoded_operand_register | x8616_decoded_operand_implicit; + source[x8616_operand_acc].width = plex->width; + source[x8616_operand_acc].reg.r16 = x8616_ax; - source[x8616_operand_dx].flags = x8616_decoded_operand_register | x8616_decoded_operand_implicit; - source[x8616_operand_dx].width = x8616_width_word; - source[x8616_operand_dx].reg = x8616_dx; + source[x8616_operand_dx].flags = x8616_decoded_operand_register | x8616_decoded_operand_implicit; + source[x8616_operand_dx].width = x8616_width_word; + source[x8616_operand_dx].reg.r16 = x8616_dx; source[x8616_operand_rm].width = plex->width; if (plex->mod == x8616_mod_reg) { - source[x8616_operand_rm].flags = x8616_decoded_operand_register; - source[x8616_operand_rm].reg = plex->rm; + source[x8616_operand_rm].flags = x8616_decoded_operand_register; + source[x8616_operand_rm].reg.r16 = C_(X8616_Reg16, plex->rm); } else { source[x8616_operand_rm].flags = x8616_decoded_operand_memory; - source[x8616_operand_rm].mod = plex->mod; - source[x8616_operand_rm].ea = plex->rm; + source[x8616_operand_rm].mod = C_(X8616_Mod, plex->mod); + source[x8616_operand_rm].ea = C_(X8616_EA, plex->rm); source[x8616_operand_rm].displacement = plex->displacement; source[x8616_operand_rm].displacement_bytes = plex->displacement_bytes; if (plex->direct_memory) { @@ -382,7 +398,7 @@ x8616_decode_one_plex(X8616_DecodePlex* plex) source[x8616_operand_shift_count].width = x8616_width_byte; if (plex->v == x8616_v_cl) { source[x8616_operand_shift_count].flags |= x8616_decoded_operand_register; - source[x8616_operand_shift_count].reg = x8616_cl; + source[x8616_operand_shift_count].reg.r8 = x8616_cl; } else { source[x8616_operand_shift_count].flags |= x8616_decoded_operand_immediate; @@ -400,10 +416,11 @@ x8616_decode_one_plex(X8616_DecodePlex* plex) plex->instruction.decode_flags = (plex->encoding_invalid ? x8616_decode_invalid : 0) | (plex->classification_truncated ? x8616_decode_truncated : 0); plex->instruction.width = plex->width; plex->instruction.prefixes = plex->prefixes; - plex->instruction.operand_count = plan->operand_count; - plex->instruction.opcode = plex->opcode; - plex->instruction.mod_rm = plex->mod_rm; - plex->instruction.has_mod_rm = (plan->flags & x8616_plan_has_modrm) != 0; + plex->instruction.operand_count = plan->operand_count; + plex->instruction.opcode = x8616_decode_opcode(plan, plex->opcode); + plex->instruction.d = C_(X8616_Direction, (plan->flags & x8616_plan_has_d) ? plex->d : 0); + plex->instruction.w = C_(X8616_Width, (plan->flags & x8616_plan_has_w) ? plex->w : 0); + plex->instruction.has_mod_rm = (plan->flags & x8616_plan_has_modrm) != 0; U4 total_required = prefix_at + plex->body_required; U4 total_available = plex->source_size; @@ -414,6 +431,7 @@ x8616_decode_one_plex(X8616_DecodePlex* plex) return total_consumed; } +#define x8616_decode_(...) x8616_decode((X8616_DecodeRequest){__VA_ARGS__}) X8616_DecodeInfo x8616_decode(X8616_DecodeRequest request) { X8616_DecodeInfo result = {0}; diff --git a/code/8086/decoder.h b/code/8086/decoder.h index b465b97..ed238c7 100644 --- a/code/8086/decoder.h +++ b/code/8086/decoder.h @@ -12,25 +12,30 @@ enum { }; typedef Enum_(U2, X8616_DecodedOperandFlags) { - x8616_decoded_operand_none = 0b0000000000000000, - x8616_decoded_operand_register = 0b0000000000000001, - x8616_decoded_operand_segment = 0b0000000000000010, - x8616_decoded_operand_memory = 0b0000000000000100, - x8616_decoded_operand_immediate = 0b0000000000001000, - x8616_decoded_operand_relative = 0b0000000000010000, - x8616_decoded_operand_far_ptr = 0b0000000000100000, - x8616_decoded_operand_direct = 0b0000000001000000, - x8616_decoded_operand_sign_extended = 0b0000000010000000, - x8616_decoded_operand_implicit = 0b0000000100000000, + Bit_(x8616_decoded_operand_none, 0), + Bit_(x8616_decoded_operand_register, 1), + Bit_(x8616_decoded_operand_segment, 2), + Bit_(x8616_decoded_operand_memory, 3), + Bit_(x8616_decoded_operand_immediate, 4), + Bit_(x8616_decoded_operand_relative, 5), + Bit_(x8616_decoded_operand_far_ptr, 6), + Bit_(x8616_decoded_operand_direct, 7), + Bit_(x8616_decoded_operand_sign_extended, 8), + Bit_(x8616_decoded_operand_implicit, 9), +}; + +typedef Union_(X8616_DecodedReg) { + X8616_Reg8 r8; + X8616_Reg16 r16; }; typedef Struct_(X8616_DecodedOperand) { X8616_DecodedOperandFlags flags; X8616_WidthMode width; - U1 reg; - U1 segment; - U1 mod; - U1 ea; + X8616_DecodedReg reg; + X8616_Segment segment; + X8616_Mod mod; + X8616_EA ea; S2 displacement; U2 address; U2 immediate; @@ -64,26 +69,27 @@ typedef Struct_(X8616_DecodedInstruction) { X8616_DecodedPrefixes prefixes; X8616_DecodedOperand operands[2]; U1 operand_count; - U1 opcode; - U1 mod_rm; + X8616_OpcodePrefix opcode; + X8616_Direction d; + X8616_Width w; B1 has_mod_rm; U1 size; U1 size_required; }; typedef Enum_(U2, X8616_DecodePlanFlags) { - x8616_plan_none = 0b0000000000000000, - x8616_plan_has_modrm = 0b0000000000000001, - x8616_plan_has_post_opcode = 0b0000000000000010, - x8616_plan_has_d = 0b0000000000000100, - x8616_plan_has_w = 0b0000000000001000, - x8616_plan_has_s = 0b0000000000010000, - x8616_plan_has_v = 0b0000000000100000, - x8616_plan_has_z = 0b0000000001000000, - x8616_plan_has_reg = 0b0000000010000000, - x8616_plan_has_sr = 0b0000000100000000, - x8616_plan_uses_rm = 0b0000001000000000, - x8616_plan_is_prefix = 0b0000010000000000, + Bit_(x8616_plan_none, 0), + Bit_(x8616_plan_has_modrm, 1), + Bit_(x8616_plan_has_post_opcode, 2), + Bit_(x8616_plan_has_d, 3), + Bit_(x8616_plan_has_w, 4), + Bit_(x8616_plan_has_s, 5), + Bit_(x8616_plan_has_v, 6), + Bit_(x8616_plan_has_z, 7), + Bit_(x8616_plan_has_reg, 8), + Bit_(x8616_plan_has_sr, 9), + Bit_(x8616_plan_uses_rm, 10), + Bit_(x8616_plan_is_prefix, 11), }; typedef Enum_(U1, X8616_DecodePayload) { diff --git a/code/duffle/dsl.h b/code/duffle/dsl.h index 858dd67..f73f7ff 100644 --- a/code/duffle/dsl.h +++ b/code/duffle/dsl.h @@ -10,6 +10,7 @@ Standard: c23 #pragma clang diagnostic ignored "-Wswitch" #pragma clang diagnostic ignored "-Wuninitialized" #pragma clang diagnostic ignored "-Wmicrosoft-enum-forward-reference" +#pragma clang diagnostic ignored "-Wmicrosoft-fixed-enum" // #pragma comment(lib, "Advapi32.lib") // #pragma comment(lib, "gdi32.lib") // #pragma comment(lib, "Kernel32.lib") @@ -122,7 +123,7 @@ Standard: c23 #define Array_expand(type,len) type Array_sym(type, len)[len]; typedef PtrSet_(Array_sym(type, len)) #define Array_(type,len) Array_expand(type,len) #define Bit_(id,b) id = (1 << b), tmpl(id,pos) = b -#define Enum_(underlying_type, symbol) underlying_type TSet_(symbol); enum symbol +#define Enum_(underlying_type, symbol) enum symbol : underlying_type TSet_(symbol); enum symbol : underlying_type #define Proc_(symbol) symbol #define Relative_(symbol) // Does nothing but annotate that a symbol is associated with another. #define Struct_(symbol) struct symbol TSet_(symbol); struct symbol @@ -277,8 +278,8 @@ enum { Bitmask_10 = 0x000003ff, }; -typedef Enum_(U4,WeekDay){ WeekDay_Sun, WeekDay_Mon, WeekDay_Tue, WeekDay_Wed, WeekDay_Thu, WeekDay_Fri, WeekDay_Sat, WeekDay_Num, }; -typedef Enum_(U4,Month) { Month_Jan, Month_Feb, Month_Mar, Month_Apr, Month_May, Month_Jun, Month_Jul, Month_Aug, Month_Sep, Month_Oct, Month_Nov, Month_Dec, Month_Num, }; +typedef Enum_(U4, WeekDay) { WeekDay_Sun, WeekDay_Mon, WeekDay_Tue, WeekDay_Wed, WeekDay_Thu, WeekDay_Fri, WeekDay_Sat, WeekDay_Num, }; +typedef Enum_(U4, Month) { Month_Jan, Month_Feb, Month_Mar, Month_Apr, Month_May, Month_Jun, Month_Jul, Month_Aug, Month_Sep, Month_Oct, Month_Nov, Month_Dec, Month_Num, }; typedef U8 DenseTime; diff --git a/code/duffle/files.h b/code/duffle/files.h index 405a27c..14137b7 100644 --- a/code/duffle/files.h +++ b/code/duffle/files.h @@ -13,7 +13,7 @@ CLANG_OPTIMIZE_DISABLE // Most of this referenced from the RAD Debugger codebase. -typedef Enum_(U4,AccessFlags) { +typedef Enum_(U4, AccessFlags) { Bit_(AccessFlag_Read, 0), Bit_(AccessFlag_Write, 1), Bit_(AccessFlag_Execute, 2), diff --git a/code/part_1/sim_8086.c b/code/part_1/sim_8086.c index d967cf2..c1ba231 100644 --- a/code/part_1/sim_8086.c +++ b/code/part_1/sim_8086.c @@ -1,4 +1,5 @@ #include "duffle/dsl.h" +#include "duffle/asm.h" #include "duffle/analysis.h" #include "duffle/math.h" #include "duffle/memory.h" @@ -10,6 +11,15 @@ #include "duffle/win32.h" +#include "8086/encoder.h" +#include "8086/encoder_table.h" +#include "8086/info.h" +#include "8086/info_render.h" +#include "8086/decoder.h" +#include "8086/gen/decoder_table.h" + +#include "8086/decoder.c" + // #include "8086/decoder.h" typedef Struct_(U2_HL) { U1 Low; U1 High; }; @@ -56,22 +66,23 @@ I_ Str8 binary_as_str8(Slice_U1 data, FArena* str8_mem) { Str8 result = {0}; jret: return result; } - - enum { - Scratchpad_Len = kilo(1), + Scratchpad_Len = kilo(16), FileRam_Len = kilo(16), }; typedef Struct_(SMemory) { U1 Scratchpad [Scratchpad_Len]; U1 FileRam [FileRam_Len]; + + U1 decode_mem[kilo(64)]; }; global SMemory smem; #define path_course_content "./course_content/perfaware/" #define path_part1 path_course_content "part1/" -CLANG_OPTIMIZE_DISABLE +typedef Slice_(X8616_DecodedInstruction); + int main() { FArena scratch = farena_make(slice_ut_arr(smem.Scratchpad)); @@ -80,8 +91,21 @@ int main() Str8 path_listing_0037_single_register_mov = slit8(path_part1 "listing_0037_single_register_mov"); Str8 path_listing_0037_single_register_mov_asm = slit8(path_part1 "listing_0037_single_register_mov.asm"); Slice_U1 data = data_from_file_path(& file_arena, path_listing_0037_single_register_mov, & scratch); + farena_reset(& scratch); + + FArena decode_arena = farena_make(slice_ut_arr(smem.decode_mem)); + Slice_X8616_DecodedInstruction decoded = farena_push_array(& decode_arena, X8616_DecodedInstruction, data.len); + + X8616_DecodeInfo info = x8616_decode_( + .source = data.ptr, + .source_size = data.len, + .instructions = decoded.ptr, + .instruction_capacity = decoded.len, + .info_arena = & decode_arena, + ); + assert(info.instruction_count > 0); + // Str8 infO_report = x8616_info_render(slice_ut_arr(smem.Scratchpad), info.msgs.first,); ms_exit_process(0); return 0; } -CLANG_OPTIMIZE_ENABLE diff --git a/perfaware.proj b/perfaware.proj index 8cb251c..55322f2 100644 --- a/perfaware.proj +++ b/perfaware.proj @@ -3,12 +3,12 @@ target: { executable: "build/sim_8086.exe" - working_directory: "" + working_directory: "../perfaware" label: "Sim 8086" + enabled: 1 } target: { executable: "build/decoder_table_generator.meta.exe" working_directory: "../perfaware" - enabled: 1 } diff --git a/scripts/build.ps1 b/scripts/build.ps1 index 0ab6a94..63b0f7f 100644 --- a/scripts/build.ps1 +++ b/scripts/build.ps1 @@ -391,7 +391,7 @@ function build-8086_decoder_table { dump-disassembly $module_c $exe } -build-8086_decoder_table +# build-8086_decoder_table function build-part_1 { # The base lib uses subdir-prefixed includes (e.g. "duffle/dsl.h"), @@ -418,4 +418,4 @@ function build-part_1 { dump-disassembly $module_c $exe } -# build-part_1 +build-part_1