10
20
30
40
50
60 :
70
80
90
100
110
120
130
140 :
150
160
170
180
190
200
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%