10 REM > S/Printer
   20 REM Provides emulated printer Spectrum
   30 REM Used IN/OUT &FB
   40 REM
   50 REM 16-Mar-2004 JGH : Initial version
   60 REM
   70 ON ERROR REPORT:PRINT ERL:END
   80 DIM mcode% &8000:ver$="0.10"
   90 sp=13:link=14:pc=15
  100 FOR p=0 TO 1
  110   P%=0:O%=mcode%
  120   [OPT p*3+4
  130   EQUD 0:\start
  140   EQUD Initialise
  150   EQUD Finalise
  160   EQUD Service
  170   EQUD TitleStr
  180   EQUD HelpStr
  190   EQUD CommandTable
  200   EQUD 0:\ SWI chunk number
  210   EQUD 0:\ SWI chunk handler
  220   EQUD 0:\ SWI decoding table
  230   EQUD 0:\ SWI decoding code
  240   :
  250   .TitleStr
  260   EQUS "SpecPrinter"
  270   EQUB 0
  280   ALIGN
  290   .HelpStr
  300   EQUS "SpecPrinter"+CHR$9+ver$+" ("+MID$(TIME$,5,11)+") Centronics"
  310   EQUB 0
  320   ALIGN
  330   :
  340   .CommandTable
  350   EQUB 0:ALIGN
  360   \EQUS "ROMBox":\EQUB 0:\ALIGN:\EQUD ROMBoxInit:\EQUD &00010001:\EQUD ROMBoxInit_Syntax:\EQUD ROMBoxInit_Help
  370   EQUB 0:ALIGN
  380   :
  390   .ROMSpecPrint_Help
  400   EQUS "Registers a module or application with ROMBox":EQUB 13
  410   .ROMSpecPrint_Syntax
  420   EQUS "Syntax: ROMBox <module name>|<address>"
  430   EQUB 0:ALIGN
  440   :
  450   :
  460   .Initialise
  470   stmfd   (sp)!,{link}
  480   ldr     r0,[r12]
  490   orrs    r0,r0,#0
  500   bne     Reinitialise  ; We already have workspace
  510   ;mov     r0,#6
  520   ;mov     r3,#10*4      ; We want 10 words
  530   ;swi     "XOS_Module"
  540   ;ldmvsfd (sp)!,{pc}    ; Memory claim failed
  550   ;str     r2,[r12]      ; Store in w/s pointer
  560   ;mov     r0,#0         ; Clear ROM pointers
  570   ;mov     r1,#0
  580   ;.InitClear
  590   ;str     r0,[r2,r1]
  600   ;add     r1,r1,#4
  610   ;cmp     r1,#10*4      ; 8 ROM pointers, module pointer, OUT copy
  620   ;bcc     InitClear
  630   .Reinitialise
  640   ldmfd   (sp)!,{pc}
  650   :
  660   :
  670   .Finalise
  680   stmfd   (sp)!,{link}
  690   ldr     r3,[r12]      ; Get pointer to module's workspace
  700   orrs    r3,r3,#0
  710   beq     Finalised     ; No workspace (shouldn't ever get called this way)
  720   ;mov     r4,#0         ; Loop from workspace+0
  730   ;.FinalLoop
  740   ;ldr     r2,[r3,r4]    ; Get pointer to ROM space
  750   ;orrs    r2,r2,#0      ; Is is zero?
  760   ;add     r4,r4,#4      ; Point to next pointer
  770   ;movne   r0,#7
  780   ;swine   "XOS_Module"  ; Release ROM space if it exists
  790   ;cmp     r4,#4*8
  800   ;bcc     FinalLoop     ; 8 ROM pointers
  810   ;ldr     r2,[r12]      ; Pointer to module's workspace
  820   ;mov     r0,#7
  830   ;swi     "XOS_Module"  ; Release it
  840   .Finalised
  850   ldmfd   (sp)!,{pc}
  860   :
  870   :
  880   .SpecPrintInit         ; *SpecPrint <module name>|<address>
  890   mov pc,link
  900   :
  910   :
  920   .Service
  930   \ In r0=mem[0]
  940   \    r1=Srv_Z80Reset - &80AC2
  950   \    r1=Srv_Z80OUT   - &80AC1
  960   \    r2=port
  970   \    r3=value
  980   \    r4=Module base
  990   \
 1000   stmfd (sp)!,{r1}      ; Check for Srv_Z80IN, Z80OUT or Z80Reset
 1010   and   r1,r1,#&FF000
 1020   cmp   r1,#&80000      ; &80xxx ?
 1030   ldmfd (sp)!,{r1}
 1040   movne pc,link         ; No
 1050   stmfd (sp)!,{r1}
 1060   and   r1,r1,#&FF0
 1070   cmp   r1,#&AC0        ; &80ACx ?
 1080   ldmfd (sp)!,{r1}
 1090   movne pc,link         ; No
 1100   ldr   r12,[r12]       ; Get workspace address
 1110   stmfd (sp)!,{r1}
 1120   and   r1,r1,#&F
 1130   cmp   r1,#&0          ; &80AC0 ?
 1140   beq   Service_Z80IN
 1150   cmp   r1,#&1          ; &80AC1 ?
 1160   beq   Service_Z80OUT
 1170   cmp   r1,#&2          ; &80AC2 ?
 1180   beq   Service_Z80Reset
 1190   ldmfd (sp)!,{r1}
 1200   mov   pc,link         ; No
 1210   :
 1220   :
 1230   .Service_Z80Reset
 1240   ;stmfd (sp)!,{link}
 1250   ;ldmfd (sp)!,{link}
 1260   ldmfd (sp)!,{r1}      ; Restore call number
 1270   mov   pc,link         ; Don't claim
 1280   :
 1290   :
 1300   .Service_Z80IN
 1310   ldmfd (sp)!,{r1}      ; Restore call number
 1320   stmfd (sp)!,{r2}      ; Save port number
 1330   and   r2,r2,#&FF      ; Lose top byte
 1340   cmp   r2,#&FB         ; Port &xxFB ?
 1350   ldmfd (sp)!,{r2}      ; Restore port number
 1360   movne pc,link         ; No -> exit unclaimed
 1370                         ; IN &xxFB
 1380   ; r0=z80mem[0]
 1390   ; r1=corruptable
 1400   ; r2=corruptable
 1410   ; r3=returns IN value [Printer Status]
 1420   ; r4=corruptable
 1430   ; stack balanced
 1440   :
 1450   mov r3,#&80           ; b7=1 - not busy
 1460   :
 1470   mov r1,#0             ; Claim the call
 1480   mov pc,link
 1490   :
 1500   :
 1510   .Service_Z80OUT
 1520   ldmfd (sp)!,{r1}      ; Restore call number
 1530   stmfd (sp)!,{r2}      ; Save port number
 1540   and   r2,r2,#&FF      ; Lose top byte
 1550   cmp   r2,#&FB         ; Port &xxFB ?
 1560   ldmfd (sp)!,{r2}      ; Restore port number
 1570   movne pc,link         ; No -> exit unclaimed
 1580                         ; OUT &xxFB,character
 1590   ; r0=z80mem[0]
 1600   ; r1=corruptable
 1610   ; r2=corruptable
 1620   ; r3=OUT value [character] - must preserve
 1630   ; r4=corruptable
 1640   ; stack balanced
 1650   :
 1660   stmfd (sp)!,{r0,r3,link} ; Save registers
 1670   mov   r0,#&80
 1680   adr   r1,PrinterName
 1690   swi   "XOS_Find"
 1700   mov   r1,r0           ; r1=OPENOUT("Printer")
 1710   mov   r0,r3           ; r0=byte sent
 1720   swi   "XOS_BPut"      ; BPUT#r1,byte
 1730   mov   r0,#0
 1740   swi   "XOS_Find"      ; CLOSE#r1
 1750   ldmfd (sp)!,{r0,r3,link} ; Restore registers
 1760   :
 1770   mov r1,#0             ; Claim the call
 1780   mov pc,link
 1790   :
 1800   .PrinterName
 1810   EQUS "Printer:":EQUB 13
 1820   :
 1830   :
 1840   ALIGN
 1850 ]NEXT
 1860 OSCLI"SAVE SpecPrint "+STR$~mcode%+" "+STR$~O%
 1870 *SetType SpecPrint Module
 1880 *Stamp SpecPrint
 1890 END