; Contains code licensed under CC-BY-SA by Michael Karcher ; from https://retrocomputing.stackexchange.com/questions/12693/how-does-single-stepping-on-the-8086-interact-with-internal-and-external-interru/12694#12694 ; 2026 by E. C. Masloch cpu 8086 org 256 start: cmp sp, stack.top jb error mov si, 81h call getnumber mov word [counter], di dec si scan: .: lodsb cmp al, 32 je . cmp al, 9 je . cmp al, 13 je .end cmp al, '!' jne .notex mov word [..@multiply], 9090h jmp . .notex: cmp al, '?' jne .notq call getnumber mov word [..@counter], di dec si jmp . .notq: cmp al, '+' jne .notplus inc byte [..@list] jmp . .notplus: jmp error .end: hook: mov ax, 3501h int 21h mov word [i01.next], bx mov word [i01.next + 2], es mov dx, i01 mov ax, 2501h int 21h mov ax, 35A1h int 21h mov word [iA1.next], bx mov word [iA1.next + 2], es mov dx, iA1 mov ax, 25A1h int 21h %define STRINGS db "" %define TABLE dw "" %imacro i 1+.nolist %assign %%entry ($ - start + 256) %defstr %%string %1 %xdefine STRINGS STRINGS, %%name:, {db %%string, 36} %xdefine TABLE TABLE, dw %%entry, dw %%length, dw %%name %1 %assign %%length ($ - start + 256) - %%entry %endmacro align 64, nop test: ; Following from https://retrocomputing.stackexchange.com/questions/12693/how-does-single-stepping-on-the-8086-interact-with-internal-and-external-interru/12694#12694 i pushf i mov ax, 300h ; 100h = TF; 200h = IF i push ax i popf ; This instruction sets the trace flag i mov ax, 1234h i mov bl, 1 i inc ax i mov dx, ds i mov es, ax ; On 8086/8088: No interrupts before NOP is executed i nop i mov dx, ss i mov ss, dx ; On any x86 processor: No interrupts before NOP is executed i nop i int 0A1h i dec cx i popf ; This instruction clears the trace flag i dec ax unhook: lds dx, [cs:i01.next] mov ax, 2501h int 21h lds dx, [cs:iA1.next] mov ax, 25A1h int 21h dump: push cs pop ds push cs pop es mov si, buffer mov di, [next] mov ax, di sub ax, si shr ax, 1 shr ax, 1 call disp_ax_hex mov dx, msg.linebreak call disp_msg mov bx, cs xchg cx, ax int3 cmp byte [..@list], 1 jb dumponly list: push si push cx mov si, table .loop: lodsw mov dx, msg.asterisk mov di, buffer push cx .next: scasw je .found scasw ; di += 2 loop .next .notfound: mov dx, msg.blank .found: call disp_msg pop cx call disp_ax_hex mov dx, msg.plus call disp_msg lodsw call disp_al_dec mov dx, msg.sep call disp_msg lodsw xchg dx, ax call disp_msg mov dx, msg.linebreak call disp_msg cmp si, table.end jb .loop .end: pop cx pop si cmp byte [..@list], 2 jb exit dumponly: jcxz .done .loop: lodsw xchg ax, dx lodsw call disp_ax_hex call disp_colon xchg ax, dx call disp_ax_hex cmp dx, bx je .ourcs mov dx, msg.not_our_cs call disp_msg jmp .next .ourcs: mov di, table .innerloop: scasw jne .innernext add ax, word [di + 0] mov dx, msg.sep call disp_msg call disp_ax_hex mov dx, msg.sep call disp_msg mov dx, word [di + 2] call disp_msg mov dx, msg.linebreak call disp_msg jmp .next .innernext: scasw ; di += 2 scasw ; di += 2 cmp di, table.end jb .innerloop mov dx, msg.unknownline call disp_msg .next: loop .loop .done: exit: mov ax, 4C00h int 21h error: mov dx, msg.error call disp_msg mov ax, 4C01h int 21h disp_msg: push ax mov ah, 09h int 21h pop ax retn disp_colon: push ax push dx mov dl, ':' mov ah, 02h int 21h pop dx pop ax retn retf_inst: retf align 2 iA1: i jmp strict short .enter .next: dd 0 dw "KB" db 0 jmp strict short retf_inst times 7 db 0 .enter: i inc dx i dec dx i iret align 2 i01: jmp strict short .enter .next: dd 0 dw "KB" db 0 jmp strict short retf_inst times 7 db 0 .enter: push bp mov bp, sp push es push di push ax push cx push dx cld push cs pop es mov di, [es:next] cmp di, buffer.end jb .space inc word [es:toomany] jmp .done .space: mov ax, word [bp + 2] ; ip stosw mov ax, word [bp + 4] ; cs stosw mov word [es:next], di .done: mov cx, word [es:counter] jcxz .skip cli .outer: push cx mov cx, -1 ..@counter: equ $ - 2 .inner: mov ax, 16661 ..@multiply: mul ax add ax, ax loop .inner pop cx loop .outer .skip: pop dx pop cx pop ax pop di pop es pop bp iret disp_ax_hex: xchg al, ah call disp_al_hex xchg al, ah disp_al_hex: push cx mov cl, 4 rol al, cl call disp_al_nybble_hex rol al, cl pop cx disp_al_nybble_hex: push ax push dx and al, 15 add al, '0' cmp al, '9' jbe .got add al, 7 .got: xchg dx, ax mov ah, 02h int 21h pop dx pop ax retn disp_al_dec: push ax push cx push dx mov cx, 100 << 8; ch = 100, cl = 0 .loop: mov ah, 0 ; ax = dividend div ch ; ah = remainder, al = quotient push ax test al, al ; leading zero ? jnz .do ; no --> test cx, 01FFh ; (ch & 1) == 0 (not true for 100, 10) ; AND cl == 0 jz .dont ; then skip leading zero --> .do: inc cx ; remember had a digit add al, '0' xchg dx, ax mov ah, 02h int 21h .dont: mov al, ch aam ; divide by 10 mov ch, ah pop ax mov al, ah cmp ch, 1 jae .loop pop dx pop cx pop ax retn ; INP: si -> text ; OUT: si - 1 -> end (nondigit) ; di = number getnumber: .skip: lodsb cmp al, 32 je .skip cmp al, 9 je .skip cmp al, '0' jb error cmp al, '9' ja error xor di, di jmp .digit .loop: lodsb .digit: cmp al, '_' je .loop sub al, '0' jb .end cmp al, 10 jae .end cbw add di, di ; times 2 mov bx, di add di, di ; times 4 add di, di ; times 8 add di, bx ; times 10 add di, ax jmp .loop .end: retn %imacro dumptables 1-*.nolist %rep %0 %1 %rotate 1 %endrep %endmacro align 2, db 0 table: dumptables TABLE .end: next: dw buffer toomany:dw 0 ..@list:db 0 msg: .sep: db " ",36 .linebreak: db 13,10,36 .not_our_cs: db " Not in our CS",13,10,36 .unknownline: db " Unknown line in our CS",13,10,36 .error: db "Error!",13,10,36 .asterisk: db "*",36 .blank: db " ",36 .plus: db "+",36 dumptables STRINGS absolute $ alignb 2 counter:resw 1 alignb 4 buffer: resd 512 .end: alignb 16 stack: resb 512 .top: