News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_zhulien

CPC Interrupts

Started by zhulien, 02:27, 04 December 19

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

zhulien

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? 


Targhan

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!
Targhan/Arkos

Arkos Tracker 2.0.1 now released! - Follow the news on Twitter!
Disark - A cross-platform Z80 disassembler/source converter
FDC Tool 1.1 - Read Amsdos files without the system

Imperial Mahjong
Orion Prime

andycadley

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.

Targhan

You can find the vectors here (the ones that are useful to you start at #bcd7). Some examples are here. This is in french, but the "programme 3" at the bottom is exactly what you need at have your asm code called every 50hz.
Targhan/Arkos

Arkos Tracker 2.0.1 now released! - Follow the news on Twitter!
Disark - A cross-platform Z80 disassembler/source converter
FDC Tool 1.1 - Read Amsdos files without the system

Imperial Mahjong
Orion Prime

Docent

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.


zhulien

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?

andycadley

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.

zhulien

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.

Docent

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)

zhulien

Any suggested ISR improvements in my POC code?


https://drive.google.com/drive/folders/1Xvirgaep8dHFQUSaQxa5aQRV_SIbAfbR


(the patching #0038 code is commented out and the firmware tickers are used)

zhulien



; 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:

Powered by SMFPacks Menu Editor Mod