From c9ce8794c77cf8d3795364053cd2b0bb22a9d35c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 15 Jun 2026 21:43:58 +0100 Subject: [PATCH] Replace `-> isa.Result` with `-> (byte_code: u32, ok: bool)` --- core/rexcode/arm32/decoder.odin | 26 +-- core/rexcode/arm32/encoder.odin | 27 +-- core/rexcode/arm32/encoding_types.odin | 1 - core/rexcode/arm32/tests/pipeline.odin | 22 +-- core/rexcode/arm32/tests/sweep.odin | 4 +- core/rexcode/arm64/decoder.odin | 20 +- core/rexcode/arm64/encoder.odin | 18 +- core/rexcode/arm64/encoding_types.odin | 1 - core/rexcode/arm64/tests/pipeline_smoke.odin | 184 +++++++++--------- core/rexcode/isa/status.odin | 4 - core/rexcode/mips/decoder.odin | 20 +- core/rexcode/mips/encoder.odin | 20 +- core/rexcode/mips/encoding_types.odin | 1 - core/rexcode/mips/tests/decode_smoke.odin | 54 ++--- core/rexcode/mips/tests/encode_smoke.odin | 42 ++-- core/rexcode/mips/tests/print_smoke.odin | 16 +- core/rexcode/mos6502/decoder.odin | 18 +- core/rexcode/mos6502/encoder.odin | 31 ++- core/rexcode/mos6502/encoding_types.odin | 1 - .../rexcode/mos6502/tests/pipeline_smoke.odin | 42 ++-- core/rexcode/mos65816/decoder.odin | 18 +- core/rexcode/mos65816/encoder.odin | 27 ++- core/rexcode/mos65816/encoding_types.odin | 1 - core/rexcode/mos65816/tests/smoke.odin | 30 +-- core/rexcode/ppc/decoder.odin | 26 +-- core/rexcode/ppc/encoder.odin | 20 +- core/rexcode/ppc/encoding_types.odin | 1 - core/rexcode/ppc/tests/branch_reloc.odin | 8 +- core/rexcode/ppc/tests/decode_sweep.odin | 4 +- core/rexcode/ppc/tests/full_sweep.odin | 18 +- core/rexcode/ppc/tests/roundtrip.odin | 12 +- core/rexcode/ppc_vle/decoder.odin | 28 +-- core/rexcode/ppc_vle/encoder.odin | 19 +- core/rexcode/ppc_vle/encoding_types.odin | 1 - core/rexcode/ppc_vle/tests/branch_test.odin | 24 +-- core/rexcode/ppc_vle/tests/cond_branch.odin | 14 +- core/rexcode/ppc_vle/tests/e2e.odin | 14 +- core/rexcode/ppc_vle/tests/extension.odin | 8 +- core/rexcode/ppc_vle/tests/full_sweep.odin | 18 +- core/rexcode/ppc_vle/tests/operand_test.odin | 8 +- core/rexcode/ppc_vle/tests/roundtrip.odin | 12 +- core/rexcode/riscv/decoder.odin | 24 +-- core/rexcode/riscv/encoder.odin | 22 +-- core/rexcode/riscv/encoding_types.odin | 1 - core/rexcode/riscv/tests/pipeline_smoke.odin | 86 ++++---- core/rexcode/rsp/decoder.odin | 20 +- core/rexcode/rsp/encoder.odin | 20 +- core/rexcode/rsp/encoding_types.odin | 1 - core/rexcode/rsp/tests/pipeline_smoke.odin | 46 ++--- core/rexcode/x86/decoder.odin | 40 ++-- core/rexcode/x86/encoder.odin | 36 ++-- core/rexcode/x86/encoding_types.odin | 1 - core/rexcode/x86/tests/test.odin | 31 ++- 53 files changed, 580 insertions(+), 611 deletions(-) diff --git a/core/rexcode/arm32/decoder.odin b/core/rexcode/arm32/decoder.odin index 9ee267889..ebc739157 100644 --- a/core/rexcode/arm32/decoder.odin +++ b/core/rexcode/arm32/decoder.odin @@ -40,7 +40,7 @@ decode :: proc( label_defs: ^[dynamic]Label_Definition, errors: ^[dynamic]Error, mode: Mode = .A32, -) -> Result { +) -> (byte_count: u32, ok: bool) { n_bytes := u32(len(data)) if mode == .T32 { n_bytes = n_bytes & ~u32(1) } else { n_bytes = n_bytes & ~u32(3) } @@ -50,21 +50,20 @@ decode :: proc( pending_branches: [dynamic]isa.Branch_Target defer delete(pending_branches) - pc: u32 = 0 - for pc < n_bytes { + for byte_count < n_bytes { word: u32 ilen: u32 = 4 if mode == .A32 { - if pc + 4 > n_bytes { break } - word = read_u32_le(data, pc) + if byte_count + 4 > n_bytes { break } + word = read_u32_le(data, byte_count) } else { // T32: 16 or 32 bit - hword_hi := read_u16_le(data, pc) + hword_hi := read_u16_le(data, byte_count) top5 := (hword_hi >> 11) & 0x1F if top5 == 0x1D || top5 == 0x1E || top5 == 0x1F { - if pc + 4 > n_bytes { break } - hword_lo := read_u16_le(data, pc + 2) + if byte_count + 4 > n_bytes { break } + hword_lo := read_u16_le(data, byte_count + 2) // Pack: bits = low_halfword | (high_halfword << 16) word = u32(hword_lo) | (u32(hword_hi) << 16) ilen = 4 @@ -76,10 +75,10 @@ decode :: proc( inst: Instruction info: Instruction_Info - info.offset = pc + info.offset = byte_count if !find_and_decode(word, mode, ilen, &inst, &info) { - append(errors, Error{inst_idx = pc, code = .INVALID_OPCODE}) + append(errors, Error{inst_idx = byte_count, code = .INVALID_OPCODE}) inst = Instruction{mnemonic = .INVALID, length = u8(ilen), mode = mode} } else { inst.length = u8(ilen) @@ -103,11 +102,12 @@ decode :: proc( append(instructions, inst) append(inst_info, info) - pc += ilen + byte_count += ilen } - isa.infer_labels_from_branches(pending_branches[:], pc, label_defs, relocs) - return Result{byte_count = pc, success = u32(len(errors)) == errors_start} + isa.infer_labels_from_branches(pending_branches[:], byte_count, label_defs, relocs) + ok = u32(len(errors)) == errors_start + return } // ============================================================================= diff --git a/core/rexcode/arm32/encoder.odin b/core/rexcode/arm32/encoder.odin index 94dcf851b..031f7337d 100644 --- a/core/rexcode/arm32/encoder.odin +++ b/core/rexcode/arm32/encoder.odin @@ -34,38 +34,37 @@ encode :: proc( errors: ^[dynamic]Error, resolve: bool = true, base_address: u64 = 0, -) -> Result { +) -> (byte_count: u32, ok: bool) { n_inst := len(instructions) if len(code) < n_inst * 4 { append(errors, Error{inst_idx = 0, code = .BUFFER_OVERFLOW}) - return Result{byte_count = 0, success = false} + return } errors_start := u32(len(errors)) pending_start := u32(len(relocs)) - pc: u32 = 0 inst_pc := make([]u32, n_inst, context.temp_allocator) // ---- PASS 1 ------------------------------------------------------------ for i in 0..> 16)) - write_u16_le(code, pc + 2, u16(word)) + write_u16_le(code, byte_count, u16(word >> 16)) + write_u16_le(code, byte_count + 2, u16(word)) } else { - write_u32_le(code, pc, word) + write_u32_le(code, byte_count, word) } } - pc += u32(ilen) + byte_count += u32(ilen) } // ---- PASS 1.5: label_def instruction-idx -> byte-offset ----------------- @@ -81,7 +80,8 @@ encode :: proc( } if !resolve { - return Result{byte_count = pc, success = u32(len(errors)) == errors_start} + ok = u32(len(errors)) == errors_start + return } // ---- PASS 2: resolve relocations ---------------------------------------- @@ -97,7 +97,8 @@ encode :: proc( } if write_idx != n_relocs { resize(relocs, int(write_idx)) } - return Result{byte_count = pc, success = u32(len(errors)) == errors_start} + ok = u32(len(errors)) == errors_start + return } // ============================================================================= diff --git a/core/rexcode/arm32/encoding_types.odin b/core/rexcode/arm32/encoding_types.odin index f8614cb88..cb0e89784 100644 --- a/core/rexcode/arm32/encoding_types.odin +++ b/core/rexcode/arm32/encoding_types.odin @@ -51,7 +51,6 @@ import "../isa" // All operand-driven fields live in the zeros of `mask`; the encoder ORs // them in. The matcher tests `(word & mask) == bits`. -Result :: isa.Result Error :: isa.Error Error_Code :: isa.Error_Code Label_Definition :: isa.Label_Definition diff --git a/core/rexcode/arm32/tests/pipeline.odin b/core/rexcode/arm32/tests/pipeline.odin index a83b1fa68..d1373f2e0 100644 --- a/core/rexcode/arm32/tests/pipeline.odin +++ b/core/rexcode/arm32/tests/pipeline.odin @@ -21,14 +21,14 @@ check_bytes :: proc(name: string, inst: a.Instruction, want: []u8) { errors: [dynamic]a.Error defer { delete(label_defs); delete(code); delete(relocs); delete(errors) } - res := a.encode(insts, label_defs[:], code, &relocs, &errors) - if !res.success { + byte_count, success := a.encode(insts, label_defs[:], code, &relocs, &errors) + if !success { fmt.printf(" [FAIL] %s: encode failed (errors=%d)\n", name, len(errors)) fail += 1 return } - if int(res.byte_count) != len(want) { - fmt.printf(" [FAIL] %s: got %d bytes, want %d\n", name, res.byte_count, len(want)) + if int(byte_count) != len(want) { + fmt.printf(" [FAIL] %s: got %d bytes, want %d\n", name, byte_count, len(want)) fail += 1 return } @@ -55,9 +55,9 @@ check_decode :: proc(name: string, bytes: []u8, want_mn: a.Mnemonic, mode: a.Mod labels: [dynamic]a.Label_Definition errors: [dynamic]a.Error defer { delete(insts); delete(info); delete(labels); delete(errors) } - res := a.decode(bytes, relocs, &insts, &info, &labels, &errors, mode) - if !res.success || len(insts) == 0 { - fmt.printf(" [FAIL] decode %s: success=%v len=%d\n", name, res.success, len(insts)) + byte_count, success := a.decode(bytes, relocs, &insts, &info, &labels, &errors, mode) + if !success || len(insts) == 0 { + fmt.printf(" [FAIL] decode %s: success=%v len=%d\n", name, success, len(insts)) fail += 1 return } @@ -160,8 +160,8 @@ check_roundtrip :: proc(name: string, inst: a.Instruction) { errors: [dynamic]a.Error defer { delete(label_defs); delete(code); delete(relocs); delete(errors) } - res := a.encode(insts, label_defs[:], code, &relocs, &errors) - if !res.success { + byte_count, success := a.encode(insts, label_defs[:], code, &relocs, &errors) + if !success { fmt.printf(" [FAIL] roundtrip %s: encode failed\n", name) fail += 1 return @@ -174,8 +174,8 @@ check_roundtrip :: proc(name: string, inst: a.Instruction) { dec_err: [dynamic]a.Error defer { delete(decoded); delete(info); delete(labels); delete(dec_err) } - dec_res := a.decode(code[:res.byte_count], dec_relocs, &decoded, &info, &labels, &dec_err, inst.mode) - if !dec_res.success || len(decoded) == 0 { + dec_byte_count, dec_success := a.decode(code[:byte_count], dec_relocs, &decoded, &info, &labels, &dec_err, inst.mode) + if !dec_success || len(decoded) == 0 { fmt.printf(" [FAIL] roundtrip %s: decode failed\n", name) fail += 1 return diff --git a/core/rexcode/arm32/tests/sweep.odin b/core/rexcode/arm32/tests/sweep.odin index cc52a971e..884410fcb 100644 --- a/core/rexcode/arm32/tests/sweep.odin +++ b/core/rexcode/arm32/tests/sweep.odin @@ -113,8 +113,8 @@ run_sweep_tests :: proc() { ren_errors: [dynamic]a.Error out: [4]u8 defer { delete(ren_relocs); delete(ren_errors) } - res := a.encode(insts[:], label_defs[:], out[:], &ren_relocs, &ren_errors, resolve=false) - if !res.success { + byte_count, success := a.encode(insts[:], label_defs[:], out[:], &ren_relocs, &ren_errors, resolve=false) + if !success { stats.fail_encode += 1 if failed_examples < max_fail_print && (only_print_kind == "" || only_print_kind == "re-enc") { fmt.printf(" [re-enc ] %v[%d] %08X re-encode failed\n", mn, idx, word) diff --git a/core/rexcode/arm64/decoder.odin b/core/rexcode/arm64/decoder.odin index 86992aa09..697ed2b4e 100644 --- a/core/rexcode/arm64/decoder.odin +++ b/core/rexcode/arm64/decoder.odin @@ -36,25 +36,24 @@ decode :: proc( label_defs: ^[dynamic]Label_Definition, errors: ^[dynamic]Error, endianness: Endianness = .LITTLE, -) -> Result { +) -> (byte_count: u32, ok: bool) { n_bytes := u32(len(data)) & ~u32(3) errors_start := u32(len(errors)) pending_branches: [dynamic]isa.Branch_Target defer delete(pending_branches) - pc: u32 = 0 - for pc < n_bytes { - word := read_u32(data, pc, endianness) + for byte_count < n_bytes { + word := read_u32(data, byte_count, endianness) inst: Instruction info: Instruction_Info - entry_idx := decode_one_inline(word, pc, &inst, &info) + entry_idx := decode_one_inline(word, byte_count, &inst, &info) if entry_idx < 0 { - append(errors, Error{inst_idx = pc, code = .INVALID_OPCODE}) + append(errors, Error{inst_idx = byte_count, code = .INVALID_OPCODE}) inst = Instruction{mnemonic = .INVALID, length = 4} - info = Instruction_Info{offset = pc} + info = Instruction_Info{offset = byte_count} } else { inst_idx_for_branches := u32(len(instructions)) for slot in 0.. Result { +) -> (byte_count: u32, ok: bool) { n_inst := u32(len(instructions)) if u32(len(code)) < n_inst * 4 { append(errors, Error{inst_idx = 0, code = .BUFFER_OVERFLOW}) - return Result{byte_count = 0, success = false} + return } errors_start := u32(len(errors)) pending_start := u32(len(relocs)) - pc: u32 = 0 // ---- PASS 1 ----------------------------------------------------------- for i in 0.. *4 ------------------------------------- @@ -71,7 +69,8 @@ encode :: proc( } if !resolve { - return Result{byte_count = pc, success = u32(len(errors)) == errors_start} + ok = u32(len(errors)) == errors_start + return } // ---- PASS 2: resolve relocations ------------------------------------- @@ -87,7 +86,8 @@ encode :: proc( } if write_idx != n_relocs { resize(relocs, int(write_idx)) } - return Result{byte_count = pc, success = u32(len(errors)) == errors_start} + ok = u32(len(errors)) == errors_start + return } // ============================================================================= diff --git a/core/rexcode/arm64/encoding_types.odin b/core/rexcode/arm64/encoding_types.odin index 9f575f34d..a1fc646df 100644 --- a/core/rexcode/arm64/encoding_types.odin +++ b/core/rexcode/arm64/encoding_types.odin @@ -37,7 +37,6 @@ import "../isa" // option 13-15 extend type (data-proc extended register, LDR/STR EXT) // imm3 10-12 extend amount -Result :: isa.Result Error :: isa.Error Error_Code :: isa.Error_Code Label_Definition :: isa.Label_Definition diff --git a/core/rexcode/arm64/tests/pipeline_smoke.odin b/core/rexcode/arm64/tests/pipeline_smoke.odin index 432539ad1..0e43529d3 100644 --- a/core/rexcode/arm64/tests/pipeline_smoke.odin +++ b/core/rexcode/arm64/tests/pipeline_smoke.odin @@ -78,8 +78,8 @@ run_pipeline_tests :: proc() { insts := []a.Instruction{ a.inst_r_r_i(.ADD_IMM, a.X0, a.X1, 100), } - r := a.encode(insts, nil, code[:], &relocs, &errors) - ok("ADD_IMM: encode", r.success) + byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors) + ok("ADD_IMM: encode", success) eq_word("ADD X0,X1,#100", load_le(code[:], 0), 0x91019020) } @@ -92,8 +92,8 @@ run_pipeline_tests :: proc() { clear(&relocs); clear(&errors) for i in 0..= 1 && d_insts[0].mnemonic == .AMX_SET) ok("AMX: LDX", len(d_insts) >= 2 && d_insts[1].mnemonic == .AMX_LDX) @@ -651,9 +651,9 @@ run_pipeline_tests :: proc() { isa.label_set_at(&labels, fwd, &insts) // .L1: at instruction 4 append(&insts, a.inst_none(.RET)) // [4] byte 16: RET - r := a.encode(insts[:], labels[:], code[:], &relocs, &errors) - ok("anon labels: encode", r.success) - ok("anon labels: byte_count = 20", r.byte_count == 20) + byte_count, success := a.encode(insts[:], labels[:], code[:], &relocs, &errors) + ok("anon labels: encode", success) + ok("anon labels: byte_count = 20", byte_count == 20) // B.LT at byte 8 -> .L1 at byte 16: offset = +8 = +2 words. // bits = 0x54000000 | (2<<5) | LT(0xB) = 0x5400004B @@ -670,7 +670,7 @@ run_pipeline_tests :: proc() { d_labels: [dynamic]a.Label_Definition defer delete(d_insts); defer delete(d_info); defer delete(d_labels) clear(&errors) - a.decode(code[:r.byte_count], nil, &d_insts, &d_info, &d_labels, &errors) + a.decode(code[:byte_count], nil, &d_insts, &d_info, &d_labels, &errors) ok("anon labels: decode 5 insts", len(d_insts) == 5) have_back, have_fwd: bool for ld in d_labels { @@ -713,8 +713,8 @@ run_pipeline_tests :: proc() { ops = {a.op_reg(a.X3), a.op_imm(a.DCZID_EL0, 2), {}, {}}, }, } - r := a.encode(insts, nil, code[:], &relocs, &errors) - ok("sysreg: encode", r.success) + byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors) + ok("sysreg: encode", success) eq_word("MRS X0,NZCV", load_le(code[:], 0), 0xD53B4200) eq_word("MRS X1,TPIDR_EL0", load_le(code[:], 4), 0xD53BD041) eq_word("MRS X2,CNTVCT_EL0", load_le(code[:], 8), 0xD53BE042) @@ -729,8 +729,8 @@ run_pipeline_tests :: proc() { insts := []a.Instruction{ a.inst_r(.DC_ZVA, a.X0), } - r := a.encode(insts, nil, code[:], &relocs, &errors) - ok("DC ZVA: encode", r.success) + byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors) + ok("DC ZVA: encode", success) eq_word("DC ZVA X0", load_le(code[:], 0), 0xD50B7420) d_insts: [dynamic]a.Instruction @@ -738,7 +738,7 @@ run_pipeline_tests :: proc() { d_labels: [dynamic]a.Label_Definition defer delete(d_insts); defer delete(d_info); defer delete(d_labels) clear(&errors) - a.decode(code[:r.byte_count], nil, &d_insts, &d_info, &d_labels, &errors) + a.decode(code[:byte_count], nil, &d_insts, &d_info, &d_labels, &errors) ok("DC ZVA: decode", len(d_insts) == 1 && d_insts[0].mnemonic == .DC_ZVA) ok("DC ZVA: Rt = X0", len(d_insts) == 1 && d_insts[0].ops[0].reg == a.X0) } @@ -756,8 +756,8 @@ run_pipeline_tests :: proc() { ops = {a.op_reg(a.X0), a.op_shifted(a.X1, .LSL, 0), {}, {}}, }, } - r := a.encode(insts, nil, code[:], &relocs, &errors) - ok("CMP_SR: encode", r.success) + byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors) + ok("CMP_SR: encode", success) eq_word("CMP X0,X1", load_le(code[:], 0), 0xEB01001F) } @@ -786,8 +786,8 @@ run_pipeline_tests :: proc() { ops = {a.op_reg(a.X0), a.op_reg(a.X1), a.op_reg(a.X2), {}}, }, } - r := a.encode(insts, nil, code[:], &relocs, &errors) - ok("MOPS CPY: encode", r.success) + byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors) + ok("MOPS CPY: encode", success) eq_word("CPYP X0,X1,X2", load_le(code[:], 0), 0x1D020420) eq_word("CPYM X0,X1,X2", load_le(code[:], 4), 0x1D420420) eq_word("CPYE X0,X1,X2", load_le(code[:], 8), 0x1D820420) @@ -808,8 +808,8 @@ run_pipeline_tests :: proc() { ops = {a.op_z_s(0), a.op_z_s(1), a.op_z_s(2), a.op_imm(2, 1)}, }, } - r := a.encode(insts, nil, code[:], &relocs, &errors) - ok("SVE FMLA indexed: encode", r.success) + byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors) + ok("SVE FMLA indexed: encode", success) eq_word("SVE FMLA Z0.S, Z1.S, Z2.S[2]", load_le(code[:], 0), 0x64B20020) } @@ -835,8 +835,8 @@ run_pipeline_tests :: proc() { ops = {a.op_z_s(0), a.op_reg(p0), a.op_mem(mem), {}}, }, } - r := a.encode(insts, nil, code[:], &relocs, &errors) - ok("SVE LD1W gather: encode", r.success) + byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors) + ok("SVE LD1W gather: encode", success) eq_word("SVE LD1W Z0.S,P0/Z,[X1,Z2.S,UXTW]", load_le(code[:], 0), 0x85024020) } @@ -864,8 +864,8 @@ run_pipeline_tests :: proc() { ops = {a.op_imm(slice_packed, 2), a.op_reg(p5), a.op_mem(mem), {}}, }, } - r := a.encode(insts, nil, code[:], &relocs, &errors) - ok("SME LD1B tile vs LLVM: encode", r.success) + byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors) + ok("SME LD1B tile vs LLVM: encode", success) eq_word("SME LD1B ZA0V.B[W14,5],P5/Z,[X10,X21]", load_le(code[:], 0), 0xE015D545) d_insts: [dynamic]a.Instruction @@ -873,7 +873,7 @@ run_pipeline_tests :: proc() { d_labels: [dynamic]a.Label_Definition defer delete(d_insts); defer delete(d_info); defer delete(d_labels) clear(&errors) - a.decode(code[:r.byte_count], nil, &d_insts, &d_info, &d_labels, &errors) + a.decode(code[:byte_count], nil, &d_insts, &d_info, &d_labels, &errors) ok("SME LD1B tile: decode 1 inst", len(d_insts) == 1) ok("SME LD1B tile: mnemonic", len(d_insts) == 1 && d_insts[0].mnemonic == .SME_LD1B_TILE) ok("SME LD1B tile: slice roundtrip", @@ -891,8 +891,8 @@ run_pipeline_tests :: proc() { ops = {a.op_v_4s(0), a.op_v_4s(1), a.op_v_4s(2), a.op_imm(0, 1)}, }, } - r := a.encode(insts, nil, code[:], &relocs, &errors) - ok("FCMLA: encode", r.success) + byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors) + ok("FCMLA: encode", success) eq_word("FCMLA V0.4S,V1.4S,V2.4S,#0", load_le(code[:], 0), 0x6E82C420) } @@ -908,8 +908,8 @@ run_pipeline_tests :: proc() { a.inst_none(.TCOMMIT), a.inst_r(.TTEST, a.X1), } - r := a.encode(insts, nil, code[:], &relocs, &errors) - ok("TME: encode", r.success) + byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors) + ok("TME: encode", success) eq_word("TSTART X0", load_le(code[:], 0), 0xD5233060) eq_word("TCOMMIT", load_le(code[:], 4), 0xD503307F) eq_word("TTEST X1", load_le(code[:], 8), 0xD5233161) @@ -925,8 +925,8 @@ run_pipeline_tests :: proc() { a.inst_r_r(.UXTB, a.W0, a.W1), a.inst_r_r(.SXTW, a.X0, a.W1), } - r := a.encode(insts, nil, code[:], &relocs, &errors) - ok("extend aliases: encode", r.success) + byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors) + ok("extend aliases: encode", success) eq_word("UXTB W0,W1", load_le(code[:], 0), 0x53001C20) eq_word("SXTW X0,W1", load_le(code[:], 4), 0x93407C20) } @@ -942,8 +942,8 @@ run_pipeline_tests :: proc() { a.inst_r_r_r(.ADC, a.X0, a.X1, a.X2), a.inst_r_r_r(.SBCS, a.X3, a.X4, a.X5), } - r := a.encode(insts, nil, code[:], &relocs, &errors) - ok("ADC/SBCS: encode", r.success) + byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors) + ok("ADC/SBCS: encode", success) eq_word("ADC X0,X1,X2", load_le(code[:], 0), 0x9A020020) eq_word("SBCS X3,X4,X5", load_le(code[:], 4), 0xFA050083) } @@ -961,8 +961,8 @@ run_pipeline_tests :: proc() { ops = {a.op_reg(a.X7), a.op_imm(a.RNDR, 2), {}, {}}, }, } - r := a.encode(insts, nil, code[:], &relocs, &errors) - ok("MRS X7,RNDR: encode", r.success) + byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors) + ok("MRS X7,RNDR: encode", success) eq_word("MRS X7,RNDR", load_le(code[:], 0), 0xD53B2407) } @@ -979,8 +979,8 @@ run_pipeline_tests :: proc() { a.inst_ldst(.LDAPUR, a.X0, a.mem_offset(a.X1, 8)), a.inst_ldst(.STLUR, a.X2, a.mem_offset(a.SP, -8)), } - r := a.encode(insts, nil, code[:], &relocs, &errors) - ok("RCpc unscaled: encode", r.success) + byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors) + ok("RCpc unscaled: encode", success) eq_word("LDAPUR X0,[X1,#8]", load_le(code[:], 0), 0xD9408020) eq_word("STLUR X2,[SP,#-8]", load_le(code[:], 4), 0xD91F83E2) } @@ -994,8 +994,8 @@ run_pipeline_tests :: proc() { a.inst_none(.BTI_J), a.inst_none(.PSB_CSYNC), } - r := a.encode(insts, nil, code[:], &relocs, &errors) - ok("barriers/BTI: encode", r.success) + byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors) + ok("barriers/BTI: encode", success) eq_word("SB", load_le(code[:], 0), 0xD50330FF) eq_word("BTI j", load_le(code[:], 4), 0xD503245F) eq_word("PSB CSYNC", load_le(code[:], 8), 0xD503223F) @@ -1011,8 +1011,8 @@ run_pipeline_tests :: proc() { insts := []a.Instruction{ a.inst_r_r_i(.LSL_IMM, a.W0, a.W1, 4), } - r := a.encode(insts, nil, code[:], &relocs, &errors) - ok("LSL_IMM 32: encode", r.success) + byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors) + ok("LSL_IMM 32: encode", success) eq_word("LSL W0,W1,#4", load_le(code[:], 0), 0x531C6C20) } @@ -1026,8 +1026,8 @@ run_pipeline_tests :: proc() { insts := []a.Instruction{ a.inst_r_r_i(.ROR_IMM, a.W0, a.W1, 4), } - r := a.encode(insts, nil, code[:], &relocs, &errors) - ok("ROR_IMM 32: encode", r.success) + byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors) + ok("ROR_IMM 32: encode", success) eq_word("ROR W0,W1,#4", load_le(code[:], 0), 0x13811020) } diff --git a/core/rexcode/isa/status.odin b/core/rexcode/isa/status.odin index 9ccff1663..35ece81e0 100644 --- a/core/rexcode/isa/status.odin +++ b/core/rexcode/isa/status.odin @@ -43,7 +43,3 @@ Error :: struct #packed { } #assert(size_of(Error) == 8) -Result :: struct { - byte_count: u32, // Bytes written/read - success: bool, // True if no errors -} diff --git a/core/rexcode/mips/decoder.odin b/core/rexcode/mips/decoder.odin index 3210a512d..22b0e83cd 100644 --- a/core/rexcode/mips/decoder.odin +++ b/core/rexcode/mips/decoder.odin @@ -57,7 +57,7 @@ decode :: proc( label_defs: ^[dynamic]Label_Definition, errors: ^[dynamic]Error, endianness: Endianness = .BIG, -) -> Result { +) -> (byte_count: u32, ok: bool) { n_bytes := u32(len(data)) if n_bytes & 3 != 0 { n_bytes &= ~u32(3) // ignore the dangling tail @@ -68,18 +68,17 @@ decode :: proc( defer delete(pending_branches) // ---- PASS 1 ----------------------------------------------------------- - pc: u32 = 0 - for pc < n_bytes { - word := read_u32(data, pc, endianness) + for byte_count < n_bytes { + word := read_u32(data, byte_count, endianness) inst: Instruction info: Instruction_Info - entry_idx := decode_one_inline(word, pc, &inst, &info) + entry_idx := decode_one_inline(word, byte_count, &inst, &info) if entry_idx < 0 { - append(errors, Error{inst_idx = pc, code = .INVALID_OPCODE}) + append(errors, Error{inst_idx = byte_count, code = .INVALID_OPCODE}) inst = Instruction{mnemonic = .INVALID, length = 4} - info = Instruction_Info{offset = pc} + info = Instruction_Info{offset = byte_count} } else { inst_idx_for_branches := u32(len(instructions)) for slot in 0.. Result { +) -> (byte_count: u32, ok: bool) { n_inst := u32(len(instructions)) if u32(len(code)) < n_inst * 4 { append(errors, Error{inst_idx = 0, code = .BUFFER_OVERFLOW}) - return Result{byte_count = 0, success = false} + return } errors_start := u32(len(errors)) pending_start := u32(len(relocs)) - pc: u32 = 0 // ---- PASS 1 ------------------------------------------------------------ for i in 0.. 0 && errors[0].code == .BUFFER_OVERFLOW, @@ -300,9 +300,9 @@ run_encoder_tests :: proc() { insts := []mips.Instruction{ mips.inst_r_r_r(.ADD_S, mips.F4, mips.F5, mips.F6), } - res := mips.encode(insts, nil, code[:], &relocs, &errors) + byte_count, success := mips.encode(insts, nil, code[:], &relocs, &errors) - check_bool("FPU: success", res.success, true) + check_bool("FPU: success", success, true) check_word("FPU: ADD.S", load_word_be(code[:], 0), 0x46062900) } @@ -316,9 +316,9 @@ run_encoder_tests :: proc() { insts := []mips.Instruction{ mips.inst_none(.RTPS), } - res := mips.encode(insts, nil, code[:], &relocs, &errors) + byte_count, success := mips.encode(insts, nil, code[:], &relocs, &errors) - check_bool("GTE: success", res.success, true) + check_bool("GTE: success", success, true) check_word("GTE: RTPS", load_word_be(code[:], 0), 0x4A000001) } diff --git a/core/rexcode/mips/tests/print_smoke.odin b/core/rexcode/mips/tests/print_smoke.odin index f346a38c6..336ae5fbb 100644 --- a/core/rexcode/mips/tests/print_smoke.odin +++ b/core/rexcode/mips/tests/print_smoke.odin @@ -38,8 +38,8 @@ encode_and_print :: proc( defer delete(relocs) defer delete(errors) - eres := mips.encode(insts, label_defs, code[:], &relocs, &errors) - if !eres.success { return "" } + byte_count, esuccess := mips.encode(insts, label_defs, code[:], &relocs, &errors) + if !esuccess { return "" } dec_insts: [dynamic]mips.Instruction dec_info: [dynamic]mips.Instruction_Info @@ -49,9 +49,9 @@ encode_and_print :: proc( defer delete(dec_labels) clear(&errors) - dres := mips.decode(code[:eres.byte_count], nil, + _, dsuccess := mips.decode(code[:byte_count], nil, &dec_insts, &dec_info, &dec_labels, &errors) - if !dres.success { return "" } + if !dsuccess { return "" } sb := strings.builder_make(context.temp_allocator) mips.sbprint(&sb, dec_insts[:], dec_info[:], dec_labels[:]) @@ -162,7 +162,7 @@ run_printer_tests :: proc() { mips.inst_none(.NOP), mips.inst_branch2(.BEQ, mips.T0, mips.T1, 0), } - eres := mips.encode(insts, ld[:], code[:], &relocs, &errors) + byte_count, _ := mips.encode(insts, ld[:], code[:], &relocs, &errors) dec_insts: [dynamic]mips.Instruction dec_info: [dynamic]mips.Instruction_Info @@ -171,7 +171,7 @@ run_printer_tests :: proc() { defer delete(dec_info) defer delete(dec_labels) clear(&errors) - mips.decode(code[:eres.byte_count], nil, &dec_insts, &dec_info, &dec_labels, &errors) + mips.decode(code[:byte_count], nil, &dec_insts, &dec_info, &dec_labels, &errors) names: map[u32]string defer delete(names) @@ -197,7 +197,7 @@ run_printer_tests :: proc() { errors: [dynamic]mips.Error defer delete(relocs) defer delete(errors) - eres := mips.encode(insts, nil, code[:], &relocs, &errors) + byte_count, _ := mips.encode(insts, nil, code[:], &relocs, &errors) dec_insts: [dynamic]mips.Instruction dec_info: [dynamic]mips.Instruction_Info @@ -206,7 +206,7 @@ run_printer_tests :: proc() { defer delete(dec_info) defer delete(dec_labels) clear(&errors) - mips.decode(code[:eres.byte_count], nil, &dec_insts, &dec_info, &dec_labels, &errors) + mips.decode(code[:byte_count], nil, &dec_insts, &dec_info, &dec_labels, &errors) out := mips.aprint(dec_insts[:], dec_info[:], dec_labels[:], nil, &opts, nil, context.temp_allocator) diff --git a/core/rexcode/mos6502/decoder.odin b/core/rexcode/mos6502/decoder.odin index 4e1327fe2..96515419d 100644 --- a/core/rexcode/mos6502/decoder.odin +++ b/core/rexcode/mos6502/decoder.odin @@ -44,23 +44,22 @@ decode :: proc( label_defs: ^[dynamic]Label_Definition, errors: ^[dynamic]Error, cpu: CPU = .NMOS, -) -> Result { +) -> (byte_count: u32, ok: bool) { n_bytes := u32(len(data)) errors_start := u32(len(errors)) pending_branches: [dynamic]isa.Branch_Target defer delete(pending_branches) - pc: u32 = 0 - for pc < n_bytes { + for byte_count < n_bytes { inst: Instruction info: Instruction_Info - entry_idx, consumed := decode_one_inline(data, pc, n_bytes, cpu, &inst, &info) + entry_idx, consumed := decode_one_inline(data, byte_count, n_bytes, cpu, &inst, &info) if entry_idx < 0 { - append(errors, Error{inst_idx = pc, code = .INVALID_OPCODE}) + append(errors, Error{inst_idx = byte_count, code = .INVALID_OPCODE}) inst = Instruction{mnemonic = .INVALID, length = 1} - info = Instruction_Info{offset = pc} + info = Instruction_Info{offset = byte_count} consumed = 1 } else { inst_idx_for_branches := u32(len(instructions)) @@ -78,11 +77,12 @@ decode :: proc( append(instructions, inst) append(inst_info, info) - pc += consumed + byte_count += consumed } - isa.infer_labels_from_branches(pending_branches[:], pc, label_defs, relocs) - return Result{byte_count = pc, success = u32(len(errors)) == errors_start} + isa.infer_labels_from_branches(pending_branches[:], byte_count, label_defs, relocs) + ok = u32(len(errors)) == errors_start + return } // ============================================================================= diff --git a/core/rexcode/mos6502/encoder.odin b/core/rexcode/mos6502/encoder.odin index b8cd3deec..57f7ca31e 100644 --- a/core/rexcode/mos6502/encoder.odin +++ b/core/rexcode/mos6502/encoder.odin @@ -48,47 +48,43 @@ encode :: proc( errors: ^[dynamic]Error, resolve: bool = true, base_address: u64 = 0, -) -> Result { +) -> (byte_count: u32, ok: bool) { n_inst := u32(len(instructions)) errors_start := u32(len(errors)) pending_start := u32(len(relocs)) inst_offsets := make([]u32, n_inst, context.temp_allocator) - pc: u32 = 0 - // ---- PASS 1 ----------------------------------------------------------- for i in 0.. u32(len(code)) { + if byte_count + u32(form.length) > u32(len(code)) { append(errors, Error{inst_idx = i, code = .BUFFER_OVERFLOW}) - return Result{byte_count = pc, success = false} + return } // Opcode byte - code[pc] = form.opcode + code[byte_count] = form.opcode // Operand bytes - if form.enc[0] != .NONE { pack_operand_inline(&inst.ops[0], form.enc[0], pc, u16(i), code, relocs) } - if form.enc[1] != .NONE { pack_operand_inline(&inst.ops[1], form.enc[1], pc, u16(i), code, relocs) } - if form.enc[2] != .NONE { pack_operand_inline(&inst.ops[2], form.enc[2], pc, u16(i), code, relocs) } + if form.enc[0] != .NONE { pack_operand_inline(&inst.ops[0], form.enc[0], byte_count, u16(i), code, relocs) } + if form.enc[1] != .NONE { pack_operand_inline(&inst.ops[1], form.enc[1], byte_count, u16(i), code, relocs) } + if form.enc[2] != .NONE { pack_operand_inline(&inst.ops[2], form.enc[2], byte_count, u16(i), code, relocs) } inst.length = form.length - pc += u32(form.length) + byte_count += u32(form.length) } // ---- PASS 1.5: inst-index -> byte-offset ----------------------------- isa.rewrite_label_defs_to_offsets(label_defs, inst_offsets) if !resolve { - return Result{byte_count = pc, success = u32(len(errors)) == errors_start} + ok = u32(len(errors)) == errors_start + return } // ---- PASS 2: resolve relocations -------------------------------------- @@ -108,7 +104,8 @@ encode :: proc( resize(relocs, int(write_idx)) } - return Result{byte_count = pc, success = u32(len(errors)) == errors_start} + ok = u32(len(errors)) == errors_start + return } // ============================================================================= diff --git a/core/rexcode/mos6502/encoding_types.odin b/core/rexcode/mos6502/encoding_types.odin index 504185655..334333bb0 100644 --- a/core/rexcode/mos6502/encoding_types.odin +++ b/core/rexcode/mos6502/encoding_types.odin @@ -27,7 +27,6 @@ import "../isa" // 65C816 (SNES, Apple IIgs) is a separate 16/24-bit ISA and lives in a // sibling subpackage if/when added. -Result :: isa.Result Error :: isa.Error Error_Code :: isa.Error_Code Label_Definition :: isa.Label_Definition diff --git a/core/rexcode/mos6502/tests/pipeline_smoke.odin b/core/rexcode/mos6502/tests/pipeline_smoke.odin index 7e8b13e82..573a2b0fc 100644 --- a/core/rexcode/mos6502/tests/pipeline_smoke.odin +++ b/core/rexcode/mos6502/tests/pipeline_smoke.odin @@ -69,8 +69,8 @@ encode_one :: proc(insts: []m.Instruction) -> ([]u8, bool) { @(static) errors: [dynamic]m.Error clear(&relocs); clear(&errors) for i in 0..= 1 && d_insts[0].mnemonic == .TII) ok("huc tii: 3 operands", d_insts[0].operand_count == 3) @@ -321,7 +321,7 @@ encode_or_fail :: proc(insts: []m.Instruction) -> []u8 { @(static) errors: [dynamic]m.Error clear(&relocs); clear(&errors) for i in 0.. Result { +) -> (byte_count: u32, ok: bool) { n_bytes := u32(len(data)) errors_start := u32(len(errors)) @@ -44,16 +44,15 @@ decode :: proc( eff := state if eff.e { eff.m = true; eff.x = true } - pc: u32 = 0 - for pc < n_bytes { + for byte_count < n_bytes { inst: Instruction info: Instruction_Info - entry_idx, consumed := decode_one_inline(data, pc, n_bytes, eff, &inst, &info) + entry_idx, consumed := decode_one_inline(data, byte_count, n_bytes, eff, &inst, &info) if entry_idx < 0 { - append(errors, Error{inst_idx = pc, code = .INVALID_OPCODE}) + append(errors, Error{inst_idx = byte_count, code = .INVALID_OPCODE}) inst = Instruction{mnemonic = .INVALID, length = 1} - info = Instruction_Info{offset = pc} + info = Instruction_Info{offset = byte_count} consumed = 1 } else { inst_idx_for_branches := u32(len(instructions)) @@ -71,11 +70,12 @@ decode :: proc( append(instructions, inst) append(inst_info, info) - pc += consumed + byte_count += consumed } - isa.infer_labels_from_branches(pending_branches[:], pc, label_defs, relocs) - return Result{byte_count = pc, success = u32(len(errors)) == errors_start} + isa.infer_labels_from_branches(pending_branches[:], byte_count, label_defs, relocs) + ok = u32(len(errors)) == errors_start + return } // ============================================================================= diff --git a/core/rexcode/mos65816/encoder.odin b/core/rexcode/mos65816/encoder.odin index 70379d8af..fb7b2dbbd 100644 --- a/core/rexcode/mos65816/encoder.odin +++ b/core/rexcode/mos65816/encoder.odin @@ -40,38 +40,36 @@ encode :: proc( errors: ^[dynamic]Error, resolve: bool = true, base_address: u64 = 0, -) -> Result { +) -> (byte_count: u32, ok: bool) { n_inst := u32(len(instructions)) errors_start := u32(len(errors)) pending_start := u32(len(relocs)) inst_offsets := make([]u32, n_inst, context.temp_allocator) - pc: u32 = 0 - for i in 0.. u32(len(code)) { + if byte_count + u32(form.length) > u32(len(code)) { append(errors, Error{inst_idx = i, code = .BUFFER_OVERFLOW}) - return Result{byte_count = pc, success = false} + return } - code[pc] = form.opcode - if form.enc[0] != .NONE { pack_operand_inline(&inst.ops[0], form.enc[0], pc, u16(i), code, relocs) } - if form.enc[1] != .NONE { pack_operand_inline(&inst.ops[1], form.enc[1], pc, u16(i), code, relocs) } + code[byte_count] = form.opcode + if form.enc[0] != .NONE { pack_operand_inline(&inst.ops[0], form.enc[0], byte_count, u16(i), code, relocs) } + if form.enc[1] != .NONE { pack_operand_inline(&inst.ops[1], form.enc[1], byte_count, u16(i), code, relocs) } inst.length = form.length - pc += u32(form.length) + byte_count += u32(form.length) } isa.rewrite_label_defs_to_offsets(label_defs, inst_offsets) if !resolve { - return Result{byte_count = pc, success = u32(len(errors)) == errors_start} + ok = u32(len(errors)) == errors_start + return } n_relocs := u32(len(relocs)) @@ -90,7 +88,8 @@ encode :: proc( resize(relocs, int(write_idx)) } - return Result{byte_count = pc, success = u32(len(errors)) == errors_start} + ok = u32(len(errors)) == errors_start + return } // ============================================================================= diff --git a/core/rexcode/mos65816/encoding_types.odin b/core/rexcode/mos65816/encoding_types.odin index 37cd7b24e..a2bc957a1 100644 --- a/core/rexcode/mos65816/encoding_types.odin +++ b/core/rexcode/mos65816/encoding_types.odin @@ -30,7 +30,6 @@ import "../isa" // passes `e=true` in Assumed_State so the decoder picks the 8-bit immediate // forms. -Result :: isa.Result Error :: isa.Error Error_Code :: isa.Error_Code Label_Definition :: isa.Label_Definition diff --git a/core/rexcode/mos65816/tests/smoke.odin b/core/rexcode/mos65816/tests/smoke.odin index 706b7b8cd..7926a1e8c 100644 --- a/core/rexcode/mos65816/tests/smoke.odin +++ b/core/rexcode/mos65816/tests/smoke.odin @@ -68,9 +68,9 @@ enc :: proc(insts: []m.Instruction) -> []u8 { @(static) errors: [dynamic]m.Error clear(&relocs); clear(&errors) for i in 0.. decode in 16-bit native, print --------- @@ -186,18 +186,18 @@ main :: proc() { m.inst_m(.STA, m.mem_long(0x7E1000)), // 4 bytes m.inst_rel(.BRA, 0), // 2 bytes back to loop } - r := m.encode(src, ld[:], code[:], &relocs, &errors) - ok("rt: encode ok", r.success) + byte_count, success := m.encode(src, ld[:], code[:], &relocs, &errors) + ok("rt: encode ok", success) d_insts: [dynamic]m.Instruction d_info: [dynamic]m.Instruction_Info d_labels: [dynamic]m.Label_Definition defer delete(d_insts); defer delete(d_info); defer delete(d_labels) clear(&errors) - d := m.decode(code[:r.byte_count], nil, + _, dsuccess := m.decode(code[:byte_count], nil, &d_insts, &d_info, &d_labels, &errors, state = m.NATIVE_16) - ok("rt: decode ok", d.success) + ok("rt: decode ok", dsuccess) ok("rt: 3 insts", len(d_insts) == 3) ok("rt: LDA", d_insts[0].mnemonic == .LDA) ok("rt: STA", d_insts[1].mnemonic == .STA) @@ -261,14 +261,14 @@ main :: proc() { m.inst_m(.JML, m.mem_abs_ind_long(0xFFFC)), m.inst_m(.LDA, m.mem_sr_ind_y(0x10)), } - r := m.encode(src, nil, code[:], &relocs, &errors) + byte_count, success := m.encode(src, nil, code[:], &relocs, &errors) d_insts: [dynamic]m.Instruction d_info: [dynamic]m.Instruction_Info d_labels: [dynamic]m.Label_Definition defer delete(d_insts); defer delete(d_info); defer delete(d_labels) clear(&errors) - m.decode(code[:r.byte_count], nil, &d_insts, &d_info, &d_labels, &errors, + m.decode(code[:byte_count], nil, &d_insts, &d_info, &d_labels, &errors, state = m.NATIVE_16) text := m.aprint(d_insts[:], d_info[:], d_labels[:], diff --git a/core/rexcode/ppc/decoder.odin b/core/rexcode/ppc/decoder.odin index f0996f241..10f960e52 100644 --- a/core/rexcode/ppc/decoder.odin +++ b/core/rexcode/ppc/decoder.odin @@ -34,36 +34,35 @@ decode :: proc( label_defs: ^[dynamic]Label_Definition, errors: ^[dynamic]Error, mode: Mode = .PPC32, -) -> Result { +) -> (byte_count: u32, ok: bool) { n_bytes := u32(len(data)) & ~u32(3) errors_start := u32(len(errors)) pending_branches: [dynamic]isa.Branch_Target defer delete(pending_branches) - pc: u32 = 0 - for pc < n_bytes { - if pc + 4 > n_bytes { break } - word := read_u32_be(data, pc) + for byte_count < n_bytes { + if byte_count + 4 > n_bytes { break } + word := read_u32_be(data, byte_count) // Detect prefixed instruction: primary opcode = 1. is_prefixed := (word >> 26) == 0x01 ilen: u32 = 4 suffix: u32 = 0 if is_prefixed { - if pc + 8 > n_bytes { break } - suffix = read_u32_be(data, pc + 4) + if byte_count + 8 > n_bytes { break } + suffix = read_u32_be(data, byte_count + 4) ilen = 8 } inst: Instruction info: Instruction_Info - info.offset = pc + info.offset = byte_count match_word := is_prefixed ? suffix : word prefix_word := is_prefixed ? word : 0 if !find_and_decode(match_word, prefix_word, is_prefixed, mode, &inst, &info) { - append(errors, Error{inst_idx = pc, code = .INVALID_OPCODE}) + append(errors, Error{inst_idx = byte_count, code = .INVALID_OPCODE}) inst = Instruction{mnemonic = .INVALID, length = u8(ilen), mode = mode} } else { inst.length = u8(ilen) @@ -74,7 +73,7 @@ decode :: proc( if op.kind == .RELATIVE && op.relative >= 0 { // The unpacker stores PC-relative byte offsets; convert // to absolute target = pc + relative. - target := u32(i32(pc) + i32(op.relative)) + target := u32(i32(byte_count) + i32(op.relative)) append(&pending_branches, isa.Branch_Target{ inst_idx = inst_idx, op_idx = slot, @@ -86,11 +85,12 @@ decode :: proc( append(instructions, inst) append(inst_info, info) - pc += ilen + byte_count += ilen } - isa.infer_labels_from_branches(pending_branches[:], pc, label_defs, relocs) - return Result{byte_count = pc, success = u32(len(errors)) == errors_start} + isa.infer_labels_from_branches(pending_branches[:], byte_count, label_defs, relocs) + ok = u32(len(errors)) == errors_start + return } // ============================================================================= diff --git a/core/rexcode/ppc/encoder.odin b/core/rexcode/ppc/encoder.odin index 583e89dd9..3ae82df23 100644 --- a/core/rexcode/ppc/encoder.odin +++ b/core/rexcode/ppc/encoder.odin @@ -34,28 +34,24 @@ encode :: proc( errors: ^[dynamic]Error, resolve: bool = true, base_address: u64 = 0, -) -> Result { +) -> (byte_count: u32, ok: bool) { n_inst := u32(len(instructions)) if u32(len(code)) < n_inst * MAX_INST_SIZE { append(errors, Error{inst_idx = 0, code = .BUFFER_OVERFLOW}) - return Result{byte_count = 0, success = false} + return } errors_start := u32(len(errors)) pending_start := u32(len(relocs)) - pc: u32 = 0 inst_pc := make([]u32, n_inst, context.temp_allocator) // ---- PASS 1 ------------------------------------------------------------ for i in 0.. byte offset -------------------- @@ -71,7 +67,8 @@ encode :: proc( } if !resolve { - return Result{byte_count = pc, success = u32(len(errors)) == errors_start} + ok = u32(len(errors)) == errors_start + return } // ---- PASS 2: resolve relocations --------------------------------------- @@ -87,7 +84,8 @@ encode :: proc( } if write_idx != n_relocs { resize(relocs, int(write_idx)) } - return Result{byte_count = pc, success = u32(len(errors)) == errors_start} + ok = u32(len(errors)) == errors_start + return } // ============================================================================= diff --git a/core/rexcode/ppc/encoding_types.odin b/core/rexcode/ppc/encoding_types.odin index a654dd10a..c1cf03dfe 100644 --- a/core/rexcode/ppc/encoding_types.odin +++ b/core/rexcode/ppc/encoding_types.odin @@ -67,7 +67,6 @@ import "../isa" // XX4-form vsx 4-op (xxsel) -- + XT + XA + XB + XC + XO + CX + AX + BX + TX // MLS / MMIRR / 8RR / 8LS prefixed (ISA 3.1) -- 8-byte (4 prefix + 4 suffix) -Result :: isa.Result Error :: isa.Error Error_Code :: isa.Error_Code Label_Definition :: isa.Label_Definition diff --git a/core/rexcode/ppc/tests/branch_reloc.odin b/core/rexcode/ppc/tests/branch_reloc.odin index f04137d03..9bf991f33 100644 --- a/core/rexcode/ppc/tests/branch_reloc.odin +++ b/core/rexcode/ppc/tests/branch_reloc.odin @@ -16,15 +16,15 @@ check :: proc(name: string, instructions: []p.Instruction, label_defs: []isa.Lab errors: [dynamic]p.Error defer delete(relocs); defer delete(errors) - r := p.encode(instructions, label_defs, code, &relocs, &errors) - if !r.success { + byte_count, success := p.encode(instructions, label_defs, code, &relocs, &errors) + if !success { fmt.printf(" [FAIL] %s: encode failed, %d errors\n", name, len(errors)) for e in errors { fmt.printf(" code=%v inst_idx=%d\n", e.code, e.inst_idx) } fail += 1 return } - if int(r.byte_count) != len(want_bytes) { - fmt.printf(" [FAIL] %s: wrong byte count (got %d, want %d)\n", name, r.byte_count, len(want_bytes)) + if int(byte_count) != len(want_bytes) { + fmt.printf(" [FAIL] %s: wrong byte count (got %d, want %d)\n", name, byte_count, len(want_bytes)) fail += 1 return } diff --git a/core/rexcode/ppc/tests/decode_sweep.odin b/core/rexcode/ppc/tests/decode_sweep.odin index 7a7f2f526..005c3061d 100644 --- a/core/rexcode/ppc/tests/decode_sweep.odin +++ b/core/rexcode/ppc/tests/decode_sweep.odin @@ -47,8 +47,8 @@ run_decode_sweep :: proc() { errors: [dynamic]p.Error defer delete(decoded); defer delete(info); defer delete(labels); defer delete(errors) - r := p.decode(buf[:ilen], nil, &decoded, &info, &labels, &errors, .PPC64) - if !r.success || len(decoded) == 0 || (len(decoded) > 0 && decoded[0].mnemonic == .INVALID) { + byte_count, success := p.decode(buf[:ilen], nil, &decoded, &info, &labels, &errors, .PPC64) + if !success || len(decoded) == 0 || (len(decoded) > 0 && decoded[0].mnemonic == .INVALID) { if missing_mn_total < 20 { fmt.printf(" [UNDECODABLE] %v word=%08x prefixed=%v\n", mn, word, f.flags.prefixed) } diff --git a/core/rexcode/ppc/tests/full_sweep.odin b/core/rexcode/ppc/tests/full_sweep.odin index 455149e92..e73d90437 100644 --- a/core/rexcode/ppc/tests/full_sweep.odin +++ b/core/rexcode/ppc/tests/full_sweep.odin @@ -182,8 +182,8 @@ test_form :: proc(mn: p.Mnemonic, fi: int, f: ^p.Encoding, fails: ^[dynamic]stri instructions := []p.Instruction{inst} label_defs: []isa.Label_Definition - r := p.encode(instructions, label_defs, code, &relocs, &errors) - if !r.success { + byte_count, success := p.encode(instructions, label_defs, code, &relocs, &errors) + if !success { stats.encode_fail += 1 if len(fails) < 100 { append(fails, fmt.aprintf("ENCODE_FAIL %v[%d] errors=%d", mn, fi, len(errors))) } return @@ -196,8 +196,8 @@ test_form :: proc(mn: p.Mnemonic, fi: int, f: ^p.Encoding, fails: ^[dynamic]stri dec_errors: [dynamic]p.Error defer delete(decoded); defer delete(dec_info); defer delete(dec_labels); defer delete(dec_errors) - dr := p.decode(code[:r.byte_count], nil, &decoded, &dec_info, &dec_labels, &dec_errors, f.mode) - if !dr.success || len(decoded) == 0 || decoded[0].mnemonic == .INVALID { + dbyte_count, dsuccess := p.decode(code[:byte_count], nil, &decoded, &dec_info, &dec_labels, &dec_errors, f.mode) + if !dsuccess || len(decoded) == 0 || decoded[0].mnemonic == .INVALID { stats.decode_fail += 1 if len(fails) < 100 { append(fails, fmt.aprintf("DECODE_FAIL %v[%d] bytes=%02x%02x%02x%02x", @@ -213,8 +213,8 @@ test_form :: proc(mn: p.Mnemonic, fi: int, f: ^p.Encoding, fails: ^[dynamic]stri re_errors: [dynamic]p.Error defer delete(re_relocs); defer delete(re_errors) - rr := p.encode(decoded[:], dec_labels[:], code2, &re_relocs, &re_errors) - if !rr.success { + rrbyte_count, rrsuccess := p.encode(decoded[:], dec_labels[:], code2, &re_relocs, &re_errors) + if !rrsuccess { stats.reencode_fail += 1 if len(fails) < 100 { append(fails, fmt.aprintf("REENCODE_FAIL %v[%d] decoded_mn=%v", @@ -223,14 +223,14 @@ test_form :: proc(mn: p.Mnemonic, fi: int, f: ^p.Encoding, fails: ^[dynamic]stri return } - if rr.byte_count != r.byte_count { + if rrbyte_count != byte_count { stats.byte_mismatch += 1 if len(fails) < 100 { - append(fails, fmt.aprintf("LEN_MISMATCH %v[%d] orig=%d re=%d", mn, fi, r.byte_count, rr.byte_count)) + append(fails, fmt.aprintf("LEN_MISMATCH %v[%d] orig=%d re=%d", mn, fi, byte_count, rrbyte_count)) } return } - for i in 0.. Result { +) -> (byte_count: u32, ok: bool) { n_bytes := u32(len(data)) & ~u32(1) errors_start := u32(len(errors)) pending_branches: [dynamic]isa.Branch_Target defer delete(pending_branches) - pc: u32 = 0 - for pc < n_bytes { - if pc + 2 > n_bytes { break } - hw := u32(read_u16_be(data, pc)) + for byte_count < n_bytes { + if byte_count + 2 > n_bytes { break } + hw := u32(read_u16_be(data, byte_count)) inst: Instruction info: Instruction_Info - info.offset = pc + info.offset = byte_count matched := try_decode(hw, true, &inst, &info) ilen: u32 = 2 if !matched { - if pc + 4 > n_bytes { - append(errors, Error{inst_idx = pc, code = .BUFFER_TOO_SHORT}) + if byte_count + 4 > n_bytes { + append(errors, Error{inst_idx = byte_count, code = .BUFFER_TOO_SHORT}) break } - word := (hw << 16) | u32(read_u16_be(data, pc + 2)) + word := (hw << 16) | u32(read_u16_be(data, byte_count + 2)) matched = try_decode(word, false, &inst, &info) ilen = 4 } if !matched { - append(errors, Error{inst_idx = pc, code = .INVALID_OPCODE}) + append(errors, Error{inst_idx = byte_count, code = .INVALID_OPCODE}) inst = Instruction{mnemonic = .INVALID, length = 2, mode = .PPC32_VLE} ilen = 2 } else { @@ -70,7 +69,7 @@ decode :: proc( append(&pending_branches, isa.Branch_Target{ inst_idx = inst_idx, op_idx = slot, - target = u32(i32(pc) + i32(op.relative)), + target = u32(i32(byte_count) + i32(op.relative)), }) } } @@ -78,11 +77,12 @@ decode :: proc( append(instructions, inst) append(inst_info, info) - pc += ilen + byte_count += ilen } - isa.infer_labels_from_branches(pending_branches[:], pc, label_defs, relocs) - return Result{byte_count = pc, success = u32(len(errors)) == errors_start} + isa.infer_labels_from_branches(pending_branches[:], byte_count, label_defs, relocs) + ok = u32(len(errors)) == errors_start + return } @(private="file") diff --git a/core/rexcode/ppc_vle/encoder.odin b/core/rexcode/ppc_vle/encoder.odin index 2869e078a..3c6d0debd 100644 --- a/core/rexcode/ppc_vle/encoder.odin +++ b/core/rexcode/ppc_vle/encoder.odin @@ -25,24 +25,23 @@ encode :: proc( errors: ^[dynamic]Error, resolve: bool = true, base_address: u64 = 0, -) -> Result { +) -> (byte_count: u32, ok: bool) { n_inst := u32(len(instructions)) if u32(len(code)) < n_inst * MAX_INST_SIZE { append(errors, Error{inst_idx = 0, code = .BUFFER_OVERFLOW}) - return Result{byte_count = 0, success = false} + return } errors_start := u32(len(errors)) pending_start := u32(len(relocs)) - pc: u32 = 0 + inst_pc := make([]u32, n_inst, context.temp_allocator) for i in 0.. Result { +) -> (byte_count: u32, ok: bool) { n_bytes := u32(len(data)) & ~u32(1) // align to halfword (RVC is 2-byte) errors_start := u32(len(errors)) pending_branches: [dynamic]isa.Branch_Target defer delete(pending_branches) - pc: u32 = 0 - for pc < n_bytes { + for byte_count < n_bytes { // Read the first halfword; bits[1:0] != 11 means compressed (2 bytes). - hword_lo := read_u16_le(data, pc) + hword_lo := read_u16_le(data, byte_count) ilen: u32 = 4 word: u32 if (hword_lo & 0x3) != 0x3 { ilen = 2 word = u32(hword_lo) } else { - if pc + 4 > n_bytes { break } - word = read_u32_le(data, pc) + if byte_count + 4 > n_bytes { break } + word = read_u32_le(data, byte_count) } inst: Instruction info: Instruction_Info - entry_idx := decode_one_inline(word, pc, xlen, ilen == 2, &inst, &info) + entry_idx := decode_one_inline(word, byte_count, xlen, ilen == 2, &inst, &info) if entry_idx < 0 { - append(errors, Error{inst_idx = pc, code = .INVALID_OPCODE}) + append(errors, Error{inst_idx = byte_count, code = .INVALID_OPCODE}) inst = Instruction{mnemonic = .INVALID, length = u8(ilen)} - info = Instruction_Info{offset = pc} + info = Instruction_Info{offset = byte_count} } else { inst.length = u8(ilen) inst_idx_for_branches := u32(len(instructions)) @@ -89,11 +88,12 @@ decode :: proc( append(instructions, inst) append(inst_info, info) - pc += ilen + byte_count += ilen } - isa.infer_labels_from_branches(pending_branches[:], pc, label_defs, relocs) - return Result{byte_count = pc, success = u32(len(errors)) == errors_start} + isa.infer_labels_from_branches(pending_branches[:], byte_count, label_defs, relocs) + ok = u32(len(errors)) == errors_start + return } // ============================================================================= diff --git a/core/rexcode/riscv/encoder.odin b/core/rexcode/riscv/encoder.odin index f0424d0ce..6ee9cc618 100644 --- a/core/rexcode/riscv/encoder.odin +++ b/core/rexcode/riscv/encoder.odin @@ -41,16 +41,15 @@ encode :: proc( errors: ^[dynamic]Error, resolve: bool = true, base_address: u64 = 0, -) -> Result { +) -> (byte_count: u32, ok: bool) { n_inst := u32(len(instructions)) if u32(len(code)) < n_inst * 4 { append(errors, Error{inst_idx = 0, code = .BUFFER_OVERFLOW}) - return Result{byte_count = 0, success = false} + return } errors_start := u32(len(errors)) pending_start := u32(len(relocs)) - pc: u32 = 0 // Per-instruction byte offsets so label_defs (instruction-indexed) // can be rewritten to byte-offset after pass 1 in the presence of @@ -59,16 +58,15 @@ encode :: proc( // ---- PASS 1 ----------------------------------------------------------- for i in 0.. byte-offset) -- @@ -84,7 +82,8 @@ encode :: proc( } if !resolve { - return Result{byte_count = pc, success = u32(len(errors)) == errors_start} + ok = u32(len(errors)) == errors_start + return } // ---- PASS 2: resolve relocations -------------------------------------- @@ -100,7 +99,8 @@ encode :: proc( } if write_idx != n_relocs { resize(relocs, int(write_idx)) } - return Result{byte_count = pc, success = u32(len(errors)) == errors_start} + ok = u32(len(errors)) == errors_start + return } // ============================================================================= diff --git a/core/rexcode/riscv/encoding_types.odin b/core/rexcode/riscv/encoding_types.odin index bc8f04d24..5b93e3fc8 100644 --- a/core/rexcode/riscv/encoding_types.odin +++ b/core/rexcode/riscv/encoding_types.odin @@ -31,7 +31,6 @@ import "../isa" // pattern, `mask` flags which positions are static. Operand-driven bits // land in the zero positions of `bits`. -Result :: isa.Result Error :: isa.Error Error_Code :: isa.Error_Code Label_Definition :: isa.Label_Definition diff --git a/core/rexcode/riscv/tests/pipeline_smoke.odin b/core/rexcode/riscv/tests/pipeline_smoke.odin index 18434bc58..ba86ba77c 100644 --- a/core/rexcode/riscv/tests/pipeline_smoke.odin +++ b/core/rexcode/riscv/tests/pipeline_smoke.odin @@ -91,8 +91,8 @@ run_pipeline_tests :: proc() { rv.inst_u (.LUI, rv.T0, 0x12345), rv.inst_u (.AUIPC,rv.RA, 0x10), } - r := rv.encode(insts, nil, code[:], &relocs, &errors) - ok("R/I/U: encode ok", r.success) + byte_count, success := rv.encode(insts, nil, code[:], &relocs, &errors) + ok("R/I/U: encode ok", success) eq_word("R: ADD t0,a0,a1", load_le(code[:], 0), 0x00B502B3) eq_word("I: ADDI sp,sp,-16", load_le(code[:], 4), 0xFF010113) eq_word("U: LUI t0,0x12345", load_le(code[:], 8), 0x123452B7) @@ -114,8 +114,8 @@ run_pipeline_tests :: proc() { rv.inst_load (.LW, rv.T0, rv.mem(rv.SP, 100)), rv.inst_store(.SW, rv.A0, rv.mem(rv.SP, -8)), } - r := rv.encode(insts, nil, code[:], &relocs, &errors) - ok("LW/SW: encode ok", r.success) + byte_count, success := rv.encode(insts, nil, code[:], &relocs, &errors) + ok("LW/SW: encode ok", success) eq_word("LW t0,100(sp)", load_le(code[:], 0), 0x06412283) eq_word("SW a0,-8(sp)", load_le(code[:], 4), 0xFEA12C23) } @@ -144,8 +144,8 @@ run_pipeline_tests :: proc() { rv.inst_branch(.BNE, rv.T0, rv.ZERO, 0), rv.inst_r_r_i(.ADDI, rv.ZERO, rv.ZERO, 0), } - r := rv.encode(insts, ld[:], code[:], &relocs, &errors) - ok("br: encode ok", r.success) + byte_count, success := rv.encode(insts, ld[:], code[:], &relocs, &errors) + ok("br: encode ok", success) ok("br: no leftover relocs", len(relocs) == 0) eq_word("BNE rel=-8", load_le(code[:], 8), 0xFE029CE3) } @@ -170,9 +170,9 @@ run_pipeline_tests :: proc() { rv.inst_r_r_i(.ADDI, rv.SP, rv.SP, 0), rv.inst_jalr(rv.ZERO, rv.RA, 0), } - r := rv.encode(insts, ld[:], code[:], &relocs, &errors) - ok("JAL: encode ok", r.success) - eq_word("JAL ra,+8", load_le(code[:], 0), 0x008000EF) + byte_count, success := rv.encode(insts, ld[:], code[:], &relocs, &errors) + ok("JAL: encode ok", success) + eq_word("JAL ra,+8", load_le(code[:], 0), 0x008000EF) } // ---- 5. Round-trip: encode -> decode -> print ----------------------- @@ -189,16 +189,16 @@ run_pipeline_tests :: proc() { rv.inst_load (.LW, rv.A0, rv.mem(rv.SP, 0)), rv.inst_branch(.BNE, rv.T0, rv.ZERO, 0), } - r := rv.encode(src, ld[:], code[:], &relocs, &errors) - ok("rt: encode ok", r.success) + byte_count, success := rv.encode(src, ld[:], code[:], &relocs, &errors) + ok("rt: encode ok", success) d_insts: [dynamic]rv.Instruction d_info: [dynamic]rv.Instruction_Info d_labels: [dynamic]rv.Label_Definition defer delete(d_insts); defer delete(d_info); defer delete(d_labels) clear(&errors) - d := rv.decode(code[:r.byte_count], nil, &d_insts, &d_info, &d_labels, &errors) - ok("rt: decode ok", d.success) + dbyte_count, dsuccess := rv.decode(code[:byte_count], nil, &d_insts, &d_info, &d_labels, &errors) + ok("rt: decode ok", dsuccess) ok("rt: 3 insts", len(d_insts) == 3) ok("rt: ADDI", d_insts[0].mnemonic == .ADDI) ok("rt: LW", d_insts[1].mnemonic == .LW) @@ -223,15 +223,15 @@ run_pipeline_tests :: proc() { rv.inst_r_r_r(.DIV, rv.T1, rv.A0, rv.A1), rv.inst_r_r_r(.REMU, rv.T2, rv.A0, rv.A1), } - r := rv.encode(src, nil, code[:], &relocs, &errors) - ok("M: encode ok", r.success) + byte_count, success := rv.encode(src, nil, code[:], &relocs, &errors) + ok("M: encode ok", success) d_insts: [dynamic]rv.Instruction d_info: [dynamic]rv.Instruction_Info d_labels: [dynamic]rv.Label_Definition defer delete(d_insts); defer delete(d_info); defer delete(d_labels) clear(&errors) - rv.decode(code[:r.byte_count], nil, &d_insts, &d_info, &d_labels, &errors) + rv.decode(code[:byte_count], nil, &d_insts, &d_info, &d_labels, &errors) ok("M: MUL", d_insts[0].mnemonic == .MUL) ok("M: DIV", d_insts[1].mnemonic == .DIV) ok("M: REMU", d_insts[2].mnemonic == .REMU) @@ -258,8 +258,8 @@ run_pipeline_tests :: proc() { }, }, } - r := rv.encode(insts, nil, code[:], &relocs, &errors) - ok("A: encode ok", r.success) + byte_count, success := rv.encode(insts, nil, code[:], &relocs, &errors) + ok("A: encode ok", success) eq_word("A: AMOADD.W", load_le(code[:], 0), 0x00B522AF) } @@ -283,8 +283,8 @@ run_pipeline_tests :: proc() { }, }, } - r := rv.encode(insts, nil, code[:], &relocs, &errors) - ok("F: encode ok", r.success) + byte_count, success := rv.encode(insts, nil, code[:], &relocs, &errors) + ok("F: encode ok", success) eq_word("F: FADD.S", load_le(code[:], 0), 0x00C58553) d_insts: [dynamic]rv.Instruction @@ -292,7 +292,7 @@ run_pipeline_tests :: proc() { d_labels: [dynamic]rv.Label_Definition defer delete(d_insts); defer delete(d_info); defer delete(d_labels) clear(&errors) - rv.decode(code[:r.byte_count], nil, &d_insts, &d_info, &d_labels, &errors) + rv.decode(code[:byte_count], nil, &d_insts, &d_info, &d_labels, &errors) text := rv.aprint(d_insts[:], d_info[:], d_labels[:], nil, nil, nil, context.temp_allocator) @@ -317,8 +317,8 @@ run_pipeline_tests :: proc() { rv.Register(rv.REG_FPR | 12), // fa2 rv.Register(rv.REG_FPR | 13)), // fa3 } - r := rv.encode(insts, nil, code[:], &relocs, &errors) - ok("D: encode ok", r.success) + byte_count, success := rv.encode(insts, nil, code[:], &relocs, &errors) + ok("D: encode ok", success) eq_word("D: FMADD.D", load_le(code[:], 0), 0x6AC58543) } @@ -333,8 +333,8 @@ run_pipeline_tests :: proc() { insts := []rv.Instruction{ rv.inst_csr(.CSRRW, rv.A0, 0xF14, rv.ZERO), } - r := rv.encode(insts, nil, code[:], &relocs, &errors) - ok("CSR: encode ok", r.success) + byte_count, success := rv.encode(insts, nil, code[:], &relocs, &errors) + ok("CSR: encode ok", success) eq_word("CSR: csrrw", load_le(code[:], 0), 0xF1401573) } @@ -382,9 +382,9 @@ run_pipeline_tests :: proc() { ops = {rv.op_reg(rv.A2), rv.op_reg(rv.A3), {}, {}}, }, } - r := rv.encode(insts, nil, code[:], &relocs, &errors) - ok("C: encode ok", r.success) - ok("C: byte count", r.byte_count == 8) + byte_count, success := rv.encode(insts, nil, code[:], &relocs, &errors) + ok("C: encode ok", success) + ok("C: byte count", byte_count == 8) get_hw := proc(buf: []u8, off: u32) -> u16 { return u16(buf[off]) | (u16(buf[off+1]) << 8) } @@ -402,7 +402,7 @@ run_pipeline_tests :: proc() { d_labels: [dynamic]rv.Label_Definition defer delete(d_insts); defer delete(d_info); defer delete(d_labels) clear(&errors) - rv.decode(code[:r.byte_count], nil, &d_insts, &d_info, &d_labels, &errors) + rv.decode(code[:byte_count], nil, &d_insts, &d_info, &d_labels, &errors) ok("C: decode 4 insts", len(d_insts) == 4) ok("C: NOP", len(d_insts) >= 1 && d_insts[0].mnemonic == .C_NOP) ok("C: LI", len(d_insts) >= 2 && d_insts[1].mnemonic == .C_LI) @@ -429,16 +429,16 @@ run_pipeline_tests :: proc() { ops = {rv.op_reg(rv.A2), rv.op_reg(rv.A0), {}, {}}, }, } - r := rv.encode(insts, nil, code[:], &relocs, &errors) - ok("C: mixed encode", r.success) - ok("C: mixed bytes = 8", r.byte_count == 8) + byte_count, success := rv.encode(insts, nil, code[:], &relocs, &errors) + ok("C: mixed encode", success) + ok("C: mixed bytes = 8", byte_count == 8) d_insts: [dynamic]rv.Instruction d_info: [dynamic]rv.Instruction_Info d_labels: [dynamic]rv.Label_Definition defer delete(d_insts); defer delete(d_info); defer delete(d_labels) clear(&errors) - rv.decode(code[:r.byte_count], nil, &d_insts, &d_info, &d_labels, &errors) + rv.decode(code[:byte_count], nil, &d_insts, &d_info, &d_labels, &errors) ok("C: mixed decode 3", len(d_insts) == 3) ok("C: [0]=C.LI len=2", len(d_insts) >= 1 && d_insts[0].mnemonic == .C_LI && d_insts[0].length == 2) ok("C: [1]=ADDI len=4", len(d_insts) >= 2 && d_insts[1].mnemonic == .ADDI && d_insts[1].length == 4) @@ -483,9 +483,9 @@ run_pipeline_tests :: proc() { }, rv.inst_none(.C_NOP), } - r := rv.encode(insts, ld[:], code[:], &relocs, &errors) - ok("C.BEQZ: encode", r.success) - ok("C.BEQZ: byte_count=8", r.byte_count == 8) + byte_count, success := rv.encode(insts, ld[:], code[:], &relocs, &errors) + ok("C.BEQZ: encode", success) + ok("C.BEQZ: byte_count=8", byte_count == 8) get_hw := proc(buf: []u8, off: u32) -> u16 { return u16(buf[off]) | (u16(buf[off+1]) << 8) @@ -502,7 +502,7 @@ run_pipeline_tests :: proc() { d_labels: [dynamic]rv.Label_Definition defer delete(d_insts); defer delete(d_info); defer delete(d_labels) clear(&errors) - rv.decode(code[:r.byte_count], nil, &d_insts, &d_info, &d_labels, &errors) + rv.decode(code[:byte_count], nil, &d_insts, &d_info, &d_labels, &errors) ok("C.BEQZ: decode count", len(d_insts) == 4) ok("C.BEQZ: [0] mnemonic", len(d_insts) >= 1 && d_insts[0].mnemonic == .C_BEQZ) ok("C.BEQZ: target = 6", len(d_insts) >= 1 && d_insts[0].ops[1].kind == .RELATIVE && u32(d_insts[0].ops[0].relative + d_insts[0].ops[1].relative)*0+ u32(d_insts[0].ops[1].relative) == 6) @@ -552,9 +552,9 @@ run_pipeline_tests :: proc() { ops = {rv.op_label(0), {}, {}, {}}, }, } - r := rv.encode(insts, ld[:], code[:], &relocs, &errors) - ok("C.J: encode", r.success) - ok("C.J: byte_count=10", r.byte_count == 10) + byte_count, success := rv.encode(insts, ld[:], code[:], &relocs, &errors) + ok("C.J: encode", success) + ok("C.J: byte_count=10", byte_count == 10) get_hw := proc(buf: []u8, off: u32) -> u16 { return u16(buf[off]) | (u16(buf[off+1]) << 8) @@ -571,7 +571,7 @@ run_pipeline_tests :: proc() { d_labels: [dynamic]rv.Label_Definition defer delete(d_insts); defer delete(d_info); defer delete(d_labels) clear(&errors) - rv.decode(code[:r.byte_count], nil, &d_insts, &d_info, &d_labels, &errors) + rv.decode(code[:byte_count], nil, &d_insts, &d_info, &d_labels, &errors) ok("C.J: decode count", len(d_insts) == 4) ok("C.J: [3] mnemonic", len(d_insts) >= 4 && d_insts[3].mnemonic == .C_J) ok("C.J: target = 0", len(d_insts) >= 4 && d_insts[3].ops[0].kind == .RELATIVE && u32(d_insts[3].ops[0].relative) == 0) @@ -601,8 +601,8 @@ run_pipeline_tests :: proc() { // Target at byte 2 + 64*4 = 258 -- out of range for 9-bit signed (max 254) append(&long_insts, rv.inst_none(.C_NOP)) - r := rv.encode(long_insts[:], ld[:], big_code[:], &relocs, &errors) - ok("C.BEQZ out-of-range: error", !r.success && len(errors) > 0) + byte_count, success := rv.encode(long_insts[:], ld[:], big_code[:], &relocs, &errors) + ok("C.BEQZ out-of-range: error", !success && len(errors) > 0) if len(errors) > 0 { ok("C.BEQZ out-of-range: code", errors[0].code == .LABEL_OUT_OF_RANGE) } diff --git a/core/rexcode/rsp/decoder.odin b/core/rexcode/rsp/decoder.odin index 150717460..21a8864eb 100644 --- a/core/rexcode/rsp/decoder.odin +++ b/core/rexcode/rsp/decoder.odin @@ -29,25 +29,24 @@ decode :: proc( label_defs: ^[dynamic]Label_Definition, errors: ^[dynamic]Error, endianness: Endianness = .BIG, -) -> Result { +) -> (byte_count: u32, ok: bool) { n_bytes := u32(len(data)) & ~u32(3) // drop dangling tail errors_start := u32(len(errors)) pending_branches: [dynamic]isa.Branch_Target defer delete(pending_branches) - pc: u32 = 0 - for pc < n_bytes { - word := read_u32(data, pc, endianness) + for byte_count < n_bytes { + word := read_u32(data, byte_count, endianness) inst: Instruction info: Instruction_Info - entry_idx := decode_one_inline(word, pc, &inst, &info) + entry_idx := decode_one_inline(word, byte_count, &inst, &info) if entry_idx < 0 { - append(errors, Error{inst_idx = pc, code = .INVALID_OPCODE}) + append(errors, Error{inst_idx = byte_count, code = .INVALID_OPCODE}) inst = Instruction{mnemonic = .INVALID, length = 4} - info = Instruction_Info{offset = pc} + info = Instruction_Info{offset = byte_count} } else { inst_idx_for_branches := u32(len(instructions)) for slot in 0.. Result { +) -> (byte_count: u32, ok: bool) { n_inst := u32(len(instructions)) if u32(len(code)) < n_inst * 4 { append(errors, Error{inst_idx = 0, code = .BUFFER_OVERFLOW}) - return Result{byte_count = 0, success = false} + return } errors_start := u32(len(errors)) pending_start := u32(len(relocs)) - pc: u32 = 0 for i in 0.. Result { +) -> (byte_count: u32, ok: bool) { if mode == ._16 { // Real-mode decoding is not implemented; the ModRM addressing // model differs from protected/long mode and needs a separate // decode path. See Mode enum comment in encoding_types.odin. fmt.panicf("x64.decode: Mode._16 (real mode) is not yet supported") } + ok = true if len(data) == 0 { - return Result{success = true} + return } - data_length := len(data) - pos := 0 - has_errors := false + data_length := u32(len(data)) // Track branch targets for label inference (resolved in pass 2 by isa). pending_branches: [dynamic]isa.Branch_Target @@ -1040,26 +1039,26 @@ decode :: proc( // PASS 1: Decode all instructions, collect branch targets // ========================================================================= - for pos < data_length { + for byte_count < data_length { inst: Instruction info: Instruction_Info // Record offset - info.offset = u32(pos) + info.offset = byte_count // Initialize decoder state state := Decoder_State{ - data = data[pos:], + data = data[byte_count:], position = 0, - mode = mode, - segment = NONE, + mode = mode, + segment = NONE, } // Phase 1: Parse prefixes err := decode_prefixes(&state) if err != nil { append(errors, Error{inst_idx = u32(len(instructions)), code = err}) - has_errors = true + ok = false break } @@ -1092,7 +1091,7 @@ decode :: proc( append(instructions, inst) append(inst_info, info) - pos += state.position + byte_count += u32(state.position) continue } } @@ -1103,7 +1102,7 @@ decode :: proc( entry, vex_entry, err = decode_opcode(&state) if err != nil { append(errors, Error{inst_idx = u32(len(instructions)), code = err}) - has_errors = true + ok = false break } @@ -1114,12 +1113,12 @@ decode :: proc( inst, err = decode_operands(&state, entry) } else { append(errors, Error{inst_idx = u32(len(instructions)), code = .INVALID_OPCODE}) - has_errors = true + ok = false break } if err != nil { append(errors, Error{inst_idx = u32(len(instructions)), code = err}) - has_errors = true + ok = false break } @@ -1164,7 +1163,7 @@ decode :: proc( } // Check for relative operands and record pending branch targets - inst_end := pos + state.position + inst_end := byte_count + u32(state.position) for op_idx in 0.. Result { +) -> (byte_count: u32, ok: bool) { if mode == ._16 { // Real-mode encoding is not implemented; the ModRM addressing // model differs from protected/long mode and needs a separate @@ -73,8 +73,7 @@ encode :: proc( fmt.panicf("x64.encode: Mode._16 (real mode) is not yet supported") } - code_pos: u32 = 0 - has_errors := false + ok = true // Temp storage for pending relocations (before resolution) pending_relocations: [dynamic]Relocation @@ -91,19 +90,19 @@ encode :: proc( for &inst, instruction_index in instructions { // Record this instruction's byte offset - inst_offsets[instruction_index] = code_pos + inst_offsets[instruction_index] = byte_count // Validate operand_count bounds if inst.operand_count > 4 { append(errors, Error{u32(instruction_index), .INVALID_OPERAND_COUNT, {}}) - has_errors = true + ok = false continue } // Check buffer space - if code_pos + MAX_INST_SIZE > u32(len(code)) { + if byte_count + MAX_INST_SIZE > u32(len(code)) { append(errors, Error{u32(instruction_index), .BUFFER_OVERFLOW, {}}) - has_errors = true + ok = false continue } @@ -136,7 +135,7 @@ encode :: proc( } if invalid { append(errors, Error{u32(instruction_index), .OPERAND_MISMATCH, {}}) - has_errors = true + ok = false continue } } @@ -145,7 +144,7 @@ encode :: proc( encodings := encoding_forms(inst.mnemonic) if len(encodings) == 0 { append(errors, Error{u32(instruction_index), .INVALID_MNEMONIC, {}}) - has_errors = true + ok = false continue } @@ -160,7 +159,7 @@ encode :: proc( if matched_enc == nil { append(errors, Error{u32(instruction_index), .NO_MATCHING_ENCODING, {}}) - has_errors = true + ok = false continue } @@ -169,7 +168,7 @@ encode :: proc( // ===================================================================== enc := matched_enc - out := code[code_pos:] + out := code[byte_count:] pos: u32 = 0 // --- Legacy Prefixes --- @@ -398,7 +397,7 @@ encode :: proc( // the instruction is not legal i386. if mode == ._32 && rex != 0 { append(errors, Error{u32(instruction_index), .OPERAND_MISMATCH, {}}) - has_errors = true + ok = false continue } @@ -598,7 +597,7 @@ encode :: proc( case .RELATIVE: // Relative reference - record relocation label_id := u32(user_op.relative) - append(&pending_relocations, Relocation{code_pos + pos, label_id, 0, .REL8, 1, u16(instruction_index)}) + append(&pending_relocations, Relocation{byte_count + pos, label_id, 0, .REL8, 1, u16(instruction_index)}) out[pos] = 0 pos += 1 } @@ -623,7 +622,7 @@ encode :: proc( pos += 4 case .RELATIVE: label_id := u32(user_op.relative) - append(&pending_relocations, Relocation{code_pos + pos, label_id, 0, .REL32, 4, u16(instruction_index)}) + append(&pending_relocations, Relocation{byte_count + pos, label_id, 0, .REL32, 4, u16(instruction_index)}) out[pos] = 0; out[pos+1] = 0; out[pos+2] = 0; out[pos+3] = 0 pos += 4 } @@ -639,7 +638,7 @@ encode :: proc( } } - code_pos += pos + byte_count += pos } // ========================================================================= @@ -677,7 +676,7 @@ encode :: proc( next_pc := patch_offset + 1 if !patch_pcrel_i8(code, patch_offset, target_offset, next_pc, relocation.addend) { append(errors, Error{u32(relocation.inst_idx), .LABEL_OUT_OF_RANGE, {}}) - has_errors = true + ok = false } case .REL32: @@ -692,10 +691,7 @@ encode :: proc( } } - return Result{ - byte_count = code_pos, - success = !has_errors, - } + return } // ----------------------------------------------------------------------------- diff --git a/core/rexcode/x86/encoding_types.odin b/core/rexcode/x86/encoding_types.odin index 62b1393df..db75512df 100644 --- a/core/rexcode/x86/encoding_types.odin +++ b/core/rexcode/x86/encoding_types.odin @@ -12,7 +12,6 @@ import "../isa" // SECTION: 6.0 Re-exports from isa (status, relocation) // ----------------------------------------------------------------------------- -Result :: isa.Result Error :: isa.Error Error_Code :: isa.Error_Code // Relocation and Relocation_Type live in reloc.odin (per-arch by design). diff --git a/core/rexcode/x86/tests/test.odin b/core/rexcode/x86/tests/test.odin index 552d8ec01..0879565c7 100644 --- a/core/rexcode/x86/tests/test.odin +++ b/core/rexcode/x86/tests/test.odin @@ -322,7 +322,7 @@ run_test :: proc(t: Test) -> bool { relocs: [dynamic]x86.Relocation defer delete(relocs) - encode_result := x86.encode( + byte_count, ok := x86.encode( t.instructions, labels_copy[:len(t.labels)], code_buf[:], @@ -333,11 +333,11 @@ run_test :: proc(t: Test) -> bool { ) // Copy encoded bytes - for i in 0.. bool { // Verify expected bytes if provided if len(t.expected_code) > 0 { - if int(encode_result.byte_count) != len(t.expected_code) { + if int(byte_count) != len(t.expected_code) { fmt.printf("%s[FAIL]%s %s - code size %d != expected %d\n", - RED, RESET, t.name, encode_result.byte_count, len(t.expected_code)) + RED, RESET, t.name, byte_count, len(t.expected_code)) g_stats.failed += 1 return false } - for i in 0.. bool { // ========================================================================= if len(code_to_decode) > 0 { - decode_result := x86.decode( + byte_count, ok := x86.decode( code_to_decode, nil, &decoded_insts, @@ -538,7 +538,7 @@ run_test :: proc(t: Test) -> bool { &decode_errors, ) - if !decode_result.success { + if !ok { fmt.printf("%s[FAIL]%s %s - decoding failed\n", RED, RESET, t.name) if len(decode_errors) > 0 { for err in decode_errors { @@ -2991,9 +2991,8 @@ run_label_map_tests :: proc() { defer delete(relocs) defer delete(errs) - result := x86.encode(instructions[:], lm.labels[:], code_buf[:], &relocs, &errs, true, 0) - - if !result.success { + byte_count, ok := x86.encode(instructions[:], lm.labels[:], code_buf[:], &relocs, &errs, true, 0) + if !ok { fmt.printf("%s[FAIL]%s Label_Map test - encoding failed\n", RED, RESET) g_stats.failed += 1 return @@ -3009,7 +3008,7 @@ run_label_map_tests :: proc() { defer delete(decoded_labels) defer delete(decode_errors) - x86.decode(code_buf[:result.byte_count], nil, &decoded_insts, &decoded_info, &decoded_labels, &decode_errors) + x86.decode(code_buf[:byte_count], nil, &decoded_insts, &decoded_info, &decoded_labels, &decode_errors) // Print with named labels (printer wants id→name; Label_Map stores name→id). id_to_name := make(map[u32]string, len(lm.names), context.temp_allocator) @@ -3088,8 +3087,8 @@ run_benchmarks :: proc() { for _ in 0..