Hi Everyone,
Regarding CPC Interupts.
What is the most reliable way to patch interrupts from BASIC's point of view? Usually I just intercepted #0038, is there a better way?
Quick answer... NEVER do that in Basic! The firmware has some nice vectors to allow plugging your own asm code every 50 or 300hz. Sorry I don't have the doc right now, make a quick search, but if you don't find anything, please say so. Stay BASIC compliant when doing Basic!
You need to add your handler to one of BASIC's "tick" lists using the relevant firmware calls. The ROM will only call a handler at 0038 in response to an external interrupt (i.e. one not from the gate array) and so putting a hook there will be unreliable, as it will normally only be called if RAM happens to be paged in at the time the interrupt occurs.
You can find the vectors here (http://www.grimware.org/doku.php/documentations/firmware/guide/jumpblock#highkernel.jumpblock) (the ones that are useful to you start at #bcd7). Some examples are here (http://quasar.cpcscene.net/doku.php?id=iassem:kernel). This is in french, but the "programme 3" at the bottom is exactly what you need at have your asm code called every 50hz.
Quote from: zhulien on 02:27, 04 December 19
Hi Everyone,
Regarding CPC Interupts.
What is the most reliable way to patch interrupts from BASIC's point of view? Usually I just intercepted #0038, is there a better way?
You can use events to configure system friendly way of calling functions at regular time intervals.
Check details on KL NEW FAST TICKER (&BCE0) for 1/300th sec. and KL ADD TICKER (&BCE9) for 1/50th second.
Thanks. I am guessing the basic vectors handle whether roms are enabled or not? Can our code lie in rom also or only in central ram?
The lower ROM is effectively fixed, so if you want your code to work while the firmware is active, you have to play by its rules. And one of those rules is using the firmware functions to add or remove interrupt events.
that might explain why my MCP POC althought it is multitasking, seems to be running a little slower than it should - likely missing lots of ticks.
Quote from: zhulien on 00:32, 05 December 19
Thanks. I am guessing the basic vectors handle whether roms are enabled or not?
Yes, you specify the rom in C register.
Quote
Can our code lie in rom also or only in central ram?
The event block needs to be in the central 32kb of ram. The routine to execute can be anywhere, even in rom, but it executes faster when located in the central 32kb (no rom switching etc)
Any suggested ISR improvements in my POC code?
https://drive.google.com/drive/folders/1Xvirgaep8dHFQUSaQxa5aQRV_SIbAfbR (https://drive.google.com/drive/folders/1Xvirgaep8dHFQUSaQxa5aQRV_SIbAfbR)
(the patching #0038 code is commented out and the firmware tickers are used)
; MCP cpc z80 rom
; Written by Julian, 2018
; www.8bitology.com
; TODO:
; implement stack for tasks
; implement task priorities
; implement R for reserved blocks, |reserve, |unreserve
; implement single instance tasks
; implement |snapshot, |restore & |autorestore
; optimisations such as when 1 task (no need to switch contexts)
; heap memory model, 4k per task? 8k per task? then 8k per heap?
org #c000
write direct -1,1,#C0
;adr_isr equ #0039
;adr_isr_intercept equ #b941
adr_sysstatus equ #be80 ;16 bytes
adr_sysstatus_backup equ #be90 ;16 bytes
adr_tickereventblock equ #bea0 ;10 bytes
adr_eidi equ #beaa ;1 byte
;adr_delaycount equ #bbab ;2 bytes
adr_taskcount equ #bead ;1 byte
adr_currenttask equ #bbad ;1 byte, 0 based
adr_taskblocksize equ #bbaf ;1 byte
adr_taskblock equ #beb0 ;33 bytes
;adr_isrhandler equ #8000 ;#bed0 ;unknown bytes
; CPC firmware entry points
SYSTEM_RESTART equ #0000
KM_READ_KEY equ #bb1b
TXT_OUT_CHAR equ #bb5a
CAS_IN_OPEN equ #bc77
CAS_IN_CLOSE equ #bc7a
CAS_IN_DIRECT equ #bc83
KL_NEW_FAST_TICKER equ #bce0
KL_DELETE_FAST_TICKER equ #bce6
; CPC ROM header
defb 1 ; background ROM
defb 1 ; mark
defb 0 ; version
defb 0 ; modification
defw rsx_names
; RSX jumpblock
jp rom_init
; general
jp rsx_help
jp rsx_version
jp rsx_status
jp rsx_status
jp rsx_tasks
jp rsx_tasks
; task related
jp rsx_spawn
jp rsx_spawn
jp rsx_kill
jp rsx_kill
jp rsx_autostart
jp rsx_autostart
jp rsx_reboot
jp rsx_reboot
jp rsx_start
jp rsx_start
jp rsx_stop
jp rsx_stop
jp rsx_recover
jp rsx_recover
; system related
;jp rsx_autorestore
;jp rsx_snapshot
;jp rsx_restore
rsx_names: defb 'MASTER CONTRO', 'L'+#80
defb 'MCPHEL', 'P'+#80
defb 'MCPVERSIO', 'N'+#80
defb 'MCPSTATU', 'S'+#80
defb 'STATU', 'S'+#80
defb 'MCPTASK', 'S'+#80
defb 'TASK', 'S'+#80
defb 'MCPSPAW', 'N'+#80
defb 'SPAW', 'N'+#80
defb 'MCPKIL', 'L'+#80
defb 'KIL', 'L'+#80
defb 'MCPAUTOSTAR', 'T'+#80
defb 'AUTOSTAR', 'T'+#80
defb 'MCPREBOO', 'T'+#80
defb 'REBOO', 'T'+#80
defb 'MCPSTAR', 'T'+#80
defb 'STAR', 'T'+#80
defb 'MCPSTO', 'P'+#80
defb 'STO', 'P'+#80
defb 'MCPRECOVE', 'R'+#80
defb 'RECOVE', 'R'+#80
;defb 'MCPAUTORESTOR', 'E'+#80
;defb 'MCPSNAPSHO', 'T'+#80
;defb 'MCPRESTOR', 'E'+#80
defb 0
; --------------------------------------------------
; help for RSXs are in the order that we want to display the entire online help
hlp_all:
hlp_help: defb '|mcphelp - Displays online help.', 0
hlp_version: defb '|mcpversion - Displays the current MCP version.', 0
hlp_status: defb '|mcpstatus - Displays system statistics.', 0
hlp_tasks: defb '|mcptasks - Lists current tasks.', 0
hlp_spawn: defb '|mcpspawn,"<filename>" - Loads and runs a new task.', 0
hlp_kill: defb '|mcpkill,<taskid> - Kills the specified task and frees up resources.', 0
hlp_autostart: defb '|mcpautostart - Automatically start tasks upon reset.', 0
hlp_reboot: defb '|mcpreboot - Reboot the computer preserving the running status of tasks.', 0
hlp_start: defb '|mcpstart - Manually start tasks.', 0
hlp_stop: defb '|mcpstop - Manually stop all tasks.', 0
hlp_recover: defb '|mcprecover - Attempts to recover the system.', 0
; NOT YET IMPLEMENTED
; hlp_autorestore: ;defb '|mcpautorestore - Automatically restore the computer state and resume tasks on reset.', 0
; hlp_snapshot: ;defb '|mcpsnapshot - Manually save the computer state.', 0
; hlp_restore: ;defb '|mcprestore - Manually restore the computer state and resume tasks.', 0
defb 0 ; terminator for |help
; system statuses & messages
msg_signon: defb ' MCP', 0
msg_space: defb ' ', 0
msg_version: defb '1.1', 0
msg_newline: defb 13, 10, 0
msg_tasks: defb 'tasks: ', 0
msg_sysstatus: defb 'backup: ', 0
msg_fileload_err: defb 'File failed to load.', 0
msg_kill_err: defb 'Cannot kill requested task.', 0
msg_spawn_err: defb 'Cannot spawn this task. Memory full?', 0
;status_autorestore: ;defb 'AUTORESTORE', 0
status_autostart: defb 'AUTOSTART', 0
status_notstarted: defb 0
status_reboot: defb 'REBOOT', 0
status_running: defb 'RUNNING', 0
status_stopped: defb 'STOPPED', 0
status_mcpram: defb 'MCP', 0
; --------------------------------------------------
; system status functions
; ------------------------- check system status functions
; -- parameters:
; --
; -- return:
; -- Z if TRUE, NZ if FALSE
; -- corrupt:
; -- AF, DE, HL
;is_autorestore: ;ld hl, status_autorestore
; ld de, adr_sysstatus
; jp str_compare
is_autostart: ld hl, status_autostart
ld de, adr_sysstatus
jp str_compare
is_notstarted: ld hl, status_notstarted
ld de, adr_sysstatus
jp str_compare
is_reboot: ld hl, status_reboot
ld de, adr_sysstatus
jp str_compare
is_running: ld hl, status_running
ld de, adr_sysstatus
jp str_compare
is_stopped: ld hl, status_stopped
ld de, adr_sysstatus
jp str_compare
;was_autorestore: ;ld hl, status_autorestore
; ld de, adr_sysstatus_backup
; jp str_compare
was_autostart: ld hl, status_autostart
ld de, adr_sysstatus_backup
jp str_compare
was_notstarted: ld hl, status_notstarted
ld de, adr_sysstatus_backup
jp str_compare
was_reboot: ld hl, status_reboot
ld de, adr_sysstatus_backup
jp str_compare
was_running: ld hl, status_running
ld de, adr_sysstatus_backup
jp str_compare
was_stopped: ld hl, status_stopped
ld de, adr_sysstatus_backup
jp str_compare
; ------------------------- set system statuses
; -- parameters:
; -- HL = zero terminated status string
; -- return:
; -- Z if TRUE, NZ if FALSE
; -- corrupt:
; -- AF, BC, DE, HL
set_status: push hl
call str_len
inc bc ; we want to copy the string terminator also
pop hl
ld de, adr_sysstatus
ldir
ret
;set_autorestore: ;ld hl, status_autorestore
; jr set_status
set_autostart: ld hl, status_autostart
jr set_status
set_notstarted: ld hl, status_notstarted
jr set_status
set_reboot: ld hl, status_reboot
jr set_status
set_running: ld hl, status_running
jr set_status
set_stopped: ld hl, status_stopped
jr set_status
backup_status: push bc
push de
push hl
ld hl, adr_sysstatus
ld de, adr_sysstatus_backup
ld bc, 16
ldir
pop hl
pop de
pop bc
ret
restore_status: push bc
push de
push hl
ld hl, adr_sysstatus_backup
ld de, adr_sysstatus
ld bc, 16
ldir
pop hl
pop de
pop bc
ret
; --------------------------------------------------
; memory functions
ram_sel_main equ #7fc0
adr_ram_start equ #4000
adr_ram_status equ #4004
adr_file_load equ #4005
adr_2kbuffer equ #c000
ram_free equ 0
ram_used equ 1
; note:
; memory blocks for MCP start with 'MCP', 0, <status>, <taskheader>
; task header 1 (version), 1 or 0 (1 instance or multi), <taskentryaddr>, 'TASKNAME', 0..
;model for 6128
;ram_model_name: ;defb '64K Extra RAM', 0
;def_taskblock: ;defb '----', 0 ;printable taskblock, contains - and *
;ram_sel_port_count equ 4
;ram_sel_ports: ;defw #7fc4, #7fc5, #7fc6, #7fc7
;model for CPC+DKTronic 512K
ram_model_name: defb '512K Extra Ram', 0
def_taskblock defb '--------------------------------', 0 ;printable taskblock, contains - and *
ram_sel_port_count equ 32
ram_sel_ports: defw #7fc4, #7fc5, #7fc6, #7fc7
defw #7fcc, #7fcd, #7fce, #7fcf
defw #7fd4, #7fd5, #7fd6, #7fd7
defw #7fdc, #7fdd, #7fde, #7fdf
defw #7fe4, #7fe5, #7fe6, #7fe7
defw #7fec, #7fed, #7fee, #7fef
defw #7ff4, #7ff5, #7ff6, #7ff7
defw #7ffc, #7ffd, #7ffe, #7fff
; ------------------------- initialise RAM - no interrupts
ram_initialise: ld b, ram_sel_port_count
ld hl, ram_sel_ports
ram_initialise_loop: push bc
ld c, (hl)
inc hl
ld b, (hl)
inc hl
out (c), c
push af
push bc
push de
push hl
ld hl, status_mcpram
push hl
call str_len
inc bc
pop hl
ld de, adr_ram_start
ldir
xor a
ld (adr_ram_status), a
pop hl
pop de
pop bc
pop af
pop bc
djnz ram_initialise_loop
ld bc, ram_sel_main
out (c), c
ret
; ------------------------- initialise the taskblock - no interrupts
taskblock_initialise: xor a
ld (adr_taskcount), a ; no task count
ld hl, def_taskblock
push hl
call str_len
ld a, c
ld (adr_taskblocksize), a
pop hl
ld de, adr_taskblock
ldir
ld b, ram_sel_port_count
ld hl, ram_sel_ports
ld de, 0
taskblock_initialise_loop:
push bc
ld c, (hl)
inc hl
ld b, (hl)
inc hl
out (c), c
push hl
push de
ld hl, status_mcpram
ld de, adr_ram_start
call str_compare
jr nz, taskblock_initialise_skip
ld a, (adr_ram_status)
and a
jr z, taskblock_initialise_skip
ld hl, adr_taskcount
inc (hl)
pop de
push de
ld a, '*'
ld hl, adr_taskblock
add hl, de
ld (hl), a
taskblock_initialise_skip:
pop de
inc de
pop hl
pop bc
djnz taskblock_initialise_loop
ld bc, ram_sel_main
out (c), c
ret
; ------------------------- find and select free block of RAM - no interrupts
; -- parameters:
; --
; -- return:
; -- Z if TRUE, NZ if FALSE
; -- DE = task number
; -- corrupt:
; -- AF, BC, HL
ram_findfree: ld b, ram_sel_port_count
ld hl, ram_sel_ports
ld de, 0
ram_findfree_loop: push bc
ld c, (hl)
inc hl
ld b, (hl)
inc hl
out (c), c
push de
push hl
ld hl, status_mcpram
ld de, adr_ram_start
call str_compare
jr nz, ram_findfree_next
ld a, (adr_ram_status)
and a
jr z, ram_findfree_found
ram_findfree_next: pop hl
pop de
inc de
pop bc
djnz ram_findfree_loop
ld de,0
ld a, 1
and a
ret
ram_findfree_found: pop hl
pop de
pop bc
xor a
ret
; ------------------------- find and select block of RAM by task number - no interrupts
; -- parameters:
; -- A = task number
; -- return:
; -- Z if TRUE, NZ if FALSE
; -- DE = task
; -- corrupt:
; -- AF, BC, HL, IX
ram_findbytask: ld b, ram_sel_port_count
ld hl, ram_sel_ports
ld de, 0
ld ix, 0
ld d, a ; put a into d, later d and e should equal
ram_findbytask_loop: push bc
ld c, (hl)
inc hl
ld b, (hl)
inc hl
out (c), c
push hl
push de
ld hl, status_mcpram
ld de, adr_ram_start
call str_compare
pop de
jr nz, ram_findbytask_next
ld a, (adr_ram_status)
and a
jr z, ram_findbytask_next
inc de
ld a,d
cp e
jr z, ram_findbytask_found
ram_findbytask_next: inc ix
pop hl
pop bc
djnz ram_findbytask_loop
ld a, 1
and a
ret
ram_findbytask_found: pop hl
pop bc
push ix
pop de
xor a
ret
; ------------------------- restore RAM from disc
;ram_restore: ;and a
; ret ; TODO IMPLEMENT
; ------------------------- snapshot RAM to disc
;ram_snapshot: ;ret ; TODO IMPLEMENT
; --------------------------------------------------
; file functions
; ------------------------- file_load - no interrupts?
; -- parameters:
; -- HL = filename address
; -- DE = file load destination
; -- return:
; -- Z if TRUE, NZ if FALSE
; -- corrupt:
; -- AF, BC, DE, HL
file_load: call CAS_IN_OPEN
;di
jr nc, file_load_err
ld hl, adr_file_load
call CAS_IN_DIRECT
;di
jr nc, file_load_err
call CAS_IN_CLOSE
;di
xor a
ret
file_load_err: ld hl, msg_fileload_err
call str_outputln
ld a, 1
and a
ret
; --------------------------------------------------
; string functions
; ------------------------- str_compare
; -- parameters:
; -- HL = zero terminated string source of truth
; -- DE = string to compare
; -- return:
; -- Z if TRUE, NZ if FALSE
; -- corrupt:
; -- AF, DE, HL
str_compare: ex de, hl
ld a, (de)
cp (hl)
ret nz ; false match return
and a
ret z ; end of string return
inc hl
inc de
jr str_compare
; ------------------------- str_len
; -- parameters:
; -- HL = zero terminated string
; -- return:
; -- BC = length
; -- corrupt:
; -- AF, BC, HL
str_len: ld bc, 0
str_len_lp: ld a,(hl)
and a
ret z
inc bc
inc hl
jr str_len_lp
; ------------------------- number output from wikiti.brandonw.net/index.php?title=Z80_Routines Other DispA - no interrupts?
; -- parameters:
; -- HL = zero terminated string
; -- return:
; --
; -- corrupt:
; -- AF, HL
str_numberoutput: ld c,-100
call str_numberoutput1
ld c,-10
call str_numberoutput1
ld c,-1
str_numberoutput1: ld b,'0'-1
str_numberoutput2: inc b
add a,c
jr c, str_numberoutput2
sub c ;works as add 100/10/1
push af ;safer than ld c,a
ld a,b ;char is in b
call TXT_OUT_CHAR
di
pop af ;safer than ld a,c
ret
; ------------------------- string output - no interrupts?
; -- parameters:
; -- HL = zero terminated string
; -- return:
; --
; -- corrupt:
; -- AF, HL
str_output: ld a, (hl)
and a
ret z
call TXT_OUT_CHAR
di
inc hl
jr str_output
; ------------------------- string output and a newline - no interrupts?
; -- parameters:
; -- HL = zero terminated string
; -- return:
; --
; -- corrupt:
; -- AF, HL
str_outputln: call str_output
push hl
ld hl, msg_newline
call str_output
pop hl
ret
; ------------------------- output info for a task - no interrupts?
; -- parameters:
; --
; -- return:
; -- A = task number
; -- corrupt:
; -- AF, HL
taskinfo_output: call str_numberoutput
ld hl, msg_space
call str_output
ld hl, adr_ram_status
inc hl ; skip memory status
inc hl ; skip task header version (since only 1 for now, future we should check and do as appropriate)
inc hl ; skip single/multi
inc hl ; skip entryaddr
inc hl ;
call str_outputln
ret
; --------------------------------------------------
; system functions
; ------------------------- boot the system
; ------------------------- enable interrupts (supports nesting)
sys_ei: push af
push hl
ld hl, adr_eidi
dec (hl)
ld a, (adr_eidi)
and a
jr nz, sys_ei_return
ei
;ld a, #43
;ld (adr_isr_intercept), a
sys_ei_return: pop hl
pop af
ret
; ------------------------- disable interrupts (supports nesting)
sys_di: di
push hl
ld hl, adr_eidi
inc (hl)
;push af
;ld a, #c9
;ld (adr_isr_intercept), a
;pop af
pop hl
ret
sys_isr_boot: call sys_di
call ram_initialise
call taskblock_initialise
call sys_isr_patch
call sys_ei
ret
; ------------------------- recover the system
sys_isr_recover: call sys_di
ld bc, ram_sel_main
out (c), c
call taskblock_initialise
call sys_isr_patch
call sys_ei
ret
; ------------------------- stop the system
sys_isr_stop: call sys_di
call sys_isr_unpatch
call sys_ei
ret
; ------------------------- patch the ISR - no interrupts
sys_isr_patch: ;ld de, adr_isrhandler
;ld hl, sys_isr_start
;ld bc, sys_isr_end - sys_isr_start
;ldir
;ld hl, (adr_isr) ; preserve old ISR
;ld (adr_tickereventblock), hl
xor a
ld (adr_currenttask), a ; no current task
;ex de, hl
;ld hl, adr_isrhandler
;inc hl
;ld (hl), e
;inc hl
;ld (hl), d
;ld hl, adr_isrhandler ; patch the ISR
;ld (adr_isr), hl
ld hl, adr_tickereventblock
ld b,%10000010 ; asynchronous event, priority 1
ld c,#01 ; rom select or #80 or #01
ld de, sys_isr_start ; patch the ISR
call KL_NEW_FAST_TICKER
di
ret
; ------------------------- unpatch the ISR - no interrupts
sys_isr_unpatch: ;ld hl, (adr_tickereventblock)
;ld (adr_isr), hl ; patch the ISR
ld hl, adr_tickereventblock
call KL_DELETE_FAST_TICKER
di
ret
; -------------------------
; ROM Initialisation
rom_init: push af
push bc
push de
push hl
xor a ; initialise ei, di to allow nesting
ld (adr_eidi), a
;ld hl, 300 ; 300 is about 1 second
;ld (adr_delaycount), hl
call KM_READ_KEY ; stop if any key is pressed
call c, set_stopped
call rom_init_isstopped ; stopped remains stopped
call rom_init_isautostart ; autostart remains autostart
call rom_init_isrunning ; running becomes stopped
call rom_init_isreboot ; reboot becomes running
call rom_init_isnotstarted
ld hl, msg_signon ; signon
call str_output
ld hl, msg_space
call str_output
ld hl, msg_version
call str_output
ld hl, msg_space
call str_output
ld hl, ram_model_name
call str_output
ld hl, msg_space
call str_output
ld hl, adr_sysstatus
call str_outputln
ld hl, msg_newline
call str_output
;call fn_do_autorestore ; goto fn_do_restore if autorestore
pop hl
pop de
pop bc
pop af
ret ; return if no autostart and no autorestore
rom_init_isstopped: call is_stopped
ret nz ; return if wasn't previously stopped
jp set_stopped
rom_init_isautostart: call is_autostart
ret nz ; return if wasn't autostart
call sys_isr_recover
jp set_autostart
rom_init_isrunning: call is_running
ret nz ; return if wasn't running
jp set_stopped
rom_init_isreboot: call is_reboot
ret nz ; return if wasn't reboot
call set_running
call backup_status
jp sys_isr_recover
rom_init_isnotstarted: call is_notstarted
ret nz ; return if wasn't not started
jp set_notstarted
; --------------------------------------------------
; RSX entry with parameter checking and help
; ------------------------- turn on 'autorestore' & start
;rsx_autorestore: ;and a
; jr z, fn_autorestore ; checked required number of parameters
;
; ; else
; ld hl, hlp_autorestore
; jp str_outputln ; display online help
;
;fn_autorestore: ;call is_autorestore
; ret z ; return if was already autorestore
;
; call is_running
; jp z, set_autorestore ; if running, set the autostart status, but don't start again
;
; call fn_restore
; jp set_autorestore
;
;fn_do_autorestore: ;call is_autorestore
; ret nz ; return if wasn't autorestore
;
; call fn_restore
; jp set_autorestore
; ------------------------- turn on 'autostart' & start
rsx_autostart: and a
jr z, fn_autostart
ld hl, hlp_autostart
jp str_outputln
fn_autostart: jp set_autostart
; ------------------------- display help
rsx_help: and a
jr z, fn_help
ld hl, hlp_help
jp str_outputln
fn_help: ld hl, hlp_all
fn_help_lp: ld a, (hl)
and a
ret z ; no more help
call str_outputln
inc hl
jr fn_help_lp
; ------------------------- kill a task and free up resources
rsx_kill: cp 1
jr z, fn_kill
ld hl, hlp_kill
jp str_outputln
fn_kill: call sys_di
ld a, (ix+0)
call ram_findbytask
jr nz, fn_kill_err
xor a
ld (adr_ram_status), a
ld a, '-'
ld hl, adr_taskblock
add hl, de
ld (hl), a
ld bc, ram_sel_main
out (c), c
call sys_ei
ld hl, adr_taskcount
dec (hl)
ret
fn_kill_err: ld bc, ram_sel_main
out (c), c
call sys_ei
ld hl, msg_kill_err
jp str_outputln
; ------------------------- reboot, if the status is running, restart the tasks
rsx_reboot: and a
jr z, fn_reboot
ld hl, hlp_reboot
jp str_outputln
fn_reboot: call is_running
jr z, fn_reboot_restart
call is_autostart
jr z, fn_reboot_autostart
call fn_stop
call set_notstarted
jp SYSTEM_RESTART
fn_reboot_restart: call fn_stop
call set_reboot
jp SYSTEM_RESTART
fn_reboot_autostart: call fn_stop
jp SYSTEM_RESTART
; ------------------------- attempt to recover a system that wasnt stopped. just 'running' & boot
rsx_recover: and a
jr z, fn_recover
ld hl, hlp_recover
jp str_outputln
fn_recover: call set_stopped
jp sys_isr_recover
; ------------------------- stop, then restore, then start
;rsx_restore: ;and a
; jr z, fn_restore
;
; ld hl, hlp_restore
; jp str_outputln
;
;fn_restore: ;call fn_stop
; call ram_restore
; call sys_isr_recover
; ret
; ------------------------- 'stop' & stop the system
rsx_stop: and a
jr z, fn_stop
ld hl, hlp_stop
jp str_outputln
fn_stop: call set_stopped
jp sys_isr_stop
; ------------------------- snapshot
;rsx_snapshot: ;and a
; jr z, fn_snapshot
;
; ld hl, hlp_snapshot
; jp str_outputln
;
;fn_snapshot: ;call fn_stop
; jp ram_snapshot
; ------------------------- load and run a task
rsx_spawn: cp 1
jr z, fn_spawn
ld hl, hlp_spawn
jp str_outputln
fn_spawn: call sys_di
call backup_status
call fn_stop
ld l, (ix+0)
ld h, (ix+1)
ld b, (hl) ; get the filename length
ld a,b
and a
jr z, fn_spawn_err ; no filename
inc hl
ld e, (hl) ; get the filename address
inc hl ;
ld d, (hl) ;
ex de, hl
push bc
push hl
call ram_findfree
pop hl
pop bc
jr nz, fn_spawn_err
push de
ld de, adr_2kbuffer
call file_load
pop de
jr nz, fn_spawn_err
ld a, 1
ld (adr_ram_status), a
ld a, '*'
ld hl, adr_taskblock
add hl, de
ld (hl), a
ld bc, ram_sel_main
out (c), c
ld hl, adr_taskcount
inc (hl)
; call was_autorestore
; call z, fn_resume
call was_autostart
call z, fn_resume
call was_running
call z, fn_resume
call restore_status
call sys_ei
ret
fn_spawn_err: ld bc, ram_sel_main
out (c), c
; call was_autorestore
; call z, fn_resume
call was_autostart
call z, fn_resume
call was_running
call z, fn_resume
call restore_status
call sys_ei
ld hl, msg_spawn_err
jp str_outputln
; ------------------------- if autorestore or autostart then just boot. if not running, then 'running' & boot
rsx_start: and a
jr z, fn_start
ld hl, hlp_start
jp str_outputln
fn_start: call is_running
ret z ; return if was already running
call is_reboot
jp z, fn_resume
call is_autostart
jp z, fn_resume
; call is_autorestore
; jp z, sys_isr_boot ; boot if autorestore
call is_stopped ; if stopped then restart
jp z, fn_resume
call is_autostart
jp z, sys_isr_boot ; boot if autostart
; else
call set_running ; set to running
call sys_isr_boot ; then boot
xor a
ret
fn_resume: call set_running
jp sys_isr_recover
; ------------------------- display system stats
rsx_status: and a
jr z, fn_status
ld hl, hlp_status
jp str_outputln
fn_status:
ld hl, adr_sysstatus
call str_outputln
;ld hl, msg_sysstatus
;call str_output
;ld hl, adr_sysstatus_backup
;call str_outputln
ret
; ------------------------- list current tasks
rsx_tasks: and a
jr z, fn_tasks
ld hl, hlp_tasks
jp str_outputln
fn_tasks: ld hl, adr_taskblock
call str_outputln
call sys_di
call backup_status
call fn_stop
ld b, ram_sel_port_count
ld hl, ram_sel_ports
ld de, 0
fn_tasks_loop: push bc
ld c, (hl)
inc hl
ld b, (hl)
inc hl
out (c), c
push hl
push de
ld hl, status_mcpram
ld de, adr_ram_start
call str_compare
pop de
jr nz, fn_tasks_next
ld a, (adr_ram_status)
and a
jr z, fn_tasks_next
inc de
push af
push hl
ld a, e
call taskinfo_output
pop hl
pop af
fn_tasks_next: pop hl
pop bc
djnz fn_tasks_loop
ld hl, msg_tasks
call str_output
ld a, (adr_taskcount)
call str_numberoutput
ld hl, msg_newline
call str_output
ld bc, ram_sel_main
out (c), c
; call was_autorestore
; call z, fn_resume
call was_autostart
call z, fn_resume
call was_running
call z, fn_resume
call restore_status
call sys_ei
ret
; ------------------------- display system version
rsx_version: and a
jr z, fn_version
ld hl, hlp_version
jp str_outputln
fn_version: ld hl, msg_version
jp str_outputln
; user functions, task related
;sys_isr_wait: ;ld hl, (adr_delaycount)
; ld a, h
; or l
; ret z
;
; dec hl
; ld (adr_delaycount), hl
; ret
sys_isr_start: ;call 0 ; old ISR is here
call sys_di
push af
ld a, (adr_taskcount)
and a
jr z, sys_isr_return
push bc
push de
push hl
push ix
push iy
exx
ex af, af'
push af
push bc
push de
push hl
exx
;call sys_isr_wait
;jr nz, sys_isr_exit
; need to switch to bank of current task
ld de, 0
ld a, (adr_currenttask)
ld e, a
sys_isr_start_loop: push de
; now check for next runnable task
ld hl, adr_taskblock
add hl, de
ld a, (hl)
and a
jr z, sys_isr_start_restart
cp '-'
jr z, sys_isr_start_skip
pop de
push de
ld l, e
ld h, d
add hl, de ; de = de * 2
ld de, ram_sel_ports
add hl, de
ld c, (hl) ; find the port and address to switch to
inc hl
ld b, (hl)
out (c), c
;ld a, (adr_currenttask)
;call str_numberoutput
;ld hl, msg_newline
;call str_output
pop de
jr sys_isr_start_continue
sys_isr_start_skip: pop de
inc de
jr sys_isr_start_loop
sys_isr_start_restart:
pop de
xor a
ld (adr_currenttask), a
ld de, 0
jr sys_isr_start_loop
sys_isr_start_continue:
; pass control to the task
ld hl, adr_ram_status
inc hl ; skip memory status
inc hl ; skip task header version (since only 1 for now, future we should check and do as appropriate)
inc hl ; skip single/multi
ld e, (hl)
inc hl
ld d, (hl)
call sys_isr_callde
jr sys_isr_callde_continue
sys_isr_callde:
push de ; call de
ret ;
sys_isr_callde_continue:
;ld a, e
;call str_numberoutput
;ld hl, msg_newline
;call str_output
;call #4012
; work out the next task
ld hl, adr_currenttask
inc (hl)
ld bc, ram_sel_main
out (c), c
sys_isr_exit: exx
pop hl
pop de
pop bc
pop af
ex af, af'
exx
pop iy
pop ix
pop hl
pop de
pop bc
sys_isr_return:
pop af
call sys_ei
ret
sys_isr_end: