* ******************************************************** * * Wiz-Print Version 1.4 Spooling Program * by Stephen Maguire * * This code is first initialized with a setup * routine, then saved on disk as GO file. * * STDCIN EQU 951H CIN routine address of N*DOS CONTC EQU 16H CONTC routine address of N*DOS * PRNTR EQU 0DH Printer call address in N*DOS HDERR EQU 19H Hard disk error trap routine DLOOK EQU 1CH File lookup routine DWRIT EQU 1FH File create routine DCOM EQU 22H Read/write routines DRET EQU 28H DOS re-entry point * OPWRT EQU 0 DOS write operation code OPRED EQU 1 DOS read operation code * SNGLON EQU 0EB90H Single density motor on byte DBLEON EQU 0EB35H Double density motor on byte * * * Initialize the driver, with onetime code. The buffer * will overwrite the initialization code. * START JMP INIT * INTINP JMP INPUT Intercept input call INTCTC JMP CTRLC Intercept control-C call INTOUT JMP STRBUF Intercept output call * * * The following data block contains the current * status' of Wiz-Print. * STATS DB DATA * INPADR DS 2 Input routine address of User I/O DVCSTT DB TRUE Will Wiz-Print accept more data? PRTSTT DB TRUE Will Wiz-Print print its buffer? CLRBUF DB TRUE Clear the print buffer if true * WRTSTT DB FALSE The write status -- buffer is NOT full MEMSTT DB TRUE Is next buffer in memory? (if not, then on disk) * DS 2 Reserved for future use * DB DATA,DATA * * * Buffer storage routine called by N*DOS. This routine * stores the input character in a circular disk file * selected by the user. In the event that the entire * disk file should fill up, the program will wait for * empty space. With a large disk file, however, this * should never occur. * * NOTE: The character to be stored comes in in B * STRBUF EQU $ * DB 0FEH "CPI" opcode DVCNUM DB 1 Is the character being sent out of this device? * OROUT JNZ $ Jump to the regular output routine if not * PUSH B Save B and C MOV B,A Save the device number LDA DVCSTT Does status say "accept" data? CPI TRUE Let's check MOV A,B Restore device number in case not POP B JNZ OROUT Exit if not * MOV A,B Put the character in A PUSH H And save all the registers for N* PUSH D PUSH B * MVI H,0 Pick up the North Star stack MVI L,0 DAD SP SHLD STACK Now, save it * LXI SP,STK2 Initialize the internal stack * CALL WRTCHR Send out the character * LHLD STACK Restore the NorthStar stack SPHL * POP B Restore all registers POP D POP H * CHKSTT LDA WRTSTT Is the spool file full? CPI TRUE If so, empty it a bit MOV A,B Character sent out must go back in A RNZ . No, the file is not full, return to N* caller * CALL NSFLSH Interrupt to the output driver JMP CHKSTT Loop up and see if the file is emptier * ******************** * * This routine stores the incoming character in A in the * currently defined print buffer. This buffer could be * contained in memory or in the disk spool file. * WRTCHR LHLD BYTSTR Get the total number of characters stored INX H Add one to the count SHLD BYTSTR Now, save it for later * * We must check to see if the disk spool file is full. * If the difference between the number of memory buffers * written to disk and read from disk equals the number of * buffers that the disk file is long, then the spool file * is full. i.e., * * If total.written - total.read = spool.size, then full. * LDA TOTGOT Get total.read MOV C,A LDA TOTWRT Now, get total.written SUB C Do total.written - total.read (= number left to read) * MOV C,A Save it momemtarily LDA SPLSIZ Find out how large the spool file is CMP C Compare with number of buffer memorys to read JNZ WRT1 If different, the the spool file is NOT full * MVI A,TRUE Say that the spool file is full STA WRTSTT * WRT1 LHLD STRPNT Get the buffer (memory) pointer MOV M,B Store the outgoing character * LDA MEMSTT Is this the first time through? CPI TRUE JNZ WRT2 If not, then ignore the special case routines * * * If this is the first time through, the most efficient way * to output the data is to store the character in the input * buffer as well and fool the program into thinking that it * has read the data off the disk * PUSH H Save the output file buffer pointer MVI D,BUFSIZ DAD D MOV M,B Put the character there POP H Restore output buffer pointer * WRT2 INX H Bump the output buffer pointer SHLD STRPNT And save it for next time * * Test to see if output buffer is full * MOV A,H The high byte will tell us FIX1 CPI OUTBUF+BUFSIZ/100H At the end? RNZ . Return to caller if not * * The output buffer is full, therefore we must write it * to the disk spool file (unless it is the first time through). * LDA MEMSTT Is this the first time through? CPI TRUE Make the test * LXI H,OUTBUF Adjust storage pointer before deciding what to do SHLD STRPNT * MVI A,FALSE The next time through will not be the first time STA MEMSTT * RZ . Return to caller if it's the special case * * * We must now write the output buffer to the spool file on * the disk. * LDA WRTSEC Get the sector number to write to PUSH PSW Save it CALL NXTSEC Go find out the next sector value STA WRTSEC Store that for next time through POP PSW Get this sector value back * MVI B,OPWRT The disk operation is a WRITE LXI D,OUTBUF DE points to the output buffer CALL GETWRT Go write out the buffer * LDA TOTWRT Add one to the total.written count INR A STA TOTWRT * RET . All done * ******************** * * The following two routines are software interrupts. This * enables Wiz-Print to take control without the NorthStar * DOS knowing. * * Interrupt from NorthStar caller to Wiz-Print * NSFLSH PUSH B Push all registers PUSH D PUSH H PUSH PSW * MVI H,0 Save the stack pointer MVI L,0 DAD SP SHLD NSSTK * LHLD FLSTK Get the Wiz-Print stack pointer SPHL * POP PSW Pop all registers POP H POP D POP B RET . Interrupt now * * * Interrupt from Wiz-Print to NorthStar caller * FLSHNS PUSH B PUSH D PUSH H PUSH PSW * MVI H,0 Swap stacks MVI L,0 DAD SP SHLD FLSTK * LHLD NSSTK SPHL * POP PSW POP H POP D POP B RET . UN-interrupt * ******************** * * Flush sends the input buffer to to printer. * FLUSH LDA CLRBUF CPI TRUE JZ FLSH0 * LHLD BYTSTR Get the storage pointer XCHG . LHLD BYTGOT And the print pointer * MOV A,H If they are equal, then nothing to print SUB D Subtract the two JNZ FLSH2 If not zero, then print a character MOV A,L SUB E Keep checking JNZ FLSH2 Nope, not empty * ******************** * * Initialize the buffer * FLSH0 XRA A Set accumulator to zero * STA TOTWRT Since nothing to print, initialize all pointers STA TOTGOT Total.written.read set to zero STA WRTSEC Reading and writing starts at sector zero STA GETSEC * MVI H,0 Likewise, nothing has been stored or retrieved MVI L,0 SHLD BYTSTR SHLD BYTGOT * MVI A,TRUE Indicate that the next printing is in memory STA MEMSTT and not on disk * MVI A,FALSE STA WRTSTT The spool file is not full STA CLRBUF The buffer should not be cleared * LXI H,OUTBUF Initialize the output buffer pointer SHLD STRPNT * LXI H,INBUF And also the input buffer pointer SHLD GETPNT * FLSH1 CALL FLSHNS All done this time return to caller JMP FLUSH Do it all again * ******************** * * Send out the next character and read more from the * disk if necessary * FLSH2 LDA PRTSTT Is the printing turned off? CPI TRUE JNZ FLSH1 Ignore request if so * LHLD GETPNT Get the input buffer pointer MOV B,M Pick up the character to print INX H Bump the pointer SHLD GETPNT And save it for next time * LHLD BYTGOT Add one to the number of characters printed INX H SHLD BYTGOT * * * We are about to call the print driver. HL is set to * the Wizprint-to-NorthStar interrupt routine so that * the printer may return to the NorthStar caller in case * the printer is busy. Of course, when NorthStar calls * again, control will be returned to the print driver for * another printer test. * LXI H,FLSHNS Put Wiz-Print re-entry address in HL * DB 0CDH "CALL" opcode DVRLOC DW SERIAL Call the print driver * * The character is sent, do we need to retrieve more data * from the disk? * LHLD GETPNT Load the buffer pointer MOV A,H Get the high byte FIX2 CPI INBUF+BUFSIZ/100H Make the test JNZ FLSH1 Not, interrupt to NorthStar caller * * We must read the next buffer * LXI H,INBUF Initialize the buffer pointer SHLD GETPNT * LDA TOTWRT If totol.got = total.written, MOV B,A Then the next set of characters to print LDA TOTGOT has not yet been written to disk CMP B Therefore, it is in the output buffer still JNZ FLSH4 Go read data from disk if necessary * * Move the contents of the output buffer to the input buffer * LXI H,INBUF Point to input buffer LXI D,OUTBUF Point to output buffer * FLSH3 LDAX D Pick up character from output buffer MOV M,A Put it in the input buffer INX D Bump both pointers INX H MOV A,H Are we through? FIX3 CPI INBUF+BUFSIZ/100H If at end of input buffer, then yes JNZ FLSH3 Go move more if not * MVI A,TRUE Indicate that an inmemory operation is now STA MEMSTT in progress JMP FLSH5 Go clean up * * * Read in the next block of data * FLSH4 LDA GETSEC Get the sector to read from PUSH PSW Save it a moment CALL NXTSEC Determine sector for next time STA GETSEC Save it POP PSW Get current sector * MVI B,OPRED Disk operation is a READ LXI D,INBUF READ from disk to input buffer CALL GETWRT Go do it * LDA TOTGOT Add one to the number of sectors retrieved INR A STA TOTGOT * FLSH5 MVI A,FALSE Since a buffer was just read, STA WRTSTT The buffer full status must be false JMP FLSH1 * ******************** * * NXTSEC -- The current sector comes in in A * Return with the next sector in A * Z flag set if sector count zeroed * NXTSEC INR A Increment the sector count MOV B,A Save it for testing LDA SPLSIZ Get the spool file size CMP B Is the sector count off the top? MOV A,B Put in A, in case not * RNZ . Return if okay * XRA A Set next-sector to the zero sector RET . * ******************** * * GETWRT -- Read or write an input/output buffer from/to * the disk spool file. * * On Entry: A = disk sector to read/write to * B = operation to perform (OPRED or OPWRT) * DE = buffer address * GETWRT EQU $ PUSH D Save the buffer address PUSH PSW Save the sector number * LHLD HDRADR All hard disk errors will be trapped MOV E,M INX H MOV D,M XCHG . SHLD ERRADR LXI H,ERROR XCHG . MOV M,D DCX H MOV M,E * * LDA DNSTY Express buffer size in its equivalent density form ORA A Single density? MVI A,BUFSEC Get the buffer size first JZ GTWT1 Jump around double density conversion if so RAR . Convert for double density * GTWT1 MOV C,A Save it temporarily * MVI D,0 Make it a 16 bit value MOV E,A * POP PSW Get number of sectors back LHLD DSKADR Get the disk address of the file * GTWT2 DCR A Calculate the disk address of the wanted sector JM GTWT3 DAD D JMP GTWT2 * GTWT3 MOV A,C Retrieve the converted sector count * PUSH PSW LDA DRVNM Get the drive number + density value MOV C,A * POP PSW POP D Get the buffer address back * RETRY EQU $ * PUSH D PUSH H PUSH PSW PUSH B * CALL DISK Go do the disk activity MVI B,DCOM We want the DCOM operation * POP B POP PSW Clean up the stack POP H POP D * LHLD ERRADR Restore the error address XCHG . LHLD HDRADR MOV M,E INX H MOV M,D * RET . * ******************** * * The error routine * ERROR POP B Get operation code PUSH B * MOV A,B CPI OPWRT LXI H,ERMS1 JZ ERR0 * LXI H,ERMS2 * ERR0 CALL OUTSTR * MVI B,10 * ERR1 MVI H,0FFH MVI L,0FFH * ERR2 DCX H Give him time to close the door MOV A,H ORA L JNZ ERR2 * DCR B JNZ ERR1 * POP B Restore all values POP PSW POP H POP D * JMP RETRY * ERMS1 DB CHCR,CHLF ASC 'WP error' DB CHCR,CHLF * ERMS2 DB CHBEL,0 * ******************** * * DISK SHLD HLPAIR * POP H Adjust the return address INX H Move past the MVI B operation code INX H PUSH H Push the new return address * PUSH D Save DE * MVI D,0 Convert the offset to 16 bits DCX H MOV E,M * LHLD DOSADR Get the DOS load address DAD D Add it to HL * POP D Restore DE * PUSH H Push the operation routine address LHLD HLPAIR Restore HL * RET . Go do the operation * ******************** * * Print text message pointed to by HL * OUTSTR MOV B,M XRA A Send it to the console * CALL DISK MVI B,PRNTR * PUSH B MVI B,2 MVI C,0 WTLP DCX B MOV A,B ORA C JNZ WTLP POP B * INX H MOV A,M ORA A JNZ OUTSTR * RET . All done, return * * ******************** * * Input calls are re-directed here * INPUT PUSH H We mustn't destroy HL LHLD INPADR Set up the return address SHLD NRMAL POP H Restore HL CALL NSFLSH Interrupt to Wiz-Print JMP NSEXIT Exit now * ******************** * * Control-C tests are detoured here * CTRLC PUSH H LHLD CNTADR Set up for proper return SHLD NRMAL POP H * CALL NSFLSH Interrupt twice for control-C case CALL NSFLSH * NSEXIT EQU $ DB 0C3H "JMP" opcode NRMAL DS 2 * ******************** * * Data storage area for Wiz-Print * DB DATA * HLPAIR DS 2 Storage location for routine DISK * FLSTK DS 2 Wiz-Print stack pointer NSSTK DS 2 NorthStar stack pointer #1 * STACK DS 2 NorthStar stack pointer #2 * STNDIO DB TRUE Standard I/O is assumed CNTADR DS 2 CTRL-C test routine address HDRADR DS 2 Hard disk error address of DOS ERRADR DS 2 Current error address * PRNTADR DS 2 Print driver run address DOSADR DW DOS NorthStar DOS load address * DSKADR DS 2 Disk address of spool file WRTSEC DS 1 Disk sector last written (1 sector = 1 buffer size) GETSEC DS 1 Disk sector last read STRPNT DS 2 The output buffer pointer GETPNT DS 2 The input buffer buffer pointer * BYTSTR DS 2 Total number of characters transfered to OUTBUF BYTGOT DS 2 Total number of characters read from INBUF TOTWRT DB 0 Total number of buffers written to disk TOTGOT DB 0 Total number of buffers read from disk * SPLSIZ DB DSKBUF/4 Size of spool file in terms of buffer size FLESIZ DB DSKBUF Size of the spool file in physical blocks * DRVNM DB 1 Drive number of disk file (with density on MSB) DNSTY DB 00H Density of file (80H = double, 00H = single) * * The Spool file disk name * DB ' ' File name is preceded and followed by blanks OUTFLE ASC '$PRDEFLT ' Room for output file name and drive DW 0 DB 0 * DS 50H Save a lot of space for stack STK1 EQU $ DS 50H STK2 EQU $ * DB DATA,DATA * ******************** * IOBUFS EQU $/100H*100H+100H * OUTBUF EQU IOBUFS INBUF EQU IOBUFS+BUFSIZ * * INIT LXI SP,STK1 * MVI H,20H HL has the "go address" (blanks for spool file) MVI L,20H * LXI D,OUTFLE DE points to "filename{,drive}" * LDA DNSTY B has density MOV B,A MVI C,7 C has type (type '7' is a spool file) * LDA FLESIZ A has number of sectors long * CALL CREATE Go open the file (create if non-existent) * JC INIT2 Carry says no room on disk * XRA A STA WRTSEC Writing will start at sector 0 STA GETSEC ...and so will reading * LDA DRVNM Get the drive number MOV B,A LDA DNSTY Get the density in use ORA B OR them together STA DRVNM Store drive number + density value * LXI H,ACTMES Send out the "Wiz-Print active" message CALL OUTSTR * LXI H,OUTFLE Put out the name of the spool CALL OUTSTR * LXI H,ACTDVC Now send out the device recognized message CALL OUTSTR * LDA DVCNUM ...followed by the device number ADI 30H MOV B,A * XRA A It goes to the terminal CALL DISK Send it out MVI B,PRNTR * LXI H,MESCRLF Print a CR/LF CALL OUTSTR * LXI SP,STK1 Initialize Wiz-Print's internal stack * LXI H,FLUSH Routine FLUSH will be executed when PUSH H the RET is executed * MVI H,0 MVI L,0 * SHLD BYTSTR Zero out these four count bytes SHLD BYTGOT * PUSH H Push a set of phoney values for each registered PUSH H PUSH H PUSH H * DAD SP Pick up the stack pointer SHLD FLSTK Now save it * LXI H,OUTBUF SHLD STRPNT * FIXDAT LXI H,INBUF SHLD GETPNT * LHLD DOSADR Modify the DOS output pointer to that MVI D,0 output is re-directed to this device MVI E,PRNTR+1 DAD D MOV E,M INX H MOV D,M XCHG . SHLD OROUT+1 Save the old pointer though * LXI H,INTOUT XCHG . MOV M,D DCX H MOV M,E * INX H Now, modify the DOS input pointer INX H INX H * LDA STNDIO Standard I/O? CPI TRUE JNZ INIT1 If so, a different modification is necessary * LHLD DOSADR Point to the DOS Input routine MVI D,STDCIN DAD D * INIT1 MOV E,M Ajust the pointers INX H MOV D,M XCHG . SHLD INPADR * LXI H,INTINP XCHG . MOV M,D DCX H MOV M,E * LHLD DOSADR Now, modify the control-C pointer MVI D,0 MVI E,CONTC+1 DAD D MOV E,M INX H MOV D,M XCHG . SHLD CNTADR LXI H,INTCTC XCHG . MOV M,D DCX H MOV M,E * INX H Determine where the hard disk error routine is INX H INX H SHLD HDRADR * LHLD PRNTADR Set up the print call address SHLD DVRLOC * INIT2 LHLD DOSADR MVI D,0 MVI E,DRET Abort address equals DOS+28H DAD D SHLD START+1 PCHL . Exit to the DOS * ******************** * * HL contains the "go address" * DE points to the file name * B is the density of the file * C is the file type (1 or 7) * A is the number of sectors * GOADR has go address * CREATE EQU $ * SHLD GOADR XCHG . * STA NUMSEC * STA FLESTT Fill these with non-zero values STA RECRET * MOV A,B Save the density value STA FLEDEN ORA A Is it single density? JZ CRTE0 If so, ignore double density correction * LDA NUMSEC Make the double density correction RAR . ANI 7FH STA NUMSEC * CRTE0 MOV A,C Store the file type STA FLETYP SHLD FLELOC And the name pointer * CRTE1 MVI A,1 Go see if that file already exists CALL DISK MVI B,DLOOK * STA DRVNM Save the drive number just in case JNC CRTE7 It does, go check to see if all is okay * XRA A File is new STA FLESTT * SHLD DSKADR Save the disk address * LDA DRVNM Set the default unit LHLD FLELOC Point to a blank file name DCX H CALL DISK Look it up MVI B,DLOOK RC . Return with carry set if no room in directory * MVI D,0FFH Back up 8 spaces MVI E,0F8H DAD D * XCHG LHLD FLELOC Pick up the file name XCHG * MVI C,8 CRTE2 LDAX D Now, transfer it to the directory CPI ' ' JZ CRTE3 CPI ',' JZ CRTE3 MOV M,A INX D INX H DCR C JNZ CRTE2 * CRTE3 INR C DCR C JZ CRTE4 MVI M,' ' INX H JMP CRTE3+1 * CRTE4 XCHG LHLD DSKADR XCHG . MOV M,E INX H MOV M,D * INX H Now, number of sectors LDA NUMSEC MOV M,A INX H MVI M,0 * INX H Set type with density LDA FLEDEN MOV M,A LDA FLETYP ORA M MOV M,A * ANI 7FH CPI 07H Spooler? INX H MVI D,20H Fill DE with blanks MVI E,20H JZ CRTE5 * PUSH H LHLD GOADR XCHG . POP H CRTE5 MOV M,E INX H MOV M,D INX H MVI M,' ' * CALL DISK MVI B,DWRIT * LHLD FLELOC JMP CRTE1 * JMP ERROR * CRTE7 PUSH H MOV E,M Get the disk address and save it INX H MOV D,M XCHG . SHLD DSKADR XCHG . INX H LDA NUMSEC CMP M JNZ CRTE8 INX H INX H LDA FLETYP MOV B,A LDA FLEDEN ORA B CMP M JNZ CRTE8 INX H LDA GOADR CMP M JNZ CRTE8 INX H LDA GOADR+1 CMP M * CRTE8 POP H RZ . * MVI D,0FFH MVI E,0F8H DAD D MVI A,16 CRTE9 MVI M,' ' DCR A JNZ CRTE9 * STA RECRET * CALL DISK MVI B,DWRIT * LHLD FLELOC JMP CRTE1 * DB DATA * FLESTT DS 1 Is the file new or old? (0=new) RECRET DS 1 If new, is it really new or just re-created? GOADR DS 2 Go address of file FLELOC DS 2 Pointer to the filename in question FLETYP DS 1 The file type (1 if Wiz-Print, 7 if Spool file) FLEDEN DS 1 The density of the file NUMSEC DS 1 Number of sectors in file to be opened * ACTMES DB CHCR,CHLF ASC 'Wiz-Print by Stephen Maguire' DB CHCR,CHLF ASC 'Version 1.4 Copyright (C) 1981' DB CHCR,CHLF ASC 'Active spool file: ' DB 0 ACTDVC DB CHCR,CHLF ASC 'Device # ' DB 0 MESCRLF DB CHCR,CHLF,CHCR,CHLF,0 * DB DATA,DATA * * * ORG 2*BUFSIZE+IOBUFS I/O buffers use 1K apiece * * The print routine goes here: * DRIVER EQU $ *