0100 ; PRINTER SPOOLER 0110 ; BY GLENN K. SMITH 0120 ; (c)1988, ANTIC PUBLISHING 0130 .OPT NO LIST 0140 .OPT OBJ 0150 ; 0160 DOSVEC = $0A ;DOS VECTOR 0170 DOSINI = $0C ;DOS INIT 0180 DEST = $CC ;DEST ADDRESS 0190 SOURCE = $CE ;SOURCE ADDRESS 0200 VVBLKD = $0224 ;VBI ADDRESS 0210 DDEVIC = $0300 ;DEVICE ID 0220 HATABS = $031A ;HANDLER TABLE 0230 PRBUFF = $03C0 ;PRINTER BUFFER 0240 MEMLO = $02E7 ;MEMLO POINTER 0250 SMOVE = $44AE ;START OF MOVER 0260 SPOOLER = $4500 ;SPOOLER ADDR 0270 SPOOL1 = $4600 ;SPOOLER+$100 0280 SPOOL2 = $4700 ;SPOOLER+$200 0290 BUFEND = $66B0 ;END OF BUFFER 0300 SIOV = $E459 ;SIOV VECTOR 0310 SETVBV = $E45C ;VBV SET ROUTINE 0320 XITVBV = $E462 0330 ; 0340 ; +---------------------------+ 0350 ; | This is the relocator part| 0360 ; | of PRINTER SPOOOLER. It | 0370 ; | will move the program to | 0380 ; | the lowest point possible | 0390 ; | in memory, then run the | 0400 ; | PRINTER SPOOLER. | 0410 ; +---------------------------+ 0420 ; 0430 *= SMOVE ;START PROGRAM 0440 ; 0450 BOOT 0460 LDY MEMLO+1 ;GET NEW ADDRESS 0470 INY ;MAKE NEXT EVEN NUMBER 0480 STY DEST+1 ;SAVE IT 0490 ; 0500 LDY #$00 ;CLEAR LSB 0510 STY DEST 0520 STY SOURCE 0530 ; 0540 LDA # >OLDMEM ;START OF SPOOLER 0550 STA SOURCE+1 0560 ; 0570 RELOC 0580 LDX MEMLO+1 ;USED TO FIGURE NEW ADDR 0590 LDA (SOURCE),Y ;MOVE SPOOLER 0600 CMP # >BUFEND ;BUFEND MSB 0610 BEQ FIXEND ;YES, FIX IT 0620 ; 0630 CMP # >SPOOLER ;SPOOLER ADDRESS? 0640 BEQ ZERO ;YES, IN FIRST 256 BYTES 0650 ; 0660 CMP # >SPOOL1 ;SPOOLER ADDRESS? 0670 BEQ ONE ;YES, IN SECOND 256 BYTES 0680 ; 0690 CMP # >SPOOL2 ;SPOOLER ADDRESS? 0700 BNE RELSTOR ;NO, SAVE AS IS 0710 ; 0720 FIXEND 0730 TXA ;FIX MSB OF BUFEND 0740 CLC 0750 ADC #$21 0760 BNE RELSTOR 0770 ; 0780 TWO 0790 INX ;ADDR IS 512 BYTES FROM ORG 0800 ONE 0810 INX ;ADDR IS 256 BYTES FROM ORG 0820 ZERO 0830 INX ;ADD 1 BECAUSE THE MSB OF MEMLO 0840 TXA ;HAD 1 ADDED TO IT 0850 ; 0860 RELSTOR 0870 STA (DEST),Y ;SAVE BYTE 0880 INC DEST ;GET NEXT ADDRESS 0890 INC SOURCE 0900 BNE EXAMINE ;NOT ZERO 0910 ; 0920 INC DEST+1 ;INC MSB 0930 INC SOURCE+1 0940 ; 0950 EXAMINE 0960 LDA SOURCE+1 ;ALL DONE? 0970 CMP # >FINI 0980 BNE RELOC ;NO GET MORE 0990 ; 1000 LDA SOURCE ;LSB THE SAME? 1010 CMP # <FINI 1020 BNE RELOC ;NO, MORE 1030 ; 1040 LDX MEMLO+1 ;GET ADDRESS TO JUMP TO 1050 INX 1060 INX 1070 STX BOOTIT+2 1080 BOOTIT 1090 JMP START ;CALL SPOOLER 1100 ; 1110 ; +---------------------------+ 1120 ; | This is the main PRINTER | 1130 ; | SPOOLER program that will | 1140 ; | be relocated in memory | 1150 ; +---------------------------+ 1160 ; 1170 ;+----------------------------+ 1180 ;| Storage used by Spooler | 1190 ;+----------------------------+ 1200 ; 1210 OLDMEM 1220 .BYTE $00,$00 ;OLD MEMLO VALUE 1230 OLDVVB 1240 .BYTE $00,$00 ;OLD VBI ADDRESS 1250 OLDHAND 1260 .BYTE $00,$00 ;OLD P: HANDLER ADDRESS 1270 INDEX 1280 .BYTE $00 ;PRINT BUFFER INDEX 1290 STATUS 1300 .BYTE $01 ;PRINT STATUS 1310 PRIORITY 1320 .BYTE $00 ;WHO DOES WHAT WHEN 1330 CHAR 1340 .BYTE $00 ;CHAR TO BE PRINTED 1350 IOCB 1360 .BYTE $00 ;DEVICE NUMBER 1370 COUNT 1380 .BYTE $00,$00 ;NUMBER OF CHARACTERS 1390 ; 1400 ;+----------------------------+ 1410 ;| P: HANDLER PUT ROUTINE | 1420 ;|This will store a character | 1430 ;| into the printer buffer | 1440 ;+----------------------------+ 1450 ; 1460 PUTCHAR 1470 STA CHAR ;SAVE CHAR TO BE PRINTED 1480 STX IOCB ;SAVE CHANNEL 1490 LDA COUNT ;ANY CHARACTERS YET? 1500 ORA COUNT+1 1510 BEQ STORE ;NO, BUFFER EMPTY 1520 ; 1530 WAIT 1540 LDA INPUT+1 ;BUFFER FULL? 1550 CMP OUTPUT+1 1560 BNE STORE ;NO, SOME SPACE LEFT 1570 ; 1580 LDA INPUT+2 ;MAYBE? 1590 CMP OUTPUT+2 1600 BNE STORE ;YES, WAIT UNTIL SOME PRINTED 1610 ; 1620 LDA #$00 1630 STA PRIORITY ;FORCE PRINT 1640 BEQ WAIT 1650 ; 1660 STORE 1670 LDA CHAR ;GET CHAR 1680 INPUT 1690 STA BUFFER ;SAVE IT 1700 ; 1710 INC COUNT ;UPDATE LSB OF CHAR COUNTER 1720 BNE BUMPIN ;NO CARRY 1730 INC COUNT+1 ;UPDATE MSB PART OF COUNTER 1740 ; 1750 BUMPIN 1760 INC INPUT+1 ;MOVE INPUT POINTER 1770 BNE CHECKIN ;NO CARRY 1780 INC INPUT+2 ;ADD CARRY TO MSB OF POINTER 1790 ; 1800 CHECKIN 1810 LDA INPUT+2 ;ROUND POINTER TO START OF BUFFER? 1820 CMP # >BUFEND 1830 BNE EXITPUT ;NO 1840 ; 1850 LDA INPUT+1 ;MAYBE? 1860 CMP # <BUFEND 1870 BNE EXITPUT ;NO, NOT YET 1880 ; 1890 LDA # <BUFFER ;ROUND TO START OF BUFFER 1900 LDX # >BUFFER 1910 STA INPUT+1 1920 STX INPUT+2 1930 ; 1940 EXITPUT 1950 LDX IOCB ;RESTORE IOCB IF NEEDED 1960 LDY #$01 ;PRINT WAS GOOD 1970 STY PRIORITY ;PUT ROUTINE HAS PRIORITY 1980 RTS 1990 ; 2000 ;+----------------------------+ 2010 ;| This is the PRINT routine | 2020 ;|that is called by the VVBLKD| 2030 ;| every 1/60th of a second | 2040 ;+----------------------------+ 2050 ; 2060 ; +---------------------------+ 2070 ; | If the priority flag=1 | 2080 ; | then the PUT CHAR routine | 2090 ; | will have priority over | 2100 ; | the print routine. If the | 2110 ; | PUT CHAR is done, then the| 2120 ; | VBI print routine has will| 2130 ; | print a character every | 2140 ; | sixtieth of a second. | 2150 ; +---------------------------+ 2160 ; 2170 NEWVBI 2180 LDA PRIORITY ;OK TO RUN? 2190 BEQ SEESTAT ;YES, ATTEMPT PRINT 2200 ; 2210 DEC PRIORITY ;SET TO VBI PRIORITY 2220 JMP XITVBV ;IF NO CHANGE, PRINT NEXT TIME 2230 ; 2240 SEESTAT 2250 LDA STATUS ;PRINT OK? 2260 BPL VBICALL ;YES, MOVE CHARS 2270 ; 2280 JMP PRINT ;NO, RE-TRY BUFFER 2290 ; 2300 VBICALL 2310 LDA COUNT ;ANY CHARS TO BE PRINTED? 2320 ORA COUNT+1 2330 BNE ISCHARS ;YES 2340 ; 2350 JMP FINISHED ;NO, EXIT 2360 ; 2370 ISCHARS 2380 LDX INDEX ;GET BUFFER INDEX 2390 OUTPUT 2400 LDA BUFFER ;GET CHAR TO BE PRINTED 2410 STA PRBUFF,X 2420 TAY ;SAVE IT 2430 INC OUTPUT+1 ;MOVE OUTPUT POINTER TO 2440 BNE CHECKOUT ;NEXT CHAR 2450 INC OUTPUT+2 ;ADD CARRY TO MSB OF POINTER 2460 ; 2470 CHECKOUT 2480 LDA OUTPUT+2 ;ROUND OUTPUT BUFFER? 2490 CMP # >BUFEND 2500 BNE SUBTRACT ;NO, NOT YET 2510 ; 2520 LDA OUTPUT+1 ;MAYBE? 2530 CMP # <BUFEND 2540 BNE SUBTRACT ;NO, NOT NEED YET 2550 ; 2560 LDA # <BUFFER ;ROUND OUTPUT POINTER TO 2570 LDX # >BUFFER 2580 STA OUTPUT+1 2590 STX OUTPUT+2 2600 ; 2610 SUBTRACT 2620 LDA COUNT ;COUNT DOWN THE CHAR COUNTER 2630 BNE DECLSB ;LSB NOT TO ZERO 2640 ; 2650 DEC COUNT+1 ;DO THE MSB OF THE COUNTER TOO 2660 DECLSB 2670 DEC COUNT ;DO THE LSB OF THE COUNTER 2680 INX ;MOVE PRINT BUFFER INDEX 2690 STX INDEX ;SAVE IT 2700 CPX #40 ;40 CHARS YET? 2710 BEQ SETPRNT ;YES, FLUSH PRINT BUFFER 2720 ; 2730 CPY #155 ;A EOL? 2740 BNE FINISHED ;NO, GET MORE CHARS 2750 ; 2760 LDA #$20 ;PADD BUFFER IF EOL 2770 FILL 2780 STA PRBUFF,X 2790 INX ;ADD 1 TO THE COUNTER 2800 CPX #40 ;40 CHARACTERS YET? 2810 BNE FILL ;NO, PADD MORE BLANKS 2820 ; 2830 ; +---------------------------+ 2840 ; | SETPRNT tells the VBI | 2850 ; | routine that the last | 2860 ; | was bad. This allows the | 2870 ; | the computer to print | 2880 ; | during the next interrupt | 2890 ; | instead of doing it all | 2900 ; | during one interrupt. | 2910 ; +---------------------------+ 2920 ; 2930 ; I could have used any number greater than 2940 ; 127. I picked $92 because it was handy, and 2950 ; had some meaning. 2960 ; 2970 SETPRNT 2980 LDY #$92 ;FUNCTION NOT IMPLEMENTED 2990 JMP QUIT ;SAVE RESULT 3000 ; 3010 ; +---------------------------+ 3020 ; | This is the actual printer| 3030 ; | part of PRINTER SPOOLER. | 3040 ; | It will save the old SIO | 3050 ; | DCB, print the buffer, and| 3060 ; | restore the SIO DCB back. | 3070 ; +---------------------------+ 3080 ; 3090 PRINT 3100 LDX #$0B ;SAVE SIO DCB 3110 SAVEDCB 3120 LDA DDEVIC,X 3130 STA OLDDCB,X 3140 DEX ;ALL DONE YET? 3150 BPL SAVEDCB ;NOPE, STILL SOME LEFT 3160 ; 3170 LDX #$0B ;SETUP SIO DCB 3180 PMOVE 3190 LDA SIODAT,X ;MY PRINT DATA 3200 STA DDEVIC,X ;SAVE SO COMPUTER WILL KNOW 3210 DEX ;ANY MORE TO MOVE? 3220 BPL PMOVE ;YES, SOME LEFT 3230 ; 3240 INX ;MAKE 0 3250 STX INDEX ;SAVE BUFFER OFFSET 3260 JSR SIOV 3270 ; 3280 LDX #$0B ;RESTORE SIO DCB 3290 REPLACE 3300 LDA OLDDCB,X ;GET THE OLD INFO 3310 STA DDEVIC,X ;AND REPLACE IT. JUST IN CASE! 3320 DEX ;ALL DONE WITH REPLACMENT? 3330 BPL REPLACE ;NO, STILL A FEW TO REPLACE 3340 .BYTE $2C ;TRICK, SKIP NEXT INSTRUCTION 3350 ; 3360 FINISHED 3370 LDY #$01 ;SAY PRINT WAS GOOD 3380 QUIT 3390 STY STATUS ;PRINT STATUS 3400 JMP XITVBV ;EXIT VVBLKD 3410 ; 3420 ; +---------------------------+ 3430 ; | This is the information | 3440 ; | that is needed by the SIO | 3450 ; | to attempt a print. | 3460 ; +---------------------------+ 3470 ; 3480 SIODAT 3490 .BYTE $40 ;P: 3500 .BYTE $01 ;#1 3510 .BYTE $57 ;WRITE 3520 .BYTE $80 ;OUTPUT 3530 .BYTE $C0 ;PRINT BUFFER LSB 3540 .BYTE $03 ;PRINT BUFFER MSB 3550 .BYTE $1E ;DEVICE TIMEOUT 3560 .BYTE $00 ;NOT USED 3570 .BYTE $28 ;40 CHARS 3580 .BYTE $00 ;NOT USED 3590 .BYTE $4E ;NORMAL MODE 3600 .BYTE $00 ;NOT USED 3610 ; 3620 ; +---------------------------+ 3630 ; | Temporary storage for the | 3640 ; | SIO DCB. Contains the | 3650 ; | values before the print | 3660 ; | was attempted. | 3670 ; +---------------------------+ 3680 ; 3690 OLDDCB 3700 .BYTE $00,$00,$00,$00,$00,$00 3710 .BYTE $00,$00,$00,$00,$00,$00 3720 ; 3730 ; +---------------------------+ 3740 ; | This the new DOS vector. | 3750 ; | It will replace the old | 3760 ; | values and disable the | 3770 ; | PRINT SPOOLER. All output| 3780 ; | to the printer will stop. | 3790 ; +---------------------------+ 3800 ; 3810 NEWDOS 3820 LDA CALLDOS+1 ;REPLACE DOSVEC 3830 LDX CALLDOS+2 3840 STA DOSVEC ;SAVE OLD VECTOR 3850 STX DOSVEC+1 3860 ; 3870 LDA RESET+1 ;REPLACE DOSINI 3880 LDX RESET+2 3890 STA DOSINI ;SAVE OLD DOSINI 3900 STX DOSINI+1 3910 ; 3920 LDA OLDMEM ;REPLACE MEMLO 3930 LDX OLDMEM+1 3940 STA MEMLO ;SAVE OLD MEMLO VALUE 3950 STX MEMLO+1 3960 ; 3970 LDA OLDHAND ;REPLACE P: HANDLER 3980 LDX OLDHAND+1 3990 STA HATABS+1 ;SAVEE THE OLD HANDLER 4000 STX HATABS+2 4010 ; 4020 LDY OLDVVB ;REPLACE VVBLKD 4030 LDX OLDVVB+1 4040 LDA #$07 4050 JSR SETVBV ;REMOVE THE VVBLKD 4060 ; 4070 CALLDOS 4080 JMP CALLDOS ;CALL OLD DOSVEC 4090 ; 4100 ; +---------------------------+ 4110 ; | This is the RESET trap | 4120 ; | routine. It will make sure| 4130 ; | that the SPOOLER is ready | 4140 ; | to handle data when needed| 4150 ; +---------------------------+ 4160 ; 4170 RESET 4180 JSR DOSINI ;INITIALIZE DOS 4190 SETDOS 4200 LDA # <NEWDOS ;TRAP DOS VECTOR 4210 LDX # >NEWDOS 4220 STA DOSVEC ;MAKE SURE DOSVECTOR IS SET 4230 STX DOSVEC+1 4240 ; 4250 LDA # <BUFFER ;RESET TO START OF BUFFER 4260 LDX # >BUFFER 4270 STA INPUT+1 ;INPUT BUFFER 4280 STX INPUT+2 4290 STA OUTPUT+1 ;OUTPUT BUFFER 4300 STX OUTPUT+2 4310 ; 4320 LDA # <BUFEND ;SAVE SOME MEMORY FOR THE BUFFER 4330 LDX # >BUFEND 4340 STA MEMLO ;TELL THE COMPUTER 4350 STX MEMLO+1 4360 ; 4370 LDA # <OPEN ;POINT P: TO MY HANDLER 4380 LDX # >OPEN 4390 STA HATABS+1 ;STUFF IT IN THE HANDLER TABLE 4400 STX HATABS+2 4410 ; 4420 LDY #$00 ;CLEAR COUNTER 4430 STY COUNT ;CLEAR THE LSB 4440 STY COUNT+1 ;CLEAR THE MSB 4450 STY INDEX ;CLEAR PRINT BUFFER INDEX 4460 ; 4470 INY ;SET TO 1 4480 STY STATUS ;SET PRINTER STATUS 4490 ; 4500 LDY # <NEWVBI ;INIT VBI PRINT ROUTINE 4510 LDX # >NEWVBI 4520 LDA #$07 4530 JMP SETVBV 4540 ; 4550 ; +---------------------------+ 4560 ; | This will be the new P: | 4570 ; | handler vector table. The | 4580 ; | only change is in the way | 4590 ; | the P: device will print. | 4600 ; +---------------------------+ 4610 ; 4620 OPEN 4630 .BYTE $00,$00 ;OPEN P: 4640 CLOSE 4650 .BYTE $00,$00 ;CLOSE P: 4660 GET 4670 .BYTE $00,$00 ;GET P: 4680 PUT 4690 .WORD PUTCHAR-1 ;PUT P: 4700 STATS 4710 .BYTE $00,$00 ;STATUS P: 4720 SPECIAL 4730 .BYTE $00,$00 ;WHATEVER 4740 INIDEV 4750 .BYTE $00,$00,$00 ;INITIALIZE P: 4760 ; 4770 BUFFER 4780 .BYTE $00 ;START OF BUFFER 4790 ; 4800 ; +---------------------------+ 4810 ; | Locate the P: handler and | 4820 ; | and copy the vectors to my| 4830 ; | handler. Copy information,| 4840 ; | addresses, and initialize | 4850 ; | the PRINTER SPOOLER | 4860 ; +---------------------------+ 4870 ; 4880 START 4890 LDA HATABS+1 ;GET HANDLER ADDRESS 4900 LDX HATABS+2 4910 STA DEST ;SAVE ADDRESS 4920 STX DEST+1 4930 STA OLDHAND ;KEEP A COPY FOR DOS CALL 4940 STX OLDHAND+1 4950 ; 4960 LDY #$00 ;MOVE HANDLER 4970 MOVELO 4980 LDA (DEST),Y ;GET HANDLER DATA 4990 STA OPEN,Y ;SAVE IT 5000 INY 5010 CPY #$06 ;SKIP PUT ADDRESS 5020 BNE MOVELO ;YES 5030 ; 5040 LDY #$08 ;GET REST OF HANDLER 5050 MOVEHI 5060 LDA (DEST),Y ;GET SOME DATA 5070 STA OPEN,Y ;SAVE IT 5080 INY 5090 CPY #$0F ;MOVE SOME MORE DATA? 5100 BNE MOVEHI ;YEP, A FEW MORE BYTES 5110 ; 5120 LDA DOSINI ;COPY DOSINI VECTOR 5130 LDX DOSINI+1 5140 STA RESET+1 5150 STX RESET+2 5160 ; 5170 LDA DOSVEC ;COPY DOS VECTOR 5180 LDX DOSVEC+1 5190 STA CALLDOS+1 5200 STX CALLDOS+2 5210 ; 5220 LDA # <RESET ;TRAP RESET 5230 LDX # >RESET 5240 STA DOSINI 5250 STX DOSINI+1 5260 ; 5270 LDA MEMLO ;SAVE OLD MEMLO VALUE 5280 LDX MEMLO+1 5290 STA OLDMEM 5300 STX OLDMEM+1 5310 ; 5320 LDA VVBLKD ;SAVE OLD VVBLKD 5330 LDX VVBLKD+1 5340 STA OLDVVB 5350 STX OLDVVB+1 5360 ; 5370 JMP SETDOS ;SETUP SPOOLER 5380 ; 5390 FINI 5400 BRK ;FOR NO REASON 5410 ; 5420 ; ADD RUN ADDRESS FOR DOS 5430 ; 5440 *= $02E0 5450 .WORD SMOVE 5460 ; 5470 ; END PROGRAM 5480 ; 5490 .END
Back to previous page