From 6a456097baa0435605435751e5af2dc3209e0104 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Fri, 4 Sep 2026 22:24:45 -0400 Subject: [PATCH] decoder --- code/8086/decoder.c | 458 +++++++ code/8086/decoder.h | 163 +++ code/8086/decoder.test.c | 36 + code/8086/decoder_table_generator.meta.c | 268 ++++ code/8086/encoder.h | 825 ++++++++++++ code/8086/encoder_table.h | 1565 ++++++++++++++++++++++ code/8086/gen/decoder_table.h | 358 +++++ code/8086/info.h | 100 ++ code/8086/info_render.h | 22 + code/duffle/memory.h | 3 +- 10 files changed, 3796 insertions(+), 2 deletions(-) create mode 100644 code/8086/decoder.c create mode 100644 code/8086/decoder.h create mode 100644 code/8086/decoder.test.c create mode 100644 code/8086/decoder_table_generator.meta.c create mode 100644 code/8086/encoder.h create mode 100644 code/8086/encoder_table.h create mode 100644 code/8086/gen/decoder_table.h create mode 100644 code/8086/info.h create mode 100644 code/8086/info_render.h diff --git a/code/8086/decoder.c b/code/8086/decoder.c new file mode 100644 index 0000000..c0f152a --- /dev/null +++ b/code/8086/decoder.c @@ -0,0 +1,458 @@ +#ifdef INTELLISENSE_DIRECTIVES +# include "encoder.h" +# include "info.h" +# include "decoder.h" +# include "gen/decoder_table.h" +#endif + +RO_ global U1 x8616_decode_disp_bytes[32] = { + 0,0,0,0,0,0,2,0, + 1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2, + 0,0,0,0,0,0,0,0, +}; + +RO_ global U1 x8616_decode_payload_bytes[] = { + 0, // none + 0, // imm: dynamic + 1, // imm8 + 2, // imm16 + 2, // mem-direct + 1, // rel8 + 2, // rel16 + 4, // far-ptr +}; + +typedef Struct_(X8616_DecodePlex) { + U1 const* source; + U4 source_size; + U4 source_offset; + + U1 body[X8616_DECODE_BODY_CAP + X8616_DECODE_BODY_PAD]; + U1 body_available; + + U2 dispatch; + U1 plan_idx; + X8616_DecodePlan const* plan; + + U1 opcode; + U1 post_opcode; + U1 mod_rm; + + U1 d; + U1 w; + U1 s; + U1 v; + U1 z; + U1 reg_opcode; + U1 sr_opcode; + + U1 mod; + U1 reg; + U1 rm; + U1 sr_modrm; + + X8616_WidthMode width; + + U1 body_at; + U1 displacement_at; + U1 displacement_bytes; + U1 payload_at; + U1 payload_bytes; + U1 body_required; + + S2 displacement; + U2 direct_address; + U2 payload_u16; + U2 far_segment; + + B1 direct_memory; + B1 classification_truncated; + B1 encoding_invalid; + + X8616_DecodedPrefixes prefixes; + X8616_DecodedOperand operand_source[X8616_OPERAND_SOURCE_COUNT]; + X8616_DecodedInstruction instruction; + + FArena* info_arena; + X8616_InfoList* msgs; +}; + +FI_ U2 x8616_decode_u2(U1_R bytes) { return C_(U2, bytes[0] | u2_(bytes[1] << 8)); } + +internal void +x8616_decode_apply_prefix(X8616_DecodePlex_R plex, X8616_DecodePlan_R plan, U1 opcode) { + plex->prefixes.count += 1; + plex->prefixes.lock |= plan->prefix_kind == x8616_prefix_lock; + if (plan->prefix_kind == x8616_prefix_repeat) { + plex->prefixes.has_repeat = 1; + plex->prefixes.repeat = (opcode >> plan->z_shift) & 0b1; + } + if (plan->prefix_kind == x8616_prefix_segment) { + plex->prefixes.has_segment = 1; + plex->prefixes.segment = (opcode >> plan->sr_shift) & 0b11; + } +} + +internal U4 +x8616_decode_one_plex(X8616_DecodePlex* plex) +{ + U4 prefix_at = 0; + + // Prefix pass. Ambiguous/group opcodes are never prefixes, so only direct + // dispatch entries participate in this loop. + while (prefix_at < plex->source_size) + { + U1 prefix_opcode = plex->source[prefix_at]; + U2 prefix_dispatch = x8616_decode_dispatch[prefix_opcode]; + if (prefix_dispatch == false || (prefix_dispatch & X8616_DECODE_AUX_BIT)) break; + + X8616_DecodePlan const* prefix_plan = x8616_decode_plans + prefix_dispatch; + if ((prefix_plan->flags & x8616_plan_is_prefix) == false) break; + + x8616_decode_apply_prefix(plex, prefix_plan, prefix_opcode); + ++ prefix_at; + } + + U4 body_source_size = plex->source_size - prefix_at; + plex->body_available = u1_(body_source_size < X8616_DECODE_BODY_CAP ? body_source_size : X8616_DECODE_BODY_CAP); + + for (U1 idx = 0; idx < plex->body_available; ++ idx) plex->body[idx] = plex->source[prefix_at + idx]; + + plex->opcode = plex->body[0]; + plex->dispatch = x8616_decode_dispatch[plex->opcode]; + + if (body_source_size == 0) { + plex->classification_truncated = 1; + x8616_info_push(plex->info_arena, plex->msgs, x8616_info_error + , x8616_info_truncated_instruction + , plex->source_offset + prefix_at + , 0 + , 1 + , 0 + ); + } + else if (plex->dispatch & X8616_DECODE_AUX_BIT) + { + if (body_source_size < 2) { + plex->classification_truncated = 1; + x8616_info_push(plex->info_arena, plex->msgs, x8616_info_error + , x8616_info_truncated_instruction + , plex->source_offset + prefix_at + , u2_(body_source_size) + , 2 + , body_source_size + ); + } + else + { + U2 aux_base = plex->dispatch & X8616_DECODE_AUX_MASK; + plex->plan_idx = x8616_decode_aux[aux_base + plex->body[1]]; + if (plex->plan_idx == false) { + plex->encoding_invalid = 1; + x8616_info_push(plex->info_arena, plex->msgs, x8616_info_error + , x8616_info_invalid_opcode_extension + , plex->source_offset + prefix_at + , 2 + , 0 + , plex->body[1] + ); + } + } + } + else + { + plex->plan_idx = C_(U1, plex->dispatch); + if (plex->plan_idx == 0) { + plex->encoding_invalid = 1; + x8616_info_push(plex->info_arena, plex->msgs, x8616_info_error + , x8616_info_invalid_opcode + , plex->source_offset + prefix_at + , 1 + , 0 + , plex->opcode + ); + } + } + + plex->plan = x8616_decode_plans + plex->plan_idx; + + // A direct-dispatch plan may still have a constrained second byte. + // Group opcodes with multiple candidates were already resolved through aux. + if (plex->plan_idx && (plex->plan->flags & (x8616_plan_has_modrm | x8616_plan_has_post_opcode))) + { + if (body_source_size < 2) + { + if (plex->classification_truncated == 0) { + plex->classification_truncated = 1; + x8616_info_push(plex->info_arena, plex->msgs, x8616_info_error + , x8616_info_truncated_instruction + , plex->source_offset + prefix_at + , u2_(body_source_size) + , 2 + , body_source_size + ); + } + } + else + { + U1 second = plex->body[1]; + if (plex->plan->mod_rm.mask && (second & plex->plan->mod_rm.mask) != plex->plan->mod_rm.bits) { + plex->encoding_invalid = 1; + x8616_info_push(plex->info_arena, plex->msgs, x8616_info_error + , x8616_info_invalid_opcode_extension + , plex->source_offset + prefix_at + 1 + , 1 + , plex->plan->mod_rm.bits + , second & plex->plan->mod_rm.mask + ); + } + + if (plex->plan->post_opcode.mask && (second & plex->plan->post_opcode.mask) != plex->plan->post_opcode.bits) { + plex->encoding_invalid = 1; + x8616_info_push(plex->info_arena, plex->msgs, x8616_info_error + , x8616_info_invalid_post_opcode + , plex->source_offset + prefix_at + 1 + , 1 + , plex->plan->post_opcode.bits + , second & plex->plan->post_opcode.mask + ); + } + } + } + + // Nil plan: still return a normal zero-valued instruction record and make + // progress through the stream. Aux classification inspected two bytes. + if (plex->plan_idx == 0) { + U1 invalid_body_size = (plex->dispatch & X8616_DECODE_AUX_BIT) && body_source_size >= 2 ? 2 : u1_(body_source_size != 0); + plex->instruction.prefixes = plex->prefixes; + plex->instruction.op = x8616_op_invalid; + plex->instruction.decode_flags = (plex->encoding_invalid ? x8616_decode_invalid : 0) | (plex->classification_truncated ? x8616_decode_truncated : 0); + plex->instruction.opcode = plex->opcode; + plex->instruction.size = u1_(prefix_at + invalid_body_size); + plex->instruction.size_required = plex->instruction.size; + return plex->instruction.size; + } + + X8616_DecodePlan const* plan = plex->plan; + plex->d = (plex->opcode >> plan->d_shift) & 0b1; + plex->w = (plex->opcode >> plan->w_shift) & 0b1; + plex->s = (plex->opcode >> plan->s_shift) & 0b1; + plex->v = (plex->opcode >> plan->v_shift) & 0b1; + plex->z = (plex->opcode >> plan->z_shift) & 0b1; + plex->reg_opcode = (plex->opcode >> plan->reg_shift) & 0b111; + plex->sr_opcode = (plex->opcode >> plan->sr_shift) & 0b11; + + plex->width = plan->width; + if (plex->width == x8616_width_dynamic && (plan->flags & x8616_plan_has_w)) + plex->width = plex->w ? x8616_width_word : x8616_width_byte; + + plex->body_at = 1; + + if (plan->flags & x8616_plan_has_post_opcode) { + plex->post_opcode = plex->body[plex->body_at]; + plex->body_at += 1; + } + + if (plan->flags & x8616_plan_has_modrm) { + plex->mod_rm = plex->body[plex->body_at]; + plex->mod = x8616_modrm_mod(plex->mod_rm); + plex->reg = x8616_modrm_reg(plex->mod_rm); + plex->rm = x8616_modrm_rm(plex->mod_rm); + plex->sr_modrm = x8616_modrm_sr(plex->mod_rm); + plex->body_at += 1; + } + + plex->displacement_at = plex->body_at; + + if (plan->flags & x8616_plan_uses_rm) plex->displacement_bytes = x8616_decode_disp_bytes[(plex->mod << 3) | plex->rm]; + + plex->direct_memory = (plan->flags & x8616_plan_uses_rm) && plex->mod == x8616_mod_mem && plex->rm == x8616_ea_direct; + + if (plex->displacement_bytes == 1) plex->displacement = s2_(s1_(plex->body[plex->displacement_at])); + else if (plex->displacement_bytes == 2) plex->displacement = s2_(x8616_decode_u2(plex->body + plex->displacement_at)); + + if (plex->direct_memory) plex->direct_address = x8616_decode_u2(plex->body + plex->displacement_at); + + plex->payload_at = plex->displacement_at + plex->displacement_bytes; + plex->payload_bytes = x8616_decode_payload_bytes[plan->payload]; + + if (plan->payload == x8616_payload_imm) { + plex->payload_bytes = (plex->width == x8616_width_word && ((plan->flags & x8616_plan_has_s) && plex->s) == false) ? 2 : 1; + } + + plex->body_required = plex->payload_at + plex->payload_bytes; + plex->payload_u16 = x8616_decode_u2(plex->body + plex->payload_at); + plex->far_segment = x8616_decode_u2(plex->body + plex->payload_at + 2); + + if (body_source_size < plex->body_required && plex->classification_truncated == 0) { + plex->classification_truncated = 1; + x8616_info_push(plex->info_arena, plex->msgs, x8616_info_error + , x8616_info_truncated_instruction + , plex->source_offset + prefix_at + , u2_(body_source_size) + , plex->body_required, body_source_size); + } + + // ------------------------------------------------------------------------ + // Operand-source plex + // + // Every possible operand source is populated once from the shared decoded + // fields. The plan projects two slots out of this array; there is no + // operand-kind switch on the hot path. + + X8616_DecodedOperand* source = plex->operand_source; + + source[x8616_operand_reg_modrm].flags = x8616_decoded_operand_register; + source[x8616_operand_reg_modrm].width = plex->width; + source[x8616_operand_reg_modrm].reg = plex->reg; + + source[x8616_operand_reg_opcode].flags = x8616_decoded_operand_register; + source[x8616_operand_reg_opcode].width = plex->width; + source[x8616_operand_reg_opcode].reg = plex->reg_opcode; + + source[x8616_operand_segment_modrm].flags = x8616_decoded_operand_segment; + source[x8616_operand_segment_modrm].width = x8616_width_word; + source[x8616_operand_segment_modrm].segment = plex->sr_modrm; + + source[x8616_operand_segment_opcode].flags = x8616_decoded_operand_segment; + source[x8616_operand_segment_opcode].width = x8616_width_word; + source[x8616_operand_segment_opcode].segment = plex->sr_opcode; + + source[x8616_operand_acc].flags = x8616_decoded_operand_register | x8616_decoded_operand_implicit; + source[x8616_operand_acc].width = plex->width; + source[x8616_operand_acc].reg = 0; + + source[x8616_operand_dx].flags = x8616_decoded_operand_register | x8616_decoded_operand_implicit; + source[x8616_operand_dx].width = x8616_width_word; + source[x8616_operand_dx].reg = x8616_dx; + + source[x8616_operand_rm].width = plex->width; + if (plex->mod == x8616_mod_reg) { + source[x8616_operand_rm].flags = x8616_decoded_operand_register; + source[x8616_operand_rm].reg = plex->rm; + } + else { + source[x8616_operand_rm].flags = x8616_decoded_operand_memory; + source[x8616_operand_rm].mod = plex->mod; + source[x8616_operand_rm].ea = plex->rm; + source[x8616_operand_rm].displacement = plex->displacement; + source[x8616_operand_rm].displacement_bytes = plex->displacement_bytes; + if (plex->direct_memory) { + source[x8616_operand_rm].flags |= x8616_decoded_operand_direct; + source[x8616_operand_rm].address = plex->direct_address; + } + } + + source[x8616_operand_imm].flags = x8616_decoded_operand_immediate + | (((plan->flags & x8616_plan_has_s) && plex->s) ? x8616_decoded_operand_sign_extended : 0); + source[x8616_operand_imm].width = plex->width; + source[x8616_operand_imm].immediate = plex->payload_u16; + source[x8616_operand_imm].immediate_bytes = plex->payload_bytes; + + source[x8616_operand_imm8].flags = x8616_decoded_operand_immediate; + source[x8616_operand_imm8].width = x8616_width_byte; + source[x8616_operand_imm8].immediate = C_(U1, plex->payload_u16); + source[x8616_operand_imm8].immediate_bytes = 1; + + source[x8616_operand_imm16].flags = x8616_decoded_operand_immediate; + source[x8616_operand_imm16].width = x8616_width_word; + source[x8616_operand_imm16].immediate = plex->payload_u16; + source[x8616_operand_imm16].immediate_bytes = 2; + + source[x8616_operand_mem_direct].flags = x8616_decoded_operand_memory | x8616_decoded_operand_direct; + source[x8616_operand_mem_direct].width = plex->width; + source[x8616_operand_mem_direct].address = plex->payload_u16; + + source[x8616_operand_rel8].flags = x8616_decoded_operand_relative; + source[x8616_operand_rel8].width = x8616_width_byte; + source[x8616_operand_rel8].displacement = C_(S2, C_(S1, plex->payload_u16)); + source[x8616_operand_rel8].displacement_bytes = 1; + + source[x8616_operand_rel16].flags = x8616_decoded_operand_relative; + source[x8616_operand_rel16].width = x8616_width_word; + source[x8616_operand_rel16].displacement = C_(S2, plex->payload_u16); + source[x8616_operand_rel16].displacement_bytes = 2; + + source[x8616_operand_far_ptr].flags = x8616_decoded_operand_far_ptr; + source[x8616_operand_far_ptr].far_offset = plex->payload_u16; + source[x8616_operand_far_ptr].far_segment = plex->far_segment; + + source[x8616_operand_shift_count].flags = x8616_decoded_operand_implicit; + source[x8616_operand_shift_count].width = x8616_width_byte; + if (plex->v == x8616_v_cl) { + source[x8616_operand_shift_count].flags |= x8616_decoded_operand_register; + source[x8616_operand_shift_count].reg = x8616_cl; + } + else { + source[x8616_operand_shift_count].flags |= x8616_decoded_operand_immediate; + source[x8616_operand_shift_count].immediate = 1; + source[x8616_operand_shift_count].immediate_bytes = 0; + } + + // Final projection. Authored operand order is d=0; d=1 exchanges the two source slots without introducing a separate decoder path. + U1 swap = C_(U1, ((plan->flags & x8616_plan_has_d) != 0) & plex->d); + plex->instruction.operands[swap] = source[plan->operands[0]]; + plex->instruction.operands[swap ^ 1] = source[plan->operands[1]]; + + plex->instruction.op = plan->op; + plex->instruction.flags = plan->encoding_flags; + plex->instruction.decode_flags = (plex->encoding_invalid ? x8616_decode_invalid : 0) | (plex->classification_truncated ? x8616_decode_truncated : 0); + plex->instruction.width = plex->width; + plex->instruction.prefixes = plex->prefixes; + plex->instruction.operand_count = plan->operand_count; + plex->instruction.opcode = plex->opcode; + plex->instruction.mod_rm = plex->mod_rm; + plex->instruction.has_mod_rm = (plan->flags & x8616_plan_has_modrm) != 0; + + U4 total_required = prefix_at + plex->body_required; + U4 total_available = plex->source_size; + U4 total_consumed = total_required < total_available ? total_required : total_available; + + plex->instruction.size = u1_(total_consumed); + plex->instruction.size_required = u1_(total_required); + return total_consumed; +} + +X8616_DecodeInfo x8616_decode(X8616_DecodeRequest request) +{ + X8616_DecodeInfo result = {0}; + result.instruction_capacity = request.instruction_capacity; + + while (result.source_consumed < request.source_size && result.instruction_count < request.instruction_capacity) { + X8616_DecodePlex plex = {0}; + plex.source = request.source + result.source_consumed; + plex.source_size = request.source_size - result.source_consumed; + plex.source_offset = result.source_consumed; + plex.info_arena = request.info_arena; + plex.msgs = & result.msgs; + U4 consumed = x8616_decode_one_plex(& plex); + request.instructions[result.instruction_count++] = plex.instruction; + if (consumed == false) consumed = 1; + result.source_consumed += consumed; + } + + if (result.source_consumed < request.source_size && result.instruction_count == request.instruction_capacity) { + x8616_info_push(request.info_arena, & result.msgs, x8616_info_warning + , x8616_info_output_full + , result.source_consumed + , 0 + , request.instruction_capacity + , result.instruction_count + ); + } + return result; +} + +X8616_DecodeOneInfo x8616_decode_one(U1_R source, U4 source_size, FArena_R info_arena) { + X8616_DecodeOneInfo result = {0}; + X8616_DecodePlex plex = {0}; + plex.source = source; + plex.source_size = source_size; + plex.source_offset = 0; + plex.info_arena = info_arena; + plex.msgs = & result.msgs; + result.source_consumed = x8616_decode_one_plex(& plex); + result.instruction = plex.instruction; + return result; +} diff --git a/code/8086/decoder.h b/code/8086/decoder.h new file mode 100644 index 0000000..b465b97 --- /dev/null +++ b/code/8086/decoder.h @@ -0,0 +1,163 @@ +#ifdef INTELLISENSE_DIRECTIVES +# pragma once +# include "dsl.h" +# include "encoder.h" +# include "info.h" +#endif + +enum { + X8616_OPERAND_SOURCE_COUNT = 0x10, + X8616_DECODE_BODY_CAP = 0x06, + X8616_DECODE_BODY_PAD = 0x02, +}; + +typedef Enum_(U2, X8616_DecodedOperandFlags) { + x8616_decoded_operand_none = 0b0000000000000000, + x8616_decoded_operand_register = 0b0000000000000001, + x8616_decoded_operand_segment = 0b0000000000000010, + x8616_decoded_operand_memory = 0b0000000000000100, + x8616_decoded_operand_immediate = 0b0000000000001000, + x8616_decoded_operand_relative = 0b0000000000010000, + x8616_decoded_operand_far_ptr = 0b0000000000100000, + x8616_decoded_operand_direct = 0b0000000001000000, + x8616_decoded_operand_sign_extended = 0b0000000010000000, + x8616_decoded_operand_implicit = 0b0000000100000000, +}; + +typedef Struct_(X8616_DecodedOperand) { + X8616_DecodedOperandFlags flags; + X8616_WidthMode width; + U1 reg; + U1 segment; + U1 mod; + U1 ea; + S2 displacement; + U2 address; + U2 immediate; + U2 far_offset; + U2 far_segment; + U1 displacement_bytes; + U1 immediate_bytes; +}; + +typedef Struct_(X8616_DecodedPrefixes) { + U1 count; + B1 lock; + B1 has_repeat; + X8616_Repeat repeat; + B1 has_segment; + X8616_Segment segment; +}; + + +typedef Enum_(U1, X8616_DecodeFlags) { + x8616_decode_none = 0b00000000, + x8616_decode_invalid = 0b00000001, + x8616_decode_truncated = 0b00000010, +}; + +typedef Struct_(X8616_DecodedInstruction) { + X8616_Op op; + X8616_EncodingFlags flags; + X8616_DecodeFlags decode_flags; + X8616_WidthMode width; + X8616_DecodedPrefixes prefixes; + X8616_DecodedOperand operands[2]; + U1 operand_count; + U1 opcode; + U1 mod_rm; + B1 has_mod_rm; + U1 size; + U1 size_required; +}; + +typedef Enum_(U2, X8616_DecodePlanFlags) { + x8616_plan_none = 0b0000000000000000, + x8616_plan_has_modrm = 0b0000000000000001, + x8616_plan_has_post_opcode = 0b0000000000000010, + x8616_plan_has_d = 0b0000000000000100, + x8616_plan_has_w = 0b0000000000001000, + x8616_plan_has_s = 0b0000000000010000, + x8616_plan_has_v = 0b0000000000100000, + x8616_plan_has_z = 0b0000000001000000, + x8616_plan_has_reg = 0b0000000010000000, + x8616_plan_has_sr = 0b0000000100000000, + x8616_plan_uses_rm = 0b0000001000000000, + x8616_plan_is_prefix = 0b0000010000000000, +}; + +typedef Enum_(U1, X8616_DecodePayload) { + x8616_payload_none = 0x0, + x8616_payload_imm = 0x1, + x8616_payload_imm8 = 0x2, + x8616_payload_imm16 = 0x3, + x8616_payload_mem_direct = 0x4, + x8616_payload_rel8 = 0x5, + x8616_payload_rel16 = 0x6, + x8616_payload_far_ptr = 0x7, +}; + +typedef Enum_(U1, X8616_DecodePrefixKind) { + x8616_prefix_none = 0x0, + x8616_prefix_lock = 0x1, + x8616_prefix_repeat = 0x2, + x8616_prefix_segment = 0x3, +}; + +typedef Struct_(X8616_DecodePlan) { + X8616_DecodePlanFlags flags; + + X8616_Op op; + X8616_EncodingFlags encoding_flags; + X8616_WidthMode width; + + X8616_Operand operands[2]; + U1 operand_count; + + X8616_DecodePayload payload; + X8616_DecodePrefixKind prefix_kind; + + U1 d_shift; + U1 w_shift; + U1 s_shift; + U1 v_shift; + U1 z_shift; + U1 reg_shift; + U1 sr_shift; + + X8616_BytePattern mod_rm; + X8616_BytePattern post_opcode; +}; + +enum { + X8616_DECODE_PLAN_INVALID = 0x00, + X8616_DECODE_AUX_BIT = 0x8000, + X8616_DECODE_AUX_MASK = 0x7FFF, +}; + +typedef Struct_(X8616_DecodeRequest) { + U1 const* source; + U4 source_size; + + X8616_DecodedInstruction* instructions; + U4 instruction_capacity; + + FArena* info_arena; +}; + +typedef Struct_(X8616_DecodeInfo) { + U4 source_consumed; + U4 instruction_count; + U4 instruction_capacity; + X8616_InfoList msgs; +}; + +X8616_DecodeInfo x8616_decode(X8616_DecodeRequest request); + +typedef Struct_(X8616_DecodeOneInfo) { + X8616_DecodedInstruction instruction; + X8616_InfoList msgs; + U4 source_consumed; +}; + +X8616_DecodeOneInfo x8616_decode_one(U1_R source, U4 source_size, FArena_R info_arena); diff --git a/code/8086/decoder.test.c b/code/8086/decoder.test.c new file mode 100644 index 0000000..f787ebc --- /dev/null +++ b/code/8086/decoder.test.c @@ -0,0 +1,36 @@ +#ifdef INTELLISENSE_DIRECTIVES +# include "duffle/dsl.h" +# include "encoder.h" +# include "decoder.h" +# include "info.h" +#endif + +internal void +x8616_decoder_smoke_test(void) +{ + U1 bytes[] = { + x8616_mov_r16_i (x8616_ax, 0x1234), + x8616_add_r16_i8s(x8616_ax, -2), + x8616_nop(), + }; + + X8616_DecodedInstruction instructions[3] = {0}; + U1 info_memory[1024] = {0}; + FArena info_scratch = farena_make(slice_ut_arr(info_memory)); + + X8616_DecodeInfo info = x8616_decode((X8616_DecodeRequest){ + .source = bytes, + .source_size = S_(bytes), + .instructions = instructions, + .instruction_capacity = Array_len(instructions), + .info_arena = & info_scratch, + }); + + assert(info.source_consumed == S_(bytes)); + assert(info.instruction_count == 3); + assert(info.msgs.error_count == 0); + + assert(instructions[0].op == x8616_op_mov); + assert(instructions[1].op == x8616_op_add); + assert(instructions[2].op == x8616_op_xchg); /* 0x90 in the Part 1 table */ +} diff --git a/code/8086/decoder_table_generator.meta.c b/code/8086/decoder_table_generator.meta.c new file mode 100644 index 0000000..3315ee1 --- /dev/null +++ b/code/8086/decoder_table_generator.meta.c @@ -0,0 +1,268 @@ +#ifdef INTELLISENSE_DIRECTIVES +# pragma once +# include "duffle/dsl.h" +# include "duffle/text.h" +# include "duffle/win32.h" +# include "encoder.h" +# include "encoder_table.h" +# include "decoder.h" +# include "info.h" +#endif + +enum { + X8616_DECODE_GEN_MAX_AUX = 256 * 256, +}; + +typedef Struct_(X8616_DecodeGen) { + X8616_DecodePlan plans[X8616_ENCODING_COUNT + 1]; + + U2 dispatch[256]; + U1 aux[X8616_DECODE_GEN_MAX_AUX]; + + U4 aux_count; + U4 ambiguous_opcode_count; + U4 verified_count; + + X8616_InfoList msgs; +}; + +typedef Struct_(X8616_DecodeGenInfo) { + U4 plan_count; + U4 aux_count; + U4 ambiguous_opcode_count; + U4 verified_count; + + X8616_InfoList msgs; +}; + +FI_ B1 x8616_decode_gen_operand_uses_modrm(X8616_Operand operand) { + return operand == x8616_operand_rm || operand == x8616_operand_reg_modrm || operand == x8616_operand_segment_modrm; +} + +FI_ B1 x8616_decode_gen_operand_uses_rm(X8616_Operand operand) { return operand == x8616_operand_rm; } + +internal X8616_DecodePayload +x8616_decode_gen_payload_from_operand(X8616_Operand operand) { + switch (operand) { + case x8616_operand_imm: return x8616_payload_imm; + case x8616_operand_imm8: return x8616_payload_imm8; + case x8616_operand_imm16: return x8616_payload_imm16; + case x8616_operand_mem_direct: return x8616_payload_mem_direct; + case x8616_operand_rel8: return x8616_payload_rel8; + case x8616_operand_rel16: return x8616_payload_rel16; + case x8616_operand_far_ptr: return x8616_payload_far_ptr; + default: return x8616_payload_none; + } +} + +internal X8616_DecodePrefixKind +x8616_decode_gen_prefix_kind(X8616_Encoding const* encoding) { + if ((encoding->flags & x8616_encoding_prefix) == 0) return x8616_prefix_none; + switch (encoding->op) { + case x8616_op_lock: return x8616_prefix_lock; + case x8616_op_rep: return x8616_prefix_repeat; + case x8616_op_segment: return x8616_prefix_segment; + default: return x8616_prefix_none; + } +} + +internal X8616_DecodePlan +x8616_decode_gen_plan(X8616_Encoding const* encoding, U4 encoding_idx, X8616_InfoList* msgs, FArena_R info_scratch) +{ + X8616_DecodePlan plan = {0}; + plan.op = encoding->op; + plan.encoding_flags = encoding->flags; + plan.width = encoding->width; + plan.operands[0] = encoding->operands[0]; + plan.operands[1] = encoding->operands[1]; + plan.operand_count = (encoding->operands[0] != x8616_operand_none) + (encoding->operands[1] != x8616_operand_none); + plan.prefix_kind = x8616_decode_gen_prefix_kind(encoding); + plan.mod_rm = encoding->mod_rm; + plan.post_opcode = encoding->post_opcode; + + if (encoding->mod_rm.mask || x8616_decode_gen_operand_uses_modrm(encoding->operands[0]) || x8616_decode_gen_operand_uses_modrm(encoding->operands[1])) + plan.flags |= x8616_plan_has_modrm; + + if (encoding->post_opcode.mask) + plan.flags |= x8616_plan_has_post_opcode; + + if (encoding->fields.d.width) { plan.flags |= x8616_plan_has_d; plan.d_shift = encoding->fields.d.shift; } + if (encoding->fields.w.width) { plan.flags |= x8616_plan_has_w; plan.w_shift = encoding->fields.w.shift; } + if (encoding->fields.s.width) { plan.flags |= x8616_plan_has_s; plan.s_shift = encoding->fields.s.shift; } + if (encoding->fields.v.width) { plan.flags |= x8616_plan_has_v; plan.v_shift = encoding->fields.v.shift; } + if (encoding->fields.z.width) { plan.flags |= x8616_plan_has_z; plan.z_shift = encoding->fields.z.shift; } + if (encoding->fields.reg.width) { plan.flags |= x8616_plan_has_reg; plan.reg_shift = encoding->fields.reg.shift; } + if (encoding->fields.sr.width) { plan.flags |= x8616_plan_has_sr; plan.sr_shift = encoding->fields.sr.shift; } + + if (x8616_decode_gen_operand_uses_rm(encoding->operands[0]) || x8616_decode_gen_operand_uses_rm(encoding->operands[1])) + plan.flags |= x8616_plan_uses_rm; + + if (encoding->flags & x8616_encoding_prefix) + plan.flags |= x8616_plan_is_prefix; + + X8616_DecodePayload payload_0 = x8616_decode_gen_payload_from_operand(encoding->operands[0]); + X8616_DecodePayload payload_1 = x8616_decode_gen_payload_from_operand(encoding->operands[1]); + + if (payload_0 && payload_1 && payload_0 != payload_1) + x8616_info_push(info_scratch, msgs, x8616_info_error, x8616_info_gen_multiple_payloads, encoding_idx, 0, payload_0, payload_1); + + plan.payload = payload_0 ? payload_0 : payload_1; + + U4 payload_max = 0; + switch (plan.payload) { + case x8616_payload_imm: payload_max = 2; break; + case x8616_payload_imm8: payload_max = 1; break; + case x8616_payload_imm16: payload_max = 2; break; + case x8616_payload_mem_direct: payload_max = 2; break; + case x8616_payload_rel8: payload_max = 1; break; + case x8616_payload_rel16: payload_max = 2; break; + case x8616_payload_far_ptr: payload_max = 4; break; + default: break; + } + + U4 body_max = 1 + + ((plan.flags & x8616_plan_has_post_opcode) != 0) + + ((plan.flags & x8616_plan_has_modrm) != 0) + + ((plan.flags & x8616_plan_uses_rm) ? 2 : 0) + + payload_max; + + if (body_max > X8616_DECODE_BODY_CAP) x8616_info_push(info_scratch, msgs, x8616_info_error + , x8616_info_gen_body_cap_exceeded + , encoding_idx + , 0 + , X8616_DECODE_BODY_CAP + , body_max + ); + return plan; +} + +FI_ B1 x8616_decode_gen_encoding_matches_opcode(X8616_Encoding const* encoding, U1 opcode) { + return (opcode & encoding->opcode.mask) == encoding->opcode.bits; +} + +FI_ B1 x8616_decode_gen_plan_matches_second(X8616_DecodePlan const* plan, U1 byte) { + if (plan->mod_rm.mask && ((byte & plan->mod_rm.mask) != plan->mod_rm.bits)) return false; + if (plan->post_opcode.mask && ((byte & plan->post_opcode.mask) != plan->post_opcode.bits)) return false; + return true; +} + +internal void x8616_decode_gen_pass_plans(X8616_DecodeGen* gen, FArena_R info_scratch) { + for (U4 idx = 0; idx < X8616_ENCODING_COUNT; ++ idx) + gen->plans[idx + 1] = x8616_decode_gen_plan(x8616_encodings + idx, idx, & gen->msgs, info_scratch); +} + +internal void +x8616_decode_gen_pass_dispatch(X8616_DecodeGen* gen, FArena_R info_scratch) +{ + for (U4 opcode = 0; opcode < 256; ++ opcode) + { + U1 candidates[X8616_ENCODING_COUNT]; + U4 candidate_count = 0; + + for (U4 encoding_idx = 0; encoding_idx < X8616_ENCODING_COUNT; ++ encoding_idx) + if (x8616_decode_gen_encoding_matches_opcode(x8616_encodings + encoding_idx, C_(U1, opcode))) + candidates[candidate_count ++] = C_(U1, encoding_idx + 1); + + if (candidate_count == 0) continue; + if (candidate_count == 1) { gen->dispatch[opcode] = candidates[0]; continue; } + + if (gen->aux_count + 256 > X8616_DECODE_GEN_MAX_AUX) { + x8616_info_push(info_scratch, & gen->msgs, x8616_info_error + , x8616_info_gen_aux_cap_exceeded + , opcode + , 0 + , X8616_DECODE_GEN_MAX_AUX + , gen->aux_count + 256 + ); + return; + } + + U4 base = gen->aux_count; + gen->dispatch[opcode] = C_(U2, X8616_DECODE_AUX_BIT | base); + gen->aux_count += 256; + gen->ambiguous_opcode_count += 1; + + for (U4 second = 0; second < 256; ++ second) + { + U1 selected = 0; + for (U4 candidate_idx = 0; candidate_idx < candidate_count; ++ candidate_idx) + { + U1 plan_idx = candidates[candidate_idx]; + if (! x8616_decode_gen_plan_matches_second(gen->plans + plan_idx, C_(U1, second))) + continue; + + if (selected) x8616_info_push(info_scratch, & gen->msgs, x8616_info_error + , x8616_info_gen_ambiguous_decode + , (opcode << 8) | second + , 0 + , selected + , plan_idx + ); + selected = plan_idx; + } + + gen->aux[base + second] = selected; + } + } +} + +internal void +x8616_decode_gen_pass_validate(X8616_DecodeGen* gen, FArena_R info_scratch) +{ + for (U4 opcode = 0; opcode < 256; ++ opcode) + for (U4 second = 0; second < 256; ++ second) + { + U1 expected = 0; + for (U4 encoding_idx = 0; encoding_idx < X8616_ENCODING_COUNT; ++ encoding_idx) + { + X8616_Encoding const* encoding = x8616_encodings + encoding_idx; + if (! x8616_decode_gen_encoding_matches_opcode(encoding, C_(U1, opcode))) continue; + + X8616_DecodePlan const* plan = gen->plans + encoding_idx + 1; + if (! x8616_decode_gen_plan_matches_second(plan, C_(U1, second))) continue; + + if (expected) x8616_info_push(info_scratch, & gen->msgs, x8616_info_error + , x8616_info_gen_ambiguous_decode + , (opcode << 8) | second, 0 + , expected, encoding_idx + 1 + ); + expected = C_(U1, encoding_idx + 1); + } + + U2 dispatch = gen->dispatch[opcode]; + U1 actual = 0; + + if (dispatch & X8616_DECODE_AUX_BIT) { + U2 base = dispatch & X8616_DECODE_AUX_MASK; + actual = gen->aux[base + second]; + } + else if (dispatch) { + U1 candidate = C_(U1, dispatch); + if (x8616_decode_gen_plan_matches_second(gen->plans + candidate, C_(U1, second))) + actual = candidate; + } + + if (actual != expected) x8616_info_push(info_scratch, & gen->msgs, x8616_info_error + , x8616_info_gen_dispatch_mismatch + , (opcode << 8) | second, 0 + , expected, actual + ); + ++ gen->verified_count; + } +} + +X8616_DecodeGenInfo +x8616_decode_table_generate(X8616_DecodeGen* gen, FArena_R info_scratch) { + gen[0] = (X8616_DecodeGen){0}; + x8616_decode_gen_pass_plans (gen, info_scratch); + x8616_decode_gen_pass_dispatch(gen, info_scratch); + x8616_decode_gen_pass_validate(gen, info_scratch); + X8616_DecodeGenInfo result = { + .plan_count = X8616_ENCODING_COUNT + 1, + .aux_count = gen->aux_count, + .ambiguous_opcode_count = gen->ambiguous_opcode_count, + .verified_count = gen->verified_count, + .msgs = gen->msgs, + }; + return result; +} diff --git a/code/8086/encoder.h b/code/8086/encoder.h new file mode 100644 index 0000000..c133082 --- /dev/null +++ b/code/8086/encoder.h @@ -0,0 +1,825 @@ +#ifdef INTELLISENSE_DIRECTIVES +# pragma once +# include "duffle/dsl.h" +#endif + +typedef Struct_(X8616_BytePattern) { U1 bits; U1 mask; }; +typedef Struct_(X8616_BitField) { U1 shift; U1 width; }; + +typedef Struct_(X8616_OpcodeFields) { + X8616_BitField d; + X8616_BitField w; + X8616_BitField s; + X8616_BitField v; + X8616_BitField z; + X8616_BitField reg; + X8616_BitField sr; +}; + +typedef Enum_(U1, X8616_Op) { + x8616_op_invalid = 0x00, + x8616_op_nop = 0x01, + x8616_op_mov = 0x02, + x8616_op_add = 0x03, + x8616_op_or = 0x04, + x8616_op_adc = 0x05, + x8616_op_sbb = 0x06, + x8616_op_and = 0x07, + x8616_op_sub = 0x08, + x8616_op_xor = 0x09, + x8616_op_cmp = 0x0A, + x8616_op_push = 0x0B, + x8616_op_pop = 0x0C, + x8616_op_xchg = 0x0D, + x8616_op_in = 0x0E, + x8616_op_out = 0x0F, + x8616_op_xlat = 0x10, + x8616_op_lea = 0x11, + x8616_op_lds = 0x12, + x8616_op_les = 0x13, + x8616_op_lahf = 0x14, + x8616_op_sahf = 0x15, + x8616_op_pushf = 0x16, + x8616_op_popf = 0x17, + x8616_op_inc = 0x18, + x8616_op_aaa = 0x19, + x8616_op_daa = 0x1A, + x8616_op_dec = 0x1B, + x8616_op_neg = 0x1C, + x8616_op_aas = 0x1D, + x8616_op_das = 0x1E, + x8616_op_mul = 0x1F, + x8616_op_imul = 0x20, + x8616_op_aam = 0x21, + x8616_op_div = 0x22, + x8616_op_idiv = 0x23, + x8616_op_aad = 0x24, + x8616_op_cbw = 0x25, + x8616_op_cwd = 0x26, + x8616_op_not = 0x27, + x8616_op_shl = 0x28, + x8616_op_shr = 0x29, + x8616_op_sar = 0x2A, + x8616_op_rol = 0x2B, + x8616_op_ror = 0x2C, + x8616_op_rcl = 0x2D, + x8616_op_rcr = 0x2E, + x8616_op_test = 0x2F, + x8616_op_rep = 0x30, + x8616_op_movs = 0x31, + x8616_op_cmps = 0x32, + x8616_op_scas = 0x33, + x8616_op_lods = 0x34, + x8616_op_stos = 0x35, + x8616_op_call = 0x36, + x8616_op_jmp = 0x37, + x8616_op_ret = 0x38, + x8616_op_retf = 0x39, + x8616_op_je = 0x3A, + x8616_op_jl = 0x3B, + x8616_op_jle = 0x3C, + x8616_op_jb = 0x3D, + x8616_op_jbe = 0x3E, + x8616_op_jp = 0x3F, + x8616_op_jo = 0x40, + x8616_op_js = 0x41, + x8616_op_jne = 0x42, + x8616_op_jnl = 0x43, + x8616_op_jg = 0x44, + x8616_op_jnb = 0x45, + x8616_op_ja = 0x46, + x8616_op_jnp = 0x47, + x8616_op_jno = 0x48, + x8616_op_jns = 0x49, + x8616_op_loop = 0x4A, + x8616_op_loopz = 0x4B, + x8616_op_loopnz = 0x4C, + x8616_op_jcxz = 0x4D, + x8616_op_int = 0x4E, + x8616_op_int3 = 0x4F, + x8616_op_into = 0x50, + x8616_op_iret = 0x51, + x8616_op_clc = 0x52, + x8616_op_cmc = 0x53, + x8616_op_stc = 0x54, + x8616_op_cld = 0x55, + x8616_op_std = 0x56, + x8616_op_cli = 0x57, + x8616_op_sti = 0x58, + x8616_op_hlt = 0x59, + x8616_op_wait = 0x5A, + x8616_op_lock = 0x5B, + x8616_op_segment = 0x5C, +}; + +typedef Enum_(U1, X8616_Operand) { + x8616_operand_none = 0x00, + x8616_operand_rm = 0x01, + x8616_operand_reg_modrm = 0x02, + x8616_operand_reg_opcode = 0x03, + x8616_operand_segment_modrm = 0x04, + x8616_operand_segment_opcode = 0x05, + x8616_operand_acc = 0x06, + x8616_operand_imm = 0x07, + x8616_operand_imm8 = 0x08, + x8616_operand_imm16 = 0x09, + x8616_operand_mem_direct = 0x0A, + x8616_operand_rel8 = 0x0B, + x8616_operand_rel16 = 0x0C, + x8616_operand_far_ptr = 0x0D, + x8616_operand_dx = 0x0E, + x8616_operand_shift_count = 0x0F, +}; + +typedef Enum_(U1, X8616_WidthMode) { + x8616_width_dynamic = 0x0, + x8616_width_byte = 0x1, + x8616_width_word = 0x2, +}; + +typedef Enum_(U1, X8616_EncodingFlags) { + x8616_encoding_none = 0b00000000, + x8616_encoding_far = 0b00000001, + x8616_encoding_prefix = 0b00000010, +}; + +/* mod_rm (Optional): Fixed constraint on the ModR/M byte. + post_opcode (Optional): Fixed byte immediately following the opcode. + fields: Variable fields carried by the opcode byte. width == 0: field is absent. + operands: Operand order describes d == 0. + If d exists and decodes to 1, operands[0] and operands[1] are swapped. + width: Explicit width only when the encoding has no w field. + flags: Encoding metadata not represented by an explicit operand. */ +typedef Struct_(X8616_Encoding) { + X8616_BytePattern opcode; + X8616_BytePattern mod_rm; + X8616_BytePattern post_opcode; + X8616_OpcodeFields fields; + X8616_Operand operands[2]; + X8616_WidthMode width; + X8616_EncodingFlags flags; + X8616_Op op; +}; + +typedef Enum_(U1, X8616_Width) { + x8616_w_byte = 0b0, + x8616_w_word = 0b1, +}; + +typedef Enum_(U1, X8616_Direction) { + x8616_d_rm_dst = 0b0, + x8616_d_reg_dst = 0b1, + x8616_d_acc_dst = 0b0, + x8616_d_mem_dst = 0b1, + x8616_d_seg_dst = 0b1, +}; + +typedef Enum_(U1, X8616_Sign) { + x8616_s_full = 0b0, + x8616_s_extend = 0b1, +}; + +typedef Enum_(U1, X8616_VariableShift) { + x8616_v_one = 0b0, + x8616_v_cl = 0b1, +}; + +typedef Enum_(U1, X8616_Repeat) { + x8616_repne = 0b0, + x8616_rep = 0b1, +}; + +typedef Enum_(U1, X8616_Mod) { + x8616_mod_mem = 0b00, + x8616_mod_mem_d8 = 0b01, + x8616_mod_mem_d16 = 0b10, + x8616_mod_reg = 0b11, +}; + +typedef Enum_(U1, X8616_Reg8) { + x8616_al = 0b000, + x8616_cl = 0b001, + x8616_dl = 0b010, + x8616_bl = 0b011, + x8616_ah = 0b100, + x8616_ch = 0b101, + x8616_dh = 0b110, + x8616_bh = 0b111, +}; + +typedef Enum_(U1, X8616_Reg16) { + x8616_ax = 0b000, + x8616_cx = 0b001, + x8616_dx = 0b010, + x8616_bx = 0b011, + x8616_sp = 0b100, + x8616_bp = 0b101, + x8616_si = 0b110, + x8616_di = 0b111, +}; + +typedef Enum_(U1, X8616_Segment) { + x8616_es = 0b00, + x8616_cs = 0b01, + x8616_ss = 0b10, + x8616_ds = 0b11, +}; + +typedef Enum_(U1, X8616_EA) { + x8616_ea_bx_si = 0b000, + x8616_ea_bx_di = 0b001, + x8616_ea_bp_si = 0b010, + x8616_ea_bp_di = 0b011, + x8616_ea_si = 0b100, + x8616_ea_di = 0b101, + x8616_ea_bp = 0b110, // mod 01/10 + x8616_ea_direct = 0b110, // mod 00 + x8616_ea_bx = 0b111, +}; + +typedef Enum_(U1, X8616_ALU) { + x8616_add = 0b000, + x8616_or = 0b001, + x8616_adc = 0b010, + x8616_sbb = 0b011, + x8616_and = 0b100, + x8616_sub = 0b101, + x8616_xor = 0b110, + x8616_cmp = 0b111, +}; + +typedef Enum_(U1, X8616_Group3) { + x8616_g3_test = 0b000, + x8616_g3_not = 0b010, + x8616_g3_neg = 0b011, + x8616_g3_mul = 0b100, + x8616_g3_imul = 0b101, + x8616_g3_div = 0b110, + x8616_g3_idiv = 0b111, +}; + +typedef Enum_(U1, X8616_IncDec) { + x8616_inc = 0b000, + x8616_dec = 0b001, +}; + +typedef Enum_(U1, X8616_GroupFF) { + x8616_ff_call_near = 0b010, + x8616_ff_call_far = 0b011, + x8616_ff_jmp_near = 0b100, + x8616_ff_jmp_far = 0b101, + x8616_ff_push = 0b110, +}; + +typedef Enum_(U1, X8616_Shift) { + x8616_rol = 0b000, + x8616_ror = 0b001, + x8616_rcl = 0b010, + x8616_rcr = 0b011, + x8616_shl = 0b100, + x8616_shr = 0b101, + x8616_sar = 0b111, +}; + +typedef Enum_(U1, X8616_Condition) { + x8616_cc_o = 0b0000, + x8616_cc_no = 0b0001, + x8616_cc_b = 0b0010, + x8616_cc_nb = 0b0011, + x8616_cc_e = 0b0100, + x8616_cc_ne = 0b0101, + x8616_cc_be = 0b0110, + x8616_cc_a = 0b0111, + x8616_cc_s = 0b1000, + x8616_cc_ns = 0b1001, + x8616_cc_p = 0b1010, + x8616_cc_np = 0b1011, + x8616_cc_l = 0b1100, + x8616_cc_nl = 0b1101, + x8616_cc_le = 0b1110, + x8616_cc_g = 0b1111, +}; + +typedef Enum_(U1, X8616_OpcodePrefix) { + x8616_opcode_mov_rm_r = 0b100010, + x8616_opcode_mov_rm_i = 0b1100011, + x8616_opcode_mov_r_i = 0b1011, + x8616_opcode_mov_acc_mem = 0b101000, + x8616_opcode_mov_seg_rm = 0b100011, + + x8616_opcode_push_reg = 0b01010, + x8616_opcode_pop_reg = 0b01011, + x8616_opcode_xchg_rm_r = 0b1000011, + x8616_opcode_xchg_ax_reg = 0b10010, + + x8616_opcode_in_i = 0b1110010, + x8616_opcode_in_dx = 0b1110110, + x8616_opcode_out_i = 0b1110011, + x8616_opcode_out_dx = 0b1110111, + + x8616_opcode_alu_rm_i = 0b100000, + x8616_opcode_logic_rm_i = 0b1000000, + x8616_opcode_incdec_rm = 0b1111111, + x8616_opcode_inc_reg = 0b01000, + x8616_opcode_dec_reg = 0b01001, + x8616_opcode_group3 = 0b1111011, + x8616_opcode_shift_rm = 0b110100, + x8616_opcode_test_rm_r = 0b1000010, + x8616_opcode_test_acc_i = 0b1010100, + + x8616_opcode_rep = 0b1111001, + x8616_opcode_movs = 0b1010010, + x8616_opcode_cmps = 0b1010011, + x8616_opcode_scas = 0b1010111, + x8616_opcode_lods = 0b1010110, + x8616_opcode_stos = 0b1010101, + + x8616_opcode_jcc = 0b0111, +}; + +typedef Enum_(U1, X8616_Opcode) { + x8616_opcode_group_ff = 0b11111111, + x8616_opcode_pop_rm = 0b10001111, + x8616_opcode_xlat = 0b11010111, + x8616_opcode_lea = 0b10001101, + x8616_opcode_lds = 0b11000101, + x8616_opcode_les = 0b11000100, + x8616_opcode_lahf = 0b10011111, + x8616_opcode_sahf = 0b10011110, + x8616_opcode_pushf = 0b10011100, + x8616_opcode_popf = 0b10011101, + + x8616_opcode_aaa = 0b00110111, + x8616_opcode_daa = 0b00100111, + x8616_opcode_aas = 0b00111111, + x8616_opcode_das = 0b00101111, + x8616_opcode_aam = 0b11010100, + x8616_opcode_aad = 0b11010101, + x8616_opcode_cbw = 0b10011000, + x8616_opcode_cwd = 0b10011001, + + x8616_opcode_call_rel16 = 0b11101000, + x8616_opcode_call_far = 0b10011010, + x8616_opcode_jmp_rel16 = 0b11101001, + x8616_opcode_jmp_rel8 = 0b11101011, + x8616_opcode_jmp_far = 0b11101010, + x8616_opcode_ret = 0b11000011, + x8616_opcode_ret_i = 0b11000010, + x8616_opcode_retf = 0b11001011, + x8616_opcode_retf_i = 0b11001010, + + x8616_opcode_loopnz = 0b11100000, + x8616_opcode_loopz = 0b11100001, + x8616_opcode_loop = 0b11100010, + x8616_opcode_jcxz = 0b11100011, + + x8616_opcode_int = 0b11001101, + x8616_opcode_int3 = 0b11001100, + x8616_opcode_into = 0b11001110, + x8616_opcode_iret = 0b11001111, + + x8616_opcode_clc = 0b11111000, + x8616_opcode_cmc = 0b11110101, + x8616_opcode_stc = 0b11111001, + x8616_opcode_cld = 0b11111100, + x8616_opcode_std = 0b11111101, + x8616_opcode_cli = 0b11111010, + x8616_opcode_sti = 0b11111011, + x8616_opcode_hlt = 0b11110100, + x8616_opcode_wait = 0b10011011, + x8616_opcode_lock = 0b11110000, + + x8616_opcode_nop = 0b10010000, +}; + +enum { + X8616_OPCODE_MASK = 0b11111111, + + X8616_OPCODE_ALU_ACC_I_FIXED = 0b10, + X8616_POST_OPCODE_AAM_AAD = 0b00001010, + +// ModR/M: +// 7 6 5 4 3 2 1 0 +// +-----+-------+-------+ +// | mod | reg | r/m | +// +-----+-------+-------+ + + X8616_MODRM_RM_SHIFT = 0, + X8616_MODRM_REG_SHIFT = 3, + X8616_MODRM_MOD_SHIFT = 6, + X8616_MODRM_RM_MASK = 0b00000111, + X8616_MODRM_REG_MASK = 0b00111000, + X8616_MODRM_MOD_MASK = 0b11000000, + +// Segment register occupies bits 4..3 in the segment-register MOV form. + + X8616_MODRM_SR_SHIFT = 3, + X8616_MODRM_SR_MASK = 0b00011000, + X8616_MODRM_SEG_FIXED_MASK = 0b00100000, + +// ... d w + + X8616_OPCODE_DW_W_SHIFT = 0, + X8616_OPCODE_DW_D_SHIFT = 1, + X8616_OPCODE_DW_PREFIX_SHIFT = X8616_OPCODE_DW_D_SHIFT + 1, + X8616_OPCODE_DW_PREFIX_MASK = 0b11111100, + +// ... s w + + X8616_OPCODE_SW_W_SHIFT = 0, + X8616_OPCODE_SW_S_SHIFT = 1, + X8616_OPCODE_SW_PREFIX_SHIFT = X8616_OPCODE_SW_S_SHIFT + 1, + X8616_OPCODE_SW_PREFIX_MASK = 0b11111100, + +// ... v w + + X8616_OPCODE_VW_W_SHIFT = 0, + X8616_OPCODE_VW_V_SHIFT = 1, + X8616_OPCODE_VW_PREFIX_SHIFT = X8616_OPCODE_VW_V_SHIFT + 1, + X8616_OPCODE_VW_PREFIX_MASK = 0b11111100, + +// ... z + + X8616_OPCODE_Z_Z_SHIFT = 0, + X8616_OPCODE_Z_PREFIX_SHIFT = X8616_OPCODE_Z_Z_SHIFT + 1, + X8616_OPCODE_Z_PREFIX_MASK = 0b11111110, + +// ... w + + X8616_OPCODE_W_W_SHIFT = 0, + X8616_OPCODE_W_PREFIX_SHIFT = X8616_OPCODE_W_W_SHIFT + 1, + X8616_OPCODE_W_PREFIX_MASK = 0b11111110, + +// ... reg + + X8616_OPCODE_REG_REG_SHIFT = 0, + X8616_OPCODE_REG_REG_WIDTH = 3, + X8616_OPCODE_REG_REG_MASK = 0b00000111, + X8616_OPCODE_REG_PREFIX_SHIFT = X8616_OPCODE_REG_REG_SHIFT + X8616_OPCODE_REG_REG_WIDTH, + X8616_OPCODE_REG_PREFIX_MASK = 0b11111000, + +// ... w reg + + X8616_OPCODE_WREG_REG_SHIFT = 0, + X8616_OPCODE_WREG_REG_WIDTH = 3, + X8616_OPCODE_WREG_REG_MASK = 0b00000111, + X8616_OPCODE_WREG_W_SHIFT = X8616_OPCODE_WREG_REG_SHIFT + X8616_OPCODE_WREG_REG_WIDTH, + X8616_OPCODE_WREG_W_MASK = 0b00001000, + X8616_OPCODE_WREG_PREFIX_SHIFT = X8616_OPCODE_WREG_W_SHIFT + 1, + X8616_OPCODE_WREG_PREFIX_MASK = 0b11110000, + +// ... d 0 + + X8616_OPCODE_D0_D_SHIFT = 1, + X8616_OPCODE_D0_PREFIX_SHIFT = X8616_OPCODE_D0_D_SHIFT + 1, + X8616_OPCODE_D0_PREFIX_MASK = 0b11111101, + +// xxx sr xxx + + X8616_OPCODE_SR_SHIFT = 3, + X8616_OPCODE_SR_WIDTH = 2, + X8616_OPCODE_SR_MASK = 0b00011000, + X8616_OPCODE_SR_PATTERN_MASK = 0b11100111, + X8616_OPCODE_PUSH_SR_FIXED = 0b00000110, + X8616_OPCODE_POP_SR_FIXED = 0b00000111, + X8616_OPCODE_SEG_FIXED = 0b00100110, + +// 0111 cccc + + X8616_OPCODE_CC_SHIFT = 0, + X8616_OPCODE_CC_WIDTH = 4, + X8616_OPCODE_CC_MASK = 0b00001111, + X8616_OPCODE_CC_PREFIX_SHIFT = X8616_OPCODE_CC_WIDTH, + +// 00 op ... + + X8616_OPCODE_ALU_OP_SHIFT = 3, +}; + +// ============================================================================ +// Encoding Helpers + +FI_ U1 x8616_byte_pattern_matches(U1 byte, X8616_BytePattern pattern) { return (byte & pattern.mask) == pattern.bits; } +FI_ U1 x8616_bit_field_exists (X8616_BitField field) { return field.width != 0; } +FI_ U1 x8616_bit_field_extract (U1 byte, X8616_BitField field) { return (byte >> field.shift) & u1_((1u << field.width) - 1u); } +FI_ U1 x8616_modrm_rm (U1 modrm) { return (modrm & X8616_MODRM_RM_MASK) >> X8616_MODRM_RM_SHIFT; } +FI_ U1 x8616_modrm_reg (U1 modrm) { return (modrm & X8616_MODRM_REG_MASK) >> X8616_MODRM_REG_SHIFT; } +FI_ U1 x8616_modrm_mod (U1 modrm) { return (modrm & X8616_MODRM_MOD_MASK) >> X8616_MODRM_MOD_SHIFT; } +FI_ U1 x8616_modrm_sr (U1 modrm) { return (modrm & X8616_MODRM_SR_MASK) >> X8616_MODRM_SR_SHIFT; } + +// ============================================================================ +// Emission DSL +// `enc_*` produces one encoded byte. +// `emit_*` expands to one or more comma-separated bytes. +// +// Intended use: +// RO_ global U1 code[] = { +// x8616_mov_r16_i(x8616_ax, 0x1234), +// x8616_mov_r16_r16(x8616_bx, x8616_ax), +// x8616_add_r16_r16(x8616_ax, x8616_bx), +// x8616_jne(-4), +// }; +// ============================================================================ + +// Byte fields + +#define x8616_enc_dw_prefix(prefix) ((prefix) << X8616_OPCODE_DW_PREFIX_SHIFT) +#define x8616_enc_sw_prefix(prefix) ((prefix) << X8616_OPCODE_SW_PREFIX_SHIFT) +#define x8616_enc_vw_prefix(prefix) ((prefix) << X8616_OPCODE_VW_PREFIX_SHIFT) +#define x8616_enc_z_prefix(prefix) ((prefix) << X8616_OPCODE_Z_PREFIX_SHIFT) +#define x8616_enc_w_prefix(prefix) ((prefix) << X8616_OPCODE_W_PREFIX_SHIFT) +#define x8616_enc_reg_prefix(prefix) ((prefix) << X8616_OPCODE_REG_PREFIX_SHIFT) +#define x8616_enc_wreg_prefix(prefix) ((prefix) << X8616_OPCODE_WREG_PREFIX_SHIFT) +#define x8616_enc_d0_prefix(prefix) ((prefix) << X8616_OPCODE_D0_PREFIX_SHIFT) + +#define x8616_enc_d(d) ((d) << X8616_OPCODE_DW_D_SHIFT) +#define x8616_enc_s(s) ((s) << X8616_OPCODE_SW_S_SHIFT) +#define x8616_enc_v(v) ((v) << X8616_OPCODE_VW_V_SHIFT) +#define x8616_enc_z(z) ((z) << X8616_OPCODE_Z_Z_SHIFT) +#define x8616_enc_width(w) ((w) << X8616_OPCODE_W_W_SHIFT) +#define x8616_enc_wreg_width(w) ((w) << X8616_OPCODE_WREG_W_SHIFT) +#define x8616_enc_opcode_reg(r) ((r) << X8616_OPCODE_REG_REG_SHIFT) +#define x8616_enc_opcode_sr(sr) ((sr) << X8616_OPCODE_SR_SHIFT) +#define x8616_enc_cc(cc) ((cc) << X8616_OPCODE_CC_SHIFT) + +#define x8616_enc_modrm_mod(mod) ((mod) << X8616_MODRM_MOD_SHIFT) +#define x8616_enc_modrm_reg(reg) ((reg) << X8616_MODRM_REG_SHIFT) +#define x8616_enc_modrm_rm(rm) ((rm) << X8616_MODRM_RM_SHIFT) +#define x8616_enc_modrm_sr(sr) ((sr) << X8616_MODRM_SR_SHIFT) + +#define x8616_enc_dw(prefix,d,w) C_(U1, x8616_enc_dw_prefix(prefix) | x8616_enc_d(d) | x8616_enc_width(w)) +#define x8616_enc_sw(prefix,s,w) C_(U1, x8616_enc_sw_prefix(prefix) | x8616_enc_s(s) | x8616_enc_width(w)) +#define x8616_enc_vw(prefix,v,w) C_(U1, x8616_enc_vw_prefix(prefix) | x8616_enc_v(v) | x8616_enc_width(w)) +#define x8616_enc_zp(prefix,z) C_(U1, x8616_enc_z_prefix(prefix) | x8616_enc_z(z)) +#define x8616_enc_w(prefix,w) C_(U1, x8616_enc_w_prefix(prefix) | x8616_enc_width(w)) +#define x8616_enc_reg(prefix,reg) C_(U1, x8616_enc_reg_prefix(prefix) | x8616_enc_opcode_reg(reg)) +#define x8616_enc_wreg(prefix,w,reg) C_(U1, x8616_enc_wreg_prefix(prefix) | x8616_enc_wreg_width(w) | x8616_enc_opcode_reg(reg)) +#define x8616_enc_d0(prefix,d) C_(U1, x8616_enc_d0_prefix(prefix) | x8616_enc_d(d)) +#define x8616_enc_sr(fixed,sr) C_(U1, fixed | x8616_enc_opcode_sr(sr)) +#define x8616_enc_jcc(cc) C_(U1, (x8616_opcode_jcc << X8616_OPCODE_CC_PREFIX_SHIFT) | x8616_enc_cc(cc)) +#define x8616_enc_modrm(mod,reg,rm) C_(U1, x8616_enc_modrm_mod(mod) | x8616_enc_modrm_reg(reg) | x8616_enc_modrm_rm(rm)) +#define x8616_enc_modrm_seg(mod,sr,rm) C_(U1, x8616_enc_modrm_mod(mod) | x8616_enc_modrm_sr(sr) | x8616_enc_modrm_rm(rm)) + +#define x8616_enc_alu_op(alu) ((alu) << X8616_OPCODE_ALU_OP_SHIFT) +#define x8616_enc_alu_acc_i_fixed (X8616_OPCODE_ALU_ACC_I_FIXED << X8616_OPCODE_W_PREFIX_SHIFT) +#define x8616_enc_alu_rm_r(alu,d,w) C_(U1, x8616_enc_alu_op(alu) | x8616_enc_d(d) | x8616_enc_width(w)) +#define x8616_enc_alu_acc_i(alu,w) C_(U1, x8616_enc_alu_op(alu) | x8616_enc_alu_acc_i_fixed | x8616_enc_width(w)) + +// Scalar / generic packets + +#define x8616_emit_u2(value) u1_(u2_(value) >> 0), u1_(u2_(value) >> 8) +#define x8616_emit_s2(value) x8616_emit_u2(value) +#define x8616_emit_op(opcode) u1_(opcode) +#define x8616_emit_op_i8(opcode,imm) u1_(opcode), u1_(imm) +#define x8616_emit_op_i16(opcode,imm) u1_(opcode), x8616_emit_u2(imm) +#define x8616_emit_op_far(opcode,seg,off) u1_(opcode), x8616_emit_u2(off), x8616_emit_u2(seg) + +#define x8616_emit_modrm(opcode,mod,reg,rm) u1_(opcode), x8616_enc_modrm(mod,reg,rm) +#define x8616_emit_modrm_d8(opcode,reg,rm,disp) x8616_emit_modrm(opcode,x8616_mod_mem_d8,reg,rm), u1_(disp) +#define x8616_emit_modrm_d16(opcode,reg,rm,disp) x8616_emit_modrm(opcode,x8616_mod_mem_d16,reg,rm), x8616_emit_s2(disp) +#define x8616_emit_modrm_direct(opcode,reg,addr) x8616_emit_modrm(opcode,x8616_mod_mem,reg,x8616_ea_direct), x8616_emit_u2(addr) +#define x8616_emit_modrm_i8(opcode,mod,reg,rm,imm) x8616_emit_modrm(opcode,mod,reg,rm), u1_(imm) +#define x8616_emit_modrm_i16(opcode,mod,reg,rm,imm) x8616_emit_modrm(opcode,mod,reg,rm), x8616_emit_u2(imm) +#define x8616_emit_modrm_d8_i8(opcode,reg,rm,disp,imm) x8616_emit_modrm_d8(opcode,reg,rm,disp), u1_(imm) +#define x8616_emit_modrm_d8_i16(opcode,reg,rm,disp,imm) x8616_emit_modrm_d8(opcode,reg,rm,disp), x8616_emit_u2(imm) +#define x8616_emit_modrm_d16_i8(opcode,reg,rm,disp,imm) x8616_emit_modrm_d16(opcode,reg,rm,disp), u1_(imm) +#define x8616_emit_modrm_d16_i16(opcode,reg,rm,disp,imm) x8616_emit_modrm_d16(opcode,reg,rm,disp), x8616_emit_u2(imm) + +// r/m + register / immediate packets + +#define x8616_emit_rm_r(prefix,d,w,mod,reg,rm) x8616_enc_dw(prefix,d,w), x8616_enc_modrm(mod,reg,rm) +#define x8616_emit_rm_r_d8(prefix,d,w,reg,rm,disp) x8616_emit_rm_r(prefix,d,w,x8616_mod_mem_d8,reg,rm), u1_(disp) +#define x8616_emit_rm_r_d16(prefix,d,w,reg,rm,disp) x8616_emit_rm_r(prefix,d,w,x8616_mod_mem_d16,reg,rm), x8616_emit_s2(disp) +#define x8616_emit_rm_r_direct(prefix,d,w,reg,addr) x8616_emit_rm_r(prefix,d,w,x8616_mod_mem,reg,x8616_ea_direct), x8616_emit_u2(addr) + +#define x8616_emit_rm_i8_w(prefix,ext,mod,rm,imm) x8616_enc_w(prefix,x8616_w_byte), x8616_enc_modrm(mod,ext,rm), u1_(imm) +#define x8616_emit_rm_i16_w(prefix,ext,mod,rm,imm) x8616_enc_w(prefix,x8616_w_word), x8616_enc_modrm(mod,ext,rm), x8616_emit_u2(imm) +#define x8616_emit_rm_i8_w_d8(prefix,ext,rm,disp,imm) x8616_enc_w(prefix,x8616_w_byte), x8616_enc_modrm(x8616_mod_mem_d8,ext,rm), u1_(disp), u1_(imm) +#define x8616_emit_rm_i16_w_d8(prefix,ext,rm,disp,imm) x8616_enc_w(prefix,x8616_w_word), x8616_enc_modrm(x8616_mod_mem_d8,ext,rm), u1_(disp), x8616_emit_u2(imm) +#define x8616_emit_rm_i8_w_d16(prefix,ext,rm,disp,imm) x8616_enc_w(prefix,x8616_w_byte), x8616_enc_modrm(x8616_mod_mem_d16,ext,rm), x8616_emit_s2(disp), u1_(imm) +#define x8616_emit_rm_i16_w_d16(prefix,ext,rm,disp,imm) x8616_enc_w(prefix,x8616_w_word), x8616_enc_modrm(x8616_mod_mem_d16,ext,rm), x8616_emit_s2(disp), x8616_emit_u2(imm) + +#define x8616_emit_rm_i8(prefix,s,w,ext,mod,rm,imm) x8616_enc_sw(prefix,s,w), x8616_enc_modrm(mod,ext,rm), u1_(imm) +#define x8616_emit_rm_i16(prefix,ext,mod,rm,imm) x8616_enc_sw(prefix,x8616_s_full,x8616_w_word), x8616_enc_modrm(mod,ext,rm), x8616_emit_u2(imm) +#define x8616_emit_rm_i8_d8(prefix,s,w,ext,rm,disp,imm) x8616_enc_sw(prefix,s,w), x8616_enc_modrm(x8616_mod_mem_d8,ext,rm), u1_(disp), u1_(imm) +#define x8616_emit_rm_i16_d8(prefix,ext,rm,disp,imm) x8616_enc_sw(prefix,x8616_s_full,x8616_w_word), x8616_enc_modrm(x8616_mod_mem_d8,ext,rm), u1_(disp), x8616_emit_u2(imm) +#define x8616_emit_rm_i8_d16(prefix,s,w,ext,rm,disp,imm) x8616_enc_sw(prefix,s,w), x8616_enc_modrm(x8616_mod_mem_d16,ext,rm), x8616_emit_s2(disp), u1_(imm) +#define x8616_emit_rm_i16_d16(prefix,ext,rm,disp,imm) x8616_enc_sw(prefix,x8616_s_full,x8616_w_word), x8616_enc_modrm(x8616_mod_mem_d16,ext,rm), x8616_emit_s2(disp), x8616_emit_u2(imm) + +// Segment-register packet + +#define x8616_emit_seg_rm(d,mod,sr,rm) x8616_enc_d0(x8616_opcode_mov_seg_rm,d), x8616_enc_modrm_seg(mod,sr,rm) +#define x8616_emit_seg_rm_d8(d,sr,rm,disp) x8616_emit_seg_rm(d,x8616_mod_mem_d8,sr,rm), u1_(disp) +#define x8616_emit_seg_rm_d16(d,sr,rm,disp) x8616_emit_seg_rm(d,x8616_mod_mem_d16,sr,rm), x8616_emit_s2(disp) +#define x8616_emit_seg_rm_direct(d,sr,addr) x8616_emit_seg_rm(d,x8616_mod_mem,sr,x8616_ea_direct), x8616_emit_u2(addr) + +// MOV + +#define x8616_nop() x8616_emit_op(x8616_opcode_nop) +#define x8616_mov_r8_r8(dst,src) x8616_emit_rm_r(x8616_opcode_mov_rm_r,x8616_d_reg_dst,x8616_w_byte,x8616_mod_reg,dst,src) +#define x8616_mov_r16_r16(dst,src) x8616_emit_rm_r(x8616_opcode_mov_rm_r,x8616_d_reg_dst,x8616_w_word,x8616_mod_reg,dst,src) +#define x8616_mov_r8_i(dst,imm) x8616_enc_wreg(x8616_opcode_mov_r_i,x8616_w_byte,dst), u1_(imm) +#define x8616_mov_r16_i(dst,imm) x8616_enc_wreg(x8616_opcode_mov_r_i,x8616_w_word,dst), x8616_emit_u2(imm) +#define x8616_mov_al_moffs(addr) x8616_enc_dw(x8616_opcode_mov_acc_mem,x8616_d_acc_dst,x8616_w_byte), x8616_emit_u2(addr) +#define x8616_mov_ax_moffs(addr) x8616_enc_dw(x8616_opcode_mov_acc_mem,x8616_d_acc_dst,x8616_w_word), x8616_emit_u2(addr) +#define x8616_mov_moffs_al(addr) x8616_enc_dw(x8616_opcode_mov_acc_mem,x8616_d_mem_dst,x8616_w_byte), x8616_emit_u2(addr) +#define x8616_mov_moffs_ax(addr) x8616_enc_dw(x8616_opcode_mov_acc_mem,x8616_d_mem_dst,x8616_w_word), x8616_emit_u2(addr) +#define x8616_mov_rm_seg(mod,rm,sr) x8616_emit_seg_rm(x8616_d_rm_dst,mod,sr,rm) +#define x8616_mov_seg_rm(sr,mod,rm) x8616_emit_seg_rm(x8616_d_seg_dst,mod,sr,rm) + +// Stack / exchange + +#define x8616_push_r16(reg) x8616_enc_reg(x8616_opcode_push_reg,reg) +#define x8616_pop_r16(reg) x8616_enc_reg(x8616_opcode_pop_reg,reg) +#define x8616_push_seg(seg) x8616_enc_sr(X8616_OPCODE_PUSH_SR_FIXED,seg) +#define x8616_pop_seg(seg) x8616_enc_sr(X8616_OPCODE_POP_SR_FIXED,seg) +#define x8616_push_rm(mod,rm) x8616_emit_modrm(x8616_opcode_group_ff,mod,x8616_ff_push,rm) +#define x8616_pop_rm(mod,rm) x8616_emit_modrm(x8616_opcode_pop_rm,mod,0b000,rm) + +#define x8616_xchg_r8_r8(a,b) x8616_enc_w(x8616_opcode_xchg_rm_r,x8616_w_byte), x8616_enc_modrm(x8616_mod_reg,a,b) +#define x8616_xchg_r16_r16(a,b) x8616_enc_w(x8616_opcode_xchg_rm_r,x8616_w_word), x8616_enc_modrm(x8616_mod_reg,a,b) +#define x8616_xchg_ax_r16(reg) x8616_enc_reg(x8616_opcode_xchg_ax_reg,reg) + +// I/O / address load + +#define x8616_in_al_i(port) x8616_enc_w(x8616_opcode_in_i,x8616_w_byte), u1_(port) +#define x8616_in_ax_i(port) x8616_enc_w(x8616_opcode_in_i,x8616_w_word), u1_(port) +#define x8616_in_al_dx() x8616_enc_w(x8616_opcode_in_dx,x8616_w_byte) +#define x8616_in_ax_dx() x8616_enc_w(x8616_opcode_in_dx,x8616_w_word) +#define x8616_out_i_al(port) x8616_enc_w(x8616_opcode_out_i,x8616_w_byte), u1_(port) +#define x8616_out_i_ax(port) x8616_enc_w(x8616_opcode_out_i,x8616_w_word), u1_(port) +#define x8616_out_dx_al() x8616_enc_w(x8616_opcode_out_dx,x8616_w_byte) +#define x8616_out_dx_ax() x8616_enc_w(x8616_opcode_out_dx,x8616_w_word) + +#define x8616_xlat() x8616_emit_op(x8616_opcode_xlat) +#define x8616_lea(reg,mod,rm) x8616_emit_modrm(x8616_opcode_lea,mod,reg,rm) +#define x8616_lds(reg,mod,rm) x8616_emit_modrm(x8616_opcode_lds,mod,reg,rm) +#define x8616_les(reg,mod,rm) x8616_emit_modrm(x8616_opcode_les,mod,reg,rm) +#define x8616_lahf() x8616_emit_op(x8616_opcode_lahf) +#define x8616_sahf() x8616_emit_op(x8616_opcode_sahf) +#define x8616_pushf() x8616_emit_op(x8616_opcode_pushf) +#define x8616_popf() x8616_emit_op(x8616_opcode_popf) + +// Arithmetic / logical + +#define x8616_emit_alu_r8_r8(alu,dst,src) x8616_enc_alu_rm_r(alu,x8616_d_reg_dst,x8616_w_byte), x8616_enc_modrm(x8616_mod_reg,dst,src) +#define x8616_emit_alu_r16_r16(alu,dst,src) x8616_enc_alu_rm_r(alu,x8616_d_reg_dst,x8616_w_word), x8616_enc_modrm(x8616_mod_reg,dst,src) +#define x8616_emit_alu_r8_i(alu,dst,imm) x8616_emit_rm_i8(x8616_opcode_alu_rm_i,x8616_s_full,x8616_w_byte,alu,x8616_mod_reg,dst,imm) +#define x8616_emit_alu_r16_i(alu,dst,imm) x8616_emit_rm_i16(x8616_opcode_alu_rm_i,alu,x8616_mod_reg,dst,imm) +#define x8616_emit_alu_r16_i8s(alu,dst,imm) x8616_emit_rm_i8(x8616_opcode_alu_rm_i,x8616_s_extend,x8616_w_word,alu,x8616_mod_reg,dst,imm) +#define x8616_emit_logic_r8_i(alu,dst,imm) x8616_emit_rm_i8_w(x8616_opcode_logic_rm_i,alu,x8616_mod_reg,dst,imm) +#define x8616_emit_logic_r16_i(alu,dst,imm) x8616_emit_rm_i16_w(x8616_opcode_logic_rm_i,alu,x8616_mod_reg,dst,imm) +#define x8616_emit_alu_al_i(alu,imm) x8616_enc_alu_acc_i(alu,x8616_w_byte), u1_(imm) +#define x8616_emit_alu_ax_i(alu,imm) x8616_enc_alu_acc_i(alu,x8616_w_word), x8616_emit_u2(imm) + +#define x8616_add_r8_r8(dst,src) x8616_emit_alu_r8_r8(x8616_add,dst,src) +#define x8616_add_r16_r16(dst,src) x8616_emit_alu_r16_r16(x8616_add,dst,src) +#define x8616_or_r8_r8(dst,src) x8616_emit_alu_r8_r8(x8616_or,dst,src) +#define x8616_or_r16_r16(dst,src) x8616_emit_alu_r16_r16(x8616_or,dst,src) +#define x8616_adc_r8_r8(dst,src) x8616_emit_alu_r8_r8(x8616_adc,dst,src) +#define x8616_adc_r16_r16(dst,src) x8616_emit_alu_r16_r16(x8616_adc,dst,src) +#define x8616_sbb_r8_r8(dst,src) x8616_emit_alu_r8_r8(x8616_sbb,dst,src) +#define x8616_sbb_r16_r16(dst,src) x8616_emit_alu_r16_r16(x8616_sbb,dst,src) +#define x8616_and_r8_r8(dst,src) x8616_emit_alu_r8_r8(x8616_and,dst,src) +#define x8616_and_r16_r16(dst,src) x8616_emit_alu_r16_r16(x8616_and,dst,src) +#define x8616_sub_r8_r8(dst,src) x8616_emit_alu_r8_r8(x8616_sub,dst,src) +#define x8616_sub_r16_r16(dst,src) x8616_emit_alu_r16_r16(x8616_sub,dst,src) +#define x8616_xor_r8_r8(dst,src) x8616_emit_alu_r8_r8(x8616_xor,dst,src) +#define x8616_xor_r16_r16(dst,src) x8616_emit_alu_r16_r16(x8616_xor,dst,src) +#define x8616_cmp_r8_r8(dst,src) x8616_emit_alu_r8_r8(x8616_cmp,dst,src) +#define x8616_cmp_r16_r16(dst,src) x8616_emit_alu_r16_r16(x8616_cmp,dst,src) + +#define x8616_add_r8_i(dst,imm) x8616_emit_alu_r8_i(x8616_add,dst,imm) +#define x8616_add_r16_i(dst,imm) x8616_emit_alu_r16_i(x8616_add,dst,imm) +#define x8616_add_r16_i8s(dst,imm) x8616_emit_alu_r16_i8s(x8616_add,dst,imm) +#define x8616_or_r8_i(dst,imm) x8616_emit_logic_r8_i(x8616_or,dst,imm) +#define x8616_or_r16_i(dst,imm) x8616_emit_logic_r16_i(x8616_or,dst,imm) +#define x8616_adc_r8_i(dst,imm) x8616_emit_alu_r8_i(x8616_adc,dst,imm) +#define x8616_adc_r16_i(dst,imm) x8616_emit_alu_r16_i(x8616_adc,dst,imm) +#define x8616_adc_r16_i8s(dst,imm) x8616_emit_alu_r16_i8s(x8616_adc,dst,imm) +#define x8616_sbb_r8_i(dst,imm) x8616_emit_alu_r8_i(x8616_sbb,dst,imm) +#define x8616_sbb_r16_i(dst,imm) x8616_emit_alu_r16_i(x8616_sbb,dst,imm) +#define x8616_sbb_r16_i8s(dst,imm) x8616_emit_alu_r16_i8s(x8616_sbb,dst,imm) +#define x8616_and_r8_i(dst,imm) x8616_emit_logic_r8_i(x8616_and,dst,imm) +#define x8616_and_r16_i(dst,imm) x8616_emit_logic_r16_i(x8616_and,dst,imm) +#define x8616_sub_r8_i(dst,imm) x8616_emit_alu_r8_i(x8616_sub,dst,imm) +#define x8616_sub_r16_i(dst,imm) x8616_emit_alu_r16_i(x8616_sub,dst,imm) +#define x8616_sub_r16_i8s(dst,imm) x8616_emit_alu_r16_i8s(x8616_sub,dst,imm) +#define x8616_xor_r8_i(dst,imm) x8616_emit_logic_r8_i(x8616_xor,dst,imm) +#define x8616_xor_r16_i(dst,imm) x8616_emit_logic_r16_i(x8616_xor,dst,imm) +#define x8616_cmp_r8_i(dst,imm) x8616_emit_alu_r8_i(x8616_cmp,dst,imm) +#define x8616_cmp_r16_i(dst,imm) x8616_emit_alu_r16_i(x8616_cmp,dst,imm) +#define x8616_cmp_r16_i8s(dst,imm) x8616_emit_alu_r16_i8s(x8616_cmp,dst,imm) + +// INC / DEC / unary + +#define x8616_inc_r16(reg) x8616_enc_reg(x8616_opcode_inc_reg,reg) +#define x8616_dec_r16(reg) x8616_enc_reg(x8616_opcode_dec_reg,reg) +#define x8616_inc_rm(w,mod,rm) x8616_emit_modrm(x8616_enc_w(x8616_opcode_incdec_rm,w),mod,x8616_inc,rm) +#define x8616_dec_rm(w,mod,rm) x8616_emit_modrm(x8616_enc_w(x8616_opcode_incdec_rm,w),mod,x8616_dec,rm) + +#define x8616_unary_rm(ext,w,mod,rm) x8616_emit_modrm(x8616_enc_w(x8616_opcode_group3,w),mod,ext,rm) +#define x8616_not_rm(w,mod,rm) x8616_unary_rm(x8616_g3_not,w,mod,rm) +#define x8616_neg_rm(w,mod,rm) x8616_unary_rm(x8616_g3_neg,w,mod,rm) +#define x8616_mul_rm(w,mod,rm) x8616_unary_rm(x8616_g3_mul,w,mod,rm) +#define x8616_imul_rm(w,mod,rm) x8616_unary_rm(x8616_g3_imul,w,mod,rm) +#define x8616_div_rm(w,mod,rm) x8616_unary_rm(x8616_g3_div,w,mod,rm) +#define x8616_idiv_rm(w,mod,rm) x8616_unary_rm(x8616_g3_idiv,w,mod,rm) + +#define x8616_aaa() x8616_emit_op(x8616_opcode_aaa) +#define x8616_daa() x8616_emit_op(x8616_opcode_daa) +#define x8616_aas() x8616_emit_op(x8616_opcode_aas) +#define x8616_das() x8616_emit_op(x8616_opcode_das) +#define x8616_aam() x8616_emit_op_i8(x8616_opcode_aam,X8616_POST_OPCODE_AAM_AAD) +#define x8616_aad() x8616_emit_op_i8(x8616_opcode_aad,X8616_POST_OPCODE_AAM_AAD) +#define x8616_cbw() x8616_emit_op(x8616_opcode_cbw) +#define x8616_cwd() x8616_emit_op(x8616_opcode_cwd) + +// Shift / rotate / TEST + +#define x8616_shift_rm(shift,v,w,mod,rm) x8616_emit_modrm(x8616_enc_vw(x8616_opcode_shift_rm,v,w),mod,shift,rm) +#define x8616_shl_r8_1(reg) x8616_shift_rm(x8616_shl,x8616_v_one,x8616_w_byte,x8616_mod_reg,reg) +#define x8616_shl_r16_1(reg) x8616_shift_rm(x8616_shl,x8616_v_one,x8616_w_word,x8616_mod_reg,reg) +#define x8616_shl_r8_cl(reg) x8616_shift_rm(x8616_shl,x8616_v_cl,x8616_w_byte,x8616_mod_reg,reg) +#define x8616_shl_r16_cl(reg) x8616_shift_rm(x8616_shl,x8616_v_cl,x8616_w_word,x8616_mod_reg,reg) + +#define x8616_test_r8_r8(a,b) x8616_enc_w(x8616_opcode_test_rm_r,x8616_w_byte), x8616_enc_modrm(x8616_mod_reg,b,a) +#define x8616_test_r16_r16(a,b) x8616_enc_w(x8616_opcode_test_rm_r,x8616_w_word), x8616_enc_modrm(x8616_mod_reg,b,a) +#define x8616_test_r8_i(reg,imm) x8616_emit_modrm_i8(x8616_enc_w(x8616_opcode_group3,x8616_w_byte),x8616_mod_reg,x8616_g3_test,reg,imm) +#define x8616_test_r16_i(reg,imm) x8616_emit_modrm_i16(x8616_enc_w(x8616_opcode_group3,x8616_w_word),x8616_mod_reg,x8616_g3_test,reg,imm) +#define x8616_test_al_i(imm) x8616_enc_w(x8616_opcode_test_acc_i,x8616_w_byte), u1_(imm) +#define x8616_test_ax_i(imm) x8616_enc_w(x8616_opcode_test_acc_i,x8616_w_word), x8616_emit_u2(imm) + +// String / prefixes + +#define x8616_rep_prefix() x8616_enc_zp(x8616_opcode_rep,x8616_rep) +#define x8616_repne_prefix() x8616_enc_zp(x8616_opcode_rep,x8616_repne) +#define x8616_movsb() x8616_enc_w(x8616_opcode_movs,x8616_w_byte) +#define x8616_movsw() x8616_enc_w(x8616_opcode_movs,x8616_w_word) +#define x8616_cmpsb() x8616_enc_w(x8616_opcode_cmps,x8616_w_byte) +#define x8616_cmpsw() x8616_enc_w(x8616_opcode_cmps,x8616_w_word) +#define x8616_scasb() x8616_enc_w(x8616_opcode_scas,x8616_w_byte) +#define x8616_scasw() x8616_enc_w(x8616_opcode_scas,x8616_w_word) +#define x8616_lodsb() x8616_enc_w(x8616_opcode_lods,x8616_w_byte) +#define x8616_lodsw() x8616_enc_w(x8616_opcode_lods,x8616_w_word) +#define x8616_stosb() x8616_enc_w(x8616_opcode_stos,x8616_w_byte) +#define x8616_stosw() x8616_enc_w(x8616_opcode_stos,x8616_w_word) +#define x8616_lock_prefix() x8616_emit_op(x8616_opcode_lock) +#define x8616_segment_prefix(seg) x8616_enc_sr(X8616_OPCODE_SEG_FIXED,seg) + +// Control transfer + +#define x8616_call_rel16(rel) x8616_emit_op_i16(x8616_opcode_call_rel16,rel) +#define x8616_call_far(seg,off) x8616_emit_op_far(x8616_opcode_call_far,seg,off) +#define x8616_call_rm(mod,rm) x8616_emit_modrm(x8616_opcode_group_ff,mod,x8616_ff_call_near,rm) +#define x8616_call_far_rm(mod,rm) x8616_emit_modrm(x8616_opcode_group_ff,mod,x8616_ff_call_far,rm) + +#define x8616_jmp_rel16(rel) x8616_emit_op_i16(x8616_opcode_jmp_rel16,rel) +#define x8616_jmp_rel8(rel) x8616_emit_op_i8(x8616_opcode_jmp_rel8,rel) +#define x8616_jmp_far(seg,off) x8616_emit_op_far(x8616_opcode_jmp_far,seg,off) +#define x8616_jmp_rm(mod,rm) x8616_emit_modrm(x8616_opcode_group_ff,mod,x8616_ff_jmp_near,rm) +#define x8616_jmp_far_rm(mod,rm) x8616_emit_modrm(x8616_opcode_group_ff,mod,x8616_ff_jmp_far,rm) + +#define x8616_ret() x8616_emit_op(x8616_opcode_ret) +#define x8616_ret_i(bytes) x8616_emit_op_i16(x8616_opcode_ret_i,bytes) +#define x8616_retf() x8616_emit_op(x8616_opcode_retf) +#define x8616_retf_i(bytes) x8616_emit_op_i16(x8616_opcode_retf_i,bytes) + +#define x8616_jcc(cc,rel) x8616_enc_jcc(cc), u1_(rel) +#define x8616_jo(rel) x8616_jcc(x8616_cc_o,rel) +#define x8616_jno(rel) x8616_jcc(x8616_cc_no,rel) +#define x8616_jb(rel) x8616_jcc(x8616_cc_b,rel) +#define x8616_jnb(rel) x8616_jcc(x8616_cc_nb,rel) +#define x8616_je(rel) x8616_jcc(x8616_cc_e,rel) +#define x8616_jne(rel) x8616_jcc(x8616_cc_ne,rel) +#define x8616_jbe(rel) x8616_jcc(x8616_cc_be,rel) +#define x8616_ja(rel) x8616_jcc(x8616_cc_a,rel) +#define x8616_js(rel) x8616_jcc(x8616_cc_s,rel) +#define x8616_jns(rel) x8616_jcc(x8616_cc_ns,rel) +#define x8616_jp(rel) x8616_jcc(x8616_cc_p,rel) +#define x8616_jnp(rel) x8616_jcc(x8616_cc_np,rel) +#define x8616_jl(rel) x8616_jcc(x8616_cc_l,rel) +#define x8616_jnl(rel) x8616_jcc(x8616_cc_nl,rel) +#define x8616_jle(rel) x8616_jcc(x8616_cc_le,rel) +#define x8616_jg(rel) x8616_jcc(x8616_cc_g,rel) + +#define x8616_loopnz(rel) x8616_emit_op_i8(x8616_opcode_loopnz,rel) +#define x8616_loopz(rel) x8616_emit_op_i8(x8616_opcode_loopz,rel) +#define x8616_loop(rel) x8616_emit_op_i8(x8616_opcode_loop,rel) +#define x8616_jcxz(rel) x8616_emit_op_i8(x8616_opcode_jcxz,rel) + +// Interrupt / flags / machine control + +#define x8616_int(vector) x8616_emit_op_i8(x8616_opcode_int,vector) +#define x8616_int3() x8616_emit_op(x8616_opcode_int3) +#define x8616_into() x8616_emit_op(x8616_opcode_into) +#define x8616_iret() x8616_emit_op(x8616_opcode_iret) +#define x8616_clc() x8616_emit_op(x8616_opcode_clc) +#define x8616_cmc() x8616_emit_op(x8616_opcode_cmc) +#define x8616_stc() x8616_emit_op(x8616_opcode_stc) +#define x8616_cld() x8616_emit_op(x8616_opcode_cld) +#define x8616_std() x8616_emit_op(x8616_opcode_std) +#define x8616_cli() x8616_emit_op(x8616_opcode_cli) +#define x8616_sti() x8616_emit_op(x8616_opcode_sti) +#define x8616_hlt() x8616_emit_op(x8616_opcode_hlt) +#define x8616_wait() x8616_emit_op(x8616_opcode_wait) diff --git a/code/8086/encoder_table.h b/code/8086/encoder_table.h new file mode 100644 index 0000000..5153af2 --- /dev/null +++ b/code/8086/encoder_table.h @@ -0,0 +1,1565 @@ +#ifdef INTELLISENSE_DIRECTIVES +# pragma once +# include "encoder.h" +#endif + +// ============================================================================ +// Encoding Table +// +// Part 1 target: the instruction cross-section exercised by Computer Enhance +// listing 0042. Later Part 1 simulation listings use a subset of this table. +// +// Fixed opcode bits are kept in binary/signature form; ModR/M /digit selectors +// use their encoded enumeration values. +// ============================================================================ + +RO_ global X8616_Encoding x8616_encodings[] = +{ + // MOV--------------------------------------------------------------------- + + /* MOV: 100010 d w | mod reg r/m */ { + .opcode = { + .bits = x8616_opcode_mov_rm_r << X8616_OPCODE_DW_PREFIX_SHIFT, + .mask = X8616_OPCODE_DW_PREFIX_MASK, + }, + .fields = { + .d = { X8616_OPCODE_DW_D_SHIFT, 1 }, + .w = { X8616_OPCODE_DW_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm, x8616_operand_reg_modrm }, + .op = x8616_op_mov, + }, + + /* MOV imm -> r/m: 1100011 w | mod 000 r/m */ { + .opcode = { + .bits = x8616_opcode_mov_rm_i << X8616_OPCODE_W_PREFIX_SHIFT, + .mask = X8616_OPCODE_W_PREFIX_MASK, + }, + .mod_rm = { + .bits = 0b000 << X8616_MODRM_REG_SHIFT, + .mask = X8616_MODRM_REG_MASK, + }, + .fields = { + .w = { X8616_OPCODE_W_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm, x8616_operand_imm }, + .op = x8616_op_mov, + }, + + /* MOV imm -> reg: 1011 w reg */ { + .opcode = { + .bits = x8616_opcode_mov_r_i << X8616_OPCODE_WREG_PREFIX_SHIFT, + .mask = X8616_OPCODE_WREG_PREFIX_MASK, + }, + .fields = { + .w = { X8616_OPCODE_WREG_W_SHIFT, 1 }, + .reg = { X8616_OPCODE_WREG_REG_SHIFT, X8616_OPCODE_WREG_REG_WIDTH }, + }, + .operands = { x8616_operand_reg_opcode, x8616_operand_imm }, + .op = x8616_op_mov, + }, + + /* MOV accumulator <-> direct memory: 101000 d w */ { + .opcode = { + .bits = x8616_opcode_mov_acc_mem << X8616_OPCODE_DW_PREFIX_SHIFT, + .mask = X8616_OPCODE_DW_PREFIX_MASK, + }, + .fields = { + .d = { X8616_OPCODE_DW_D_SHIFT, 1 }, + .w = { X8616_OPCODE_DW_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_acc, x8616_operand_mem_direct }, + .op = x8616_op_mov, + }, + + /* MOV segment <-> r/m: 100011 d 0 | mod 0 sr r/m */ { + .opcode = { + .bits = x8616_opcode_mov_seg_rm << X8616_OPCODE_D0_PREFIX_SHIFT, + .mask = X8616_OPCODE_D0_PREFIX_MASK, + }, + .mod_rm = { + .bits = 0, + .mask = X8616_MODRM_SEG_FIXED_MASK, + }, + .fields = { + .d = { X8616_OPCODE_D0_D_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm, x8616_operand_segment_modrm }, + .width = x8616_width_word, + .op = x8616_op_mov, + }, + + // Stack / exchange-------------------------------------------------------- + + /* PUSH r/m16: 11111111 | mod 110 r/m */ { + .opcode = { + .bits = x8616_opcode_group_ff, + .mask = X8616_OPCODE_MASK, + }, + .mod_rm = { + .bits = x8616_ff_push << X8616_MODRM_REG_SHIFT, + .mask = X8616_MODRM_REG_MASK, + }, + .operands = { x8616_operand_rm }, + .width = x8616_width_word, + .op = x8616_op_push, + }, + + /* PUSH reg16: 01010 reg */ { + .opcode = { + .bits = x8616_opcode_push_reg << X8616_OPCODE_REG_PREFIX_SHIFT, + .mask = X8616_OPCODE_REG_PREFIX_MASK, + }, + .fields = { + .reg = { X8616_OPCODE_REG_REG_SHIFT, X8616_OPCODE_REG_REG_WIDTH }, + }, + .operands = { x8616_operand_reg_opcode }, + .width = x8616_width_word, + .op = x8616_op_push, + }, + + /* PUSH segment: 000 sr 110 */ { + .opcode = { + .bits = X8616_OPCODE_PUSH_SR_FIXED, + .mask = X8616_OPCODE_SR_PATTERN_MASK, + }, + .fields = { + .sr = { X8616_OPCODE_SR_SHIFT, X8616_OPCODE_SR_WIDTH }, + }, + .operands = { x8616_operand_segment_opcode }, + .width = x8616_width_word, + .op = x8616_op_push, + }, + + /* POP r/m16: 10001111 | mod 000 r/m */ { + .opcode = { + .bits = x8616_opcode_pop_rm, + .mask = X8616_OPCODE_MASK, + }, + .mod_rm = { + .bits = 0b000 << X8616_MODRM_REG_SHIFT, + .mask = X8616_MODRM_REG_MASK, + }, + .operands = { x8616_operand_rm }, + .width = x8616_width_word, + .op = x8616_op_pop, + }, + + /* POP reg16: 01011 reg */ { + .opcode = { + .bits = x8616_opcode_pop_reg << X8616_OPCODE_REG_PREFIX_SHIFT, + .mask = X8616_OPCODE_REG_PREFIX_MASK, + }, + .fields = { + .reg = { X8616_OPCODE_REG_REG_SHIFT, X8616_OPCODE_REG_REG_WIDTH }, + }, + .operands = { x8616_operand_reg_opcode }, + .width = x8616_width_word, + .op = x8616_op_pop, + }, + + /* POP segment: 000 sr 111 */ { + .opcode = { + .bits = X8616_OPCODE_POP_SR_FIXED, + .mask = X8616_OPCODE_SR_PATTERN_MASK, + }, + .fields = { + .sr = { X8616_OPCODE_SR_SHIFT, X8616_OPCODE_SR_WIDTH }, + }, + .operands = { x8616_operand_segment_opcode }, + .width = x8616_width_word, + .op = x8616_op_pop, + }, + + /* XCHG r/m,reg: 1000011 w | mod reg r/m */ { + .opcode = { + .bits = x8616_opcode_xchg_rm_r << X8616_OPCODE_W_PREFIX_SHIFT, + .mask = X8616_OPCODE_W_PREFIX_MASK, + }, + .fields = { + .w = { X8616_OPCODE_W_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_reg_modrm, x8616_operand_rm }, + .op = x8616_op_xchg, + }, + + /* XCHG AX,reg16: 10010 reg (also encodes NOP at reg=AX) */ { + .opcode = { + .bits = x8616_opcode_xchg_ax_reg << X8616_OPCODE_REG_PREFIX_SHIFT, + .mask = X8616_OPCODE_REG_PREFIX_MASK, + }, + .fields = { + .reg = { X8616_OPCODE_REG_REG_SHIFT, X8616_OPCODE_REG_REG_WIDTH }, + }, + .operands = { x8616_operand_acc, x8616_operand_reg_opcode }, + .width = x8616_width_word, + .op = x8616_op_xchg, + }, + + // I/O / address / flags--------------------------------------------------- + + /* IN acc,imm8: 1110010 w */ { + .opcode = { + .bits = x8616_opcode_in_i << X8616_OPCODE_W_PREFIX_SHIFT, + .mask = X8616_OPCODE_W_PREFIX_MASK, + }, + .fields = { + .w = { X8616_OPCODE_W_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_acc, x8616_operand_imm8 }, + .op = x8616_op_in, + }, + + /* IN acc,DX: 1110110 w */ { + .opcode = { + .bits = x8616_opcode_in_dx << X8616_OPCODE_W_PREFIX_SHIFT, + .mask = X8616_OPCODE_W_PREFIX_MASK, + }, + .fields = { + .w = { X8616_OPCODE_W_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_acc, x8616_operand_dx }, + .op = x8616_op_in, + }, + + /* OUT imm8,acc: 1110011 w */ { + .opcode = { + .bits = x8616_opcode_out_i << X8616_OPCODE_W_PREFIX_SHIFT, + .mask = X8616_OPCODE_W_PREFIX_MASK, + }, + .fields = { + .w = { X8616_OPCODE_W_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_imm8, x8616_operand_acc }, + .op = x8616_op_out, + }, + + /* OUT DX,acc: 1110111 w */ { + .opcode = { + .bits = x8616_opcode_out_dx << X8616_OPCODE_W_PREFIX_SHIFT, + .mask = X8616_OPCODE_W_PREFIX_MASK, + }, + .fields = { + .w = { X8616_OPCODE_W_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_dx, x8616_operand_acc }, + .op = x8616_op_out, + }, + + /* XLAT */ { + .opcode = { + .bits = x8616_opcode_xlat, + .mask = X8616_OPCODE_MASK, + }, + .op = x8616_op_xlat, + }, + + /* LEA: mod reg r/m */ { + .opcode = { + .bits = x8616_opcode_lea, + .mask = X8616_OPCODE_MASK, + }, + .operands = { x8616_operand_reg_modrm, x8616_operand_rm }, + .width = x8616_width_word, + .op = x8616_op_lea, + }, + + /* LDS: mod reg r/m */ { + .opcode = { + .bits = x8616_opcode_lds, + .mask = X8616_OPCODE_MASK, + }, + .operands = { x8616_operand_reg_modrm, x8616_operand_rm }, + .width = x8616_width_word, + .op = x8616_op_lds, + }, + + /* LES: mod reg r/m */ { + .opcode = { + .bits = x8616_opcode_les, + .mask = X8616_OPCODE_MASK, + }, + .operands = { x8616_operand_reg_modrm, x8616_operand_rm }, + .width = x8616_width_word, + .op = x8616_op_les, + }, + + /* LAHF */ { + .opcode = { + .bits = x8616_opcode_lahf, + .mask = X8616_OPCODE_MASK, + }, + .op = x8616_op_lahf, + }, + + /* SAHF */ { + .opcode = { + .bits = x8616_opcode_sahf, + .mask = X8616_OPCODE_MASK, + }, + .op = x8616_op_sahf, + }, + + /* PUSHF */ { + .opcode = { + .bits = x8616_opcode_pushf, + .mask = X8616_OPCODE_MASK, + }, + .op = x8616_op_pushf, + }, + + /* POPF */ { + .opcode = { + .bits = x8616_opcode_popf, + .mask = X8616_OPCODE_MASK, + }, + .op = x8616_op_popf, + }, + + // Arithmetic / logical---------------------------------------------------- + + /* ADD r/m,reg: 000000 d w */ { + .opcode = { + .bits = 0b000000 << X8616_OPCODE_DW_PREFIX_SHIFT, + .mask = X8616_OPCODE_DW_PREFIX_MASK, + }, + .fields = { + .d = { X8616_OPCODE_DW_D_SHIFT, 1 }, + .w = { X8616_OPCODE_DW_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm, x8616_operand_reg_modrm }, + .op = x8616_op_add, + }, + + /* ADD imm,r/m: 100000 s w /0 */ { + .opcode = { + .bits = x8616_opcode_alu_rm_i << X8616_OPCODE_SW_PREFIX_SHIFT, + .mask = X8616_OPCODE_SW_PREFIX_MASK, + }, + .mod_rm = { + .bits = x8616_add << X8616_MODRM_REG_SHIFT, + .mask = X8616_MODRM_REG_MASK, + }, + .fields = { + .s = { X8616_OPCODE_SW_S_SHIFT, 1 }, + .w = { X8616_OPCODE_SW_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm, x8616_operand_imm }, + .op = x8616_op_add, + }, + + /* ADD accumulator,imm: 0000010 w */ { + .opcode = { + .bits = 0b0000010 << X8616_OPCODE_W_PREFIX_SHIFT, + .mask = X8616_OPCODE_W_PREFIX_MASK, + }, + .fields = { + .w = { X8616_OPCODE_W_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_acc, x8616_operand_imm }, + .op = x8616_op_add, + }, + + /* OR r/m,reg: 000010 d w */ { + .opcode = { + .bits = 0b000010 << X8616_OPCODE_DW_PREFIX_SHIFT, + .mask = X8616_OPCODE_DW_PREFIX_MASK, + }, + .fields = { + .d = { X8616_OPCODE_DW_D_SHIFT, 1 }, + .w = { X8616_OPCODE_DW_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm, x8616_operand_reg_modrm }, + .op = x8616_op_or, + }, + + /* OR imm,r/m: 1000000 w /1 */ { + .opcode = { + .bits = x8616_opcode_logic_rm_i << X8616_OPCODE_W_PREFIX_SHIFT, + .mask = X8616_OPCODE_W_PREFIX_MASK, + }, + .mod_rm = { + .bits = x8616_or << X8616_MODRM_REG_SHIFT, + .mask = X8616_MODRM_REG_MASK, + }, + .fields = { + .w = { X8616_OPCODE_W_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm, x8616_operand_imm }, + .op = x8616_op_or, + }, + + /* OR accumulator,imm: 0000110 w */ { + .opcode = { + .bits = 0b0000110 << X8616_OPCODE_W_PREFIX_SHIFT, + .mask = X8616_OPCODE_W_PREFIX_MASK, + }, + .fields = { + .w = { X8616_OPCODE_W_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_acc, x8616_operand_imm }, + .op = x8616_op_or, + }, + + /* ADC r/m,reg: 000100 d w */ { + .opcode = { + .bits = 0b000100 << X8616_OPCODE_DW_PREFIX_SHIFT, + .mask = X8616_OPCODE_DW_PREFIX_MASK, + }, + .fields = { + .d = { X8616_OPCODE_DW_D_SHIFT, 1 }, + .w = { X8616_OPCODE_DW_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm, x8616_operand_reg_modrm }, + .op = x8616_op_adc, + }, + + /* ADC imm,r/m: 100000 s w /2 */ { + .opcode = { + .bits = x8616_opcode_alu_rm_i << X8616_OPCODE_SW_PREFIX_SHIFT, + .mask = X8616_OPCODE_SW_PREFIX_MASK, + }, + .mod_rm = { + .bits = x8616_adc << X8616_MODRM_REG_SHIFT, + .mask = X8616_MODRM_REG_MASK, + }, + .fields = { + .s = { X8616_OPCODE_SW_S_SHIFT, 1 }, + .w = { X8616_OPCODE_SW_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm, x8616_operand_imm }, + .op = x8616_op_adc, + }, + + /* ADC accumulator,imm: 0001010 w */ { + .opcode = { + .bits = 0b0001010 << X8616_OPCODE_W_PREFIX_SHIFT, + .mask = X8616_OPCODE_W_PREFIX_MASK, + }, + .fields = { + .w = { X8616_OPCODE_W_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_acc, x8616_operand_imm }, + .op = x8616_op_adc, + }, + + /* SBB r/m,reg: 000110 d w */ { + .opcode = { + .bits = 0b000110 << X8616_OPCODE_DW_PREFIX_SHIFT, + .mask = X8616_OPCODE_DW_PREFIX_MASK, + }, + .fields = { + .d = { X8616_OPCODE_DW_D_SHIFT, 1 }, + .w = { X8616_OPCODE_DW_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm, x8616_operand_reg_modrm }, + .op = x8616_op_sbb, + }, + + /* SBB imm,r/m: 100000 s w /3 */ { + .opcode = { + .bits = x8616_opcode_alu_rm_i << X8616_OPCODE_SW_PREFIX_SHIFT, + .mask = X8616_OPCODE_SW_PREFIX_MASK, + }, + .mod_rm = { + .bits = x8616_sbb << X8616_MODRM_REG_SHIFT, + .mask = X8616_MODRM_REG_MASK, + }, + .fields = { + .s = { X8616_OPCODE_SW_S_SHIFT, 1 }, + .w = { X8616_OPCODE_SW_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm, x8616_operand_imm }, + .op = x8616_op_sbb, + }, + + /* SBB accumulator,imm: 0001110 w */ { + .opcode = { + .bits = 0b0001110 << X8616_OPCODE_W_PREFIX_SHIFT, + .mask = X8616_OPCODE_W_PREFIX_MASK, + }, + .fields = { + .w = { X8616_OPCODE_W_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_acc, x8616_operand_imm }, + .op = x8616_op_sbb, + }, + + /* AND r/m,reg: 001000 d w */ { + .opcode = { + .bits = 0b001000 << X8616_OPCODE_DW_PREFIX_SHIFT, + .mask = X8616_OPCODE_DW_PREFIX_MASK, + }, + .fields = { + .d = { X8616_OPCODE_DW_D_SHIFT, 1 }, + .w = { X8616_OPCODE_DW_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm, x8616_operand_reg_modrm }, + .op = x8616_op_and, + }, + + /* AND imm,r/m: 1000000 w /4 */ { + .opcode = { + .bits = x8616_opcode_logic_rm_i << X8616_OPCODE_W_PREFIX_SHIFT, + .mask = X8616_OPCODE_W_PREFIX_MASK, + }, + .mod_rm = { + .bits = x8616_and << X8616_MODRM_REG_SHIFT, + .mask = X8616_MODRM_REG_MASK, + }, + .fields = { + .w = { X8616_OPCODE_W_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm, x8616_operand_imm }, + .op = x8616_op_and, + }, + + /* AND accumulator,imm: 0010010 w */ { + .opcode = { + .bits = 0b0010010 << X8616_OPCODE_W_PREFIX_SHIFT, + .mask = X8616_OPCODE_W_PREFIX_MASK, + }, + .fields = { + .w = { X8616_OPCODE_W_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_acc, x8616_operand_imm }, + .op = x8616_op_and, + }, + + /* SUB r/m,reg: 001010 d w */ { + .opcode = { + .bits = 0b001010 << X8616_OPCODE_DW_PREFIX_SHIFT, + .mask = X8616_OPCODE_DW_PREFIX_MASK, + }, + .fields = { + .d = { X8616_OPCODE_DW_D_SHIFT, 1 }, + .w = { X8616_OPCODE_DW_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm, x8616_operand_reg_modrm }, + .op = x8616_op_sub, + }, + + /* SUB imm,r/m: 100000 s w /5 */ { + .opcode = { + .bits = x8616_opcode_alu_rm_i << X8616_OPCODE_SW_PREFIX_SHIFT, + .mask = X8616_OPCODE_SW_PREFIX_MASK, + }, + .mod_rm = { + .bits = x8616_sub << X8616_MODRM_REG_SHIFT, + .mask = X8616_MODRM_REG_MASK, + }, + .fields = { + .s = { X8616_OPCODE_SW_S_SHIFT, 1 }, + .w = { X8616_OPCODE_SW_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm, x8616_operand_imm }, + .op = x8616_op_sub, + }, + + /* SUB accumulator,imm: 0010110 w */ { + .opcode = { + .bits = 0b0010110 << X8616_OPCODE_W_PREFIX_SHIFT, + .mask = X8616_OPCODE_W_PREFIX_MASK, + }, + .fields = { + .w = { X8616_OPCODE_W_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_acc, x8616_operand_imm }, + .op = x8616_op_sub, + }, + + /* XOR r/m,reg: 001100 d w */ { + .opcode = { + .bits = 0b001100 << X8616_OPCODE_DW_PREFIX_SHIFT, + .mask = X8616_OPCODE_DW_PREFIX_MASK, + }, + .fields = { + .d = { X8616_OPCODE_DW_D_SHIFT, 1 }, + .w = { X8616_OPCODE_DW_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm, x8616_operand_reg_modrm }, + .op = x8616_op_xor, + }, + + /* XOR imm,r/m: 1000000 w /6 */ { + .opcode = { + .bits = x8616_opcode_logic_rm_i << X8616_OPCODE_W_PREFIX_SHIFT, + .mask = X8616_OPCODE_W_PREFIX_MASK, + }, + .mod_rm = { + .bits = x8616_xor << X8616_MODRM_REG_SHIFT, + .mask = X8616_MODRM_REG_MASK, + }, + .fields = { + .w = { X8616_OPCODE_W_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm, x8616_operand_imm }, + .op = x8616_op_xor, + }, + + /* XOR accumulator,imm: 0011010 w */ { + .opcode = { + .bits = 0b0011010 << X8616_OPCODE_W_PREFIX_SHIFT, + .mask = X8616_OPCODE_W_PREFIX_MASK, + }, + .fields = { + .w = { X8616_OPCODE_W_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_acc, x8616_operand_imm }, + .op = x8616_op_xor, + }, + + /* CMP r/m,reg: 001110 d w */ { + .opcode = { + .bits = 0b001110 << X8616_OPCODE_DW_PREFIX_SHIFT, + .mask = X8616_OPCODE_DW_PREFIX_MASK, + }, + .fields = { + .d = { X8616_OPCODE_DW_D_SHIFT, 1 }, + .w = { X8616_OPCODE_DW_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm, x8616_operand_reg_modrm }, + .op = x8616_op_cmp, + }, + + /* CMP imm,r/m: 100000 s w /7 */ { + .opcode = { + .bits = x8616_opcode_alu_rm_i << X8616_OPCODE_SW_PREFIX_SHIFT, + .mask = X8616_OPCODE_SW_PREFIX_MASK, + }, + .mod_rm = { + .bits = x8616_cmp << X8616_MODRM_REG_SHIFT, + .mask = X8616_MODRM_REG_MASK, + }, + .fields = { + .s = { X8616_OPCODE_SW_S_SHIFT, 1 }, + .w = { X8616_OPCODE_SW_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm, x8616_operand_imm }, + .op = x8616_op_cmp, + }, + + /* CMP accumulator,imm: 0011110 w */ { + .opcode = { + .bits = 0b0011110 << X8616_OPCODE_W_PREFIX_SHIFT, + .mask = X8616_OPCODE_W_PREFIX_MASK, + }, + .fields = { + .w = { X8616_OPCODE_W_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_acc, x8616_operand_imm }, + .op = x8616_op_cmp, + }, + + // INC / DEC / unary / adjust--------------------------------------------- + + /* INC r/m: 1111111 w /0 */ { + .opcode = { + .bits = x8616_opcode_incdec_rm << X8616_OPCODE_W_PREFIX_SHIFT, + .mask = X8616_OPCODE_W_PREFIX_MASK, + }, + .mod_rm = { + .bits = x8616_inc << X8616_MODRM_REG_SHIFT, + .mask = X8616_MODRM_REG_MASK, + }, + .fields = { + .w = { X8616_OPCODE_W_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm }, + .op = x8616_op_inc, + }, + + /* INC reg16: 01000 reg */ { + .opcode = { + .bits = x8616_opcode_inc_reg << X8616_OPCODE_REG_PREFIX_SHIFT, + .mask = X8616_OPCODE_REG_PREFIX_MASK, + }, + .fields = { + .reg = { X8616_OPCODE_REG_REG_SHIFT, X8616_OPCODE_REG_REG_WIDTH }, + }, + .operands = { x8616_operand_reg_opcode }, + .width = x8616_width_word, + .op = x8616_op_inc, + }, + + /* AAA */ { + .opcode = { + .bits = x8616_opcode_aaa, + .mask = X8616_OPCODE_MASK, + }, + .op = x8616_op_aaa, + }, + + /* DAA */ { + .opcode = { + .bits = x8616_opcode_daa, + .mask = X8616_OPCODE_MASK, + }, + .op = x8616_op_daa, + }, + + /* DEC r/m: 1111111 w /1 */ { + .opcode = { + .bits = x8616_opcode_incdec_rm << X8616_OPCODE_W_PREFIX_SHIFT, + .mask = X8616_OPCODE_W_PREFIX_MASK, + }, + .mod_rm = { + .bits = x8616_dec << X8616_MODRM_REG_SHIFT, + .mask = X8616_MODRM_REG_MASK, + }, + .fields = { + .w = { X8616_OPCODE_W_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm }, + .op = x8616_op_dec, + }, + + /* DEC reg16: 01001 reg */ { + .opcode = { + .bits = x8616_opcode_dec_reg << X8616_OPCODE_REG_PREFIX_SHIFT, + .mask = X8616_OPCODE_REG_PREFIX_MASK, + }, + .fields = { + .reg = { X8616_OPCODE_REG_REG_SHIFT, X8616_OPCODE_REG_REG_WIDTH }, + }, + .operands = { x8616_operand_reg_opcode }, + .width = x8616_width_word, + .op = x8616_op_dec, + }, + + /* NEG r/m: 1111011 w /neg */ { + .opcode = { + .bits = x8616_opcode_group3 << X8616_OPCODE_W_PREFIX_SHIFT, + .mask = X8616_OPCODE_W_PREFIX_MASK, + }, + .mod_rm = { + .bits = x8616_g3_neg << X8616_MODRM_REG_SHIFT, + .mask = X8616_MODRM_REG_MASK, + }, + .fields = { + .w = { X8616_OPCODE_W_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm }, + .op = x8616_op_neg, + }, + + /* MUL r/m: 1111011 w /mul */ { + .opcode = { + .bits = x8616_opcode_group3 << X8616_OPCODE_W_PREFIX_SHIFT, + .mask = X8616_OPCODE_W_PREFIX_MASK, + }, + .mod_rm = { + .bits = x8616_g3_mul << X8616_MODRM_REG_SHIFT, + .mask = X8616_MODRM_REG_MASK, + }, + .fields = { + .w = { X8616_OPCODE_W_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm }, + .op = x8616_op_mul, + }, + + /* IMUL r/m: 1111011 w /imul */ { + .opcode = { + .bits = x8616_opcode_group3 << X8616_OPCODE_W_PREFIX_SHIFT, + .mask = X8616_OPCODE_W_PREFIX_MASK, + }, + .mod_rm = { + .bits = x8616_g3_imul << X8616_MODRM_REG_SHIFT, + .mask = X8616_MODRM_REG_MASK, + }, + .fields = { + .w = { X8616_OPCODE_W_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm }, + .op = x8616_op_imul, + }, + + /* DIV r/m: 1111011 w /div */ { + .opcode = { + .bits = x8616_opcode_group3 << X8616_OPCODE_W_PREFIX_SHIFT, + .mask = X8616_OPCODE_W_PREFIX_MASK, + }, + .mod_rm = { + .bits = x8616_g3_div << X8616_MODRM_REG_SHIFT, + .mask = X8616_MODRM_REG_MASK, + }, + .fields = { + .w = { X8616_OPCODE_W_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm }, + .op = x8616_op_div, + }, + + /* IDIV r/m: 1111011 w /idiv */ { + .opcode = { + .bits = x8616_opcode_group3 << X8616_OPCODE_W_PREFIX_SHIFT, + .mask = X8616_OPCODE_W_PREFIX_MASK, + }, + .mod_rm = { + .bits = x8616_g3_idiv << X8616_MODRM_REG_SHIFT, + .mask = X8616_MODRM_REG_MASK, + }, + .fields = { + .w = { X8616_OPCODE_W_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm }, + .op = x8616_op_idiv, + }, + + /* NOT r/m: 1111011 w /not */ { + .opcode = { + .bits = x8616_opcode_group3 << X8616_OPCODE_W_PREFIX_SHIFT, + .mask = X8616_OPCODE_W_PREFIX_MASK, + }, + .mod_rm = { + .bits = x8616_g3_not << X8616_MODRM_REG_SHIFT, + .mask = X8616_MODRM_REG_MASK, + }, + .fields = { + .w = { X8616_OPCODE_W_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm }, + .op = x8616_op_not, + }, + + /* AAS */ { + .opcode = { + .bits = x8616_opcode_aas, + .mask = X8616_OPCODE_MASK, + }, + .op = x8616_op_aas, + }, + + /* DAS */ { + .opcode = { + .bits = x8616_opcode_das, + .mask = X8616_OPCODE_MASK, + }, + .op = x8616_op_das, + }, + + /* AAM: 11010100 00001010 */ { + .opcode = { + .bits = x8616_opcode_aam, + .mask = X8616_OPCODE_MASK, + }, + .post_opcode = { + .bits = X8616_POST_OPCODE_AAM_AAD, + .mask = X8616_OPCODE_MASK, + }, + .op = x8616_op_aam, + }, + + /* AAD: 11010101 00001010 */ { + .opcode = { + .bits = x8616_opcode_aad, + .mask = X8616_OPCODE_MASK, + }, + .post_opcode = { + .bits = X8616_POST_OPCODE_AAM_AAD, + .mask = X8616_OPCODE_MASK, + }, + .op = x8616_op_aad, + }, + + /* CBW */ { + .opcode = { + .bits = x8616_opcode_cbw, + .mask = X8616_OPCODE_MASK, + }, + .op = x8616_op_cbw, + }, + + /* CWD */ { + .opcode = { + .bits = x8616_opcode_cwd, + .mask = X8616_OPCODE_MASK, + }, + .op = x8616_op_cwd, + }, + + // Shift / rotate / TEST--------------------------------------------------- + + /* ROL r/m,1|CL: 110100 v w */ { + .opcode = { + .bits = x8616_opcode_shift_rm << X8616_OPCODE_VW_PREFIX_SHIFT, + .mask = X8616_OPCODE_VW_PREFIX_MASK, + }, + .mod_rm = { + .bits = x8616_rol << X8616_MODRM_REG_SHIFT, + .mask = X8616_MODRM_REG_MASK, + }, + .fields = { + .v = { X8616_OPCODE_VW_V_SHIFT, 1 }, + .w = { X8616_OPCODE_VW_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm, x8616_operand_shift_count }, + .op = x8616_op_rol, + }, + + /* ROR r/m,1|CL: 110100 v w */ { + .opcode = { + .bits = x8616_opcode_shift_rm << X8616_OPCODE_VW_PREFIX_SHIFT, + .mask = X8616_OPCODE_VW_PREFIX_MASK, + }, + .mod_rm = { + .bits = x8616_ror << X8616_MODRM_REG_SHIFT, + .mask = X8616_MODRM_REG_MASK, + }, + .fields = { + .v = { X8616_OPCODE_VW_V_SHIFT, 1 }, + .w = { X8616_OPCODE_VW_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm, x8616_operand_shift_count }, + .op = x8616_op_ror, + }, + + /* RCL r/m,1|CL: 110100 v w */ { + .opcode = { + .bits = x8616_opcode_shift_rm << X8616_OPCODE_VW_PREFIX_SHIFT, + .mask = X8616_OPCODE_VW_PREFIX_MASK, + }, + .mod_rm = { + .bits = x8616_rcl << X8616_MODRM_REG_SHIFT, + .mask = X8616_MODRM_REG_MASK, + }, + .fields = { + .v = { X8616_OPCODE_VW_V_SHIFT, 1 }, + .w = { X8616_OPCODE_VW_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm, x8616_operand_shift_count }, + .op = x8616_op_rcl, + }, + + /* RCR r/m,1|CL: 110100 v w */ { + .opcode = { + .bits = x8616_opcode_shift_rm << X8616_OPCODE_VW_PREFIX_SHIFT, + .mask = X8616_OPCODE_VW_PREFIX_MASK, + }, + .mod_rm = { + .bits = x8616_rcr << X8616_MODRM_REG_SHIFT, + .mask = X8616_MODRM_REG_MASK, + }, + .fields = { + .v = { X8616_OPCODE_VW_V_SHIFT, 1 }, + .w = { X8616_OPCODE_VW_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm, x8616_operand_shift_count }, + .op = x8616_op_rcr, + }, + + /* SHL r/m,1|CL: 110100 v w */ { + .opcode = { + .bits = x8616_opcode_shift_rm << X8616_OPCODE_VW_PREFIX_SHIFT, + .mask = X8616_OPCODE_VW_PREFIX_MASK, + }, + .mod_rm = { + .bits = x8616_shl << X8616_MODRM_REG_SHIFT, + .mask = X8616_MODRM_REG_MASK, + }, + .fields = { + .v = { X8616_OPCODE_VW_V_SHIFT, 1 }, + .w = { X8616_OPCODE_VW_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm, x8616_operand_shift_count }, + .op = x8616_op_shl, + }, + + /* SHR r/m,1|CL: 110100 v w */ { + .opcode = { + .bits = x8616_opcode_shift_rm << X8616_OPCODE_VW_PREFIX_SHIFT, + .mask = X8616_OPCODE_VW_PREFIX_MASK, + }, + .mod_rm = { + .bits = x8616_shr << X8616_MODRM_REG_SHIFT, + .mask = X8616_MODRM_REG_MASK, + }, + .fields = { + .v = { X8616_OPCODE_VW_V_SHIFT, 1 }, + .w = { X8616_OPCODE_VW_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm, x8616_operand_shift_count }, + .op = x8616_op_shr, + }, + + /* SAR r/m,1|CL: 110100 v w */ { + .opcode = { + .bits = x8616_opcode_shift_rm << X8616_OPCODE_VW_PREFIX_SHIFT, + .mask = X8616_OPCODE_VW_PREFIX_MASK, + }, + .mod_rm = { + .bits = x8616_sar << X8616_MODRM_REG_SHIFT, + .mask = X8616_MODRM_REG_MASK, + }, + .fields = { + .v = { X8616_OPCODE_VW_V_SHIFT, 1 }, + .w = { X8616_OPCODE_VW_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm, x8616_operand_shift_count }, + .op = x8616_op_sar, + }, + + /* TEST r/m,reg: 1000010 w */ { + .opcode = { + .bits = x8616_opcode_test_rm_r << X8616_OPCODE_W_PREFIX_SHIFT, + .mask = X8616_OPCODE_W_PREFIX_MASK, + }, + .fields = { + .w = { X8616_OPCODE_W_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm, x8616_operand_reg_modrm }, + .op = x8616_op_test, + }, + + /* TEST r/m,imm: 1111011 w /0 */ { + .opcode = { + .bits = x8616_opcode_group3 << X8616_OPCODE_W_PREFIX_SHIFT, + .mask = X8616_OPCODE_W_PREFIX_MASK, + }, + .mod_rm = { + .bits = x8616_g3_test << X8616_MODRM_REG_SHIFT, + .mask = X8616_MODRM_REG_MASK, + }, + .fields = { + .w = { X8616_OPCODE_W_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_rm, x8616_operand_imm }, + .op = x8616_op_test, + }, + + /* TEST accumulator,imm: 1010100 w */ { + .opcode = { + .bits = x8616_opcode_test_acc_i << X8616_OPCODE_W_PREFIX_SHIFT, + .mask = X8616_OPCODE_W_PREFIX_MASK, + }, + .fields = { + .w = { X8616_OPCODE_W_W_SHIFT, 1 }, + }, + .operands = { x8616_operand_acc, x8616_operand_imm }, + .op = x8616_op_test, + }, + + // String / prefixes------------------------------------------------------- + + /* REP/REPNE prefix: 1111001 z */ { + .opcode = { + .bits = x8616_opcode_rep << X8616_OPCODE_Z_PREFIX_SHIFT, + .mask = X8616_OPCODE_Z_PREFIX_MASK, + }, + .fields = { + .z = { X8616_OPCODE_Z_Z_SHIFT, 1 }, + }, + .flags = x8616_encoding_prefix, + .op = x8616_op_rep, + }, + + /* MOVS: ... w */ { + .opcode = { + .bits = x8616_opcode_movs << X8616_OPCODE_W_PREFIX_SHIFT, + .mask = X8616_OPCODE_W_PREFIX_MASK, + }, + .fields = { + .w = { X8616_OPCODE_W_W_SHIFT, 1 }, + }, + .op = x8616_op_movs, + }, + + /* CMPS: ... w */ { + .opcode = { + .bits = x8616_opcode_cmps << X8616_OPCODE_W_PREFIX_SHIFT, + .mask = X8616_OPCODE_W_PREFIX_MASK, + }, + .fields = { + .w = { X8616_OPCODE_W_W_SHIFT, 1 }, + }, + .op = x8616_op_cmps, + }, + + /* SCAS: ... w */ { + .opcode = { + .bits = x8616_opcode_scas << X8616_OPCODE_W_PREFIX_SHIFT, + .mask = X8616_OPCODE_W_PREFIX_MASK, + }, + .fields = { + .w = { X8616_OPCODE_W_W_SHIFT, 1 }, + }, + .op = x8616_op_scas, + }, + + /* LODS: ... w */ { + .opcode = { + .bits = x8616_opcode_lods << X8616_OPCODE_W_PREFIX_SHIFT, + .mask = X8616_OPCODE_W_PREFIX_MASK, + }, + .fields = { + .w = { X8616_OPCODE_W_W_SHIFT, 1 }, + }, + .op = x8616_op_lods, + }, + + /* STOS: ... w */ { + .opcode = { + .bits = x8616_opcode_stos << X8616_OPCODE_W_PREFIX_SHIFT, + .mask = X8616_OPCODE_W_PREFIX_MASK, + }, + .fields = { + .w = { X8616_OPCODE_W_W_SHIFT, 1 }, + }, + .op = x8616_op_stos, + }, + + /* LOCK prefix */ { + .opcode = { + .bits = x8616_opcode_lock, + .mask = X8616_OPCODE_MASK, + }, + .flags = x8616_encoding_prefix, + .op = x8616_op_lock, + }, + + /* Segment override: 001 sr 110 */ { + .opcode = { + .bits = X8616_OPCODE_SEG_FIXED, + .mask = X8616_OPCODE_SR_PATTERN_MASK, + }, + .fields = { + .sr = { X8616_OPCODE_SR_SHIFT, X8616_OPCODE_SR_WIDTH }, + }, + .flags = x8616_encoding_prefix, + .op = x8616_op_segment, + }, + + // Control transfer-------------------------------------------------------- + + /* CALL rel16 */ { + .opcode = { + .bits = x8616_opcode_call_rel16, + .mask = X8616_OPCODE_MASK, + }, + .operands = { x8616_operand_rel16 }, + .op = x8616_op_call, + }, + + /* CALL r/m16: FF /2 */ { + .opcode = { + .bits = x8616_opcode_group_ff, + .mask = X8616_OPCODE_MASK, + }, + .mod_rm = { + .bits = x8616_ff_call_near << X8616_MODRM_REG_SHIFT, + .mask = X8616_MODRM_REG_MASK, + }, + .operands = { x8616_operand_rm }, + .width = x8616_width_word, + .op = x8616_op_call, + }, + + /* CALL far ptr16:16 */ { + .opcode = { + .bits = x8616_opcode_call_far, + .mask = X8616_OPCODE_MASK, + }, + .operands = { x8616_operand_far_ptr }, + .flags = x8616_encoding_far, + .op = x8616_op_call, + }, + + /* CALL far r/m16: FF /3 */ { + .opcode = { + .bits = x8616_opcode_group_ff, + .mask = X8616_OPCODE_MASK, + }, + .mod_rm = { + .bits = x8616_ff_call_far << X8616_MODRM_REG_SHIFT, + .mask = X8616_MODRM_REG_MASK, + }, + .operands = { x8616_operand_rm }, + .width = x8616_width_word, + .flags = x8616_encoding_far, + .op = x8616_op_call, + }, + + /* JMP rel16 */ { + .opcode = { + .bits = x8616_opcode_jmp_rel16, + .mask = X8616_OPCODE_MASK, + }, + .operands = { x8616_operand_rel16 }, + .op = x8616_op_jmp, + }, + + /* JMP rel8 */ { + .opcode = { + .bits = x8616_opcode_jmp_rel8, + .mask = X8616_OPCODE_MASK, + }, + .operands = { x8616_operand_rel8 }, + .op = x8616_op_jmp, + }, + + /* JMP r/m16: FF /4 */ { + .opcode = { + .bits = x8616_opcode_group_ff, + .mask = X8616_OPCODE_MASK, + }, + .mod_rm = { + .bits = x8616_ff_jmp_near << X8616_MODRM_REG_SHIFT, + .mask = X8616_MODRM_REG_MASK, + }, + .operands = { x8616_operand_rm }, + .width = x8616_width_word, + .op = x8616_op_jmp, + }, + + /* JMP far ptr16:16 */ { + .opcode = { + .bits = x8616_opcode_jmp_far, + .mask = X8616_OPCODE_MASK, + }, + .operands = { x8616_operand_far_ptr }, + .flags = x8616_encoding_far, + .op = x8616_op_jmp, + }, + + /* JMP far r/m16: FF /5 */ { + .opcode = { + .bits = x8616_opcode_group_ff, + .mask = X8616_OPCODE_MASK, + }, + .mod_rm = { + .bits = x8616_ff_jmp_far << X8616_MODRM_REG_SHIFT, + .mask = X8616_MODRM_REG_MASK, + }, + .operands = { x8616_operand_rm }, + .width = x8616_width_word, + .flags = x8616_encoding_far, + .op = x8616_op_jmp, + }, + + /* RET */ { + .opcode = { + .bits = x8616_opcode_ret, + .mask = X8616_OPCODE_MASK, + }, + .op = x8616_op_ret, + }, + + /* RET imm16 */ { + .opcode = { + .bits = x8616_opcode_ret_i, + .mask = X8616_OPCODE_MASK, + }, + .operands = { x8616_operand_imm16 }, + .op = x8616_op_ret, + }, + + /* RETF */ { + .opcode = { + .bits = x8616_opcode_retf, + .mask = X8616_OPCODE_MASK, + }, + .op = x8616_op_retf, + }, + + /* RETF imm16 */ { + .opcode = { + .bits = x8616_opcode_retf_i, + .mask = X8616_OPCODE_MASK, + }, + .operands = { x8616_operand_imm16 }, + .op = x8616_op_retf, + }, + + /* JO rel8 */ { + .opcode = { + .bits = x8616_enc_jcc(x8616_cc_o), + .mask = X8616_OPCODE_MASK, + }, + .operands = { x8616_operand_rel8 }, + .op = x8616_op_jo, + }, + + /* JNO rel8 */ { + .opcode = { + .bits = x8616_enc_jcc(x8616_cc_no), + .mask = X8616_OPCODE_MASK, + }, + .operands = { x8616_operand_rel8 }, + .op = x8616_op_jno, + }, + + /* JB rel8 */ { + .opcode = { + .bits = x8616_enc_jcc(x8616_cc_b), + .mask = X8616_OPCODE_MASK, + }, + .operands = { x8616_operand_rel8 }, + .op = x8616_op_jb, + }, + + /* JNB rel8 */ { + .opcode = { + .bits = x8616_enc_jcc(x8616_cc_nb), + .mask = X8616_OPCODE_MASK, + }, + .operands = { x8616_operand_rel8 }, + .op = x8616_op_jnb, + }, + + /* JE rel8 */ { + .opcode = { + .bits = x8616_enc_jcc(x8616_cc_e), + .mask = X8616_OPCODE_MASK, + }, + .operands = { x8616_operand_rel8 }, + .op = x8616_op_je, + }, + + /* JNE rel8 */ { + .opcode = { + .bits = x8616_enc_jcc(x8616_cc_ne), + .mask = X8616_OPCODE_MASK, + }, + .operands = { x8616_operand_rel8 }, + .op = x8616_op_jne, + }, + + /* JBE rel8 */ { + .opcode = { + .bits = x8616_enc_jcc(x8616_cc_be), + .mask = X8616_OPCODE_MASK, + }, + .operands = { x8616_operand_rel8 }, + .op = x8616_op_jbe, + }, + + /* JA rel8 */ { + .opcode = { + .bits = x8616_enc_jcc(x8616_cc_a), + .mask = X8616_OPCODE_MASK, + }, + .operands = { x8616_operand_rel8 }, + .op = x8616_op_ja, + }, + + /* JS rel8 */ { + .opcode = { + .bits = x8616_enc_jcc(x8616_cc_s), + .mask = X8616_OPCODE_MASK, + }, + .operands = { x8616_operand_rel8 }, + .op = x8616_op_js, + }, + + /* JNS rel8 */ { + .opcode = { + .bits = x8616_enc_jcc(x8616_cc_ns), + .mask = X8616_OPCODE_MASK, + }, + .operands = { x8616_operand_rel8 }, + .op = x8616_op_jns, + }, + + /* JP rel8 */ { + .opcode = { + .bits = x8616_enc_jcc(x8616_cc_p), + .mask = X8616_OPCODE_MASK, + }, + .operands = { x8616_operand_rel8 }, + .op = x8616_op_jp, + }, + + /* JNP rel8 */ { + .opcode = { + .bits = x8616_enc_jcc(x8616_cc_np), + .mask = X8616_OPCODE_MASK, + }, + .operands = { x8616_operand_rel8 }, + .op = x8616_op_jnp, + }, + + /* JL rel8 */ { + .opcode = { + .bits = x8616_enc_jcc(x8616_cc_l), + .mask = X8616_OPCODE_MASK, + }, + .operands = { x8616_operand_rel8 }, + .op = x8616_op_jl, + }, + + /* JNL rel8 */ { + .opcode = { + .bits = x8616_enc_jcc(x8616_cc_nl), + .mask = X8616_OPCODE_MASK, + }, + .operands = { x8616_operand_rel8 }, + .op = x8616_op_jnl, + }, + + /* JLE rel8 */ { + .opcode = { + .bits = x8616_enc_jcc(x8616_cc_le), + .mask = X8616_OPCODE_MASK, + }, + .operands = { x8616_operand_rel8 }, + .op = x8616_op_jle, + }, + + /* JG rel8 */ { + .opcode = { + .bits = x8616_enc_jcc(x8616_cc_g), + .mask = X8616_OPCODE_MASK, + }, + .operands = { x8616_operand_rel8 }, + .op = x8616_op_jg, + }, + + /* LOOPNZ rel8 */ { + .opcode = { + .bits = x8616_opcode_loopnz, + .mask = X8616_OPCODE_MASK, + }, + .operands = { x8616_operand_rel8 }, + .op = x8616_op_loopnz, + }, + + /* LOOPZ rel8 */ { + .opcode = { + .bits = x8616_opcode_loopz, + .mask = X8616_OPCODE_MASK, + }, + .operands = { x8616_operand_rel8 }, + .op = x8616_op_loopz, + }, + + /* LOOP rel8 */ { + .opcode = { + .bits = x8616_opcode_loop, + .mask = X8616_OPCODE_MASK, + }, + .operands = { x8616_operand_rel8 }, + .op = x8616_op_loop, + }, + + /* JCXZ rel8 */ { + .opcode = { + .bits = x8616_opcode_jcxz, + .mask = X8616_OPCODE_MASK, + }, + .operands = { x8616_operand_rel8 }, + .op = x8616_op_jcxz, + }, + + // Interrupt / machine control-------------------------------------------- + + /* INT imm8 */ { + .opcode = { + .bits = x8616_opcode_int, + .mask = X8616_OPCODE_MASK, + }, + .operands = { x8616_operand_imm8 }, + .op = x8616_op_int, + }, + + /* INT3 */ { + .opcode = { + .bits = x8616_opcode_int3, + .mask = X8616_OPCODE_MASK, + }, + .op = x8616_op_int3, + }, + + /* INTO */ { + .opcode = { + .bits = x8616_opcode_into, + .mask = X8616_OPCODE_MASK, + }, + .op = x8616_op_into, + }, + + /* IRET */ { + .opcode = { + .bits = x8616_opcode_iret, + .mask = X8616_OPCODE_MASK, + }, + .op = x8616_op_iret, + }, + + /* CLC */ { + .opcode = { + .bits = x8616_opcode_clc, + .mask = X8616_OPCODE_MASK, + }, + .op = x8616_op_clc, + }, + + /* CMC */ { + .opcode = { + .bits = x8616_opcode_cmc, + .mask = X8616_OPCODE_MASK, + }, + .op = x8616_op_cmc, + }, + + /* STC */ { + .opcode = { + .bits = x8616_opcode_stc, + .mask = X8616_OPCODE_MASK, + }, + .op = x8616_op_stc, + }, + + /* CLD */ { + .opcode = { + .bits = x8616_opcode_cld, + .mask = X8616_OPCODE_MASK, + }, + .op = x8616_op_cld, + }, + + /* STD */ { + .opcode = { + .bits = x8616_opcode_std, + .mask = X8616_OPCODE_MASK, + }, + .op = x8616_op_std, + }, + + /* CLI */ { + .opcode = { + .bits = x8616_opcode_cli, + .mask = X8616_OPCODE_MASK, + }, + .op = x8616_op_cli, + }, + + /* STI */ { + .opcode = { + .bits = x8616_opcode_sti, + .mask = X8616_OPCODE_MASK, + }, + .op = x8616_op_sti, + }, + + /* HLT */ { + .opcode = { + .bits = x8616_opcode_hlt, + .mask = X8616_OPCODE_MASK, + }, + .op = x8616_op_hlt, + }, + + /* WAIT */ { + .opcode = { + .bits = x8616_opcode_wait, + .mask = X8616_OPCODE_MASK, + }, + .op = x8616_op_wait, + }, + +}; + +enum { + X8616_ENCODING_COUNT = S_(x8616_encodings) / S_(x8616_encodings[0]), +}; diff --git a/code/8086/gen/decoder_table.h b/code/8086/gen/decoder_table.h new file mode 100644 index 0000000..48c2d16 --- /dev/null +++ b/code/8086/gen/decoder_table.h @@ -0,0 +1,358 @@ +// Generated from encoder_table.h. Do not hand-edit. + +RO_ global X8616_DecodePlan x8616_decode_plans[132] = +{ + { 0x0000, 0x00, 0x00, 0x00, {0x00,0x00}, 0, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x020D, 0x02, 0x00, 0x00, {0x01,0x02}, 2, 0, 0, 1,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0209, 0x02, 0x00, 0x00, {0x01,0x07}, 2, 1, 0, 0,0,0,0,0,0,0, {0x00,0x38}, {0x00,0x00} }, + { 0x0088, 0x02, 0x00, 0x00, {0x03,0x07}, 2, 1, 0, 0,3,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x000C, 0x02, 0x00, 0x00, {0x06,0x0A}, 2, 4, 0, 1,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0205, 0x02, 0x00, 0x02, {0x01,0x04}, 2, 0, 0, 1,0,0,0,0,0,0, {0x00,0x20}, {0x00,0x00} }, + { 0x0201, 0x0B, 0x00, 0x02, {0x01,0x00}, 1, 0, 0, 0,0,0,0,0,0,0, {0x30,0x38}, {0x00,0x00} }, + { 0x0080, 0x0B, 0x00, 0x02, {0x03,0x00}, 1, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0100, 0x0B, 0x00, 0x02, {0x05,0x00}, 1, 0, 0, 0,0,0,0,0,0,3, {0x00,0x00}, {0x00,0x00} }, + { 0x0201, 0x0C, 0x00, 0x02, {0x01,0x00}, 1, 0, 0, 0,0,0,0,0,0,0, {0x00,0x38}, {0x00,0x00} }, + { 0x0080, 0x0C, 0x00, 0x02, {0x03,0x00}, 1, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0100, 0x0C, 0x00, 0x02, {0x05,0x00}, 1, 0, 0, 0,0,0,0,0,0,3, {0x00,0x00}, {0x00,0x00} }, + { 0x0209, 0x0D, 0x00, 0x00, {0x02,0x01}, 2, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0080, 0x0D, 0x00, 0x02, {0x06,0x03}, 2, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0008, 0x0E, 0x00, 0x00, {0x06,0x08}, 2, 2, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0008, 0x0E, 0x00, 0x00, {0x06,0x0E}, 2, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0008, 0x0F, 0x00, 0x00, {0x08,0x06}, 2, 2, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0008, 0x0F, 0x00, 0x00, {0x0E,0x06}, 2, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x10, 0x00, 0x00, {0x00,0x00}, 0, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0201, 0x11, 0x00, 0x02, {0x02,0x01}, 2, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0201, 0x12, 0x00, 0x02, {0x02,0x01}, 2, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0201, 0x13, 0x00, 0x02, {0x02,0x01}, 2, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x14, 0x00, 0x00, {0x00,0x00}, 0, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x15, 0x00, 0x00, {0x00,0x00}, 0, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x16, 0x00, 0x00, {0x00,0x00}, 0, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x17, 0x00, 0x00, {0x00,0x00}, 0, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x020D, 0x03, 0x00, 0x00, {0x01,0x02}, 2, 0, 0, 1,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0219, 0x03, 0x00, 0x00, {0x01,0x07}, 2, 1, 0, 0,0,1,0,0,0,0, {0x00,0x38}, {0x00,0x00} }, + { 0x0008, 0x03, 0x00, 0x00, {0x06,0x07}, 2, 1, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x020D, 0x04, 0x00, 0x00, {0x01,0x02}, 2, 0, 0, 1,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0209, 0x04, 0x00, 0x00, {0x01,0x07}, 2, 1, 0, 0,0,0,0,0,0,0, {0x08,0x38}, {0x00,0x00} }, + { 0x0008, 0x04, 0x00, 0x00, {0x06,0x07}, 2, 1, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x020D, 0x05, 0x00, 0x00, {0x01,0x02}, 2, 0, 0, 1,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0219, 0x05, 0x00, 0x00, {0x01,0x07}, 2, 1, 0, 0,0,1,0,0,0,0, {0x10,0x38}, {0x00,0x00} }, + { 0x0008, 0x05, 0x00, 0x00, {0x06,0x07}, 2, 1, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x020D, 0x06, 0x00, 0x00, {0x01,0x02}, 2, 0, 0, 1,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0219, 0x06, 0x00, 0x00, {0x01,0x07}, 2, 1, 0, 0,0,1,0,0,0,0, {0x18,0x38}, {0x00,0x00} }, + { 0x0008, 0x06, 0x00, 0x00, {0x06,0x07}, 2, 1, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x020D, 0x07, 0x00, 0x00, {0x01,0x02}, 2, 0, 0, 1,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0209, 0x07, 0x00, 0x00, {0x01,0x07}, 2, 1, 0, 0,0,0,0,0,0,0, {0x20,0x38}, {0x00,0x00} }, + { 0x0008, 0x07, 0x00, 0x00, {0x06,0x07}, 2, 1, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x020D, 0x08, 0x00, 0x00, {0x01,0x02}, 2, 0, 0, 1,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0219, 0x08, 0x00, 0x00, {0x01,0x07}, 2, 1, 0, 0,0,1,0,0,0,0, {0x28,0x38}, {0x00,0x00} }, + { 0x0008, 0x08, 0x00, 0x00, {0x06,0x07}, 2, 1, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x020D, 0x09, 0x00, 0x00, {0x01,0x02}, 2, 0, 0, 1,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0209, 0x09, 0x00, 0x00, {0x01,0x07}, 2, 1, 0, 0,0,0,0,0,0,0, {0x30,0x38}, {0x00,0x00} }, + { 0x0008, 0x09, 0x00, 0x00, {0x06,0x07}, 2, 1, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x020D, 0x0A, 0x00, 0x00, {0x01,0x02}, 2, 0, 0, 1,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0219, 0x0A, 0x00, 0x00, {0x01,0x07}, 2, 1, 0, 0,0,1,0,0,0,0, {0x38,0x38}, {0x00,0x00} }, + { 0x0008, 0x0A, 0x00, 0x00, {0x06,0x07}, 2, 1, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0209, 0x18, 0x00, 0x00, {0x01,0x00}, 1, 0, 0, 0,0,0,0,0,0,0, {0x00,0x38}, {0x00,0x00} }, + { 0x0080, 0x18, 0x00, 0x02, {0x03,0x00}, 1, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x19, 0x00, 0x00, {0x00,0x00}, 0, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x1A, 0x00, 0x00, {0x00,0x00}, 0, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0209, 0x1B, 0x00, 0x00, {0x01,0x00}, 1, 0, 0, 0,0,0,0,0,0,0, {0x08,0x38}, {0x00,0x00} }, + { 0x0080, 0x1B, 0x00, 0x02, {0x03,0x00}, 1, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0209, 0x1C, 0x00, 0x00, {0x01,0x00}, 1, 0, 0, 0,0,0,0,0,0,0, {0x18,0x38}, {0x00,0x00} }, + { 0x0209, 0x1F, 0x00, 0x00, {0x01,0x00}, 1, 0, 0, 0,0,0,0,0,0,0, {0x20,0x38}, {0x00,0x00} }, + { 0x0209, 0x20, 0x00, 0x00, {0x01,0x00}, 1, 0, 0, 0,0,0,0,0,0,0, {0x28,0x38}, {0x00,0x00} }, + { 0x0209, 0x22, 0x00, 0x00, {0x01,0x00}, 1, 0, 0, 0,0,0,0,0,0,0, {0x30,0x38}, {0x00,0x00} }, + { 0x0209, 0x23, 0x00, 0x00, {0x01,0x00}, 1, 0, 0, 0,0,0,0,0,0,0, {0x38,0x38}, {0x00,0x00} }, + { 0x0209, 0x27, 0x00, 0x00, {0x01,0x00}, 1, 0, 0, 0,0,0,0,0,0,0, {0x10,0x38}, {0x00,0x00} }, + { 0x0000, 0x1D, 0x00, 0x00, {0x00,0x00}, 0, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x1E, 0x00, 0x00, {0x00,0x00}, 0, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0002, 0x21, 0x00, 0x00, {0x00,0x00}, 0, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x0A,0xFF} }, + { 0x0002, 0x24, 0x00, 0x00, {0x00,0x00}, 0, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x0A,0xFF} }, + { 0x0000, 0x25, 0x00, 0x00, {0x00,0x00}, 0, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x26, 0x00, 0x00, {0x00,0x00}, 0, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0229, 0x2B, 0x00, 0x00, {0x01,0x0F}, 2, 0, 0, 0,0,0,1,0,0,0, {0x00,0x38}, {0x00,0x00} }, + { 0x0229, 0x2C, 0x00, 0x00, {0x01,0x0F}, 2, 0, 0, 0,0,0,1,0,0,0, {0x08,0x38}, {0x00,0x00} }, + { 0x0229, 0x2D, 0x00, 0x00, {0x01,0x0F}, 2, 0, 0, 0,0,0,1,0,0,0, {0x10,0x38}, {0x00,0x00} }, + { 0x0229, 0x2E, 0x00, 0x00, {0x01,0x0F}, 2, 0, 0, 0,0,0,1,0,0,0, {0x18,0x38}, {0x00,0x00} }, + { 0x0229, 0x28, 0x00, 0x00, {0x01,0x0F}, 2, 0, 0, 0,0,0,1,0,0,0, {0x20,0x38}, {0x00,0x00} }, + { 0x0229, 0x29, 0x00, 0x00, {0x01,0x0F}, 2, 0, 0, 0,0,0,1,0,0,0, {0x28,0x38}, {0x00,0x00} }, + { 0x0229, 0x2A, 0x00, 0x00, {0x01,0x0F}, 2, 0, 0, 0,0,0,1,0,0,0, {0x38,0x38}, {0x00,0x00} }, + { 0x0209, 0x2F, 0x00, 0x00, {0x01,0x02}, 2, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0209, 0x2F, 0x00, 0x00, {0x01,0x07}, 2, 1, 0, 0,0,0,0,0,0,0, {0x00,0x38}, {0x00,0x00} }, + { 0x0008, 0x2F, 0x00, 0x00, {0x06,0x07}, 2, 1, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0440, 0x30, 0x02, 0x00, {0x00,0x00}, 0, 0, 2, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0008, 0x31, 0x00, 0x00, {0x00,0x00}, 0, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0008, 0x32, 0x00, 0x00, {0x00,0x00}, 0, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0008, 0x33, 0x00, 0x00, {0x00,0x00}, 0, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0008, 0x34, 0x00, 0x00, {0x00,0x00}, 0, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0008, 0x35, 0x00, 0x00, {0x00,0x00}, 0, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0400, 0x5B, 0x02, 0x00, {0x00,0x00}, 0, 0, 1, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0500, 0x5C, 0x02, 0x00, {0x00,0x00}, 0, 0, 3, 0,0,0,0,0,0,3, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x36, 0x00, 0x00, {0x0C,0x00}, 1, 6, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0201, 0x36, 0x00, 0x02, {0x01,0x00}, 1, 0, 0, 0,0,0,0,0,0,0, {0x10,0x38}, {0x00,0x00} }, + { 0x0000, 0x36, 0x01, 0x00, {0x0D,0x00}, 1, 7, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0201, 0x36, 0x01, 0x02, {0x01,0x00}, 1, 0, 0, 0,0,0,0,0,0,0, {0x18,0x38}, {0x00,0x00} }, + { 0x0000, 0x37, 0x00, 0x00, {0x0C,0x00}, 1, 6, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x37, 0x00, 0x00, {0x0B,0x00}, 1, 5, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0201, 0x37, 0x00, 0x02, {0x01,0x00}, 1, 0, 0, 0,0,0,0,0,0,0, {0x20,0x38}, {0x00,0x00} }, + { 0x0000, 0x37, 0x01, 0x00, {0x0D,0x00}, 1, 7, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0201, 0x37, 0x01, 0x02, {0x01,0x00}, 1, 0, 0, 0,0,0,0,0,0,0, {0x28,0x38}, {0x00,0x00} }, + { 0x0000, 0x38, 0x00, 0x00, {0x00,0x00}, 0, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x38, 0x00, 0x00, {0x09,0x00}, 1, 3, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x39, 0x00, 0x00, {0x00,0x00}, 0, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x39, 0x00, 0x00, {0x09,0x00}, 1, 3, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x40, 0x00, 0x00, {0x0B,0x00}, 1, 5, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x48, 0x00, 0x00, {0x0B,0x00}, 1, 5, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x3D, 0x00, 0x00, {0x0B,0x00}, 1, 5, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x45, 0x00, 0x00, {0x0B,0x00}, 1, 5, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x3A, 0x00, 0x00, {0x0B,0x00}, 1, 5, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x42, 0x00, 0x00, {0x0B,0x00}, 1, 5, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x3E, 0x00, 0x00, {0x0B,0x00}, 1, 5, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x46, 0x00, 0x00, {0x0B,0x00}, 1, 5, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x41, 0x00, 0x00, {0x0B,0x00}, 1, 5, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x49, 0x00, 0x00, {0x0B,0x00}, 1, 5, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x3F, 0x00, 0x00, {0x0B,0x00}, 1, 5, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x47, 0x00, 0x00, {0x0B,0x00}, 1, 5, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x3B, 0x00, 0x00, {0x0B,0x00}, 1, 5, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x43, 0x00, 0x00, {0x0B,0x00}, 1, 5, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x3C, 0x00, 0x00, {0x0B,0x00}, 1, 5, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x44, 0x00, 0x00, {0x0B,0x00}, 1, 5, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x4C, 0x00, 0x00, {0x0B,0x00}, 1, 5, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x4B, 0x00, 0x00, {0x0B,0x00}, 1, 5, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x4A, 0x00, 0x00, {0x0B,0x00}, 1, 5, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x4D, 0x00, 0x00, {0x0B,0x00}, 1, 5, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x4E, 0x00, 0x00, {0x08,0x00}, 1, 2, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x4F, 0x00, 0x00, {0x00,0x00}, 0, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x50, 0x00, 0x00, {0x00,0x00}, 0, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x51, 0x00, 0x00, {0x00,0x00}, 0, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x52, 0x00, 0x00, {0x00,0x00}, 0, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x53, 0x00, 0x00, {0x00,0x00}, 0, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x54, 0x00, 0x00, {0x00,0x00}, 0, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x55, 0x00, 0x00, {0x00,0x00}, 0, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x56, 0x00, 0x00, {0x00,0x00}, 0, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x57, 0x00, 0x00, {0x00,0x00}, 0, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x58, 0x00, 0x00, {0x00,0x00}, 0, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x59, 0x00, 0x00, {0x00,0x00}, 0, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, + { 0x0000, 0x5A, 0x00, 0x00, {0x00,0x00}, 0, 0, 0, 0,0,0,0,0,0,0, {0x00,0x00}, {0x00,0x00} }, +}; + +RO_ global U2 x8616_decode_dispatch[256] = +{ + 0x001A, 0x001A, 0x001A, 0x001A, 0x001C, 0x001C, 0x0008, 0x000B, 0x001D, 0x001D, 0x001D, 0x001D, 0x001F, 0x001F, 0x0008, 0x000B, + 0x0020, 0x0020, 0x0020, 0x0020, 0x0022, 0x0022, 0x0008, 0x000B, 0x0023, 0x0023, 0x0023, 0x0023, 0x0025, 0x0025, 0x0008, 0x000B, + 0x0026, 0x0026, 0x0026, 0x0026, 0x0028, 0x0028, 0x0055, 0x0035, 0x0029, 0x0029, 0x0029, 0x0029, 0x002B, 0x002B, 0x0055, 0x003F, + 0x002C, 0x002C, 0x002C, 0x002C, 0x002E, 0x002E, 0x0055, 0x0034, 0x002F, 0x002F, 0x002F, 0x002F, 0x0031, 0x0031, 0x0055, 0x003E, + 0x0033, 0x0033, 0x0033, 0x0033, 0x0033, 0x0033, 0x0033, 0x0033, 0x0037, 0x0037, 0x0037, 0x0037, 0x0037, 0x0037, 0x0037, 0x0037, + 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x000A, 0x000A, 0x000A, 0x000A, 0x000A, 0x000A, 0x000A, 0x000A, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070, 0x0071, 0x0072, + 0x8000, 0x8100, 0x8200, 0x8300, 0x004B, 0x004B, 0x000C, 0x000C, 0x0001, 0x0001, 0x0001, 0x0001, 0x0005, 0x0013, 0x0005, 0x0009, + 0x000D, 0x000D, 0x000D, 0x000D, 0x000D, 0x000D, 0x000D, 0x000D, 0x0042, 0x0043, 0x0058, 0x0083, 0x0018, 0x0019, 0x0017, 0x0016, + 0x0004, 0x0004, 0x0004, 0x0004, 0x004F, 0x004F, 0x0050, 0x0050, 0x004D, 0x004D, 0x0053, 0x0053, 0x0052, 0x0052, 0x0051, 0x0051, + 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, + 0x0000, 0x0000, 0x0060, 0x005F, 0x0015, 0x0014, 0x0002, 0x0002, 0x0000, 0x0000, 0x0062, 0x0061, 0x0078, 0x0077, 0x0079, 0x007A, + 0x8400, 0x8500, 0x8600, 0x8700, 0x0040, 0x0041, 0x0000, 0x0012, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0073, 0x0074, 0x0075, 0x0076, 0x000E, 0x000E, 0x0010, 0x0010, 0x0056, 0x005A, 0x005D, 0x005B, 0x000F, 0x000F, 0x0011, 0x0011, + 0x0054, 0x0000, 0x004E, 0x004E, 0x0082, 0x007C, 0x8800, 0x8900, 0x007B, 0x007D, 0x0080, 0x0081, 0x007E, 0x007F, 0x8A00, 0x8B00, +}; + +RO_ global U1 x8616_decode_aux[3072] = +{ + 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, + 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, + 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, + 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, + 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, + 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, + 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, + 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, + 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, + 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, + 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, + 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, + 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, + 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, + 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, + 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, + 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, + 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, + 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, + 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, + 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, + 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, + 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, + 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, + 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, + 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, + 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, + 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, + 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +enum { + X8616_DECODE_PLAN_COUNT = 132, + X8616_DECODE_AUX_COUNT = 3072, +}; diff --git a/code/8086/info.h b/code/8086/info.h new file mode 100644 index 0000000..8f7c319 --- /dev/null +++ b/code/8086/info.h @@ -0,0 +1,100 @@ +#ifdef INTELLISENSE_DIRECTIVES +# pragma once +# include "duffle/dsl.h" +# include "duffle/memory.h" +# include "duffle/text.h" +#endif + +typedef Enum_(U1, X8616_InfoKind) { + x8616_info_note = 0x0, + x8616_info_warning = 0x1, + x8616_info_error = 0x2, +}; + +typedef Enum_(U1, X8616_InfoCode) { + x8616_info_none = 0x00, + + x8616_info_invalid_opcode = 0x01, + x8616_info_invalid_opcode_extension = 0x02, + x8616_info_invalid_post_opcode = 0x03, + x8616_info_truncated_instruction = 0x04, + x8616_info_output_full = 0x05, + + x8616_info_gen_multiple_payloads = 0x06, + x8616_info_gen_body_cap_exceeded = 0x07, + x8616_info_gen_aux_cap_exceeded = 0x08, + x8616_info_gen_ambiguous_decode = 0x09, + x8616_info_gen_dispatch_mismatch = 0x0A, + + x8616_info_count, +}; + +/* The hot path stores structured diagnostic facts only. + Human-readable text is a projection of those facts. */ +typedef Struct_(X8616_InfoMsg) { + X8616_InfoMsg* next; + X8616_InfoKind kind; + X8616_InfoCode code; + U4 source_offset; + U2 source_size; + U4 expected; + U4 actual; + Str8 text; +}; + +/* Static templates use the same vocabulary as Duffle's str8_fmt_ktl_buf path. + The decoder itself never expands these. */ +RO_ global Str8 x8616_info_templates[x8616_info_count] = { + [x8616_info_none] = str8(""), + [x8616_info_invalid_opcode] = str8("Opcode is not in the Part 1 8086 decode table at ."), + [x8616_info_invalid_opcode_extension] = str8("Opcode extension does not match the selected encoding at ."), + [x8616_info_invalid_post_opcode] = str8("Post-opcode byte does not match expected at ."), + [x8616_info_truncated_instruction] = str8("Instruction at needs bytes; are available."), + [x8616_info_output_full] = str8("Decoded-instruction output is full: capacity , produced ."), + [x8616_info_gen_multiple_payloads] = str8("Encoding describes more than one stream payload."), + [x8616_info_gen_body_cap_exceeded] = str8("Encoding requires body bytes; decoder body capacity is ."), + [x8616_info_gen_aux_cap_exceeded] = str8("Generated auxiliary decode table exceeds capacity ."), + [x8616_info_gen_ambiguous_decode] = str8("Decode is ambiguous for opcode/second-byte key : plans and ."), + [x8616_info_gen_dispatch_mismatch] = str8("Generated dispatch mismatch for opcode/second-byte key : expected , actual ."), +}; + +typedef Struct_(X8616_InfoList) { + X8616_InfoMsg* first; + X8616_InfoMsg* last; + U4 count; + U4 error_count; + U4 warning_count; + U4 dropped_count; +}; + +FI_ Str8 x8616_info_template(X8616_InfoCode code) { return code < x8616_info_count ? x8616_info_templates[code] : x8616_info_templates[x8616_info_none]; } + +FI_ void x8616_info_push(FArena_R scratch + , X8616_InfoList_R list + , X8616_InfoKind kind + , X8616_InfoCode code + , U4 source_offset + , U2 source_size + , U4 expected + , U4 actual +){ + assert(scratch != nullptr); + list->count += 1; + list->error_count += kind == x8616_info_error; + list->warning_count += kind == x8616_info_warning; + + U4 allocation_size = align_pow2(S_(X8616_InfoMsg), MEM_ALIGNMENT_DEFAULT); + U4 left = scratch->capacity - scratch->used; + if (allocation_size > left) { ++ list->dropped_count; return; } + + X8616_InfoMsg_R msg = farena_push_type(scratch, X8616_InfoMsg); + // msg[0] = (X8616_InfoMsg){0}; + msg->kind = kind; + msg->code = code; + msg->source_offset = source_offset; + msg->source_size = source_size; + msg->expected = expected; + msg->actual = actual; + msg->text = x8616_info_template(code); + sll_queue_push_n(list->first, list->last, msg, next); +} diff --git a/code/8086/info_render.h b/code/8086/info_render.h new file mode 100644 index 0000000..f48af43 --- /dev/null +++ b/code/8086/info_render.h @@ -0,0 +1,22 @@ +#ifdef INTELLISENSE_DIRECTIVES +# pragma once +# include "duffle/tables.h" +# include "duffle/text.h" +# include "info.h" +#endif + +/* Numeric representation remains a presentation decision. + Feed whatever Duffle-formatted Str8 values you want here (hex for opcode + facts, decimal for capacities, etc.) and the existing formatter does + the composition. */ +typedef Struct_(X8616_InfoTextValues) { Str8 offset; Str8 expected; Str8 actual; }; + +FI_ Str8 +x8616_info_render(Slice output, X8616_InfoMsg_R msg, X8616_InfoTextValues values) { + KTL_Slot_Str8 slots[] = { + { ktl_str8_key("offset"), values.offset }, + { ktl_str8_key("expected"), values.expected }, + { ktl_str8_key("actual"), values.actual }, + }; + return str8_fmt_ktl_buf(output, ktl_str8_from_arr(slots), msg->text); +} diff --git a/code/duffle/memory.h b/code/duffle/memory.h index 3e8c33f..712a28f 100644 --- a/code/duffle/memory.h +++ b/code/duffle/memory.h @@ -64,8 +64,7 @@ FI_ B4 mem_match (U8 a, U8 b, U8 z) { return mem_compare(a, b, z) == 0; } #pragma region Slice typedef unsigned char TSet_(UTF8); -typedef Struct_(Str8) { UTF8* ptr; U8 len; }; -typedef Str8 Slice_UTF8; +typedef Struct_(Str8) { UTF8* ptr; U8 len; }; typedef Str8 Slice_UTF8; typedef Struct_(Slice_Str8) { Str8* ptr; U8 len; }; #define slit8(string_literal) (Str8){ (UTF8*) string_literal, S_(string_literal) - 1 } #define str8(p,l) (Str8){p,l}