Mastering Sideways ROM & RAM - Module 14 - Unrecognised Interupts ----------------------------------------------------------------- An interupt is a signal to the 6502 processor informing it that a hardware device somewhere in the system requires immediate attention. Interupts not recognised by the operating system are first offered to the paged ROMs and then to the user via the IRQ2 vector. Service call 5 is used to offer unrecognised interupts to the paged ROMs but, because an interupt could be generated by almost any device, it is not possible to identify the source of an interupt without directly interrogating the hardware that might be responsible for generating it. If you want to design a SWR program to process interupts it must intercept service call 5 and poll the hardware that it expects to generate an interupt to see if that device was responsible for the unrecognised interupt, and if so process it. If you do not want the interupt to be offered to the other ROMs the accumulator should be reset to zero before returning. Always return from an unrecognised interupt with RTS and not RTI. One way of connecting hardware to the BBC Micro is to use the 6522 versatile interface adaptor (VIA). There are two 6522 VIAs in the BBC B. VIA-A is used for internal functions and the joystick fire buttons. VIA-B provides the parallel printer interface and the user port. Printers are the most commonly used device connected to VIA-B, and a printer buffer will be used to demonstrate how interupts generated by external hardware can be intercepted and processed in sideways RAM. The program BUFFER is used to generate an object code file just under &100 bytes long. When the object code is loaded into SWR it uses the remaining 15.75K in the RAM bank as a parallel printer buffer. When sideways RAM is used in this way the size of the object code needs to be as small as possible. For this reason a number of techniques have been used in the source code to make the object code fit into just one page of memory. The SWR header used by the buffer is as small as it can be. All the optional coding has been left out. There is no binary version number, title string, version string, copyright message or tube relocation address. Just the essential jump to the service entry point, ROM type byte, copyright offset pointer and minimum copyright string (lines 250-340). Resetting the user print vector is done with the minimum of coding by taking the Osbyte &A8 call out of the object code (lines 180-210). The service call interpreter does not implement * commands to enable the buffer but instead intercepts service call &FE (tube system post initialisation) to set up the user print extended vector to point to the printer buffer code (lines 470-710). To use the buffer load the object code into SWR and press the Break key. Service call &FE is always issued on reset and so the buffer will be initialised every time you press Break. After pressing the Break key type *FX5,3 to enable the buffer. The printer can then be used as normal but with a 15.75K buffer. Type *FX5,1 or press Ctrl+Break to disable the buffer after printing has been completed. The buffer was designed to be used with a parallel printer using the Centronics. It is unsuitable for serial or other printers and I suspect that the early versions of the Solidisk sideways RAM boards may not allow this program to work properly, although I have not been able to test the program with one to confirm this suspicion. The user print vector is normally used to provide a printer driver for printers which do not have either a Centronics parallel or a standard serial interface. With this printer buffer program the user print vector interfaces the printer buffer with the SWR buffer and the printer hardware. The buffer program reads data from the printer buffer using Osbyte &91 (lines 1020-1040) and writes it into the SWR buffer using a pointer (line 1080) to indicate the position in SWR to store each individual byte. The data is read from the SWR buffer using another pointer (line 1540) to indicate the byte to be written into the VIA-B printer output register. When a byte is recieved by the printer the acknowledge line goes low and generates an IRQ interupt. This is the source of the interupt processed by the program. The pointers are updated with every read and write of the SWR buffer and when a pointer reaches &C000 it is reset to &8100 (lines 900-920 and lines 1620-1640). When the last character in the buffer has been printed the printer driver declares itself dormant and the MOS is informed using Osbyte &7B (lines 1350-1470). When all the data is either printed or in the SWR buffer the computer is released to continue with other tasks but you must not press the Break key or use *FX5 until all printing has been completed. You can continue with any task such as word processing or programming while the printer is using the data in SWR printer buffer. The 6522 VIA used to control the parallel printer interface is quite a complex device controled by 16 registers. The VIA-B registers are mapped onto Sheila addresses &60 to &6F as shown in figure 14.1 +-------------------------------------+ &FE6F ! A Input/Output (no handshake) ! +-------------------------------------+ &FE6E ! Interupt control ! +-------------------------------------+ &FE6D ! Interupt status ! +-------------------------------------+ &FE6C ! Peripheral control (handshake) ! +-------------------------------------+ &FE6B ! Auxiliary (timer/shift reg) control ! +-------------------------------------+ &FE6A ! Shift register ! +-------------------------------------+ &FE69 ! Timer 2 MSB counter ! +-------------------------------------+ &FE68 ! Timer 2 LSB latch/counter ! +-------------------------------------+ &FE67 ! Timer 1 MSB latch ! +-------------------------------------+ &FE66 ! Timer 1 LSB latch ! +-------------------------------------+ &FE65 ! Timer 1 MSB latch/counter ! +-------------------------------------+ &FE64 ! Timer 1 LSB latch/counter ! +-------------------------------------+ &FE63 ! Direction register A ! +-------------------------------------+ &FE62 ! Direction register B ! +-------------------------------------+ &FE61 ! A Input/Output ! +-------------------------------------+ &FE60 ! B Input/Output ! +-------------------------------------+ Figure 14.1 The VIA-B registers ----------- ------------------- Both VIAs have 20 I/O lines grouped into an A side and a B side of 10 lines each. These 10 lines are divided into 8 data lines and 2 handshake lines. The data lines are called PA0 to PA7 on the A side and PB0 to PB7 on the B side. The handshake lines are called CA1 and CA2 on the A side and CB1 and CB2 on the B side. The BBC Micro uses the A side of VIA-B for the printer interface and the B side of VIA-B for the user port. PA0 to PA7 are used as the output data lines for the parallel printer, CA1 is used for the printer acknowledge and CA2 for the printer strobe. The printer buffer program uses the output register at &FE61, the peripheral control register at &FE6C, the interupt status register at &FE6D and the interupt control register at &FE6E. The peripheral control register is used to set up the handshaking with the printer (lines 1490-1510 and line 1550). The number &0A is stored in the least significant nybble of this register and this has the effect of sending a strobe pulse (CA2 low) to the printer for 1 cycle of the 1 MHz clock following a write to the output register at &FE61. The Centronics interface requires a strobe pulse width of at least 0.5 micro seconds at the recieving terminal. The peripheral control register is shown in figure 14.2 with bits 1 and 3 set (see also program lines 1490-1510 and line 1550). 7 6 5 4 3 2 1 0 +-------+-------+-------+-------+-------+-------+-------+-------+ ! CB2 ! CB1 ! CA2 ! CA1 ! ! control !control! control !control! +-------+-------+-------+-------+-------+-------+-------+-------+ 1 0 1 0 &0A Figure 14.2 The peripheral control (handshake) register. ----------- -------------------------------------------- The acknowledge line is connected to CA1 and is used to generate an interupt when the printer has recieved data and is ready to accept more data from the printer buffer. The Centronics protocol takes the acknowledge line low for about 12 micro seconds. CA1 is reset to zero in the peripheral control register (lines 1490-1510 and line 1550) and its corresponding bit in the interupt status register will be set to 1 when the voltage on the CA1 input line goes from high to low. CA1 will set a bit in the interupt status register and generate an IRQ interupt if the CA1 bit in the status register has been set. Bit 2 (CA1) is set by setting bits 7 and 2, ie. by storing &82 in the control register as shown in figure 14.3 (line 1520 and line 1560). Bit 2 of the control register can be cleared by clearing bit 7 and setting bit 2, ie. by storing 2 in the control register (lines 1420-1430). 7 6 5 4 3 2 1 0 +---------+-----+-----+-----+-----+-----+-----+-----+ ! IRQ ! T1 ! T2 ! CB1 ! CB2 ! SR ! CA1 ! CA2 ! Interupt status +---------+-----+-----+-----+-----+-----+-----+-----+ !Set/Clear! T1 ! T2 ! CB1 ! CB2 ! SR ! CA1 ! CA2 ! Interupt control +---------+-----+-----+-----+-----+-----+-----+-----+ 1 0 0 0 0 0 1 0 &82 Figure 14.3 Interupt status and control registers. ----------- -------------------------------------- The control and status registers work as a pair and the status register is interrogated by the buffer program to see if the printer is the source of an interupt (lines 1140-1160). If bits 1 and 7 of the status register are not set then the printer was not the source of the interupt and control is returned to the MOS with all the register preserved (line 1160, lines 1280-1300 and lines 640-710). If the buffer has not been enabled with *FX5,3 control is also returned to the MOS (lines 1170-1190, lines 1280-1300 and lines 640-710). 10 REM: BUFFER 20 REM: (C) Gordon Horsington 1987 30 MODE7 40 HIMEM=&3C00 50 DIM save 50 60 diff=&8000-HIMEM 70 ROMnumber=&F4 80 stack=&103 90 uptv=&222 100 starfx5=&285 110 pointer=&8100 120 printout=&FE61 130 handshake=&FE6C 140 status=&FE6D 150 control=&FE6E 160 osbyte=&FFF4 170 oscli=&FFF7 180 A%=&A8 190 X%=0 200 Y%=&FF 210 extvec=(USR(osbyte)AND&FFFF00)DIV256 220 FOR pass = 0 TO 2 STEP 2 230 P%=HIMEM 240 [ OPT pass 250 BRK 260 BRK 270 BRK 280 JMP service+diff 290 OPT FNequb(&82) 300 OPT FNequb((copyright+diff) MOD 256) 310 .copyright 320 BRK 330 OPT FNequs("(C)") 340 BRK 350 .flag 360 BRK 370 .service 380 PHA 390 TXA 400 PHA 410 TYA 420 PHA 430 TSX 440 LDA stack,X 450 CMP #5 460 BEQ interupt 470 CMP #&FE 480 BNE exit 490 LDA #(buffer+diff) MOD 256 500 STA extvec+&33 510 LDA #(buffer+diff) DIV 256 520 STA extvec+&34 530 LDA ROMnumber 540 STA extvec+&35 550 LDA #&81 560 STA datin+diff+1 570 STA datin+diff+2 580 STA datout+diff+1 590 STA datout+diff+2 600 LDX #&33 610 LDY #&FF 620 STX uptv 630 STY uptv+1 640 .exit 650 PLA 660 TAY 670 PLA 680 TAX 690 PLA 700 .return 710 RTS 720 .buffer 730 CPY #3 740 BNE return 750 CMP #1 760 BNE active 770 STA flag+diff 780 .active 790 PHA 800 TXA 810 PHA 820 TYA 830 PHA 840 .outerloop 850 LDY datin+diff+2 860 LDX datin+diff+1 870 INX 880 BNE nottop 890 INY 900 CPY #&C0 910 BNE nottop 920 LDY #&81 930 .nottop 940 CPX datout+diff+1 950 BNE morespace 960 CPY datout+diff+2 970 BEQ innerloop 980 SEC 990 .morespace 1000 TYA 1010 PHA 1020 LDA #&91 1030 LDX #3 1040 JSR osbyte 1050 PLA 1060 BCS innerloop 1070 .datin 1080 STY pointer 1090 INC datin+diff+1 1100 STA datin+diff+2 1110 CLC 1120 BCC innerloop 1130 .interupt 1140 LDA #&82 1150 BIT status 1160 BEQ restore 1170 LDA starfx5 1180 CMP #3 1190 BNE restore 1200 .innerloop 1210 LDA flag+diff 1220 BNE notpoll 1230 LDA #&82 1240 BIT status 1250 BNE notpoll 1260 .step 1270 BCC outerloop 1280 .restore 1290 CLC 1300 BCC exit 1310 .notpoll 1320 PHP 1330 LDA #0 1340 STA flag+diff 1350 LDA datin+diff+1 1360 CMP datout+diff+1 1370 BNE output 1380 LDA datin+diff+2 1390 CMP datout+diff+2 1400 BNE output 1410 PLP 1420 LDX #2 1430 STX control 1440 LDA #&7B 1450 INX 1460 JSR osbyte 1470 JMP restore+diff 1480 .output 1490 LDA handshake 1500 AND #&F0 1510 ORA #&0A 1520 LDX #&82 1530 .datout 1540 LDY pointer 1550 STA handshake 1560 STX control 1570 STY printout 1580 INC datout+diff+1 1590 BNE notpage 1600 LDY datout+diff+2 1610 INY 1620 CPY #&C0 1630 BNE moreroom 1640 LDY #&81 1650 .moreroom 1660 STY datout+diff+2 1670 .notpage 1680 PLP 1690 BCS innerloop 1700 BCC step 1710 .lastbyte 1720 ] 1730 NEXT 1740 INPUT'"Save filename = "filename$ 1750 IF filename$="" END 1760 $save="SAVE "+filename$+" "+STR$~(HIMEM)+" "+STR$~(las tbyte)+" FFFF8000 FFFF8000" 1770 X%=save 1780 Y%=X% DIV 256 1790 *OPT1,2 1800 CALL oscli 1810 *OPT1,0 1820 END 1830 DEFFNequb(byte) 1840 ?P%=byte 1850 P%=P%+1 1860 =pass 1870 DEFFNequw(word) 1880 ?P%=word 1890 P%?1=word DIV 256 1900 P%=P%+2 1910 =pass 1920 DEFFNequd(double) 1930 !P%=double 1940 P%=P%+4 1950 =pass 1960 DEFFNequs(string$) 1970 $P%=string$ 1980 P%=P%+LEN(string$) 1990 =pass