-; virtual processor, emulator for FIFTH\r
-\r
-; registers usage:\r
-\r
-; edi - data stack pointer\r
-; esi - instruction pointer\r
-; es = 0\r
-; cs - emulator program code segment\r
-; ds = cs\r
-\r
-\r
-org 100h\r
-\r
- call system_init ; init system, allocate XMS\r
- call KB_init ; init keyoard\r
-\r
- push 0 ; initialize segments\r
- pop es\r
- push cs\r
- pop ds\r
- sub ebx, ebx ; initialize pointers\r
- mov bx, cs\r
- shl ebx, 4\r
- add ebx, buf\r
- add ebx, 20000\r
- mov edi, ebx ; data stack\r
- add ebx, 10000\r
- mov [resp], ebx ; return stack\r
- mov esi, [xms_addr] ; instruction pointer\r
-\r
- mov ah, 3dh ; open diskfile\r
- mov al, 2\r
- mov dx, infile\r
- int 21h\r
- mov word [fileh], ax\r
-\r
- mov ax, 4F02h ; set VESA 640*480 8 bit\r
- mov bx, 101h\r
- int 10h\r
-\r
- mov ecx, 0 ; load boot block (first 1024 bytes)\r
- mov ebx, [xms_addr]\r
- call diskload\r
- jmp emu\r
-\r
-xmemtot dw 0 ; amount of accessible XMS\r
-\r
-infile db 'disk.raw', 0 ; virtual disk file name\r
-fileh dw 0 ; it's handle\r
-\r
-coresiz dw 4096 ; core size\r
-gran dw 0 ; VESA granule size\r
-\r
-quit: mov ax, 3 ; restore text mode\r
- int 10h\r
-\r
- mov ah, 3eh ; close diskfile\r
- mov bx, word [fileh]\r
- int 21h\r
-\r
- call KB_restore\r
- jmp system_exit ; terminate program\r
-\r
-resp dd 0 ; return stack pointer\r
-\r
-emu: ; pick instruction\r
-movzx bx, byte [es:esi]\r
-inc esi\r
-shl bx, 1\r
-add bx, table\r
-jmp word [cs:bx]\r
-\r
-table:\r
- dw emu ; 0\r
- dw quit\r
- dw xkbd@\r
- dw xnum\r
- dw xjmp\r
- dw xcall ; 5\r
- dw xinc\r
- dw xdec\r
- dw xdup\r
- dw xdrop\r
- dw xif ; 10\r
- dw xret\r
- dw xc@\r
- dw xc!\r
- dw xpush\r
- dw xpop ; 15\r
- dw 0\r
- dw xrot\r
- dw xdisk@\r
- dw xdisk!\r
- dw x@ ; 20\r
- dw x!\r
- dw xover\r
- dw xswap\r
- dw xplus\r
- dw xminus ; 25\r
- dw xmul\r
- dw xdiv\r
- dw xgreat\r
- dw xless ; 29\r
- dw xnot ; 30\r
- dw xi ; 31\r
- dw xcprt@ ; 32\r
- dw xcprt! ; 33\r
- dw xi2 ; 34\r
- dw xi3 ; 35\r
- dw xshl ; 36\r
- dw xshr ; 37\r
- dw lor ; 38\r
- dw lxor ; 39\r
- dw xvidmap ; 40\r
- dw xmouse@ ; 41\r
- dw xvidput ; 42\r
- dw xcmove ; 43\r
- dw xcfill ; 44\r
- dw xtvidput ; 45\r
- dw xdep ; 46\r
- dw xcharput ; 47\r
-\r
-xkbd@: call KB_read\r
- sub edi, 4\r
- mov [es:edi], dl\r
-\r
- mov ah, 0bh ; check for key in keyboard buffer\r
- int 21h\r
- cmp al, 0h\r
- je emu\r
- mov ah, 0 ; read key\r
- int 16h\r
- jmp emu\r
-\r
-xnum: mov edx, dword [es:esi]\r
- sub edi, 4\r
- mov [es:edi], edx\r
- add esi, 4\r
- jmp emu\r
-\r
-xjmp: mov esi, dword [es:esi]\r
- add esi, [xms_addr]\r
- jmp emu\r
-\r
-xcall: mov edx, dword [es:esi]\r
- mov eax, [resp]\r
- sub eax, 4\r
- mov ebx, esi\r
- add ebx, 4\r
- sub ebx, [xms_addr]\r
- mov [es:eax], ebx\r
- mov [resp], eax\r
- mov esi, edx\r
- add esi, [xms_addr]\r
- jmp emu\r
-\r
-xinc: ; Increment: ( n -- n+1 )\r
-; Increments the top of the data stack by 1.\r
-\r
- inc dword [es:edi]\r
- jmp emu\r
-\r
-\r
-xdec: ; Decrement: ( n -- n-1 )\r
-;\r
-; Decrements the top of the data stack by 1.\r
-;\r
-; Memory layout before execution:\r
-; [es:edi] = n\r
-;\r
-; Memory layout after execution:\r
-; [es:edi] = n-1\r
-\r
- dec dword [es:edi] ; decrement the top of the stack\r
- jmp emu\r
-\r
-\r
-xdup: ; Duplicate: ( n -- n n )\r
-;\r
-; Duplicates the top element of the data stack.\r
-;\r
-; Memory layout before execution:\r
-; [es:edi] = n\r
-;\r
-; Memory layout after execution:\r
-; [es:edi] = n (new top)\r
-; [es:edi+4] = n (original top)\r
-\r
- mov eax, [es:edi] ; copy top element to eax\r
- sub edi, 4 ; move stack pointer down to make space\r
- mov [es:edi], eax ; push copy of top element onto stack\r
- jmp emu\r
-\r
-\r
-xdrop: ; Drop: ( n -- )\r
-;\r
-; Removes the top element from the data stack.\r
-;\r
-; Memory layout before execution:\r
-; [es:edi] = n\r
-;\r
-; Memory layout after execution:\r
-; Stack pointer is adjusted; n is no longer on stack\r
-\r
- add edi, 4 ; pop top element off the stack\r
- jmp emu\r
-\r
-xif: mov eax, [es:edi]\r
- add edi, 4\r
- cmp eax, 0\r
- jne l2\r
- mov esi, [es:esi]\r
- add esi, [xms_addr]\r
- jmp emu\r
-l2:\r
- add esi, 4\r
- jmp emu\r
-\r
-xret: mov eax, [resp]\r
- mov esi, [es:eax]\r
- add esi, [xms_addr]\r
- add eax, 4\r
- mov [resp], eax\r
- jmp emu\r
-\r
-xc@: mov eax, [es:edi]\r
- add eax, [xms_addr]\r
- sub ecx, ecx\r
- mov cl, [es:eax]\r
- mov [es:edi], ecx\r
- jmp emu\r
-\r
-xc!: ;( n addr -- )\r
- mov ebx, [es:edi]\r
- add edi, 4\r
- mov ecx, [es:edi]\r
- add edi, 4\r
- add ebx, [xms_addr]\r
- mov [es:ebx], cl\r
- jmp emu\r
-\r
-xpush: mov ebx, [es:edi]\r
- add edi, 4\r
- mov eax, [resp]\r
- sub eax, 4\r
- mov [es:eax], ebx\r
- mov [resp], eax\r
- jmp emu\r
-\r
-xpop: mov eax, [resp]\r
- mov ebx, [es:eax]\r
- add eax, 4\r
- mov [resp], eax\r
- sub edi, 4\r
- mov [es:edi], ebx\r
- jmp emu\r
-\r
-xrot: mov ebx, [es:edi]\r
- mov ecx, [es:edi+4]\r
- mov edx, [es:edi+8]\r
- mov [es:edi+8], ecx\r
- mov [es:edi+4], ebx\r
- mov [es:edi], edx\r
- jmp emu\r
-\r
-xdisk@: mov ebx, [es:edi]\r
- add ebx, [xms_addr]\r
- mov ecx, [es:edi+4]\r
- add edi, 8\r
- call diskload ; ecx-fromdisk ebx-tomem\r
- jmp emu\r
-\r
-xdisk!: mov ecx, [es:edi]\r
- call file_seek\r
- mov ecx, 1024\r
- mov ebx, [es:edi+4]\r
- add edi, 8\r
- add ebx, [xms_addr]\r
- sub edx, edx\r
- mov dx, cs\r
- shl edx, 4\r
- add edx, buf\r
- call memmove ; ebx - from, edx - to, ecx - amount\r
- mov ah, 40h\r
- mov bx, [fileh]\r
- mov cx, 1024\r
- mov dx, buf\r
- int 21h\r
- jmp emu\r
-\r
-x@: mov eax, [es:edi]\r
- add eax, [xms_addr]\r
- mov eax, [es:eax]\r
- mov [es:edi], eax\r
- jmp emu\r
-\r
-x!: ;( n addr -- )\r
- mov eax, [es:edi]\r
- add eax, [xms_addr]\r
- mov ecx, [es:edi+4]\r
- add edi, 8\r
- mov [es:eax], ecx\r
- jmp emu\r
-\r
-xover: mov ebx, [es:edi+4]\r
- sub edi, 4\r
- mov [es:edi], ebx\r
- jmp emu\r
-\r
-xswap: mov ebx, [es:edi]\r
- xchg ebx, [es:edi+4]\r
- mov [es:edi], ebx\r
- jmp emu\r
-\r
-xplus: mov ebx, [es:edi]\r
- add edi, 4\r
- add [es:edi], ebx\r
- jmp emu\r
-\r
-\r
-xminus:\r
-; Subtract: ( n1 n2 -- n1-n2 )\r
-;\r
-; Pops the top two elements from the data stack, subtracts the top\r
-; element (n2) from the second element (n1), and pushes the result.\r
-;\r
-; In Fifth source code, this corresponds to the "-" word:\r
-;\r
-; 10 3 - \ result is 7 (10 minus 3)\r
-;\r
-; Argument order:\r
-; n1 is pushed first (sits deeper in the stack, at [es:edi+4])\r
-; n2 is pushed second (sits on top of the stack, at [es:edi])\r
-;\r
-; Memory layout before execution:\r
-; [es:edi] = n2 (top of stack — the value being subtracted)\r
-; [es:edi+4] = n1 (second on stack — the value subtracted from)\r
-;\r
-; Memory layout after execution:\r
-; [es:edi] = n1 - n2 (edi has been adjusted; old n2 slot is freed)\r
-\r
- mov ebx, [es:edi] ; ebx = n2 (the subtrahend — value to subtract)\r
- add edi, 4 ; pop n2 off the stack; n1 is now the new top\r
- sub [es:edi], ebx ; [es:edi] = n1 - n2 (subtract n2 from n1 in place)\r
- jmp emu\r
-\r
-\r
-xmul:\r
- mov eax, [es:edi]\r
- add edi, 4\r
- sub edx, edx\r
- imul dword [es:edi]\r
- mov [es:edi], eax\r
- jmp emu\r
-\r
-xdiv: add edi, 4\r
- mov eax, [es:edi]\r
- cdq\r
- idiv dword [es:edi-4]\r
- mov [es:edi], eax\r
- jmp emu\r
-\r
-xgreat: mov eax, [es:edi]\r
- add edi, 4\r
- mov edx, 0\r
- cmp [es:edi], eax\r
- jng l3\r
- dec edx\r
-l3: mov [es:edi], edx\r
- jmp emu\r
-\r
-xless: mov eax, [es:edi]\r
- add edi, 4\r
- mov edx, 0\r
- cmp [es:edi], eax\r
- jnl l4\r
- dec edx\r
-l4: mov [es:edi], edx\r
- jmp emu\r
-\r
-file_seek: ; ( ecx - pointer to seek )\r
- mov eax, 1024\r
- mul ecx\r
- mov ecx, eax\r
- mov dx, cx\r
- shr ecx, 16\r
- mov ah, 42h\r
- mov al, 0\r
- mov bx, [ds:fileh]\r
- int 21h\r
- ret\r
-\r
-xnot: not dword [es:edi]\r
- jmp emu\r
-\r
-xi: mov ebx, [resp]\r
- mov eax, [es:ebx]\r
- sub edi, 4\r
- mov [es:edi], eax\r
- jmp emu\r
-\r
-xcprt@: mov dx, [es:edi]\r
- in al, dx\r
- sub ecx, ecx\r
- mov cl, al\r
- mov [es:edi], ecx\r
- jmp emu\r
-\r
-xcprt!: mov dx, [es:edi]\r
- mov al, [es:edi+4]\r
- add edi, 8\r
- out dx, al\r
- jmp emu\r
-\r
-xi2: mov ebx, [resp]\r
- mov eax, [es:ebx+4]\r
- sub edi, 4\r
- mov [es:edi], eax\r
- jmp emu\r
-\r
-xi3: mov ebx, [resp]\r
- mov eax, [es:ebx+8]\r
- sub edi, 4\r
- mov [es:edi], eax\r
- jmp emu\r
-\r
-xshl: mov cl, [es:edi]\r
- add edi, 4\r
- shl dword [es:edi], cl\r
- jmp emu\r
-\r
-xshr: mov cl, [es:edi]\r
- add edi, 4\r
- shr dword [es:edi], cl\r
- jmp emu\r
-\r
-lor: mov eax, [es:edi]\r
- add edi, 4\r
- or [es:edi], eax\r
- jmp emu\r
-\r
-lxor: mov eax, [es:edi]\r
- add edi, 4\r
- xor [es:edi], eax\r
- jmp emu\r
-\r
-xvidmap:\r
- mov edx, [es:edi]\r
- add edx, [xms_addr]\r
- add edi, 4\r
- push edi\r
- push esi\r
- push 0a000h\r
- pop es\r
- mov word [ds:gra], 0\r
- push 0\r
- pop ds\r
- mov esi, edx\r
-mapl1: mov dx, [cs:gra]\r
- xor bx, bx\r
- mov ax, 4f05h\r
- int 10h\r
- mov edi, 0\r
- mov cx, 4096\r
-; mov cx, 16384\r
-mapl2: mov eax, [ds:esi]\r
- add esi, 4\r
- stosd\r
- loop mapl2\r
- inc word [cs:gra]\r
-; cmp word [cs:gra], 5\r
- cmp word [cs:gra], 19\r
- jne mapl1\r
- push 0\r
- pop es\r
- push cs\r
- pop ds\r
- pop esi\r
- pop edi\r
- jmp emu\r
-gra dw 0\r
-\r
-\r
-xmouse@:\r
- mov ax, 0bh ; read motion counter\r
- int 33h\r
- push dx\r
- sub eax, eax\r
- mov ax, cx\r
- cwd\r
- shl edx, 16\r
- add edx, eax\r
- mov [es:edi-4], edx\r
- pop ax\r
- cwd\r
- shl edx, 16\r
- add edx, eax\r
- mov [es:edi-8], edx\r
- mov ax, 3 ; read buttons\r
- int 33h\r
- sub eax, eax\r
- mov ax, bx\r
- sub edi, 12\r
- mov [es:edi], eax\r
- jmp emu\r
-\r
-memmove: ; ebx - from, edx - to, ecx - amount\r
- cmp ecx, 0\r
- je l11\r
- mov al, [es:ebx]\r
- mov [es:edx], al\r
- inc ebx\r
- inc edx\r
- dec ecx\r
- jmp memmove\r
-l11: ret\r
-\r
-memmove2: ; ebx - from, edx - to, ecx - amount\r
- add ebx, ecx\r
- add edx, ecx\r
-l7: cmp ecx, 0\r
- je l12\r
- dec ebx\r
- dec edx\r
- mov al, [es:ebx]\r
- mov [es:edx], al\r
- dec ecx\r
- jmp l7\r
-l12: ret\r
-\r
-xcmove: mov ecx, [es:edi]\r
- add edi, 12\r
- mov edx, [es:edi-8]\r
- add edx, [xms_addr]\r
- mov ebx, [es:edi-4]\r
- add ebx, [xms_addr]\r
- cmp ecx, 0\r
- je emu\r
- cmp ebx, edx\r
- ja l8\r
- call memmove2\r
- jmp emu\r
-l8: call memmove\r
- jmp emu\r
-\r
-xcfill: mov ecx, [es:edi]\r
- mov edx, [es:edi+4]\r
- add edx, [xms_addr]\r
- mov eax, [es:edi+8]\r
- add edi, 12\r
-l9: cmp ecx, 0\r
- je emu\r
- mov [es:edx], al\r
- inc edx\r
- dec ecx\r
- jmp l9\r
-\r
-diskload: ; ecx-fromdisk ebx-tomem\r
- push ebx\r
- call file_seek\r
- mov cx, 1024\r
- mov ah, 3fh\r
- mov bx, [fileh]\r
- mov dx, buf\r
- int 21h\r
-\r
- sub ebx, ebx ; move it to XMS\r
- mov bx, cs\r
- shl ebx, 4\r
- add ebx, buf\r
- pop edx\r
- mov ecx, 1024\r
- call memmove ; ebx - from, edx - to, ecx - amount\r
- ret\r
-\r
-xdep: sub eax, eax\r
- mov ax, cs\r
- shl eax, 4\r
- add eax, buf\r
- add eax, 20000\r
- sub eax, edi\r
- shr eax, 2\r
- sub edi, 4\r
- mov [es:edi], eax\r
- jmp emu\r
-\r
-include 'vidput.inc'\r
-include 'tvidput.inc'\r
-include 'charput.inc'\r
-include 'system.inc'\r
-include 'kbdrive.inc'\r
-\r
-buf: ; pointer to end of the code\r
+; virtual processor, emulator for FIFTH
+
+; registers usage:
+
+; edi - data stack pointer
+; esi - instruction pointer
+; es = 0
+; cs - emulator program code segment
+; ds = cs
+
+
+org 100h
+
+ call system_init ; init system, allocate XMS
+ call KB_init ; init keyoard
+
+ push 0 ; initialize segments
+ pop es
+ push cs
+ pop ds
+ sub ebx, ebx ; initialize pointers
+ mov bx, cs
+ shl ebx, 4
+ add ebx, buf
+ add ebx, 20000
+ mov edi, ebx ; data stack
+ add ebx, 10000
+ mov [resp], ebx ; return stack
+ mov esi, [xms_addr] ; instruction pointer
+
+ mov ah, 3dh ; open diskfile
+ mov al, 2
+ mov dx, infile
+ int 21h
+ mov word [fileh], ax
+
+ mov ax, 4F02h ; set VESA 640*480 8 bit
+ mov bx, 101h
+ int 10h
+
+ mov ecx, 0 ; load boot block (first 1024 bytes)
+ mov ebx, [xms_addr]
+ call diskload
+ jmp emu
+
+xmemtot dw 0 ; amount of accessible XMS
+
+infile db 'disk.raw', 0 ; virtual disk file name
+fileh dw 0 ; it's handle
+
+coresiz dw 4096 ; core size
+gran dw 0 ; VESA granule size
+
+quit: mov ax, 3 ; restore text mode
+ int 10h
+
+ mov ah, 3eh ; close diskfile
+ mov bx, word [fileh]
+ int 21h
+
+ call KB_restore
+ jmp system_exit ; terminate program
+
+resp dd 0 ; return stack pointer
+
+emu: ; pick instruction
+movzx bx, byte [es:esi]
+inc esi
+shl bx, 1
+add bx, table
+jmp word [cs:bx]
+
+table:
+ dw emu ; 0
+ dw quit
+ dw xkbd@
+ dw xnum
+ dw xjmp
+ dw xcall ; 5
+ dw xinc
+ dw xdec
+ dw xdup
+ dw xdrop
+ dw xif ; 10
+ dw xret
+ dw xc@
+ dw xc!
+ dw xpush
+ dw xpop ; 15
+ dw 0 ; 16 - unused instruction
+ dw xrot
+ dw xdisk@
+ dw xdisk!
+ dw x@ ; 20
+ dw x!
+ dw xover
+ dw xswap
+ dw xplus
+ dw xminus ; 25
+ dw xmul
+ dw xdiv
+ dw xgreat
+ dw xless ; 29
+ dw xnot ; 30
+ dw xi ; 31
+ dw xcprt@ ; 32
+ dw xcprt! ; 33
+ dw xi2 ; 34
+ dw xi3 ; 35
+ dw xshl ; 36
+ dw xshr ; 37
+ dw lor ; 38
+ dw lxor ; 39
+ dw xvidmap ; 40
+ dw xmouse@ ; 41
+ dw xvidput ; 42
+ dw xcmove ; 43
+ dw xcfill ; 44
+ dw xtvidput ; 45
+ dw xdep ; 46
+ dw xcharput ; 47
+
+
+include 'opcodes_00_09.inc'
+include 'opcodes_10_19.inc'
+include 'opcodes_20_29.inc'
+include 'opcodes_30_39.inc'
+include 'opcodes_40_47.inc'
+
+file_seek: ; ( ecx - pointer to seek )
+ mov eax, 1024
+ mul ecx
+ mov ecx, eax
+ mov dx, cx
+ shr ecx, 16
+ mov ah, 42h
+ mov al, 0
+ mov bx, [ds:fileh]
+ int 21h
+ ret
+
+memmove: ; ebx - from, edx - to, ecx - amount
+ cmp ecx, 0
+ je l11
+ mov al, [es:ebx]
+ mov [es:edx], al
+ inc ebx
+ inc edx
+ dec ecx
+ jmp memmove
+l11: ret
+
+memmove2: ; ebx - from, edx - to, ecx - amount
+ add ebx, ecx
+ add edx, ecx
+l7: cmp ecx, 0
+ je l12
+ dec ebx
+ dec edx
+ mov al, [es:ebx]
+ mov [es:edx], al
+ dec ecx
+ jmp l7
+l12: ret
+
+diskload: ; ecx-fromdisk ebx-tomem
+ push ebx
+ call file_seek
+ mov cx, 1024
+ mov ah, 3fh
+ mov bx, [fileh]
+ mov dx, buf
+ int 21h
+
+ sub ebx, ebx ; move it to XMS
+ mov bx, cs
+ shl ebx, 4
+ add ebx, buf
+ pop edx
+ mov ecx, 1024
+ call memmove ; ebx - from, edx - to, ecx - amount
+ ret
+
+include 'system.inc'
+include 'kbdrive.inc'
+
+buf: ; pointer to end of the code
--- /dev/null
+; Opcodes 0-9: nop, halt, kbd@, num, jmp, call, inc, dec, dup, drop
+; Opcode 0 (xnop) is handled inline as the emu loop entry point.
+; Opcode 1 (xhalt/quit) is handled in the main emulator file.
+
+xkbd@: call KB_read
+ sub edi, 4
+ mov [es:edi], dl
+
+ mov ah, 0bh ; check for key in keyboard buffer
+ int 21h
+ cmp al, 0h
+ je emu
+ mov ah, 0 ; read key
+ int 16h
+ jmp emu
+
+xnum: mov edx, dword [es:esi]
+ sub edi, 4
+ mov [es:edi], edx
+ add esi, 4
+ jmp emu
+
+xjmp: mov esi, dword [es:esi]
+ add esi, [xms_addr]
+ jmp emu
+
+xcall: mov edx, dword [es:esi]
+ mov eax, [resp]
+ sub eax, 4
+ mov ebx, esi
+ add ebx, 4
+ sub ebx, [xms_addr]
+ mov [es:eax], ebx
+ mov [resp], eax
+ mov esi, edx
+ add esi, [xms_addr]
+ jmp emu
+
+xinc: ; Increment: ( n -- n+1 )
+; Increments the top of the data stack by 1.
+
+ inc dword [es:edi]
+ jmp emu
+
+
+xdec: ; Decrement: ( n -- n-1 )
+;
+; Decrements the top of the data stack by 1.
+;
+; Memory layout before execution:
+; [es:edi] = n
+;
+; Memory layout after execution:
+; [es:edi] = n-1
+
+ dec dword [es:edi] ; decrement the top of the stack
+ jmp emu
+
+
+xdup: ; Duplicate: ( n -- n n )
+;
+; Duplicates the top element of the data stack.
+;
+; Memory layout before execution:
+; [es:edi] = n
+;
+; Memory layout after execution:
+; [es:edi] = n (new top)
+; [es:edi+4] = n (original top)
+
+ mov eax, [es:edi] ; copy top element to eax
+ sub edi, 4 ; move stack pointer down to make space
+ mov [es:edi], eax ; push copy of top element onto stack
+ jmp emu
+
+
+xdrop: ; Drop: ( n -- )
+;
+; Removes the top element from the data stack.
+;
+; Memory layout before execution:
+; [es:edi] = n
+;
+; Memory layout after execution:
+; Stack pointer is adjusted; n is no longer on stack
+
+ add edi, 4 ; pop top element off the stack
+ jmp emu