From 4264e19b37ff2c043a67a3f9ef9b9d584a0f0c01 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Wed, 9 Sep 2026 22:35:45 -0400 Subject: [PATCH] last thing on runtime encode of the night --- code/8086/encode.c | 244 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 226 insertions(+), 18 deletions(-) diff --git a/code/8086/encode.c b/code/8086/encode.c index 8d47e88..834befb 100644 --- a/code/8086/encode.c +++ b/code/8086/encode.c @@ -1,5 +1,6 @@ #ifdef INTELLISENSE_DIRECTIVES # include "encode.h" +# include "encoder_table.h" #endif internal void @@ -12,46 +13,253 @@ x8616_encode_push(FArena_R arena, X8616_InfoList_R msgs, X8616_EncodeStatus stat x8616_info_push(arena, msgs, kind, code, id, size, expected, actual); } -FI_ void x8616_encode_buf_u1(U1* buf, U1_R n, U1 value) { buf[n[0]] = value; n[0] += 1; } -FI_ void x8616_encode_buf_u2(U1* buf, U1_R n, U2 value) { +FI_ void x8616_encode_buf_u1(U1_R buf, U1_R n, U1 value) { buf[n[0]] = value; n[0] += 1; } +FI_ void x8616_encode_buf_u2(U1_R buf, U1_R n, U2 value) { x8616_encode_buf_u1(buf, n, u1_(value)); x8616_encode_buf_u1(buf, n, u1_(value >> 8)); } -FI_ void x8616_encode_buf_disp(U1* buf, U1_R n, S2 value, U1 bytes) { +FI_ void x8616_encode_buf_disp(U1_R buf, U1_R n, S2 value, U1 bytes) { if (bytes == 1) x8616_encode_buf_u1(buf, n, u1_(value)); if (bytes == 2) x8616_encode_buf_u2(buf, n, u2_(value)); } +I_ B4 x8616_encode_is_alu (X8616_Op op) { return op >= x8616_op_add && op <= x8616_op_cmp; } +I_ B4 x8616_encode_is_shift (X8616_Op op) { return op >= x8616_op_shl && op <= x8616_op_rcr; } +I_ B4 x8616_encode_is_jcc (X8616_Op op) { return op >= x8616_op_je && op <= x8616_op_jns; } +I_ U1 x8616_encode_alu_from_op(X8616_Op op) { return u1_(op - x8616_op_add); } +I_ U1 x8616_encode_cc_from_op (X8616_Op op) { + for (U1 i = 0; i < Array_len(x8616_op_from_cc); ++i) if (x8616_op_from_cc[i] == op) return i; + return 0; +} +I_ U1 x8616_encode_shift_from_op(X8616_Op op) { + for (U1 i = 0; i < Array_len(x8616_op_from_shift); ++i) if (x8616_op_from_shift[i] == op) return i; + return 0; +} +I_ void x8616_encode_or_field(U1_R header, X8616_BitField f, U1 value) { + header[0] |= (value << f.shift) & x8616_field_mask(f.shift, f.width); +} + +FI_ U1 x8616_encode_prefix_count(X8616_DecodedInstruction_R inst) { + return u1_(inst->prefixes.lock) + u1_(inst->prefixes.has_repeat) + u1_(inst->prefixes.has_segment); +} + +FI_ B4 x8616_encode_is_acc(X8616_DecodedOperand_R op) { + if ((op->flags & x8616_decoded_operand_register) == 0) return 0; + if (op->width == x8616_width_byte) return op->reg.r8 == x8616_al; + return op->reg.r16 == x8616_ax; +} + +RO_ global U2 x8616_encode_slot_any[] = { + [x8616_operand_none] = 0, + [x8616_operand_rm] = x8616_decoded_operand_register | x8616_decoded_operand_memory, + [x8616_operand_reg_modrm] = x8616_decoded_operand_register, + [x8616_operand_reg_opcode] = x8616_decoded_operand_register, + [x8616_operand_segment_modrm] = x8616_decoded_operand_segment, + [x8616_operand_segment_opcode] = x8616_decoded_operand_segment, + [x8616_operand_acc] = x8616_decoded_operand_register, + [x8616_operand_imm] = x8616_decoded_operand_immediate, + [x8616_operand_imm8] = x8616_decoded_operand_immediate, + [x8616_operand_imm16] = x8616_decoded_operand_immediate, + [x8616_operand_mem_direct] = x8616_decoded_operand_memory, + [x8616_operand_rel8] = x8616_decoded_operand_relative, + [x8616_operand_rel16] = x8616_decoded_operand_relative, + [x8616_operand_far_ptr] = x8616_decoded_operand_far_ptr, + [x8616_operand_dx] = x8616_decoded_operand_register, + [x8616_operand_shift_count] = x8616_decoded_operand_register | x8616_decoded_operand_immediate, +}; + +I_ B4 x8616_encode_slot_match(X8616_Operand slot, X8616_DecodedOperand_R op, X8616_DecodedInstruction_R inst) { + B4 ok = (op->flags & x8616_encode_slot_any[slot]) != 0; + ok &= (slot != x8616_operand_acc) || x8616_encode_is_acc(op); + ok &= (slot != x8616_operand_dx) || (op->reg.r16 == x8616_dx); + ok &= (slot != x8616_operand_imm8) || (op->immediate <= 0xFF); + ok &= (slot != x8616_operand_mem_direct) || ((op->flags & x8616_decoded_operand_direct) != 0); + ok &= (slot != x8616_operand_shift_count) || ((op->flags & x8616_decoded_operand_register) && op->reg.r8 == x8616_cl) || (op->immediate == 1); + if (slot == x8616_operand_rel8 && ok) { + S2 machine = s2_(op->displacement - s2_(x8616_encode_prefix_count(inst) + 2)); + ok = machine >= -128 && machine <= 127; + } + return ok; +} + +FI_ U1 x8616_encode_enc_count(X8616_Encoding_R enc) { return u1_(enc->operands[0] != x8616_operand_none) + u1_(enc->operands[1] != x8616_operand_none); } + +I_ B4 x8616_encode_op_match(X8616_Encoding_R enc, X8616_Op op) { + B4 prefix = (enc->flags & x8616_encoding_prefix) != 0; + B4 exact = enc->op == op; + B4 family = enc->op == x8616_op_invalid; + B4 alu = family && (enc->fields.alu.width || enc->digit_kind == x8616_digit_alu) && x8616_encode_is_alu(op); + B4 cc = family && enc->fields.cc.width && x8616_encode_is_jcc(op); + B4 shift = family && enc->digit_kind == x8616_digit_shift && x8616_encode_is_shift(op); + return prefix == 0 && (exact || alu || cc || shift); +} + +I_ B4 x8616_encode_row_match(X8616_Encoding_R enc, X8616_DecodedInstruction_R inst, U1 d) { + B4 op_ok = x8616_encode_op_match(enc, inst->op); + B4 enc_far = (enc->flags & x8616_encoding_far) != 0; + B4 inst_far = (inst->flags & x8616_encoding_far) != 0; + inst_far |= (inst->operands[0].flags & x8616_decoded_operand_far_ptr) != 0; + inst_far |= (inst->operands[1].flags & x8616_decoded_operand_far_ptr) != 0; + B4 far_ok = enc_far == inst_far; + B4 width_any = enc->width == x8616_width_dynamic || inst->width == x8616_width_dynamic; + B4 width_ok = width_any || enc->width == inst->width; + B4 count_ok = x8616_encode_enc_count(enc) == inst->operand_count; + B4 d_ok = enc->fields.d.width || d == 0; + B4 slots_ok = 1; + for (U1 i = 0; i < inst->operand_count; ++i) { + U1 slot_i = d ? (i ^ 1) : i; + slots_ok &= x8616_encode_slot_match(enc->operands[slot_i], inst->operands + i, inst); + } + return op_ok && far_ok && width_ok && count_ok && d_ok && slots_ok; +} + +FI_ U1 x8616_encode_row_score(X8616_Encoding const* enc) { + U1 score = 0; + for (U1 i = 0; i < 2; ++i) { + X8616_Operand s = enc->operands[i]; + if (s == x8616_operand_reg_opcode || s == x8616_operand_acc || s == x8616_operand_mem_direct) score += 2; + if (s == x8616_operand_rel8 || s == x8616_operand_imm8) score += 1; + } + return score; +} + +I_ B4 x8616_encode_slot_modrm(X8616_Operand s) { return s == x8616_operand_rm || s == x8616_operand_reg_modrm || s == x8616_operand_segment_modrm; } +I_ B4 x8616_encode_needs_modrm(X8616_Encoding const* enc) { + B4 masked = enc->mod_rm.mask != 0; + B4 digit = enc->digit_kind != x8616_digit_none; + B4 slots = x8616_encode_slot_modrm(enc->operands[0]) || x8616_encode_slot_modrm(enc->operands[1]); + return masked || digit || slots; +} + +internal B4 +x8616_encode_assemble(X8616_DecodedInstruction_R inst) +{ + X8616_Encoding const* best = 0; + U1 best_d = 0; + U1 best_score = 0; + B4 found = 0; + for (U4 id = 0; id < Array_len(x8616_encodings); ++id) + { + X8616_Encoding_R enc = x8616_encodings + id; + U1 d_hi = enc->fields.d.width ? 1 : 0; + for (U1 d = 0; d <= d_hi; ++d) { + if (x8616_encode_row_match(enc, inst, d) == 0) continue; + U1 score = x8616_encode_row_score(enc); + B4 not_bested = found && (score < best_score || (score == best_score && d < best_d)); + if (not_bested) continue; + best = enc; best_d = d; best_score = score; found = 1; + } + } + if (found == 0) return 0; + + X8616_DecodedOperand_R slot[X8616_OPERAND_SOURCE_COUNT] = {0}; + for (U1 op_id = 0; op_id < inst->operand_count; ++op_id) { + U1 slot_id = best_d ? (op_id ^ 1) : op_id; + slot[best->operands[slot_id]] = inst->operands + op_id; + } + + X8616_DecodedOperand_R operand_acc = slot[x8616_operand_acc]; + X8616_Width w = inst->width == x8616_width_word ? x8616_w_word : x8616_w_byte; + if (operand_acc) w = operand_acc->width == x8616_width_word ? x8616_w_word : x8616_w_byte; + + U1 header = best->header.bits; + X8616_DecodedOperand_R sc = slot[x8616_operand_shift_count]; + X8616_DecodedOperand_R imm = slot[x8616_operand_imm]; + if (imm == 0) imm = slot[x8616_operand_imm8]; + if (imm == 0) imm = slot[x8616_operand_imm16]; + U1 s = 0; + if (best->fields.s.width && imm) { + s = (inst->width == x8616_width_word && imm->immediate_bytes <= 1) || (imm->flags & x8616_decoded_operand_sign_extended); + } + U1 v = sc && (sc->flags & x8616_decoded_operand_register); + U1 reg_op = slot[x8616_operand_reg_opcode] ? u1_(slot[x8616_operand_reg_opcode ]->reg.r16) : 0; + U1 sr_op = slot[x8616_operand_segment_opcode] ? u1_(slot[x8616_operand_segment_opcode]->segment) : 0; + x8616_encode_or_field(& header, best->fields.w, u1_(w)); + x8616_encode_or_field(& header, best->fields.d, best_d); + x8616_encode_or_field(& header, best->fields.alu, x8616_encode_alu_from_op(inst->op)); + x8616_encode_or_field(& header, best->fields.cc, x8616_encode_cc_from_op(inst->op)); + x8616_encode_or_field(& header, best->fields.reg, reg_op); + x8616_encode_or_field(& header, best->fields.sr, sr_op); + x8616_encode_or_field(& header, best->fields.v, v); + x8616_encode_or_field(& header, best->fields.s, s); + header = (header & ~best->header.mask) | (best->header.bits & best->header.mask); + if (sc && (sc->flags & x8616_decoded_operand_immediate) && sc->immediate == 1) sc->immediate_bytes = 0; + + U1 modrm = 0; + B4 has_modrm = x8616_encode_needs_modrm(best); + X8616_DecodedOperand_R rm_op = slot[x8616_operand_rm]; + U1 mod = x8616_mod_reg; + U1 rm = 0; + if (rm_op) { + B4 mem = (rm_op->flags & x8616_decoded_operand_memory) != 0; + B4 dir = (rm_op->flags & x8616_decoded_operand_direct) != 0; + B4 bp0 = mem && dir == 0 && rm_op->displacement_bytes == 0 && rm_op->ea == x8616_ea_bp; + if (bp0) { rm_op->displacement_bytes = 1; rm_op->displacement = 0; } + U1 db = rm_op->displacement_bytes; + mod = mem ? (dir ? x8616_mod_mem : (db > 2 ? 2 : db)) : x8616_mod_reg; + rm = dir ? u1_(x8616_ea_direct) : (mem ? u1_(rm_op->ea) : u1_(rm_op->reg.r16)); + } + U1 kind_digit[3] = { 0, x8616_encode_alu_from_op(inst->op), x8616_encode_shift_from_op(inst->op) }; + U1 reg = slot[x8616_operand_reg_modrm] ? u1_(slot[x8616_operand_reg_modrm]->reg.r16) : 0; + if (best->digit_kind) reg = kind_digit[best->digit_kind]; + X8616_DecodedOperand_R sr_m = slot[x8616_operand_segment_modrm]; + modrm = sr_m ? x8616_enc_modrm_seg(mod, sr_m->segment, rm) : x8616_enc_modrm(mod, reg, rm); + modrm = (modrm & ~best->mod_rm.mask) | (best->mod_rm.bits & best->mod_rm.mask); + + X8616_DecodedOperand_R rel = slot[x8616_operand_rel8]; + U1 rel_bytes = 1; + if (rel == 0) { rel = slot[x8616_operand_rel16]; rel_bytes = 2; } + if (imm) { + U1 imm16 = slot[x8616_operand_imm16] != 0; + U1 imm8 = slot[x8616_operand_imm8] != 0; + imm->immediate_bytes = imm16 ? 2 : (imm8 || w == x8616_w_byte || s ? 1 : 2); + } + if (rel) { + U1 size = x8616_encode_prefix_count(inst) + 1 + rel_bytes; + rel->displacement = s2_(rel->displacement - s2_(size)); + rel->displacement_bytes = rel_bytes; + } + + inst->header = header; + inst->mod_rm = modrm; + inst->has_mod_rm = has_modrm; + inst->post_opcode = best->post_opcode.mask ? best->post_opcode.bits : 0; + return 1; +} + internal X8616_EncodeStatus x8616_encode_instruction(Str8Gen_R gen, X8616_DecodedInstruction_R inst) { - B4 bad = inst->decode_flags & (x8616_decode_invalid | x8616_decode_truncated); - bad |= inst->size == 0; - if (bad) return x8616_encode_invalid_record; + if (inst->decode_flags & (x8616_decode_invalid | x8616_decode_truncated)) return x8616_encode_invalid_record; + X8616_DecodedInstruction local = *inst; + if (local.size == 0) { + if (x8616_encode_assemble(& local) == 0) return x8616_encode_invalid_record; + } + U1 buf[16]; U1 n = 0; - U1 rep = inst->prefixes.repeat == x8616_rep ? x8616_rep_prefix() : x8616_repne_prefix(); - if (inst->prefixes.lock) { x8616_encode_buf_u1(buf, & n, x8616_lock_prefix()); } - if (inst->prefixes.has_repeat) { x8616_encode_buf_u1(buf, & n, rep); } - if (inst->prefixes.has_segment) { x8616_encode_buf_u1(buf, & n, x8616_segment_prefix(inst->prefixes.segment)); } - x8616_encode_buf_u1(buf, & n, inst->header); - if (inst->post_opcode) { x8616_encode_buf_u1(buf, & n, inst->post_opcode); } - if (inst->has_mod_rm) { x8616_encode_buf_u1(buf, & n, inst->mod_rm); } + U1 rep = local.prefixes.repeat == x8616_rep ? x8616_rep_prefix() : x8616_repne_prefix(); + if (local.prefixes.lock) { x8616_encode_buf_u1(buf, & n, x8616_lock_prefix()); } + if (local.prefixes.has_repeat) { x8616_encode_buf_u1(buf, & n, rep); } + if (local.prefixes.has_segment) { x8616_encode_buf_u1(buf, & n, x8616_segment_prefix(local.prefixes.segment)); } + x8616_encode_buf_u1(buf, & n, local.header); + if (local.post_opcode) { x8616_encode_buf_u1(buf, & n, local.post_opcode); } + if (local.has_mod_rm) { x8616_encode_buf_u1(buf, & n, local.mod_rm); } - for (U1 id = 0; id < inst->operand_count; ++id) { - X8616_DecodedOperand_R op = inst->operands + id; + for (U1 id = 0; id < local.operand_count; ++id) { + X8616_DecodedOperand_R op = local.operands + id; if ((op->flags & x8616_decoded_operand_memory) == 0) continue; if ( op->flags & x8616_decoded_operand_direct) x8616_encode_buf_u2(buf, & n, op->address); else x8616_encode_buf_disp(buf, & n, op->displacement, op->displacement_bytes); } - for (U1 id = 0; id < inst->operand_count; ++id) { - X8616_DecodedOperand_R op = inst->operands + id; + for (U1 id = 0; id < local.operand_count; ++id) { + X8616_DecodedOperand_R op = local.operands + id; B4 op_rel = op->flags & x8616_decoded_operand_relative; B4 op_imm = (op->flags & x8616_decoded_operand_immediate) && op->immediate_bytes; B4 op_far = op->flags & x8616_decoded_operand_far_ptr; if (op_rel) { x8616_encode_buf_disp(buf, & n, op->displacement, op->displacement_bytes); } else if (op_imm) { x8616_encode_buf_disp(buf, & n, s2_(op->immediate), op->immediate_bytes); } - else if (op_far) { + else if (op_far) { x8616_encode_buf_u2(buf, & n, op->far_offset); x8616_encode_buf_u2(buf, & n, op->far_segment); }