; cop handler ; software interrupt generated by 'cop' istruction ; ; cop instruction save on stack program bank register (pbr), ; program counter (pc) and status register (p) ; this handler switch processor to 16 bit mode, then push ; on stack register's a, x, and y, all 16 bits ; after push on stack direct page (dp) register and ; data bank register (dbr), followed by the count (16 bits) ; of parameter's passed by caller on stack ; ; stack frame look like below (with relative offset): ; ; --------- ; | 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 ; --------- ; | cntl | 01 ; --------- ; ; cnth is always zero, while cntl is retrivied by system table ; and is related to the system function number ; ; equates for access stack data (offset relative to the sp register) ; add 3 to these equates for use in system function (because jsl ...) ; stkcnt .set $01 stky .set $06 stkx .set $08 stka .set $0a stkp .set $0c stkpc .set $0d stkpbr .set $0f ; note: copp is a long pointer defined in true zero page ; cophdlr: c16 ; all register's 16 bits pha ; save c in stack phx ; save x in stack phy ; save y in stack phd ; save dpr in stack phb ; save dbr in stack lda #0 pha ; params byte count in the stack (cnt = 0) tcd ; set dpr = $0000 phk ; set dbr = pbr = $00 plb lda stkpc,s ; load pc saved in stack dec a ; pointer to signature byte sta copp lda stkpbr,s ; pbr bank where cop was executed (8 bits low) sta copp+2 ; low 8 bits hold pbr lda [copp] ; fetch signature byte and #$00ff ; clear high byte asl a ; get index to access system table asl a tax ; get system function from system table located in bank $00 ; y = address ; a = bank address, b = parameter's count ; ldy .abs.systbl_addr,x lda .abs.systbl_addr+2,x sty .abs.?jmp+1 ; store function address c8 ; switch processor to 8 bits sta .abs.?jmp+3 ; store function bank tax bne ?ok ; bank must not be $00 ; system functions never are located in bank $00 so if bank = $00 ; the function is not valid ; lda #einval ; invalid function error bra ?err ; set error ; clear carry in saved status (carry is the error indicator) ; ?ok: xba ; a = parameter's count sta stkcnt,s ; set param's count lda stkp,s ; get saved status and #~pcflag ; clear carry in saved status sta stkp,s bit #piflag ; interrupt was enabled? bne ?jmp ; no cli ; re-enable interrupt ?jmp: jsl $000000 ; jmp to function ; system function return error condition with carry flag set ; error code in accumulator ; bcc ?epl ; no error ?err: sta stky,s ; report error on y register lda #0 sta stky+1,s lda stkp,s ; set carry on saved status ora #pcflag sta stkp,s ; epilogue code - realign stack and exit ; ?epl: c16c ; switch to 16 bits & reset carry lda stkcnt,s ; number of params bytes in the stack beq ?done ; no params -- skip stack cleaning tsc ; c = stack pointer adc #stkpbr ; 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 #stkpbr-1 ; move bytes count mvp #0, #0 ; cleanup stack tya ; new stack pointer tcs ?done: pla ; skip stkcnt plb ; restore dbr pld ; restore dpr ply ; restore y plx ; restore x pla ; restore a rti ; restore p and return ; systbl_addr mark the beginning of a table that contain 4 bytes for ; any cop vector. The structure is simple: ; first 3 bytes: long address of system function (if high byte = 0 ; then the function is not valid). ; Last byte contain the count of bytes of paramters passed on stack ; systbl_addr: .db addrl, addrh, addrk, count ......