diff --git a/part1/listing_0037_single_register_mov.asm b/part1/listing_0037_single_register_mov.asm index a20862f..1b58e05 100644 --- a/part1/listing_0037_single_register_mov.asm +++ b/part1/listing_0037_single_register_mov.asm @@ -8,7 +8,7 @@ ; ; Please see https://computerenhance.com for further information ; -; ======================================================================== */ +; ======================================================================== ; ======================================================================== ; LISTING 37 diff --git a/part1/listing_0038_many_register_mov.asm b/part1/listing_0038_many_register_mov.asm index 7431c2f..c157b91 100644 --- a/part1/listing_0038_many_register_mov.asm +++ b/part1/listing_0038_many_register_mov.asm @@ -8,7 +8,7 @@ ; ; Please see https://computerenhance.com for further information ; -; ======================================================================== */ +; ======================================================================== ; ======================================================================== ; LISTING 38 diff --git a/part1/listing_0039_more_movs b/part1/listing_0039_more_movs index 7536cd8..405b804 100644 Binary files a/part1/listing_0039_more_movs and b/part1/listing_0039_more_movs differ diff --git a/part1/listing_0039_more_movs.asm b/part1/listing_0039_more_movs.asm index 4a667e2..854fcb4 100644 --- a/part1/listing_0039_more_movs.asm +++ b/part1/listing_0039_more_movs.asm @@ -21,10 +21,12 @@ mov si, bx mov dh, al ; 8-bit immediate-to-register -mov cx, 12 -mov cx, -12 +mov cl, 12 +mov ch, -12 ; 16-bit immediate-to-register +mov cx, 12 +mov cx, -12 mov dx, 3948 mov dx, -3948 diff --git a/part1/listing_0041_add_sub_cmp_jnz b/part1/listing_0041_add_sub_cmp_jnz new file mode 100644 index 0000000..6c71f1b Binary files /dev/null and b/part1/listing_0041_add_sub_cmp_jnz differ diff --git a/part1/listing_0041_add_sub_cmp_jnz.asm b/part1/listing_0041_add_sub_cmp_jnz.asm new file mode 100644 index 0000000..6b79cf0 --- /dev/null +++ b/part1/listing_0041_add_sub_cmp_jnz.asm @@ -0,0 +1,121 @@ +; ======================================================================== +; +; (C) Copyright 2023 by Molly Rocket, Inc., All Rights Reserved. +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any damages +; arising from the use of this software. +; +; Please see https://computerenhance.com for further information +; +; ======================================================================== + +; ======================================================================== +; LISTING 41 +; ======================================================================== + +bits 16 + +add bx, [bx+si] +add bx, [bp] +add si, 2 +add bp, 2 +add cx, 8 +add bx, [bp + 0] +add cx, [bx + 2] +add bh, [bp + si + 4] +add di, [bp + di + 6] +add [bx+si], bx +add [bp], bx +add [bp + 0], bx +add [bx + 2], cx +add [bp + si + 4], bh +add [bp + di + 6], di +add byte [bx], 34 +add word [bp + si + 1000], 29 +add ax, [bp] +add al, [bx + si] +add ax, bx +add al, ah +add ax, 1000 +add al, -30 +add al, 9 + +sub bx, [bx+si] +sub bx, [bp] +sub si, 2 +sub bp, 2 +sub cx, 8 +sub bx, [bp + 0] +sub cx, [bx + 2] +sub bh, [bp + si + 4] +sub di, [bp + di + 6] +sub [bx+si], bx +sub [bp], bx +sub [bp + 0], bx +sub [bx + 2], cx +sub [bp + si + 4], bh +sub [bp + di + 6], di +sub byte [bx], 34 +sub word [bx + di], 29 +sub ax, [bp] +sub al, [bx + si] +sub ax, bx +sub al, ah +sub ax, 1000 +sub al, -30 +sub al, 9 + +cmp bx, [bx+si] +cmp bx, [bp] +cmp si, 2 +cmp bp, 2 +cmp cx, 8 +cmp bx, [bp + 0] +cmp cx, [bx + 2] +cmp bh, [bp + si + 4] +cmp di, [bp + di + 6] +cmp [bx+si], bx +cmp [bp], bx +cmp [bp + 0], bx +cmp [bx + 2], cx +cmp [bp + si + 4], bh +cmp [bp + di + 6], di +cmp byte [bx], 34 +cmp word [4834], 29 +cmp ax, [bp] +cmp al, [bx + si] +cmp ax, bx +cmp al, ah +cmp ax, 1000 +cmp al, -30 +cmp al, 9 + +test_label0: +jnz test_label1 +jnz test_label0 +test_label1: +jnz test_label0 +jnz test_label1 + +label: +je label +jl label +jle label +jb label +jbe label +jp label +jo label +js label +jne label +jnl label +jg label +jnb label +ja label +jnp label +jno label +jns label +loop label +loopz label +loopnz label +jcxz label diff --git a/part1/listing_0042_completionist_decode b/part1/listing_0042_completionist_decode new file mode 100644 index 0000000..c200467 Binary files /dev/null and b/part1/listing_0042_completionist_decode differ diff --git a/part1/listing_0042_completionist_decode.asm b/part1/listing_0042_completionist_decode.asm new file mode 100644 index 0000000..894bdf8 --- /dev/null +++ b/part1/listing_0042_completionist_decode.asm @@ -0,0 +1,425 @@ +; ======================================================================== +; +; (C) Copyright 2023 by Molly Rocket, Inc., All Rights Reserved. +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any damages +; arising from the use of this software. +; +; Please see https://computerenhance.com for further information +; +; ======================================================================== + +; ======================================================================== +; LISTING 42 +; ======================================================================== + +; +; NOTE(casey): This is not meant to be a real compliance test for 8086 +; disassemblers. It's just a reasonable selection of opcodes and patterns +; to use as a first pass in making sure a disassembler handles a large +; cross-section of the encoding. To be absolutely certain you haven't +; missed something, you would need a more exhaustive listing! +; + +bits 16 + +mov si, bx +mov dh, al +mov cl, 12 +mov ch, -12 +mov cx, 12 +mov cx, -12 +mov dx, 3948 +mov dx, -3948 +mov al, [bx + si] +mov bx, [bp + di] +mov dx, [bp] +mov ah, [bx + si + 4] +mov al, [bx + si + 4999] +mov [bx + di], cx +mov [bp + si], cl +mov [bp], ch +mov ax, [bx + di - 37] +mov [si - 300], cx +mov dx, [bx - 32] +mov [bp + di], byte 7 +mov [di + 901], word 347 +mov bp, [5] +mov bx, [3458] +mov ax, [2555] +mov ax, [16] +mov [2554], ax +mov [15], ax + +push word [bp + si] +push word [3000] +push word [bx + di - 30] +push cx +push ax +push dx +push cs + +pop word [bp + si] +pop word [3] +pop word [bx + di - 3000] +pop sp +pop di +pop si +pop ds + +xchg ax, [bp - 1000] +xchg [bx + 50], bp + +xchg ax, ax +xchg ax, dx +xchg ax, sp +xchg ax, si +xchg ax, di + +xchg cx, dx +xchg si, cx +xchg cl, ah + +in al, 200 +in al, dx +in ax, dx + +out 44, ax +out dx, al + +xlat +lea ax, [bx + di + 1420] +lea bx, [bp - 50] +lea sp, [bp - 1003] +lea di, [bx + si - 7] + +lds ax, [bx + di + 1420] +lds bx, [bp - 50] +lds sp, [bp - 1003] +lds di, [bx + si - 7] + +les ax, [bx + di + 1420] +les bx, [bp - 50] +les sp, [bp - 1003] +les di, [bx + si - 7] + +lahf +sahf +pushf +popf + +add cx, [bp] +add dx, [bx + si] +add [bp + di + 5000], ah +add [bx], al +add sp, 392 +add si, 5 +add ax, 1000 +add ah, 30 +add al, 9 +add cx, bx +add ch, al + +adc cx, [bp] +adc dx, [bx + si] +adc [bp + di + 5000], ah +adc [bx], al +adc sp, 392 +adc si, 5 +adc ax, 1000 +adc ah, 30 +adc al, 9 +adc cx, bx +adc ch, al + +inc ax +inc cx +inc dh +inc al +inc ah +inc sp +inc di +inc byte [bp + 1002] +inc word [bx + 39] +inc byte [bx + si + 5] +inc word [bp + di - 10044] +inc word [9349] +inc byte [bp] + +aaa +daa + +sub cx, [bp] +sub dx, [bx + si] +sub [bp + di + 5000], ah +sub [bx], al +sub sp, 392 +sub si, 5 +sub ax, 1000 +sub ah, 30 +sub al, 9 +sub cx, bx +sub ch, al + +sbb cx, [bp] +sbb dx, [bx + si] +sbb [bp + di + 5000], ah +sbb [bx], al +sbb sp, 392 +sbb si, 5 +sbb ax, 1000 +sbb ah, 30 +sbb al, 9 +sbb cx, bx +sbb ch, al + +dec ax +dec cx +dec dh +dec al +dec ah +dec sp +dec di +dec byte [bp + 1002] +dec word [bx + 39] +dec byte [bx + si + 5] +dec word [bp + di - 10044] +dec word [9349] +dec byte [bp] + +neg ax +neg cx +neg dh +neg al +neg ah +neg sp +neg di +neg byte [bp + 1002] +neg word [bx + 39] +neg byte [bx + si + 5] +neg word [bp + di - 10044] +neg word [9349] +neg byte [bp] + +cmp bx, cx +cmp dh, [bp + 390] +cmp [bp + 2], si +cmp bl, 20 +cmp byte [bx], 34 +cmp ax, 23909 + +aas +das + +mul al +mul cx +mul word [bp] +mul byte [bx + di + 500] + +imul ch +imul dx +imul byte [bx] +imul word [9483] + +aam + +div bl +div sp +div byte [bx + si + 2990] +div word [bp + di + 1000] + +idiv ax +idiv si +idiv byte [bp + si] +idiv word [bx + 493] + +aad +cbw +cwd + +not ah +not bl +not sp +not si +not word [bp] +not byte [bp + 9905] + +shl ah, 1 +shr ax, 1 +sar bx, 1 +rol cx, 1 +ror dh, 1 +rcl sp, 1 +rcr bp, 1 + +shl word [bp + 5], 1 +shr byte [bx + si - 199], 1 +sar byte [bx + di - 300], 1 +rol word [bp], 1 +ror word [4938], 1 +rcl byte [3], 1 +rcr word [bx], 1 + +shl ah, cl +shr ax, cl +sar bx, cl +rol cx, cl +ror dh, cl +rcl sp, cl +rcr bp, cl + +shl word [bp + 5], cl +shr word [bx + si - 199], cl +sar byte [bx + di - 300], cl +rol byte [bp], cl +ror byte [4938], cl +rcl byte [3], cl +rcr word [bx], cl + +and al, ah +and ch, cl +and bp, si +and di, sp +and al, 93 +and ax, 20392 +and [bp + si + 10], ch +and [bx + di + 1000], dx +and bx, [bp] +and cx, [4384] +and byte [bp - 39], 239 +and word [bx + si - 4332], 10328 + +test bx, cx +test dh, [bp + 390] +test [bp + 2], si +test bl, 20 +test byte [bx], 34 +test ax, 23909 + +or al, ah +or ch, cl +or bp, si +or di, sp +or al, 93 +or ax, 20392 +or [bp + si + 10], ch +or [bx + di + 1000], dx +or bx, [bp] +or cx, [4384] +or byte [bp - 39], 239 +or word [bx + si - 4332], 10328 + +xor al, ah +xor ch, cl +xor bp, si +xor di, sp +xor al, 93 +xor ax, 20392 +xor [bp + si + 10], ch +xor [bx + di + 1000], dx +xor bx, [bp] +xor cx, [4384] +xor byte [bp - 39], 239 +xor word [bx + si - 4332], 10328 + +rep movsb +rep cmpsb +rep scasb +rep lodsb +rep movsw +rep cmpsw +rep scasw +rep lodsw + +; NOTE(casey): Special thanks (as always!) to Mārtiņš Možeiko for figuring out why NASM +; wouldn't compile "rep stds" instructions. It was because it was a misprint in the 8086 +; manual! It was really just "rep stos", which of course is still in x64, and NASM +; assembles it just fine. +rep stosb +rep stosw + +call [39201] +call [bp - 100] +call sp +call ax + +jmp ax +jmp di +jmp [12] +jmp [4395] + +ret -7 +ret 500 +ret + +label: +je label +jl label +jle label +jb label +jbe label +jp label +jo label +js label +jne label +jnl label +jg label +jnb label +ja label +jnp label +jno label +jns label +loop label +loopz label +loopnz label +jcxz label + +int 13 +int 3 + +into +iret + +clc +cmc +stc +cld +std +cli +sti +hlt +wait + +lock not byte [bp + 9905] +lock xchg [100], al + +mov al, cs:[bx + si] +mov bx, ds:[bp + di] +mov dx, es:[bp] +mov ah, ss:[bx + si + 4] + +and ss:[bp + si + 10], ch +or ds:[bx + di + 1000], dx +xor bx, es:[bp] +cmp cx, es:[4384] +test byte cs:[bp - 39], 239 +sbb word cs:[bx + si - 4332], 10328 + +lock not byte CS:[bp + 9905] + +; +; TODO(casey): I would like to uncomment this, but as far as I can tell, NASM doesn't recognize the ESC instruction :( +; so even if I just force the assembler to output the bits here, our disasm will fail to assemble because it will (correctly!) +; print the esc instruction and NASM will error because it doesn't know what that is. +; +; esc 938,ax +; + +; +; TODO(casey): According to NASM, "rep movsb" is "not lockable". However the 8086 manual seems to think it is, and +; even describes what happens when you you lock a rep: the lock is held for the duration of the rep operation. So... +; yeah. Not sure why this doesn't work in NASM: +; +; lock rep movsb +; \ No newline at end of file diff --git a/part1/sim8086.c b/part1/sim8086.c index c4011d5..8467c31 100644 --- a/part1/sim8086.c +++ b/part1/sim8086.c @@ -76,6 +76,9 @@ typedef enum S86_InstructionType { S86_InstructionType_MOVAccumToMem, S86_InstructionType_MOVRegOrMemToSegReg, S86_InstructionType_MOVSegRegToRegOrMem, + S86_InstructionType_ADDRegOrMemToOrFromReg, + S86_InstructionType_ADDImmediateToRegOrMem, + S86_InstructionType_ADDImmediateToAccum, S86_InstructionType_Count, } S86_InstructionType; @@ -128,6 +131,21 @@ S86_Instruction const S86_INSTRUCTIONS[S86_InstructionType_Count] = { .op_bits0 = 0b1000'1100, .op_mask1 = 0b0010'0000, .op_bits1 = 0b0000'0000}, + + [S86_InstructionType_ADDRegOrMemToOrFromReg] = {.op_mask0 = 0b1111'1100, + .op_bits0 = 0b0000'0000, + .op_mask1 = 0b0000'0000, + .op_bits1 = 0b0000'0000}, + + [S86_InstructionType_ADDImmediateToRegOrMem] = {.op_mask0 = 0b1111'1100, + .op_bits0 = 0b1000'0000, + .op_mask1 = 0b0011'1000, + .op_bits1 = 0b0000'0000}, + + [S86_InstructionType_ADDImmediateToAccum] = {.op_mask0 = 0b1111'1110, + .op_bits0 = 0b0000'0100, + .op_mask1 = 0b0000'0000, + .op_bits1 = 0b0000'0000}, }; typedef struct S86_EffectiveAddressStr8 { @@ -135,7 +153,7 @@ typedef struct S86_EffectiveAddressStr8 { size_t size; } S86_EffectiveAddressStr8; -S86_EffectiveAddressStr8 S86_EffectiveAddressCalc(S86_BufferIterator *buffer_it, uint8_t rm, uint8_t mod); +S86_EffectiveAddressStr8 S86_EffectiveAddressCalc(S86_BufferIterator *buffer_it, uint8_t rm, uint8_t mod, uint8_t w); // NOTE: Implementation // ============================================================================ @@ -282,7 +300,8 @@ void S86_PrintLnFmt(char const *fmt, ...) va_end(args); } -S86_EffectiveAddressStr8 S86_EffectiveAddressCalc(S86_BufferIterator *buffer_it, uint8_t rm, uint8_t mod) +S86_Str8 REGISTER_FIELD_ENCODING[2][8]; +S86_EffectiveAddressStr8 S86_EffectiveAddressCalc(S86_BufferIterator *buffer_it, uint8_t rm, uint8_t mod, uint8_t w) { // NOTE: Calculate displacement // ========================================================================= @@ -295,43 +314,49 @@ S86_EffectiveAddressStr8 S86_EffectiveAddressCalc(S86_BufferIterator *buffer_it, } else if (mod == 0b01) { // Mem mode 8 bit displacement displacement = (int8_t)S86_BufferIteratorNextByte(buffer_it); } else { - S86_ASSERT(mod == 0b00 /*Mem mode (no displacement)*/); + S86_ASSERT(mod == 0b00 || mod == 0b11 /*Mem mode (no displacement)*/); } - // NOTE: Effective address calculation w/ displacement - // ========================================================================= S86_EffectiveAddressStr8 result = {0}; - result.data[result.size++] = '['; - if (direct_address) { - result.size += snprintf(result.data + result.size, - sizeof(result.data) - result.size, - "%s%d", - displacement >= 0 ? "" : "-", displacement >= 0 ? displacement : -displacement); + if (mod == 0b11) { + S86_Str8 register_field = REGISTER_FIELD_ENCODING[w][rm]; + memcpy(result.data, register_field.data, register_field.size); + result.size = register_field.size; } else { - S86_Str8 base_calc = {0}; - switch (rm) { - case 0b000: base_calc = S86_STR8("bx + si"); break; - case 0b001: base_calc = S86_STR8("bx + di"); break; - case 0b010: base_calc = S86_STR8("bp + si"); break; - case 0b011: base_calc = S86_STR8("bp + di"); break; - case 0b100: base_calc = S86_STR8("si"); break; - case 0b101: base_calc = S86_STR8("di"); break; - case 0b110: base_calc = S86_STR8("bp"); break; - case 0b111: base_calc = S86_STR8("bx"); break; - default: S86_ASSERT(!"Invalid rm value, must be 3 bits"); break; - } - - memcpy(result.data + result.size, base_calc.data, base_calc.size); - result.size += S86_CAST(int)base_calc.size; - - if ((mod == 0b01 || mod == 0b10) && displacement) { + // NOTE: Effective address calculation w/ displacement + // ========================================================================= + result.data[result.size++] = '['; + if (direct_address) { result.size += snprintf(result.data + result.size, sizeof(result.data) - result.size, - " %c %d", - displacement >= 0 ? '+' : '-', displacement >= 0 ? displacement : -displacement); + "%s%d", + displacement >= 0 ? "" : "-", displacement >= 0 ? displacement : -displacement); + } else { + S86_Str8 base_calc = {0}; + switch (rm) { + case 0b000: base_calc = S86_STR8("bx + si"); break; + case 0b001: base_calc = S86_STR8("bx + di"); break; + case 0b010: base_calc = S86_STR8("bp + si"); break; + case 0b011: base_calc = S86_STR8("bp + di"); break; + case 0b100: base_calc = S86_STR8("si"); break; + case 0b101: base_calc = S86_STR8("di"); break; + case 0b110: base_calc = S86_STR8("bp"); break; + case 0b111: base_calc = S86_STR8("bx"); break; + default: S86_ASSERT(!"Invalid rm value, must be 3 bits"); break; + } + + memcpy(result.data + result.size, base_calc.data, base_calc.size); + result.size += S86_CAST(int)base_calc.size; + + if ((mod == 0b01 || mod == 0b10) && displacement) { + result.size += snprintf(result.data + result.size, + sizeof(result.data) - result.size, + " %c %d", + displacement >= 0 ? '+' : '-', displacement >= 0 ? displacement : -displacement); + } } + result.data[result.size++] = ']'; } - result.data[result.size++] = ']'; S86_ASSERT(result.size < S86_ARRAY_UCOUNT(result.data)); return result; @@ -356,30 +381,23 @@ int main(int argc, char **argv) // NOTE: Sim8086 // ========================================================================= // Mapping from a 'reg' encoding to the register name. - S86_Str8 const REGISTER_FIELD_ENCODING[2][8] = { - [0b0] = - { - S86_STR8("al"), - S86_STR8("cl"), - S86_STR8("dl"), - S86_STR8("bl"), - S86_STR8("ah"), - S86_STR8("ch"), - S86_STR8("dh"), - S86_STR8("bh"), - }, - [0b1] = - { - S86_STR8("ax"), - S86_STR8("cx"), - S86_STR8("dx"), - S86_STR8("bx"), - S86_STR8("sp"), - S86_STR8("bp"), - S86_STR8("si"), - S86_STR8("di"), - }, - }; + REGISTER_FIELD_ENCODING[0b0][0] = S86_STR8("al"); + REGISTER_FIELD_ENCODING[0b0][1] = S86_STR8("cl"); + REGISTER_FIELD_ENCODING[0b0][2] = S86_STR8("dl"); + REGISTER_FIELD_ENCODING[0b0][3] = S86_STR8("bl"); + REGISTER_FIELD_ENCODING[0b0][4] = S86_STR8("ah"); + REGISTER_FIELD_ENCODING[0b0][5] = S86_STR8("ch"); + REGISTER_FIELD_ENCODING[0b0][6] = S86_STR8("dh"); + REGISTER_FIELD_ENCODING[0b0][7] = S86_STR8("bh"); + + REGISTER_FIELD_ENCODING[0b1][0] = S86_STR8("ax"); + REGISTER_FIELD_ENCODING[0b1][1] = S86_STR8("cx"); + REGISTER_FIELD_ENCODING[0b1][2] = S86_STR8("dx"); + REGISTER_FIELD_ENCODING[0b1][3] = S86_STR8("bx"); + REGISTER_FIELD_ENCODING[0b1][4] = S86_STR8("sp"); + REGISTER_FIELD_ENCODING[0b1][5] = S86_STR8("bp"); + REGISTER_FIELD_ENCODING[0b1][6] = S86_STR8("si"); + REGISTER_FIELD_ENCODING[0b1][7] = S86_STR8("di"); // NOTE: Decode assembly // ========================================================================= @@ -430,6 +448,7 @@ int main(int argc, char **argv) switch (instruction_type) { + case S86_InstructionType_ADDRegOrMemToOrFromReg: /*FALLTHRU*/ case S86_InstructionType_MOVRegOrMemToOrFromReg: { // NOTE: Instruction does not have opcode bits in the 2nd byte S86_ASSERT(op_code_size == 1); @@ -446,55 +465,90 @@ int main(int argc, char **argv) S86_ASSERT(reg < 8); S86_ASSERT(rm < 8); + S86_Str8 op = {0}; + if (instruction_type == S86_InstructionType_MOVRegOrMemToOrFromReg) { + op = S86_STR8("mov"); + } else { + op = S86_STR8("add"); + S86_ASSERT(instruction_type == S86_InstructionType_ADDRegOrMemToOrFromReg); + } + if (mod == 0b11) { // NOTE: Register-to-register move // ========================================================= S86_Str8 src_op = REGISTER_FIELD_ENCODING[w][d ? rm : reg]; S86_Str8 dest_op = REGISTER_FIELD_ENCODING[w][d ? reg : rm]; - S86_PrintLnFmt("mov %.*s, %.*s", S86_STR8_FMT(dest_op), S86_STR8_FMT(src_op)); + S86_PrintLnFmt("%.*s %.*s, %.*s", S86_STR8_FMT(op), S86_STR8_FMT(dest_op), S86_STR8_FMT(src_op)); } else { // NOTE: Memory mode w/ effective address calculation // ========================================================= - S86_EffectiveAddressStr8 effective_address = S86_EffectiveAddressCalc(&buffer_it, rm, mod); + S86_EffectiveAddressStr8 effective_address = S86_EffectiveAddressCalc(&buffer_it, rm, mod, w); S86_Str8 addr = { .data = effective_address.data, .size = effective_address.size }; S86_Str8 dest_op = d ? REGISTER_FIELD_ENCODING[w][reg] : addr; S86_Str8 src_op = d ? addr : REGISTER_FIELD_ENCODING[w][reg]; - S86_PrintLnFmt("mov %.*s, %.*s", S86_STR8_FMT(dest_op), S86_STR8_FMT(src_op)); + S86_PrintLnFmt("%.*s %.*s, %.*s", S86_STR8_FMT(op), S86_STR8_FMT(dest_op), S86_STR8_FMT(src_op)); } } break; + case S86_InstructionType_ADDImmediateToRegOrMem: /*FALLTHRU*/ case S86_InstructionType_MOVImmediateToRegOrMem: { S86_ASSERT(op_code_size == 2); uint8_t w = (op_code_bytes[0] & 0b0000'0001) >> 0; + uint8_t s = (op_code_bytes[0] & 0b0000'0010) >> 1; uint8_t mod = (op_code_bytes[1] & 0b1100'0000) >> 6; uint8_t rm = (op_code_bytes[1] & 0b0000'0111) >> 0; S86_ASSERT(w < 2); S86_ASSERT(mod < 4); S86_ASSERT(rm < 8); - S86_ASSERT(mod != 0b11); // NOTE: Op is IMM->Reg, register-to-register not permitted - // NOTE: Memory mode w/ effective address calculation - // ========================================================= - S86_EffectiveAddressStr8 effective_address = S86_EffectiveAddressCalc(&buffer_it, rm, mod); + S86_EffectiveAddressStr8 effective_address = S86_EffectiveAddressCalc(&buffer_it, rm, mod, w); // NOTE: Parse data payload // ============================================================= - uint16_t data = S86_BufferIteratorNextByte(&buffer_it); + uint16_t data = S86_BufferIteratorNextByte(&buffer_it); + bool sign_extend_8bit_data = false; if (w) { // 16 bit data - uint8_t data_hi = S86_BufferIteratorNextByte(&buffer_it); - data |= (uint16_t)(data_hi) << 8; + if (instruction_type == S86_InstructionType_ADDImmediateToRegOrMem && s) { + sign_extend_8bit_data = true; + } else { + uint8_t data_hi = S86_BufferIteratorNextByte(&buffer_it); + data |= (uint16_t)(data_hi) << 8; + } + } + + S86_Str8 op = {0}; + if (instruction_type == S86_InstructionType_MOVImmediateToRegOrMem) { + S86_ASSERT(mod != 0b11); // NOTE: Op is IMM->Reg, register-to-register not permitted + op = S86_STR8("mov"); + } else { + S86_ASSERT(instruction_type == S86_InstructionType_ADDImmediateToRegOrMem); + op = S86_STR8("add"); } // NOTE: Disassemble // ========================================================= - S86_PrintLnFmt("mov %.*s, %s %u", effective_address.size, effective_address.data, w ? "word" : "byte", data); + if (instruction_type == S86_InstructionType_MOVImmediateToRegOrMem) { + S86_PrintLnFmt("%.*s %.*s, %s %u", S86_STR8_FMT(op), effective_address.size, effective_address.data, w ? "word" : "byte", data); + } else { + if (sign_extend_8bit_data) { + S86_PrintLnFmt("%.*s %.*s, %d", S86_STR8_FMT(op), effective_address.size, effective_address.data, (int16_t)data); + } else { + S86_PrintLnFmt("%.*s %.*s, %u", S86_STR8_FMT(op), effective_address.size, effective_address.data, data); + } + } } break; + case S86_InstructionType_ADDImmediateToAccum: /*FALLTHRU*/ case S86_InstructionType_MOVImmediateToReg: { // NOTE: Parse opcode control bits // ============================================================= S86_ASSERT(op_code_size == 1); - uint8_t w = (op_code_bytes[0] & 0b0000'1000) >> 3; + uint8_t w = 0; + if (instruction_type == S86_InstructionType_ADDImmediateToAccum) { + w = (op_code_bytes[0] & 0b0000'0001) >> 0; + } else { + w = (op_code_bytes[0] & 0b0000'1000) >> 3; + } uint8_t reg = (op_code_bytes[0] & 0b0000'0111) >> 0; // NOTE: Parse data payload @@ -507,8 +561,23 @@ int main(int argc, char **argv) // NOTE: Disassemble // ============================================================= - S86_Str8 dest_register = REGISTER_FIELD_ENCODING[w][reg]; - S86_PrintLnFmt("mov %.*s, %d", S86_STR8_FMT(dest_register), (int16_t)data); + S86_Str8 op = {0}; + S86_Str8 dest_register = {0}; + if (instruction_type == S86_InstructionType_MOVImmediateToReg) { + op = S86_STR8("mov"); + dest_register = REGISTER_FIELD_ENCODING[w][reg]; + } else { + S86_ASSERT(instruction_type == S86_InstructionType_ADDImmediateToAccum); + op = S86_STR8("add"); + if (w) { + dest_register = S86_STR8("ax"); + } else { + data = (uint16_t)(int8_t)data; // Sign extension + dest_register = S86_STR8("al"); + } + } + + S86_PrintLnFmt("%.*s %.*s, %d", S86_STR8_FMT(op), S86_STR8_FMT(dest_register), (int16_t)data); } break; case S86_InstructionType_MOVAccumToMem: /*FALLTHRU*/ diff --git a/project.rdbg b/project.rdbg index 2d6808e..b3f9a96 100644 Binary files a/project.rdbg and b/project.rdbg differ