> OswFFv3/src ! Source for OSWORD &FF v1.03 5 Accesses sideways ROMs and shadow screen memory (8 Faster counter, adapts to Electron ROMSEL and Tube 2= Enables IRQs, uses Tube polling and fast transfer loops <: FH OSWORD &FF transfers blocks of memory between I/O and CoPro memory P X%?0 =&0D Z X%?1 =&01 d X%!2 =I/O address n X%!6 =CoPro address x) X%!10=Number of bytes to transfer % X%?12=0 for C->H, =1 for H->C :  I/O address can be:  &FFxRxxxx for ROM R " &FF8xxxxx for workspace RAM  &FFFFxxxx for I/O memory + &FFFExxxx for current display memory * &FFFDxxxx for shadow display memory : 7OS_CLI=&FFF7:OSBYTE=&FFF4:OSWORD=&FFF1:OSWRCH=&FFEE 7OSWRCR=&FFEC:OSNEWL=&FFE7:OSASCI=&FFE3:OSRDCH=&FFE0 USERV=&200 : )ctrl=&70:saveA=&72:count=&73:addr=&74 : 3run%=&FFFF2500:load%=&FFFF0900:fname$="OswFFv3" " mcode% &180 , P=0 1 6P%=run%:O%=mcode% @[OPT P*3+4 J .L2500 T6JMP L2505 :\ New USER entry ^ .OldUSERV hCEQUW L2500 :\ Swapped with USERV to claim r .L2505 |ECMP #&FF:BEQ L250C :\ If my OSWORD, jump to respond =JMP (OldUSERV) :\ Continue via OldUSERV :  .L250C LPHP:CLI :\ Enable IRQs, allow clock, etc to run >STX ctrl+0:STY ctrl+1:PHA :\ Save OSWORD parameters 8LDA &F4:PHA :\ Save current ROM HLDA &FFB2: #&BC :\ Check for Electron, has to be done ICMP #&FC:BNE GetAddress :\ inline as no initialisation call ASTA TUBEIO1+2:STA TUBEIO2+2 :\ Change to Electron TUBEIO STA TUBEIO3+2:STA TUBEIO4+2 : .GetAddress  LDY #&02 .GetAddrLp 8LDA (ctrl),Y:STA addr-2,Y :\ Copy I/O address CINY:CPY #5:BCC GetAddrLp :\ Overflow to ROM/screen byte &BPHA:ADC #&3F :\ Allow &0x and &Fx for ROMs 01 #&8F:JSR ROMSelect :\ Page in ROM :INX:BEQ GetIOMem :\ &FFFFxxxx - I/O memory NBINX:BEQ GetDisplay :\ &FFFExxxx - current screen XAINX:BEQ GetShadow :\ &FFFDxxxx - shadow memory bBNE GetIOMem l: v.GetDisplay LDA #&84:JSR OSBYTE ITYA:BPL GetIOMem :\ Not shadow screen being displayed .GetShadow LDA #1:JSR vramSelect :  .GetIOMem .TubeClaim @LDA #&C0+7:JSR &0406 :\ Claim the Tube with ID=7 :BCC TubeClaim :\ Loop until claimed >LDY #&0C:LDA (ctrl),Y:PHA :\ Get read/write command :LDA ctrl+0:CLC:ADC #&06:TAX :\ Point to Control+6 JLDA #&00:ADC ctrl+1:TAY :\ XY->CoPro address in control block APLA:PHA:JSR &406 :\ Initiate specified action =LDY #&0B:LDA (ctrl),Y:TAX:INX :\ Get X=count high byte  :DEY:LDA (ctrl),Y:STA count :\ Get count low byte FLDY #&00 :\ Prepare zero offset for (zp),Y  FPLA:ROR A:BCS L2585 :\ Get command back, jump if H->C *7SEC:BCS L2568 :\ Jump to do C->H 4: >\ Copy from Client to Host H\ ------------------------ R .L2558 \ .TUBEIO1 f;BIT &FEE4:BPL TUBEIO1 :\ Wait for Tube RxRDY p .TUBEIO2 z5LDA &FEE5 :\ Get byte C->H ;STA (addr),Y :\ Store in I/O memory ?INY:BCC L2570 :\ Skip for last few bytes :BNE L2558 :\ Loop for 256 bytes INC addr+1  .L2568 HDEX:BNE L2558 :\ Loop for each block of 256 bytes DCLC:LDX count:INX :\ Get count of remaining bytes  .L2570 @DEX:BNE L2558 :\ Loop for remaining bytes BBEQ L2592 :\ Jump to exit when finished : \ Copy from Host to Client \ ------------------------  .L2577 =LDA (addr),Y :\ Fetch from I/O memory  .TUBEIO3 $;BIT &FEE4:BVC TUBEIO3 :\ Wait for Tube TxRDY . .TUBEIO4 86STA &FEE5 :\ Send byte H->C B?INY:BCC L258F :\ Skip for last few bytes L:BNE L2577 :\ Loop for 256 bytes VINC addr+1 ` .L2585 jHDEX:BNE L2577 :\ Loop for each block of 256 bytes tDCLC:LDX count:INX :\ Get count of remaining bytes ~ .L258F @DEX:BNE L2577 :\ Loop for remaining bytes : \ Release and return \ ------------------  .L2592 >LDA #&80+7:JSR &0406 :\ Release Tube with ID=7 @LDA #0:JSR vramSelect :\ Page main memory back in 3PLA:JSR ROMSelect :\ Restore ROM ?LDX ctrl+0:LDY ctrl+1:PLA :\ Restore entry registers ?PLP :\ Restore IRQs and return  .vramOk RTS :  .vramSelect ;PHA:TAX :\ A=0 main RAM, A=1 video RAM BLDA #108:JSR OSBYTE :\ Attempt to select Master video RAM (2PLA:INX:BNE vramOk :\ X<>255, successful 29 #1:TAX :\ A=1 main RAM, A=0 video RAM &2600: "Code overrun": rI "*SAVE ";fname$;" ";~mcode%;" ";~O%;" ";~exec%&FFFF0000;" ";~load%