10
20
30
40 :
50
60
70 key1 = &EC :
80 key2 = &ED :
90 :
100
110
120 keyvec = &0228 :
130 oswrch = &FFEE :
140 osbyte = &FFF4 :
150 :
160
170
180 userv = &200 :
190 irqv1 = &204 :
200 eventvec = &220 :
210 :
220
230
240 tube_entry = &406 :
250 :
260
270
280 userport = &FE60 :
290 :
300
310
320 Master_fdc_base=&24
330 Master_fdn_stat=&28
340 Master_fdc_data=&2B
350 BBC_fdc_base =&80
360 BBC_fdc_stat =&84
370 BBC_fdc_data =&87
380 :
390
400
410 tubeR1stat = &FEE0 :
420 tubeR1data = &FEE1 :
430 tubeR2stat = &FEE2 :
440 tubeR2data = &FEE3 :
450 tubeR3stat = &FEE4 :
460 tubeR3data = &FEE5 :
470 tubeR4stat = &FEE6 :
480 tubeR4data = &FEE7 :
490 :
500
510
520 OSW_GRAPH = &FF :
530 OSW_HDD = &FE :
540 OSW_TEXT = &FD :
550 OSW_CRTC = &FC :
560 OSW_FDC = &FB :
570 OSW_FAD = &FA :
580 :
590 load%=&FFFF2800:exec%=load%:fname$="OswFB-FF"
600 DIM mcode% &57F
610 FOR P=0 TO 1
620 P%=load%:O%=mcode%
630 [OPT P*3+4
640 .L2800
650 JMP &2800 :\ Jumps to OSWORD &FA code, loader changes to &2500
660 :
670 \ Main entry point, USERV directed to here
680 \ ========================================
690 .L2803
700 CMP #OSW_GRAPH:BEQ oswFFjmp :\ OSWORD &FF graphics update
710 CMP #OSW_CRTC :BEQ oswFCjmp :\ OSWORD &FC CRTC control
720 CMP #OSW_HDD :BEQ oswFEjmp :\ OSWORD &FE hard disk
730 CMP #OSW_FDC :BEQ oswFBjmp :\ OSWORD &FB floppy disk controller
740 JMP L2800 :\ Else default code to go to OSWORD &FA
750 \ NOTE - Doesn't test for OSWORD &FD
760 :
770 \ Memory used as transient storage
780 \ --------------------------------
790 \ Storage for FDC operations
800 .fdc_dma :EQUD 0 :\ FDC data transfer address
810 .fdc_status :EQUB 0 :\ FDC status when completed
820 .tube_cmd :EQUB 0 :\ Tube transfer command
830 .sector_count:EQUB 0 :\ Number of sectors
840 .error_mask :EQUB 0 :\ Bitmap to test FDC status
850 .fdc_cmd :EQUB 0 :\ FDC command
860 .watchdog1 :EQUB 0 :\ Timer to time out FDC commands
870 .watchdog2 :EQUB 0
880 :
890 \ Mouse coordinates
900 .mouse_y_hi :EQUB 0
910 .mouse_y_lo :EQUB 0
920 .mouse_x_hi :EQUB 0
930 .mouse_x_lo :EQUB 0
940 :
950 .oswFEjmp:JMP osword_fe :\ OSWORD &FE - Jump to RTS
960 .oswFCjmp:JMP osword_crtc :\ OSWORD &FC - CRTC control
970 .oswFFjmp:JMP osword_graph :\ OSWORD &FF - Graphics output
980 .oswFBjmp:JMP osword_fdc :\ OSWORD &FB - Floppy disk access
990 .newevent:JMP eventcode :\ Jump to event handler
1000 .newirq :JMP newirq1 :\ Jump to IRQ1V handler
1010 :
1020 :
1030 \ General Tube access routines
1040 \ ============================
1050 :
1060 \ Get one byte from Tube register 2
1070 \ ---------------------------------
1080 .getR2data
1090 LDA tubeR2stat:BPL tube_oswrch :\ Wait for data present in TubeR2
1100 LDA tubeR2data:RTS :\ Read data from TubeR2
1110 :
1120 \ Check if TubeR1 data present, if not wait for TubeR2 data
1130 .tube_oswrch
1140 LDA tubeR1stat:BPL getR2data :\ If nothing in TubeR1, jump to check TubeR2
1150 LDA tubeR1data:JSR oswrch :\ Read R1 data and send to OSWRCH
1160 JMP tube_oswrch :\ Loop back to wait
1170 :
1180 \ Write one byte to register 2
1190 \ ----------------------------
1200 \ Not called from anywhere
1210 .write_R2
1220 BIT tubeR2stat:BVC write_R2 :\ Wait until TubeR2 available
1230 STA tubeR2data:RTS :\ Write data to TubeR2
1240 :
1250 \ Get one byte from register 4
1260 \ ----------------------------
1270 .read_R4
1280 BIT tubeR4stat:BPL read_R4 :\ Wait for data present in TubeR4
1290 LDA tubeR4data:RTS :\ Read data from TubeR4
1300 :
1310 \ Write one byte to register 4
1320 \ ----------------------------
1330 \ Not called from anywhere
1340 .write_R4
1350 BIT tubeR4stat:BVC write_R4 :\ Wait until TubeR4 available
1360 STA tubeR4data:RTS :\ Write data to TubeR4
1370 :
1380 \ Write one byte to register 1
1390 \ ----------------------------
1400 .write_R1
1410 BIT tubeR1stat:BVC write_R1 :\ Wait until TubeR1 available
1420 STA tubeR1data:RTS :\ Write data to TubeR1
1430 :
1440 :
1450 \ OSWORD &FB for WD1770 floppy controller
1460 \ =======================================
1470 \ The floppy controller uses five registers, pointed to by (&A0)
1480 \ 0 drive control latch
1490 \ 4 command/status
1500 \ 5 track register
1510 \ 6 sector register
1520 \ 7 data register, track for SEEK
1530 :
1540 \ WARNING! - POSITION-DEPENDENT CODE FOLLOWS
1550 \ ------------------------------------------
1560 .fdc_exec
1570 LDA #&00:STA fdc_status :\ Set result=Ok
1580 LDY #&07:LDA (&A0),Y :\ Read FDC data reg to clear any pending DRQ
1590 JSR getR2data:STA error_mask :\ Get FDC status mask
1600 JSR getR2data:STA sector_count :\ Get sector count
1610 JSR getR2data:STA fdc_cmd :\ Get FDC command
1620 JSR tube_program :\ Initiate Tube transfer
1630 LDY #&04:LDA fdc_cmd :\ Get FDC commend
1640 STA (&A0),Y :\ Send command to FDC, start operation
1650 AND #&C0 :\ Check top two bits of FDC command
1660 CMP #&C0:BNE fdc_e7 :\ Not Group 3 or 4 command, leave to interupts
1670 \ This could be just CMP #&C0, BCC fdc_e7
1680 :
1690 LDA #&3C:STA watchdog1 :\ Set watchdog counters for
1700 LDA #&00:STA watchdog2 :\ non-interupt-driven actions
1710 TAX:LDY #&04 :\ Prepare Y=>FDC status register
1720 .fdc_e1
1730 DEX:BNE fdc_e1 :\ Wait 256 loops to allow status to go busy
1740 .fdc_e2
1750 LDA #&01:AND (&A0),Y :\ Test FDC status BUSY flag
1760 \
1770 \ WARNING! - the following instruction must not lie
1780 \ on an address where the bottom 3 bits are set
1790 \ -------------------------------------------------
1800 \ (why? I haven't found anything position-dependent in this code)
1810 :
1820 BEQ fdc_e4 :\ No longer busy...
1830 DEC watchdog2:BNE fdc_e1 :\ Loop back to keep waiting
1840 DEC watchdog1:BNE fdc_e1 :\ Loop back to keep waiting
1850 LDA #&FF:BNE fdc_e5 :\ Return &FF=timeout
1860 :
1870 .fdc_e4
1880 LDY #&04:LDA (&A0),Y :\ Get FDC status
1890 .fdc_e5
1900 STA fdc_status :\ Set the returned status
1910 .fdc_e6
1920 SEI:JSR fdc_event:CLI :\ Generate FDC event
1930 RTS
1940 :
1950 \ Not Group 3 or Group 4 command
1960 \ ------------------------------
1970 .fdc_e7
1980 BPL fdc_e9 :\ Group 1 command, return
1990 LDY #&00:LDX #&00 :\ Group 2 command, wait for interupts
2000 .fdc_e8
2010 LDA status_pending:BNE fdc_e6 :\ NMI finished, return status
2020 DEX:BNE fdc_e8 :\ Loop and keep testing
2030 DEY:BNE fdc_e8 :\ Loop 256*256 times and keep testing
2040 .fdc_e9
2050 RTS :\ Return &00/<>&00 from status_pending
2060 :
2070 \ OSWORD &FB - FDC and I/O control
2080 \ ================================
2090 \ Commands are transfered via TubeR2 within the OSWORD transaction:
2100 \ &00 no more commands
2110 \ &01 FDC action on Master
2120 \ &02 FDC action on Master
2130 \ Command block for &01 and &02:
2140 \ addr0,addr1,addr2,addr3,tube_cmd,rdwr,errmask,count,fdc_cmd
2150 \ Drive, track and sector must be set beforehand by subcode &05+
2160 \ &03 claim NMI and Tube
2170 \ &04 release NMI and Tube
2180 \ otherwise
2190 \ &nn,&mm write &mm to I/O at &FE00+&nn
2200 \
2210 .osword_fdc
2220 CLI:CLD :\ Enable IRQs, ensure binary
2230 JSR getR2data :\ Read tube R2 data - get a command
2240 BNE tube_call_1 :\ If non-zero, jump to test for tube_call_1
2250 .osword_fdc_ret
2260 RTS :\ Done
2270 :
2280 \ These routines claim or release the tube, set up the l770 addresses
2290 \ for the host machine, or write data to memory mapped I/O in SHEILA.
2300 \ ===================================================================
2310 .tube_call_1
2320 CMP #&01 :\ Master FDC command?
2330 BNE tube_call_2 :\ No, try tube_call_2 (B/B+)
2340 JSR tube_setup :\ Get FDC parameters, store at tube_cmd
2350 JSR copy_NMI_data :\ Copy and adapt NMI routine
2360 JSR Master_setup :\ Set up FDC addresses for Master
2370 JSR fdc_exec :\ Get and execute command
2380 JMP osword_fdc :\ Loop back for another command
2390 :
2400 .tube_call_2
2410 CMP #&02 :\ BBC (B/B+) FDC command?
2420 BNE tube_call_3 :\ No, try tube_call_3
2430 JSR tube_setup :\ Get FDC parameters, store at tube_cmd
2440 JSR copy_NMI_data :\ Copy and adapt NMI routine
2450 JSR BBC_setup :\ Set up FDC addresses for BBC
2460 JSR fdc_exec :\ Get and execute command
2470 JMP osword_fdc :\ Loop back for another command
2480 :
2490 .tube_call_3
2500 CMP #&03 :\ Claim tube and NMI?
2510 BNE tube_call_4 :\ No, try tube_call_4
2520 JSR nmi_claim :\ Claim NMIs
2530 JSR tube_claim :\ Claim the Tube
2540 JMP osword_fdc :\ Loop back for another command
2550 :
2560 .tube_call_4
2570 CMP #&04 :\ Release tube and NMI?
2580 BNE other_output :\ No, branch to do generic I/O
2590 JSR tube_release :\ Release tube
2600 JSR nmi_release :\ Release NMIs
2610 JMP osword_fdc :\ Loop back for another command
2620 :
2630 .other_output
2640 TAX :\ Offset into SHEILA in X
2650 JSR getR2data :\ Read tube R2 data - get data byte
2660 STA &FE00,X :\ Store in SHEILA,X - write to I/O
2670 JMP osword_fdc :\ Loop back for another command
2680 :
2690 \ Set up offsets into SHEILA to FDC hardware
2700 \ ------------------------------------------
2710 .BBC_setup
2720 LDX #&84 :\ BBC_fdc_stat at &FE84
2730 LDY #&87 :\ BBC_fdc_data at &FE87
2740 LDA #&80 :\ BBC_fdc_base at &FE80
2750 BNE setup1
2760 .Master_setup
2770 LDX #&28 :\ Master_fdc_stat at &FE28
2780 LDY #&2B :\ Master_fdc_data at &FE2B
2790 LDA #&24 :\ Master_fdc_base at &FE24
2800 :
2810 .setup1
2820 STA &A0 :\ Offset to FDC hardware
2830 LDA #&FE:STA &A1 :\ (&A0),Y=>FDC registers
2840 STX &0D02 :\ Patch NMI status register address
2850 JSR getR2data :\ Get read/write setting
2860 BEQ setup2 :\ &00 - set up for reading
2870 STY &0D0E:RTS :\ <>&00 - patch NMI code for writing
2880 .setup2
2890 STY &0D0B:RTS :\ Patch NMI code for writing
2900 :
2910 .tube_claim
2920 LDA #&C0+1:JSR tube_entry :\ Claim Tube with ID=1
2930 BCC tube_claim:RTS :\ Loop until claimed
2940 :
2950 \ Fill in data transfer address
2960 \ -----------------------------
2970 .tube_setup
2980 LDX #&00
2990 .fdc_dma1
3000 JSR getR2data:STA fdc_dma,X :\ Read address from R2data
3010 INX:CPX #&04:BNE fdc_dma1 :\ Four bytes to read
3020 JSR getR2data:STA tube_cmd :\ Read R2data, store Tube action
3030 RTS
3040 :
3050 .tube_program
3060 LDA tube_cmd :\ A=Tube transfer command
3070 LDX #fdc_dma AND 255 :\ XY=>transfer address
3080 LDY #fdc_dma DIV 256
3090 JSR tube_entry :\ Initiate Tube transfer
3100 RTS
3110 :
3120 .tube_release
3130 LDA #&80+1:JSR tube_entry :\ Release Tube with ID=1
3140 RTS
3150 :
3160 \ These routines claim or release NMI ownership according to whether
3170 \ tube data transfer is to take place or disc access is required. In
3180 \ practical terms only one of three facilities can be the current NMI
3190 \ owner, the disc system, the network handler (econet), or the tube.
3200 \ A copy of this routine's NMI code is kept at nmi_image (&29DB) and
3210 \ transferred to page &D when NMI ownership is required. The routines
3220 \ are called by the code in tube_call_1 to tube_call_4.
3230 \ ===================================================================
3240 .nmi_claim
3250 LDA #&8F:LDX #&0C :\ Service call &0C
3260 LDY #&FF:JSR osbyte :\ Claim NMIs
3270 STY nmi_owner:RTS :\ Store previous NMI owner
3280 :
3290 .nmi_release
3300 LDY nmi_owner :\ Get previous NMI owner
3310 LDA #&8F:LDX #&0B :\ Service call &0B
3320 JMP osbyte
3330 :
3340 .nmi_owner:EQUB 0 :\ Previous NMI owner
3350 :
3360 .copy_NMI_data
3370 LDX #&1F :\ Copy 32 bytes (more than needed)
3380 .nmi_lp1
3390 LDA nmi_image,X:STA &0D00,X :\ Copy NMI code to NMi area
3400 DEX:BPL nmi_lp1:RTS :\ Loop until all done
3410 :
3420 \ This routine is called from the NMI code in the NMI area.
3430 \ NMI occured with no data transfer, will be either an error or a
3440 \ transfer completion. Decide to abort or step to next sector.
3450 \ ---------------------------------------------------------------
3460 .nmi_next_sect
3470 LDY #&04:LDA (&A0),Y :\ Get FDC status from FDC+4
3480 STA fdc_status :\ Save for returned status
3490 AND error_mask :\ Mask for any error bits on
3500 BNE nmi_next_exit :\ Error occured, abort operation
3510 LDA fdc_cmd :\ Check FDC command
3520 BPL nmi_next_exit :\ b7=0, Restore/Seek, so finished
3530 LDA sector_count :\ Get current sector count
3540 CMP #&01 :\ Is this the last one?
3550 BEQ nmi_next_exit :\ Final sector done, finished
3560 DEC sector_count :\ Decre. sector count
3570 LDY #&06:LDA (&A0),Y :\ Get FDC sector register from FDC+6
3580 CLC:ADC #&01 :\ Increment sector number
3590 STA (&A0),Y :\ Set FDC sector register
3600 LDA fdc_cmd:AND #&F3 :\ Get FDC command without settle delay
3610 LDY #&04:STA (&A0),Y :\ Write to FDC command register to start again
3620 RTS
3630 .nmi_next_exit
3640 LDA #&FF:STA status_pending :\ Set that NMI has completed
3650 RTS
3660 :
3670 \ FDC NMI routine, copied to NMI area at &0D00
3680 \ --------------------------------------------
3690 .nmi_image
3700 PHA:LDA &FE00 :\ &0D00 Get FDC status, address set up earlier
3710 AND #&1F :\ &0D04 Keep error bits
3720 CMP #&03:BNE nmi_exit :\ &0D06 If not DRQ+BSY, final NMI, exit
3730 LDA tubeR3data :\ &0D0A Either this or next instruction
3740 STA tubeR3data :\ &0D0D patched to point to FDC data register
3750 PLA:RTI :\ &0D11 Restore and return
3760 .nmi_exit
3770 TYA:PHA :\ &0D12 Also save Y
3780 JSR nmi_next_sect :\ &0D14 Check for next sector or finish
3790 PLA:TAY :\ &0D17 Restore Y
3800 PLA:RTI :\ &0D19 Restore and return
3810 .nmi_end
3820 :
3830 .status_pending:EQUB 0 :\ &00=NMI in progress, <>&00=NMI finished
3840 :
3850 :
3860 \ OSWORD &FF - Write graphics data
3870 \ =========================================================
3880 \ Bit patterns are sent to write to screen memory
3890 \ Commands are sent via TubeR2 within the OSWORD transaction:
3900 \ &00 - no more commands
3910 \ Otherwise high,low - address to start transfer
3920 \ Then data is sent via TubeR1 with subcommand in TubeR2:
3930 \ &00 - read 8 bytes from TubeR1 for next 8 addresses
3940 \ &01-&FE - read 1 byte from TubeR1 for next 8 addresses
3950 \ &FF - go back to wait for another address or exit
3960 \ The data address is updated and wraps from &7FFF to &4000
3970 \ =========================================================
3980 :
3990 .osword_ff_exit
4000 RTS
4010 .osword_graph
4020 CLI:CLD :\ Enable IRQs, ensure binary
4030 .next_addr_hi
4040 JSR getR2data:BEQ osword_ff_exit :\ &00, finish
4050 STA &71 :\ Store as high byte of data address
4060 .next_addr_lo
4070 LDA tubeR2stat:BPL next_addr_lo :\ Wait for data in TubeR2
4080 LDA tubeR2data:TAY :\ Get as offset to data address
4090 LDA #&00:STA &70 :\ (&70)=>data
4100 :
4110 \ Writing to the screen is optimised for maximum possible
4120 \ speed, hence these routines are written 'longhand' and
4130 \ so avoid the use of counters, instructions to decrement
4140 \ them and the tests to check when the loop is complete.
4150 \ Spaces are further optimised because they are the most
4160 \ frequently written character and only need a single
4170 \ fill byte. They are therefore the easiest to write as
4180 \ no reading of tubeR1data is required between bytes. Also,
4190 \ the data address is assumed to always be a multiple of 8.
4200 :
4210 .transfer_loop1
4220 LDA tubeR2stat:BPL transfer_loop1 :\ Wait for data in TubeR2
4230 LDA tubeR2data:BEQ transfer_loop2 :\ Get data, if &00 jump to read 8 bytes
4240 CMP #&FF:BEQ next_addr_hi :\ &FF, go back for next command
4250 :
4260 \ Write single byte to 8 locations
4270 \ --------------------------------
4280 LDA tubeR1data :\ Get byte from TubeR1
4290 STA (&70),Y:INY :\ Write to screen RAM eight times
4300 STA (&70),Y:INY :\ as fast as possible
4310 STA (&70),Y:INY
4320 STA (&70),Y:INY
4330 STA (&70),Y:INY
4340 STA (&70),Y:INY
4350 STA (&70),Y:INY
4360 STA (&70),Y:INY
4370 BNE transfer_loop1 :\ Not next page, go back for more
4380 INC &71 :\ Incr. address high byte
4390 BPL transfer_loop1 :\ If not wrapped round, go back for more
4400 LDA #&40:STA &71 :\ Reset to start of screen at &4000
4410 BNE transfer_loop1 :\ And back for more
4420 :
4430 \ Write 8 bytes to 8 locations
4440 \ ----------------------------
4450 .transfer_loop2
4460 LDA tubeR1data:STA (&70),Y:INY :\ Copy byte to memory
4470 LDA tubeR1data:STA (&70),Y:INY :\ Copy byte to memory
4480 LDA tubeR1data:STA (&70),Y:INY :\ Copy byte to memory
4490 LDA tubeR1data:STA (&70),Y:INY :\ Copy byte to memory
4500 LDA tubeR1data:STA (&70),Y:INY :\ Copy byte to memory
4510 LDA tubeR1data:STA (&70),Y:INY :\ Copy byte to memory
4520 LDA tubeR1data:STA (&70),Y:INY :\ Copy byte to memory
4530 LDA tubeR1data:STA (&70),Y:INY :\ Copy byte to memory
4540 BNE transfer_loop1 :\ Not next page, go back for more
4550 INC &71 :\ Incr. address high byte
4560 BPL transfer_loop1 :\ If not wrapped round, go back for more
4570 LDA #&40:STA &71 :\ Reset to start of screen at &4000
4580 BNE transfer_loop1 :\ And back for more
4590 :
4600 :
4610 \ OSWORD &FC - program CRTC controller, initialise mouse, etc.
4620 \ ============================================================
4630 \ Commands are sent via TubeR2 within the OSWORD transaction:
4640 \ <&80,&mm - Write to CRTC register
4650 \ &FF - No more commands
4660 \ &FE - Initialise mouse handler
4670 \ &FD - Initialise event code
4680 \ &FC - Write to mouse port
4690 \ Otherwise, exit
4700 \
4710 .osword_crtc
4720 JSR getR2data:BMI &2A90 :\ Set up or exit if >&7F received
4730 STA &FE00 :\ Write 6845 CRTC address register
4740 JSR getR2data:STA &FE01 :\ Write 6845 CRTC data register
4750 JMP osword_crtc :\ Loop for more
4760 :
4770 .osword_fc_1
4780 TAX:INX:BEQ osword_fc_exit :\ &FF - finished
4790 INX:BNE osword_fc_2 :\ Not &FE, try osword_fc_2
4800 :
4810 \ Command &FE - initialise Mouse code
4820 \ -----------------------------------
4830 SEI :\ Disable IQRs while changing vector
4840 LDA irqv1+0:STA oldirq1+1 :\ Store old IQR1V
4850 LDA irqv1+1:STA oldirq1+2
4860 LDA #newirq MOD 256:STA irqv1+0 :\ Set new IRQ1V
4870 LDA #newirq DIV 256:STA irqv1+1 :\ Store in IRQ1 vector high byte
4880 CLI :\ re-enable interrupts
4890 LDA #0:STA &FE62 :\ Set UserData as inputs
4900 LDA #&98:STA &FE6E :\ Enable CB1+CB2 interupts
4910 LDA &FE6B:AND #1:STA &FE6B :\ Enable PA latching, disable everything else
4920 LDA &FE6C:AND #&0F:STA &FE6C :\ Clear CB1 and CB2
4930 JMP osword_crtc :\ Loop for more commands
4940 :
4950 \ Command &FD - initialise Event code
4960 \ -----------------------------------
4970 .osword_fc_2
4980 INX:BNE osword_fc_3 :\ Not &FD, try osword_fc_3
4990 LDA eventvec+0:STA oldevent+1 :\ Store old EventV
5000 LDA eventvec+1:STA oldevent+2
5010 LDA #newevent MOD 256:STA eventvec+0 :\ Set new EventV
5020 LDA #newevent DIV 256:STA eventvec+1
5030 JMP osword_crtc :\ Loop for more commands
5040 :
5050 \ Command &FC - write to mouse port
5060 \ -----------------------------------
5070 \ Not implemented
5080 .osword_fc_3
5090 INX:BNE osword_fc_exit :\ Not &FC, exit
5100 JMP osword_crtc :\ Loop for more commands
5110 :
5120 .osword_fc_exit
5130 RTS
5140 :
5150 :
5160 \ EVENT PROCESSING
5170 \ ================
5180 \ On VSync event every 20cs, do some background processing
5190 \
5200 .fdc_event
5210 LDX fdc_status :\ Get the FDC status
5220 LDY #0:STY status_pending :\ Clear the FDC pending flag
5230 LDA #&0A :\ Pass on as Event 10 - FDC result waiting
5240 .oldevent
5250 JMP &0000 :\ Pass on to old EVENTV
5260 :
5270 \ Two-key rollover processing done on VSync event
5280 \ -----------------------------------------------
5290 .eventcode
5300 CMP #4:BNE oldevent :\ Not Event 4 (VSync), pass on
5310 LDA status_pending:BEQ eventcode1 :\ Skip if no FDC event pending
5320 JSR fdc_event :\ Do the FDC event
5330 .eventcode1
5340 JSR keyscan :\ Test SHIFT/CTRL keys
5350 PHP:LDA key1:AND #&7F:PLP:PHP :\ Get current key with bit 7 clear
5360 BPL no_ctrl:ORA #&80 :\ Set bit 7 is CTRL pressed
5370 .no_ctrl
5380 TAX:LDA key2:AND #&7F:PLP :\ Get previous key with bit 7 clear
5390 BVC no_shift:ORA #&80 :\ Set bit 7 if SHIFT pressed
5400 .no_shift
5410 TAY :\ X=CTRL+current key, Y=SHIFT+last key
5420 LDA #4:JSR oldevent :\ Call old EVENTV claimant
5430 :
5440 \ The current key (if any in now in X - The top bit is set
5450 \ if CONTROL was pressed, even when no other key was pressed.
5460 \ The previous key, (if any) is now in Y - The top bit is set
5470 \ if SHIFT was pressed, even when there is no previous key press.
5480 \ This results in VSync Event handler being passed keypresses in
5490 \ X and Y and thence passed over the Tube to the coprocessor.
5500 :
5510 .async_command
5520 JSR read_R4:BEQ async_exit :\ Read from TubeR4, exit if zero
5530 TAX:DEX:BNE async_mouse :\ Not &01, skip to try async_mouse
5540 :
5550 \ Update 6845 CRTC registers
5560 \ --------------------------
5570 JSR read_R4:STA &FE00 :\ Get data from TubeR4, write as CRTC address
5580 JSR read_R4:STA &FE01 :\ Get data from TubeR4, write as CRTC data
5590 JMP async_command :\ Go back for any more commands
5600 :
5610 \ Read mouse button state and position
5620 \ ------------------------------------
5630 .async_mouse
5640 DEX:BNE async_leds :\ Not &02, skip to try async_leds
5650 LDA amx:PHP :\ Set flags from mouse type
5660 LDA userport :\ Read mouse data lines
5670 PLP:BEQ &2B4F :\ Not AMX, skip adjustment
5680 ROL A:ROL A:ROL A :\ AMX buttons are top bits, so move them
5690 ROL A :\ Buttons are now in bits 0, 1, 2
5700 .async_mouse_1
5710 AND #7:EOR #7 :\ Mask off and invert the buttons
5720 JSR write_R1 :\ Send the button state to TubeR1
5730 LDX #3 :\ Prepare to send four bytes of mouse coords
5740 .async_mouse_2
5750 LDA mouse_y_hi,X:JSR write_R1 :\ Send mouse coords to TubeR1
5760 DEX:BPL async_mouse_2
5770 JMP async_command :\ Go back for any more commands
5780 :
5790 \ Set keyboard status and update LEDs
5800 \ -----------------------------------
5810 .async_leds
5820 DEX:BNE async_command :\ Not &03, go back for more commands
5830 JSR read_R4:TAX :\ Read data from TubeR4
5840 LDA #&CA :\ *FX 202 - keyboard status
5850 LDY #0:JSR osbyte :\ Set keyboard status
5860 LDA #&76:JSR osbyte :\ Update LEDs to match status
5870 JMP async_command :\ Go back for any more commands
5880 :
5890 .async_exit
5900 RTS
5910 :
5920 \ Test SHIFT and CTRL keys
5930 \ ------------------------
5940 .keyscan
5950 CLC:CLV:JMP (keyvec) :\ CC+CV=Test SHIFT+CTRL
5960 :
5970 :
5980 \ WARNING! MASKABLE INTERRUPT CODE
5990 \ ===========================================================
6000 \ X and Y must be preserved here. The original contents of A
6010 \ are preserved by the MOS, in zero page location &FC. This
6020 \ must be reloaded before exiting - with an RTI if we process
6030 \ the interrupt, or if we jump to the original vector because
6040 \ we're not interested.
6050 :
6060 .newirq1
6070 LDA &FE6D :\ Get Interupt Flag register
6080 AND #&18:BNE new_irq_code :\ Branch if CB1 or CB2 active edge
6090 LDA &FC :\ Not CB1 or CB2, restore A and continue
6100 .oldirq1
6110 JMP &0000 :\ Pass on to old IRQ1V
6120 :
6130 .new_irq_code
6140 STA ifr_copy :\ Save CB1/CB2 interupt flags
6150 LDA userport:STA orb_copy :\ Get PortB data
6160 AND #&18 :\ Check for AMX mouse
6170 CMP #&18:BEQ new_irq_code2 :\ Will be %xxx11xxx for AMX mouse
6180 LDA #0:STA amx :\ Set amx=0 for tracker ball
6190 LDA #&08:STA mouse_y_quad :\ Set data bit for tracker ball y_quad signal
6200 LDA #&10:STA mouse_x_quad :\ Set data bit for tracker ball x_quad signal
6210 :
6220 \ Check for X movement
6230 \ --------------------
6240 .new_irq_code2
6250 LDA ifr_copy :\ Get interupt register back
6260 AND #&10:BEQ new_irq_code5 :\ CB2 interupt, X moved
6270 :
6280 \ Update X movement
6290 \ -----------------
6300 LDA pcr_copy :\ Get peripheral control copy
6310 EOR #&10:STA pcr_copy :\ Invert pos/neg edge bit
6320 LDA x_edge :\ Get get edge triggering mode
6330 EOR #&FF:STA x_edge :\ Invert it
6340 EOR orb_copy :\ Invert with edge trigger
6350 AND mouse_y_quad :\ Test X direction bit
6360 BNE new_irq_code3 :\ Xdir set, decrease X coord
6370 INC mouse_x_lo :\ Xdir clear, increase X coord
6380 BNE new_irq_code5 :\ No rollover, jump to check Ymovement
6390 INC mouse_x_hi :\ Increase X coordinate
6400 JMP new_irq_code5 :\ And jump to check Ymovement
6410 .new_irq_code3
6420 LDA mouse_x_lo :\ Decrement Xcoord
6430 BNE new_irq_code4 :\ Do a 16-bit decrement
6440 DEC mouse_x_hi :\ Decrement mouse_x_hi
6450 .new_irq_code4
6460 DEC mouse_x_lo :\ Decrement mouse_x_lo
6470 :
6480 \ Check for Y movement
6490 \ --------------------
6500 .new_irq_code5
6510 LDA ifr_copy :\ Get interupt register back
6520 AND #&08:BEQ new_irq_code8 :\ CB1 interupt, Y moved
6530 :
6540 \ Update Y movement
6550 \ -----------------
6560 LDA pcr_copy :\ Get peripheral control copy
6570 EOR #&40:STA pcr_copy :\ Invert pos/neg edge bit
6580 LDA y_edge :\ Get edge triggering mode
6590 EOR #&FF:STA y_edge :\ Invert it
6600 EOR orb_copy :\ Invert with edge trigger
6610 AND mouse_x_quad :\ Test Y direction bit
6620 BNE new_irq_code6 :\ Ydir set, decrease Y coord
6630 INC mouse_y_lo :\ Ydir cler, increment Y coord
6640 BNE new_irq_code8 :\ No rollover, exit
6650 INC mouse_y_hi :\ Increment Y coord
6660 JMP new_irq_code8 :\ And jump to finish
6670 .new_irq_code6
6680 LDA mouse_y_lo :\ Decrement Y coord
6690 BNE new_irq_code7 :\ Do a 16-bit decrement
6700 DEC mouse_y_hi :\ Decrement mouse_y_hi
6710 .new_irq_code7
6720 DEC mouse_y_lo :\ Decrement mouse_y_lo
6730 :
6740 .new_irq_code8
6750 LDA &FE6C:AND #&0F :\ Get peripheral control register CA bits
6760 ORA pcr_copy:STA &FE6C :\ Update with stored CB control bits
6770 LDA #&18:STA &FE6D :\ Clear CB1 and CB2 interupts
6780 LDA &FC:RTI :\ Recover A and return from interupt
6790 :
6800 .amx :EQUB &FF :\ default is AMX, 0 = Tracker
6810 .mouse_y_quad:EQUB 1 :\ 01 = AMX, 08 = Tracker
6820 .mouse_x_quad:EQUB 4 :\ 04 = AMX, 10 = Tracker
6830 .ifr_copy :BRK :\ RAM copy of IFR state
6840 .orb_copy :BRK :\ RAM copy of user port B
6850 .x_edge :BRK :\ defines pos/neg edge triggering
6860 .y_edge :BRK :\ defines pos/neg edge triggering
6870 .pcr_copy :BRK :\ Local copy of PCR
6880 :
6890 \ NOTE A local copy of the peripheral control register is
6900 \ maintained at pcr_copy because someone is reprogramming
6910 \ the VIA when they shouldn't be, leading to mouse reversal
6920 \ - suspect a Master 128 hardware problem (??)
6930 :
6940 \ OSWORD &FE - HARD DISK ACCESS
6950 \ =============================
6960 .osword_fe
6970 RTS :\ not implemented
6980 :
6990 :
7000 .pad :\ Pad to page boundary
7010 EQUS STRING$(((P%+256)AND&FF00)-P%,CHR$0)
7020 ]NEXT
7030 A$=fname$+" "+STR$~mcode%+" "+STR$~O%+" "+STR$~(exec%OR&FFFF0000)+" "+STR$~load%
7040 PRINT"Saving ";A$:OSCLI "SAVE "+A$:PRINT