2026-01-11
ETA:
New script to step through an emu2-style CPU log. This log is similar to a list of lDebug trace register dumps, except both register lines and the disassembly line are all on the same line. step.pl allows to specify an input file and an output file to append to, and provides several commands to step through the input. The output is expanded into the lines as expected by TracList.
The input loop was copied from TracList to allow receiving keys without trailing linebreaks.
'\n' didn't work. "\n" did the trick.
Update sync-gitrepos-with-github to git fetch from origin, pass the -u switch, and pass '*:*'. This seems to do what we want, namely update the default log on bare repos. Repos need to be set up as follows:
git clone SOURCE -n REPOtouch REPORobert pointed me to emu2 recently again. Loving to work with simple 8086 DOS emulators, I picked it up and worked some on my own fork, based on amuramatsu's fork. Here's what I did:
I uploaded a number of test programs that were used for recent changes:
testmcb.asm: Test program for the original emu2 repo, for a bug report on MCB coalescing. What it does: Allocate a number of 64 KiB memory blocks, free them in a certain order, then try to allocate a larger block.
cpu 8086 org 256 start: mov ah, 4Ah mov bx, 1000h int 21h mov di, array xor cx, cx loopalloc: mov ah, 48h mov bx, 1000h int 21h jc endalloc stosw inc cx jmp loopalloc endalloc: cmp cx, 4 jb errorinit mov si, array mov cx, 4 loopfree: lodsw mov es, ax mov ah, 49h int 21h loop loopfree mov ah, 48h mov bx, 3000h int 21h jc errorexit mov dx, msg.success mov ah, 09h int 21h mov ax, 4C00h int 21h errorexit: mov dx, msg.errorexit jmp error errorinit: mov dx, msg.errorinit error: mov ah, 09h int 21h mov ax, 4C01h int 21h msg: .errorinit: db "Too small initial allocation!",13,10,36 .errorexit: db "Failed last allocation!",13,10,36 .success: db "Success!",13,10,36 align 2 array:
testmcb2.asm: Test program to check that lDOS kernel option COMPAT=COLLECTFREEMCB works as intended. What it does: Allocate several 64 KiB blocks, then free some of them in a certain order.
cpu 8086 org 256 start: mov ah, 4Ah mov bx, 1000h int 21h mov di, array xor cx, cx loopalloc: mov ah, 48h mov bx, 1000h int 21h jc endalloc stosw inc cx jmp loopalloc endalloc: cmp cx, 4 jb errorinit mov es, word [array + 4] mov ah, 49h int 21h mov es, word [array + 2] mov ah, 49h int 21h mov es, word [array + 0] mov ah, 49h int 21h mov dx, msg.success mov ah, 09h int 21h mov ax, 4C00h int 21h errorexit: mov dx, msg.errorexit jmp error errorinit: mov dx, msg.errorinit error: mov ah, 09h int 21h mov ax, 4C01h int 21h msg: .errorinit: db "Too small initial allocation!",13,10,36 .errorexit: db "Failed last allocation!",13,10,36 .success: db "Success!",13,10,36 align 2 array:
tsr.asm: Test case for a simple TSR program that calls int 27h with dx equal to zero. Used to test the int 27h service in emu2. What it does: Close the first 20 process handles, free the environment block, and TSR using int 27h.
cpu 8086 org 256 start: mov cx, 20 xor bx, bx .loop: mov ah, 3Eh int 21h inc bx loop .loop xor ax, ax xchg ax, [2Ch] mov es, ax mov ah, 49h int 21h xor dx, dx int 27h mov ax, 4CFFh int 21h
testrep.asm: Test case for tracing repeated string instructions. Used to develop emu2 Trace Flag support. What it does: Use rep lodsb with several different counter values in cx.
cpu 8086 org 256 start: xor ax, ax mov si, buffer mov cx, 0 rep lodsb mov si, buffer mov cx, 1 rep lodsb mov si, buffer mov cx, 2 rep lodsb mov si, buffer mov cx, 3 rep lodsb mov ax, 4C00h int 21h align 2 buffer: db 1, 2, 3, 4
testrepz.asm: Test case for repz and repnz prefixed string instructions to preserve all flags on execution with cx equal to zero. Used to develop emu2.
org 256 start: xor cx, cx cmp al, al repe cmpsb or al, 1 repe cmpsb cmp al, al repne cmpsb or al, 1 repne cmpsb mov ax, 4C00h int 21h
int6.asm: Run an interrupt 6 by means of int instruction.
cpu 8086 org 256 start: int 6 mov ax, 4C00h int 21h
testirq.asm: Trigger IRQ #8 several times to test that the default ROM-BIOS handler correctly issues EOIs. This was used in conjunction with the int 2Dh test handler of emu2, to trigger the IRQ #8 (int 70h).
cpu 8086 org 256 start: mov ax, 3570h int 21h mov word [next + 2], es mov word [next + 0], bx mov ax, 2570h mov dx, handler int 21h in al, 0A1h and al, ~1 out 0A1h, al xor ax, ax int 2Dh mov dx, [variable] mov ax, 2600h int 2Dh mov dx, [variable] mov ax, 3800h int 2Dh mov dx, [variable] lds dx, [next] mov ax, 2570h int 21h mov ax, 4C00h int 21h handler: inc word [cs:variable] jmp 0:0 next: equ $ - 4 align 2 variable: dw 0
testxms.asm: Test program to allocate or free XMS memory blocks. Not tested much. Used to check emu2 XMS allocation works and fails as expected.
%if 0
Usage of the works is permitted provided that this
instrument is retained with the works, so that any entity
that uses the works is notified of this instrument.
DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.
%endif
cpu 8086
org 256
start:
mov si, 81h
.skip:
lodsb
cmp al, 32
je .skip
cmp al, 9
je .skip
cmp al, '!'
jne .notex
not byte [wantfree]
.notex:
dec si
call getnumber
init:
mov ax, 4300h
int 2Fh
cmp al, 80h
je .gotxms
mov dx, msg.noxms
jmp errorexit
.gotxms:
mov ax, 4310h
int 2Fh
mov word [handler], bx
mov word [handler + 2], es
rol byte [wantfree], 1
jc free
alloc:
mov dx, msg.alloc1
call disp_msg
mov ax, di
call disp_ax_dec
mov dx, msg.alloc2
call disp_msg
mov dx, di
mov ah, 09h
push cs
call callhandler
cmp ax, 1
jne .error
push dx
mov dx, msg.alloc3
call disp_msg
pop ax
call disp_ax_dec
mov dx, msg.alloc4
call disp_msg
mov ax, 4C00h
int 21h
.error:
push dx
mov dx, msg.alloc5
call disp_msg
mov al, bl
call disp_al_hex
mov dx, msg.alloc6
call disp_msg
pop ax
call disp_ax_dec
mov dx, msg.alloc7
errorexit:
call disp_msg
mov ax, 4C01h
int 21h
free:
mov dx, msg.free1
call disp_msg
mov ax, di
call disp_ax_dec
mov dx, msg.free2
call disp_msg
mov dx, di
mov ah, 0Ah
push cs
call callhandler
cmp ax, 1
jne .error
mov dx, msg.free3
call disp_msg
mov ax, 4C00h
int 21h
.error:
mov dx, msg.free5
call disp_msg
mov al, bl
call disp_al_hex
mov dx, msg.free6
jmp errorexit
disp_msg:
push ax
mov ah, 09h
int 21h
pop ax
retn
disp_ax_dec:
push ax
push cx
push dx
mov cx, 10
mov dx, -1
push dx
.loop1:
xor dx, dx
div cx
push dx
test ax, ax
jnz .loop1
.loop2:
pop ax
add al, '0'
jc .end
xchg dx, ax
mov ah, 02h
int 21h
jmp .loop2
.end:
pop dx
pop cx
pop ax
retn
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
callhandler:
jmp 0:0
handler equ $ - 4
; 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
error:
mov dx, msg.error
jmp errorexit
wantfree: db 0
msg:
.error: db "Error!",13,10,36
.noxms: db "No XMS entry found!",13,10,36
.alloc1: db "Trying to allocate ",36
.alloc2: db " KiB, ",36
.alloc3: db "success, handle=",36
.alloc7:
.alloc4: db 13,10,36
.free5:
.alloc5: db "error, code=",36
.alloc6: db "h, dx=",36
.free1: db "Trying to free handle=",36
.free2: db ", ",36
.free6: db "h",13,10,36
.free3: db "success",13,10,36
testxmsm.asm: Test two XMS move calls with differing overlapping buffers, all in conventional memory. Used to check that the XMS specification is, indeed, wrong about the overlapping move direction. This test program was used during emu2 development to test the various combinations of checks and move implementations.
On the int3 breakpoints, the following debugger command can be used to view the "destination" memory buffer: d word [si + 4 + 6 + 2] l word [si]
cpu 186 org 256 start: mov ax, 4310h int 2Fh push es push bx mov bp, sp push cs push lower1 ; dest push 0 push cs push higher1 ; source push 0 push 0 push length1 ; length mov si, sp mov ah, 0Bh call far [bp] int3 push cs push higher2 ; dest push 0 push cs push lower2 ; source push 0 push 0 push length2 ; length mov si, sp mov ah, 0Bh call far [bp] int3 mov ax, 4C00h int 21h align 16, db 0 lower1: times 16 db 0 higher1: times 4 db "Foo bar baz quux@" align 16, db 0 length1 equ $ - higher1 align 16, db 0 lower2: times 4 db "Foo bar baz quux@" align 16, db 0 length2 equ $ - lower2 higher2: equ lower2 + 16
testmcb3.asm: Set up pathological MCB allocation situation to test that the lDOS kernel MCB collection is hardened appropriately. What it does: You need to run lDOS kernel with COMPAT=HIDEDOSENTRY in a dosemu2 instance, then run ldebug /t testmcb3.com so that the first MCB is the debuggee's environment block. Then, it will free its environment, check that the first MCB is free, get the first UMCB, walk until the 'Z' UMCB (last UMCB), check that this is an S MCB (owner 8, name "S", type 30h "excluded UMA") that's empty (size 0), and that the second-to-last UMCB is free. Then it sets up the memory allocation strategy 0382h and writes a 'Z' signature to the second-to-last UMCB. Finally, it tries to allocate memory with the impossible size (0FFFFh).
Prior to this lDOS kernel change, the allocation call would incorrectly collect the first LMCB upon encountering the last UMCB when both are free. This is because of the extended strategy:
cpu 8086 org 256 start: xor di, di xor ax, ax xchg ax, [di + 2Ch] mov es, ax mov ah, 49h int 21h mov ah, 52h int 21h mov ax, [es:bx - 2] mov es, ax cmp word [es:di + 1], 0 jne error mov ax, 1261h stc int 2Fh jc error xor bx, bx .loop: mov ds, ax cmp byte [di], 'Z' je .last cmp byte [di], 'M' jne error mov bx, ax add ax, word [di + 3] inc ax jmp .loop .last: test bx, bx jz error cmp word [di + 1], 8 jne error cmp word [di + 3], 0 jne error cmp word [di + 8], "S" jne error cmp byte [di + 10], 30h jne error mov ds, bx cmp word [di + 1], 0 jne error mov ax, 5801h mov bx, 382h stc int 21h jc error int3 mov byte [di], 'Z' mov ah, 48h mov bx, -1 int 21h mov ax, 4C00h int 21h error: int3 mov ax, 4CFFh int 21h