; 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