perfaware/part1: Support add instructions
This commit is contained in:
parent
9f76a7d181
commit
bcd509318c
@ -8,7 +8,7 @@
|
||||
;
|
||||
; Please see https://computerenhance.com for further information
|
||||
;
|
||||
; ======================================================================== */
|
||||
; ========================================================================
|
||||
|
||||
; ========================================================================
|
||||
; LISTING 37
|
||||
|
@ -8,7 +8,7 @@
|
||||
;
|
||||
; Please see https://computerenhance.com for further information
|
||||
;
|
||||
; ======================================================================== */
|
||||
; ========================================================================
|
||||
|
||||
; ========================================================================
|
||||
; LISTING 38
|
||||
|
Binary file not shown.
@ -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
|
||||
|
||||
|
BIN
part1/listing_0041_add_sub_cmp_jnz
Normal file
BIN
part1/listing_0041_add_sub_cmp_jnz
Normal file
Binary file not shown.
121
part1/listing_0041_add_sub_cmp_jnz.asm
Normal file
121
part1/listing_0041_add_sub_cmp_jnz.asm
Normal file
@ -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
|
BIN
part1/listing_0042_completionist_decode
Normal file
BIN
part1/listing_0042_completionist_decode
Normal file
Binary file not shown.
425
part1/listing_0042_completionist_decode.asm
Normal file
425
part1/listing_0042_completionist_decode.asm
Normal file
@ -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
|
||||
;
|
207
part1/sim8086.c
207
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*/
|
||||
|
BIN
project.rdbg
BIN
project.rdbg
Binary file not shown.
Loading…
Reference in New Issue
Block a user