389 lines
4.4 KiB
NASM
389 lines
4.4 KiB
NASM
; 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
|