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