From c49e296f5e0075e02c37ece4fc7dedf765c9b970 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 14 Jun 2026 18:24:59 +0100 Subject: [PATCH] Update doc files --- core/rexcode/arm32/tests/sweep.odin | 7 +- core/rexcode/doc.odin | 76 ++++++------ core/rexcode/docs/cross_arch_design.md | 69 +++++------ core/rexcode/docs/x86_api.md | 160 +++++++++++++------------ core/rexcode/x86/decoder.odin | 147 ++++++++++++----------- core/rexcode/x86/tests/test.odin | 46 +++---- 6 files changed, 253 insertions(+), 252 deletions(-) diff --git a/core/rexcode/arm32/tests/sweep.odin b/core/rexcode/arm32/tests/sweep.odin index 1568a6264..069b509e5 100644 --- a/core/rexcode/arm32/tests/sweep.odin +++ b/core/rexcode/arm32/tests/sweep.odin @@ -42,18 +42,17 @@ run_sweep_tests :: proc() { for mn in a.Mnemonic { forms := a.ENCODING_TABLE[mn] - for idx in 0../tools/`: ``` rexcode/ - isa/ # shared core: labels, status, print framework, label-inference - docs/ # cross-arch design + per-arch design docs - x86/ # x86-64 / i386 - arm32/ # AArch32 - arm64/ # AArch64 - mips/ # MIPS (R1..R6 + ASEs + coprocessors) - mos6502/ # NMOS 6502 family - mos65816/ # W65C816S - ppc/ # PowerPC (Power ISA 3.1) - ppc_vle/ # Freescale VLE (sibling of ppc) - riscv/ # RISC-V - rsp/ # N64 RSP + isa/ # shared core: labels, status, print framework, label-inference + docs/ # cross-arch design + per-arch design docs + x86/ # x86-64 / i386 + arm32/ # AArch32 + arm64/ # AArch64 + mips/ # MIPS (R1..R6 + ASEs + coprocessors) + mos6502/ # NMOS 6502 family + mos65816/ # W65C816S + ppc/ # PowerPC (Power ISA 3.1) + ppc_vle/ # Freescale VLE (sibling of ppc) + riscv/ # RISC-V + rsp/ # N64 RSP ``` Per-package layout (canonical, enforced by the cross-arch contract): ``` / - encoder.odin # encode() — two-pass, label/reloc-aware - decoder.odin # decode() - printer.odin # sb/sbln/print/println/aprint/aprintln/tprint/tprintln/bprint/bprintln/fprint/fprintln/wprint/wprintln - registers.odin # Register, REG_* classes, typed enums - operands.odin # Operand, Memory, Operand_Kind, op_* constructors - instructions.odin # Instruction, inst_* builders - encoding_types.odin # Encoding, Encoding_Flags, isa re-exports - encoding_table.odin # ENCODING_TABLE: [Mnemonic][]Encoding - decoding_tables.odin # generated dispatch tables - mnemonics.odin # Mnemonic enum (u16, INVALID=0) - reloc.odin # Relocation_Type + Relocation - tests/ # smoke, pipeline_smoke, sweep - tools/ # gen_decode_tables, dump_verify_input, verify_against_* + encoder.odin # encode() — two-pass, label/reloc-aware + decoder.odin # decode() + printer.odin # sb/sbln/print/println/aprint/aprintln/tprint/tprintln/bprint/bprintln/fprint/fprintln/wprint/wprintln + registers.odin # Register, REG_* classes, typed enums + operands.odin # Operand, Memory, Operand_Kind, op_* constructors + instructions.odin # Instruction, inst_* builders + encoding_types.odin # Encoding, Encoding_Flags, isa re-exports + encoding_table.odin # ENCODING_TABLE: [Mnemonic][]Encoding + decoding_tables.odin # generated dispatch tables + mnemonics.odin # Mnemonic enum (u16, INVALID=0) + reloc.odin # Relocation_Type + Relocation + tests/ # smoke, pipeline_smoke, sweep + tools/ # gen_decode_tables, dump_verify_input, verify_against_* ``` ## Cross-architecture API design diff --git a/core/rexcode/docs/cross_arch_design.md b/core/rexcode/docs/cross_arch_design.md index 102d43082..02b710a86 100644 --- a/core/rexcode/docs/cross_arch_design.md +++ b/core/rexcode/docs/cross_arch_design.md @@ -207,25 +207,25 @@ for an **opt-in** facade (§5.3) that only multi-target *tools* pay for. ``` rexcode/ isa/ # shared, architecture-independent core - labels.odin # Label, Label_Definition, Label_Map, resolution - reloc.odin # Relocation (type field is generic/u8) - status.odin # Result, Error, shared Error_Code core - print.odin # Token, Token_Kind, Print_Options, sinks, num-fmt - register.odin # distinct-u16 layout convention + reg_hw/reg_class - pipeline.odin # parametric encode_stream/decode_stream (§7) - target.odin # optional runtime Target vtable (§5.3) + labels.odin # Label, Label_Definition, Label_Map, resolution + reloc.odin # Relocation (type field is generic/u8) + status.odin # Result, Error, shared Error_Code core + print.odin # Token, Token_Kind, Print_Options, sinks, num-fmt + register.odin # distinct-u16 layout convention + reg_hw/reg_class + pipeline.odin # parametric encode_stream/decode_stream (§7) + target.odin # optional runtime Target vtable (§5.3) x86/ # exists today; refactor to import isa - registers.odin operands.odin instructions.odin mnemonics.odin - encoding_types.odin encoder.odin decoder.odin printer.odin - encoding_table.odin decoding_tables.odin mnemonic_builders.odin - tests/ tools/ + registers.odin operands.odin instructions.odin mnemonics.odin + encoding_types.odin encoder.odin decoder.odin printer.odin + encoding_table.odin decoding_tables.odin mnemonic_builders.odin + tests/ tools/ riscv/ # next: same shape as x86/ - registers.odin operands.odin instructions.odin mnemonics.odin - encoding_types.odin encoder.odin decoder.odin printer.odin - encoding_table.odin decoding_tables.odin mnemonic_builders.odin - tests/ tools/ + registers.odin operands.odin instructions.odin mnemonics.odin + encoding_types.odin encoder.odin decoder.odin printer.odin + encoding_table.odin decoding_tables.odin mnemonic_builders.odin + tests/ tools/ arm64/ mips/ … # future, same template ``` @@ -269,11 +269,11 @@ provides a vtable populated by each arch: ```odin // isa/target.odin Target :: struct { - name: string, - decode: proc(data: []u8, out: ^Decoded) -> Result, // bytes → generic Decoded - print: proc(d: ^Decoded, opts: ^Print_Options) -> string, - inst_align: u32, // 1 for x86, 4 for riscv/arm64/mips - max_inst: u32, // 15 for x86, 4 for riscv (8 for C-pairs), 4 for arm64 + name: string, + decode: proc(data: []u8, out: ^Decoded) -> Result, // bytes → generic Decoded + print: proc(d: ^Decoded, opts: ^Print_Options) -> string, + inst_align: u32, // 1 for x86, 4 for riscv/arm64/mips + max_inst: u32, // 15 for x86, 4 for riscv (8 for C-pairs), 4 for arm64 } // each arch: x86.TARGET: isa.Target = { … } ``` @@ -323,7 +323,7 @@ Builder names spell out each operand kind separated by underscores ``` inst_none / inst_r / inst_r_r / inst_r_i / inst_r_m / inst_m_r / … emit_none / emit_r / emit_rr / emit_ri / emit_rm / emit_mr / … - # NB: emit_* uses concatenated suffixes (legacy x86 spelling) + # NB: emit_* uses concatenated suffixes (legacy x86 spelling) inst_(…) / emit_(…) # generated typed overloads ``` @@ -339,8 +339,8 @@ decode(data: []u8, relocs: []Relocation, label_defs: ^[dynamic]Label_Definition, errors: ^[dynamic]Error) -> Result print/println/aprint/tprint/bprint/fprint/wprint(+ln)( - instructions: []Instruction, inst_info: []Instruction_Info, - label_defs: []Label_Definition, tokens=nil, options=nil, label_names=nil) + instructions: []Instruction, inst_info: []Instruction_Info, + label_defs: []Label_Definition, tokens=nil, options=nil, label_names=nil) ``` ### Register/label/print helpers @@ -366,18 +366,19 @@ these at compile time → **no runtime cost, real code sharing.** ```odin // isa/pipeline.odin (sketch) encode_stream :: proc( - instructions: []$I, - label_defs: []Label_Definition, - code: []u8, - relocs: ^[dynamic]Relocation, - errors: ^[dynamic]Error, - encode_one: proc(inst: ^I, out: []u8, code_pos: u32, - relocs: ^[dynamic]Relocation, errors: ^[dynamic]Error) -> (n: u32, ok: bool), - resolve := true, base_address: u64 = 0, + instructions: []$I, + label_defs: []Label_Definition, + code: []u8, + relocs: ^[dynamic]Relocation, + errors: ^[dynamic]Error, + encode_one: proc(inst: ^I, out: []u8, code_pos: u32, + relocs: ^[dynamic]Relocation, errors: ^[dynamic]Error) -> (n: u32, ok: bool), + resolve := true, + base_address: u64 = 0, ) -> Result { - // PASS 1: for each inst → record offset, call encode_one, advance - // PASS 1.5: rewrite label_defs inst-index → byte-offset (identical on every arch) - // PASS 2: resolve relocations / patch / spill unresolved (identical on every arch) + // PASS 1: for each inst → record offset, call encode_one, advance + // PASS 1.5: rewrite label_defs inst-index → byte-offset (identical on every arch) + // PASS 2: resolve relocations / patch / spill unresolved (identical on every arch) } ``` diff --git a/core/rexcode/docs/x86_api.md b/core/rexcode/docs/x86_api.md index e61f1490b..b15b3888c 100644 --- a/core/rexcode/docs/x86_api.md +++ b/core/rexcode/docs/x86_api.md @@ -110,16 +110,16 @@ Operand_Kind :: enum u8 { NONE, REGISTER, MEMORY, IMMEDIATE, RELATIVE } ```odin Memory :: bit_field u64 { - base_hw: u8 | 5, - base_ext: bool | 1, - index_hw: u8 | 5, - index_ext: bool | 1, - scale_enc: u8 | 2, - displacement: i32 | 32, - segment: u8 | 3, - addr_size_override: bool | 1, - base_class: u8 | 5, - index_class: u8 | 5, + base_hw: u8 | 5, + base_ext: bool | 1, + index_hw: u8 | 5, + index_ext: bool | 1, + scale_enc: u8 | 2, + displacement: i32 | 32, + segment: u8 | 3, + addr_size_override: bool | 1, + base_class: u8 | 5, + index_class: u8 | 5, } MEM_BASE_RIP :: 30 MEM_BASE_NONE :: 31 MEM_INDEX_NONE :: 31 ``` @@ -143,25 +143,25 @@ MEM_BASE_RIP :: 30 MEM_BASE_NONE :: 31 MEM_INDEX_NONE :: 31 ```odin Operand :: struct #packed { // 16 bytes - using _: struct #raw_union { - reg: Register, - mem: Memory, - immediate: i64, - relative: i64, // offset or label id - }, - kind: Operand_Kind, - size: u8, // operand size in bytes (1,2,4,8,16,32,64) - flags: Operand_Flags, - _pad: [4]u8, + using _: struct #raw_union { + reg: Register, + mem: Memory, + immediate: i64, + relative: i64, // offset or label id + }, + kind: Operand_Kind, + size: u8, // operand size in bytes (1,2,4,8,16,32,64) + flags: Operand_Flags, + _: [4]u8, } Broadcast :: enum u8 { NONE, B1TO2, B1TO4, B1TO8, B1TO16 } // EVEX Operand_Flags :: bit_field u16 { // EVEX-specific - mask: u8 | 3, // opmask K1–K7 - zeroing: bool | 1, // merge vs zero masking - broadcast: Broadcast | 3, - er_sae: u8 | 2, // embedded rounding / SAE + mask: u8 | 3, // opmask K1–K7 + zeroing: bool | 1, // merge vs zero masking + broadcast: Broadcast | 3, + er_sae: u8 | 2, // embedded rounding / SAE } ``` @@ -189,12 +189,12 @@ Instruction_Flags :: bit_field u8 { } Instruction :: struct #packed { // 72 bytes - ops: [4]Operand, - mnemonic: Mnemonic, - operand_count: u8, - flags: Instruction_Flags, - length: u8, // filled by decoder - _pad: [3]u8, + ops: [4]Operand, + mnemonic: Mnemonic, + operand_count: u8, + flags: Instruction_Flags, + length: u8, // filled by decoder + _: [3]u8, } ``` @@ -278,16 +278,16 @@ These describe **how** an instruction is encoded; they are the schema of ```odin Operand_Type :: enum u8 { // ~70 values - NONE, R8,R16,R32,R64, RM8,RM16,RM32,RM64, M,M8..M512, - IMM8,IMM16,IMM32,IMM64, IMM8SX, REL8,REL32, - AL_IMPL,AX_IMPL,EAX_IMPL,RAX_IMPL,CL_IMPL,DX_IMPL,ONE_IMPL, - SREG, CR, DR, XMM,YMM,ZMM, XMM_M32,XMM_M64,XMM_M128,YMM_M256,ZMM_M512, - MM,MM_M64, ST0_IMPL,STI, XMM0_IMPL, K,K_M8..K_M64, - MOFFS8..MOFFS64, PTR16_16,PTR16_32,PTR16_64, M16_16,M16_32,M16_64, + NONE, R8,R16,R32,R64, RM8,RM16,RM32,RM64, M,M8..M512, + IMM8,IMM16,IMM32,IMM64, IMM8SX, REL8,REL32, + AL_IMPL,AX_IMPL,EAX_IMPL,RAX_IMPL,CL_IMPL,DX_IMPL,ONE_IMPL, + SREG, CR, DR, XMM,YMM,ZMM, XMM_M32,XMM_M64,XMM_M128,YMM_M256,ZMM_M512, + MM,MM_M64, ST0_IMPL,STI, XMM0_IMPL, K,K_M8..K_M64, + MOFFS8..MOFFS64, PTR16_16,PTR16_32,PTR16_64, M16_16,M16_32,M16_64, } Operand_Encoding :: enum u8 { // where an operand's bits go - NONE, MR, REG, VVVV, OP_R, IB,IW,ID,IQ, IMPL, IS4, AAA, + NONE, MR, REG, VVVV, OP_R, IB,IW,ID,IQ, IMPL, IS4, AAA, } Escape :: enum u8 { NONE, _0F, _0F38, _0F3A } @@ -296,14 +296,26 @@ VEX_W :: enum u8 { WIG, W0, W1 } VEX_L :: enum u8 { LIG, L0, L1, L2 } Encoding_Flags :: bit_field u16 { - esc: Escape|2, prefix: u8|2, vex_type: VEX_Type|2, vex_w: VEX_W|2, - vex_l: VEX_L|2, default_64: bool|1, force_rex_w: bool|1, no_rex: bool|1, - lock_ok: bool|1, rep_ok: bool|1, modrm_reg_ext: bool|1, + esc: Escape | 2, + prefix: u8 | 2, + vex_type: VEX_Type | 2, + vex_w: VEX_W | 2, + vex_l: VEX_L | 2, + default_64: bool | 1, + force_rex_w: bool | 1, + no_rex: bool | 1, + lock_ok: bool | 1, + rep_ok: bool | 1, + modrm_reg_ext: bool | 1, } Encoding :: struct #packed { // 14 bytes — one encoding form - mnemonic: Mnemonic, ops: [4]Operand_Type, enc: [4]Operand_Encoding, - opcode: u8, ext: u8, flags: Encoding_Flags, + mnemonic: Mnemonic, + ops: [4]Operand_Type, + enc: [4]Operand_Encoding, + opcode: u8, + ext: u8, + flags: Encoding_Flags, } PREFIX_66 :: 1 PREFIX_F3 :: 2 PREFIX_F2 :: 3 ``` @@ -314,19 +326,19 @@ Helper: `encoding_flags(esc=…, prefix=…, …) -> Encoding_Flags`. ```odin Relocation_Type :: enum u8 { NONE, REL8, REL32, ABS32, ABS64 } Relocation :: struct #packed { // 16 bytes (ELF-rela-like) - offset: u32, label_id: u32, addend: i32, - type: Relocation_Type, size: u8, inst_idx: u16, + offset: u32, label_id: u32, addend: i32, + type: Relocation_Type, size: u8, inst_idx: u16, } Error_Code :: enum u8 { - NONE, - // encode - INVALID_MNEMONIC, NO_MATCHING_ENCODING, OPERAND_MISMATCH, - IMMEDIATE_OUT_OF_RANGE, BUFFER_OVERFLOW, LABEL_OUT_OF_RANGE, - INVALID_OPERAND_COUNT, - // decode - BUFFER_TOO_SHORT, INVALID_OPCODE, INVALID_MODRM, INVALID_SIB, - INVALID_PREFIX, INVALID_VEX, INVALID_EVEX, TOO_MANY_PREFIXES, + NONE, + // encode + INVALID_MNEMONIC, NO_MATCHING_ENCODING, OPERAND_MISMATCH, + IMMEDIATE_OUT_OF_RANGE, BUFFER_OVERFLOW, LABEL_OUT_OF_RANGE, + INVALID_OPERAND_COUNT, + // decode + BUFFER_TOO_SHORT, INVALID_OPCODE, INVALID_MODRM, INVALID_SIB, + INVALID_PREFIX, INVALID_VEX, INVALID_EVEX, TOO_MANY_PREFIXES, } Error :: struct #packed { inst_idx: u32, code: Error_Code, _pad: [3]u8 } // 8 bytes Result :: struct { byte_count: u32, success: bool } @@ -341,13 +353,13 @@ Helper: `op_type_to_size(Operand_Type) -> u8`. MAX_INST_SIZE :: 15 encode :: proc( - instructions: []Instruction, - label_defs: []Label_Definition, // in: inst index; MODIFIED to byte offsets - code: []u8, // output machine code - relocs: ^[dynamic]Relocation, // unresolved relocations appended - errors: ^[dynamic]Error, - resolve: bool = true, // patch resolvable relocs in place - base_address: u64 = 0, // for ABS relocations + instructions: []Instruction, + label_defs: []Label_Definition, // in: inst index; MODIFIED to byte offsets + code: []u8, // output machine code + relocs: ^[dynamic]Relocation, // unresolved relocations appended + errors: ^[dynamic]Error, + resolve: bool = true, // patch resolvable relocs in place + base_address: u64 = 0, // for ABS relocations ) -> Result ``` @@ -371,19 +383,19 @@ Internal matcher (file-local, inlined): `encoding_matches_inline`, ```odin Instruction_Info :: struct { // parallel metadata, one per decoded inst - offset: u32, - rex: u8, has_lock: bool, rep: Rep, segment: Register, - vex_type: VEX_Type, vex_l: VEX_L, vex_w: VEX_W, - evex_b: bool, evex_z: bool, opmask: u8, + offset: u32, + rex: u8, has_lock: bool, rep: Rep, segment: Register, + vex_type: VEX_Type, vex_l: VEX_L, vex_w: VEX_W, + evex_b: bool, evex_z: bool, opmask: u8, } decode :: proc( - data: []u8, - relocs: []Relocation, // optional in: name labels - instructions: ^[dynamic]Instruction, // out - inst_info: ^[dynamic]Instruction_Info, // out (parallel) - label_defs: ^[dynamic]Label_Definition, // out: inferred branch labels - errors: ^[dynamic]Error, + data: []u8, + relocs: []Relocation, // optional in: name labels + instructions: ^[dynamic]Instruction, // out + inst_info: ^[dynamic]Instruction_Info, // out (parallel) + label_defs: ^[dynamic]Label_Definition, // out: inferred branch labels + errors: ^[dynamic]Error, ) -> Result ``` @@ -406,15 +418,15 @@ Modified Intel syntax: size suffix on the mnemonic (`.b .w .d .q .x .y ```odin Token_Kind :: enum u8 { WHITESPACE, NEWLINE, LABEL_DEF, LABEL_REF, OFFSET, - MNEMONIC, REGISTER, IMMEDIATE, MEMORY_BRACKET, MEMORY_OPERATOR, - MEMORY_DISP, MEMORY_SCALE, PUNCTUATION, COMMENT } + MNEMONIC, REGISTER, IMMEDIATE, MEMORY_BRACKET, MEMORY_OPERATOR, + MEMORY_DISP, MEMORY_SCALE, PUNCTUATION, COMMENT } Token :: struct { offset: u32, length: u16, kind: Token_Kind, instruction_index: u16 } Print_Options :: struct { - uppercase: bool, hex_prefix: string, hex_lowercase: bool, - label_prefix: string, show_offsets: bool, indent: string, - separator: string, space_after_comma: bool, + uppercase: bool, hex_prefix: string, hex_lowercase: bool, + label_prefix: string, show_offsets: bool, indent: string, + separator: string, space_after_comma: bool, } DEFAULT_PRINT_OPTIONS :: Print_Options{ … } diff --git a/core/rexcode/x86/decoder.odin b/core/rexcode/x86/decoder.odin index df38f03db..ca63b12c9 100644 --- a/core/rexcode/x86/decoder.odin +++ b/core/rexcode/x86/decoder.odin @@ -22,21 +22,21 @@ import "../isa" // part of the core Instruction struct. For batch decoding, this is stored // in a parallel array at the same index as the corresponding Instruction. Instruction_Info :: struct { - offset: u32, // Byte offset from start of decoded region + offset: u32, // Byte offset from start of decoded region // Prefix info - rex: u8, // REX byte (0 if none) + rex: u8, // REX byte (0 if none) has_lock: bool, - rep: Rep, // Rep prefix (uses same enum as Instruction_Flags) - segment: Register, // Segment override (NONE if none) + rep: Rep, // Rep prefix (uses same enum as Instruction_Flags) + segment: Register, // Segment override (NONE if none) // VEX/EVEX info vex_type: VEX_Type, - vex_l: VEX_L, - vex_w: VEX_W, - evex_b: bool, // EVEX broadcast - evex_z: bool, // EVEX zeroing - opmask: u8, // EVEX opmask register (k0-k7) + vex_l: VEX_L, + vex_w: VEX_W, + evex_b: bool, // EVEX broadcast + evex_z: bool, // EVEX zeroing + opmask: u8, // EVEX opmask register (k0-k7) } @@ -46,39 +46,39 @@ Instruction_Info :: struct { // ----------------------------------------------------------------------------- Decoder_State :: struct { - data: []u8, // Input bytes - position: int, // Current position - mode: Mode, // CPU mode (._64 = long mode, ._32 = i386) + data: []u8, // Input bytes + position: int, // Current position + mode: Mode, // CPU mode (._64 = long mode, ._32 = i386) // Decoded prefix state - rex: u8, - prefix_66: bool, - prefix_f2: bool, - prefix_f3: bool, - prefix_67: bool, // Address size override - segment: Register, - has_lock: bool, + rex: u8, + prefix_66: bool, + prefix_f2: bool, + prefix_f3: bool, + prefix_67: bool, // Address size override + segment: Register, + has_lock: bool, // +r opcode encoding opcode_reg: u8, // Register encoded in low 3 bits of opcode // VEX/EVEX state - vex_type: VEX_Type, - vex_r: bool, // VEX.R (inverted) - vex_x: bool, // VEX.X (inverted) - vex_b: bool, // VEX.B (inverted) - vex_w: bool, // VEX.W - vex_l: u8, // VEX.L (0, 1, or 2 for EVEX) - vex_vvvv: u8, // VEX.vvvv register - vex_pp: u8, // VEX.pp (implied prefix) - vex_mmmmm: u8, // VEX.mmmmm (implied escape) + vex_type: VEX_Type, + vex_r: bool, // VEX.R (inverted) + vex_x: bool, // VEX.X (inverted) + vex_b: bool, // VEX.B (inverted) + vex_w: bool, // VEX.W + vex_l: u8, // VEX.L (0, 1, or 2 for EVEX) + vex_vvvv: u8, // VEX.vvvv register + vex_pp: u8, // VEX.pp (implied prefix) + vex_mmmmm: u8, // VEX.mmmmm (implied escape) // EVEX specific - evex_r2: bool, // EVEX.R' - evex_v2: bool, // EVEX.V' - evex_z: bool, // EVEX.z (zeroing) - evex_b: bool, // EVEX.b (broadcast/rc/sae) - evex_aaa: u8, // EVEX.aaa (opmask) + evex_r2: bool, // EVEX.R' + evex_v2: bool, // EVEX.V' + evex_z: bool, // EVEX.z (zeroing) + evex_b: bool, // EVEX.b (broadcast/rc/sae) + evex_aaa: u8, // EVEX.aaa (opmask) } @@ -114,6 +114,7 @@ PREFIX_TYPE_TABLE := [256]u8{ } // Segment register lookup for prefix types 4-9 +@(rodata) PREFIX_SEGMENT_TABLE := [6]Register{ES, CS, SS, DS, FS, GS} decode_prefixes :: #force_inline proc(state: ^Decoder_State) -> Error_Code { @@ -186,15 +187,15 @@ decode_vex2 :: #force_inline proc(state: ^Decoder_State) -> Error_Code { b1 := state.data[state.position + 1] state.position += 2 - state.vex_type = .VEX - state.vex_r = (b1 & 0x80) == 0 // true = extend (bit was 0) - state.vex_x = false // Implied 1 in 2-byte VEX = no extend - state.vex_b = false // Implied 1 in 2-byte VEX = no extend - state.vex_vvvv = (b1 >> 3) & 0x0F - state.vex_l = (b1 >> 2) & 0x01 - state.vex_pp = b1 & 0x03 - state.vex_mmmmm = 1 // Implied 0F escape - state.vex_w = false // Implied 0 in 2-byte VEX + state.vex_type = .VEX + state.vex_r = (b1 & 0x80) == 0 // true = extend (bit was 0) + state.vex_x = false // Implied 1 in 2-byte VEX = no extend + state.vex_b = false // Implied 1 in 2-byte VEX = no extend + state.vex_vvvv = (b1 >> 3) & 0x0F + state.vex_l = (b1 >> 2) & 0x01 + state.vex_pp = b1 & 0x03 + state.vex_mmmmm = 1 // Implied 0F escape + state.vex_w = false // Implied 0 in 2-byte VEX return .NONE } @@ -205,20 +206,20 @@ decode_vex3 :: #force_inline proc(state: ^Decoder_State) -> Error_Code { } data := state.data - pos := state.position - b1 := data[pos + 1] - b2 := data[pos + 2] + pos := state.position + b1 := data[pos + 1] + b2 := data[pos + 2] state.position = pos + 3 - state.vex_type = .VEX - state.vex_r = (b1 & 0x80) == 0 // Inverted - state.vex_x = (b1 & 0x40) == 0 // Inverted - state.vex_b = (b1 & 0x20) == 0 // Inverted - state.vex_mmmmm = b1 & 0x1F - state.vex_w = (b2 & 0x80) != 0 - state.vex_vvvv = (b2 >> 3) & 0x0F - state.vex_l = (b2 >> 2) & 0x01 - state.vex_pp = b2 & 0x03 + state.vex_type = .VEX + state.vex_r = (b1 & 0x80) == 0 // Inverted + state.vex_x = (b1 & 0x40) == 0 // Inverted + state.vex_b = (b1 & 0x20) == 0 // Inverted + state.vex_mmmmm = b1 & 0x1F + state.vex_w = (b2 & 0x80) != 0 + state.vex_vvvv = (b2 >> 3) & 0x0F + state.vex_l = (b2 >> 2) & 0x01 + state.vex_pp = b2 & 0x03 return .NONE } @@ -237,20 +238,20 @@ decode_evex :: #force_inline proc(state: ^Decoder_State) -> Error_Code { state.vex_type = .EVEX // Byte 1: R, X, B, R', 0, 0, m, m - state.vex_r = (b1 & 0x80) == 0 // Inverted - state.vex_x = (b1 & 0x40) == 0 // Inverted - state.vex_b = (b1 & 0x20) == 0 // Inverted - state.evex_r2 = (b1 & 0x10) == 0 // Inverted (R') - state.vex_mmmmm = b1 & 0x03 + state.vex_r = (b1 & 0x80) == 0 // Inverted + state.vex_x = (b1 & 0x40) == 0 // Inverted + state.vex_b = (b1 & 0x20) == 0 // Inverted + state.evex_r2 = (b1 & 0x10) == 0 // Inverted (R') + state.vex_mmmmm = b1 & 0x03 // Byte 2: W, v, v, v, v, 1, p, p - state.vex_w = (b2 & 0x80) != 0 + state.vex_w = (b2 & 0x80) != 0 state.vex_vvvv = (b2 >> 3) & 0x0F - state.vex_pp = b2 & 0x03 + state.vex_pp = b2 & 0x03 // Byte 3: z, L', L, b, V', a, a, a - state.evex_z = (b3 & 0x80) != 0 - state.vex_l = ((b3 >> 5) & 0x03) // L'L combined - state.evex_b = (b3 & 0x10) != 0 - state.evex_v2 = (b3 & 0x08) == 0 // Inverted (V') + state.evex_z = (b3 & 0x80) != 0 + state.vex_l = ((b3 >> 5) & 0x03) // L'L combined + state.evex_b = (b3 & 0x10) != 0 + state.evex_v2 = (b3 & 0x08) == 0 // Inverted (V') state.evex_aaa = b3 & 0x07 return .NONE @@ -572,7 +573,7 @@ decode_operands :: proc(state: ^Decoder_State, entry: ^Decode_Entry) -> (inst: I // Check if we need ModR/M needs_modrm := false - for i in 0..<4 { + for _, i in entry.enc { enc := entry.enc[i] if enc == .MR || enc == .REG || enc == .VVVV { needs_modrm = true @@ -614,7 +615,7 @@ decode_operands :: proc(state: ^Decoder_State, entry: ^Decode_Entry) -> (inst: I } // Decode each operand - for i in 0..<4 { + for _, i in entry.ops { op_type := entry.ops[i] op_enc := entry.enc[i] @@ -626,7 +627,7 @@ decode_operands :: proc(state: ^Decoder_State, entry: ^Decode_Entry) -> (inst: I // really mean R32/RM32 in 32-bit mode (same encoded bytes). effective := mode_rewrite_op_type(op_type, state.mode, entry.flags.default_64) inst.ops[i], err = decode_single_operand(state, effective, op_enc, modrm_info, sib_info, has_sib) - if err != .NONE { + if err != nil { return {}, err } inst.operand_count += 1 @@ -661,7 +662,7 @@ decode_operands_vex :: proc(state: ^Decoder_State, entry: ^VEX_Decode_Entry) -> } // Decode each operand - for i in 0..<4 { + for _, i in entry.ops { op_type := entry.ops[i] op_enc := entry.enc[i] @@ -670,7 +671,7 @@ decode_operands_vex :: proc(state: ^Decoder_State, entry: ^VEX_Decode_Entry) -> } inst.ops[i], err = decode_single_operand_vex(state, op_type, op_enc, modrm_info, sib_info, has_sib) - if err != .NONE { + if err != nil { return {}, err } inst.operand_count += 1 @@ -1058,7 +1059,7 @@ decode :: proc( // Phase 1: Parse prefixes err := decode_prefixes(&state) - if err != .NONE { + if err != nil { append(errors, Error{inst_idx = u32(len(instructions)), code = err}) has_errors = true break @@ -1102,7 +1103,7 @@ decode :: proc( entry: ^Decode_Entry vex_entry: ^VEX_Decode_Entry entry, vex_entry, err = decode_opcode(&state) - if err != .NONE { + if err != nil { append(errors, Error{inst_idx = u32(len(instructions)), code = err}) has_errors = true break @@ -1118,7 +1119,7 @@ decode :: proc( has_errors = true break } - if err != .NONE { + if err != nil { append(errors, Error{inst_idx = u32(len(instructions)), code = err}) has_errors = true break diff --git a/core/rexcode/x86/tests/test.odin b/core/rexcode/x86/tests/test.odin index 5b6e9d4f6..94432ef06 100644 --- a/core/rexcode/x86/tests/test.odin +++ b/core/rexcode/x86/tests/test.odin @@ -313,9 +313,7 @@ run_test :: proc(t: Test) -> bool { // Make mutable copy of labels labels_copy: [256]x86.Label_Definition - for i in 0.. bool { defer free_exec(exec_buf) // Copy code - for i in 0.. bool { } // Verify mnemonics - for i in 0..