cpu 8086 org 0x0000 %macro push8086 0 push ss push es push ds push di push si push bp push sp push bx push dx push cx push ax ; adjust stored SP to be value before interrupt mov bp, sp mov [bp+08], bp add WORD [bp+08], 28 %endmacro %macro pop8086 0 pop ax pop cx pop dx pop bx add sp, 2 ; skip SP pop bp pop si pop di pop ds pop es add sp, 2 ; skip SS %endmacro rom: db 0x55, 0xAA .sectors: db 0x00 .init: jmp init nop .name: db "RDOS DEBUG", 0 times (0x18 - ($-$$)) db 0 .pcir_ptr: dw 0 times (0x1A - ($-$$)) db 0 .pnp_ptr: dw pnp pnp: db "$PnP" .version: db 1 ; version 1 .length: db 2 ; 2 * 16 length dw 0 ; offset of next header db 0 .checksum: db 0 ; checksum (filled by fix-rom) dd 0 ; device identifier dw 0 ; manufacturer string dw rom.name ; product name string db 0,0,0 ; device type string db 0x20 ; device indicator, bit for "read cacheable" set dw 0 ; boot connection vector dw 0 ; boot disconnect vector dw 0 ; bootstrap entry point dw 0 ; reserved dw 0 init: mov bx, 0 mov dx, isr_divide_error call hook_int mov bx, 1 mov dx, isr_singlestep call hook_int mov bx, 2 mov dx, isr_nmi call hook_int mov bx, 3 mov dx, isr_breakpoint call hook_int mov bx, 4 mov dx, isr_overflow call hook_int ; 5 left out mov bx, 6 mov dx, isr_invalid_opcode call hook_int push cs pop ds mov si, rom.name push cs push si call printf db "%S %X", 0x0A, 0x0D, 0 add sp, 4 retf ; Hook interrupt hook_int: ; bx times 4 add bx, bx add bx, bx ; store offset mov [bx], dx ; store segment push ax mov ax, cs mov [bx+2], ax pop ax ret putc: push bx push cx mov ah, 0x0e mov bx, 0x0000 int 0x10 pop cx pop bx ret ; Names for words in debug frame ; Two characters per word, 14 words total debug_frame_names: ; general-purpose registers db "AXCXDXBXSPBPSIDI" ; extra registers db "DSESSSIPCSFL" ; Names for bits in debug_frame+26 (FL/Flags register) ; One character per bit, 16 bits total debug_frame_flags: db "++++ODIT" db "SZ+A+P+C" ; Print a single register from the frame ; in SI frame offset for register debug_frame_register_print: mov bx, debug_frame_names mov al, [cs:bx+si] ; first name char load call putc mov al, [cs:bx+si+1] ; second name char load call putc mov al, '=' call putc mov ax, [ss:bp+si] ; value load ; prepare call to print_number push bx push cx mov bx, 0x0010 mov cx, 3 call print_number_padded pop cx pop bx mov al, ' ' call putc ret debug_frame_print: mov si, 0 mov cx, 8 .reg1loop: call debug_frame_register_print add si, 2 loop .reg1loop mov dx, [ss:bp+26] mov di, debug_frame_flags mov cx, 0x0010 .flag_loop: mov al, [cs:di] inc di cmp al, '+' je .next test dx, 0x8000 jnz .write mov al, '-' .write: call putc .next: sal dx, 1 loop .flag_loop call printf db 0x0A, 0x0D, 0 mov si, 16 mov cx, 5 .reg2loop: call debug_frame_register_print add si, 2 loop .reg2loop call printf db 0x0A, 0x0D, 0 ret isr_divide_error: push8086 call printf db 0x0A, 0x0D, "INT 0 - DIVIDE ERROR", 0x0A, 0x0D, 0 call debug_frame_print jmp halt isr_singlestep: push8086 call printf db 0x0A, 0x0D, 0 call debug_frame_print ; wait for keypress xor ax, ax int 0x16 ; enable trace flag so we fire again after next instruction or word [ss:bp+26], 0x0100 pop8086 iret isr_nmi: push8086 call printf db 0x0A, 0x0D, "INT 2 - NON-MASKABLE INTERRUPT", 0x0A, 0x0D, 0 call debug_frame_print jmp halt isr_breakpoint: push8086 call printf db 0x0A, 0x0D, 0 call debug_frame_print pop8086 iret isr_overflow: push8086 call printf db 0x0A, 0x0D, "INT 4 - OVERFLOW", 0x0A, 0x0D, 0 call debug_frame_print jmp halt isr_invalid_opcode: push8086 call printf db 0x0A, 0x0D, "INT 6 - INVALID OPCODE", 0x0A, 0x0D, 0 call debug_frame_print jmp halt halt: call printf db "HALTED", 0x0A, 0x0D, 0 .loop: hlt jmp halt %include "printf.asm" align 512