10 REM > OswFFv3/src
   20 REM Source for OSWORD &FF v1.03
   30 REM Accesses sideways ROMs and shadow screen memory
   40 REM Faster counter, adapts to Electron Tube, uses OSRDRM
   50 REM Enables IRQs, copies control block to workspace
   60 REM Tried polling TUBEIO, but fails consistantly on Z80
   70 :
   80 REM OSWORD &FF transfers blocks of memory between I/O and CoPro memory
   90 REM   X%?0 =&0D
  100 REM   X%?1 =&01
  110 REM   X%!2 =I/O address
  120 REM   X%!6 =CoPro address
  130 REM   X%!10=Number of bytes to transfer
  140 REM   X%?12=0 for C->H, =1 for H->C
  150 :
  160 REM I/O address can be:
  170 REM  &FFxRxxxx for ROM R
  180 REM  &FF8xxxxx for workspace RAM
  190 REM  &FFFFxxxx for I/O memory
  200 REM  &FFFExxxx for current display memory
  210 REM  &FFFDxxxx for shadow display memory
  220 :
  230 OS_CLI=&FFF7:OSBYTE=&FFF4:OSWORD=&FFF1:OSWRCH=&FFEE
  240 OSWRCR=&FFEC:OSNEWL=&FFE7:OSASCI=&FFE3:OSRDCH=&FFE0
  250 USERV=&200
  260 :
  270 ctrl=&70:addr=ctrl+2:tube=ctrl+6:count=ctrl+10:action=ctrl+12
  280 :
  290 run%=&FFFF2500:load%=&FFFF0900:fname$="OswFFv3"
  300 DIM mcode% &180
  310 FOR P=0 TO 1
  320   P%=run%:O%=mcode%
  330   [OPT P*3+4
  340   .L2500
  350   JMP L2505                        :\ New USER entry
  360   .OldUSERV
  370   EQUW L2500                       :\ Swapped with USERV to claim
  380   .L2505
  390   CMP #&FF:BEQ L250C               :\ If my OSWORD, jump to respond
  400   JMP (OldUSERV)                   :\ Continue via OldUSERV
  410   :
  420   .L250C
  430   PHP:CLI                          :\ Enable IRQs, allow clock, etc to run
  440   STX ctrl+0:STY ctrl+1:PHA        :\ Save OSWORD parameters
  450   LDA &F4:PHA                      :\ Save current ROM
  460   LDA &FFB2:EOR #&BC               :\ Check for Electron, has to be done
  470   CMP #&FC:BNE GetAddress          :\  inline as no initialisation call
  480   STA TUBEIO1+2:STA TUBEIO2+2      :\ Change to Electron TUBEIO
  490   :
  500   .GetAddress
  510   LDY #12
  520   .GetAddrLp
  530   LDA (ctrl),Y:STA ctrl,Y          :\ Copy control block
  540   DEY:CPY #2:BCS GetAddrLp
  550   STY &F7                          :\ (&F6)=>&02xx, safe ROMSEL access
  560   LDA addr+2:ADC #&40              :\ Allow &0x and &Fx for ROMs
  570   AND #&8F:JSR ROMSelect           :\ Page in ROM
  580   LDX addr+2                       :\ Get screen byte
  590   INX:BEQ GetIOMem                 :\ &FFFFxxxx - I/O memory
  600   INX:BEQ GetDisplay               :\ &FFFExxxx - current screen
  610   INX:BEQ GetShadow                :\ &FFFDxxxx - shadow memory
  620   BNE GetIOMem
  630   :
  640   .GetDisplay
  650   LDA #&84:JSR OSBYTE
  660   TYA:BPL GetIOMem                 :\ Not shadow screen displayed
  670   .GetShadow
  680   LDA #1:JSR vramSelect
  690   :
  700   .GetIOMem
  710   .TubeClaim
  720   LDA #&C0+7:JSR &0406             :\ Claim the Tube with ID=7
  730   BCC TubeClaim                    :\ Loop until claimed
  740   LDX #addr+4:LDY #0               :\ XY=>CoPro address
  750   LDA action:PHA:JSR &406          :\ Initiate specified action
  760   LDX count+1:INX                  :\ Get X=count high byte
  770   LDY #&00                         :\ Prepare zero offset for (zp),Y
  780   PLA:ROR A:BCS L2585              :\ Get command back, jump if H->C
  790   SEC:BCS L2568                    :\ Jump to do C->H
  800   :
  810   \ Copy from Client to Host
  820   \ ------------------------
  830   .L2558
  840   JSR L259B:JSR L259B:JSR L259B    :\ Delay before starting and between bytes
  850   .TUBEIO1
  860   LDA &FEE5:STA (addr),Y           :\ Transfer a byte C->H
  870   INY:BCC L2570                    :\ Skip for last few bytes
  880   BNE L2558                        :\ Loop for 256 bytes
  890   INC addr+1
  900   .L2568
  910   DEX:BNE L2558                    :\ Loop for each block of 256 bytes
  920   CLC:LDX count:INX                :\ Get count of remaining bytes
  930   .L2570
  940   DEX:BNE L2558                    :\ Loop for remaining bytes
  950   BEQ L2592                        :\ Jump to exit when finished
  960   :
  970   \ Copy from Host to Client
  980   \ ------------------------
  990   .L2577
 1000   LDA (addr),Y:.TUBEIO2:STA &FEE5  :\ Transfer byte H->C
 1010   JSR L259B:JSR L259B:JSR L259B    :\ Delay between bytes
 1020   INY:BCC L258F                    :\ Skip for last few bytes
 1030   BNE L2577                        :\ Loop for 256 bytes
 1040   INC addr+1
 1050   .L2585
 1060   DEX:BNE L2577                    :\ Loop for each block of 256 bytes
 1070   CLC:LDX count:INX                :\ Get count of remaining bytes
 1080   .L258F
 1090   DEX:BNE L2577                    :\ Loop for remaining bytes
 1100   :
 1110   \ Release and return
 1120   \ ------------------
 1130   .L2592
 1140   LDA #&80+7:JSR &0406             :\ Release Tube with ID=7
 1150   LDA #0:JSR vramSelect            :\ Page main memory back in
 1160   PLA:JSR ROMSelect                :\ Restore ROM
 1170   LDX ctrl+0:LDY ctrl+1:PLA        :\ Restore entry registers
 1180   PLP                              :\ Restore IRQs and return
 1190   .L259B                           :\ Call here to delay 6us
 1200   .vramOk
 1210   RTS
 1220   :
 1230   .vramSelect
 1240   PHA:TAX                  :\ A=0 main RAM, A=1 video RAM
 1250   LDA #108:JSR OSBYTE      :\ Attempt to select Master video RAM
 1260   PLA:INX:BNE vramOk       :\ X<>255, successful
 1270   EOR #1:TAX               :\ A=1 main RAM, A=0 video RAM
 1280   LDA #111:JMP OSBYTE      :\ Attempt to select Aries/Watford RAM
 1290   :
 1300   .ROMSelect
 1310   STA &F4:JMP &FFB9        :\ Page ROM in via OSRDRM
 1320   .end%
 1330   :
 1340   ]:P%=P%-run%+load%:off%=run%-load%:[OPT P*3+4
 1350   :
 1360   \ This code allows OSWORD &FF to live in a *runnable program
 1370   \ Can be *RUN on top of itself or on top of other code at &2500
 1380   :
 1390   .exec%
 1400   PHP:SEI                                   :\ Prevent IRQs while changing vectors
 1410   BIT &27A:BPL SetupExit                    :\ No Tube present
 1420   LDA USERV+1:CMP OldUSERV-off%+1:BNE Setup :\ Not linked to me, claim it
 1430   LDA USERV+0:CMP OldUSERV-off%+0:BNE Setup :\ Not linked to me, claim it
 1440   LDA OldUSERV+1:STA USERV+1                :\ Already linked, restore USER V
 1450   LDA OldUSERV+0:STA USERV+0                :\ And then reclaim it
 1460   .Setup
 1470   LDY #0
 1480   .SetupLp
 1490   LDA load%,Y:STA run%,Y:INY:BNE SetupLp    :\ Copy code to main memory
 1500   LDA USERV+1:LDX OldUSERV+1                :\ Claim USERV
 1510   STX USERV+1:STA OldUSERV+1
 1520   LDA USERV+0:LDX OldUSERV+0
 1530   STX USERV+0:STA OldUSERV+0
 1540   .SetupExit
 1550   PLP:RTS                                   :\ Exit
 1560   :
 1570 ]NEXT
 1580 A$=fname$+" "+STR$~mcode%+" "+STR$~O%+" "+STR$~(exec%OR&FFFF0000)+" "+STR$~load%
 1590 PRINT"Saving ";A$:OSCLI "SAVE "+A$:PRINT