22 Commits
Author SHA1 Message Date
ed 4264e19b37 last thing on runtime encode of the night 2026-09-09 22:35:45 -04:00
ed be55514e93 Runtime encode 2026-09-09 20:00:11 -04:00
ed d08709128a validation 2026-09-09 19:24:32 -04:00
ed e24b68028c drafting an asm parser (rudimentary) 2026-09-09 19:09:06 -04:00
ed 6bb1386995 last updates to comp-time encoder. 2026-09-09 18:25:05 -04:00
ed 2a89a342df done for now, doing validation suite next. 2026-09-09 17:01:22 -04:00
ed 7daa333a71 correct terminology 2026-09-09 16:30:11 -04:00
ed f2a8f6d2cf might have finally finished reviewing the encoder. 2026-09-09 16:23:54 -04:00
ed 8912f3e0e9 sigh 2026-09-09 16:04:16 -04:00
ed 21334b48d8 asm formatting. 2026-09-09 15:07:42 -04:00
ed b973b0cd41 yet more progress 2026-09-09 14:38:56 -04:00
ed 95e67a8c1a simplifcation of encoding table, properly define compositionaly various encoding definitions. 2026-09-09 14:03:30 -04:00
ed 588fa20778 progress 2026-09-09 12:38:18 -04:00
ed d3fd791537 working on serializer 2026-09-09 12:09:12 -04:00
ed 6cca3fbe8b decoder seems to be working, need to make a serializer next. 2026-09-09 01:50:20 -04:00
ed 5e6e139cc0 x8616_decode_gen_emit now easier to read... 2026-09-08 23:46:35 -04:00
ed b9b1ed460a Better str8_fmt_ktl_buf (using simd) 2026-09-08 20:45:57 -04:00
ed 749a712ceb update comment 2026-09-08 15:32:40 -04:00
ed 7e533cbfb2 fixes, convering x8616_decode_gen_emit_plan to use formatting template. 2026-09-08 13:42:59 -04:00
ed 28e6e38c92 decoder table generator (metaprogram) works... will test rest tmrw. 2026-09-05 00:03:12 -04:00
ed 6a456097ba decoder 2026-09-04 22:24:45 -04:00
ed bfd02f4472 misc changes, preparing for 8086 module. 2026-09-04 21:02:31 -04:00
25 changed files with 5167 additions and 317 deletions
+508
View File
@@ -0,0 +1,508 @@
#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* 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* plan;
U1 header;
U1 post_opcode;
U1 mod_rm;
X8616_Direction d;
X8616_Width w;
X8616_Sign s;
X8616_VariableShift v;
X8616_Repeat z;
X8616_ALU alu;
X8616_Condition cc;
X8616_DecodedReg reg_opcode;
X8616_Segment sr_opcode;
X8616_Mod mod;
X8616_DecodedReg reg;
X8616_EA rm;
X8616_Segment 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 X8616_Opcode
x8616_decode_opcode(X8616_DecodePlan const* plan, U1 header)
{
U1 field_mask = 0;
if (plan->flags & x8616_plan_has_d) field_mask |= x8616_field_mask(plan->d_shift, X8616_OPCODE_BIT_WIDTH);
if (plan->flags & x8616_plan_has_w) field_mask |= x8616_field_mask(plan->w_shift, X8616_OPCODE_BIT_WIDTH);
if (plan->flags & x8616_plan_has_s) field_mask |= x8616_field_mask(plan->s_shift, X8616_OPCODE_BIT_WIDTH);
if (plan->flags & x8616_plan_has_v) field_mask |= x8616_field_mask(plan->v_shift, X8616_OPCODE_BIT_WIDTH);
if (plan->flags & x8616_plan_has_z) field_mask |= x8616_field_mask(plan->z_shift, X8616_OPCODE_BIT_WIDTH);
if (plan->flags & x8616_plan_has_reg) field_mask |= x8616_field_mask(plan->reg_shift, X8616_OPCODE_REG_REG_WIDTH);
if (plan->flags & x8616_plan_has_sr) field_mask |= x8616_field_mask(plan->sr_shift, X8616_OPCODE_SR_WIDTH);
if (plan->flags & x8616_plan_has_alu) field_mask |= x8616_field_mask(plan->alu_shift, X8616_OPCODE_ALU_TTT_WIDTH);
if (plan->flags & x8616_plan_has_cc) field_mask |= x8616_field_mask(plan->cc_shift, X8616_OPCODE_CC_WIDTH);
if (field_mask == 0) return C_(X8616_Opcode, header);
U1 opcode_mask = u1_(~field_mask);
if (opcode_mask == 0) return C_(X8616_Opcode, header);
return C_(X8616_Opcode, (header & opcode_mask) >> count_trailing_zeros_u4(opcode_mask));
}
internal void
x8616_decode_apply_prefix(X8616_DecodePlex_R plex, X8616_DecodePlan_R plan, U1 header) {
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 = C_(X8616_Repeat, x8616_bit_field_extract(header, (X8616_BitField){ plan->z_shift, X8616_OPCODE_BIT_WIDTH }));
}
if (plan->prefix_kind == x8616_prefix_segment) {
plex->prefixes.has_segment = 1;
plex->prefixes.segment = C_(X8616_Segment, x8616_bit_field_extract(header, (X8616_BitField){ plan->sr_shift, X8616_OPCODE_SR_WIDTH }));
}
}
internal U4
x8616_decode_one_plex(X8616_DecodePlex* plex)
{
U4 prefix_at = 0;
// Prefix pass. LOCK / REP / segment are prior bytes. Encodings that need a
// second byte (aux dispatch) are never prefixes.
while (prefix_at < plex->source_size)
{
U1 prefix_header = plex->source[prefix_at];
U2 prefix_dispatch = x8616_decode_dispatch[prefix_header];
if (prefix_dispatch == false || (prefix_dispatch & X8616_DECODE_AUX_BIT)) break;
X8616_DecodePlan_R prefix_plan = x8616_decode_plans + prefix_dispatch;
if ((prefix_plan->flags & x8616_plan_is_prefix) == false) break;
x8616_decode_apply_prefix(plex, prefix_plan, prefix_header);
++ 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->header = plex->body[0];
plex->dispatch = x8616_decode_dispatch[plex->header];
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 = 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->header
);
}
}
plex->plan = x8616_decode_plans + plex->plan_idx;
// A direct-dispatch plan may still have a constrained second byte.
// Headers with multiple catalog rows 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.size = u1_(prefix_at + invalid_body_size);
plex->instruction.size_required = plex->instruction.size;
return plex->instruction.size;
}
X8616_DecodePlan_R plan = plex->plan;
plex->d = C_(X8616_Direction, x8616_bit_field_extract(plex->header, (X8616_BitField){ plan->d_shift, X8616_OPCODE_BIT_WIDTH }));
plex->w = C_(X8616_Width, x8616_bit_field_extract(plex->header, (X8616_BitField){ plan->w_shift, X8616_OPCODE_BIT_WIDTH }));
plex->s = C_(X8616_Sign, x8616_bit_field_extract(plex->header, (X8616_BitField){ plan->s_shift, X8616_OPCODE_BIT_WIDTH }));
plex->v = C_(X8616_VariableShift, x8616_bit_field_extract(plex->header, (X8616_BitField){ plan->v_shift, X8616_OPCODE_BIT_WIDTH }));
plex->z = C_(X8616_Repeat, x8616_bit_field_extract(plex->header, (X8616_BitField){ plan->z_shift, X8616_OPCODE_BIT_WIDTH }));
plex->reg_opcode.r16 = C_(X8616_Reg16, x8616_bit_field_extract(plex->header, (X8616_BitField){ plan->reg_shift, X8616_OPCODE_REG_REG_WIDTH }));
plex->sr_opcode = C_(X8616_Segment, x8616_bit_field_extract(plex->header, (X8616_BitField){ plan->sr_shift, X8616_OPCODE_SR_WIDTH }));
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 = C_(X8616_Mod, x8616_modrm_mod(plex->mod_rm));
plex->reg.r16 = C_(X8616_Reg16, x8616_modrm_reg(plex->mod_rm));
plex->rm = C_(X8616_EA, x8616_modrm_rm(plex->mod_rm));
plex->sr_modrm = C_(X8616_Segment, x8616_modrm_sr(plex->mod_rm));
plex->body_at += 1;
}
if (plan->flags & x8616_plan_has_alu) {
plex->alu = C_(X8616_ALU, x8616_bit_field_extract(plex->header, (X8616_BitField){ plan->alu_shift, X8616_OPCODE_ALU_TTT_WIDTH }));
}
if (plan->flags & x8616_plan_has_cc) {
plex->cc = C_(X8616_Condition, x8616_bit_field_extract(plex->header, (X8616_BitField){ plan->cc_shift, X8616_OPCODE_CC_WIDTH }));
}
plex->displacement_at = plex->body_at;
if (plan->flags & x8616_plan_uses_rm) plex->displacement_bytes = x8616_decode_disp_bytes[(u1_(plex->mod) << 3) | u1_(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.r16 = x8616_ax;
source[x8616_operand_dx].flags = x8616_decoded_operand_register | x8616_decoded_operand_implicit;
source[x8616_operand_dx].width = x8616_width_word;
source[x8616_operand_dx].reg.r16 = x8616_dx;
source[x8616_operand_rm].width = plex->width;
if (plex->mod == x8616_mod_reg) {
source[x8616_operand_rm].flags = x8616_decoded_operand_register;
source[x8616_operand_rm].reg.r16 = C_(X8616_Reg16, plex->rm);
}
else {
source[x8616_operand_rm].flags = x8616_decoded_operand_memory;
source[x8616_operand_rm].mod = plex->mod;
source[x8616_operand_rm].ea = plex->rm;
source[x8616_operand_rm].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 = 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, 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 = 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.r8 = 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) & u1_(plex->d));
plex->instruction.operands[swap] = source[plan->operands[0]];
plex->instruction.operands[swap ^ 1] = source[plan->operands[1]];
plex->instruction.op = plan->op;
if (plan->flags & x8616_plan_has_alu) {
plex->instruction.alu = plex->alu;
plex->instruction.op = x8616_op_from_alu[plex->alu];
}
if (plan->flags & x8616_plan_has_cc) {
plex->instruction.cc = plex->cc;
plex->instruction.op = x8616_op_from_cc[plex->cc];
}
if (plan->digit_kind != x8616_digit_none) {
U1 digit = u1_(plex->reg.r16);
if (plan->digit_kind == x8616_digit_alu) {
plex->alu = C_(X8616_ALU, digit);
plex->instruction.alu = plex->alu;
plex->instruction.op = x8616_op_from_alu[digit];
}
else if (plan->digit_kind == x8616_digit_shift) plex->instruction.op = x8616_op_from_shift[digit];
}
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 = x8616_decode_opcode(plan, plex->header);
plex->instruction.d = (plan->flags & x8616_plan_has_d) ? plex->d : x8616_d_rm_dst;
plex->instruction.w = (plan->flags & x8616_plan_has_w) ? plex->w : x8616_w_byte;
plex->instruction.has_mod_rm = (plan->flags & x8616_plan_has_modrm) != 0;
plex->instruction.header = plex->header;
plex->instruction.mod_rm = plex->mod_rm;
plex->instruction.post_opcode = plex->post_opcode;
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;
}
#define x8616_decode_(...) x8616_decode((X8616_DecodeRequest){__VA_ARGS__})
X8616_DecodeInfo x8616_decode(X8616_DecodeRequest request)
{
X8616_DecodeInfo result = {0};
result.instruction_cap = request.instruction_cap;
while (result.source_consumed < request.source_len && result.instruction_count < request.instruction_cap) {
X8616_DecodePlex plex = {0};
plex.source = request.source + result.source_consumed;
plex.source_size = request.source_len - 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.out_instructions[result.instruction_count] = plex.instruction;
result.instruction_count += 1;
if (consumed == false) consumed = 1;
result.source_consumed += consumed;
}
if (result.source_consumed < request.source_len && result.instruction_count == request.instruction_cap) {
x8616_info_push(request.info_arena, & result.msgs, x8616_info_warning
, x8616_info_output_full
, result.source_consumed
, 0
, request.instruction_cap
, 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;
}
+177
View File
@@ -0,0 +1,177 @@
#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) {
Bit_(x8616_decoded_operand_none, 0),
Bit_(x8616_decoded_operand_register, 1),
Bit_(x8616_decoded_operand_segment, 2),
Bit_(x8616_decoded_operand_memory, 3),
Bit_(x8616_decoded_operand_immediate, 4),
Bit_(x8616_decoded_operand_relative, 5),
Bit_(x8616_decoded_operand_far_ptr, 6),
Bit_(x8616_decoded_operand_direct, 7),
Bit_(x8616_decoded_operand_sign_extended, 8),
Bit_(x8616_decoded_operand_implicit, 9),
};
typedef Union_(X8616_DecodedReg) {
X8616_Reg8 r8;
X8616_Reg16 r16;
};
typedef Struct_(X8616_DecodedOperand) {
X8616_DecodedOperandFlags flags;
X8616_WidthMode width;
X8616_DecodedReg reg;
X8616_Segment segment;
X8616_Mod mod;
X8616_EA 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;
X8616_Opcode opcode;
X8616_Direction d;
X8616_Width w;
X8616_ALU alu;
X8616_Condition cc;
B1 has_mod_rm;
U1 header;
U1 mod_rm;
U1 post_opcode;
U1 size;
U1 size_required;
};
typedef Enum_(U2, X8616_DecodePlanFlags) {
Bit_(x8616_plan_none, 0),
Bit_(x8616_plan_has_modrm, 1),
Bit_(x8616_plan_has_post_opcode, 2),
Bit_(x8616_plan_has_d, 3),
Bit_(x8616_plan_has_w, 4),
Bit_(x8616_plan_has_s, 5),
Bit_(x8616_plan_has_v, 6),
Bit_(x8616_plan_has_z, 7),
Bit_(x8616_plan_has_reg, 8),
Bit_(x8616_plan_has_sr, 9),
Bit_(x8616_plan_uses_rm, 10),
Bit_(x8616_plan_is_prefix, 11),
Bit_(x8616_plan_has_alu, 12),
Bit_(x8616_plan_has_cc, 13),
};
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;
U1 alu_shift;
U1 cc_shift;
X8616_DigitKind digit_kind;
};
enum {
X8616_DECODE_PLAN_INVALID = 0x00,
X8616_DECODE_AUX_BIT = 0x8000,
X8616_DECODE_AUX_MASK = 0x7FFF,
};
typedef Struct_(X8616_DecodeRequest) {
U1* source;
X8616_DecodedInstruction* out_instructions;
U4 source_len;
U4 instruction_cap;
FArena* info_arena;
};
typedef Struct_(X8616_DecodeInfo) {
X8616_InfoList msgs;
U4 source_consumed;
U4 instruction_count;
U4 instruction_cap;
};
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);
+493
View File
@@ -0,0 +1,493 @@
#include "duffle/dsl.h"
#include "duffle/asm.h"
#include "duffle/analysis.h"
#include "duffle/math.h"
#include "duffle/encoding.h"
#include "duffle/memory.h"
#include "duffle/hashing.h"
#include "duffle/tables.h"
#include "duffle/text.h"
#include "duffle/files.h"
#include "duffle/win32.h"
#include "info.h"
#include "encoder.h"
#include "encoder_table.h"
#include "decoder.h"
enum {
X8616_DECODE_GEN_MAX_AUX = X8616_DECODE_AUX_MASK + 1,
};
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_header_count;
U4 verified_count;
X8616_InfoList msgs;
};
typedef Struct_(X8616_DecodeGenInfo) {
U4 plan_count;
U4 aux_count;
U4 ambiguous_header_count;
U4 verified_count;
X8616_InfoList msgs;
};
FI_ B4 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_ B4 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_R encoding, U4 encoding_idx, X8616_InfoList_R 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 (encoding->fields.alu.width) { plan.flags |= x8616_plan_has_alu; plan.alu_shift = encoding->fields.alu.shift; }
if (encoding->fields.cc.width) { plan.flags |= x8616_plan_has_cc; plan.cc_shift = encoding->fields.cc.shift; }
plan.digit_kind = encoding->digit_kind;
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_ B4 x8616_decode_gen_encoding_matches_header(X8616_Encoding_R encoding, U1 header) {
return (header & encoding->header.mask) == encoding->header.bits;
}
FI_ B4 x8616_decode_gen_plan_matches_second(X8616_DecodePlan_R 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 header = 0; header < 256; ++ header)
{
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_header(x8616_encodings + encoding_idx, C_(U1, header)))
candidates[candidate_count ++] = C_(U1, encoding_idx + 1);
if (candidate_count == 0) continue;
if (candidate_count == 1) { gen->dispatch[header] = 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
, header
, 0
, X8616_DECODE_GEN_MAX_AUX
, gen->aux_count + 256
);
return;
}
U4 base = gen->aux_count;
gen->dispatch[header] = C_(U2, X8616_DECODE_AUX_BIT | base);
gen->aux_count += 256;
gen->ambiguous_header_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
, (header << 8) | second
, 0
, selected
, plan_idx
);
selected = plan_idx;
}
gen->aux[base + second] = selected;
}
}
}
internal void
x8616_decode_gen_pass_validate(X8616_DecodeGen_R gen, FArena_R info_scratch)
{
for (U4 header = 0; header < 256; ++ header)
for (U4 second = 0; second < 256; ++ second)
{
U1 expected = 0;
for (U4 encoding_idx = 0; encoding_idx < X8616_ENCODING_COUNT; ++ encoding_idx)
{
X8616_Encoding_R encoding = x8616_encodings + encoding_idx;
if (x8616_decode_gen_encoding_matches_header(encoding, C_(U1, header)) == false) continue;
X8616_DecodePlan_R plan = gen->plans + encoding_idx + 1;
if (x8616_decode_gen_plan_matches_second(plan, C_(U1, second)) == false) continue;
if (expected) x8616_info_push(info_scratch, & gen->msgs, x8616_info_error
, x8616_info_gen_ambiguous_decode
, (header << 8) | second, 0
, expected, encoding_idx + 1
);
expected = C_(U1, encoding_idx + 1);
}
U2 dispatch = gen->dispatch[header];
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
, (header << 8) | second, 0
, expected, actual
);
++ gen->verified_count;
}
}
X8616_DecodeGenInfo
x8616_decode_table_generate(X8616_DecodeGen* gen, FArena_R info_scratch) {
mem_zero_struct(gen[0]);
// 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_header_count = gen->ambiguous_header_count,
.verified_count = gen->verified_count,
.msgs = gen->msgs,
};
return result;
}
#define X8616_DECODE_TABLE_OUTPUT "./code/8086/gen/decoder_table.h"
enum {
INFO_MEMORY_SIZE = kilo(64),
TEXT_MEMORY_SIZE = kilo(128),
FILE_MEMORY_SIZE = kilo(4),
};
typedef FStack_(FStack_64k, U1, kilo(64));
typedef Struct_(SMemory) {
U1 info[INFO_MEMORY_SIZE];
U1 text[TEXT_MEMORY_SIZE];
U1 file[FILE_MEMORY_SIZE];
FStack_64k scratch;
X8616_DecodeGen gen;
};
global SMemory smem;
I_ void str8gen_append_u4(Str8Gen_R out, U4 value, U4 radix, U4 min_digits) {
UTF8 buffer[64]; Info_str8_from_u4 info = str8_from_u4_info(value, radix, min_digits, 0);
Str8 text = str8_from_u4_buf(slice_ut_arr(buffer), value, radix, min_digits, 0, info);
str8gen_append_str8(out, text);
}
I_ void str8gen_append_hex_u1(Str8Gen_R out, U1 value) { str8gen_append_u4(out, value, 16, 2); }
I_ void str8gen_append_hex_u2(Str8Gen_R out, U2 value) { str8gen_append_u4(out, value, 16, 4); }
I_ void str8gen_append_dec (Str8Gen_R out, U4 value) { str8gen_append_u4(out, value, 10, 1); }
FI_ Slice scratch_push(U8 len) { return fstack_push_(smem.scratch, len); }
typedef Opt_(str8_from_u4) { U4 radix, min_digits, digit_group_separator; };
I_ Str8 str8_from_u4_opt(U4 num, Opt_str8_from_u4 o) { if (o.radix == 0) {o.radix = 10;}
/*gather info*/Info_str8_from_u4 info = str8_from_u4_info(num, o.radix, o.min_digits, o.digit_group_separator);
/*write buf */return str8_from_u4_buf(scratch_push(128), num, o.radix, o.min_digits, o.digit_group_separator, info);
}
#define str8_from_u4(num, ...) str8_from_u4_opt(num, opt_(str8_from_u4, __VA_ARGS__))
#define code_str8(...) slit8(stringify(__VA_ARGS__))
#define dec(v) str8_from_u4(v, .radix = 10, .min_digits = 1)
#define hex_u1(v) str8_from_u4(v, .radix = 16, .min_digits = 2)
#define hex_u2(v) str8_from_u4(v, .radix = 16, .min_digits = 4)
#define entry(k,v) { ktl_str8_key(k), v }
internal void
x8616_decode_gen_emit_plan(Str8Gen_R out, X8616_DecodePlan_R plan) { defer_rewind(smem.scratch.top) {
Str8 template = code_str8(
\t{
<flags>, <op>, <encoding_flags>, <width>,
{<operands[0]>, <operands[1]>}, <operand_count>,
<payload>, <prefix_kind>,
<d_shift>, <w_shift>, <s_shift>, <v_shift>, <z_shift>, <reg_shift>, <sr_shift>,
{<mod_rm.bits>, <mod_rm.mask>},
{<post_opcode.bits>, <post_opcode.mask>},
<alu_shift>, <cc_shift>, <digit_kind>,
},\n
);
KTL_Slot_Str8 tbl[] = {
entry("flags", hex_u2(plan->flags)),
entry("op", hex_u1(plan->op)),
entry("encoding_flags", hex_u1(plan->encoding_flags)),
entry("width", hex_u1(plan->width)),
entry("operands[0]", hex_u1(plan->operands[0])),
entry("operands[1]", hex_u1(plan->operands[1])),
entry("operand_count", dec(plan->operand_count)),
entry("payload", dec(plan->payload)),
entry("prefix_kind", dec(plan->prefix_kind)),
entry("d_shift", dec(plan->d_shift)),
entry("w_shift", dec(plan->w_shift)),
entry("s_shift", dec(plan->s_shift)),
entry("v_shift", dec(plan->v_shift)),
entry("z_shift", dec(plan->z_shift)),
entry("reg_shift", dec(plan->reg_shift)),
entry("sr_shift", dec(plan->sr_shift)),
entry("mod_rm.bits", hex_u1(plan->mod_rm.bits)),
entry("mod_rm.mask", hex_u1(plan->mod_rm.mask)),
entry("post_opcode.bits", hex_u1(plan->post_opcode.bits)),
entry("post_opcode.mask", hex_u1(plan->post_opcode.mask)),
entry("alu_shift", dec(plan->alu_shift)),
entry("cc_shift", dec(plan->cc_shift)),
entry("digit_kind", dec(plan->digit_kind)),
};
str8gen_append_fmt(out, template, ktl_str8_from_arr(tbl));
}}
#define gen_fmt(out, tmpl, ...) str8gen_append_fmt((out), (tmpl), ktl_str8_from_arr(((KTL_Slot_Str8[]){ __VA_ARGS__ })))
internal Str8
x8616_decode_gen_emit(Str8Gen_R out, X8616_DecodeGen_R gen)
{
#pragma push_macro("RO_")
#pragma push_macro("global")
#undef RO_
#undef global
defer_rewind(smem.scratch.top)
{
str8gen_append_str8(out, slit8(
"// Generated from encoder_table.h. Do not hand-edit.\n"
"// Plan 0 is a nil/invalid entry.\n"
"#ifdef INTELLISENSE_DIRECTIVES\n"
"#\tinclude \"dsl.h\"\n"
"#endif\n\n"
));
gen_fmt(out, code_str8(RO_ global X8616_DecodePlan x8616_decode_plans[<plan_count>] =\n{\n)
, entry("plan_count", dec(X8616_ENCODING_COUNT + 1))
);
for (U4 idx = 0; idx < X8616_ENCODING_COUNT + 1; ++ idx) { x8616_decode_gen_emit_plan(out, gen->plans + idx); }
str8gen_append_str8(out, code_str8(
};\n\n
));
str8gen_append_str8(out, code_str8(RO_ global U2 x8616_decode_dispatch[256] =\n{\n));
{
Str8 line = code_str8(\t<e0>, <e1>, <e2>, <e3>, <e4>, <e5>, <e6>, <e7>, <e8>, <e9>, <e10>, <e11>, <e12>, <e13>, <e14>, <e15>,\n);
for (U4 idx = 0; idx < 256; idx += 16) defer_rewind(smem.scratch.top) {
U2_R d = gen->dispatch + idx;
gen_fmt(out, line,
entry("e0", hex_u2(d[0])),
entry("e1", hex_u2(d[1])),
entry("e2", hex_u2(d[2])),
entry("e3", hex_u2(d[3])),
entry("e4", hex_u2(d[4])),
entry("e5", hex_u2(d[5])),
entry("e6", hex_u2(d[6])),
entry("e7", hex_u2(d[7])),
entry("e8", hex_u2(d[8])),
entry("e9", hex_u2(d[9])),
entry("e10", hex_u2(d[10])),
entry("e11", hex_u2(d[11])),
entry("e12", hex_u2(d[12])),
entry("e13", hex_u2(d[13])),
entry("e14", hex_u2(d[14])),
entry("e15", hex_u2(d[15]))
);
}
}
str8gen_append_str8(out, code_str8(};\n\n));
gen_fmt(out, code_str8(RO_ global U1 x8616_decode_aux[<aux_count>] =\n{\n)
, entry("aux_count", dec(gen->aux_count))
);
{
Str8 line = code_str8(\t<a0>, <a1>, <a2>, <a3>, <a4>, <a5>, <a6>, <a7>, <a8>, <a9>, <a10>, <a11>, <a12>, <a13>, <a14>, <a15>,\n);
U4 idx = 0;
for (; idx + 16 <= gen->aux_count; idx += 16) defer_rewind(smem.scratch.top) {
U1_R a = gen->aux + idx;
gen_fmt(out, line,
entry("a0", hex_u1(a[0])),
entry("a1", hex_u1(a[1])),
entry("a2", hex_u1(a[2])),
entry("a3", hex_u1(a[3])),
entry("a4", hex_u1(a[4])),
entry("a5", hex_u1(a[5])),
entry("a6", hex_u1(a[6])),
entry("a7", hex_u1(a[7])),
entry("a8", hex_u1(a[8])),
entry("a9", hex_u1(a[9])),
entry("a10", hex_u1(a[10])),
entry("a11", hex_u1(a[11])),
entry("a12", hex_u1(a[12])),
entry("a13", hex_u1(a[13])),
entry("a14", hex_u1(a[14])),
entry("a15", hex_u1(a[15]))
);
}
if (idx < gen->aux_count) {
str8gen_append_str8(out, slit8("\t"));
for (; idx < gen->aux_count; ++ idx) {
str8gen_append_hex_u1(out, gen->aux[idx]); str8gen_append_str8(out, slit8(", "));
}
str8gen_append_str8(out, slit8("\n"));
}
}
str8gen_append_str8(out, code_str8(};\n\n));
gen_fmt(out, code_str8(enum {\n
\tX8616_DECODE_PLAN_COUNT = <plan_count>,\n
\tX8616_DECODE_AUX_COUNT = <aux_count>,
\n};\n
),
entry("plan_count", dec(X8616_ENCODING_COUNT + 1)),
entry("aux_count", dec(gen->aux_count))
);
}
return str8(out->ptr, out->len);
#pragma pop_macro("RO_")
#pragma pop_macro("global")
}
#undef gen_fmt
#undef entry
#undef hex_u2
#undef hex_u1
#undef dec
int main(void) {
FArena info_scratch = farena_make(slice_ut_arr(smem.info));
X8616_DecodeGenInfo gen_info = x8616_decode_table_generate(& smem.gen, & info_scratch);
if (gen_info.msgs.error_count) { ms_exit_process(1); return 1; }
Str8Gen output = str8gen_make(slice_ut_arr(smem.text));
Str8 generated = x8616_decode_gen_emit(& output, & smem.gen);
FArena file_scratch = farena_make(slice_ut_arr(smem.file));
B4 wrote = write_data_to_file_path(slit8(X8616_DECODE_TABLE_OUTPUT), generated, & file_scratch);
if (wrote == false) { ms_exit_process(2); return 2; }
if (gen_info.verified_count != 256 * 256) { ms_exit_process(3); return 3; }
ms_exit_process(0);
return 0;
}
+318
View File
@@ -0,0 +1,318 @@
#ifdef INTELLISENSE_DIRECTIVES
# include "encode.h"
# include "encoder_table.h"
#endif
internal void
x8616_encode_push(FArena_R arena, X8616_InfoList_R msgs, X8616_EncodeStatus status, U4 id, U2 size, U4 expected, U4 actual) {
if (status == x8616_encode_ok || arena == 0) return;
X8616_InfoKind kind = x8616_info_error;
X8616_InfoCode code = x8616_info_encode_invalid_record;
if (status == x8616_encode_output_full) code = x8616_info_encode_output_full;
else if (status == x8616_encode_bad_request) code = x8616_info_encode_bad_request;
x8616_info_push(arena, msgs, kind, code, id, size, expected, actual);
}
FI_ void x8616_encode_buf_u1(U1_R buf, U1_R n, U1 value) { buf[n[0]] = value; n[0] += 1; }
FI_ void x8616_encode_buf_u2(U1_R buf, U1_R n, U2 value) {
x8616_encode_buf_u1(buf, n, u1_(value));
x8616_encode_buf_u1(buf, n, u1_(value >> 8));
}
FI_ void x8616_encode_buf_disp(U1_R buf, U1_R n, S2 value, U1 bytes) {
if (bytes == 1) x8616_encode_buf_u1(buf, n, u1_(value));
if (bytes == 2) x8616_encode_buf_u2(buf, n, u2_(value));
}
I_ B4 x8616_encode_is_alu (X8616_Op op) { return op >= x8616_op_add && op <= x8616_op_cmp; }
I_ B4 x8616_encode_is_shift (X8616_Op op) { return op >= x8616_op_shl && op <= x8616_op_rcr; }
I_ B4 x8616_encode_is_jcc (X8616_Op op) { return op >= x8616_op_je && op <= x8616_op_jns; }
I_ U1 x8616_encode_alu_from_op(X8616_Op op) { return u1_(op - x8616_op_add); }
I_ U1 x8616_encode_cc_from_op (X8616_Op op) {
for (U1 i = 0; i < Array_len(x8616_op_from_cc); ++i) if (x8616_op_from_cc[i] == op) return i;
return 0;
}
I_ U1 x8616_encode_shift_from_op(X8616_Op op) {
for (U1 i = 0; i < Array_len(x8616_op_from_shift); ++i) if (x8616_op_from_shift[i] == op) return i;
return 0;
}
I_ void x8616_encode_or_field(U1_R header, X8616_BitField f, U1 value) {
header[0] |= (value << f.shift) & x8616_field_mask(f.shift, f.width);
}
FI_ U1 x8616_encode_prefix_count(X8616_DecodedInstruction_R inst) {
return u1_(inst->prefixes.lock) + u1_(inst->prefixes.has_repeat) + u1_(inst->prefixes.has_segment);
}
FI_ B4 x8616_encode_is_acc(X8616_DecodedOperand_R op) {
if ((op->flags & x8616_decoded_operand_register) == 0) return 0;
if (op->width == x8616_width_byte) return op->reg.r8 == x8616_al;
return op->reg.r16 == x8616_ax;
}
RO_ global U2 x8616_encode_slot_any[] = {
[x8616_operand_none] = 0,
[x8616_operand_rm] = x8616_decoded_operand_register | x8616_decoded_operand_memory,
[x8616_operand_reg_modrm] = x8616_decoded_operand_register,
[x8616_operand_reg_opcode] = x8616_decoded_operand_register,
[x8616_operand_segment_modrm] = x8616_decoded_operand_segment,
[x8616_operand_segment_opcode] = x8616_decoded_operand_segment,
[x8616_operand_acc] = x8616_decoded_operand_register,
[x8616_operand_imm] = x8616_decoded_operand_immediate,
[x8616_operand_imm8] = x8616_decoded_operand_immediate,
[x8616_operand_imm16] = x8616_decoded_operand_immediate,
[x8616_operand_mem_direct] = x8616_decoded_operand_memory,
[x8616_operand_rel8] = x8616_decoded_operand_relative,
[x8616_operand_rel16] = x8616_decoded_operand_relative,
[x8616_operand_far_ptr] = x8616_decoded_operand_far_ptr,
[x8616_operand_dx] = x8616_decoded_operand_register,
[x8616_operand_shift_count] = x8616_decoded_operand_register | x8616_decoded_operand_immediate,
};
I_ B4 x8616_encode_slot_match(X8616_Operand slot, X8616_DecodedOperand_R op, X8616_DecodedInstruction_R inst) {
B4 ok = (op->flags & x8616_encode_slot_any[slot]) != 0;
ok &= (slot != x8616_operand_acc) || x8616_encode_is_acc(op);
ok &= (slot != x8616_operand_dx) || (op->reg.r16 == x8616_dx);
ok &= (slot != x8616_operand_imm8) || (op->immediate <= 0xFF);
ok &= (slot != x8616_operand_mem_direct) || ((op->flags & x8616_decoded_operand_direct) != 0);
ok &= (slot != x8616_operand_shift_count) || ((op->flags & x8616_decoded_operand_register) && op->reg.r8 == x8616_cl) || (op->immediate == 1);
if (slot == x8616_operand_rel8 && ok) {
S2 machine = s2_(op->displacement - s2_(x8616_encode_prefix_count(inst) + 2));
ok = machine >= -128 && machine <= 127;
}
return ok;
}
FI_ U1 x8616_encode_enc_count(X8616_Encoding_R enc) { return u1_(enc->operands[0] != x8616_operand_none) + u1_(enc->operands[1] != x8616_operand_none); }
I_ B4 x8616_encode_op_match(X8616_Encoding_R enc, X8616_Op op) {
B4 prefix = (enc->flags & x8616_encoding_prefix) != 0;
B4 exact = enc->op == op;
B4 family = enc->op == x8616_op_invalid;
B4 alu = family && (enc->fields.alu.width || enc->digit_kind == x8616_digit_alu) && x8616_encode_is_alu(op);
B4 cc = family && enc->fields.cc.width && x8616_encode_is_jcc(op);
B4 shift = family && enc->digit_kind == x8616_digit_shift && x8616_encode_is_shift(op);
return prefix == 0 && (exact || alu || cc || shift);
}
I_ B4 x8616_encode_row_match(X8616_Encoding_R enc, X8616_DecodedInstruction_R inst, U1 d) {
B4 op_ok = x8616_encode_op_match(enc, inst->op);
B4 enc_far = (enc->flags & x8616_encoding_far) != 0;
B4 inst_far = (inst->flags & x8616_encoding_far) != 0;
inst_far |= (inst->operands[0].flags & x8616_decoded_operand_far_ptr) != 0;
inst_far |= (inst->operands[1].flags & x8616_decoded_operand_far_ptr) != 0;
B4 far_ok = enc_far == inst_far;
B4 width_any = enc->width == x8616_width_dynamic || inst->width == x8616_width_dynamic;
B4 width_ok = width_any || enc->width == inst->width;
B4 count_ok = x8616_encode_enc_count(enc) == inst->operand_count;
B4 d_ok = enc->fields.d.width || d == 0;
B4 slots_ok = 1;
for (U1 i = 0; i < inst->operand_count; ++i) {
U1 slot_i = d ? (i ^ 1) : i;
slots_ok &= x8616_encode_slot_match(enc->operands[slot_i], inst->operands + i, inst);
}
return op_ok && far_ok && width_ok && count_ok && d_ok && slots_ok;
}
FI_ U1 x8616_encode_row_score(X8616_Encoding const* enc) {
U1 score = 0;
for (U1 i = 0; i < 2; ++i) {
X8616_Operand s = enc->operands[i];
if (s == x8616_operand_reg_opcode || s == x8616_operand_acc || s == x8616_operand_mem_direct) score += 2;
if (s == x8616_operand_rel8 || s == x8616_operand_imm8) score += 1;
}
return score;
}
I_ B4 x8616_encode_slot_modrm(X8616_Operand s) { return s == x8616_operand_rm || s == x8616_operand_reg_modrm || s == x8616_operand_segment_modrm; }
I_ B4 x8616_encode_needs_modrm(X8616_Encoding const* enc) {
B4 masked = enc->mod_rm.mask != 0;
B4 digit = enc->digit_kind != x8616_digit_none;
B4 slots = x8616_encode_slot_modrm(enc->operands[0]) || x8616_encode_slot_modrm(enc->operands[1]);
return masked || digit || slots;
}
internal B4
x8616_encode_assemble(X8616_DecodedInstruction_R inst)
{
X8616_Encoding const* best = 0;
U1 best_d = 0;
U1 best_score = 0;
B4 found = 0;
for (U4 id = 0; id < Array_len(x8616_encodings); ++id)
{
X8616_Encoding_R enc = x8616_encodings + id;
U1 d_hi = enc->fields.d.width ? 1 : 0;
for (U1 d = 0; d <= d_hi; ++d) {
if (x8616_encode_row_match(enc, inst, d) == 0) continue;
U1 score = x8616_encode_row_score(enc);
B4 not_bested = found && (score < best_score || (score == best_score && d < best_d));
if (not_bested) continue;
best = enc; best_d = d; best_score = score; found = 1;
}
}
if (found == 0) return 0;
X8616_DecodedOperand_R slot[X8616_OPERAND_SOURCE_COUNT] = {0};
for (U1 op_id = 0; op_id < inst->operand_count; ++op_id) {
U1 slot_id = best_d ? (op_id ^ 1) : op_id;
slot[best->operands[slot_id]] = inst->operands + op_id;
}
X8616_DecodedOperand_R operand_acc = slot[x8616_operand_acc];
X8616_Width w = inst->width == x8616_width_word ? x8616_w_word : x8616_w_byte;
if (operand_acc) w = operand_acc->width == x8616_width_word ? x8616_w_word : x8616_w_byte;
U1 header = best->header.bits;
X8616_DecodedOperand_R sc = slot[x8616_operand_shift_count];
X8616_DecodedOperand_R imm = slot[x8616_operand_imm];
if (imm == 0) imm = slot[x8616_operand_imm8];
if (imm == 0) imm = slot[x8616_operand_imm16];
U1 s = 0;
if (best->fields.s.width && imm) {
s = (inst->width == x8616_width_word && imm->immediate_bytes <= 1) || (imm->flags & x8616_decoded_operand_sign_extended);
}
U1 v = sc && (sc->flags & x8616_decoded_operand_register);
U1 reg_op = slot[x8616_operand_reg_opcode] ? u1_(slot[x8616_operand_reg_opcode ]->reg.r16) : 0;
U1 sr_op = slot[x8616_operand_segment_opcode] ? u1_(slot[x8616_operand_segment_opcode]->segment) : 0;
x8616_encode_or_field(& header, best->fields.w, u1_(w));
x8616_encode_or_field(& header, best->fields.d, best_d);
x8616_encode_or_field(& header, best->fields.alu, x8616_encode_alu_from_op(inst->op));
x8616_encode_or_field(& header, best->fields.cc, x8616_encode_cc_from_op(inst->op));
x8616_encode_or_field(& header, best->fields.reg, reg_op);
x8616_encode_or_field(& header, best->fields.sr, sr_op);
x8616_encode_or_field(& header, best->fields.v, v);
x8616_encode_or_field(& header, best->fields.s, s);
header = (header & ~best->header.mask) | (best->header.bits & best->header.mask);
if (sc && (sc->flags & x8616_decoded_operand_immediate) && sc->immediate == 1) sc->immediate_bytes = 0;
U1 modrm = 0;
B4 has_modrm = x8616_encode_needs_modrm(best);
X8616_DecodedOperand_R rm_op = slot[x8616_operand_rm];
U1 mod = x8616_mod_reg;
U1 rm = 0;
if (rm_op) {
B4 mem = (rm_op->flags & x8616_decoded_operand_memory) != 0;
B4 dir = (rm_op->flags & x8616_decoded_operand_direct) != 0;
B4 bp0 = mem && dir == 0 && rm_op->displacement_bytes == 0 && rm_op->ea == x8616_ea_bp;
if (bp0) { rm_op->displacement_bytes = 1; rm_op->displacement = 0; }
U1 db = rm_op->displacement_bytes;
mod = mem ? (dir ? x8616_mod_mem : (db > 2 ? 2 : db)) : x8616_mod_reg;
rm = dir ? u1_(x8616_ea_direct) : (mem ? u1_(rm_op->ea) : u1_(rm_op->reg.r16));
}
U1 kind_digit[3] = { 0, x8616_encode_alu_from_op(inst->op), x8616_encode_shift_from_op(inst->op) };
U1 reg = slot[x8616_operand_reg_modrm] ? u1_(slot[x8616_operand_reg_modrm]->reg.r16) : 0;
if (best->digit_kind) reg = kind_digit[best->digit_kind];
X8616_DecodedOperand_R sr_m = slot[x8616_operand_segment_modrm];
modrm = sr_m ? x8616_enc_modrm_seg(mod, sr_m->segment, rm) : x8616_enc_modrm(mod, reg, rm);
modrm = (modrm & ~best->mod_rm.mask) | (best->mod_rm.bits & best->mod_rm.mask);
X8616_DecodedOperand_R rel = slot[x8616_operand_rel8];
U1 rel_bytes = 1;
if (rel == 0) { rel = slot[x8616_operand_rel16]; rel_bytes = 2; }
if (imm) {
U1 imm16 = slot[x8616_operand_imm16] != 0;
U1 imm8 = slot[x8616_operand_imm8] != 0;
imm->immediate_bytes = imm16 ? 2 : (imm8 || w == x8616_w_byte || s ? 1 : 2);
}
if (rel) {
U1 size = x8616_encode_prefix_count(inst) + 1 + rel_bytes;
rel->displacement = s2_(rel->displacement - s2_(size));
rel->displacement_bytes = rel_bytes;
}
inst->header = header;
inst->mod_rm = modrm;
inst->has_mod_rm = has_modrm;
inst->post_opcode = best->post_opcode.mask ? best->post_opcode.bits : 0;
return 1;
}
internal X8616_EncodeStatus
x8616_encode_instruction(Str8Gen_R gen, X8616_DecodedInstruction_R inst)
{
if (inst->decode_flags & (x8616_decode_invalid | x8616_decode_truncated)) return x8616_encode_invalid_record;
X8616_DecodedInstruction local = *inst;
if (local.size == 0) {
if (x8616_encode_assemble(& local) == 0) return x8616_encode_invalid_record;
}
U1 buf[16];
U1 n = 0;
U1 rep = local.prefixes.repeat == x8616_rep ? x8616_rep_prefix() : x8616_repne_prefix();
if (local.prefixes.lock) { x8616_encode_buf_u1(buf, & n, x8616_lock_prefix()); }
if (local.prefixes.has_repeat) { x8616_encode_buf_u1(buf, & n, rep); }
if (local.prefixes.has_segment) { x8616_encode_buf_u1(buf, & n, x8616_segment_prefix(local.prefixes.segment)); }
x8616_encode_buf_u1(buf, & n, local.header);
if (local.post_opcode) { x8616_encode_buf_u1(buf, & n, local.post_opcode); }
if (local.has_mod_rm) { x8616_encode_buf_u1(buf, & n, local.mod_rm); }
for (U1 id = 0; id < local.operand_count; ++id) {
X8616_DecodedOperand_R op = local.operands + id;
if ((op->flags & x8616_decoded_operand_memory) == 0) continue;
if ( op->flags & x8616_decoded_operand_direct) x8616_encode_buf_u2(buf, & n, op->address);
else x8616_encode_buf_disp(buf, & n, op->displacement, op->displacement_bytes);
}
for (U1 id = 0; id < local.operand_count; ++id) {
X8616_DecodedOperand_R op = local.operands + id;
B4 op_rel = op->flags & x8616_decoded_operand_relative;
B4 op_imm = (op->flags & x8616_decoded_operand_immediate) && op->immediate_bytes;
B4 op_far = op->flags & x8616_decoded_operand_far_ptr;
if (op_rel) { x8616_encode_buf_disp(buf, & n, op->displacement, op->displacement_bytes); }
else if (op_imm) { x8616_encode_buf_disp(buf, & n, s2_(op->immediate), op->immediate_bytes); }
else if (op_far) {
x8616_encode_buf_u2(buf, & n, op->far_offset);
x8616_encode_buf_u2(buf, & n, op->far_segment);
}
}
if (n > gen->cap - gen->len) return x8616_encode_output_full;
mem_copy(u8_(gen->ptr + gen->len), u8_(buf), n);
gen->len += n;
return x8616_encode_ok;
}
X8616_EncodeInfo x8616_encode_instructions(X8616_EncodeRequest request)
{
X8616_EncodeInfo result = {0};
X8616_InfoList local = {0};
X8616_InfoList_R msgs = request.msgs ? request.msgs : & local;
Str8Gen gen = {0};
B4 bad =
(request.instruction_count && request.instructions == 0)
|| (request.output.len && request.output.ptr == 0)
|| (request.info_arena == 0);
if (bad) {
if (request.info_arena) {
x8616_encode_push(request.info_arena, msgs, x8616_encode_bad_request, 0, 0, 0, 0);
}
goto exit;
}
gen = str8gen_make(request.output);
result.bytes.ptr = u8_(gen.ptr);
for (U4 id = 0; id < request.instruction_count; ++id)
{
X8616_DecodedInstruction_R inst = & request.instructions[id];
U8 at = gen.len;
X8616_EncodeStatus st = x8616_encode_instruction(& gen, inst);
if (st == x8616_encode_invalid_record) {
gen.len = at;
x8616_encode_push(request.info_arena, msgs, st, id, inst->size, 0, u4_(inst->op));
continue;
}
if (st == x8616_encode_output_full) {
gen.len = at;
x8616_encode_push(request.info_arena, msgs, st
, id, inst->size, u4_(request.output.len), u4_(at));
goto exit;
}
result.instructions_written += 1;
}
exit:
result.bytes.len = gen.len;
result.msgs = *msgs;
return result;
}
+28
View File
@@ -0,0 +1,28 @@
#ifdef INTELLISENSE_DIRECTIVES
# pragma once
# include "decoder.h"
#endif
typedef Enum_(U1, X8616_EncodeStatus) {
x8616_encode_ok = 0x00,
x8616_encode_output_full = 0x01,
x8616_encode_invalid_record = 0x02,
x8616_encode_bad_request = 0x03,
};
typedef Struct_(X8616_EncodeRequest) {
X8616_DecodedInstruction* instructions;
U4 instruction_count; byte_pad(4);
Slice output;
FArena* info_arena;
X8616_InfoList_R msgs;
};
typedef Struct_(X8616_EncodeInfo) {
X8616_InfoList msgs;
Slice bytes;
U4 instructions_written;
byte_pad(4);
};
X8616_EncodeInfo x8616_encode_instructions(X8616_EncodeRequest request);
+919
View File
@@ -0,0 +1,919 @@
#ifdef INTELLISENSE_DIRECTIVES
# pragma once
# include "duffle/dsl.h"
#endif
/* Intel 8086 Family User's Manual, Oct 1979 (9800722-03) ch.4 p.4-18,
Figure 4-20, Table 4-11, Table 4-12.
Figure 4-20 byte 1:
7 hole 0
+------------+-------------+
| OPCODE | fields |
+------------+-------------+
^ ^
| d, w, s, v, z, reg, cccc (Table 4-11)
Table 4-12 identifying bits (width 4..8)
Construction:
header = (opcode << hole) | fields
X8616_Opcode = the unshifted identifying bits
X8616_Encoding.header = BytePattern for that packed byte
INC AX:
Table 4-12: 0 1 0 0 0 reg
opcode = 01000, hole = 3, reg = AX
header = (01000 << 3) | 000 = 0x40
BytePattern.mask = bits that must match (opcode bits + any fixed literals). */
typedef Struct_(X8616_BytePattern) { U1 bits; U1 mask; };
typedef Struct_(X8616_BitField) { U1 shift; U1 width; };
// width field size in bits; 0 means this encoding skips it.
// d w s v z reg sr = Table 4-11. alu = ttt, cc = cccc (catalog).
typedef Struct_(X8616_HeaderFields) {
X8616_BitField d;
X8616_BitField w;
X8616_BitField s;
X8616_BitField v;
X8616_BitField z;
X8616_BitField reg;
X8616_BitField sr;
X8616_BitField alu;
X8616_BitField cc;
};
#define x8616_field_mask(shift, width) u1_(((1u << (width)) - 1u) << (shift))
#define x8616_header_opcode_mask(field_width) u1_(~((1u << (field_width)) - 1u))
#define x8616_opc(opcode, field_width) ((X8616_BytePattern){ u1_((opcode) << (field_width)), x8616_header_opcode_mask(field_width) })
#define x8616_opc_byte(opcode) x8616_opc((opcode), 0)
#define x8616_opcode_in(header, hole) ((header) >> (hole)) /* fields-zeroed byte 1 → identifying bits */
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,
};
typedef Enum_(U1, X8616_DigitKind) {
x8616_digit_none = 0x0,
x8616_digit_alu = 0x1,
x8616_digit_shift = 0x2,
};
typedef Struct_(X8616_Encoding) {
X8616_BytePattern header;
X8616_BytePattern mod_rm;
X8616_BytePattern post_opcode;
X8616_HeaderFields fields;
X8616_Operand operands[2];
X8616_WidthMode width;
X8616_EncodingFlags flags;
X8616_DigitKind digit_kind;
X8616_Op op;
};
typedef Enum_(U1, X8616_Width) { // Table 4-7 W
x8616_w_byte = 0b0,
x8616_w_word = 0b1,
};
typedef Enum_(U1, X8616_Direction) { // Table 4-7 D: REG is dest when 1
x8616_d_rm_dst = 0b0,
x8616_d_reg_dst = 0b1,
x8616_d_acc_dst = x8616_d_rm_dst,
x8616_d_mem_dst = x8616_d_reg_dst,
x8616_d_seg_dst = x8616_d_reg_dst,
};
typedef Enum_(U1, X8616_Sign) { // Table 4-7 S
x8616_s_full = 0b0,
x8616_s_extend = 0b1,
};
typedef Enum_(U1, X8616_VariableShift) { // Table 4-7 V
x8616_v_one = 0b0,
x8616_v_cl = 0b1,
};
typedef Enum_(U1, X8616_Repeat) { // Table 4-7 Z
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,
};
// Table 4-12 B(110) / B(111) beside SR.
typedef Enum_(U1, X8616_SRLow) {
x8616_sr_low_push = 0b110,
x8616_sr_low_pop = 0b111,
};
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) { // ttt in 00 ttt 0 d w and 00 ttt 10 w
x8616_add = 0b000,
x8616_or = 0b001,
x8616_adc = 0b010,
x8616_sbb = 0b011,
x8616_and = 0b100,
x8616_sub = 0b101,
x8616_xor = 0b110,
x8616_cmp = 0b111,
};
RO_ global X8616_Op x8616_op_from_alu[] = {
[x8616_add] = x8616_op_add,
[x8616_or] = x8616_op_or,
[x8616_adc] = x8616_op_adc,
[x8616_sbb] = x8616_op_sbb,
[x8616_and] = x8616_op_and,
[x8616_sub] = x8616_op_sub,
[x8616_xor] = x8616_op_xor,
[x8616_cmp] = x8616_op_cmp,
};
typedef Enum_(U1, X8616_Group3) { // ModR/M /digit of 1111011 w
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) { // /0 /1 of 1111111 w
x8616_inc = 0b000,
x8616_dec = 0b001,
};
typedef Enum_(U1, X8616_GroupFF) { // /2../6 of 1111111 w=1
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) { // /digit of 110100 v w
x8616_rol = 0b000,
x8616_ror = 0b001,
x8616_rcl = 0b010,
x8616_rcr = 0b011,
x8616_shl = 0b100,
x8616_shr = 0b101,
x8616_sar = 0b111,
};
RO_ global X8616_Op x8616_op_from_shift[] = {
[x8616_rol] = x8616_op_rol,
[x8616_ror] = x8616_op_ror,
[x8616_rcl] = x8616_op_rcl,
[x8616_rcr] = x8616_op_rcr,
[x8616_shl] = x8616_op_shl,
[x8616_shr] = x8616_op_shr,
[0b110] = x8616_op_invalid,
[x8616_sar] = x8616_op_sar,
};
typedef Enum_(U1, X8616_Condition) { // cccc of 0111 cccc
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,
};
RO_ global X8616_Op x8616_op_from_cc[] = {
[x8616_cc_o] = x8616_op_jo,
[x8616_cc_no] = x8616_op_jno,
[x8616_cc_b] = x8616_op_jb,
[x8616_cc_nb] = x8616_op_jnb,
[x8616_cc_e] = x8616_op_je,
[x8616_cc_ne] = x8616_op_jne,
[x8616_cc_be] = x8616_op_jbe,
[x8616_cc_a] = x8616_op_ja,
[x8616_cc_s] = x8616_op_js,
[x8616_cc_ns] = x8616_op_jns,
[x8616_cc_p] = x8616_op_jp,
[x8616_cc_np] = x8616_op_jnp,
[x8616_cc_l] = x8616_op_jl,
[x8616_cc_nl] = x8616_op_jnl,
[x8616_cc_le] = x8616_op_jle,
[x8616_cc_g] = x8616_op_jg,
};
typedef Enum_(U1, X8616_Digit) {
x8616_digit_0 = 0b000,
};
enum { // hole = low-bit field width in byte 1
X8616_OPCODE_DW_W_SHIFT = 0,
X8616_OPCODE_DW_D_SHIFT = 1,
X8616_OPCODE_DW_HOLE = X8616_OPCODE_DW_D_SHIFT + 1,
X8616_OPCODE_SW_W_SHIFT = 0,
X8616_OPCODE_SW_S_SHIFT = 1,
X8616_OPCODE_SW_HOLE = X8616_OPCODE_SW_S_SHIFT + 1,
X8616_OPCODE_VW_W_SHIFT = 0,
X8616_OPCODE_VW_V_SHIFT = 1,
X8616_OPCODE_VW_HOLE = X8616_OPCODE_VW_V_SHIFT + 1,
X8616_OPCODE_Z_Z_SHIFT = 0,
X8616_OPCODE_Z_HOLE = X8616_OPCODE_Z_Z_SHIFT + 1,
X8616_OPCODE_W_W_SHIFT = 0,
X8616_OPCODE_W_HOLE = X8616_OPCODE_W_W_SHIFT + 1,
X8616_OPCODE_REG_REG_SHIFT = 0,
X8616_OPCODE_REG_REG_WIDTH = 3,
X8616_OPCODE_REG_HOLE = X8616_OPCODE_REG_REG_SHIFT + X8616_OPCODE_REG_REG_WIDTH,
X8616_OPCODE_WREG_REG_SHIFT = 0,
X8616_OPCODE_WREG_REG_WIDTH = 3,
X8616_OPCODE_WREG_W_SHIFT = X8616_OPCODE_WREG_REG_SHIFT + X8616_OPCODE_WREG_REG_WIDTH,
X8616_OPCODE_WREG_HOLE = X8616_OPCODE_WREG_W_SHIFT + 1,
X8616_OPCODE_D0_D_SHIFT = 1,
X8616_OPCODE_D0_HOLE = X8616_OPCODE_D0_D_SHIFT + 1,
X8616_OPCODE_SR_CLASS_SHIFT = 5,
X8616_OPCODE_CC_WIDTH = 4,
X8616_OPCODE_CC_HOLE = X8616_OPCODE_CC_WIDTH,
};
typedef Enum_(U1, X8616_Opcode) { /* identifying bits: fields-zeroed header >> hole */
x8616_opcode_mov_rm_r = x8616_opcode_in(0b10001000, X8616_OPCODE_DW_HOLE), // 100010 d w
x8616_opcode_mov_rm_i = x8616_opcode_in(0b11000110, X8616_OPCODE_W_HOLE), // 1100011 w
x8616_opcode_mov_r_i = x8616_opcode_in(0b10110000, X8616_OPCODE_WREG_HOLE), // 1011 w reg
x8616_opcode_mov_acc_mem = x8616_opcode_in(0b10100000, X8616_OPCODE_DW_HOLE), // 101000 d w
x8616_opcode_mov_seg_rm = x8616_opcode_in(0b10001100, X8616_OPCODE_D0_HOLE), // 100011 d 0
x8616_opcode_push_reg = x8616_opcode_in(0b01010000, X8616_OPCODE_REG_HOLE), // 01010 reg
x8616_opcode_pop_reg = x8616_opcode_in(0b01011000, X8616_OPCODE_REG_HOLE), // 01011 reg
x8616_opcode_xchg_rm_r = x8616_opcode_in(0b10000110, X8616_OPCODE_W_HOLE), // 1000011 w
x8616_opcode_xchg_ax_reg = x8616_opcode_in(0b10010000, X8616_OPCODE_REG_HOLE), // 10010 reg
x8616_opcode_in_i = x8616_opcode_in(0b11100100, X8616_OPCODE_W_HOLE), // 1110010 w
x8616_opcode_in_dx = x8616_opcode_in(0b11101100, X8616_OPCODE_W_HOLE), // 1110110 w
x8616_opcode_out_i = x8616_opcode_in(0b11100110, X8616_OPCODE_W_HOLE), // 1110011 w
x8616_opcode_out_dx = x8616_opcode_in(0b11101110, X8616_OPCODE_W_HOLE), // 1110111 w
x8616_opcode_alu_rm_i = x8616_opcode_in(0b10000000, X8616_OPCODE_SW_HOLE), // 100000 s w
x8616_opcode_incdec_rm = x8616_opcode_in(0b11111110, X8616_OPCODE_W_HOLE), // 1111111 w
x8616_opcode_inc_reg = x8616_opcode_in(0b01000000, X8616_OPCODE_REG_HOLE), // 01000 reg
x8616_opcode_dec_reg = x8616_opcode_in(0b01001000, X8616_OPCODE_REG_HOLE), // 01001 reg
x8616_opcode_group3 = x8616_opcode_in(0b11110110, X8616_OPCODE_W_HOLE), // 1111011 w
x8616_opcode_shift_rm = x8616_opcode_in(0b11010000, X8616_OPCODE_VW_HOLE), // 110100 v w
x8616_opcode_test_rm_r = x8616_opcode_in(0b10000100, X8616_OPCODE_W_HOLE), // 1000010 w
x8616_opcode_test_acc_i = x8616_opcode_in(0b10101000, X8616_OPCODE_W_HOLE), // 1010100 w
x8616_opcode_rep = x8616_opcode_in(0b11110010, X8616_OPCODE_Z_HOLE), // 1111001 z
x8616_opcode_movs = x8616_opcode_in(0b10100100, X8616_OPCODE_W_HOLE), // 1010010 w
x8616_opcode_cmps = x8616_opcode_in(0b10100110, X8616_OPCODE_W_HOLE),
x8616_opcode_scas = x8616_opcode_in(0b10101110, X8616_OPCODE_W_HOLE),
x8616_opcode_lods = x8616_opcode_in(0b10101100, X8616_OPCODE_W_HOLE),
x8616_opcode_stos = x8616_opcode_in(0b10101010, X8616_OPCODE_W_HOLE),
x8616_opcode_jcc = x8616_opcode_in(0b01110000, X8616_OPCODE_CC_HOLE), // 0111 cccc
x8616_opcode_sr_stack = x8616_opcode_in(0b00000110, X8616_OPCODE_SR_CLASS_SHIFT), // 000 sr 110
x8616_opcode_sr_override = x8616_opcode_in(0b00100110, X8616_OPCODE_SR_CLASS_SHIFT), // 001 sr 110
x8616_opcode_pop_rm = x8616_opcode_in(0b10001111, 0),
x8616_opcode_xlat = x8616_opcode_in(0b11010111, 0),
x8616_opcode_lea = x8616_opcode_in(0b10001101, 0),
x8616_opcode_lds = x8616_opcode_in(0b11000101, 0),
x8616_opcode_les = x8616_opcode_in(0b11000100, 0),
x8616_opcode_lahf = x8616_opcode_in(0b10011111, 0),
x8616_opcode_sahf = x8616_opcode_in(0b10011110, 0),
x8616_opcode_pushf = x8616_opcode_in(0b10011100, 0),
x8616_opcode_popf = x8616_opcode_in(0b10011101, 0),
x8616_opcode_aaa = x8616_opcode_in(0b00110111, 0),
x8616_opcode_daa = x8616_opcode_in(0b00100111, 0),
x8616_opcode_aas = x8616_opcode_in(0b00111111, 0),
x8616_opcode_das = x8616_opcode_in(0b00101111, 0),
x8616_opcode_aam = x8616_opcode_in(0b11010100, 0),
x8616_opcode_aad = x8616_opcode_in(0b11010101, 0),
x8616_opcode_cbw = x8616_opcode_in(0b10011000, 0),
x8616_opcode_cwd = x8616_opcode_in(0b10011001, 0),
x8616_opcode_call_rel16 = x8616_opcode_in(0b11101000, 0),
x8616_opcode_call_far = x8616_opcode_in(0b10011010, 0),
x8616_opcode_jmp_rel16 = x8616_opcode_in(0b11101001, 0),
x8616_opcode_jmp_rel8 = x8616_opcode_in(0b11101011, 0),
x8616_opcode_jmp_far = x8616_opcode_in(0b11101010, 0),
x8616_opcode_ret = x8616_opcode_in(0b11000011, 0),
x8616_opcode_ret_i = x8616_opcode_in(0b11000010, 0),
x8616_opcode_retf = x8616_opcode_in(0b11001011, 0),
x8616_opcode_retf_i = x8616_opcode_in(0b11001010, 0),
x8616_opcode_loopnz = x8616_opcode_in(0b11100000, 0),
x8616_opcode_loopz = x8616_opcode_in(0b11100001, 0),
x8616_opcode_loop = x8616_opcode_in(0b11100010, 0),
x8616_opcode_jcxz = x8616_opcode_in(0b11100011, 0),
x8616_opcode_int = x8616_opcode_in(0b11001101, 0),
x8616_opcode_int3 = x8616_opcode_in(0b11001100, 0),
x8616_opcode_into = x8616_opcode_in(0b11001110, 0),
x8616_opcode_iret = x8616_opcode_in(0b11001111, 0),
x8616_opcode_clc = x8616_opcode_in(0b11111000, 0),
x8616_opcode_cmc = x8616_opcode_in(0b11110101, 0),
x8616_opcode_stc = x8616_opcode_in(0b11111001, 0),
x8616_opcode_cld = x8616_opcode_in(0b11111100, 0),
x8616_opcode_std = x8616_opcode_in(0b11111101, 0),
x8616_opcode_cli = x8616_opcode_in(0b11111010, 0),
x8616_opcode_sti = x8616_opcode_in(0b11111011, 0),
x8616_opcode_hlt = x8616_opcode_in(0b11110100, 0),
x8616_opcode_wait = x8616_opcode_in(0b10011011, 0),
x8616_opcode_lock = x8616_opcode_in(0b11110000, 0),
};
enum {
X8616_OPCODE_BIT_WIDTH = 1,
X8616_BYTE_MASK = x8616_field_mask(0, 8),
X8616_POST_OPCODE_AAM_AAD = 0b00001010, // AAM/AAD immediate 00001010
/* Hole = field width in the low bits of byte 1.
header = (opcode << HOLE) | fields
OPCODE_MASK = bits of the header that are opcode.
*/
// ModR/M:
// 7 6 5 4 3 2 1 0
// +-----+-------+-------+
// | mod | reg | r/m |
// +-----+-------+-------+
X8616_MODRM_RM_SHIFT = 0,
X8616_MODRM_RM_WIDTH = 3,
X8616_MODRM_REG_SHIFT = 3,
X8616_MODRM_REG_WIDTH = 3,
X8616_MODRM_MOD_SHIFT = 6,
X8616_MODRM_MOD_WIDTH = 2,
X8616_MODRM_RM_MASK = x8616_field_mask(X8616_MODRM_RM_SHIFT, X8616_MODRM_RM_WIDTH),
X8616_MODRM_REG_MASK = x8616_field_mask(X8616_MODRM_REG_SHIFT, X8616_MODRM_REG_WIDTH),
X8616_MODRM_MOD_MASK = x8616_field_mask(X8616_MODRM_MOD_SHIFT, X8616_MODRM_MOD_WIDTH),
X8616_MODRM_SR_SHIFT = 3,
X8616_MODRM_SR_WIDTH = 2,
X8616_MODRM_SR_MASK = x8616_field_mask(X8616_MODRM_SR_SHIFT, X8616_MODRM_SR_WIDTH),
X8616_MODRM_SEG_FIXED_BIT = 5,
X8616_MODRM_SEG_FIXED_MASK = x8616_field_mask(X8616_MODRM_SEG_FIXED_BIT, 1),
X8616_OPCODE_DW_OPCODE_MASK = x8616_header_opcode_mask(X8616_OPCODE_DW_HOLE),
X8616_OPCODE_SW_OPCODE_MASK = x8616_header_opcode_mask(X8616_OPCODE_SW_HOLE),
X8616_OPCODE_VW_OPCODE_MASK = x8616_header_opcode_mask(X8616_OPCODE_VW_HOLE),
X8616_OPCODE_Z_OPCODE_MASK = x8616_header_opcode_mask(X8616_OPCODE_Z_HOLE),
X8616_OPCODE_W_OPCODE_MASK = x8616_header_opcode_mask(X8616_OPCODE_W_HOLE),
X8616_OPCODE_REG_REG_MASK = x8616_field_mask(X8616_OPCODE_REG_REG_SHIFT, X8616_OPCODE_REG_REG_WIDTH),
X8616_OPCODE_REG_OPCODE_MASK = x8616_header_opcode_mask(X8616_OPCODE_REG_HOLE),
X8616_OPCODE_WREG_REG_MASK = x8616_field_mask(X8616_OPCODE_WREG_REG_SHIFT, X8616_OPCODE_WREG_REG_WIDTH),
X8616_OPCODE_WREG_W_MASK = x8616_field_mask(X8616_OPCODE_WREG_W_SHIFT, 1),
X8616_OPCODE_WREG_OPCODE_MASK = x8616_header_opcode_mask(X8616_OPCODE_WREG_HOLE),
X8616_OPCODE_D0_OPCODE_MASK = x8616_header_opcode_mask(X8616_OPCODE_D0_HOLE) | x8616_field_mask(0, 1),
X8616_OPCODE_SR_LOW_SHIFT = 0,
X8616_OPCODE_SR_LOW_WIDTH = 3,
X8616_OPCODE_SR_SHIFT = 3,
X8616_OPCODE_SR_WIDTH = 2,
X8616_OPCODE_SR_CLASS_WIDTH = 3,
X8616_OPCODE_SR_MASK = x8616_field_mask(X8616_OPCODE_SR_SHIFT, X8616_OPCODE_SR_WIDTH),
X8616_OPCODE_SR_PATTERN_MASK = u1_(~X8616_OPCODE_SR_MASK),
X8616_OPCODE_CC_SHIFT = 0,
X8616_OPCODE_CC_MASK = x8616_field_mask(X8616_OPCODE_CC_SHIFT, X8616_OPCODE_CC_WIDTH),
// 00 ttt ... class + form live in the matcher
X8616_OPCODE_ALU_CLASS = 0b00,
X8616_OPCODE_ALU_CLASS_SHIFT = 6,
X8616_OPCODE_ALU_CLASS_WIDTH = 2,
X8616_OPCODE_ALU_TTT_SHIFT = 3,
X8616_OPCODE_ALU_TTT_WIDTH = 3,
X8616_OPCODE_ALU_OP_SHIFT = X8616_OPCODE_ALU_TTT_SHIFT,
X8616_OPCODE_ALU_BIT2_SHIFT = 2,
X8616_OPCODE_ALU_RM_FORM = 0b0,
X8616_OPCODE_ALU_ACC_FORM = 0b10,
X8616_OPCODE_ALU_ACC_FORM_SHIFT = 1,
};
// ============================================================================
// 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),
// };
// ============================================================================
// Shift opcode into the hole, then OR fields:
// x8616_enc_dw(mov_rm_r, d, w) → 100010 d w
#define x8616_enc_dw_opcode(opcode) ((opcode) << X8616_OPCODE_DW_HOLE)
#define x8616_enc_sw_opcode(opcode) ((opcode) << X8616_OPCODE_SW_HOLE)
#define x8616_enc_vw_opcode(opcode) ((opcode) << X8616_OPCODE_VW_HOLE)
#define x8616_enc_z_opcode(opcode) ((opcode) << X8616_OPCODE_Z_HOLE)
#define x8616_enc_w_opcode(opcode) ((opcode) << X8616_OPCODE_W_HOLE)
#define x8616_enc_reg_opcode(opcode) ((opcode) << X8616_OPCODE_REG_HOLE)
#define x8616_enc_wreg_opcode(opcode) ((opcode) << X8616_OPCODE_WREG_HOLE)
#define x8616_enc_d0_opcode(opcode) ((opcode) << X8616_OPCODE_D0_HOLE)
#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_reg_field(r) ((r) << X8616_OPCODE_REG_REG_SHIFT)
#define x8616_enc_sr_field(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(opcode,d,w) C_(U1, x8616_enc_dw_opcode(opcode) | x8616_enc_d(d) | x8616_enc_width(w))
#define x8616_enc_sw(opcode,s,w) C_(U1, x8616_enc_sw_opcode(opcode) | x8616_enc_s(s) | x8616_enc_width(w))
#define x8616_enc_vw(opcode,v,w) C_(U1, x8616_enc_vw_opcode(opcode) | x8616_enc_v(v) | x8616_enc_width(w))
#define x8616_enc_zp(opcode,z) C_(U1, x8616_enc_z_opcode(opcode) | x8616_enc_z(z))
#define x8616_enc_w(opcode,w) C_(U1, x8616_enc_w_opcode(opcode) | x8616_enc_width(w))
#define x8616_enc_reg(opcode,reg) C_(U1, x8616_enc_reg_opcode(opcode) | x8616_enc_reg_field(reg))
#define x8616_enc_wreg(opcode,w,reg) C_(U1, x8616_enc_wreg_opcode(opcode) | x8616_enc_wreg_width(w) | x8616_enc_reg_field(reg))
#define x8616_enc_d0(opcode,d) C_(U1, x8616_enc_d0_opcode(opcode) | x8616_enc_d(d))
#define x8616_enc_sr(class,sr,low) C_(U1, ((class) << X8616_OPCODE_SR_CLASS_SHIFT) | x8616_enc_sr_field(sr) | (low))
#define x8616_enc_jcc(cc) C_(U1, (x8616_opcode_jcc << X8616_OPCODE_CC_HOLE) | 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))
// Catalog matchers. header_w: PUSH r/m is incdec_rm + w=1.
// header_d0: MOV sreg 100011 d 0. header_sr: 000 sr 110.
#define x8616_header_w(opcode,w) ((X8616_BytePattern){ x8616_enc_w((opcode), (w)), X8616_BYTE_MASK })
#define x8616_header_sr(class,low) ((X8616_BytePattern){ u1_(((class) << X8616_OPCODE_SR_CLASS_SHIFT) | (low)), X8616_OPCODE_SR_PATTERN_MASK })
#define x8616_header_d0(opcode) ((X8616_BytePattern){ u1_((opcode) << X8616_OPCODE_D0_HOLE), X8616_OPCODE_D0_OPCODE_MASK })
// 00 ttt 0 d w and 00 ttt 10 w. Class + ttt + form.
#define x8616_enc_alu_class() (X8616_OPCODE_ALU_CLASS << X8616_OPCODE_ALU_CLASS_SHIFT)
#define x8616_enc_alu_ttt(ttt) ((ttt) << X8616_OPCODE_ALU_TTT_SHIFT)
#define x8616_enc_alu_op(alu) x8616_enc_alu_ttt(alu)
#define x8616_enc_alu_rm_r(ttt,d,w) C_(U1, x8616_enc_alu_class() | x8616_enc_alu_ttt(ttt) | (X8616_OPCODE_ALU_RM_FORM << X8616_OPCODE_ALU_BIT2_SHIFT) | x8616_enc_d(d) | x8616_enc_width(w))
#define x8616_enc_alu_acc_i(ttt,w) C_(U1, x8616_enc_alu_class() | x8616_enc_alu_ttt(ttt) | (X8616_OPCODE_ALU_ACC_FORM << X8616_OPCODE_ALU_ACC_FORM_SHIFT) | x8616_enc_width(w))
// Scalar / generic packets
#define x8616_emit_u2(value) u2_lo(value), u2_hi(value)
#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(header,mod,reg,rm) u1_(header), x8616_enc_modrm(mod,reg,rm)
#define x8616_emit_modrm_d8(header,reg,rm,disp) x8616_emit_modrm (header,x8616_mod_mem_d8,reg,rm), u1_(disp)
#define x8616_emit_modrm_d16(header,reg,rm,disp) x8616_emit_modrm (header,x8616_mod_mem_d16,reg,rm), x8616_emit_s2(disp)
#define x8616_emit_modrm_direct(header,reg,addr) x8616_emit_modrm (header,x8616_mod_mem,reg,x8616_ea_direct), x8616_emit_u2(addr)
#define x8616_emit_modrm_i8(header,mod,reg,rm,imm) x8616_emit_modrm (header,mod,reg,rm), u1_(imm)
#define x8616_emit_modrm_i16(header,mod,reg,rm,imm) x8616_emit_modrm (header,mod,reg,rm), x8616_emit_u2(imm)
#define x8616_emit_modrm_d8_i8(header,reg,rm,disp,imm) x8616_emit_modrm_d8 (header,reg,rm,disp), u1_(imm)
#define x8616_emit_modrm_d8_i16(header,reg,rm,disp,imm) x8616_emit_modrm_d8 (header,reg,rm,disp), x8616_emit_u2(imm)
#define x8616_emit_modrm_d16_i8(header,reg,rm,disp,imm) x8616_emit_modrm_d16(header,reg,rm,disp), u1_(imm)
#define x8616_emit_modrm_d16_i16(header,reg,rm,disp,imm) x8616_emit_modrm_d16(header,reg,rm,disp), x8616_emit_u2(imm)
// r/m + register / immediate packets
#define x8616_emit_rm_r(opcode,d,w,mod,reg,rm) x8616_enc_dw (opcode,d,w), x8616_enc_modrm(mod,reg,rm)
#define x8616_emit_rm_r_d8(opcode,d,w,reg,rm,disp) x8616_emit_rm_r(opcode,d,w,x8616_mod_mem_d8, reg,rm), u1_(disp)
#define x8616_emit_rm_r_d16(opcode,d,w,reg,rm,disp) x8616_emit_rm_r(opcode,d,w,x8616_mod_mem_d16,reg,rm), x8616_emit_s2(disp)
#define x8616_emit_rm_r_direct(opcode,d,w,reg,addr) x8616_emit_rm_r(opcode,d,w,x8616_mod_mem,reg,x8616_ea_direct), x8616_emit_u2(addr)
#define x8616_emit_rm_i8_w(opcode,ext,mod,rm,imm) x8616_enc_w(opcode,x8616_w_byte), x8616_enc_modrm(mod,ext,rm), u1_(imm)
#define x8616_emit_rm_i16_w(opcode,ext,mod,rm,imm) x8616_enc_w(opcode,x8616_w_word), x8616_enc_modrm(mod,ext,rm), x8616_emit_u2(imm)
#define x8616_emit_rm_i8_w_d8(opcode,ext,rm,disp,imm) x8616_enc_w(opcode,x8616_w_byte), x8616_enc_modrm(x8616_mod_mem_d8,ext,rm), u1_(disp), u1_(imm)
#define x8616_emit_rm_i16_w_d8(opcode,ext,rm,disp,imm) x8616_enc_w(opcode,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(opcode,ext,rm,disp,imm) x8616_enc_w(opcode,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(opcode,ext,rm,disp,imm) x8616_enc_w(opcode,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(opcode,s,w,ext,mod,rm,imm) x8616_enc_sw(opcode,s,w), x8616_enc_modrm(mod,ext,rm), u1_(imm)
#define x8616_emit_rm_i16(opcode,ext,mod,rm,imm) x8616_enc_sw(opcode,x8616_s_full,x8616_w_word), x8616_enc_modrm(mod,ext,rm), x8616_emit_u2(imm)
#define x8616_emit_rm_i8_d8(opcode,s,w,ext,rm,disp,imm) x8616_enc_sw(opcode,s,w), x8616_enc_modrm(x8616_mod_mem_d8,ext,rm), u1_(disp), u1_(imm)
#define x8616_emit_rm_i16_d8(opcode,ext,rm,disp,imm) x8616_enc_sw(opcode,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(opcode,s,w,ext,rm,disp,imm) x8616_enc_sw(opcode,s,w), x8616_enc_modrm(x8616_mod_mem_d16,ext,rm), x8616_emit_s2(disp), u1_(imm)
#define x8616_emit_rm_i16_d16(opcode,ext,rm,disp,imm) x8616_enc_sw(opcode,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 — Table 4-12 100010 d w / 1011 w reg / 101000 d w / 100011 d 0
#define x8616_nop() x8616_enc_reg (x8616_opcode_xchg_ax_reg, x8616_ax) /* 10010 000 */
#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 — 01010 reg / 000 sr 110 / PUSH r/m = 1111111 w=1 /6
#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_sr_stack,seg,x8616_sr_low_push)
#define x8616_pop_seg(seg) x8616_enc_sr (x8616_opcode_sr_stack,seg,x8616_sr_low_pop)
#define x8616_push_rm(mod,rm) x8616_emit_modrm(x8616_enc_w(x8616_opcode_incdec_rm,x8616_w_word),mod,x8616_ff_push,rm)
#define x8616_pop_rm(mod,rm) x8616_emit_modrm(x8616_opcode_pop_rm,mod,x8616_digit_0,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 — 00 ttt 0 d w / 00 ttt 10 w / 100000 s w /ttt
#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 (x8616_opcode_alu_rm_i,x8616_s_full,x8616_w_byte,alu,x8616_mod_reg,dst,imm)
#define x8616_emit_logic_r16_i(alu,dst,imm) x8616_emit_rm_i16 (x8616_opcode_alu_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 — 01000 reg / 1111111 w /0 /1. Unary — 1111011 w /digit
#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 — 110100 v w /ttt. TEST r/m,imm is group3 /0
#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)
// Prefix = prior byte: 1111001 z / 11110000 / 001 sr 110
#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_sr_override,seg,x8616_sr_low_push)
// CALL/JMP r/m — same 1111111 w=1 as INC r/m, /digit 010..101
#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_enc_w(x8616_opcode_incdec_rm,x8616_w_word),mod,x8616_ff_call_near,rm)
#define x8616_call_far_rm(mod,rm) x8616_emit_modrm(x8616_enc_w(x8616_opcode_incdec_rm,x8616_w_word),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_enc_w(x8616_opcode_incdec_rm,x8616_w_word),mod,x8616_ff_jmp_near,rm)
#define x8616_jmp_far_rm(mod,rm) x8616_emit_modrm(x8616_enc_w(x8616_opcode_incdec_rm,x8616_w_word),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)
+802
View File
@@ -0,0 +1,802 @@
#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.
//
// Table 4-12: .header is byte 1 (opcode bits aligned, fields masked).
// X8616_Opcode members are the identifying bits.
// ModR/M /digit selectors use their encoded enumeration values.
// =========================================================================================
RO_ global X8616_Encoding x8616_encodings[] =
{
// MOV---------------------------------------------------------------------
/* MOV: 100010 d w | mod reg r/m */ {
.header = x8616_opc(x8616_opcode_mov_rm_r, X8616_OPCODE_DW_HOLE),
.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 */ {
.header = x8616_opc(x8616_opcode_mov_rm_i, X8616_OPCODE_W_HOLE),
.mod_rm = {
.bits = x8616_digit_0 << 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 */ {
.header = x8616_opc(x8616_opcode_mov_r_i, X8616_OPCODE_WREG_HOLE),
.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 */ {
.header = x8616_opc(x8616_opcode_mov_acc_mem, X8616_OPCODE_DW_HOLE),
.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 */ {
.header = x8616_header_d0(x8616_opcode_mov_seg_rm),
.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: 1111111 w=1 | mod 110 r/m */ {
.header = x8616_header_w(x8616_opcode_incdec_rm, x8616_w_word),
.mod_rm = {
.bits = x8616_ff_push << X8616_MODRM_REG_SHIFT,
.mask = X8616_MODRM_REG_MASK,
},
.fields = {
.w = { X8616_OPCODE_W_W_SHIFT, 1 },
},
.operands = { x8616_operand_rm },
.width = x8616_width_word,
.op = x8616_op_push,
},
/* PUSH reg16: 01010 reg */ {
.header = x8616_opc(x8616_opcode_push_reg, X8616_OPCODE_REG_HOLE),
.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,
},
/* POP reg16: 01011 reg */ {
.header = x8616_opc(x8616_opcode_pop_reg, X8616_OPCODE_REG_HOLE),
.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,
},
/* PUSH segment: 000 sr 110 */ {
.header = x8616_header_sr(x8616_opcode_sr_stack, x8616_sr_low_push),
.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 */ {
.header = x8616_opc_byte(x8616_opcode_pop_rm),
.mod_rm = {
.bits = x8616_digit_0 << X8616_MODRM_REG_SHIFT,
.mask = X8616_MODRM_REG_MASK,
},
.operands = { x8616_operand_rm },
.width = x8616_width_word,
.op = x8616_op_pop,
},
/* POP segment: 000 sr 111 */ {
.header = x8616_header_sr(x8616_opcode_sr_stack, x8616_sr_low_pop),
.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 */ {
.header = x8616_opc(x8616_opcode_xchg_rm_r, X8616_OPCODE_W_HOLE),
.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) */ {
.header = x8616_opc(x8616_opcode_xchg_ax_reg, X8616_OPCODE_REG_HOLE),
.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: 1110 0 10 w */ {
.header = x8616_opc(x8616_opcode_in_i, X8616_OPCODE_W_HOLE),
.fields = {
.w = { X8616_OPCODE_W_W_SHIFT, 1 },
},
.operands = { x8616_operand_acc, x8616_operand_imm8 },
.op = x8616_op_in,
},
/* IN acc,DX: 1110 1 10 w */ {
.header = x8616_opc(x8616_opcode_in_dx, X8616_OPCODE_W_HOLE),
.fields = {
.w = { X8616_OPCODE_W_W_SHIFT, 1 },
},
.operands = { x8616_operand_acc, x8616_operand_dx },
.op = x8616_op_in,
},
/* OUT imm8,acc: 1110 0 11 w */ {
.header = x8616_opc(x8616_opcode_out_i, X8616_OPCODE_W_HOLE),
.fields = {
.w = { X8616_OPCODE_W_W_SHIFT, 1 },
},
.operands = { x8616_operand_imm8, x8616_operand_acc },
.op = x8616_op_out,
},
/* OUT DX,acc: 1110 1 11 w */ {
.header = x8616_opc(x8616_opcode_out_dx, X8616_OPCODE_W_HOLE),
.fields = {
.w = { X8616_OPCODE_W_W_SHIFT, 1 },
},
.operands = { x8616_operand_dx, x8616_operand_acc },
.op = x8616_op_out,
},
/* XLAT */ {
.header = x8616_opc_byte(x8616_opcode_xlat),
.op = x8616_op_xlat,
},
/* LEA: mod reg r/m */ {
.header = x8616_opc_byte(x8616_opcode_lea),
.operands = { x8616_operand_reg_modrm, x8616_operand_rm },
.width = x8616_width_word,
.op = x8616_op_lea,
},
/* LDS: mod reg r/m */ {
.header = x8616_opc_byte(x8616_opcode_lds),
.operands = { x8616_operand_reg_modrm, x8616_operand_rm },
.width = x8616_width_word,
.op = x8616_op_lds,
},
/* LES: mod reg r/m */ {
.header = x8616_opc_byte(x8616_opcode_les),
.operands = { x8616_operand_reg_modrm, x8616_operand_rm },
.width = x8616_width_word,
.op = x8616_op_les,
},
/* LAHF */ {
.header = x8616_opc_byte(x8616_opcode_lahf),
.op = x8616_op_lahf,
},
/* SAHF */ {
.header = x8616_opc_byte(x8616_opcode_sahf),
.op = x8616_op_sahf,
},
/* PUSHF */ {
.header = x8616_opc_byte(x8616_opcode_pushf),
.op = x8616_op_pushf,
},
/* POPF */ {
.header = x8616_opc_byte(x8616_opcode_popf),
.op = x8616_op_popf,
},
// Arithmetic / logical----------------------------------------------------
// 00 ttt 0 d w | 00 ttt 10 w | 100000 s w /ttt
/* ALU r/m,reg: 00 ttt 0 d w */ {
.header = {
.bits = x8616_enc_alu_class(),
.mask = x8616_field_mask(X8616_OPCODE_ALU_CLASS_SHIFT, X8616_OPCODE_ALU_CLASS_WIDTH)
| x8616_field_mask(X8616_OPCODE_ALU_BIT2_SHIFT, 1),
},
.fields = {
.alu = { X8616_OPCODE_ALU_TTT_SHIFT, X8616_OPCODE_ALU_TTT_WIDTH },
.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_invalid,
},
/* ALU acc,imm: 00 ttt 10 w */ {
.header = {
.bits = x8616_enc_alu_class() | (X8616_OPCODE_ALU_ACC_FORM << X8616_OPCODE_ALU_ACC_FORM_SHIFT),
.mask = x8616_field_mask(X8616_OPCODE_ALU_CLASS_SHIFT, X8616_OPCODE_ALU_CLASS_WIDTH)
| x8616_field_mask(X8616_OPCODE_ALU_ACC_FORM_SHIFT, 2),
},
.fields = {
.alu = { X8616_OPCODE_ALU_TTT_SHIFT, X8616_OPCODE_ALU_TTT_WIDTH },
.w = { X8616_OPCODE_W_W_SHIFT, 1 },
},
.operands = { x8616_operand_acc, x8616_operand_imm },
.op = x8616_op_invalid,
},
/* ALU imm,r/m: 100000 s w /ttt */ {
.header = x8616_opc(x8616_opcode_alu_rm_i, X8616_OPCODE_SW_HOLE),
.fields = {
.s = { X8616_OPCODE_SW_S_SHIFT, 1 },
.w = { X8616_OPCODE_SW_W_SHIFT, 1 },
},
.operands = { x8616_operand_rm, x8616_operand_imm },
.digit_kind = x8616_digit_alu,
.op = x8616_op_invalid,
},
// INC / DEC / unary / adjust---------------------------------------------
/* INC r/m: 1111111 w /0 */ {
.header = x8616_opc(x8616_opcode_incdec_rm, X8616_OPCODE_W_HOLE),
.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 */ {
.header = x8616_opc(x8616_opcode_inc_reg, X8616_OPCODE_REG_HOLE),
.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,
},
/* DEC reg16: 01001 reg */ {
.header = x8616_opc(x8616_opcode_dec_reg, X8616_OPCODE_REG_HOLE),
.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,
},
/* AAA */ {
.header = x8616_opc_byte(x8616_opcode_aaa),
.op = x8616_op_aaa,
},
/* DAA */ {
.header = x8616_opc_byte(x8616_opcode_daa),
.op = x8616_op_daa,
},
/* DEC r/m: 1111111 w /1 */ {
.header = x8616_opc(x8616_opcode_incdec_rm, X8616_OPCODE_W_HOLE),
.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,
},
/* NEG r/m: 1111011 w /neg */ {
.header = x8616_opc(x8616_opcode_group3, X8616_OPCODE_W_HOLE),
.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 */ {
.header = x8616_opc(x8616_opcode_group3, X8616_OPCODE_W_HOLE),
.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 */ {
.header = x8616_opc(x8616_opcode_group3, X8616_OPCODE_W_HOLE),
.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 */ {
.header = x8616_opc(x8616_opcode_group3, X8616_OPCODE_W_HOLE),
.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 */ {
.header = x8616_opc(x8616_opcode_group3, X8616_OPCODE_W_HOLE),
.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 */ {
.header = x8616_opc(x8616_opcode_group3, X8616_OPCODE_W_HOLE),
.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 */ {
.header = x8616_opc_byte(x8616_opcode_aas),
.op = x8616_op_aas,
},
/* DAS */ {
.header = x8616_opc_byte(x8616_opcode_das),
.op = x8616_op_das,
},
/* AAM: 11010100 00001010 */ {
.header = x8616_opc_byte(x8616_opcode_aam),
.post_opcode = {
.bits = X8616_POST_OPCODE_AAM_AAD,
.mask = X8616_BYTE_MASK,
},
.op = x8616_op_aam,
},
/* AAD: 11010101 00001010 */ {
.header = x8616_opc_byte(x8616_opcode_aad),
.post_opcode = {
.bits = X8616_POST_OPCODE_AAM_AAD,
.mask = X8616_BYTE_MASK,
},
.op = x8616_op_aad,
},
/* CBW */ {
.header = x8616_opc_byte(x8616_opcode_cbw),
.op = x8616_op_cbw,
},
/* CWD */ {
.header = x8616_opc_byte(x8616_opcode_cwd),
.op = x8616_op_cwd,
},
// Shift / rotate / TEST---------------------------------------------------
/* SHIFT/ROTATE r/m,1|CL: 110100 v w /ttt */ {
.header = x8616_opc(x8616_opcode_shift_rm, X8616_OPCODE_VW_HOLE),
.fields = {
.v = { X8616_OPCODE_VW_V_SHIFT, 1 },
.w = { X8616_OPCODE_VW_W_SHIFT, 1 },
},
.operands = { x8616_operand_rm, x8616_operand_shift_count },
.digit_kind = x8616_digit_shift,
.op = x8616_op_invalid,
},
/* TEST r/m,reg: 1000010 w */ {
.header = x8616_opc(x8616_opcode_test_rm_r, X8616_OPCODE_W_HOLE),
.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 */ {
.header = x8616_opc(x8616_opcode_group3, X8616_OPCODE_W_HOLE),
.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 */ {
.header = x8616_opc(x8616_opcode_test_acc_i, X8616_OPCODE_W_HOLE),
.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 */ {
.header = x8616_opc(x8616_opcode_rep, X8616_OPCODE_Z_HOLE),
.fields = {
.z = { X8616_OPCODE_Z_Z_SHIFT, 1 },
},
.flags = x8616_encoding_prefix,
.op = x8616_op_rep,
},
/* MOVS: ... w */ {
.header = x8616_opc(x8616_opcode_movs, X8616_OPCODE_W_HOLE),
.fields = {
.w = { X8616_OPCODE_W_W_SHIFT, 1 },
},
.op = x8616_op_movs,
},
/* CMPS: ... w */ {
.header = x8616_opc(x8616_opcode_cmps, X8616_OPCODE_W_HOLE),
.fields = {
.w = { X8616_OPCODE_W_W_SHIFT, 1 },
},
.op = x8616_op_cmps,
},
/* SCAS: ... w */ {
.header = x8616_opc(x8616_opcode_scas, X8616_OPCODE_W_HOLE),
.fields = {
.w = { X8616_OPCODE_W_W_SHIFT, 1 },
},
.op = x8616_op_scas,
},
/* LODS: ... w */ {
.header = x8616_opc(x8616_opcode_lods, X8616_OPCODE_W_HOLE),
.fields = {
.w = { X8616_OPCODE_W_W_SHIFT, 1 },
},
.op = x8616_op_lods,
},
/* STOS: ... w */ {
.header = x8616_opc(x8616_opcode_stos, X8616_OPCODE_W_HOLE),
.fields = {
.w = { X8616_OPCODE_W_W_SHIFT, 1 },
},
.op = x8616_op_stos,
},
/* LOCK prefix */ {
.header = x8616_opc_byte(x8616_opcode_lock),
.flags = x8616_encoding_prefix,
.op = x8616_op_lock,
},
/* Segment override: 001 sr 110 */ {
.header = x8616_header_sr(x8616_opcode_sr_override, x8616_sr_low_push),
.fields = {
.sr = { X8616_OPCODE_SR_SHIFT, X8616_OPCODE_SR_WIDTH },
},
.flags = x8616_encoding_prefix,
.op = x8616_op_segment,
},
// Control transfer--------------------------------------------------------
/* CALL rel16 */ {
.header = x8616_opc_byte(x8616_opcode_call_rel16),
.operands = { x8616_operand_rel16 },
.op = x8616_op_call,
},
/* CALL r/m16: FF /2 */ {
.header = x8616_header_w(x8616_opcode_incdec_rm, x8616_w_word),
.mod_rm = {
.bits = x8616_ff_call_near << X8616_MODRM_REG_SHIFT,
.mask = X8616_MODRM_REG_MASK,
},
.fields = {
.w = { X8616_OPCODE_W_W_SHIFT, 1 },
},
.operands = { x8616_operand_rm },
.width = x8616_width_word,
.op = x8616_op_call,
},
/* CALL far ptr16:16 */ {
.header = x8616_opc_byte(x8616_opcode_call_far),
.operands = { x8616_operand_far_ptr },
.flags = x8616_encoding_far,
.op = x8616_op_call,
},
/* CALL far r/m16: FF /3 */ {
.header = x8616_header_w(x8616_opcode_incdec_rm, x8616_w_word),
.mod_rm = {
.bits = x8616_ff_call_far << X8616_MODRM_REG_SHIFT,
.mask = X8616_MODRM_REG_MASK,
},
.fields = {
.w = { X8616_OPCODE_W_W_SHIFT, 1 },
},
.operands = { x8616_operand_rm },
.width = x8616_width_word,
.flags = x8616_encoding_far,
.op = x8616_op_call,
},
/* JMP rel16 */ {
.header = x8616_opc_byte(x8616_opcode_jmp_rel16),
.operands = { x8616_operand_rel16 },
.op = x8616_op_jmp,
},
/* JMP rel8 */ {
.header = x8616_opc_byte(x8616_opcode_jmp_rel8),
.operands = { x8616_operand_rel8 },
.op = x8616_op_jmp,
},
/* JMP r/m16: FF /4 */ {
.header = x8616_header_w(x8616_opcode_incdec_rm, x8616_w_word),
.mod_rm = {
.bits = x8616_ff_jmp_near << X8616_MODRM_REG_SHIFT,
.mask = X8616_MODRM_REG_MASK,
},
.fields = {
.w = { X8616_OPCODE_W_W_SHIFT, 1 },
},
.operands = { x8616_operand_rm },
.width = x8616_width_word,
.op = x8616_op_jmp,
},
/* JMP far ptr16:16 */ {
.header = x8616_opc_byte(x8616_opcode_jmp_far),
.operands = { x8616_operand_far_ptr },
.flags = x8616_encoding_far,
.op = x8616_op_jmp,
},
/* JMP far r/m16: FF /5 */ {
.header = x8616_header_w(x8616_opcode_incdec_rm, x8616_w_word),
.mod_rm = {
.bits = x8616_ff_jmp_far << X8616_MODRM_REG_SHIFT,
.mask = X8616_MODRM_REG_MASK,
},
.fields = {
.w = { X8616_OPCODE_W_W_SHIFT, 1 },
},
.operands = { x8616_operand_rm },
.width = x8616_width_word,
.flags = x8616_encoding_far,
.op = x8616_op_jmp,
},
/* RET */ {
.header = x8616_opc_byte(x8616_opcode_ret),
.op = x8616_op_ret,
},
/* RET imm16 */ {
.header = x8616_opc_byte(x8616_opcode_ret_i),
.operands = { x8616_operand_imm16 },
.op = x8616_op_ret,
},
/* RETF */ {
.header = x8616_opc_byte(x8616_opcode_retf),
.op = x8616_op_retf,
},
/* RETF imm16 */ {
.header = x8616_opc_byte(x8616_opcode_retf_i),
.operands = { x8616_operand_imm16 },
.op = x8616_op_retf,
},
/* Jcc rel8: 0111 cccc */ {
.header = x8616_opc(x8616_opcode_jcc, X8616_OPCODE_CC_HOLE),
.fields = {
.cc = { X8616_OPCODE_CC_SHIFT, X8616_OPCODE_CC_WIDTH },
},
.operands = { x8616_operand_rel8 },
.op = x8616_op_invalid,
},
/* LOOPNZ rel8 */ {
.header = x8616_opc_byte(x8616_opcode_loopnz),
.operands = { x8616_operand_rel8 },
.op = x8616_op_loopnz,
},
/* LOOPZ rel8 */ {
.header = x8616_opc_byte(x8616_opcode_loopz),
.operands = { x8616_operand_rel8 },
.op = x8616_op_loopz,
},
/* LOOP rel8 */ {
.header = x8616_opc_byte(x8616_opcode_loop),
.operands = { x8616_operand_rel8 },
.op = x8616_op_loop,
},
/* JCXZ rel8 */ {
.header = x8616_opc_byte(x8616_opcode_jcxz),
.operands = { x8616_operand_rel8 },
.op = x8616_op_jcxz,
},
// Interrupt / machine control--------------------------------------------
/* INT imm8 */ {
.header = x8616_opc_byte(x8616_opcode_int),
.operands = { x8616_operand_imm8 },
.op = x8616_op_int,
},
/* INT3 */ {
.header = x8616_opc_byte(x8616_opcode_int3),
.op = x8616_op_int3,
},
/* INTO */ {
.header = x8616_opc_byte(x8616_opcode_into),
.op = x8616_op_into,
},
/* IRET */ {
.header = x8616_opc_byte(x8616_opcode_iret),
.op = x8616_op_iret,
},
/* CLC */ {
.header = x8616_opc_byte(x8616_opcode_clc),
.op = x8616_op_clc,
},
/* CMC */ {
.header = x8616_opc_byte(x8616_opcode_cmc),
.op = x8616_op_cmc,
},
/* STC */ {
.header = x8616_opc_byte(x8616_opcode_stc),
.op = x8616_op_stc,
},
/* CLD */ {
.header = x8616_opc_byte(x8616_opcode_cld),
.op = x8616_op_cld,
},
/* STD */ {
.header = x8616_opc_byte(x8616_opcode_std),
.op = x8616_op_std,
},
/* CLI */ {
.header = x8616_opc_byte(x8616_opcode_cli),
.op = x8616_op_cli,
},
/* STI */ {
.header = x8616_opc_byte(x8616_opcode_sti),
.op = x8616_op_sti,
},
/* HLT */ {
.header = x8616_opc_byte(x8616_opcode_hlt),
.op = x8616_op_hlt,
},
/* WAIT */ {
.header = x8616_opc_byte(x8616_opcode_wait),
.op = x8616_op_wait,
},
};
enum {
X8616_ENCODING_COUNT = S_(x8616_encodings) / S_(x8616_encodings[0]),
};
+192
View File
@@ -0,0 +1,192 @@
// Generated from encoder_table.h. Do not hand-edit.
// Plan 0 is a nil/invalid entry.
#ifdef INTELLISENSE_DIRECTIVES
# include "dsl.h"
#endif
RO_ global X8616_DecodePlan x8616_decode_plans[90] =
{
{ 0x0000, 0x00, 0x00, 0x00, {0x00, 0x00}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x041a, 0x02, 0x00, 0x00, {0x01, 0x02}, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0412, 0x02, 0x00, 0x00, {0x01, 0x07}, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x38}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0110, 0x02, 0x00, 0x00, {0x03, 0x07}, 2, 1, 0, 0, 3, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0018, 0x02, 0x00, 0x00, {0x06, 0x0a}, 2, 4, 0, 1, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x040a, 0x02, 0x00, 0x02, {0x01, 0x04}, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, {0x00, 0x20}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0412, 0x0b, 0x00, 0x02, {0x01, 0x00}, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x30, 0x38}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0100, 0x0b, 0x00, 0x02, {0x03, 0x00}, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0100, 0x0c, 0x00, 0x02, {0x03, 0x00}, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0200, 0x0b, 0x00, 0x02, {0x05, 0x00}, 1, 0, 0, 0, 0, 0, 0, 0, 0, 3, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0402, 0x0c, 0x00, 0x02, {0x01, 0x00}, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x38}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0200, 0x0c, 0x00, 0x02, {0x05, 0x00}, 1, 0, 0, 0, 0, 0, 0, 0, 0, 3, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0412, 0x0d, 0x00, 0x00, {0x02, 0x01}, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0100, 0x0d, 0x00, 0x02, {0x06, 0x03}, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0010, 0x0e, 0x00, 0x00, {0x06, 0x08}, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0010, 0x0e, 0x00, 0x00, {0x06, 0x0e}, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0010, 0x0f, 0x00, 0x00, {0x08, 0x06}, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0010, 0x0f, 0x00, 0x00, {0x0e, 0x06}, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x10, 0x00, 0x00, {0x00, 0x00}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0402, 0x11, 0x00, 0x02, {0x02, 0x01}, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0402, 0x12, 0x00, 0x02, {0x02, 0x01}, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0402, 0x13, 0x00, 0x02, {0x02, 0x01}, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x14, 0x00, 0x00, {0x00, 0x00}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x15, 0x00, 0x00, {0x00, 0x00}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x16, 0x00, 0x00, {0x00, 0x00}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x17, 0x00, 0x00, {0x00, 0x00}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x141a, 0x00, 0x00, 0x00, {0x01, 0x02}, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 3, 0, 0, },
{ 0x1010, 0x00, 0x00, 0x00, {0x06, 0x07}, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 3, 0, 0, },
{ 0x0432, 0x00, 0x00, 0x00, {0x01, 0x07}, 2, 1, 0, 0, 0, 1, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 1, },
{ 0x0412, 0x18, 0x00, 0x00, {0x01, 0x00}, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x38}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0100, 0x18, 0x00, 0x02, {0x03, 0x00}, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0100, 0x1b, 0x00, 0x02, {0x03, 0x00}, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x19, 0x00, 0x00, {0x00, 0x00}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x1a, 0x00, 0x00, {0x00, 0x00}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0412, 0x1b, 0x00, 0x00, {0x01, 0x00}, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x08, 0x38}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0412, 0x1c, 0x00, 0x00, {0x01, 0x00}, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x18, 0x38}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0412, 0x1f, 0x00, 0x00, {0x01, 0x00}, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x20, 0x38}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0412, 0x20, 0x00, 0x00, {0x01, 0x00}, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x28, 0x38}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0412, 0x22, 0x00, 0x00, {0x01, 0x00}, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x30, 0x38}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0412, 0x23, 0x00, 0x00, {0x01, 0x00}, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x38, 0x38}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0412, 0x27, 0x00, 0x00, {0x01, 0x00}, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x10, 0x38}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x1d, 0x00, 0x00, {0x00, 0x00}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x1e, 0x00, 0x00, {0x00, 0x00}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0004, 0x21, 0x00, 0x00, {0x00, 0x00}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x0a, 0xff}, 0, 0, 0, },
{ 0x0004, 0x24, 0x00, 0x00, {0x00, 0x00}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x0a, 0xff}, 0, 0, 0, },
{ 0x0000, 0x25, 0x00, 0x00, {0x00, 0x00}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x26, 0x00, 0x00, {0x00, 0x00}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0452, 0x00, 0x00, 0x00, {0x01, 0x0f}, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 2, },
{ 0x0412, 0x2f, 0x00, 0x00, {0x01, 0x02}, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0412, 0x2f, 0x00, 0x00, {0x01, 0x07}, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x38}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0010, 0x2f, 0x00, 0x00, {0x06, 0x07}, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0880, 0x30, 0x02, 0x00, {0x00, 0x00}, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0010, 0x31, 0x00, 0x00, {0x00, 0x00}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0010, 0x32, 0x00, 0x00, {0x00, 0x00}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0010, 0x33, 0x00, 0x00, {0x00, 0x00}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0010, 0x34, 0x00, 0x00, {0x00, 0x00}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0010, 0x35, 0x00, 0x00, {0x00, 0x00}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0800, 0x5b, 0x02, 0x00, {0x00, 0x00}, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0a00, 0x5c, 0x02, 0x00, {0x00, 0x00}, 0, 0, 3, 0, 0, 0, 0, 0, 0, 3, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x36, 0x00, 0x00, {0x0c, 0x00}, 1, 6, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0412, 0x36, 0x00, 0x02, {0x01, 0x00}, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x10, 0x38}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x36, 0x01, 0x00, {0x0d, 0x00}, 1, 7, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0412, 0x36, 0x01, 0x02, {0x01, 0x00}, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x18, 0x38}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x37, 0x00, 0x00, {0x0c, 0x00}, 1, 6, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x37, 0x00, 0x00, {0x0b, 0x00}, 1, 5, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0412, 0x37, 0x00, 0x02, {0x01, 0x00}, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x20, 0x38}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x37, 0x01, 0x00, {0x0d, 0x00}, 1, 7, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0412, 0x37, 0x01, 0x02, {0x01, 0x00}, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x28, 0x38}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x38, 0x00, 0x00, {0x00, 0x00}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x38, 0x00, 0x00, {0x09, 0x00}, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x39, 0x00, 0x00, {0x00, 0x00}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x39, 0x00, 0x00, {0x09, 0x00}, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x2000, 0x00, 0x00, 0x00, {0x0b, 0x00}, 1, 5, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x4c, 0x00, 0x00, {0x0b, 0x00}, 1, 5, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x4b, 0x00, 0x00, {0x0b, 0x00}, 1, 5, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x4a, 0x00, 0x00, {0x0b, 0x00}, 1, 5, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x4d, 0x00, 0x00, {0x0b, 0x00}, 1, 5, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x4e, 0x00, 0x00, {0x08, 0x00}, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x4f, 0x00, 0x00, {0x00, 0x00}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x50, 0x00, 0x00, {0x00, 0x00}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x51, 0x00, 0x00, {0x00, 0x00}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x52, 0x00, 0x00, {0x00, 0x00}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x53, 0x00, 0x00, {0x00, 0x00}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x54, 0x00, 0x00, {0x00, 0x00}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x55, 0x00, 0x00, {0x00, 0x00}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x56, 0x00, 0x00, {0x00, 0x00}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x57, 0x00, 0x00, {0x00, 0x00}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x58, 0x00, 0x00, {0x00, 0x00}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x59, 0x00, 0x00, {0x00, 0x00}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
{ 0x0000, 0x5a, 0x00, 0x00, {0x00, 0x00}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0x00, 0x00}, {0x00, 0x00}, 0, 0, 0, },
};
RO_ global U2 x8616_decode_dispatch[256] =
{
0x001a, 0x001a, 0x001a, 0x001a, 0x001b, 0x001b, 0x0009, 0x000b, 0x001a, 0x001a, 0x001a, 0x001a, 0x001b, 0x001b, 0x0009, 0x000b,
0x001a, 0x001a, 0x001a, 0x001a, 0x001b, 0x001b, 0x0009, 0x000b, 0x001a, 0x001a, 0x001a, 0x001a, 0x001b, 0x001b, 0x0009, 0x000b,
0x001a, 0x001a, 0x001a, 0x001a, 0x001b, 0x001b, 0x003a, 0x0021, 0x001a, 0x001a, 0x001a, 0x001a, 0x001b, 0x001b, 0x003a, 0x002a,
0x001a, 0x001a, 0x001a, 0x001a, 0x001b, 0x001b, 0x003a, 0x0020, 0x001a, 0x001a, 0x001a, 0x001a, 0x001b, 0x001b, 0x003a, 0x0029,
0x001e, 0x001e, 0x001e, 0x001e, 0x001e, 0x001e, 0x001e, 0x001e, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f,
0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0048, 0x0048, 0x0048, 0x0048, 0x0048, 0x0048, 0x0048, 0x0048, 0x0048, 0x0048, 0x0048, 0x0048, 0x0048, 0x0048, 0x0048, 0x0048,
0x001c, 0x001c, 0x001c, 0x001c, 0x0030, 0x0030, 0x000c, 0x000c, 0x0001, 0x0001, 0x0001, 0x0001, 0x0005, 0x0013, 0x0005, 0x000a,
0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x002d, 0x002e, 0x003d, 0x0059, 0x0018, 0x0019, 0x0017, 0x0016,
0x0004, 0x0004, 0x0004, 0x0004, 0x0034, 0x0034, 0x0035, 0x0035, 0x0032, 0x0032, 0x0038, 0x0038, 0x0037, 0x0037, 0x0036, 0x0036,
0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003,
0x0000, 0x0000, 0x0045, 0x0044, 0x0015, 0x0014, 0x0002, 0x0002, 0x0000, 0x0000, 0x0047, 0x0046, 0x004e, 0x004d, 0x004f, 0x0050,
0x002f, 0x002f, 0x002f, 0x002f, 0x002b, 0x002c, 0x0000, 0x0012, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0049, 0x004a, 0x004b, 0x004c, 0x000e, 0x000e, 0x0010, 0x0010, 0x003b, 0x003f, 0x0042, 0x0040, 0x000f, 0x000f, 0x0011, 0x0011,
0x0039, 0x0000, 0x0033, 0x0033, 0x0058, 0x0052, 0x8000, 0x8100, 0x0051, 0x0053, 0x0056, 0x0057, 0x0054, 0x0055, 0x8200, 0x8300,
};
RO_ global U1 x8616_decode_aux[1024] =
{
0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,
0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,
0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,
0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,
0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,
0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,
0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,
0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,
0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
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,
0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
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,
0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
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,
0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
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,
0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e,
0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e,
0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e,
0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e,
0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
enum {
X8616_DECODE_PLAN_COUNT = 90,
X8616_DECODE_AUX_COUNT = 1024,
};
+141
View File
@@ -0,0 +1,141 @@
#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_serialize_bad_request = 0x0B,
x8616_info_serialize_invalid_record = 0x0C,
x8616_info_serialize_unsupported_form = 0x0D,
x8616_info_serialize_output_full = 0x0E,
x8616_info_parse_bad_request = 0x0F,
x8616_info_parse_syntax = 0x10,
x8616_info_parse_unknown_mnemonic = 0x11,
x8616_info_parse_output_full = 0x12,
x8616_info_parse_invalid_record = 0x13,
x8616_info_parse_unsupported_form = 0x14,
x8616_info_encode_bad_request = 0x15,
x8616_info_encode_invalid_record = 0x16,
x8616_info_encode_output_full = 0x17,
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;
U2 source_size;
U4 source_offset;
U4 expected;
U4 actual;
Str8 text;
};
/* Static templates use the same <identifier> 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] = slit8(""),
[x8616_info_invalid_opcode] = slit8("Header <actual> is not in the Part 1 8086 decode table at <offset>."),
[x8616_info_invalid_opcode_extension] = slit8("Opcode extension <actual> does not match the selected encoding at <offset>."),
[x8616_info_invalid_post_opcode] = slit8("Post-opcode byte <actual> does not match expected <expected> at <offset>."),
[x8616_info_truncated_instruction] = slit8("Instruction at <offset> needs <expected> bytes; <actual> are available."),
[x8616_info_output_full] = slit8("Decoded-instruction output is full: capacity <expected>, produced <actual>."),
[x8616_info_gen_multiple_payloads] = slit8("Encoding <offset> describes more than one stream payload."),
[x8616_info_gen_body_cap_exceeded] = slit8("Encoding <offset> requires <actual> body bytes; decoder body capacity is <expected>."),
[x8616_info_gen_aux_cap_exceeded] = slit8("Generated auxiliary decode table exceeds capacity <expected>."),
[x8616_info_gen_ambiguous_decode] = slit8("Decode is ambiguous for header/second-byte key <offset>: plans <expected> and <actual>."),
[x8616_info_gen_dispatch_mismatch] = slit8("Generated dispatch mismatch for header/second-byte key <offset>: expected <expected>, actual <actual>."),
[x8616_info_serialize_bad_request] = slit8("Serialize request is missing instructions, output, scratch, or info arena."),
[x8616_info_serialize_invalid_record] = slit8("Serialize record <offset> is not printable (op <actual>)."),
[x8616_info_serialize_unsupported_form] = slit8("Serialize record <offset> has an unsupported display form (op <actual>)."),
[x8616_info_serialize_output_full] = slit8("Serialize output is full at record <offset>: capacity <expected>, produced <actual>."),
[x8616_info_parse_bad_request] = slit8("Parse request is missing source, output, or info arena."),
[x8616_info_parse_syntax] = slit8("Parse syntax error at <offset>."),
[x8616_info_parse_unknown_mnemonic] = slit8("Unknown mnemonic at <offset>."),
[x8616_info_parse_output_full] = slit8("Parse output is full: capacity <expected>, produced <actual>."),
[x8616_info_parse_invalid_record] = slit8("Parse record at <offset> is not a valid instruction (op <actual>)."),
[x8616_info_parse_unsupported_form] = slit8("Parse record at <offset> has an unsupported form (op <actual>)."),
[x8616_info_encode_bad_request] = slit8("Encode request is missing instructions, output, or info arena."),
[x8616_info_encode_invalid_record] = slit8("Encode record <offset> is invalid or truncated (op <actual>)."),
[x8616_info_encode_output_full] = slit8("Encode output is full at record <offset>: capacity <expected>, produced <actual>."),
};
typedef Struct_(X8616_InfoList) {
X8616_InfoMsg* first;
X8616_InfoMsg* last;
U4 count;
U4 error_count;
U4 warning_count;
U4 dropped_count;
};
I_ 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 msgs
, X8616_InfoKind kind
, X8616_InfoCode code
, U4 source_offset
, U2 source_size
, U4 expected
, U4 actual
){
assert(scratch != nullptr);
msgs->count += 1;
msgs->error_count += kind == x8616_info_error;
msgs->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) { ++ msgs->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(msgs->first, msgs->last, msg, next);
}
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);
}
+420
View File
@@ -0,0 +1,420 @@
#ifdef INTELLISENSE_DIRECTIVES
# include "parser.h"
# include "serializer_tables.h"
#endif
FI_ void x8616_parse_skip_ws(Str8_R cur) {
while (cur->len && char_is_space(cur->ptr[0])) { cur->ptr += 1; cur->len -= 1; }
}
FI_ B4 x8616_parse_walk(Str8_R cur, Str8 lit) {
B4 too_big = cur->len < lit.len;
B4 miss = too_big || mem_match(u8_(cur->ptr), u8_(lit.ptr), lit.len) == 0;
if (miss) return 0;
cur->ptr += lit.len;
cur->len -= lit.len;
return 1;
}
FI_ U4 x8616_parse_lookup(Str8_R cur, Str8* table, U4 table_len) {
U4 best = table_len;
U8 best_len = 0;
for (U4 i = 0; i < table_len; ++i)
{
Str8 lit = table[i];
B4 empty = lit.len == 0;
B4 too_big = lit.len > cur->len;
B4 worse = lit.len <= best_len;
B4 skip = empty || too_big || worse;
B4 miss = skip || mem_match(u8_(cur->ptr), u8_(lit.ptr), lit.len) == 0;
if (miss) continue;
best = i;
best_len = lit.len;
}
if (best < table_len) {
cur->ptr += best_len;
cur->len -= best_len;
}
return best;
}
FI_ B4 x8616_parse_number(Str8_R cur, U2_R value, B4_R neg_out) {
x8616_parse_skip_ws(cur);
B4 neg = 0;
if (x8616_parse_walk(cur, slit8("-"))) neg = 1;
if (cur->len == 0 || char_is_digit(cur->ptr[0], 10) == 0) return 0;
U8 start = 0;
while (start < cur->len && char_is_digit(cur->ptr[start], 10)) start += 1;
U8 mag = u8_from_str8(str8(cur->ptr, start), 10);
cur->ptr += start;
cur->len -= start;
value[0] = u2_(mag);
neg_out[0] = neg;
return 1;
}
internal B4 x8616_parse_memory(Str8_R cur, X8616_DecodedOperand_R op)
{
B4 ok = 1;
if (x8616_parse_walk(cur, slit8("[")) == 0) { ok = 0; goto exit; }
x8616_parse_skip_ws(cur);
U4 ea_n = Array_len(x8616_serialize_ea);
U4 ea = x8616_parse_lookup(cur, x8616_serialize_ea, ea_n);
if (ea < ea_n)
{
op->flags = x8616_decoded_operand_memory;
op->ea = C_(X8616_EA, ea);
x8616_parse_skip_ws(cur);
if (x8616_parse_walk(cur, slit8("+"))) {
U2 mag = 0; B4 neg = 0;
x8616_parse_skip_ws(cur);
if (x8616_parse_number(cur, & mag, & neg) == 0) { ok = 0; goto exit; }
op->displacement = neg ? s2_(-s4_(mag)) : s2_(mag);
op->displacement_bytes = (u2_(op->displacement) > 0x7F && op->displacement >= 0) || op->displacement < -128 ? 2 : (op->displacement ? 1 : 0);
}
else if (x8616_parse_walk(cur, slit8("-"))) {
U2 mag = 0; B4 dummy = 0;
x8616_parse_skip_ws(cur);
if (x8616_parse_number(cur, & mag, & dummy) == 0) { ok = 0; goto exit; }
op->displacement = s2_(-s4_(mag));
op->displacement_bytes = op->displacement < -128 ? 2 : 1;
}
}
else {
U2 mag = 0; B4 neg = 0;
if (x8616_parse_number(cur, & mag, & neg) == 0) { ok = 0; goto exit; }
op->flags = x8616_decoded_operand_memory | x8616_decoded_operand_direct;
op->address = mag;
op->ea = x8616_ea_direct;
}
x8616_parse_skip_ws(cur);
if (x8616_parse_walk(cur, slit8("]")) == 0) { ok = 0; goto exit; }
exit:
return ok;
}
internal B4
x8616_parse_operand(Str8_R cur, X8616_DecodedInstruction_R inst, X8616_DecodedOperand_R op)
{
B4 ok = 1;
x8616_parse_skip_ws(cur);
X8616_WidthMode size = x8616_width_dynamic;
if (x8616_parse_walk(cur, slit8("byte "))) size = x8616_width_byte;
else if (x8616_parse_walk(cur, slit8("word "))) size = x8616_width_word;
if (x8616_parse_walk(cur, slit8("far "))) inst->flags |= x8616_encoding_far;
x8616_parse_skip_ws(cur);
U4 seg_n = Array_len(x8616_serialize_seg);
Str8 save = cur[0];
U4 seg = x8616_parse_lookup(cur, x8616_serialize_seg, seg_n);
if (seg < seg_n)
{
x8616_parse_skip_ws(cur);
if (x8616_parse_walk(cur, slit8(":"))) {
inst->prefixes.has_segment = 1;
inst->prefixes.segment = C_(X8616_Segment, seg);
x8616_parse_skip_ws(cur);
if (x8616_parse_memory(cur, op) == 0) { ok = 0; goto exit; }
}
else {
op->flags = x8616_decoded_operand_segment;
op->segment = C_(X8616_Segment, seg);
op->width = x8616_width_word;
}
}
else
{
cur[0] = save;
U4 r16_n = Array_len(x8616_serialize_reg16);
U4 r8_n = Array_len(x8616_serialize_reg8);
U4 r16 = x8616_parse_lookup(cur, x8616_serialize_reg16, r16_n);
if (r16 < r16_n) {
op->flags = x8616_decoded_operand_register;
op->width = x8616_width_word;
op->reg.r16 = C_(X8616_Reg16, r16);
}
else
{
cur[0] = save;
U4 r8 = x8616_parse_lookup(cur, x8616_serialize_reg8, r8_n);
if (r8 < r8_n) {
op->flags = x8616_decoded_operand_register;
op->width = x8616_width_byte;
op->reg.r8 = C_(X8616_Reg8, r8);
}
else if (x8616_parse_walk(cur, slit8("$"))) {
B4 neg = 0;
if (x8616_parse_walk(cur, slit8("+"))) {}
else if (x8616_parse_walk(cur, slit8("-"))) neg = 1;
else { ok = 0; goto exit; }
U2 mag = 0; B4 extra = 0;
if (x8616_parse_number(cur, & mag, & extra) == 0) { ok = 0; goto exit; }
if (extra) neg = 1;
op->flags = x8616_decoded_operand_relative;
op->displacement = neg ? s2_(-s4_(mag)) : s2_(mag);
op->width = x8616_width_byte;
}
else if (cur->len && cur->ptr[0] == '[') {
if (x8616_parse_memory(cur, op) == 0) { ok = 0; goto exit; }
}
else
{
U2 mag = 0; B4 neg = 0;
Str8 before = *cur;
if (x8616_parse_number(cur, & mag, & neg) == 0) { ok = 0; goto exit; }
x8616_parse_skip_ws(cur);
if (x8616_parse_walk(cur, slit8(":"))) {
U2 off = 0; B4 off_neg = 0;
if (x8616_parse_number(cur, & off, & off_neg) == 0) { ok = 0; goto exit; }
op->flags = x8616_decoded_operand_far_ptr;
op->far_segment = mag;
op->far_offset = off;
}
else {
*cur = before;
if (x8616_parse_number(cur, & mag, & neg) == 0) { ok = 0; goto exit; }
op->flags = x8616_decoded_operand_immediate;
op->immediate = mag;
if (neg) {
op->flags |= x8616_decoded_operand_sign_extended;
op->immediate = u2_(s2_(-s4_(mag)));
}
op->immediate_bytes = mag > 0xFF ? 2 : 1;
op->width = mag > 0xFF ? x8616_width_word : x8616_width_byte;
}
}
}
}
if (size != x8616_width_dynamic) {
op->width = size;
if (inst->width == x8616_width_dynamic) inst->width = size;
}
exit:
return ok;
}
FI_ B4 x8616_parse_is_shift(X8616_Op op) { switch (op) {
case x8616_op_shl:
case x8616_op_shr:
case x8616_op_sar:
case x8616_op_rol:
case x8616_op_ror:
case x8616_op_rcl:
case x8616_op_rcr:
return 1;
default:
return 0;
}}
FI_ B4 x8616_parse_is_string(X8616_Op op) { switch (op) {
case x8616_op_movs:
case x8616_op_cmps:
case x8616_op_scas:
case x8616_op_lods:
case x8616_op_stos:
return 1;
default:
return 0;
}}
FI_ B4 x8616_parse_has_memory(X8616_DecodedInstruction_R inst) {
for (U1 id = 0; id < inst->operand_count; ++id) { if (inst->operands[id].flags & x8616_decoded_operand_memory) return 1; }
return 0;
}
FI_ X8616_DecodedOperandFlags x8616_parse_base_flags(X8616_DecodedOperandFlags flags) {
return flags & (
x8616_decoded_operand_register
| x8616_decoded_operand_segment
| x8616_decoded_operand_memory
| x8616_decoded_operand_immediate
| x8616_decoded_operand_relative
| x8616_decoded_operand_far_ptr
);
}
FI_ B4 x8616_parse_one_flag(X8616_DecodedOperandFlags flags) { U2 bits = C_(U2, flags); return (bits != 0) && ((bits & (bits - 1)) == 0); }
internal void
x8616_parse_push(FArena_R arena, X8616_InfoList_R msgs, X8616_ParseStatus status, U4 id, U2 size, U4 expected, U4 actual) {
if (status == x8616_parse_ok || arena == 0) return;
X8616_InfoKind kind = x8616_info_error;
X8616_InfoCode code = x8616_info_parse_syntax;
if (status == x8616_parse_output_full) code = x8616_info_parse_output_full;
else if (status == x8616_parse_unknown_mnemonic) code = x8616_info_parse_unknown_mnemonic;
else if (status == x8616_parse_invalid_record) code = x8616_info_parse_invalid_record;
else if (status == x8616_parse_unsupported_form) code = x8616_info_parse_unsupported_form;
x8616_info_push(arena, msgs, kind, code, id, size, expected, actual);
}
internal X8616_ParseStatus
x8616_parse_validate(X8616_DecodedInstruction_R inst)
{
X8616_ParseStatus status = x8616_parse_ok;
B4 invalid_sig = inst->operand_count > 2;
B4 invalid_mnemonic = u4_(inst->op) >= Array_len(x8616_serialize_mnemonic) || inst->op == x8616_op_invalid;
B4 empty_mnemonic = invalid_mnemonic == 0 && x8616_serialize_mnemonic[inst->op].len == 0;
B4 invalid_prefix_with_seg = inst->prefixes.has_segment && u1_(inst->prefixes.segment) >= Array_len(x8616_serialize_seg);
if (invalid_sig || invalid_mnemonic || invalid_prefix_with_seg) {
status = x8616_parse_invalid_record; goto status_failed;
}
if (empty_mnemonic) {
status = x8616_parse_unknown_mnemonic; goto status_failed;
}
B4 bad_prefix_segment = inst->prefixes.has_segment && (x8616_parse_has_memory(inst) == 0);
B4 bad_prefix_repeat = inst->prefixes.has_repeat && (x8616_parse_is_string(inst->op) == 0);
if (bad_prefix_segment || bad_prefix_repeat) {
status = x8616_parse_unsupported_form; goto status_failed;
}
for (U1 id = 0; id < inst->operand_count; ++id)
{
X8616_DecodedOperand_R operand = & inst->operands[id];
X8616_DecodedOperandFlags base = x8616_parse_base_flags(operand->flags);
B4 invalid_flag = x8616_parse_one_flag(base) == 0;
B4 has_operand_register = base & x8616_decoded_operand_register;
B4 has_operand_segment = base & x8616_decoded_operand_segment;
B4 has_operand_memory = base & x8616_decoded_operand_memory;
B4 invalid_reg_r16 = u1_(operand->reg.r16) >= Array_len(x8616_serialize_reg16);
B4 invalid_width = operand->width != x8616_width_byte && operand->width != x8616_width_word;
B4 invalid_operand_seg = u1_(operand->segment) >= Array_len(x8616_serialize_seg);
B4 invalid_operand_ea = u1_(operand->ea) >= Array_len(x8616_serialize_ea);
B4 invalid_direct_ea = has_operand_memory && ((operand->flags & x8616_decoded_operand_direct) == 0) && invalid_operand_ea;
B4 invalid_operand = invalid_flag
|| (has_operand_register && (invalid_reg_r16 || invalid_width))
|| (has_operand_segment && invalid_operand_seg)
|| invalid_direct_ea;
if (invalid_operand) {
status = x8616_parse_invalid_record; goto status_failed;
}
}
status_failed:
return status;
}
internal B4 x8616_parse_line(Str8 line, X8616_DecodedInstruction_R inst)
{
B4 ok = 1;
x8616_parse_skip_ws(& line);
if (line.len == 0) { ok = 0; goto exit; }
if (x8616_parse_walk(& line, slit8("lock "))) inst->prefixes.lock = 1;
if (x8616_parse_walk(& line, slit8("repne "))) {
inst->prefixes.has_repeat = 1;
inst->prefixes.repeat = x8616_repne;
}
else if (x8616_parse_walk(& line, slit8("rep "))) {
inst->prefixes.has_repeat = 1;
inst->prefixes.repeat = x8616_rep;
}
U4 mnem_n = Array_len(x8616_serialize_mnemonic);
U4 mnem = x8616_parse_lookup(& line, x8616_serialize_mnemonic, mnem_n);
if (mnem >= mnem_n) { ok = 0; goto exit; }
inst->op = C_(X8616_Op, mnem);
if (x8616_parse_is_string(inst->op)) {
if (x8616_parse_walk(& line, slit8("b"))) inst->width = x8616_width_byte;
else if (x8616_parse_walk(& line, slit8("w"))) inst->width = x8616_width_word;
}
x8616_parse_skip_ws(& line);
if (line.len == 0) goto exit;
if (x8616_parse_operand(& line, inst, inst->operands + 0) == 0) { ok = 0; goto exit; }
inst->operand_count = 1;
x8616_parse_skip_ws(& line);
if (x8616_parse_walk(& line, slit8(","))) {
if (x8616_parse_operand(& line, inst, inst->operands + 1) == 0) { ok = 0; goto exit; }
inst->operand_count = 2;
}
x8616_parse_skip_ws(& line);
if (inst->width == x8616_width_dynamic) {
for (U1 id = 0; id < inst->operand_count; ++id) {
if (inst->operands[id].width != x8616_width_dynamic) {
inst->width = inst->operands[id].width;
break;
}
}
}
if (inst->width != x8616_width_dynamic) {
for (U1 id = 0; id < inst->operand_count; ++id) {
X8616_DecodedOperand_R op = inst->operands + id;
B4 take = op->width == x8616_width_dynamic;
take |= (op->flags & x8616_decoded_operand_immediate) && (x8616_parse_is_shift(inst->op) == 0);
if (take) op->width = inst->width;
}
}
ok = line.len == 0;
exit:
return ok;
}
X8616_ParseInfo x8616_parse_instructions(X8616_ParseRequest request)
{
X8616_ParseInfo result = {0};
X8616_InfoList local = {0};
X8616_InfoList_R msgs = request.msgs ? request.msgs : & local;
U4 offset = 0;
B4 bad = request.source.ptr == 0 && request.source.len != 0;
bad |= request.instruction_cap && request.out_instructions == 0;
bad |= request.info_arena == 0;
if (bad) {
if (request.info_arena) {
x8616_info_push(request.info_arena, msgs, x8616_info_error
, x8616_info_parse_bad_request, 0, 0, 0, 0);
}
goto exit;
}
Str8 cur = request.source;
if (x8616_parse_walk(& cur, x8616_serialize_header)) {}
offset = u4_(request.source.len - cur.len);
while (cur.len)
{
U8 n = 0;
while (n < cur.len && cur.ptr[n] != '\n') n += 1;
Str8 line = str8(cur.ptr, n);
U8 step = n + (n < cur.len);
U4 line_at = offset;
cur.ptr += step;
cur.len -= step;
offset += u4_(step);
while (line.len && char_is_space(line.ptr[line.len - 1])) line.len -= 1;
x8616_parse_skip_ws(& line);
if (line.len == 0) continue;
if (result.instruction_count == request.instruction_cap) {
x8616_parse_push(request.info_arena, msgs, x8616_parse_output_full
, line_at, 0, request.instruction_cap, result.instruction_count);
goto exit;
}
X8616_DecodedInstruction inst = {0};
if (x8616_parse_line(line, & inst) == 0) {
x8616_parse_push(request.info_arena, msgs, x8616_parse_syntax
, line_at, u2_(line.len), 0, 0);
continue;
}
X8616_ParseStatus st = x8616_parse_validate(& inst);
if (st != x8616_parse_ok) {
x8616_parse_push(request.info_arena, msgs, st
, line_at, inst.size, 0, u4_(inst.op));
continue;
}
request.out_instructions[result.instruction_count] = inst;
result.instruction_count += 1;
}
exit:
result.source_consumed = offset;
result.msgs = *msgs;
return result;
}
+29
View File
@@ -0,0 +1,29 @@
#ifdef INTELLISENSE_DIRECTIVES
# pragma once
# include "decoder.h"
#endif
typedef Enum_(U1, X8616_ParseStatus) {
x8616_parse_ok = 0x00,
x8616_parse_output_full = 0x01,
x8616_parse_syntax = 0x02,
x8616_parse_invalid_record = 0x03,
x8616_parse_unsupported_form = 0x04,
x8616_parse_unknown_mnemonic = 0x05,
};
typedef Struct_(X8616_ParseRequest) {
Str8 source;
X8616_DecodedInstruction* out_instructions;
U4 instruction_cap;
FArena* info_arena;
X8616_InfoList_R msgs;
};
typedef Struct_(X8616_ParseInfo) {
X8616_InfoList msgs;
U4 instruction_count;
U4 source_consumed;
};
X8616_ParseInfo x8616_parse_instructions(X8616_ParseRequest request);
+421
View File
@@ -0,0 +1,421 @@
#ifdef INTELLISENSE_DIRECTIVES
# include "serializer.h"
# include "serializer_tables.h"
#endif
typedef Enum_(U1, X8616_SerializeSizeWhere) {
x8616_serialize_size_none = 0x00,
x8616_serialize_size_before_mem = 0x01,
x8616_serialize_size_before_imm = 0x02,
};
FI_ B4 x8616_serialize_put(Str8Gen_R gen, Str8 piece) {
if (piece.len > gen->cap - gen->len) return false;
str8gen_append_str8(gen, piece); return true;
}
FI_ X8616_SerializeStatus x8616_serialize_put_or_full(Str8Gen_R gen, Str8 piece) {
X8616_SerializeStatus status = x8616_serialize_ok;
if (x8616_serialize_put(gen, piece) == 0) status = x8616_serialize_output_full;
return status;
}
internal B4 x8616_serialize_put_u4(Str8Gen_R gen, U4 value) {
Info_str8_from_u4 info = str8_from_u4_info(value, 10, 0, 0); UTF8 digits[16];
B4 ok = info.size_required != 0 && info.size_required <= Array_len(digits) && info.size_required <= gen->cap - gen->len;
if (ok) {
Str8 text = str8_from_u4_buf(slice_ut(digits, info.size_required), value, 10, 0, 0, info);
ok = x8616_serialize_put(gen, text);
}
return ok;
}
internal B4 x8616_serialize_put_s4(Str8Gen_R gen, S4 value) {
B4 ok = true;
if (value < 0) {
ok = x8616_serialize_put(gen, slit8("-"));
if (ok) ok = x8616_serialize_put_u4(gen, C_(U4, -value));
}
else {
ok = x8616_serialize_put_u4(gen, C_(U4, value));
}
return ok;
}
internal S4 x8616_serialize_s4_from_bits(U2 bits, U1 byte_count) {
if (byte_count <= 1) return s4_(s1_(u1_(bits)));
return s4_(s2_(bits));
}
FI_ B4 x8616_serialize_imm_is_signed(X8616_Op op) { switch (op) {
case x8616_op_mov:
case x8616_op_add:
case x8616_op_adc:
case x8616_op_sub:
case x8616_op_sbb:
case x8616_op_cmp:
case x8616_op_ret:
case x8616_op_retf:
return 1;
default:
return 0;
}}
FI_ U1 x8616_serialize_imm_bytes(X8616_DecodedOperandFlags flags, U1 immediate_bytes, X8616_WidthMode width) {
if (immediate_bytes) return immediate_bytes;
if (flags & x8616_decoded_operand_sign_extended) return 1;
if (width == x8616_width_word) return 2;
return 1;
}
internal B4
x8616_serialize_put_imm(Str8Gen_R gen, X8616_DecodedInstruction_R inst, X8616_DecodedOperand_R operand) {
U1 bytes = x8616_serialize_imm_bytes(operand->flags, operand->immediate_bytes, operand->width);
if (x8616_serialize_imm_is_signed(inst->op)) {
return x8616_serialize_put_s4(gen, x8616_serialize_s4_from_bits(operand->immediate, bytes));
}
U4 value = operand->immediate;
if (bytes <= 1) value &= 0xFF;
return x8616_serialize_put_u4(gen, value);
}
internal X8616_WidthMode
x8616_serialize_mem_width(X8616_DecodedInstruction_R inst) {
for (U1 id = 0; id < inst->operand_count; ++id) {
if (inst->operands[id].flags & x8616_decoded_operand_memory) return inst->operands[id].width;
}
return inst->width;
}
internal X8616_SerializeSizeWhere
x8616_serialize_size_where(X8616_Op op, U1 operand_count, X8616_DecodedOperand operands[static 2])
{
B4 has_mem = 0;
B4 has_imm = 0;
for (U1 id = 0; id < operand_count; ++id) {
X8616_DecodedOperandFlags flags = operands[id].flags;
if (flags & x8616_decoded_operand_memory) has_mem = 1;
if ((flags & x8616_decoded_operand_immediate) && ((flags & x8616_decoded_operand_register) == 0)) has_imm = 1;
}
switch (op) {
case x8616_op_mov:
if (has_mem && has_imm) return x8616_serialize_size_before_imm;
return x8616_serialize_size_none;
case x8616_op_add:
case x8616_op_adc:
case x8616_op_sub:
case x8616_op_sbb:
case x8616_op_cmp:
case x8616_op_and:
case x8616_op_or:
case x8616_op_xor:
case x8616_op_test:
if (has_mem && has_imm) return x8616_serialize_size_before_mem;
return x8616_serialize_size_none;
case x8616_op_not:
case x8616_op_neg:
case x8616_op_inc:
case x8616_op_dec:
case x8616_op_mul:
case x8616_op_imul:
case x8616_op_div:
case x8616_op_idiv:
case x8616_op_push:
case x8616_op_pop:
case x8616_op_shl:
case x8616_op_shr:
case x8616_op_sar:
case x8616_op_rol:
case x8616_op_ror:
case x8616_op_rcl:
case x8616_op_rcr:
if (has_mem) return x8616_serialize_size_before_mem;
return x8616_serialize_size_none;
default:
return x8616_serialize_size_none;
}
}
internal B4 x8616_serialize_put_size(Str8Gen_R gen, X8616_WidthMode width) {
Str8 name = slit8("");
if (width == x8616_width_byte) name = slit8("byte");
if (width == x8616_width_word) name = slit8("word");
B4 ok = name.len != 0;
if (ok) ok = x8616_serialize_put(gen, name);
if (ok) ok = x8616_serialize_put(gen, slit8(" "));
return ok;
}
internal B4
x8616_serialize_put_memory(Str8Gen_R gen, X8616_DecodedInstruction_R inst, X8616_DecodedOperand_R operand)
{
B4 ok = true;
if (inst->prefixes.has_segment) {
ok = x8616_serialize_put(gen, x8616_serialize_seg[inst->prefixes.segment]);
if (ok) ok = x8616_serialize_put(gen, slit8(":"));
}
if (ok) ok = x8616_serialize_put(gen, slit8("["));
if (ok && (operand->flags & x8616_decoded_operand_direct)) {
ok = x8616_serialize_put_u4(gen, operand->address);
}
else if (ok) {
ok = x8616_serialize_put(gen, x8616_serialize_ea[operand->ea]);
S4 disp = operand->displacement;
if (ok && disp > 0) {
ok = x8616_serialize_put(gen, slit8(" + "));
if (ok) ok = x8616_serialize_put_u4(gen, C_(U4, disp));
}
else if (ok && disp < 0) {
ok = x8616_serialize_put(gen, slit8(" - "));
if (ok) ok = x8616_serialize_put_u4(gen, C_(U4, -disp));
}
}
if (ok) ok = x8616_serialize_put(gen, slit8("]"));
return ok;
}
FI_ B4 x8616_serialize_is_string(X8616_Op op) { switch (op) {
case x8616_op_movs:
case x8616_op_cmps:
case x8616_op_scas:
case x8616_op_lods:
case x8616_op_stos:
return 1;
default:
return 0;
}}
FI_ B4 x8616_serialize_has_memory(X8616_DecodedInstruction_R inst) {
for (U1 id = 0; id < inst->operand_count; ++id) { if (inst->operands[id].flags & x8616_decoded_operand_memory) return 1; }
return 0;
}
internal X8616_SerializeStatus
x8616_serialize_put_operand(Str8Gen_R gen, X8616_DecodedInstruction_R inst, X8616_DecodedOperand_R operand)
{
X8616_SerializeStatus status = x8616_serialize_ok;
X8616_SerializeSizeWhere where = x8616_serialize_size_where(inst->op, inst->operand_count, inst->operands);
X8616_WidthMode width = x8616_serialize_mem_width(inst);
B4 is_mem = (operand->flags & x8616_decoded_operand_memory) != 0;
B4 is_imm = ((operand->flags & x8616_decoded_operand_immediate) != 0) && ((operand->flags & x8616_decoded_operand_register) == 0);
B4 is_reg = (operand->flags & x8616_decoded_operand_register) != 0;
B4 is_seg = (operand->flags & x8616_decoded_operand_segment) != 0;
B4 is_rel = (operand->flags & x8616_decoded_operand_relative) != 0;
B4 is_far = (operand->flags & x8616_decoded_operand_far_ptr) != 0;
if (status == x8616_serialize_ok && where == x8616_serialize_size_before_mem && is_mem) {
if (x8616_serialize_put_size(gen, width) == 0) status = x8616_serialize_output_full;
}
if (status == x8616_serialize_ok && where == x8616_serialize_size_before_imm && is_imm) {
if (x8616_serialize_put_size(gen, width) == 0) status = x8616_serialize_output_full;
}
if (status == x8616_serialize_ok && (inst->flags & x8616_encoding_far) && is_mem) {
status = x8616_serialize_put_or_full(gen, slit8("far "));
}
if (status == x8616_serialize_ok) {
if (is_reg) {
U1 index = C_(U1, operand->reg.r16);
if (operand->width == x8616_width_byte) status = x8616_serialize_put_or_full(gen, x8616_serialize_reg8 [index]);
else if (operand->width == x8616_width_word) status = x8616_serialize_put_or_full(gen, x8616_serialize_reg16[index]);
else status = x8616_serialize_unsupported_form;
}
else if (is_seg) {
status = x8616_serialize_put_or_full(gen, x8616_serialize_seg[operand->segment]);
}
else if (is_mem) {
if (x8616_serialize_put_memory(gen, inst, operand) == 0) status = x8616_serialize_output_full;
}
else if (is_imm) {
if (x8616_serialize_put_imm(gen, inst, operand) == 0) status = x8616_serialize_output_full;
}
else if (is_rel) {
S4 rel = C_(S4, inst->size) + operand->displacement;
status = x8616_serialize_put_or_full(gen, slit8("$"));
if (status == x8616_serialize_ok && rel >= 0) status = x8616_serialize_put_or_full(gen, slit8("+"));
if (status == x8616_serialize_ok && x8616_serialize_put_s4(gen, rel) == 0) status = x8616_serialize_output_full;
}
else if (is_far) {
if (x8616_serialize_put_u4(gen, operand->far_segment) == 0) status = x8616_serialize_output_full;
if (status == x8616_serialize_ok) status = x8616_serialize_put_or_full(gen, slit8(":"));
if (status == x8616_serialize_ok && x8616_serialize_put_u4(gen, operand->far_offset) == 0) status = x8616_serialize_output_full;
}
else {
status = x8616_serialize_unsupported_form;
}
}
return status;
}
FI_ X8616_DecodedOperandFlags x8616_serialize_base_flags(X8616_DecodedOperandFlags flags) {
return flags & (
x8616_decoded_operand_register
| x8616_decoded_operand_segment
| x8616_decoded_operand_memory
| x8616_decoded_operand_immediate
| x8616_decoded_operand_relative
| x8616_decoded_operand_far_ptr
);
}
FI_ B4 x8616_serialize_one_flag(X8616_DecodedOperandFlags flags) { U2 bits = C_(U2, flags); return (bits != 0) && ((bits & (bits - 1)) == 0); }
internal void
x8616_serialize_push(FArena_R arena, X8616_InfoList_R msgs, X8616_SerializeStatus status, U4 id, U2 size, U4 expected, U4 actual) {
if (status == x8616_serialize_ok || arena == 0) return;
X8616_InfoKind kind = x8616_info_error;
X8616_InfoCode code = x8616_info_serialize_invalid_record;
if (status == x8616_serialize_output_full) {
kind = x8616_info_warning;
code = x8616_info_serialize_output_full;
}
else if (status == x8616_serialize_unsupported_form) {
code = x8616_info_serialize_unsupported_form;
}
x8616_info_push(arena, msgs, kind, code, id, size, expected, actual);
}
internal X8616_SerializeStatus
x8616_serialize_validate(X8616_DecodedInstruction_R inst)
{
X8616_SerializeStatus status = x8616_serialize_ok;
B4 bad_decode = inst->decode_flags & (x8616_decode_invalid | x8616_decode_truncated);
B4 invalid_sig = inst->size == 0 || inst->operand_count > 2;
B4 invalid_mnemonic = u4_(inst->op) >= Array_len(x8616_serialize_mnemonic) || inst->op == x8616_op_invalid;
B4 invalid_prefix_with_seg = inst->prefixes.has_segment && u1_(inst->prefixes.segment) >= Array_len(x8616_serialize_seg);
if (bad_decode || invalid_sig || invalid_mnemonic || invalid_prefix_with_seg) {
status = x8616_serialize_invalid_record; goto status_failed;
}
B4 bad_prefix_segment = inst->prefixes.has_segment && (x8616_serialize_has_memory(inst) == 0);
B4 bad_prefix_repeat = inst->prefixes.has_repeat && (x8616_serialize_is_string(inst->op) == 0);
if (bad_prefix_segment || bad_prefix_repeat) {
status = x8616_serialize_unsupported_form; goto status_failed;
}
for (U1 id = 0; id < inst->operand_count; ++id)
{
X8616_DecodedOperand_R operand = & inst->operands[id];
X8616_DecodedOperandFlags base = x8616_serialize_base_flags(operand->flags);
B4 invalid_flag = x8616_serialize_one_flag(base) == 0;
B4 has_operand_register = base & x8616_decoded_operand_register;
B4 has_operand_segment = base & x8616_decoded_operand_segment;
B4 has_operand_memory = base & x8616_decoded_operand_memory;
B4 invalid_reg_r16 = u1_(operand->reg.r16) >= Array_len(x8616_serialize_reg16);
B4 invalid_width = operand->width != x8616_width_byte && operand->width != x8616_width_word;
B4 invalid_operand_seg = u1_(operand->segment) >= Array_len(x8616_serialize_seg);
B4 invalid_operand_ea = u1_(operand->ea) >= Array_len(x8616_serialize_ea);
B4 invalid_direct_ea = has_operand_memory && ((operand->flags & x8616_decoded_operand_direct) == 0) && invalid_operand_ea;
B4 invalid_operand = invalid_flag
|| (has_operand_register && (invalid_reg_r16 || invalid_width))
|| (has_operand_segment && invalid_operand_seg)
|| invalid_direct_ea;
if (invalid_operand) {
status = x8616_serialize_invalid_record; goto status_failed;
}
}
status_failed:
return status;
}
internal X8616_SerializeStatus
x8616_serialize_instruction_line(Str8Gen_R line, X8616_DecodedInstruction* inst)
{
X8616_SerializeStatus st = x8616_serialize_ok;
Str8 mnemonic = x8616_serialize_mnemonic[inst->op];
if (mnemonic.len == 0) st = x8616_serialize_unsupported_form;
if (st == x8616_serialize_ok && inst->prefixes.lock) {
st = x8616_serialize_put_or_full(line, slit8("lock "));
}
if (st == x8616_serialize_ok && inst->prefixes.has_repeat) {
if (inst->prefixes.repeat == x8616_rep) st = x8616_serialize_put_or_full(line, slit8("rep "));
else st = x8616_serialize_put_or_full(line, slit8("repne "));
}
if (st == x8616_serialize_ok) st = x8616_serialize_put_or_full(line, mnemonic);
if (st == x8616_serialize_ok && x8616_serialize_is_string(inst->op)) {
if (inst->width == x8616_width_byte) st = x8616_serialize_put_or_full(line, slit8("b"));
else if (inst->width == x8616_width_word) st = x8616_serialize_put_or_full(line, slit8("w"));
else st = x8616_serialize_unsupported_form;
}
if (st == x8616_serialize_ok && inst->operand_count) {
st = x8616_serialize_put_or_full(line, slit8(" "));
for (U1 id = 0; st == x8616_serialize_ok && id < inst->operand_count; ++id) {
if (id) st = x8616_serialize_put_or_full(line, slit8(", "));
if (st == x8616_serialize_ok) st = x8616_serialize_put_operand(line, inst, & inst->operands[id]);
}
}
if (st == x8616_serialize_ok) st = x8616_serialize_put_or_full(line, slit8("\n"));
return st;
}
X8616_SerializeInfo x8616_serialize_instructions(X8616_SerializeRequest request)
{
X8616_SerializeInfo result = {0}; result.text.ptr = C_(UTF8*, request.output.ptr);
X8616_InfoList local = {0};
X8616_InfoList_R msgs = request.msgs ? request.msgs : & local;
B4 bad_request =
(request.instruction_count && request.instructions == 0)
|| (request.output.len && request.output.ptr == 0)
|| (request.scratch.len && request.scratch.ptr == 0)
|| (request.info_arena == 0);
if (bad_request)
{
if (request.info_arena) {
x8616_info_push(request.info_arena, msgs, x8616_info_error
, x8616_info_serialize_bad_request, 0, 0, 0, 0);
}
else {
msgs->count += 1;
msgs->error_count += 1;
msgs->dropped_count += 1;
}
goto exit;
}
if (request.output.len < x8616_serialize_header.len) {
x8616_serialize_push(request.info_arena, msgs, x8616_serialize_output_full
, 0, 0, u4_(x8616_serialize_header.len), u4_(request.output.len));
goto exit;
}
Str8Gen gen = str8gen_make(request.output);
str8gen_append_str8(& gen, x8616_serialize_header);
result.text.len = gen.len;
for (U4 id = 0; id < request.instruction_count; ++id)
{
X8616_DecodedInstruction_R inst = & request.instructions[id];
X8616_SerializeStatus line_status = x8616_serialize_validate(inst);
if (line_status != x8616_serialize_ok) {
x8616_serialize_push(request.info_arena, msgs, line_status
, id, inst->size, 0, u4_(inst->op));
continue;
}
Str8Gen line = str8gen_make(request.scratch);
line_status = x8616_serialize_instruction_line(& line, inst);
if (line_status != x8616_serialize_ok) {
x8616_serialize_push(request.info_arena, msgs, line_status
, id, inst->size, u4_(request.scratch.len), u4_(line.len));
continue;
}
Str8 text = str8(line.ptr, line.len);
if (text.len > gen.cap - gen.len) {
x8616_serialize_push(request.info_arena, msgs, x8616_serialize_output_full
, id, inst->size, u4_(request.output.len), u4_(gen.len));
goto exit;
}
str8gen_append_str8(& gen, text);
result.text.len = gen.len;
result.instructions_written += 1;
}
exit:
result.msgs = *msgs;
return result;
}
+29
View File
@@ -0,0 +1,29 @@
#ifdef INTELLISENSE_DIRECTIVES
# pragma once
# include "decoder.h"
#endif
typedef Enum_(U1, X8616_SerializeStatus) {
x8616_serialize_ok = 0x00,
x8616_serialize_output_full = 0x01,
x8616_serialize_invalid_record = 0x02,
x8616_serialize_unsupported_form = 0x03,
};
typedef Struct_(X8616_SerializeRequest) {
X8616_DecodedInstruction* instructions;
U4 instruction_count; byte_pad(4);
Slice output;
Slice scratch;
FArena* info_arena;
X8616_InfoList_R msgs;
};
typedef Struct_(X8616_SerializeInfo) {
X8616_InfoList msgs;
Str8 text;
U4 instructions_written;
byte_pad(4);
};
X8616_SerializeInfo x8616_serialize_instructions(X8616_SerializeRequest request);
+142
View File
@@ -0,0 +1,142 @@
#ifdef INTELLISENSE_DIRECTIVES
# pragma once
# include "encoder.h"
#endif
RO_ global Str8 x8616_serialize_header = slit8("bits 16\n\n");
RO_ global Str8 x8616_serialize_mnemonic[] = {
[x8616_op_invalid] = slit8(""),
[x8616_op_nop] = slit8("nop"),
[x8616_op_mov] = slit8("mov"),
[x8616_op_add] = slit8("add"),
[x8616_op_or] = slit8("or"),
[x8616_op_adc] = slit8("adc"),
[x8616_op_sbb] = slit8("sbb"),
[x8616_op_and] = slit8("and"),
[x8616_op_sub] = slit8("sub"),
[x8616_op_xor] = slit8("xor"),
[x8616_op_cmp] = slit8("cmp"),
[x8616_op_push] = slit8("push"),
[x8616_op_pop] = slit8("pop"),
[x8616_op_xchg] = slit8("xchg"),
[x8616_op_in] = slit8("in"),
[x8616_op_out] = slit8("out"),
[x8616_op_xlat] = slit8("xlat"),
[x8616_op_lea] = slit8("lea"),
[x8616_op_lds] = slit8("lds"),
[x8616_op_les] = slit8("les"),
[x8616_op_lahf] = slit8("lahf"),
[x8616_op_sahf] = slit8("sahf"),
[x8616_op_pushf] = slit8("pushf"),
[x8616_op_popf] = slit8("popf"),
[x8616_op_inc] = slit8("inc"),
[x8616_op_aaa] = slit8("aaa"),
[x8616_op_daa] = slit8("daa"),
[x8616_op_dec] = slit8("dec"),
[x8616_op_neg] = slit8("neg"),
[x8616_op_aas] = slit8("aas"),
[x8616_op_das] = slit8("das"),
[x8616_op_mul] = slit8("mul"),
[x8616_op_imul] = slit8("imul"),
[x8616_op_aam] = slit8("aam"),
[x8616_op_div] = slit8("div"),
[x8616_op_idiv] = slit8("idiv"),
[x8616_op_aad] = slit8("aad"),
[x8616_op_cbw] = slit8("cbw"),
[x8616_op_cwd] = slit8("cwd"),
[x8616_op_not] = slit8("not"),
[x8616_op_shl] = slit8("shl"),
[x8616_op_shr] = slit8("shr"),
[x8616_op_sar] = slit8("sar"),
[x8616_op_rol] = slit8("rol"),
[x8616_op_ror] = slit8("ror"),
[x8616_op_rcl] = slit8("rcl"),
[x8616_op_rcr] = slit8("rcr"),
[x8616_op_test] = slit8("test"),
[x8616_op_rep] = slit8(""),
[x8616_op_movs] = slit8("movs"),
[x8616_op_cmps] = slit8("cmps"),
[x8616_op_scas] = slit8("scas"),
[x8616_op_lods] = slit8("lods"),
[x8616_op_stos] = slit8("stos"),
[x8616_op_call] = slit8("call"),
[x8616_op_jmp] = slit8("jmp"),
[x8616_op_ret] = slit8("ret"),
[x8616_op_retf] = slit8("retf"),
[x8616_op_je] = slit8("je"),
[x8616_op_jl] = slit8("jl"),
[x8616_op_jle] = slit8("jle"),
[x8616_op_jb] = slit8("jb"),
[x8616_op_jbe] = slit8("jbe"),
[x8616_op_jp] = slit8("jp"),
[x8616_op_jo] = slit8("jo"),
[x8616_op_js] = slit8("js"),
[x8616_op_jne] = slit8("jne"),
[x8616_op_jnl] = slit8("jnl"),
[x8616_op_jg] = slit8("jg"),
[x8616_op_jnb] = slit8("jnb"),
[x8616_op_ja] = slit8("ja"),
[x8616_op_jnp] = slit8("jnp"),
[x8616_op_jno] = slit8("jno"),
[x8616_op_jns] = slit8("jns"),
[x8616_op_loop] = slit8("loop"),
[x8616_op_loopz] = slit8("loopz"),
[x8616_op_loopnz] = slit8("loopnz"),
[x8616_op_jcxz] = slit8("jcxz"),
[x8616_op_int] = slit8("int"),
[x8616_op_int3] = slit8("int3"),
[x8616_op_into] = slit8("into"),
[x8616_op_iret] = slit8("iret"),
[x8616_op_clc] = slit8("clc"),
[x8616_op_cmc] = slit8("cmc"),
[x8616_op_stc] = slit8("stc"),
[x8616_op_cld] = slit8("cld"),
[x8616_op_std] = slit8("std"),
[x8616_op_cli] = slit8("cli"),
[x8616_op_sti] = slit8("sti"),
[x8616_op_hlt] = slit8("hlt"),
[x8616_op_wait] = slit8("wait"),
[x8616_op_lock] = slit8(""),
[x8616_op_segment] = slit8(""),
};
RO_ global Str8 x8616_serialize_reg8[] = {
[x8616_al] = slit8("al"),
[x8616_cl] = slit8("cl"),
[x8616_dl] = slit8("dl"),
[x8616_bl] = slit8("bl"),
[x8616_ah] = slit8("ah"),
[x8616_ch] = slit8("ch"),
[x8616_dh] = slit8("dh"),
[x8616_bh] = slit8("bh"),
};
RO_ global Str8 x8616_serialize_reg16[] = {
[x8616_ax] = slit8("ax"),
[x8616_cx] = slit8("cx"),
[x8616_dx] = slit8("dx"),
[x8616_bx] = slit8("bx"),
[x8616_sp] = slit8("sp"),
[x8616_bp] = slit8("bp"),
[x8616_si] = slit8("si"),
[x8616_di] = slit8("di"),
};
RO_ global Str8 x8616_serialize_seg[] = {
[x8616_es] = slit8("es"),
[x8616_cs] = slit8("cs"),
[x8616_ss] = slit8("ss"),
[x8616_ds] = slit8("ds"),
};
RO_ global Str8 x8616_serialize_ea[] = {
[x8616_ea_bx_si] = slit8("bx + si"),
[x8616_ea_bx_di] = slit8("bx + di"),
[x8616_ea_bp_si] = slit8("bp + si"),
[x8616_ea_bp_di] = slit8("bp + di"),
[x8616_ea_si] = slit8("si"),
[x8616_ea_di] = slit8("di"),
[x8616_ea_bp] = slit8("bp"),
[x8616_ea_bx] = slit8("bx"),
};
+123
View File
@@ -0,0 +1,123 @@
#ifdef INTELLISENSE_DIRECTIVES
# pragma once
# include "dsl.h"
#endif
#define asm_out /* outputs */
#define asm_in /* inputs */
#define asm_clobber /* clobbers */
#define asm_out_r(name) [name] "=r"(name)
#define asm_in_r(name) [name] "r"(name)
#define asm_out_x(name) [name] "=&x"(name) /* XMM, earlyclobber */
#define asm_out_x0(name) [name] "=x"(name) /* XMM, no earlyclobber */
#define asm_in_x(name) [name] "x"(name)
#define x64_r(name) "%[" #name "]"
#define x64_m(name) "(%[" #name "])"
#define x64_xmm(name) "%x[" #name "]"
typedef U8 U8x2 attribute(vector_size(16));
typedef U8 U8x4 attribute(vector_size(32));
typedef U1 U1x16 attribute(vector_size(16));
#define x64_u4_from_byte_hits(dst, src) "pmovmskb " x64_r(src) ", " x64_r(dst) "\n"
#define x64_u4_count_trailing_zeros(dst, src) "tzcntl " x64_r(src) ", " x64_r(dst) "\n"
#define x64_u1x16_repeat_dwords(dst, src, n) "pshufd $" #n ", " x64_r(src) ", " x64_r(dst) "\n"
#define x64_u1x16_load_mem4(dst, src) "movd " x64_r(src) ", " x64_r(dst) "\n"
#define x64_u1x16_load_mem8(dst, src) "movq " x64_m(src) ", " x64_r(dst) "\n"
#define x64_u1x16_load_mem16(dst, src) "movdqu " x64_m(src) ", " x64_r(dst) "\n"
#define x64_u1x16_match_bytes(dst, src) "pcmpeqb " x64_r(src) ", " x64_r(dst) "\n"
#define x64_u8x2_load_u8(dst, src) "vmovq " x64_m(src) ", " x64_r(dst) "\n"
#define x64_u8x2_insert_u8(dst, src, n) "vpinsrq $" #n ", " x64_m(src) ", " x64_r(dst) ", " x64_r(dst) "\n"
#define x64_u8x4_insert_xmm(dst, src, n) "vinserti128 $" #n ", " x64_r(src) ", " x64_r(dst) ", " x64_r(dst) "\n"
#define x64_u8x4_broadcast(dst, src) "vpbroadcastq " x64_r(src) ", " x64_r(dst) "\n"
#define x64_u8x4_match(dst, a, b) "vpcmpeqq " x64_r(b) ", " x64_r(a) ", " x64_r(dst) "\n"
#define x64_u4_from_qword_hits(dst, src) "vmovmskpd " x64_r(src) ", " x64_r(dst) "\n"
FI_ U4 count_trailing_zeros_u4(U4 mask) {
U4 n;
asm volatile(
x64_u4_count_trailing_zeros(n, mask)
asm_out : asm_out_r(n)
asm_in : asm_in_r(mask)
);
return n;
}
FI_ U1x16 splat_u4_u1x16(U4 b4) {
U1x16 v;
asm volatile(
x64_u1x16_load_mem4 (v, b4)
x64_u1x16_repeat_dwords(v, v, 0)
asm_out : asm_out_x0(v)
asm_in : asm_in_r(b4)
);
return v;
}
FI_ U4 mask_eq8_u1x16(U1_R p, U1x16 needle) {
U1x16 chunk;
U4 mask;
asm volatile(
x64_u1x16_load_mem8 (chunk, p)
x64_u1x16_match_bytes(chunk, needle)
x64_u4_from_byte_hits(mask, chunk)
asm_out : asm_out_x(chunk), asm_out_r(mask)
asm_in : asm_in_r(p), asm_in_x(needle)
asm_clobber : "memory"
);
return mask; /* movq zero-fills the high 8 bytes; bits 815 stay 0 */
}
FI_ U4 mask_eq16_u1x16(U1_R p, U1x16 needle) {
U1x16 chunk;
U4 mask;
asm volatile(
x64_u1x16_load_mem16 (chunk, p)
x64_u1x16_match_bytes(chunk, needle)
x64_u4_from_byte_hits(mask, chunk)
asm_out : asm_out_x(chunk), asm_out_r(mask)
asm_in : asm_in_r(p), asm_in_x(needle)
asm_clobber : "memory"
);
return mask;
}
I_ U8 find_u1_via_u1x16(U1_R p, U8 len, U1 ch, U1x16 needle) {
U8 i = 0;
while (len - i >= 16) {
U4 mask = mask_eq16_u1x16(p + i, needle);
if (mask) return i + C_(U8, count_trailing_zeros_u4(mask));
i += 16;
}
while (len - i >= 8) {
U4 mask = mask_eq8_u1x16(p + i, needle);
if (mask) return i + C_(U8, count_trailing_zeros_u4(mask));
i += 8;
}
while (i < len) {
if (p[i] == ch) return i;
++ i;
}
return len; /* not found */
}
FI_ U4 find_aos_keys_mask_u8x4(U8_R p0, U8_R p1, U8_R p2, U8_R p3, U8 key) {
U8x2 lo, hi;
U8x4 keys, splat, eq;
U4 mask;
asm volatile(
x64_u8x2_load_u8 (lo, p0) x64_u8x2_insert_u8(lo, p1, 1)
x64_u8x2_load_u8 (hi, p2) x64_u8x2_insert_u8(hi, p3, 1)
x64_u8x4_insert_xmm(keys, lo, 0) x64_u8x4_insert_xmm(keys, hi, 1)
x64_u8x4_broadcast(splat, key) x64_u8x4_match(eq, keys, splat)
x64_u4_from_qword_hits(mask, eq)
asm_out : asm_out_x(lo), asm_out_x(hi), asm_out_x(keys), asm_out_x(splat), asm_out_x(eq), asm_out_r(mask)
asm_in : asm_in_r(p0), asm_in_r(p1), asm_in_r(p2), asm_in_r(p3), asm_in_r(key)
asm_clobber : "memory"
);
return mask;
}
+28 -71
View File
@@ -10,6 +10,7 @@ Standard: c23
#pragma clang diagnostic ignored "-Wswitch" #pragma clang diagnostic ignored "-Wswitch"
#pragma clang diagnostic ignored "-Wuninitialized" #pragma clang diagnostic ignored "-Wuninitialized"
#pragma clang diagnostic ignored "-Wmicrosoft-enum-forward-reference" #pragma clang diagnostic ignored "-Wmicrosoft-enum-forward-reference"
#pragma clang diagnostic ignored "-Wmicrosoft-fixed-enum"
// #pragma comment(lib, "Advapi32.lib") // #pragma comment(lib, "Advapi32.lib")
// #pragma comment(lib, "gdi32.lib") // #pragma comment(lib, "gdi32.lib")
// #pragma comment(lib, "Kernel32.lib") // #pragma comment(lib, "Kernel32.lib")
@@ -41,8 +42,8 @@ Standard: c23
#define glue(A, B) glue_impl(A, B) #define glue(A, B) glue_impl(A, B)
#define tmpl(prefix, type) prefix ## _ ## type #define tmpl(prefix, type) prefix ## _ ## type
#define stringify_impl(S) #S #define stringify_impl(...) #__VA_ARGS__
#define stringify(S) stringify_impl(S) #define stringify(...) stringify_impl(__VA_ARGS__)
#define VA_Sel_1( _1, ... ) _1 // <-- Of all th args passed pick _1. #define VA_Sel_1( _1, ... ) _1 // <-- Of all th args passed pick _1.
#define VA_Sel_2( _1, _2, ... ) _2 // <-- Of all the args passed pick _2. #define VA_Sel_2( _1, _2, ... ) _2 // <-- Of all the args passed pick _2.
@@ -54,54 +55,23 @@ Standard: c23
#define LP_ static // static data within procedure scope #define LP_ static // static data within procedure scope
#define internal static // internal #define internal static // internal
#define attribute(directive) __attribute__((directive))
#define asm __asm__ #define asm __asm__
#define align_(value) __attribute__((aligned (value))) // for easy alignment #define align_(value) attribute(aligned(value)) // for easy alignment
#define C_(type,data) ((type)(data)) // for enforced precedence #define C_(type,data) ((type)(data)) // for enforced precedence
#define expect_(x, y) __builtin_expect(x, y) // so compiler knows the common path #define expect_(x, y) __builtin_expect(x, y) // so compiler knows the common path
#define cexpr_ __builtin_constant_p #define cexpr_ __builtin_constant_p
#define I_ internal inline #define I_ internal inline
#define FI_ inline __attribute__((always_inline)) // inline always #define FI_ inline attribute(always_inline) // inline always
#define NI_ internal __attribute__((noinline)) // inline never #define NI_ internal attribute(noinline) // inline never
#define RO_ __attribute__((section(".rodata"))) // Read only data allocation #define RO_ attribute(section(".rodata")) // Read only data allocation
#define T_ typeof // #define T_ typeof //
#define T_same(a,b) _Generic((a), typeof((b)): 1, default: 0) #define T_same(a,b) _Generic((a), typeof((b)): 1, default: 0)
#define R_ restrict #define R_ restrict
#define V_ volatile #define V_ volatile
// R_ (restrict) establishes an "Eigen" or "Proprius" mapping.
// Unlike volatile (V_), which assumes the memory can be changed by anything,
// R_ tells the compiler that this pointer holds the *sole*, private (idios) ownership of the memory slice.
// Writes to this memory are exclusively bound to this single symbolic mapping for the duration of the scope, guaranteeing zero aliasing.
#pragma region Fictional //, used for intiution
#define EUB_ restrict // Execute Unit Bound: Data is siloed in the ALU Register File. The Load/Store Unit is bypassed. (Route to Execution Unit. Keep in registers)
#define ISO_ restrict // Isolated Provenance: Alternative to Exu_. Guarantees electrical memory isolation,
// unlocking the compilers ability to safely pack data across multiple parallel SIMD lanes (vectorization).
#define LSU_ volatile // Load/Store Unit Bound: The compiler is forbidden from caching in registers. Forces physical L1 Cache matrix sampling.
#define LIVE_ volatile // Live External Data: Alternative to Lsu_ emphasizing the memory is tapped by an external electrical actor.
#define latch_store /* ~: atomic_store*/ // Blasts voltages from the Store Buffer into the L1 SRAM, physically flipping the cross-coupled inverters to lock the state.
#define pulse_rfo /* ~: atomic_xchg*/ // Broadcasts an electrical RFO (Request For Ownership) pulse across the CPU mesh network to invalidate other L1 caches.
#define tact_acquire /* ~: memory_order_acquire*/ // Clamp. Sends a voltage signal to the instruction decoder to halt the Out-of-Order engine until the load resolves.
#define tact_release /* ~: memory_order_release*/ // Drain. Forces the Store Buffer flip-flops to completely empty into the L1 cache before proceeding.
// -----------------------------------------------------------------------------
// Out-of-Order (OoO) Pipeline Modifiers
// -----------------------------------------------------------------------------
#define ooo_drift_ __ATOMIC_RELAXED // OoO engine allowed to drift
#define ooo_anchor_ __ATOMIC_ACQUIRE // Anchor the Load Queue (halt spec lookahead)
#define ooo_drain_ __ATOMIC_RELEASE // Drain the Store Buffer (force writeback)
#define ooo_weld_ __ATOMIC_SEQ_CST // Weld pipeline (total order bus lock)
// Latch operations with physical queue modifiers
#define latch_load_anchor(ptr) //__atomic_load_n(ptr, ooo_anchor_)
#define latch_store_drain(ptr, val) //__atomic_store_n(ptr, val, ooo_drain_)
#define pulse_xchg_weld(ptr, val) //__atomic_exchange_n(ptr, val, ooo_weld_)
#pragma endregion Fictional
#define r_(ptr) C_(T_(ptr[0])*R_, ptr) // Constrain pointer to restrict #define r_(ptr) C_(T_(ptr[0])*R_, ptr) // Constrain pointer to restrict
#define v_(ptr) C_(T_(ptr[0])V_*, ptr) // #define v_(ptr) C_(T_(ptr[0])V_*, ptr) //
@@ -119,7 +89,7 @@ Standard: c23
#define Array_expand(type,len) type Array_sym(type, len)[len]; typedef PtrSet_(Array_sym(type, len)) #define Array_expand(type,len) type Array_sym(type, len)[len]; typedef PtrSet_(Array_sym(type, len))
#define Array_(type,len) Array_expand(type,len) #define Array_(type,len) Array_expand(type,len)
#define Bit_(id,b) id = (1 << b), tmpl(id,pos) = b #define Bit_(id,b) id = (1 << b), tmpl(id,pos) = b
#define Enum_(underlying_type, symbol) underlying_type TSet_(symbol); enum symbol #define Enum_(underlying_type, symbol) enum symbol : underlying_type TSet_(symbol); enum symbol : underlying_type
#define Proc_(symbol) symbol #define Proc_(symbol) symbol
#define Relative_(symbol) // Does nothing but annotate that a symbol is associated with another. #define Relative_(symbol) // Does nothing but annotate that a symbol is associated with another.
#define Struct_(symbol) struct symbol TSet_(symbol); struct symbol #define Struct_(symbol) struct symbol TSet_(symbol); struct symbol
@@ -164,8 +134,11 @@ typedef float F4_2 __attribute__((vector_size(16)));
#define u8_v(value) C_(U8 V_*, value) #define u8_v(value) C_(U8 V_*, value)
enum { false = 0, true = 1, true_overflow, }; enum { false = 0, true = 1, true_overflow, };
#define u2_lo(value) u1_(u2_(value))
#define u2_hi(value) u1_(u2_(value) >> 8)
#define u4_lo(value) ((value) & 0xFFFFU) #define u4_lo(value) ((value) & 0xFFFFU)
#define u4_hi(value) ((value) >> 12) #define u4_hi(value) ((value) >> 16)
typedef void Proc_(VoidFn) (void); typedef void Proc_(VoidFn) (void);
@@ -218,6 +191,10 @@ def_signed_ops(le, <=)
#define dbg_args(...) __VA_ARGS__ #define dbg_args(...) __VA_ARGS__
#pragma region Control Flow & Iteration #pragma region Control Flow & Iteration
#define jump_ne(a,b,label) if (a != b) goto label
#define jump_gt(a,b,label) if (a > b) goto label
#define jump_lt(a,b,label) if (a < b) goto label
#define unreachable() __builtin_unreachable() #define unreachable() __builtin_unreachable()
#define each_iter(type, iter, end) (type iter = 0; iter < end; ++ iter) #define each_iter(type, iter, end) (type iter = 0; iter < end; ++ iter)
@@ -262,6 +239,10 @@ FI_ U8 atm_swap_u8(U8_R addr, U8 value){asm volatile("lock xchgq %0,%1":"=r"(val
#pragma endregion Thread Coherence #pragma endregion Thread Coherence
#pragma region Misc #pragma region Misc
#define byte_pos(pos) (pos * 8)
#define byte_shift(value,pos) (value << byte_pos(pos))
#define u4_byte_fill(value) byte_shift(value,0) | byte_shift(value,1) | byte_shift(value,2) | byte_shift(value,3)
enum { enum {
Bitmask_3 = 0x00000007, Bitmask_3 = 0x00000007,
Bitmask_4 = 0x0000000f, Bitmask_4 = 0x0000000f,
@@ -270,32 +251,8 @@ enum {
Bitmask_10 = 0x000003ff, Bitmask_10 = 0x000003ff,
}; };
typedef Enum_(U4, WeekDay) { typedef Enum_(U4, WeekDay) { WeekDay_Sun, WeekDay_Mon, WeekDay_Tue, WeekDay_Wed, WeekDay_Thu, WeekDay_Fri, WeekDay_Sat, WeekDay_Num, };
WeekDay_Sun, typedef Enum_(U4, Month) { Month_Jan, Month_Feb, Month_Mar, Month_Apr, Month_May, Month_Jun, Month_Jul, Month_Aug, Month_Sep, Month_Oct, Month_Nov, Month_Dec, Month_Num, };
WeekDay_Mon,
WeekDay_Tue,
WeekDay_Wed,
WeekDay_Thu,
WeekDay_Fri,
WeekDay_Sat,
WeekDay_Num,
};
typedef Enum_(U4, Month) {
Month_Jan,
Month_Feb,
Month_Mar,
Month_Apr,
Month_May,
Month_Jun,
Month_Jul,
Month_Aug,
Month_Sep,
Month_Oct,
Month_Nov,
Month_Dec,
Month_Num,
};
typedef U8 DenseTime; typedef U8 DenseTime;
+1 -1
View File
@@ -16,7 +16,7 @@ FI_ void u64_to_hex(U8 val, char* buf, S4 chars) {
for(S1 i = chars - 1; i >= 0; --i) { buf[i] = hex_chars[val & 0xF]; val >>= 4; } for(S1 i = chars - 1; i >= 0; --i) { buf[i] = hex_chars[val & 0xF]; val >>= 4; }
} }
internal UnicodeDecode I_ UnicodeDecode
utf8_decode(U1* str, U1 max) { utf8_decode(U1* str, U1 max) {
UnicodeDecode result = {1, Max_U4}; UnicodeDecode result = {1, Max_U4};
U1 byte = str[0]; U1 byte = str[0];
+14 -4
View File
@@ -13,7 +13,7 @@
CLANG_OPTIMIZE_DISABLE CLANG_OPTIMIZE_DISABLE
// Most of this referenced from the RAD Debugger codebase. // Most of this referenced from the RAD Debugger codebase.
typedef Enum_(U4,AccessFlags) { typedef Enum_(U4, AccessFlags) {
Bit_(AccessFlag_Read, 0), Bit_(AccessFlag_Read, 0),
Bit_(AccessFlag_Write, 1), Bit_(AccessFlag_Write, 1),
Bit_(AccessFlag_Execute, 2), Bit_(AccessFlag_Execute, 2),
@@ -48,15 +48,17 @@ os_layer File file_open(FArena* scratch, AccessFlags flags, Str8 path);
#define file_scope(scratch, flags, path) scope_info(Scope_FileInfo, {.f = file_open(scratch, flags, path)}, file_close(info.f)) #define file_scope(scratch, flags, path) scope_info(Scope_FileInfo, {.f = file_open(scratch, flags, path)}, file_close(info.f))
os_layer FileProperties properties_from_file(File file); os_layer FileProperties properties_from_file(File file);
os_layer U8 file_read(File file, R1_U8 rng, U1* out_data); os_layer U8 file_read (File file, R1_U8 rng, U1* out_data);
os_layer U8 file_write(File file, R1_U8 rng, U1* data);
internal Slice_U1 I_ Slice_U1
data_from_file_range(FArena* arena, File file, R1_U8 range) { data_from_file_range(FArena* arena, File file, R1_U8 range) {
U8 pre_pos = farena_save(arena[0]); U8 pre_pos = farena_save(arena[0]);
U8 len = span_r1u8(range); U8 len = span_r1u8(range);
Slice_U1 result = farena_push_array(arena, U1, len); Slice_U1 result = farena_push_array(arena, U1, len);
U8 actual_read_size = file_read(file, range, result.ptr); if (actual_read_size < result.len) { U8 actual_read_size = file_read(file, range, result.ptr); if (actual_read_size < result.len) {
farena_rewind(arena, pre_pos + actual_read_size); result.len = actual_read_size; U8 committed = align_pow2(actual_read_size, MEM_ALIGNMENT_DEFAULT);
farena_rewind(arena, pre_pos + committed); result.len = actual_read_size;
} }
return result; return result;
} }
@@ -67,4 +69,12 @@ data_from_file_path(FArena* arena, Str8 path, FArena* scratch) { file_scope(scra
Slice_U1 data = data_from_file_range(arena, info.f, r1u8(0, props.size)); return data; Slice_U1 data = data_from_file_range(arena, info.f, r1u8(0, props.size)); return data;
} unreachable(); } } unreachable(); }
I_ B4
write_data_to_file_path(Str8 path, Str8 data, FArena* scratch) {
B4 good = false; file_scope(scratch, AccessFlag_Write, path) if (file_match(info.f, file_zero()) == false) {
U8 bytes_written = file_write(info.f, r1u8(0, data.len), data.ptr); good = bytes_written == data.len;
}
return good;
}
CLANG_OPTIMIZE_ENABLE CLANG_OPTIMIZE_ENABLE
+43 -24
View File
@@ -5,7 +5,7 @@
#define MEM_ALIGNMENT_DEFAULT 4 #define MEM_ALIGNMENT_DEFAULT 4
#define assert_bounds(point, start, end) for(;0;){ \ #define assert_bounds(point, start, end) do{ \
assert((start) <= (point)); \ assert((start) <= (point)); \
assert((point) <= (end)); \ assert((point) <= (end)); \
} while(0) } while(0)
@@ -37,9 +37,19 @@ FI_ U8 mem_compare(U8 a, U8 b, U8 len) { return (U8)(__builtin_memcmp((void cons
FI_ B4 mem_match (U8 a, U8 b, U8 z) { return mem_compare(a, b, z) == 0; } FI_ B4 mem_match (U8 a, U8 b, U8 z) { return mem_compare(a, b, z) == 0; }
#define mem_match_struct(a,b) mem_match(C_(U8,a), C_(U8,b), S_((a)[0])) #define mem_match_struct(a,b) mem_match(C_(U8,a), C_(U8,b), S_((a)[0]))
#define mem_zero_struct(s) mem_zero(u8_(& s), S_(s))
I_ void mem_push_aligned_typed(U8 start, U8 capacity, U8_R used, U8 amount, U4 alignment, U4 type_width, U8_R out_ptr, U8_R out_len) {
if (amount == 0) { out_ptr[0] = 0; out_len[0] = 0; return; }
U8 desired = amount * (type_width == 0 ? 1 : type_width);
U8 to_commit = align_pow2(desired, alignment ? alignment : MEM_ALIGNMENT_DEFAULT);
U8 ptr = start + used[0];
mem_bump_u8(start, capacity, used, to_commit);
out_ptr[0] = ptr;
out_len[0] = to_commit;
}
#pragma region DAG #pragma region DAG
#define check_nil(nil, p) ((p) == 0 || (p) == nil) #define check_nil(nil, p) ((p) == 0 || (p) == nil)
#define set_nil(nil, p) ((p) = nil) #define set_nil(nil, p) ((p) = nil)
@@ -58,16 +68,13 @@ FI_ B4 mem_match (U8 a, U8 b, U8 z) { return mem_compare(a, b, z) == 0; }
) \ ) \
) )
#define sll_queue_push_n(f, l, n, next) sll_queue_push_nz(0, f, l, n, next) #define sll_queue_push_n(f, l, n, next) sll_queue_push_nz(0, f, l, n, next)
#pragma endregion DAG #pragma endregion DAG
#pragma region Slice #pragma region Slice
typedef unsigned char TSet_(UTF8); typedef unsigned char TSet_(UTF8);
typedef Struct_(Str8) { UTF8* ptr; U8 len; }; typedef Struct_(Str8) { UTF8* ptr; U8 len; }; typedef Str8 Slice_UTF8;
typedef Str8 Slice_UTF8;
typedef Struct_(Slice_Str8) { Str8* ptr; U8 len; }; typedef Struct_(Slice_Str8) { Str8* ptr; U8 len; };
#define slit8(string_literal) (Str8){ (UTF8*) string_literal, S_(string_literal) - 1 } #define slit8(string_literal) ((Str8){ (UTF8*) string_literal, S_(string_literal) - 1 })
#define str8(p,l) (Str8){p,l} #define str8(p,l) (Str8){p,l}
typedef Struct_(Slice) { U8 ptr; U8 len; }; // Untyped Slice typedef Struct_(Slice) { U8 ptr; U8 len; }; // Untyped Slice
@@ -81,7 +88,6 @@ FI_ Slice slice_ut_(U8 ptr, U8 len) { return (Slice){ptr, len}; }
#define slice_ut(ptr,len) slice_ut_(u8_(ptr), u8_(len)) #define slice_ut(ptr,len) slice_ut_(u8_(ptr), u8_(len))
#define slice_ut_arr(a) slice_ut_(u8_(a), S_(a)) #define slice_ut_arr(a) slice_ut_(u8_(a), S_(a))
#define slice_to_ut(s) slice_ut_(u8_((s).ptr), S_slice(s)) #define slice_to_ut(s) slice_ut_(u8_((s).ptr), S_slice(s))
#define slice_iter(container, iter) (T_((container).ptr) iter = (container).ptr; iter != slice_end(container); ++ iter) #define slice_iter(container, iter) (T_((container).ptr) iter = (container).ptr; iter != slice_end(container); ++ iter)
#define slice_arg_from_array(type, ...) & (tmpl(Slice,type)) { .ptr = Array_decl(type,__VA_ARGS__), .len = Array_len( Array_decl(type,__VA_ARGS__)) } #define slice_arg_from_array(type, ...) & (tmpl(Slice,type)) { .ptr = Array_decl(type,__VA_ARGS__), .len = Array_len( Array_decl(type,__VA_ARGS__)) }
#define slice_from_array(type, array) (tmpl(Slice,type)) { .ptr = array, .len = S_(array) } #define slice_from_array(type, array) (tmpl(Slice,type)) { .ptr = array, .len = S_(array) }
@@ -105,11 +111,9 @@ typedef Slice_(U1);
typedef Slice_(U2); typedef Slice_(U2);
typedef Slice_(U4); typedef Slice_(U4);
typedef Slice_(U8); typedef Slice_(U8);
#pragma endregion Slice #pragma endregion Slice
#pragma region FArena #pragma region FArena
typedef Opt_(farena) { U8 alignment, type_width; }; typedef Opt_(farena) { U8 alignment, type_width; };
typedef Struct_(FArena) { U8 start, capacity, used; }; typedef Struct_(FArena) { U8 start, capacity, used; };
FI_ void farena_init(FArena_R arena, Slice mem) { assert(arena != nullptr); FI_ void farena_init(FArena_R arena, Slice mem) { assert(arena != nullptr);
@@ -118,22 +122,37 @@ FI_ void farena_init(FArena_R arena, Slice mem) { assert(arena != nullptr);
arena->used = 0; arena->used = 0;
} }
FI_ FArena farena_make(Slice mem) { FArena a; farena_init(& a, mem); return a; } FI_ FArena farena_make(Slice mem) { FArena a; farena_init(& a, mem); return a; }
I_ Slice farena_push(FArena_R arena, U8 amount, Opt_farena o) { FI_ Slice farena_push(FArena_R arena, U8 amount, Opt_farena o) { Slice res;
if (amount == 0) { return (Slice){}; } mem_push_aligned_typed(arena->start, arena->capacity, & arena->used, amount, o.alignment, o.type_width
U8 desired = amount * (o.type_width == 0 ? 1 : o.type_width); , & res.ptr, & res.len);
U8 to_commit = align_pow2(desired, o.alignment ? o.alignment : MEM_ALIGNMENT_DEFAULT); return res;
U8 ptr = arena->start + arena->used;
mem_bump_u8(arena->start, arena->capacity, & arena->used, to_commit);
return (Slice){ ptr, to_commit };
} }
FI_ void farena_reset (FArena_R arena) { arena->used = 0; } FI_ void farena_reset (FArena_R arena) { arena->used = 0; }
FI_ void farena_rewind(FArena_R arena, U4 save_point) { FI_ void farena_rewind(FArena_R arena, U8 save_point) {
U8 end = arena->start + arena->used; assert_bounds(save_point, arena->start, end); assert(save_point <= arena->used);
arena->used -= save_point - arena->start; arena->used = save_point;
} }
FI_ U8 farena_save(FArena arena) { return arena.used; } FI_ U8 farena_save(FArena arena) { return arena.used; }
#define farena_push_(arena, amount, ...) farena_push((arena), (amount), opt_(farena, __VA_ARGS__)) #define farena_push_(arena, amount, ...) farena_push((arena),(amount),opt_(farena,__VA_ARGS__))
#define farena_push_type(arena, type, ...) C_(type*, farena_push((arena), 1, opt_(farena, .type_width=S_(type), __VA_ARGS__)).ptr) #define farena_push_type(arena, type, ...) C_(type*,farena_push((arena),1, opt_(farena,.type_width=S_(type),__VA_ARGS__)).ptr)
#define farena_push_array(arena, type, amount, ...) (tmpl(Slice,type)){ C_(type*, farena_push((arena), (amount), opt_(farena, .type_width=S_(type), __VA_ARGS__)).ptr), (amount) } #define farena_push_array(arena, type, amount, ...) (tmpl(Slice,type)){ C_(type*,farena_push((arena),(amount),opt_(farena,.type_width=S_(type),__VA_ARGS__)).ptr),(amount) }
#pragma endregion FArena #pragma endregion FArena
#pragma region FStack
#define FStack_(name, type, width) Struct_(name) { U8 top; type arr[width]; }
FI_ Slice fstack_push(Slice mem, U8_R top, U8 amount, Opt_farena o) { Slice res;
mem_push_aligned_typed(mem.ptr, mem.len, top, amount, o.alignment, o.type_width
, & res.ptr, & res.len);
return res;
};
// This is here more for annotation than anything else.
#define fstack_save(stack) stack.top
#define fstack_rewind(stack, sp) do{stack.top = sp;}while(0)
#define fstack_reset(stack) do{stack.top = 0; }while(0)
#define fstack_slice(stack) slice_ut_arr((stack).arr)
#define fstack_push_(stk, amount, ...) fstack_push(fstack_slice(stk),&(stk).top,(amount),opt_(farena,__VA_ARGS__))
#define fstack_push_array(stk, type, amount, ...) (tmpl(Slice,type)){ C_(type*,fstack_push(fstack_slice(stk),&(stk).top,(amount),opt_(farena,.type_width=S_(type),__VA_ARGS__)).ptr),(amount) }
#pragma endregion FStack
+19 -4
View File
@@ -1,14 +1,14 @@
#ifdef INTELLISENSE_DIRECTIVES #ifdef INTELLISENSE_DIRECTIVES
# pragma once # pragma once
# include "dsl.h" # include "dsl.h"
# include "asm.h"
# include "memory.h" # include "memory.h"
# include "hashing.h" # include "hashing.h"
# include "analysis.h" # include "analysis.h"
#endif #endif
#pragma region Key Table Linear (KTL) #pragma region Key Table Linear (KTL)
enum { KT_Slot_value = S_(U8), };
enum { KT_SLot_value = S_(U8), };
#define KTL_Slot_(type) Struct_(tmpl(KTL_Slot,type)) { \ #define KTL_Slot_(type) Struct_(tmpl(KTL_Slot,type)) { \
U8 key; \ U8 key; \
type value; \ type value; \
@@ -34,7 +34,22 @@ FI_ void ktl_populate_slice_a2_str8(KTL_Str8* kt, Slice_A2_Str8 values) {
mem_copy(u8_(& kt->ptr[id].value), u8_(& values.ptr[id][1]), S_(Str8)); mem_copy(u8_(& kt->ptr[id].value), u8_(& values.ptr[id][1]), S_(Str8));
} }
} }
#define ktl_str8_key(str) hash64_fnv1a_ret(slice_to_ut(str8(str)), 0) #define ktl_str8_key(str) hash64_fnv1a_ret(slice_to_ut(slit8(str)), 0)
#define ktl_str8_from_arr(arr) (KTL_Str8){arr, array_len(arr)} #define ktl_str8_from_arr(arr) (KTL_Str8){arr, Array_len(arr)}
FI_ Str8_R ktl_str8_find(KTL_Str8 table, U8 key) {
U8 i = 0;
while (table.len - i >= 4) {
KTL_Slot_Str8_R p = table.ptr + i;
U4 mask = find_aos_keys_mask_u8x4(& p[0].key, & p[1].key, & p[2].key, & p[3].key, key);
if (mask) return & table.ptr[i + C_(U8, count_trailing_zeros_u4(mask))].value;
i += 4;
}
while (i < table.len) {
if (table.ptr[i].key == key) return & table.ptr[i].value;
++ i;
}
assert(false);
return nullptr;
}
#pragma endregion KTL #pragma endregion KTL
+59 -61
View File
@@ -6,6 +6,7 @@
# include "hashing.h" # include "hashing.h"
# include "tables.h" # include "tables.h"
# include "analysis.h" # include "analysis.h"
# include "asm.h"
#endif #endif
// NOTE(rjf): Includes reverses for uppercase and lowercase hex. // NOTE(rjf): Includes reverses for uppercase and lowercase hex.
@@ -20,6 +21,7 @@ RO_ U8 integer_symbol_reverse[128] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
}; };
FI_ B4 char_is_space(UTF8 c) { return(c == ' ' || c == '\n' || c == '\t' || c == '\r' || c == '\f' || c == '\v'); }
FI_ B4 char_is_upper(UTF8 c) { return('A' <= c && c <= 'Z'); } FI_ B4 char_is_upper(UTF8 c) { return('A' <= c && c <= 'Z'); }
FI_ UTF8 char_to_lower(UTF8 c) { if (char_is_upper(c)) { c += ('a' - 'A'); } return(c); } FI_ UTF8 char_to_lower(UTF8 c) { if (char_is_upper(c)) { c += ('a' - 'A'); } return(c); }
FI_ B4 char_is_digit(UTF8 c, U4 base) { FI_ B4 char_is_digit(UTF8 c, U4 base) {
@@ -122,8 +124,8 @@ I_ Str8 str8_from_u4_buf(Slice buf, U4 num, U4 radix, U4 min_digits, U4 digit_gr
/*Fill Prefix*/ if (info.prefix.len > 0) { slice_copy(result, info.prefix); } /*Fill Prefix*/ if (info.prefix.len > 0) { slice_copy(result, info.prefix); }
return result; return result;
} }
I_ Str8 str8_fmt_ktl_buf(Slice buffer, KTL_Str8 table, Str8 fmt_template)
{ I_ Str8 str8_fmt_ktl_buf(Slice buffer, KTL_Str8 table, Str8 fmt_template){
slice_assert(buffer); slice_assert(buffer);
slice_assert(table); slice_assert(table);
slice_assert(fmt_template); slice_assert(fmt_template);
@@ -131,73 +133,46 @@ I_ Str8 str8_fmt_ktl_buf(Slice buffer, KTL_Str8 table, Str8 fmt_template)
U8 buffer_remaining = buffer.len; U8 buffer_remaining = buffer.len;
UTF8_R cursor_fmt = fmt_template.ptr; UTF8_R cursor_fmt = fmt_template.ptr;
U8 left_fmt = fmt_template.len; U8 left_fmt = fmt_template.len;
U1x16 needle_lt = splat_u4_u1x16(u4_byte_fill('<'));
U1x16 needle_gt = splat_u4_u1x16(u4_byte_fill('>'));
while (left_fmt && buffer_remaining) while (left_fmt && buffer_remaining)
{ {
// Forward until we hit the delimiter '<' or the template's contents are exhausted. // Forward until we hit the delimiter '<' or the template's contents are exhausted.
U8 copy_offset = 0; U8 copy_offset = 0;
if (cursor_fmt[0] == '<') if (cursor_fmt[0] == '<') {
{ UTF8_R sig = cursor_fmt + 1;
UTF8_R potential_token_cursor = cursor_fmt + 1; // Skip '<' U8 sig_max = slice_end(fmt_template) - sig;
U8 potential_token_len = 0; U8 sig_len = find_u1_via_u1x16(sig, sig_max, '>', needle_gt);
B4 fmt_overflow = false; assert(sig_len < sig_max);
while(true) {
UTF8_R cursor = potential_token_cursor + potential_token_len; Str8_R value = ktl_str8_find(table, hash64_fnv1a_ret(slice_ut(sig, sig_len), 0));
fmt_overflow = cursor >= slice_end(fmt_template); U8 n = min(buffer_remaining, value->len);
B4 found_terminator = potential_token_cursor[potential_token_len] == '>'; assert((buffer_remaining - n) > 0); mem_copy(u8_(cursor_buffer), u8_(value->ptr), n);
if (fmt_overflow || found_terminator) { break; } cursor_buffer += n;
++ potential_token_len; buffer_remaining -= n;
} cursor_fmt = sig + sig_len + 1;
if (fmt_overflow) { left_fmt -= sig_len + 2;
// Failed to find a subst and we're at end of fmt, just copy segment. continue;
copy_offset = 1 + potential_token_len; // '<' + token
goto write_to_buffer;
}
// Hashing the potential token and cross checking it with our token table
U8 key = hash64_fnv1a_ret(slice_ut(u8_(potential_token_cursor), potential_token_len), 0);
Str8_R value = nullptr; for slice_iter(table, token) {
// We do a linear iteration instead of a hash table lookup because the user should never subst with more than 100 unqiue tokens..
if (token->key == key) { value = & token->value; break; }
}
if (value)
{
// We're going to appending the string, make sure we have enough space in our buffer.
// NOTE(Ed): this version doesn't support growing the buffer (No Allocator Interface)
assert((buffer_remaining - potential_token_len) > 0);
copy_offset = min(buffer_remaining, value->len); // Prevent Buffer overflow.
mem_copy(u8_(cursor_buffer), u8_(value->ptr), buffer_remaining);
// Sync cursor format to after the processed token
cursor_buffer += copy_offset;
buffer_remaining -= copy_offset;
cursor_fmt = potential_token_cursor + 1 + potential_token_len; // '<' + token
left_fmt -= potential_token_len + 2; // The 2 here are the '<' & '>' delimiters being omitted.
continue;
}
// If not a subsitution, we copy the segment and continue.
copy_offset = 1 + potential_token_len; // '<' + token
goto write_to_buffer;
} }
else do { U8 n = find_u1_via_u1x16(cursor_fmt, min(left_fmt, buffer_remaining), '<', needle_lt);
++ copy_offset; assert((buffer_remaining - 1) > 0); n = min(buffer_remaining, n);
} mem_copy(u8_(cursor_buffer), u8_(cursor_fmt), n);
while ( (cursor_fmt[copy_offset] != '<' && (cursor_fmt + copy_offset) < slice_end(fmt_template)) ); cursor_buffer += n;
write_to_buffer: cursor_fmt += n;
assert((buffer_remaining - copy_offset) > 0); buffer_remaining -= n;
copy_offset = min(buffer_remaining, copy_offset); // Prevent buffer overflow. left_fmt -= n;
mem_copy(u8_(cursor_buffer), u8_(cursor_fmt), copy_offset);
buffer_remaining -= copy_offset;
left_fmt -= copy_offset;
cursor_buffer += copy_offset;
cursor_fmt += copy_offset;
} }
return (Str8){C_(UTF8*, buffer.ptr), buffer.len - buffer_remaining}; return str8(C_(UTF8*,buffer.ptr), buffer.len - buffer_remaining);
} }
typedef Struct_(Str8Gen) { UTF8* ptr; U8 cap, len; }; typedef Struct_(Str8Gen) { UTF8* ptr; U8 cap, len; };
FI_ Str8Gen str8gen_make(Slice s) { return (Str8Gen){C_(UTF8*,s.ptr), s.len, 0}; }
FI_ Slice str8gen_buf(Str8Gen_R gen) { return (Slice){u8_(gen->ptr) + gen->len, gen->cap - gen->len}; } FI_ Slice str8gen_buf(Str8Gen_R gen) { return (Slice){u8_(gen->ptr) + gen->len, gen->cap - gen->len}; }
FI_ void str8gen_append_str8(Str8Gen_R gen, Str8 str) { assert(gen != nullptr); FI_ void str8gen_append_str8(Str8Gen_R gen, Str8 str) { assert(gen != nullptr);
mem_bump_u8(u8_(gen->ptr), gen->cap, & gen->len, str.len);
U8 ptr = u8_(gen->ptr) + gen->len; U8 ptr = u8_(gen->ptr) + gen->len;
mem_bump_u8(u8_(gen->ptr), gen->cap, & gen->len, str.len);
mem_copy(ptr, u8_(str.ptr), str.len); mem_copy(ptr, u8_(str.ptr), str.len);
} }
FI_ void str8gen_append_fmt(Str8Gen_R gen, Str8 fmt, KTL_Str8 tbl) { FI_ void str8gen_append_fmt(Str8Gen_R gen, Str8 fmt, KTL_Str8 tbl) {
@@ -216,19 +191,42 @@ typedef Str16 Slice_UTF16;
internal Str16 internal Str16
str16_from_8(FArena* arena, Str8 in) { str16_from_8(FArena* arena, Str8 in) {
Str16 result = {0}; if (in.len) { Str16 result = {0}; if (in.len) {
U8 cap = in.len * 2; U8 pre_pos = farena_save(arena[0]);
Slice_U2 str = farena_push_array(arena, U2, cap + 1); U8 cap = in.len * 2;
Slice_U2 str = farena_push_array(arena, U2, cap + 1);
U1* ptr = in.ptr; U1* ptr = in.ptr;
U1* opl = ptr + in.len; U1* opl = ptr + in.len;
U8 size = 0; U8 size = 0;
UnicodeDecode consume; UnicodeDecode consume;
for(;ptr < opl; ptr += consume.inc) for(;ptr < opl; ptr += consume.inc) {
{
consume = utf8_decode(ptr, opl - ptr); consume = utf8_decode(ptr, opl - ptr);
size += utf16_encode(str.ptr + size, consume.codepoint); size += utf16_encode(str.ptr + size, consume.codepoint);
} }
str.ptr[size] = 0; farena_rewind(arena, (cap - size) * 2); str.ptr[size] = 0;
U8 committed = align_pow2((size + 1) * S_(U2), MEM_ALIGNMENT_DEFAULT);
farena_rewind(arena, pre_pos + committed);
result = str16(C_(UTF16*, str.ptr), size); result = str16(C_(UTF16*, str.ptr), size);
} }
return result; return result;
} }
// Formatter where serial operation is done on-demand per-entry.
// enum {
// KTL_Str8FmtEntry_InlaidSize = (S_(Str8) * 2) - S_(Str8Fmt_TokenKind),
// };
// typedef Enum_(U4, Str8Fmt_SerialOpKind) {
// Str8Fmt_TKind_Str8,
// Str8Fmt_Base16_U1,
// Str8Fmt_Base16_U2,
// Str8Fmt_Base10_U4,
// };
// typedef Struct_(KTL_Str8Fmt_SerialOp_Entry) {
// union {
// U1 InlaidData[KTL_Str8FmtEntry_InlaidSize];
// Str8 str;
// void* Ptr;
// };
// Str8Fmt_SerialOpKind kind;
// };
// typedef KTL_Slot_(KTL_Str8Fmt_SerialOp_Entry);
+22 -3
View File
@@ -2,6 +2,7 @@
# pragma once # pragma once
# include "dsl.h" # include "dsl.h"
# include "memory.h" # include "memory.h"
# include "files.h"
#endif #endif
WinAPI void ms_exit_process(U4 uExitCode) asm("ExitProcess"); // Kernel 32 WinAPI void ms_exit_process(U4 uExitCode) asm("ExitProcess"); // Kernel 32
@@ -245,7 +246,7 @@ w32_date_time_from_system_time(DateTime* out, MS_SYSTEMTIME* in) {
I_ void I_ void
w32_dense_time_from_file_time(DenseTime* out, MS_FILETIME* in) { w32_dense_time_from_file_time(DenseTime* out, MS_FILETIME* in) {
MS_SYSTEMTIME systime = {0}; ms_filetime_to_systemtime(in, &systime); DateTime date_time = {0}; MS_SYSTEMTIME systime = {0}; ms_filetime_to_systemtime(in, &systime); DateTime date_time = {0};
w32_date_time_from_system_time(&date_time, &systime); *out = dense_time_from_date_time(date_time); w32_date_time_from_system_time(&date_time, &systime); out[0] = dense_time_from_date_time(date_time);
} }
I_ FilePropertyFlags I_ FilePropertyFlags
@@ -270,8 +271,9 @@ properties_from_file(File file) {
internal File internal File
file_open(FArena* scratch, AccessFlags flags, Str8 path) { file_open(FArena* scratch, AccessFlags flags, Str8 path) {
File result = {0}; File result = {0};
Str16 path16 = str16_from_8(scratch, path); U8 scratch_at = farena_save(scratch[0]);
Str16 path16 = str16_from_8(scratch, path);
U4 access_flags = 0; U4 access_flags = 0;
U4 share_mode = 0; U4 share_mode = 0;
U4 creation_disposition = MS_OPEN_EXISTING; U4 creation_disposition = MS_OPEN_EXISTING;
@@ -289,6 +291,7 @@ file_open(FArena* scratch, AccessFlags flags, Str8 path) {
else { else {
U4 err = ms_get_last_error(); (void)err; U4 err = ms_get_last_error(); (void)err;
} }
farena_rewind(scratch, scratch_at);
return result; return result;
} }
@@ -313,4 +316,20 @@ internal U8 file_read(File file, R1_U8 rng, U1* out_data) {
} }
U8 total_read_size = off - rng.p0; return total_read_size; U8 total_read_size = off - rng.p0; return total_read_size;
} }
internal U8 file_write(File file, R1_U8 rng, U1* data) {
if (file_match(file, file_zero())) { return 0; }
MS_Handle* handle = C_(MS_Handle*,file.ptr[0]);
U1 const* ptr = data;
U8 off = rng.p0; while (off != rng.p1) {
U8 amt64 = rng.p1 - off;
U4 amt32 = C_(U4, min(mega(32), amt64));
U4 write_size = 0;
MS_OVERLAPPED overlapped = { .Offset = C_(U4,off), .OffsetHigh = C_(U4,off >> 32) };
if ( ! ms_write_file(handle, ptr, amt32, & write_size, & overlapped) || write_size == 0) { break; }
ptr += write_size;
off += write_size;
}
return off - rng.p0;
}
#endif #endif
+48 -9
View File
@@ -1,4 +1,5 @@
#include "duffle/dsl.h" #include "duffle/dsl.h"
#include "duffle/asm.h"
#include "duffle/analysis.h" #include "duffle/analysis.h"
#include "duffle/math.h" #include "duffle/math.h"
#include "duffle/memory.h" #include "duffle/memory.h"
@@ -10,6 +11,19 @@
#include "duffle/win32.h" #include "duffle/win32.h"
#include "8086/encoder.h"
#include "8086/encoder_table.h"
#include "8086/info.h"
#include "8086/decoder.h"
#include "8086/serializer.h"
#include "8086/serializer_tables.h"
#include "8086/gen/decoder_table.h"
#include "8086/decoder.c"
#include "8086/serializer.c"
// #include "8086/decoder.h"
typedef Struct_(U2_HL) { U1 Low; U1 High; }; typedef Struct_(U2_HL) { U1 Low; U1 High; };
#define bitmask_(pos) (1 << pos) #define bitmask_(pos) (1 << pos)
@@ -45,7 +59,6 @@ FI_ void a8utf8_from_u1_be(UTF8 out[8], U1 value) {
I_ U4 binary_as_str8_eval_len(Slice_U1 data) { return data.len * 8; } I_ U4 binary_as_str8_eval_len(Slice_U1 data) { return data.len * 8; }
#define jump_lt(a,b,label) if (a < b) goto label
I_ Str8 binary_as_str8(Slice_U1 data, FArena* str8_mem) { Str8 result = {0}; I_ Str8 binary_as_str8(Slice_U1 data, FArena* str8_mem) { Str8 result = {0};
U4 req_len = data.len * 8; jump_lt(str8_mem->capacity,req_len, jret); U4 req_len = data.len * 8; jump_lt(str8_mem->capacity,req_len, jret);
@@ -54,25 +67,24 @@ I_ Str8 binary_as_str8(Slice_U1 data, FArena* str8_mem) { Str8 result = {0};
jret: return result; jret: return result;
} }
typedef Enum_(U4, x86_Op) {
x86_mov
};
enum { enum {
Scratchpad_Len = kilo(1), Scratchpad_Len = kilo(16),
FileRam_Len = kilo(16), FileRam_Len = kilo(16),
}; };
typedef Struct_(SMemory) { typedef Struct_(SMemory) {
U1 Scratchpad [Scratchpad_Len]; U1 Scratchpad [Scratchpad_Len];
U1 FileRam [FileRam_Len]; U1 FileRam [FileRam_Len];
U1 decode_mem[kilo(64)];
UTF8 text_mem [kilo(16)];
}; };
global SMemory smem; global SMemory smem;
#define path_course_content "./course_content/perfaware/" #define path_course_content "./course_content/perfaware/"
#define path_part1 path_course_content "part1/" #define path_part1 path_course_content "part1/"
CLANG_OPTIMIZE_DISABLE typedef Slice_(X8616_DecodedInstruction);
int main() int main()
{ {
FArena scratch = farena_make(slice_ut_arr(smem.Scratchpad)); FArena scratch = farena_make(slice_ut_arr(smem.Scratchpad));
@@ -81,8 +93,35 @@ int main()
Str8 path_listing_0037_single_register_mov = slit8(path_part1 "listing_0037_single_register_mov"); Str8 path_listing_0037_single_register_mov = slit8(path_part1 "listing_0037_single_register_mov");
Str8 path_listing_0037_single_register_mov_asm = slit8(path_part1 "listing_0037_single_register_mov.asm"); Str8 path_listing_0037_single_register_mov_asm = slit8(path_part1 "listing_0037_single_register_mov.asm");
Slice_U1 data = data_from_file_path(& file_arena, path_listing_0037_single_register_mov, & scratch); Slice_U1 data = data_from_file_path(& file_arena, path_listing_0037_single_register_mov, & scratch);
farena_reset(& scratch);
FArena decode_arena = farena_make(slice_ut_arr(smem.decode_mem));
Slice_X8616_DecodedInstruction decoded = farena_push_array(& decode_arena, X8616_DecodedInstruction, data.len);
X8616_DecodeInfo info = x8616_decode_(
.source = data.ptr,
.source_len = data.len,
.out_instructions = decoded.ptr,
.instruction_cap = decoded.len,
.info_arena = & decode_arena,
);
if (info.source_consumed != data.len || info.instruction_count == 0 || info.msgs.error_count || info.msgs.dropped_count) {
ms_exit_process(10);
return 10;
}
X8616_SerializeInfo text = x8616_serialize_instructions((X8616_SerializeRequest){
.instructions = decoded.ptr,
.instruction_count = info.instruction_count,
.output = slice_ut_arr(smem.text_mem),
.scratch = slice_ut_arr(smem.Scratchpad),
.info_arena = & decode_arena,
.msgs = & info.msgs,
});
if (text.msgs.error_count || text.msgs.dropped_count || text.instructions_written != info.instruction_count) {
ms_exit_process(13);
return 13;
}
ms_exit_process(0); ms_exit_process(0);
return 0; return 0;
} }
CLANG_OPTIMIZE_ENABLE
+7 -2
View File
@@ -3,7 +3,12 @@
target: target:
{ {
executable: "build/sim_8086.exe" executable: "build/sim_8086.exe"
working_directory: "" working_directory: "../perfaware"
enabled: 1
label: "Sim 8086" label: "Sim 8086"
enabled: 1
}
target:
{
executable: "build/decoder_table_generator.meta.exe"
working_directory: "../perfaware"
} }
+184 -138
View File
@@ -18,6 +18,7 @@ if ((test-path $path_build) -eq $false) {
$compiler = "clang" $compiler = "clang"
$linker = 'lld-link.exe' $linker = 'lld-link.exe'
$objcopy = 'llvm-objcopy' $objcopy = 'llvm-objcopy'
$objdump = 'llvm-objdump'
$archiver = 'llvm-ar' $archiver = 'llvm-ar'
# --- Compiler Flags: General / Compilation Mode --- # --- Compiler Flags: General / Compilation Mode ---
@@ -59,23 +60,23 @@ $f_charset_utf8 = '-utf-8' # Source charset = UTF-8
# --- Compiler Flags: Warnings --- # --- Compiler Flags: Warnings ---
# https://clang.llvm.org/docs/DiagnosticsReference.html # https://clang.llvm.org/docs/DiagnosticsReference.html
$f_wall = '-Wall' $f_wall = '-Wall'
$f_wextra = '-Wextra' $f_wextra = '-Wextra'
$f_werror = '-Werror' $f_werror = '-Werror'
$f_warnings_as_errors = '-Werror' $f_warnings_as_errors = '-Werror'
$f_wno_attributes = '-Wno-attributes' $f_wno_attributes = '-Wno-attributes'
$f_warnings_ignore = '-Wno-' # Prefix; usage: $f_warnings_ignore + 'unused' $f_warnings_ignore = '-Wno-' # Prefix; usage: $f_warnings_ignore + 'unused'
$f_wno_unused_function = '-Wno-unused-function' $f_wno_unused_function = '-Wno-unused-function'
$f_wno_unused_variable = '-Wno-unused-variable' $f_wno_unused_variable = '-Wno-unused-variable'
$f_wno_switch = '-Wno-switch' $f_wno_switch = '-Wno-switch'
$f_wno_uninitialized = '-Wno-uninitialized' $f_wno_uninitialized = '-Wno-uninitialized'
$f_wno_implicit_function_declaration = '-Wno-implicit-function-declaration' $f_wno_implicit_function_declaration = '-Wno-implicit-function-declaration'
$f_wno_ms_include = '-Wno-microsoft-include' $f_wno_ms_include = '-Wno-microsoft-include'
$f_wno_return_type_c_linkage = '-Wno-return-type-c-linkage' $f_wno_return_type_c_linkage = '-Wno-return-type-c-linkage'
$f_wno_main_return_type = '-Wno-main-return-type' $f_wno_main_return_type = '-Wno-main-return-type'
$f_warning = '-W' # Prefix; usage: $f_warning + 'switch' $f_warning = '-W' # Prefix; usage: $f_warning + 'switch'
$f_pedantic = '-Wpedantic' $f_pedantic = '-Wpedantic'
$f_doc_warnings = '-Wdocumentation' $f_doc_warnings = '-Wdocumentation'
# --- Compiler Flags: Optimization --- # --- Compiler Flags: Optimization ---
$f_optimize_none = '-O0' # No optimization (debug default) $f_optimize_none = '-O0' # No optimization (debug default)
@@ -91,48 +92,49 @@ $f_lto = '-flto' # Link-time optimization
$f_lto_thin = '-flto=thin' $f_lto_thin = '-flto=thin'
# --- Compiler Flags: Debug / Profile --- # --- Compiler Flags: Debug / Profile ---
$f_debug = '-g' # Debug info (default DWARF) $f_debug = '-g' # Debug info (default DWARF)
$f_debug_codeview = '-gcodeview' # CodeView debug format (MS tools) $f_debug_codeview = '-gcodeview' # CodeView debug format (MS tools)
$f_debug_dwarf_4 = '-gdwarf-4' # Specific DWARF version $f_debug_dwarf_4 = '-gdwarf-4' # Specific DWARF version
$f_debug_dwarf_5 = '-gdwarf-5' $f_debug_dwarf_5 = '-gdwarf-5'
$f_debug_line_tables_only = '-gline-tables-only' $f_debug_line_tables_only = '-gline-tables-only'
$f_profiling_debug = '-fdebug-info-for-profiling' $f_profiling_debug = '-fdebug-info-for-profiling'
$f_time_trace = '-ftime-trace' # Emit Chrome trace JSON $f_time_trace = '-ftime-trace' # Emit Chrome trace JSON
$f_coverage_generate = '-fprofile-instr-generate' $f_coverage_generate = '-fprofile-instr-generate'
$f_coverage_use = '-fprofile-instr-use=' $f_coverage_use = '-fprofile-instr-use='
# --- Compiler Flags: Code Generation --- # --- Compiler Flags: Code Generation ---
$f_no_color_diagnostics = '-fno-color-diagnostics' $f_no_color_diagnostics = '-fno-color-diagnostics'
$f_color_diagnostics = '-fcolor-diagnostics' $f_color_diagnostics = '-fcolor-diagnostics'
$f_diagnostics_absolute = '-fdiagnostics-absolute-paths' $f_diagnostics_absolute = '-fdiagnostics-absolute-paths'
$f_exceptions_disabled = '-fno-exceptions' $f_exceptions_disabled = '-fno-exceptions'
$f_exceptions_enabled = '-fexceptions' $f_exceptions_enabled = '-fexceptions'
$f_RTTI_disabled = '-fno-rtti' $f_RTTI_disabled = '-fno-rtti'
$f_RTTI_enabled = '-frtti' $f_RTTI_enabled = '-frtti'
$f_section_data = '-fdata-sections' $f_section_data = '-fdata-sections'
$f_section_functions = '-ffunction-sections' $f_section_functions = '-ffunction-sections'
$f_no_strict_alias = '-fno-strict-aliasing' $f_no_strict_alias = '-fno-strict-aliasing'
$f_strict_aliasing = '-fstrict-aliasing' $f_strict_aliasing = '-fstrict-aliasing'
$f_signed_char = '-fsigned-char' $f_signed_char = '-fsigned-char'
$f_unsigned_char = '-funsigned-char' $f_unsigned_char = '-funsigned-char'
$f_pic = '-fPIC' # Position-independent code $f_pic = '-fPIC' # Position-independent code
$f_pie = '-fPIE' # Position-independent executable $f_pie = '-fPIE' # Position-independent executable
$f_no_pic = '-fno-pic' $f_no_pic = '-fno-pic'
$f_no_pie = '-fno-pie' $f_no_pie = '-fno-pie'
$f_visible_hidden = '-fvisibility=hidden' $f_visible_hidden = '-fvisibility=hidden'
$f_visible_default = '-fvisibility=default' $f_visible_default = '-fvisibility=default'
$f_align_functions = '-falign-functions=' $f_align_functions = '-falign-functions='
$f_align_loops = '-falign-loops=' $f_align_loops = '-falign-loops='
$f_ms_extensions = '-fms-extensions' # Allow MSVC language extensions $f_ms_extensions = '-fms-extensions' # Allow MSVC language extensions
$f_ms_compatibility = '-fms-compatibility' $f_ms_compatibility = '-fms-compatibility'
$f_ms_runtime_lib_none = '-fno-ms-runtime' $f_ms_runtime_lib_none = '-fno-ms-runtime'
$f_preprocess_non_integrated = '-no-integrated-cpp' $f_preprocess_non_integrated = '-no-integrated-cpp'
$f_stack_protector = '-fstack-protector' $f_stack_probes_disabled = '-mno-stack-arg-probe' # Requires the fully committed stack in link-modules
$f_stack_protector_strong = '-fstack-protector-strong' $f_stack_protector = '-fstack-protector'
$f_stack_protector_all = '-fstack-protector-all' $f_stack_protector_strong = '-fstack-protector-strong'
$f_vptr = '-fvirtual-function-elimination' $f_stack_protector_all = '-fstack-protector-all'
$f_vectorize = '-vectorize-loops' $f_vptr = '-fvirtual-function-elimination'
$f_vectorize_slp = '-vectorize-slp' $f_vectorize = '-vectorize-loops'
$f_vectorize_slp = '-vectorize-slp'
# --- Compiler Flags: Sanitizers --- # --- Compiler Flags: Sanitizers ---
$f_sanitize_address = '-fsanitize=address' $f_sanitize_address = '-fsanitize=address'
@@ -143,6 +145,9 @@ $f_sanitize_hwaddress = '-fsanitize=hwaddress'
$f_sanitize_address_safe = '-fsanitize=address,safe-stack' $f_sanitize_address_safe = '-fsanitize=address,safe-stack'
$f_sanitize_cfi = '-fsanitize=cfi' $f_sanitize_cfi = '-fsanitize=cfi'
# --- Compiler Flags: Hardware Architecture ---
$f_arch_haswell = '-march=haswell'
# --- Compiler Flags: Environment / Target --- # --- Compiler Flags: Environment / Target ---
$f_no_stdlib = '-nostdlib' $f_no_stdlib = '-nostdlib'
$f_freestanding = '-ffreestanding' $f_freestanding = '-ffreestanding'
@@ -163,24 +168,6 @@ $f_verbose = '-v'
$f_set_stack_size = '-stack=' # Stack size (linker-side, but accepted by clang) $f_set_stack_size = '-stack=' # Stack size (linker-side, but accepted by clang)
$f_symbol_prefix = '-femit-all-decls' $f_symbol_prefix = '-femit-all-decls'
# --- Compiler Flags: MIPS Architecture (catalog parity with ps1/build_psyq.ps1) ---
# Used by the PS1 cross-compile path (C:\projects\Pikuma\ps1). Not used by
# the current Win32 build. Kept here so the catalog is complete.
$f_arch_mips1 = '-march=mips1'
$f_arch_mips2 = '-march=mips2'
$f_arch_mips3 = '-march=mips3'
$f_arch_abi32 = '-mabi=32'
$f_arch_abi64 = '-mabi=64'
$f_arch_little_endian = '-EL'
$f_arch_big_endian = '-EB'
$f_arch_fp32 = '-mfp32'
$f_arch_no_pic = '-fno-pic'
$f_arch_no_shared = '-mno-shared'
$f_arch_no_abicalls = '-mno-abicalls'
$f_arch_no_llsc = '-mno-llsc'
$f_arch_no_gpopt = '-mno-gpopt'
$f_arch_no_stack_prot = '-fno-stack-protector'
# --- Linker Flags (passed via -Wl, to clang; or directly to gcc-style linkers) --- # --- Linker Flags (passed via -Wl, to clang; or directly to gcc-style linkers) ---
# These are GNU ld-style flags. When invoking lld-link.exe directly, prefer # These are GNU ld-style flags. When invoking lld-link.exe directly, prefer
# the Win32-flavored flags below. # the Win32-flavored flags below.
@@ -207,72 +194,82 @@ $f_link_no_as_needed = '--no-as-needed'
# --- Linker Flags (Win32 lld-link, used directly) --- # --- Linker Flags (Win32 lld-link, used directly) ---
# https://lld.llvm.org/windows_support.html # https://lld.llvm.org/windows_support.html
$f_nologo = '/NOLOGO' $f_nologo = '/NOLOGO'
$f_link_win_no_incremental = '/INCREMENTAL:NO' $f_link_win_no_incremental = '/INCREMENTAL:NO'
$f_link_win_no_default_lib = '/NODEFAULTLIB' $f_link_win_no_default_lib = '/NODEFAULTLIB'
$f_link_win_subsystem_console = '/SUBSYSTEM:CONSOLE' $f_link_win_subsystem_console = '/SUBSYSTEM:CONSOLE'
$f_link_win_subsystem_windows = '/SUBSYSTEM:WINDOWS' $f_link_win_subsystem_windows = '/SUBSYSTEM:WINDOWS'
$f_link_win_subsystem_efi_app = '/SUBSYSTEM:EFI_APPLICATION' $f_link_win_subsystem_efi_app = '/SUBSYSTEM:EFI_APPLICATION'
$f_link_win_subsystem_native = '/SUBSYSTEM:NATIVE' $f_link_win_subsystem_native = '/SUBSYSTEM:NATIVE'
$f_link_win_machine_32 = '/MACHINE:X86' $f_link_win_machine_32 = '/MACHINE:X86'
$f_link_win_machine_64 = '/MACHINE:X64' $f_link_win_machine_64 = '/MACHINE:X64'
$f_link_win_machine_arm = '/MACHINE:ARM' $f_link_win_machine_arm = '/MACHINE:ARM'
$f_link_win_machine_arm64 = '/MACHINE:ARM64' $f_link_win_machine_arm64 = '/MACHINE:ARM64'
$f_link_win_debug = '/DEBUG' $f_link_win_debug = '/DEBUG'
$f_link_win_pdb = '/PDB:' $f_link_win_pdb = '/PDB:'
$f_link_win_path_output = '/OUT:' $f_link_win_path_output = '/OUT:'
$f_link_win_map = '/MAP:' $f_link_win_map = '/MAP:'
$f_link_win_entry = '/ENTRY:' $f_link_win_entry = '/ENTRY:'
$f_link_win_lib_path = '/LIBPATH:' $f_link_win_lib_path = '/LIBPATH:'
$f_link_win_default_lib = '/DEFAULTLIB:' $f_link_win_default_lib = '/DEFAULTLIB:'
$f_link_win_dll = '/DLL' $f_link_win_dll = '/DLL'
$f_link_win_optimize_ref = '/OPT:REF' # Eliminate unreferenced data/functions $f_link_win_optimize_ref = '/OPT:REF' # Eliminate unreferenced data/functions
$f_link_win_optimize_no_icf = '/OPT:NOICF' # Disable identical COMDAT folding $f_link_win_optimize_no_icf = '/OPT:NOICF' # Disable identical COMDAT folding
$f_link_win_optimize_no_ref = '/OPT:NOREF' # Disable dead-strip $f_link_win_optimize_no_ref = '/OPT:NOREF' # Disable dead-strip
$f_link_win_stack = '/STACK:' $f_link_win_stack = '/STACK:'
$f_link_win_heap = '/HEAP:' $f_link_win_heap = '/HEAP:'
$f_link_win_merge = '/MERGE:' $f_link_win_merge = '/MERGE:'
$f_link_win_align = '/ALIGN:' $f_link_win_align = '/ALIGN:'
$f_link_win_base = '/BASE:' $f_link_win_base = '/BASE:'
$f_link_win_version = '/VERSION:' $f_link_win_version = '/VERSION:'
$f_link_win_dynamic_base = '/DYNAMICBASE' $f_link_win_dynamic_base = '/DYNAMICBASE'
$f_link_win_release = '/RELEASE' $f_link_win_release = '/RELEASE'
$f_link_win_force = '/FORCE' $f_link_win_force = '/FORCE'
$f_link_win_verbose = '/VERBOSE' $f_link_win_verbose = '/VERBOSE'
$f_link_win_wholearchive = '/WHOLEARCHIVE:' $f_link_win_wholearchive = '/WHOLEARCHIVE:'
$f_link_win_export = '/EXPORT:' $f_link_win_export = '/EXPORT:'
$f_link_win_delay_load = '/DELAYLOAD:' $f_link_win_delay_load = '/DELAYLOAD:'
$f_link_win_import = '/IMPORT:' $f_link_win_import = '/IMPORT:'
$f_link_win_def = '/DEF:' $f_link_win_def = '/DEF:'
$f_link_win_manifest = '/MANIFEST' $f_link_win_manifest = '/MANIFEST'
$f_link_win_manifest_no = '/MANIFEST:NO' $f_link_win_manifest_no = '/MANIFEST:NO'
$f_link_win_manifest_uac = '/MANIFESTUAC:' $f_link_win_manifest_uac = '/MANIFESTUAC:'
$f_link_win_manifest_input = '/MANIFESTINPUT:' $f_link_win_manifest_input = '/MANIFESTINPUT:'
$f_link_win_section = '/SECTION:' $f_link_win_section = '/SECTION:'
$f_link_win_swaprun = '/SWAPRUN' $f_link_win_swaprun = '/SWAPRUN'
$f_link_win_driver = '/DRIVER' $f_link_win_driver = '/DRIVER'
$f_link_win_large_address_aware = '/LARGEADDRESSAWARE' $f_link_win_large_address_aware = '/LARGEADDRESSAWARE'
$f_link_win_fail_if_mismatch = '/FAILIFMISMATCH' $f_link_win_fail_if_mismatch = '/FAILIFMISMATCH'
$f_link_win_through = '/THREADOPT' $f_link_win_through = '/THREADOPT'
$f_link_win_error_report = '/ERRORREPORT' $f_link_win_error_report = '/ERRORREPORT'
$f_link_win_repro = '/BREPRO' $f_link_win_repro = '/BREPRO'
$f_link_win_safeseh = '/SAFESEH' $f_link_win_safeseh = '/SAFESEH'
$f_link_win_guard_cf = '/GUARD:CF' $f_link_win_guard_cf = '/GUARD:CF'
$f_link_win_guard_no_cf = '/GUARD:NOCF' $f_link_win_guard_no_cf = '/GUARD:NOCF'
$f_link_win_pgo_run = '/USEPROFILE' $f_link_win_pgo_run = '/USEPROFILE'
$f_link_win_pgo_gen = '/PROFILE' $f_link_win_pgo_gen = '/PROFILE'
$f_link_win_idl = '/IDLOUT:' $f_link_win_idl = '/IDLOUT:'
$f_link_win_delay_unload = '/DELAY:UNLOAD' $f_link_win_delay_unload = '/DELAY:UNLOAD'
$f_link_win_compat_property = '/CETCOMPAT' $f_link_win_compat_property = '/CETCOMPAT'
$f_link_win_debug_fastlink = '/DEBUG:FASTLINK' $f_link_win_debug_fastlink = '/DEBUG:FASTLINK'
$f_link_win_lib_list = '/LIB' $f_link_win_lib_list = '/LIB'
# --- Objcopy Flags --- # --- Objcopy Flags ---
$f_objcopy_format = '-O' # Output format $f_objcopy_format = '-O' # Output format
$f_objcopy_add_section = '--add-section' $f_objcopy_add_section = '--add-section'
$f_objcopy_update_section = '--update-section' $f_objcopy_update_section = '--update-section'
$f_objcopy_set_section_flags = '--set-section-flags' $f_objcopy_set_section_flags = '--set-section-flags'
# --- Objdump Flags ---
$f_objdump_disassemble = '-d' # Disassemble all executable sections
$f_objdump_machine = '-M' # Usage: $f_objdump_machine + 'intel'
$f_objdump_source_lines = '-l' # Interleave source lines (requires -g)
$f_objdump_no_raw_insn = '--no-show-raw-insn' # Omit hex bytes
$f_objdump_reloc = '-r' # Inline relocations
$f_objdump_symbols = '--disassemble-symbols=' # Usage: $f_objdump_symbols + 'main'
$f_objdump_headers = '-x' # All headers + sections (verbose)
$f_objdump_section_contents = '-s' # Raw section contents (hex dump)
# --- Baseline Libraries (lld-link, Win32) --- # --- Baseline Libraries (lld-link, Win32) ---
$libraries_win32 = @( $libraries_win32 = @(
'kernel32.lib' 'kernel32.lib'
@@ -283,8 +280,7 @@ $libraries_win32 = @(
# --- Functions --- # --- Functions ---
function compile-unit { function compile-unit { param(
param(
[string] $unit, [string] $unit,
[string] $link_module, [string] $link_module,
[string[]] $include_paths, [string[]] $include_paths,
@@ -293,10 +289,12 @@ function compile-unit {
$compile_args = @() $compile_args = @()
$compile_args += $f_std_c11 $compile_args += $f_std_c11
$compile_args += $f_all_c $compile_args += $f_all_c
$compile_args += $f_arch_haswell
$compile_args += $f_ms_ex $compile_args += $f_ms_ex
$compile_args += $f_wall $compile_args += $f_wall
$compile_args += $f_wno_attributes $compile_args += $f_wno_attributes
$compile_args += $f_exceptions_disabled $compile_args += $f_exceptions_disabled
$compile_args += $f_stack_probes_disabled
$compile_args += $f_diagnostics_absolute $compile_args += $f_diagnostics_absolute
$compile_args += $f_debug $compile_args += $f_debug
foreach ($p in $include_paths) { foreach ($p in $include_paths) {
@@ -313,8 +311,7 @@ function compile-unit {
if ($LASTEXITCODE -ne 0) { write-error "Compilation failed for $unit. Aborting."; exit 1 } if ($LASTEXITCODE -ne 0) { write-error "Compilation failed for $unit. Aborting."; exit 1 }
} }
function link-modules { function link-modules { param(
param(
[string[]] $link_modules, [string[]] $link_modules,
[string] $module, [string] $module,
[string] $pdb, [string] $pdb,
@@ -330,6 +327,7 @@ function link-modules {
$link_args += $f_link_win_no_incremental $link_args += $f_link_win_no_incremental
$link_args += ($f_link_win_path_output + $module) $link_args += ($f_link_win_path_output + $module)
$link_args += $f_link_win_subsystem_console $link_args += $f_link_win_subsystem_console
$link_args += ($f_link_win_stack + '262144,262144') # 256 KiB reserved
$link_args += $f_link_win_debug $link_args += $f_link_win_debug
$link_args += ($f_link_win_entry + 'main') $link_args += ($f_link_win_entry + 'main')
$link_args += ($f_link_win_pdb + $pdb) $link_args += ($f_link_win_pdb + $pdb)
@@ -348,6 +346,53 @@ function link-modules {
if ($LASTEXITCODE -ne 0) { write-error "Linking failed. Aborting."; exit 1 } if ($LASTEXITCODE -ne 0) { write-error "Linking failed. Aborting."; exit 1 }
} }
function dump-disassembly { param([string] $obj, [string] $exe)
$base = [System.IO.Path]::GetFileNameWithoutExtension($exe)
$asm_obj = join-path $path_build "$base.obj.asm"
$asm_exe = join-path $path_build "$base.exe.asm"
$objdump_args = @()
$objdump_args += $f_objdump_disassemble
$objdump_args += ($f_objdump_machine + 'intel')
$objdump_args += $f_objdump_source_lines
$objdump_args += $f_objdump_no_raw_insn
write-host "Dumping object disassembly -> '$asm_obj'" -ForegroundColor DarkCyan
$time_to_objdump = Measure-Command { & $objdump $objdump_args $obj | Out-File -FilePath $asm_obj -Encoding utf8 }
write-host "Object disassembly took $($time_to_objdump.TotalMilliseconds)ms"
if ($LASTEXITCODE -ne 0) { write-error "objdump failed for $obj. Aborting."; exit 1 }
write-host "Dumping executable disassembly -> '$asm_exe'" -ForegroundColor DarkCyan
$time_to_objdump = Measure-Command { & $objdump $objdump_args $exe | Out-File -FilePath $asm_exe -Encoding utf8 }
write-host "Executable disassembly took $($time_to_objdump.TotalMilliseconds)ms"
if ($LASTEXITCODE -ne 0) { write-error "objdump failed for $exe. Aborting."; exit 1 }
}
function build-8086_decoder_table {
$includes = @(
$path_code
)
$source_c = join-path $path_8086 'decoder_table_generator.meta.c'
$module_c = join-path $path_build 'decoder_table_generator.meta.o'
$compile_args = @()
$compile_args += $f_debug
$compile_args += $f_optimize_none
# $compile_args += $f_optimize_size
$compile_args += ($f_define + 'BUILD_DEBUG=1')
compile-unit $source_c $module_c $includes $compile_args
$pdb = join-path $path_build 'decoder_table_generator.meta.pdb'
$exe = join-path $path_build 'decoder_table_generator.meta.exe'
link-modules $module_c $exe $pdb @()
dump-disassembly $module_c $exe
}
# build-8086_decoder_table
function build-part_1 { function build-part_1 {
# The base lib uses subdir-prefixed includes (e.g. "duffle/dsl.h"), # The base lib uses subdir-prefixed includes (e.g. "duffle/dsl.h"),
# so the include root is <code>, not <code>/duffle. # so the include root is <code>, not <code>/duffle.
@@ -370,6 +415,7 @@ function build-part_1 {
$exe = join-path $path_build 'sim_8086.exe' $exe = join-path $path_build 'sim_8086.exe'
link-modules $module_c $exe $pdb @() link-modules $module_c $exe $pdb @()
}
dump-disassembly $module_c $exe
}
build-part_1 build-part_1