0576d2dfa1
* Add files via upload * a monolithic build recipe for ZX Spectrum * emulation and emulated tapes in README.md
263 lines
6.3 KiB
NASM
263 lines
6.3 KiB
NASM
.equ IYBAS 23610 ; user.h
|
|
; The ZX Spectrum firmware requires IY value to be equal to 23610
|
|
; (in this case, to handle keyboard interrupts and screen correctly).
|
|
; an IM2 handler has to be included to manage this.
|
|
|
|
.equ RAMEND 0xffff ; user.h
|
|
|
|
.equ USER_CODE 41639 ; = BAS_RAMEND+527 in user.h
|
|
; when changing the memory layout, it should have a dummy value for a test assembly,
|
|
; then changed to the actual value in relation to the new BAS_RAMEND
|
|
|
|
.org 0x5efd
|
|
|
|
jp init
|
|
|
|
.inc "err.h"
|
|
.inc "ascii.h"
|
|
.inc "blkdev.h"
|
|
.inc "fs.h"
|
|
|
|
.inc "kernel/zxs/jumps.asm"
|
|
|
|
.inc "core.asm"
|
|
.inc "kernel/str.asm"
|
|
|
|
.inc "kernel/zxs/vid.asm"
|
|
.inc "kernel/zxs/kbd.asm"
|
|
|
|
.equ GRID_COLS 32
|
|
.equ GRID_ROWS 21 ; to avoid CRLF outside of the #2 screen
|
|
.equ GRID_SETCELL v_putc
|
|
.equ GRID_GETC k_getc
|
|
.equ GRID_RAMSTART RAMSTART
|
|
.inc "kernel/grid.asm"
|
|
|
|
.equ BLOCKDEV_RAMSTART GRID_RAMEND
|
|
.equ BLOCKDEV_COUNT 4
|
|
.inc "kernel/blockdev.asm"
|
|
; List of devices
|
|
.dw mmapGetB, mmapPutB
|
|
.dw blk1GetB, blk1PutB
|
|
.dw blk2GetB, blk2PutB
|
|
.dw tapeGetB, unsetZ ;read-only
|
|
|
|
.equ STDIO_RAMSTART BLOCKDEV_RAMEND
|
|
.equ STDIO_GETC gridGetC
|
|
.equ STDIO_PUTC gridPutC
|
|
.equ STDIO_SETCUR gridSetCurH
|
|
.inc "kernel/stdio.asm"
|
|
|
|
.equ MMAP_START 0xc000 ; 49152
|
|
.equ MMAP_LEN RAMEND-MMAP_START+1
|
|
; 16K, 64 fs blocks for MMAP FS
|
|
.inc "kernel/mmap.asm"
|
|
|
|
.equ FS_RAMSTART STDIO_RAMEND
|
|
.equ FS_HANDLE_COUNT 2
|
|
.inc "kernel/fs.asm"
|
|
|
|
; BASIC shell
|
|
; RAM space used in different routines for short term processing.
|
|
.equ SCRATCHPAD_SIZE STDIO_BUFSIZE
|
|
.equ SCRATCHPAD FS_RAMEND
|
|
.inc "lib/util.asm"
|
|
.inc "lib/ari.asm"
|
|
.inc "lib/parse.asm"
|
|
.inc "lib/fmt.asm"
|
|
.equ EXPR_PARSE parseLiteralOrVar
|
|
.inc "lib/expr.asm"
|
|
.inc "basic/util.asm"
|
|
.inc "basic/parse.asm"
|
|
.inc "basic/tok.asm"
|
|
.equ VAR_RAMSTART SCRATCHPAD+SCRATCHPAD_SIZE
|
|
.inc "basic/var.asm"
|
|
.equ BUF_RAMSTART VAR_RAMEND
|
|
.equ BUF_POOLSIZE 0x800 ; 0x1000 by default, cut to save some RAM
|
|
.equ BUF_POOL shell_buf ; in contended memory
|
|
.equ BUF_MAXLINES 0x100
|
|
.equ BUF_LINES BUF_RAMSTART+4
|
|
.equ BUF_RAMEND @+BUF_MAXLINES*4 ; continue allocating in higher RAM
|
|
.inc "basic/buf.asm"
|
|
.equ BFS_RAMSTART BUF_RAMEND
|
|
.inc "basic/fs.asm"
|
|
.inc "basic/blk.asm"
|
|
.equ BAS_RAMSTART BFS_RAMEND
|
|
.inc "basic/main.asm"
|
|
|
|
; BASIC records the SP value, which is glue init value-2; the address of this storage +6 is BAS_RAMEND
|
|
; this is the value to be learned from a memory dump for user.h!
|
|
|
|
.equ tap_buffer BAS_RAMEND
|
|
.equ buf_pos @+256
|
|
.equ tap_pos @+1
|
|
.equ TAP_RAMEND @+8 ; user.h for assembling zxs/tapeutil.bin, BAS_RAMEND+265
|
|
.inc "kernel/zxs/tapeblk.asm"
|
|
|
|
;.equ USER_CODE BAS_RAMEND+527 ; 265 tapeblk + 262 tapeutil.bin below
|
|
|
|
.equ ZBCOUNT USER_CODE+14
|
|
tpztell:
|
|
; fetches the zasm internal counter (IO_OUT_BLK) at ZASM_RAMSTART+14
|
|
; it's called through 'addr ztell: s=a: usr s: print h'
|
|
ld hl, (ZBCOUNT)
|
|
xor a
|
|
ret
|
|
|
|
basFindCmdExtra:
|
|
ld hl, basBLKCmds
|
|
call basFindCmd
|
|
ret z
|
|
ld hl, basFSCmds
|
|
call basFindCmd
|
|
ret z
|
|
ld hl, .mycmds
|
|
call basFindCmd
|
|
ret z
|
|
jp basPgmHook
|
|
.mycmds:
|
|
.db "binsv", 0
|
|
.dw tapeutil
|
|
.db "binld", 0
|
|
.dw tapeutil+3
|
|
.db "head", 0
|
|
.dw tapeutil+6
|
|
.db "filsv", 0
|
|
.dw tapeutil+9
|
|
.db "filld", 0
|
|
.dw tapeutil+12
|
|
.db "cfssv", 0
|
|
.dw tapeutil+15
|
|
.db "cfsld", 0
|
|
.dw tapeutil+18
|
|
.db "cutsv", 0
|
|
.dw tapeutil+21
|
|
.db "ztell", 0
|
|
.dw tpztell
|
|
.db "ed", 0
|
|
.dw edrun
|
|
.db "zasm", 0
|
|
.dw zasmrun
|
|
.db 0xff
|
|
|
|
init:
|
|
di
|
|
ld sp, 0x8000
|
|
; if precise timings are needed,
|
|
; the stack should be moved to non-contended memory
|
|
call int_init
|
|
call v_init
|
|
call tapeblk_init
|
|
|
|
; init a FS in mmap
|
|
; possibly not needed in the final build
|
|
ld hl, MMAP_START
|
|
ld a, 'C'
|
|
ld (hl), a
|
|
inc hl
|
|
ld a, 'F'
|
|
ld (hl), a
|
|
inc hl
|
|
ld a, 'S'
|
|
ld (hl), a
|
|
|
|
call gridInit
|
|
|
|
call fsInit
|
|
xor a
|
|
ld de, BLOCKDEV_SEL
|
|
call blkSel
|
|
call fsOn
|
|
|
|
call basInit
|
|
ld hl, basFindCmdExtra
|
|
ld (BAS_FINDHOOK), hl
|
|
|
|
ei
|
|
jp basStart
|
|
|
|
; *** blkdev 1: file handle 0 ***
|
|
|
|
blk1GetB:
|
|
ld ix, FS_HANDLES
|
|
jp fsGetB
|
|
|
|
blk1PutB:
|
|
ld ix, FS_HANDLES
|
|
jp fsPutB
|
|
|
|
; *** blkdev 2: file handle 1 ***
|
|
|
|
blk2GetB:
|
|
ld ix, FS_HANDLES+FS_HANDLE_SIZE
|
|
jp fsGetB
|
|
|
|
blk2PutB:
|
|
ld ix, FS_HANDLES+FS_HANDLE_SIZE
|
|
jp fsPutB
|
|
|
|
int_init:
|
|
di
|
|
ld a,0x80
|
|
ld i,a
|
|
im 2
|
|
ret ; does not enable interrupts yet
|
|
|
|
tapeutil:
|
|
.bin "zxs/tapeutil.bin"
|
|
; all tape utilities in one block with library
|
|
; t_load ROM call routine is duplicated in zxs/tapeblk.asm in case those utilities are moved to userspace
|
|
|
|
; 0x7492 is free space, +2K=7c92, the rest 0x36e=878b for stack space
|
|
shell_buf:
|
|
; basic shell BUF_POOL points here
|
|
|
|
.fill 0x8000-$
|
|
; The ZX Spectrum hardware noises the CPU data bus so that any value can appear on interrupt instead of 0xFF.
|
|
; A 257-byte table is thus required to hold the INT handler address for IM2 mode.
|
|
|
|
; interrupt table = 128 words + 1 byte
|
|
.dw 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181
|
|
.dw 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181
|
|
.dw 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181
|
|
.dw 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181
|
|
.dw 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181
|
|
.dw 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181
|
|
.dw 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181
|
|
.dw 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181
|
|
.dw 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181
|
|
.dw 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181
|
|
.dw 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181
|
|
.dw 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181
|
|
.dw 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181
|
|
.dw 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181
|
|
.dw 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181
|
|
.dw 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181
|
|
.db 0x81
|
|
|
|
; the handler and the table are to reside in the non-contended memory, i.e. in 0x8000-0xC000
|
|
; (or rather in 0x8080-0xBFBF)
|
|
|
|
.fill 0x8181-$
|
|
|
|
; *** interrupt handler
|
|
; other possible int routines here, e.g. RS232 or debug calls
|
|
push iy
|
|
ld iy, IYBAS
|
|
rst 56
|
|
pop iy
|
|
ei
|
|
ret
|
|
|
|
;0x818c
|
|
edrun:
|
|
.bin "zxs/ed.bin" ;1108 = 0x0454
|
|
|
|
;0x85e0 = 0x818c+0x454
|
|
zasmrun:
|
|
.bin "zxs/zasm.bin" ;4881 = 0x1311
|
|
|
|
RAMSTART: ; 0x98f1 = 0x85e0+0x1311 (39153)
|
|
; bin length (14836)
|
|
|
|
|