diff --git a/code/8086/decoder.c b/code/8086/decoder.c index c46450e..bc59ad9 100644 --- a/code/8086/decoder.c +++ b/code/8086/decoder.c @@ -449,6 +449,9 @@ x8616_decode_one_plex(X8616_DecodePlex* plex) 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; diff --git a/code/8086/decoder.h b/code/8086/decoder.h index 8a60e96..2dfeb81 100644 --- a/code/8086/decoder.h +++ b/code/8086/decoder.h @@ -74,6 +74,9 @@ typedef Struct_(X8616_DecodedInstruction) { X8616_ALU alu; X8616_Condition cc; B1 has_mod_rm; + U1 header; + U1 mod_rm; + U1 post_opcode; U1 size; U1 size_required; }; diff --git a/code/8086/encode.c b/code/8086/encode.c new file mode 100644 index 0000000..8d47e88 --- /dev/null +++ b/code/8086/encode.c @@ -0,0 +1,110 @@ +#ifdef INTELLISENSE_DIRECTIVES +# include "encode.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* buf, U1_R n, U1 value) { buf[n[0]] = value; n[0] += 1; } +FI_ void x8616_encode_buf_u2(U1* buf, U1_R n, U2 value) { + x8616_encode_buf_u1(buf, n, u1_(value)); + x8616_encode_buf_u1(buf, n, u1_(value >> 8)); +} +FI_ void x8616_encode_buf_disp(U1* buf, U1_R n, S2 value, U1 bytes) { + if (bytes == 1) x8616_encode_buf_u1(buf, n, u1_(value)); + if (bytes == 2) x8616_encode_buf_u2(buf, n, u2_(value)); +} + +internal X8616_EncodeStatus +x8616_encode_instruction(Str8Gen_R gen, X8616_DecodedInstruction_R inst) +{ + B4 bad = inst->decode_flags & (x8616_decode_invalid | x8616_decode_truncated); + bad |= inst->size == 0; + if (bad) return x8616_encode_invalid_record; + U1 buf[16]; + U1 n = 0; + U1 rep = inst->prefixes.repeat == x8616_rep ? x8616_rep_prefix() : x8616_repne_prefix(); + if (inst->prefixes.lock) { x8616_encode_buf_u1(buf, & n, x8616_lock_prefix()); } + if (inst->prefixes.has_repeat) { x8616_encode_buf_u1(buf, & n, rep); } + if (inst->prefixes.has_segment) { x8616_encode_buf_u1(buf, & n, x8616_segment_prefix(inst->prefixes.segment)); } + x8616_encode_buf_u1(buf, & n, inst->header); + if (inst->post_opcode) { x8616_encode_buf_u1(buf, & n, inst->post_opcode); } + if (inst->has_mod_rm) { x8616_encode_buf_u1(buf, & n, inst->mod_rm); } + + for (U1 id = 0; id < inst->operand_count; ++id) { + X8616_DecodedOperand_R op = inst->operands + id; + if ((op->flags & x8616_decoded_operand_memory) == 0) continue; + if ( op->flags & x8616_decoded_operand_direct) x8616_encode_buf_u2(buf, & n, op->address); + else x8616_encode_buf_disp(buf, & n, op->displacement, op->displacement_bytes); + } + for (U1 id = 0; id < inst->operand_count; ++id) { + X8616_DecodedOperand_R op = inst->operands + id; + 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; +} diff --git a/code/8086/encode.h b/code/8086/encode.h new file mode 100644 index 0000000..a1b255a --- /dev/null +++ b/code/8086/encode.h @@ -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); diff --git a/code/8086/info.h b/code/8086/info.h index 97a899b..77d0523 100644 --- a/code/8086/info.h +++ b/code/8086/info.h @@ -38,6 +38,10 @@ typedef Enum_(U1, X8616_InfoCode) { 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, }; @@ -78,6 +82,9 @@ RO_ global Str8 x8616_info_templates[x8616_info_count] = { [x8616_info_parse_output_full] = slit8("Parse output is full: capacity , produced ."), [x8616_info_parse_invalid_record] = slit8("Parse record at is not a valid instruction (op )."), [x8616_info_parse_unsupported_form] = slit8("Parse record at has an unsupported form (op )."), + [x8616_info_encode_bad_request] = slit8("Encode request is missing instructions, output, or info arena."), + [x8616_info_encode_invalid_record] = slit8("Encode record is invalid or truncated (op )."), + [x8616_info_encode_output_full] = slit8("Encode output is full at record : capacity , produced ."), }; typedef Struct_(X8616_InfoList) { @@ -120,3 +127,15 @@ FI_ void x8616_info_push(FArena_R scratch 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); +} diff --git a/code/8086/info_render.h b/code/8086/info_render.h deleted file mode 100644 index 46ed196..0000000 --- a/code/8086/info_render.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifdef INTELLISENSE_DIRECTIVES -# pragma once -# include "duffle/tables.h" -# include "duffle/text.h" -# include "info.h" -#endif - -typedef Struct_(X8616_InfoTextValues) { Str8 offset; Str8 expected; Str8 actual; }; - -FI_ Str8 -x8616_info_render(Slice output, X8616_InfoMsg_R msg, X8616_InfoTextValues values) { - KTL_Slot_Str8 slots[] = { - { ktl_str8_key("offset"), values.offset }, - { ktl_str8_key("expected"), values.expected }, - { ktl_str8_key("actual"), values.actual }, - }; - return str8_fmt_ktl_buf(output, ktl_str8_from_arr(slots), msg->text); -} diff --git a/code/part_1/sim_8086.c b/code/part_1/sim_8086.c index 475c908..c0f7fb4 100644 --- a/code/part_1/sim_8086.c +++ b/code/part_1/sim_8086.c @@ -14,7 +14,6 @@ #include "8086/encoder.h" #include "8086/encoder_table.h" #include "8086/info.h" -#include "8086/info_render.h" #include "8086/decoder.h" #include "8086/serializer.h" #include "8086/serializer_tables.h"