You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
388 lines
4.4 KiB
388 lines
4.4 KiB
; CC0 2021 nortti |
|
org 0x7c00 |
|
|
|
jmp 0:start |
|
|
|
start: |
|
cld |
|
cli |
|
xor dx, dx |
|
mov ds, dx |
|
mov ss, dx |
|
mov sp, $$ |
|
sti |
|
|
|
; VGA video memory |
|
mov ax, 0xb800 |
|
mov es, ax |
|
|
|
; Start at bootloader |
|
mov bx, $$ |
|
|
|
init_screen: |
|
; Set 80x25 text mode |
|
mov ax, 3 |
|
int 0x10 |
|
|
|
; Clear screen |
|
xor di, di |
|
xor ax, ax |
|
mov cx, 80 * 25 |
|
rep stosw |
|
|
|
mainloop: |
|
; Align dump display to 256 byte page |
|
mov si, 0xff00 |
|
and si, bx |
|
|
|
; Display RAM contents |
|
xor di, di |
|
mov bp, 256 |
|
.dump: |
|
cmp si, bx |
|
jne .not_cursor |
|
|
|
; Set cursor |
|
pusha |
|
|
|
shr di, 1 ; Cursor position is in char cells |
|
|
|
mov dx, 0x3d4 |
|
mov al, 0x0f ; Lower 8 bits of position |
|
out dx, al |
|
inc dx |
|
mov ax, di |
|
out dx, al |
|
|
|
mov dx, 0x3d4 |
|
mov al, 0x0e ; Higher 8 bits of position |
|
out dx, al |
|
inc dx |
|
mov ax, di |
|
mov al, ah |
|
out dx, al |
|
|
|
popa |
|
|
|
.not_cursor: |
|
lodsb |
|
call hexprint8 |
|
|
|
; Fletcher-16 |
|
add dl, al |
|
adc dl, 0 |
|
add dh, dl |
|
adc dh, 0 |
|
|
|
inc di |
|
inc di |
|
|
|
dec bp |
|
test bp, 0x0f |
|
jnz .dump |
|
|
|
inc di |
|
inc di |
|
mov ax, dx |
|
call hexprint16 |
|
xor dx, dx |
|
|
|
add di, (80 - 16*3 - 5)*2 |
|
|
|
test bp, bp |
|
jnz .dump |
|
|
|
.end_dump: |
|
|
|
; Display address |
|
mov di, 17 * 80 * 2 |
|
mov ax, bx |
|
call hexprint16 |
|
|
|
xor ax, ax |
|
call disasm |
|
|
|
; Read user input |
|
int 0x16 |
|
|
|
.left: |
|
cmp ah, 0x4b |
|
jne .right |
|
dec bx |
|
|
|
.right: |
|
cmp ah, 0x4d |
|
jne .up |
|
inc bx |
|
|
|
.up: |
|
cmp ah, 0x48 |
|
jne .down |
|
sub bx, 16 |
|
|
|
.down: |
|
cmp ah, 0x50 |
|
jne .digit09 |
|
add bx, 16 |
|
|
|
.digit09: |
|
cmp al, '0' |
|
jb .digitaf |
|
cmp al, '9' |
|
ja .digitaf |
|
sub al, '0' |
|
jmp digit |
|
|
|
.digitaf: |
|
cmp al, 'a' |
|
jb .r |
|
cmp al, 'f' |
|
ja .r |
|
sub al, 'a' - 10 |
|
jmp digit |
|
|
|
.r: |
|
cmp al, 'r' |
|
mov al, 0xff |
|
jne digit.update_nybble |
|
|
|
pusha |
|
call bx |
|
popa |
|
jmp init_screen |
|
|
|
digit: |
|
; 00 … 0f are stored nybbles, other values are sentinels |
|
test byte [high_nybble], 0xf0 |
|
jnz .update_nybble |
|
|
|
mov cl, [high_nybble] |
|
shl cl, 4 |
|
or al, cl |
|
mov [bx], al |
|
inc bx |
|
|
|
mov al, 0xff |
|
|
|
.update_nybble: |
|
mov [high_nybble], al |
|
jmp mainloop |
|
|
|
; IN: |
|
; ah = 0 |
|
; bx = offset |
|
disasm: |
|
pusha |
|
mov si, bx |
|
mov di, 19 * 80 * 2 |
|
mov cx, 2 * 80 |
|
push di |
|
rep stosw |
|
pop di |
|
|
|
; Opcode byte |
|
lodsb |
|
mov dl, al |
|
shr al, 1 |
|
cmp al, 0x7f ; fe ff |
|
jz .do_disasm |
|
test al, 0x62 ; add, or, adc, sbb, and, sub, xor, cmp |
|
jz .do_disasm |
|
cmp al, 0x40 |
|
jb .no_disasm |
|
cmp al, 0x45 ; 80 81 82 83, test, mov |
|
jbe .do_disasm |
|
cmp al, 0x60 ; c0 c1 |
|
je .do_disasm |
|
jb .no_disasm |
|
cmp al, 0x62 ; c4 c5 |
|
je .do_disasm |
|
test al, 0x16 ; d0 d1 d2 d3 |
|
jnz .no_disasm |
|
|
|
.do_disasm: |
|
; Opcode |
|
shr al, 1 |
|
call hexprint8 |
|
|
|
inc di |
|
inc di |
|
|
|
; Direction / extend |
|
mov ax, 0x0700 + ' ' |
|
test dl, 2 |
|
jz .print_direction |
|
mov al, 's' |
|
.print_direction: |
|
stosw |
|
|
|
inc di |
|
inc di |
|
|
|
; Width |
|
mov al, 'b' |
|
test dl, 1 |
|
jz .print_width |
|
mov al, 'w' |
|
.print_width: |
|
stosw |
|
|
|
add di, (80 - 6) * 2 |
|
|
|
; Mod-reg-r/m byte |
|
lodsb |
|
mov dh, al |
|
|
|
; Mode |
|
shr al, 6 |
|
call hexprint4 |
|
|
|
inc di |
|
inc di |
|
|
|
; Reg or opcode extension |
|
mov al, 0x38 |
|
and al, dh |
|
shr al, 3 |
|
cmp dl, 0x80 |
|
jb .not_op_ext |
|
cmp dl, 0x83 ; 80 81 82 83 |
|
jbe .op_ext |
|
cmp dl, 0x8b ; test mov |
|
jbe .not_op_ext |
|
|
|
.op_ext: |
|
call hexprint4 |
|
jmp .skip_print_reg |
|
|
|
.not_op_ext: |
|
call .reg |
|
|
|
.skip_print_reg: |
|
inc di |
|
inc di |
|
|
|
; R/m |
|
mov al, 0x07 |
|
and al, dh |
|
cmp dh, 0xc0 ; Hacky way to check if top two bits are both set |
|
jb .base |
|
call .reg |
|
|
|
.no_disasm: |
|
popa |
|
ret |
|
|
|
.reg: |
|
xor bx, bx |
|
mov bl, al |
|
|
|
test dl, 1 |
|
jz .reg8 |
|
mov al, byte [bx + register_first] |
|
stosw |
|
|
|
shr bx, 1 |
|
mov al, byte [bx + register_second] |
|
stosw |
|
|
|
ret |
|
|
|
.reg8: |
|
mov cl, al |
|
shr cl, 2 |
|
|
|
and bl, 3 |
|
mov al, byte [bx + register_first] |
|
stosw |
|
|
|
mov bl, cl |
|
mov al, byte [bx + register_halves] |
|
stosw |
|
|
|
ret |
|
|
|
.base: |
|
mov cl, al |
|
test al, 4 |
|
jnz .base47 |
|
|
|
mov al, 'b' |
|
stosw |
|
|
|
mov bx, 2 |
|
and bl, cl |
|
shr bl, 1 |
|
mov al, byte [bx + base_first] |
|
stosw |
|
|
|
mov al, '+' |
|
stosw |
|
|
|
.si_di: |
|
mov bl, 1 |
|
and bl, cl |
|
mov al, byte [bx + base_second] |
|
stosw |
|
|
|
mov al, 'i' |
|
stosw |
|
|
|
popa |
|
ret |
|
|
|
.base47: |
|
test al, 2 |
|
jz .si_di |
|
|
|
mov al, 'b' |
|
stosw |
|
|
|
mov bx, 7 |
|
sub bl, cl |
|
mov al, byte [bx + base_first] |
|
stosw |
|
|
|
popa |
|
ret |
|
|
|
register_first db 'acdbsb' |
|
base_second db 'sd' |
|
|
|
register_second db 'x' |
|
base_first db 'xp' |
|
db 'i' |
|
|
|
register_halves db 'lh' |
|
|
|
; IN: ax/al/al = number |
|
; UPDATE: di = index into video memory |
|
hexprint16: |
|
xchg al, ah |
|
call hexprint8 |
|
xchg al, ah |
|
|
|
hexprint8: |
|
rol al, 4 |
|
call hexprint4 |
|
rol al, 4 |
|
|
|
hexprint4: |
|
push ax |
|
and al, 0xf |
|
|
|
cmp al, 10 |
|
jb .below_10 |
|
add al, 'a' - '0' - 10 |
|
|
|
.below_10: |
|
add al, '0' |
|
|
|
; 07 = white on black |
|
mov ah, 0x07 |
|
stosw |
|
pop ax |
|
ret |
|
|
|
times 510 - ($ - $$) db 0 |
|
high_nybble db 0x55, 0xaa
|
|
|