; ; Copyright (C) Kopriha Software, 1990 - 1991 ; All rights reserved. ; Licensed material -- property of Kopriha Software ; ; This software is made available solely pursuant to the terms ; of a Kopriha Software license agreement which governs its use. ; ; ; The following macros (port_routine/port_return) are support ; routines for IIGS port drivers. ; ; ; Macros: port_routine (:[,...])[,] ; - Enter a port driver routine ; ; port_return :[,] ; - Exit a port driver routine ; - This macro must be followed by an RTL. By coding the ; macro this way you can customize the return (some, but ; not all port driver routines must return after a CMP #1. ; See the source to port.asm for the details). ; ; ; Note: These macros are derived from the csubroutine/creturn ; macros supplied with Orca/C (on the demos disk). ; MACRO &lab port_subroutine &parms,&work &lab anop Places the label from macro invocation aif c:&work,.a If there is a work parm goto .a lclc &work Local define work a string &work setc 0 Set work to zero .a .a gbla &totallen Global define totallen gbla &worklen Global define worklen gbla &PClen Global define length of PC &worklen seta &work Set worklen = work (type conversion) &totallen seta 0 Set totallen to zero &PClen seta 8 Set PC length to 8 (6(rtnPC*2)+1(direct page)+1(data bank)) aif c:&parms=0,.e If there are no parms to routine then goto .e lclc &len Local define char len lclc &p Local define char p lcla &i Local define int i &i seta 1 i = 1 .b .b &p setc &parms(&i) p = parms[i] &len amid &p,2,1 len = substr(p,2,1) aif "&len"=":",.c if len == ':' goto .c &len amid &p,1,2 len = substr(p,1,2) {First 2 chars} &p amid &p,4,l:&p-3 p = substr(p,4,strlen(p)-3) {get name} ago .d goto .d .c .c &len amid &p,1,1 len = substr(p,1,1) {only first char} &p amid &p,3,l:&p-2 p = substr(p,3,strlen(p)-2) {get name} .d .d We have a name and its length &p equ &totallen+&PClen+&work {name} equ totallen+PClen+work &totallen seta &totallen+&len totallen = totallen+len (length of parm) &i seta &i+1 i = i + 1 aif &i<=c:&parms,^b if i<#parms goto b (backwards goto) .e .e All parms setup (equ'd) tsc get stack pointer aif &work=0,.f If you need work space... sec add it onto the stack pointer sbc #&work tcs .f Stack is setup by here... phd Save the direct page tcd Set direct page == stack ptr mend Thus lda parm is a direct page reference... MACRO &lab port_return &returnparm,&comproutine ; ; Parse the return parameter (if defined). ; &lab anop Place any label from macro invocation lclc &len Local create len aif c:&returnparm,.a If there is a parameter goto .a lclc &returnparm Local create r (for parm length) &returnparm setc 0 Set returnparm to zero &len setc 0 Set len to zero ago .h Goto skip arguement parsing .a .a We have a parameter - parse it! &len amid &returnparm,2,1 len = substr(r,2,1) aif "&len"=":",.b if (len == ':') goto .b &len amid &returnparm,1,2 len = substr(r,1,2) &returnparm amid &returnparm,4,l:&returnparm-3 r = substr(r,4,strlen(r)-3) ago .c goto .c .b .b One character length... &len amid &returnparm,1,1 len = substr(r,1,1) &returnparm amid &returnparm,3,l:&returnparm-2 r = substr(3,1,strlen(r)-2) ; ; Get the return parameter - if we have something to ; return. The return parameter can be 2,4 or 10 bytes ; (IE: Word, Long or Sane #). ; .c aif &len=0,.h If len == 0 then skip this... aif &len<>2,.d if len != 2 goto .d ldy &returnparm LDY ago .h goto .h .d .d Not length == 2 aif &len<>4,.e if length != 4 goto .e ldx &returnparm+2 LDX +2 (high byte) ldy &returnparm LDY (low byte) ago .h goto .h .e .e Not length == 4 aif &len<>10,.g if length != 10 (IE: Sane #) goto .g ldx #^&returnparm LDX #^ (high byte) ldy #&returnparm LDY # (low byte) &len setc 4 We're returning a pointer...len 4 ago .h goto .h .g .g Not sane # (hehehe) mnote 'Not a valid return length',16 Print error} mexit Oops... stop here ; ; Setup the completion routine - if there is one. ; .h aif c:&comproutine=0,.m ; ; Ok, lets setup the completion routine JSR (but only if its not NIL) ; stz cjmp&SYSCNT+1 Clear the completion routine address stz cjmp&SYSCNT+2 (all three words of it...) ; lda &comproutine ora &comproutine+1 'OR' the other bits in... beq compa&SYSCNT If its NIL, then return to our caller. ; ; Looks non-NIL to me. Setup the completion routine call and then do it. ; (Ug... self modifying code... Its the easy solution for now...) ; lda &comproutine Get low 2 bytes sta cjmp&SYSCNT+1 Save them in our JSR instruction lda &comproutine+1 Get the high bytes (actually, sta cjmp&SYSCNT+2 just the bank byte...) compa&SYSCNT anop ; ; Setup the return parameters on the stack (if any) ; .m aif &len<>2,.k If return nothing, goto .j sty &worklen+&totallen+&PClen-&len .k aif &len<>4,.j stx &worklen+&totallen+&PClen-&len Store low byte sty &worklen+&totallen+&PClen-&len+2 Store high byte .j ; ; If the return PCs need to be moved, then lets move ; them... the determination is based on if we have ; to remove parameters from the stack. ; Note: The order of the moving these PCs is significant! ; We must move the PCs in the order coded... any other ; may cause the first store to overwrite part of the ; PCs before moving them. ; aif &totallen=0,.i if no parms to port_routine, goto .i aif &totallen-&len=0,.i No sense in moving PCs nowhere... lda &worklen+6 Copy return PCs (both of them) sta &worklen+&totallen+6-&len lda &worklen+4 sta &worklen+&totallen+4-&len lda &worklen+2 sta &worklen+&totallen+2-&len .i ; ; If there is a possible completion routine, then ; generate the code to check if it actually exists ; and if it does then call it (jsl) - otherwise rtl. ; aif c:&comproutine=0,.p ; ; Ok, lets go to the completion routine JSR (but only if its not NIL) ; lda cjmp&SYSCNT+1 Is there a completion routine? ora cjmp&SYSCNT+2 'OR' the rest of the address... beq compb&SYSCNT If its NIL, then return to our caller. .i ; ; Looks non-NIL to me. Setup the completion routine call and then do it. ; (Ug... self modifying code... Its the easy solution for now...) ; clc Clear carry - no errors on this call lda #0 (Also need zero in ac for no error!) cjmp&SYSCNT jsr >123456 Jmp to the completion routine compb&SYSCNT anop (Jsl would come back to a rtl, may as well just go there) .p ; ; If we have to then it is time to adjust the stack pointer ; (also get the direct page/data bank restored for our caller) ; pld Restore the direct page plb Restore the data bank aif &worklen+&totallen-&len=0,.o If we aren't changing the stack ptr tsc Fix the stack pointer clc ... adc #&worklen+&totallen-&len ... tcs ... .o clc Clear carry - no errors on this call lda #0 (Also need zero in ac for no error!) mend