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