Add check for `fasm` installation in `compile.sh` script with optional prompt to...
authorSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Tue, 17 Feb 2026 00:01:23 +0000 (02:01 +0200)
committerSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Tue, 17 Feb 2026 00:01:23 +0000 (02:01 +0200)
emulator/emulator.asm
emulator/opcodes_00_09.inc [new file with mode: 0644]
emulator/opcodes_10_19.inc [new file with mode: 0644]
emulator/opcodes_20_29.inc [new file with mode: 0644]
emulator/opcodes_30_39.inc [new file with mode: 0644]
emulator/opcodes_40_47.inc [new file with mode: 0644]

index 8ad524c..6949925 100644 (file)
-; 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
diff --git a/emulator/opcodes_00_09.inc b/emulator/opcodes_00_09.inc
new file mode 100644 (file)
index 0000000..03a5fec
--- /dev/null
@@ -0,0 +1,88 @@
+; 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
diff --git a/emulator/opcodes_10_19.inc b/emulator/opcodes_10_19.inc
new file mode 100644 (file)
index 0000000..ab7b284
--- /dev/null
@@ -0,0 +1,84 @@
+; Opcodes 10-19: if, ret, c@, c!, push, pop, (unused), rot, disk@, disk!
+
+xif:   mov     eax, [es:edi]
+       add     edi, 4
+       cmp     eax, 0
+       jne     l2
+       mov     esi, [es:esi]
+       add     esi, [xms_addr]
+       jmp     emu
+l2:
+       add     esi, 4
+       jmp     emu
+
+xret:  mov     eax, [resp]
+       mov     esi, [es:eax]
+       add     esi, [xms_addr]
+       add     eax, 4
+       mov     [resp], eax
+       jmp     emu
+
+xc@:   mov     eax, [es:edi]
+       add     eax, [xms_addr]
+       sub     ecx, ecx
+       mov     cl, [es:eax]
+       mov     [es:edi], ecx
+       jmp     emu
+
+xc!:   ;( n addr -- )
+       mov     ebx, [es:edi]
+       add     edi, 4
+       mov     ecx, [es:edi]
+       add     edi, 4
+       add     ebx, [xms_addr]
+       mov     [es:ebx], cl
+       jmp     emu
+
+xpush: mov     ebx, [es:edi]
+       add     edi, 4
+       mov     eax, [resp]
+       sub     eax, 4
+       mov     [es:eax], ebx
+       mov     [resp], eax
+       jmp     emu
+
+xpop:  mov     eax, [resp]
+       mov     ebx, [es:eax]
+       add     eax, 4
+       mov     [resp], eax
+       sub     edi, 4
+       mov     [es:edi], ebx
+       jmp     emu
+
+xrot:  mov     ebx, [es:edi]
+       mov     ecx, [es:edi+4]
+       mov     edx, [es:edi+8]
+       mov     [es:edi+8], ecx
+       mov     [es:edi+4], ebx
+       mov     [es:edi], edx
+       jmp     emu
+
+xdisk@: mov    ebx, [es:edi]
+       add     ebx, [xms_addr]
+       mov     ecx, [es:edi+4]
+       add     edi, 8
+       call    diskload        ; ecx-fromdisk ebx-tomem
+       jmp     emu
+
+xdisk!: mov    ecx, [es:edi]
+       call    file_seek
+       mov     ecx, 1024
+       mov     ebx, [es:edi+4]
+       add     edi, 8
+       add     ebx, [xms_addr]
+       sub     edx, edx
+       mov     dx, cs
+       shl     edx, 4
+       add     edx, buf
+       call    memmove  ; ebx - from, edx - to, ecx - amount
+       mov     ah, 40h
+       mov     bx, [fileh]
+       mov     cx, 1024
+       mov     dx, buf
+       int     21h
+       jmp     emu
diff --git a/emulator/opcodes_20_29.inc b/emulator/opcodes_20_29.inc
new file mode 100644 (file)
index 0000000..fc2b828
--- /dev/null
@@ -0,0 +1,91 @@
+; Opcodes 20-29: @, !, over, swap, plus, minus, mul, div, great, less
+
+x@:    mov     eax, [es:edi]
+       add     eax, [xms_addr]
+       mov     eax, [es:eax]
+       mov     [es:edi], eax
+       jmp     emu
+
+x!:    ;( n addr -- )
+       mov     eax, [es:edi]
+       add     eax, [xms_addr]
+       mov     ecx, [es:edi+4]
+       add     edi, 8
+       mov     [es:eax], ecx
+       jmp     emu
+
+xover: mov     ebx, [es:edi+4]
+       sub     edi, 4
+       mov     [es:edi], ebx
+       jmp     emu
+
+xswap: mov     ebx, [es:edi]
+       xchg    ebx, [es:edi+4]
+       mov     [es:edi], ebx
+       jmp     emu
+
+xplus: mov     ebx, [es:edi]
+       add     edi, 4
+       add     [es:edi], ebx
+       jmp     emu
+
+
+xminus:
+; Subtract: ( n1 n2 -- n1-n2 )
+;
+; Pops the top two elements from the data stack, subtracts the top
+; element (n2) from the second element (n1), and pushes the result.
+;
+; In Fifth source code, this corresponds to the "-" word:
+;
+;     10 3 -       \ result is 7  (10 minus 3)
+;
+; Argument order:
+;   n1 is pushed first  (sits deeper in the stack, at [es:edi+4])
+;   n2 is pushed second (sits on top of the stack,  at [es:edi])
+;
+; Memory layout before execution:
+;   [es:edi]   = n2  (top of stack — the value being subtracted)
+;   [es:edi+4] = n1  (second on stack — the value subtracted from)
+;
+; Memory layout after execution:
+;   [es:edi]   = n1 - n2  (edi has been adjusted; old n2 slot is freed)
+
+    mov        ebx, [es:edi]           ; ebx = n2 (the subtrahend — value to subtract)
+       add     edi, 4                          ; pop n2 off the stack; n1 is now the new top
+       sub     [es:edi], ebx               ; [es:edi] = n1 - n2  (subtract n2 from n1 in place)
+       jmp     emu
+
+
+xmul:
+    mov        eax, [es:edi]
+       add     edi, 4
+       sub     edx, edx
+       imul dword [es:edi]
+       mov     [es:edi], eax
+       jmp     emu
+
+xdiv:  add     edi, 4
+       mov     eax, [es:edi]
+       cdq
+       idiv    dword [es:edi-4]
+       mov     [es:edi], eax
+       jmp     emu
+
+xgreat: mov    eax, [es:edi]
+       add     edi, 4
+       mov     edx, 0
+       cmp     [es:edi], eax
+       jng     l3
+       dec     edx
+l3:    mov     [es:edi], edx
+       jmp     emu
+
+xless: mov     eax, [es:edi]
+       add     edi, 4
+       mov     edx, 0
+       cmp     [es:edi], eax
+       jnl     l4
+       dec     edx
+l4:    mov     [es:edi], edx
+       jmp     emu
diff --git a/emulator/opcodes_30_39.inc b/emulator/opcodes_30_39.inc
new file mode 100644 (file)
index 0000000..a87a58b
--- /dev/null
@@ -0,0 +1,55 @@
+; Opcodes 30-39: not, i, cprt@, cprt!, i2, i3, shl, shr, or, xor
+
+xnot:  not     dword [es:edi]
+       jmp     emu
+
+xi:    mov  ebx, [resp]
+       mov     eax, [es:ebx]
+       sub     edi, 4
+       mov     [es:edi], eax
+       jmp     emu
+
+xcprt@: mov    dx, [es:edi]
+       in      al, dx
+       sub     ecx, ecx
+       mov     cl, al
+       mov     [es:edi], ecx
+       jmp     emu
+
+xcprt!: mov    dx, [es:edi]
+       mov     al, [es:edi+4]
+       add     edi, 8
+       out     dx, al
+       jmp     emu
+
+xi2:   mov ebx, [resp]
+       mov     eax, [es:ebx+4]
+       sub     edi, 4
+       mov     [es:edi], eax
+       jmp     emu
+
+xi3:   mov ebx, [resp]
+       mov     eax, [es:ebx+8]
+       sub     edi, 4
+       mov     [es:edi], eax
+       jmp     emu
+
+xshl:  mov     cl, [es:edi]
+       add     edi, 4
+       shl     dword [es:edi], cl
+       jmp     emu
+
+xshr:  mov     cl, [es:edi]
+       add     edi, 4
+       shr     dword [es:edi], cl
+       jmp     emu
+
+lor:   mov     eax, [es:edi]
+       add     edi, 4
+       or      [es:edi], eax
+       jmp     emu
+
+lxor:  mov     eax, [es:edi]
+       add     edi, 4
+       xor      [es:edi], eax
+       jmp     emu
diff --git a/emulator/opcodes_40_47.inc b/emulator/opcodes_40_47.inc
new file mode 100644 (file)
index 0000000..9b06324
--- /dev/null
@@ -0,0 +1,103 @@
+; Opcodes 40-47: vidmap, mouse@, vidput, cmove, cfill, tvidput, dep, charput
+
+xvidmap:
+       mov     edx, [es:edi]
+       add     edx, [xms_addr]
+       add     edi, 4
+       push    edi
+       push    esi
+       push    0a000h
+       pop     es
+       mov     word [ds:gra], 0
+       push    0
+       pop     ds
+       mov     esi, edx
+mapl1: mov     dx, [cs:gra]
+       xor     bx, bx
+       mov     ax, 4f05h
+       int     10h
+       mov     edi, 0
+       mov     cx, 4096
+;      mov     cx, 16384
+mapl2: mov     eax, [ds:esi]
+       add     esi, 4
+       stosd
+       loop    mapl2
+       inc     word [cs:gra]
+;      cmp     word [cs:gra], 5
+       cmp     word [cs:gra], 19
+       jne     mapl1
+       push    0
+       pop     es
+       push    cs
+       pop     ds
+       pop     esi
+       pop     edi
+       jmp     emu
+gra    dw 0
+
+
+xmouse@:
+       mov     ax, 0bh         ; read motion counter
+       int     33h
+       push    dx
+       sub     eax, eax
+       mov     ax, cx
+       cwd
+       shl     edx, 16
+       add     edx, eax
+       mov     [es:edi-4], edx
+       pop     ax
+       cwd
+       shl     edx, 16
+       add     edx, eax
+       mov     [es:edi-8], edx
+       mov     ax, 3           ; read buttons
+       int     33h
+       sub     eax, eax
+       mov     ax, bx
+       sub     edi, 12
+       mov     [es:edi], eax
+       jmp     emu
+
+xcmove: mov    ecx, [es:edi]
+       add     edi, 12
+       mov     edx, [es:edi-8]
+       add     edx, [xms_addr]
+       mov     ebx, [es:edi-4]
+       add     ebx, [xms_addr]
+       cmp     ecx, 0
+       je      emu
+       cmp     ebx, edx
+       ja      l8
+       call    memmove2
+       jmp     emu
+l8:    call    memmove
+       jmp     emu
+
+xcfill: mov    ecx, [es:edi]
+       mov     edx, [es:edi+4]
+       add     edx, [xms_addr]
+       mov     eax, [es:edi+8]
+       add     edi, 12
+l9:    cmp     ecx, 0
+       je      emu
+       mov     [es:edx], al
+       inc     edx
+       dec     ecx
+       jmp     l9
+
+xdep:  sub     eax, eax
+       mov     ax, cs
+       shl     eax, 4
+       add     eax, buf
+       add     eax, 20000
+       sub     eax, edi
+       shr     eax, 2
+       sub     edi, 4
+       mov     [es:edi], eax
+       jmp     emu
+
+include 'vidput.inc'
+include 'tvidput.inc'
+include 'charput.inc'