A possible COP handler to implement system callsCode:
; This COP software interrupt handler is intended to be used as
; interface to system call for bios/o.s.
; This handler can accept parameters passed by register and
; parameter passed by stack and in this case make stack cleanup.
; The COP instruction accept a signature byte so is possible
; handle 256 system calls (can be expanded with a second signature byte).
; The handler is table-driven: a table of 1024 bytes can hold the long
; pointer to implementation function (3 bytes) plus one byte that hold
; the bytes count of parameters on stack (4 bytes per function).
;
; For example suppose that we will implement a function that write N bytes
; to a file handle H from a buffer B, we need 3 parameters:
; 1) the handle H of file (2 byte)
; 2) the long pointer to buffer B (4 bytes)
; 3) the count N of bytes to write (2 bytes)
; the assumption here is that the max. number of bytes to write is $FFFF
; we suppose that the system call is the function number $xx, and that:
; H is stored in direct page location $hh and $hh+1
; long pointer to buffer is stored in direct page locations $bb, $bb+1, $bb+2
; N is stored in direct page locations $nn, $nn+1
; the sequence for call the function "write" is:
;
; pei ($hh) ; push H
; pei ($bb+2) ; push bank that hold buffer B
; pei ($bb) ; push address of buffer B
; pei ($nn) ; push N
; cop $xx ; call function "write"
; bcs ERROR ; carry mean error
; ... ; here ok, no failure
; ...
; ERROR: ; error handler
; ; Y hold the error code
;
; The handler use a table in bank 0 that hold the effective address
; of the routine that implement the function plus the count of bytes
; passed as parameters on stack; this table, labeled SYSTBL, need so
; of 4 bytes per function: 256*4 = 1024 bytes.
; Suppose that the implementation of the function "write" is
; at address $FFA673, and we know that the bytes counting of parameters
; is 8, at address SYSTBL + ($xx*4) we have stored the bytes:
;
; $73 $A6 $FF $08
;
; The handler call the right function and restore the stack before exit.
; It use 3 location in true page 0 (COPPtr, COPPtr+1, COPPtr+2) and modify
; the code itself (for call the right function) so is reentrant only if not
; called by an interrupt handler. Take care about this. But not need to call
; a system function in an interrupt handler. This long pointer in true page 0
; is used just to fetch the signature byte, while others variables are stored
; on stack so the effective implementation subroutine can call safety others
; system functions by way of the cop instruction (of course the implementation
; subroutine must be reentrant).
;
; below the stack frame after the handler save registers on the stack:
;
; ---------
; | PBR | 0F
; ---------
; | PCH | 0E
; ---------
; | PCL | 0D
; ---------
; | P | 0C
; ---------
; | B | 0B
; ---------
; | A | 0A
; ---------
; | XH | 09
; ---------
; | XL | 08
; ---------
; | YH | 07
; ---------
; | YL | 06
; ---------
; | DPH | 05
; ---------
; | DPL | 04
; ---------
; | DBR | 03
; ---------
; | CNTH | 02
; --------- --> CNT bytes count of parameters
; | CNTL | 01
; ---------
;
; equates for access stack offset data
STKCNT .SET $01
STKYR .SET $06
STKXR .SET $08
STKCR .SET $0A
STKBR .SET $0B
STKSR .SET $0C
STKPCL .SET $0D
STKPBR .SET $0F
STKNVAR .SET $0F
_COPhndl:
rep #$30 ; A/MEM/X/Y -> 16 bit
.LONGA on
.LONGI on
pha ; save C in stack
phx ; save X(16) in stack
phy ; save Y(16) in stack
phd ; save DPR in stack
phb ; save DBR in stack
lda #0
tax ; X = 0
pha ; params byte count in the stack ( = 0)
tcd ; set DPR = $0000
phk ; set DBR = PBR = $00
; remember that cop handler is in bank 0 !
plb
lda STKPCL,s ; load PC saved in stack
dec a ; pointer to signature byte
sta COPPtr ; save long pointer
sep #$30 ; A/MEM/X/Y -> 8 bit
.LONGA off
.LONGI off
txa
xba ; B = 0
lda STKPBR,s ; PBR bank where COP was executed
sta COPPtr+2
lda STKSR,s ; fetch saved P in stack
and #$FE ; clear carry in saved P
sta STKSR,s
bit #40 ; check if IRQ was enabled
bne ?04 ; NO
cli ; enable IRQ
?04: lda [COPPtr] ; fetch signature byte
rep #$30 ; now C = $00XX (B was cleared above)
.LONGA on
.LONGI on
asl a ; index * 4
asl a
tax ; index to access SYSTBL
ldy SYSTBLE_ADDR,x ; address of function
lda SYSTBLE_ADDR+2,x ; A = bank, B = count
?06: sty ?08+1 ; modify code on the fly
sep #$30 ; all 8 bit
.LONGA off
.LONGI off
sta !?08+3
xba ; A = bytes count of params
sta STKCNT,s
?08: jsl $000000 ; here call the function
; will return with RTL
bcc ?16 ; no error
sta STKYR,s ; return error in Y
lda #0
sta STKYR+1,s
lda STKSR,s ; saved P in stack
ora #$01 ; set carry in saved P
sta STKSR,s
?16: ; epilogue code
rep #$30 ; all 16 bit
.LONGA on
.LONGI on
lda STKCNT,s ; number of params bytes in the stack
beq ?20 ; no params -- skip stack cleaning
clc
tsc ; C = stack pointer
adc #STKNVAR ; add size of stack vars
tax ; source pointer for data move
adc STKCNT,s ; add params bytes count
tay ; dest pointer for data move
lda #STKNVAR-1 ; move bytes count
mvp #0, #0 ; cleanup stack
tya ; new stack pointer
tcs
?20: pla ; skip STKCNT
plb ; restore DBR
pld ; restore DPR
ply ; restore Y
plx ; restore X
pla ; restore C
rti ; restore P and return
_________________
http://65xx.unet.bz/ - Hardware & Software 65XX family