10 REM > OswFF/src
   20 REM Source for OSWORD &FF
   30 :
   40 REM OSWORD &FF transfers blocks of memory between I/O and CoPro memory
   50 REM   X%?0 =&0D
   60 REM   X%?1 =&01
   70 REM   X%!2 =I/O address
   80 REM   X%!6 =CoPro address
   90 REM   X%!10=Number of bytes to transfer
  100 REM   X%?12=0 for C->H, =1 for H->C
  110 :
  120 REM Note: the default code does not work on the Electron as the Tube I/O
  130 REM port on the Electron is at &FCE5 instead of at &FEE5.
  140 :
  150 OS_CLI=&FFF7:OSBYTE=&FFF4:OSWORD=&FFF1:OSWRCH=&FFEE
  160 OSWRCR=&FFEC:OSNEWL=&FFE7:OSASCI=&FFE3:OSRDCH=&FFE0
  170 USERV=&200
  180 :
  190 ctrl=&70:saveA=&72:unused=&73:addr=&74:count=&76
  200 :
  210 run%=&FFFF2500:load%=&FFFF0900
  220 DIM mcode% &100
  230 FOR P=0 TO 1
  240   P%=run%:O%=mcode%
  250   [OPT P*3+4
  260   .L2500
  270   JMP L2505                        :\ New USER entry
  280   .OldUSERV
  290   EQUW L2500                       :\ Swapped with USERV to claim
  300   .L2505
  310   CMP #&FF:BEQ L250C               :\ If my OSWORD, jump to respond
  320   JMP (OldUSERV)                   :\ Continue via OldUSERV
  330   
  340   .L250C
  350   STX ctrl+0:STY ctrl+1:STA saveA  :\ Save OSWORD parameters
  360   LDY #&02:LDA (ctrl),Y:STA addr+0 :\ I/O address low byte
  370   INY:LDA (ctrl),Y:STA addr+1      :\ I/O address high byte
  380   JSR L259C                        :\ Claim the Tube
  390   LDY #&0C:LDA (ctrl),Y:PHA        :\ Get read/write command
  400   LDA ctrl+0:CLC:ADC #&06:TAX      :\ Point to Control+6
  410   LDA #&00:ADC ctrl+1:TAY          :\ XY->CoPro address in control block
  420   PLA:PHA:JSR &406                 :\ Initiate specified action
  430   LDY #&0A:LDA (ctrl),Y:TAX        :\ Get count low byte
  440   INY:LDA (ctrl),Y:STA count       :\ Get count high byte
  450   BNE L2544                        :\ Jump forward if >255 bytes to do
  460   TXA:BEQ L2592                    :\ Jump to exit if no bytes left
  470   .L2544
  480   TXA:BEQ L2549                    :\ Jump forward if multiple of 256 bytes
  490   INC count                        :\ Inc high byte to balance DECs later
  500   .L2549
  510   PLA:ROR A:BCS L2575              :\ Get command back, jump if H->C
  520   :
  530   JSR L259B:JSR L259B:JSR L259B    :\ Delay before starting
  540   LDY #&00                         :\ Zero offset for (zp),Y
  550   .L2558
  560   LDA &FEE5:STA (addr),Y           :\ Transfer a byte C->H
  570   JSR L259B:JSR L259B:JSR L259B    :\ Delay between bytes
  580   INC addr+0:BNE L256C:INC addr+1  :\ Update I/O address
  590   .L256C
  600   DEX:BNE L2558                    :\ Loop for up to 256 bytes
  610   DEC count:BNE L2558              :\ Loop for each 256-byte chunk
  620   BEQ L2592                        :\ Jump to exit when finished
  630   :
  640   .L2575
  650   LDY #&00
  660   .L2577
  670   LDA (addr),Y:STA &FEE5           :\ Transfer byte H->C
  680   JSR L259B:JSR L259B:JSR L259B    :\ Delay between bytes
  690   INC addr+0:BNE L258B:INC addr+1  :\ Update I/O address
  700   .L258B
  710   DEX:BNE L2577                    :\ Loop for up to 256 bytes
  720   DEC count:BNE L2577              :\ Loop for each 256-byte chunk
  730   :
  740   .L2592
  750   JSR L25A4                        :\ Release Tube
  760   LDX ctrl+0:LDY ctrl+1:LDA saveA  :\ Restore entry registers
  770   .L259B                           :\ Call here to delay 6us
  780   RTS                              :\ And return
  790   
  800   .L259C
  810   LDA #&C0+7:JSR &0406             :\ Claim with ID=7
  820   BCC L259C:RTS                    :\ Loop until claimed
  830   
  840   .L25A4
  850   LDA #&80+7:JSR &0406             :\ Release with ID=7
  860   RTS
  870   .end%
  880   
  890   ]:P%=P%-run%+load%:off%=run%-load%:[OPT P*3+4
  900   :
  910   \ This code allows OSWORD &FF to live in a *runnable program
  920   :
  930   .exec%
  940   BIT &27A:BPL SetupExit                        :\ No Tube present
  950   LDA USERV+0:CMP OldUSERV-off%+0:BNE Setup     :\ Vector diff, claim it
  960   LDA USERV+1:CMP OldUSERV-off%+1:BEQ SetupExit :\ Same, already claimed
  970   .Setup
  980   PHP:SEI:LDY #0                                :\ Prevent IRQs while changing vectors
  990   .SetupLp
 1000   LDA load%,Y:STA run%,Y:INY               :\ Copy code to main memory
 1010   CPY #end%-run%:BNE SetupLp
 1020   LDA USERV+0:LDX OldUSERV+0               :\ Claim USERV
 1030   STX USERV+0:STA OldUSERV+0
 1040   LDA USERV+1:LDX OldUSERV+1
 1050   STX USERV+1:STA OldUSERV+1
 1060   PLP                                      :\ Restore IRQs and exit
 1070   .SetupExit
 1080   RTS
 1090   :
 1100 ]NEXT
 1110 PRINT "*SAVE OSWFF ";~mcode%;" ";~O%;" ";~exec%OR&FFFF0000;" ";~load%