10
20
30 :
40
50
60
70
80
90
100
110 :
120
130
140 :
150 USERV=&200
160 ctrl=&70:saveA=&72:unused=&73:addr=&74:count=&76:countLO=&77
170 :
180 run%=&FFFF2500:load%=&FFFF0900:fname$="OswFFv136"
190 DIM mcode% &180
200 FOR P=0 TO 1
210 P%=run%:O%=mcode%
220 [OPT P*3+4:\ \v1.20 :\ v1.36
230 .L2500
240 CLC:BCC L2505 \JMP L2505 :\ New USER entry
250 .OldUSERV
260 EQUW &E310 \EQUW L2500:\ Swapped with USERV to claim
270 .L2505
280 CMP #&FF:BEQ L250C :\ If my OSWORD, jump to respond
290 JMP (OldUSERV) :\ Continue via OldUSERV
300 :
310 .L250C
320 STX ctrl+0:STY ctrl+1:PHA \STA saveA :\ Save OSWORD parameters
330 .L2511
340 LDA #&C0+7:JSR &0406 \new :\ Claim with ID=7
350 BCC L2511 \new :\ Loop until claimed
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 #&0A:LDA (ctrl),Y:STA countLO \TAX :\ Get count low byte
400 INY:LDA (ctrl),Y:STA count \new :\ Get count high byte
410 ORA countLO:BNE L2534:BEQ L257F \new :\ Nothing to do
420 .L2534
430 LDA countLO \TXA :\ Jump forward if multiple of 256
440 BEQ L253A:INC count \ :\ Inc high byte to balance DECs later
450 .L253A
460 INY \LDY #&0C
470 LDA (ctrl),Y:PHA :\ Get read/write command
480 LDA ctrl+0:CLC:ADC #&06:TAX :\ Point to Control+6
490 LDA #&00:ADC ctrl+1:TAY :\ XY->CoPro address in control block
500 PLA:PHA:JSR &406 :\ Initiate specified action
510 LDX countLO \new :\ Get vount low into X
520 PLA :\ Get command back
530 LDY #0 \new :\ Zero offset for (zp),Y
540 CMP #0:BEQ L2567 \new :\ Transfer bytes C->H
550 CMP #1:BEQ L2581 \new :\ Transfer bytes H->C
560 CMP #2:BEQ L2598 \new :\ Transfer pairs C->H
570 CMP #3:BEQ L25C2 \new :\ Transfer pairs H->C
580 LDA #0:BEQ L257F \new :\ Ignore
590 :
600 \ 1-byte CoPro->Host
610 \ ------------------
620 .L2567
630 JSR L25F6 :\ Delay before starting
640 : \LDY #&00 :\ Zero offset for (zp),Y
650 .L256A
660 LDA &FEE5:STA (addr),Y :\ Transfer a byte C->H
670 JSR L25F6 :\ Delay between bytes
680 : \JSR L259B
690 : \JSR L259B
700 INC addr+0:BNE L2578:INC addr+1 :\ Update I/O address
710 .L2578
720 DEX:BNE L256A :\ Loop for up to 256 bytes
730 DEC count:BNE L256A :\ Loop for each 256-byte chunk
740 .L257F
750 BEQ L25EB :\ Jump to exit when finished
760 :
770 \ 1-byte Host->CoPro
780 \ ------------------
790 : \LDY #&00 :\ Zero offset for (zp),Y
800 .L2581
810 LDA (addr),Y:STA &FEE5 :\ Transfer byte H->C
820 JSR L25F6 :\ Delay between bytes
830 : \JSR L259B
840 : \JSR L259B
850 INC addr+0:BNE L258F:INC addr+1 :\ Update I/O address
860 .L258F
870 DEX:BNE L2581 :\ Loop for up to 256 bytes
880 DEC count:BNE L2581 :\ Loop for each 256-byte chunk
890 BEQ L25EB :\ Jump to exit when finished
900 :
910 \ 2-byte CoPro->Host - must be an even number of bytes
920 \ ----------------------------------------------------
930 .L2598
940 JSR L25F6 \new :\ Delay before starting
950 .L259B \new
960 LDA &FEE5:STA (addr),Y \new :\ Transfer a byte C->H
970 INC addr+0:BNE L25A6:INC addr+1 \new :\ Update I/O address
980 .L25A6 \new
990 NOP:NOP \new :\ Sort delay between bytes
1000 LDA &FEE5:STA (addr),Y \new :\ Transfer a byte C->H
1010 INC addr+0:BNE L25B3:INC addr+1 \new :\ Update I/O address
1020 .L25B3 \new
1030 JSR L25F5 \new :\ Delay between bytes
1040 NOP:NOP \new :\ Sort delay between bytes
1050 DEX:DEX:BNE L259B \new :\ Loop for up to 256 bytes
1060 DEC count:BNE L259B \new :\ Loop for each 256-byte chunk
1070 BEQ L25EB \new :\ Jump to exit when finished
1080 :
1090 \ 2-byte Host->CoPro - must be an even number of bytes
1100 \ ----------------------------------------------------
1110 .L25C2
1120 LDA (addr),Y:STA &FEE5 \new :\ Transfer byte H->C
1130 INC addr+0:BEQ L25CE \new :\ Update I/O address
1140 NOP:BNE L25D0 \new :\ Short delay between bytes
1150 .L25CE \new
1160 INC addr+1 \new
1170 .L25D0 \new
1180 LDA unused \new :\ Another delay between bytes
1190 LDA (addr),Y:STA &FEE5 \new :\ Transfer byte H->C
1200 INC addr+0:BEQ L25DE \new :\ Update I/O address
1210 NOP:BNE L25E0 \new :\ Short delay between bytes
1220 .L25DE \new
1230 INC addr+1 \new
1240 .L25E0 \new
1250 JSR L25F5 \new :\ Delay between bytes
1260 DEX:DEX:BNE L25C2 \new :\ Loop for up to 256 bytes
1270 DEC count:BNE L25C2 \new :\ Loop for each 256-byte chunk
1280 :
1290 .L25EB
1300 LDA #&80+7:JSR &0406 \JSR L25A4 :\ Release with ID=7
1310 LDX ctrl+0:LDY ctrl+1:PLA \LDA saveA :\ Restore entry registers
1320 .L25F5 :\ Call here to delay 6us
1330 RTS :\ And return
1340 :
1350 .L25F6
1360 JSR L25F5:JSR L25F5:RTS \new :\ Delay 18us
1370 :
1380 : \.L259C
1390 : \LDA #&C0+7
1400 : \JSR &0406 :\ Claim with ID=7
1410 : \BCC L259C :\ Loop until claimed
1420 : \RTS
1430 :
1440 : \.L25A4
1450 : \LDA #&80+7
1460 : \JSR &0406 :\ Release with ID=7
1470 : \RTS
1480 .end%
1490 :
1500 ]:P%=P%-run%+load%:off%=run%-load%:[OPT P*3+4
1510 :
1520 \ This code allows OSWORD &FF to live in a *runnable program
1530 :
1540 .exec%
1550 BIT &27A:BPL SetupExit :\ No Tube present
1560 LDA USERV+0:CMP OldUSERV-off%+0:BNE Setup :\ Vector diff, claim it
1570 LDA USERV+1:CMP OldUSERV-off%+1:BEQ SetupExit :\ Same, already claimed
1580 .Setup
1590 PHP:SEI:LDY #0 :\ Prevent IRQs while changing vectors
1600 .SetupLp
1610 LDA load%,Y:STA run%,Y:INY :\ Copy code to main memory
1620 CPY #(end%-run%)AND&FF:BNE SetupLp
1630 LDA USERV+0:LDX OldUSERV+0 :\ Claim USERV
1640 STX USERV+0:STA OldUSERV+0
1650 LDA USERV+1:LDX OldUSERV+1
1660 STX USERV+1:STA OldUSERV+1
1670 PLP :\ Restore IRQs and exit
1680 .SetupExit
1690 RTS
1700 :
1710 ]NEXT
1720 A$=fname$+" "+STR$~mcode%+" "+STR$~O%+" "+STR$~(exec%OR&FFFF0000)+" "+STR$~load%
1730 PRINT"Saving ";A$:OSCLI "SAVE "+A$:PRINT