* * SolPrinter 3 Driver * 1.0 (mod 1) * * * Equates * * Conditions * TRUE equ 00001H FALSE equ 00000H * BUSY equ 0FFFFH DONE equ 00000H * * Characters * CHnull equ 000H CHdel equ 07FH CHcr equ 00DH CHlf equ 00AH CHff equ 00CH CHfle equ 001H CHnolf equ 0FFH CHesc equ 01BH CHsp equ 020H CHb equ CHsp CHws equ 07EH * * Control/Status Codes * CSds equ 7 device status request CSwpm equ 100 word processor mode CScps equ 101 cross perfs skip (not supported) CSsps equ 102 set page size (not supported) CSshi equ 103 set horz. inc. CSsvi equ 104 set vert. inc. CScb equ 105 cancel buffer * * I/O Port Assignments * IOssp - serial status port * IOsdp - serial data port * IOssp equ 0F8H IOsdp equ 0F9H IOsdr equ 002H data set ready (when 0) IOscs equ 020H clear to send (when 0) IOsbe equ 080H transmitter buffer empty (when 1) * * Maximums and Initial Settings * MXvi equ 7 max vert. inc. Ivi equ 8 * * PTDOS equates * nlst copy NPTDEFS lst * * the program origin * org 07800H * * The Device Header * DTrb dw 0 no reads DTrnb dw 0 DTrlb dw 0 DTwbr dw wblock write a block of 1 DTwb dw wblock write a block of 1 DTrew dw dummy rewind supported for BASIC DTeof dw eof end-file DTclo dw close the close operation DTsek dw 0 seek not supported DTctl dw ctrl control/status call DTblk dw 1 block size must be 1 !!! DTito db 1 must be 1 !!! DTini dw init dummy ret * * * wblock -- write a block of 1 character * wblock lda mode word processing mode? ora a jnz wbl2 yes * wbl1 call ti test input status jz wbl3 jump if status is DONE (Z flag = 1) call task not done, give printer task a chance jmp wbl1 try again * * if in word processing mode then don't wait for input * to go DONE; instead, return to caller. * wbl2 call ti test input status jnz wblret return if status is BUSY (Z flag = 0) * * Here, get the character and start the printer task * by setting its status to BUSY. * wbl3 mov a,m get character call sib set input BUSY call task give the printer driver a chance to run * fall thru * * return to wblock caller * wblret xthl inx h inx h inx h xthl lxi h,0 nothing read ret * * * eof -- write an end-file on the printer * eof call cantst test for cansel rz call wblock write any residew jmp dummy ignore eof return ret * * * close -- close the printer driver * close call cantst test for cansel cloz1 call ti test input status rz . return when printer driver goes DONE (Z flag = 1) call task BUSY, give it a chance to go DONE jmp cloz1 keep trying * * * ctrl -- process the Control/Status calls * * CSds -- return: DE=0 ==> printer driver BUSY * DE=1 ==> printer driver DONE * A =1 always * * CSwpm - input : E =1 ==> word processor mode * E =0 ==> not word processor mode * return: A =1 ==> was in word processor mode * A =0 ==> was not in word processor mode * * CSshi - ignored * * CSsvi - input: E = new vertical increment in 1/48" * output:A = old increment * * CScb -- cancel the contents of any internal buffers * ctrl cpi CSds device status? jnz ctrl1 * call task give the printer task a chance to run call ti test input status jz ctrl0 DONE, indicate so lxi d,0 BUSY, indicate so mvi a,1 ret ctrl0 lxi d,1 DONE mvi a,1 ret ctrl1 equ $ * cpi CSwpm change word processing mode? jnz ctrl2 * lxi h,mode mov a,m get old value mov m,e set new value ret ctrl2 equ $ * cpi CSshi rz . ignored but supported * cpi CSsvi jnz ctrl3 * lxi h,vi mov a,m get old value mov m,e save new value ret . done ctrl3 equ $ * cpi CScb jnz ctrle error, Control/Status op not supported * mvi a,TRUE sta cansel set cansel flag ret * * * Control/Status op not supported * ctrle call ERRL2 db ERNCT * * * task -- Saves the state of the machine for PTDOS and * restores the state of the machine for the * printer driver. * task push b save state for PTDOS push d push h push psw lxi h,0 dad sp shld ptstk * lhld tskstk restore the machine state for the printer driver sphl pop psw pop h pop d pop b ret . this will take us back to whoever called 'yeild' * * * yeild -- this saves the state of the machine for the printer * driver and restores the state for PTDOS. * yeild push b save machine state for the printer driver push d push h push psw lxi h,0 dad sp shld tskstk * lhld ptstk restore state of the PTDOS execution sphl pop psw pop h pop d pop b ret . this will take us back to the caller of 'task' * * * server -- this is the main loop of the printer driver. It * waits for PTDOS code to set the 'status' semiphore * to the BUSY state indicating the there is a * character ready to be processed. It then processes * the character and sends the proper info the the * printing mechanism. * server mvi a,CHcr send out an initial cr to reset the printer call putc * mvi a,TRUE sta lffg set linefeed flag to TRUE * serv0 call getc get a character from PTDOS * call process process the character * jmp serv0 loop forever * * * process -- This processes the character. Some characters * are not sent to the printer mechanism; they * are handled special. * process cpi CHcr jnz pro0 * call pcr call to process carriage returns ret pro0 equ $ * cpi CHfle forced line end? jnz pro1 * lda mode check for word processor mode ora a mvi a,CHfle jz pro1 not WPMODE, send character ret . ignore it pro1 equ $ * cpi CHlf rz . ignore linefeeds * cpi CHnolf jnz pro2 * mvi a,FALSE sta lffg set linefeed-after-cr flag to FALSE ret pro2 equ $ * cpi CHnull rz . ignore nulls * cpi CHdel rz . ignore delete characters * cpi CHws jnz pro3 * mvi a,CHb pro3 equ $ * cpi 32 jnc pro4 * mvi a,'?' xlate all control characters to '?' pro4 equ $ * call putc put the character out to the device * ret . and return * * * pcr -- process a carriage reutrn * pcr mvi a,CHcr call putc output a cr * lda lffg test linefeed-after-cr flag cpi TRUE first set hardware flags mvi a,TRUE the reset the flag to TRUE sta lffg jnz pcr0 jmp if not TRUE * lda vi mov c,a * pcr1 push b mvi a,CHesc call putc mvi a,CHlf call putc output a CHlf mvi a,1 call putc pop b * dcr c jnz pcr1 pcr0 equ $ * ret . all done with the cr * * * getc -- get a character from the PTDOS task * getc call sid first set input DONE * getc0 call ti test input status jnz getc1 Z flag 1 means DONE, wait for BUSY call yeild let the PTDOS task run for a while jmp getc0 * getc1 lda data get the data that was passed ret * * * putc -- put a character out to the printer mwchanism * putc push psw save caharacter call cantst test for cansel state jnz putc0 no, continue putc3 pop psw ret . cansel state, do nothing * putc0 call tod test output status jz putc1 Z flag 0 means BUSY, wait till' DONE call yeild give the PTDOS task a chance to run call cantst jz putc3 if in cansel state, return and do nothing jmp putc0 * putc1 pop psw ani 07FH call sob set output BUSY * ret * * * cantst - test the cansel flag * cantst lda cansel cpi TRUE ret * * * sid -- set input DONE. This sets the input (to the printer * driver) status semiphore to the DONE state. This * indicates to the PTDOS task that the printer driver * is ready to process another character. * sid mvi a,DONE sta status ret * * * sib -- set input BUSY. This sets the input (to the printer * driver) status semiphore to the BUSY state. This * tells the PTDOS task that it cannot send the printer * driver a character. PTDOS code must wait for the * semiphore to go DONE. * sib sta data send the character to the printer driver mvi a,BUSY sta status make the printer driver BUSY ret * * * sob -- set output BUSY. This sets the hardware semiphore * to its BUSY state and starts the printer mechanism * going. There is no software complement (sod-set * output DONE) because the printer hardware dose this. * sob out IOsdp send out character ret * * * ti -- test input status. This tests the input (from the * PTDOS task) status for DONE and sets the Z flag * to 1 for DONE, 0 for BUSY. Carry flag is always 0. * ti lda status cpi DONE ret * * * tod -- test output for DONE. This tests the printer * mechanism status semiphore for a DONE condition. * The Z flag is set to 1 if DONE, 0 if not * tod in IOssp read in status port ani IOsbe+IOscs+IOsdr only these bits... cpi IOsbe+0+0 must be thus for a DONE state ret . return Z set if DONE, clear otherwise * * * init -- initialize the driver * init lxi h,server init the server's start addr shld iretadr lxi h,istkptr init the server's stack addr shld tskstk * mvi a,0 set to non-word processor mode sta mode * mvi a,FALSE sta cansel * mvi a,DONE set input status to DONE sta status * mvi a,Ivi sta vi set initial vertical increment * call task initialize the control structure * ret . thats it * * * storage * status ds 1 printer driver BUSY/DONE semiphore ptstk ds 2 the stack ptr for the PTDOS task tskstk ds 2 the stack ptr for the printer driver task mode ds 1 the driver mode: word processor/non-word processor lffg ds 1 linefeed-after-cr flag data ds 1 the character passing buffer cansel ds 1 cansel state flag vi ds 1 vertical increments per LF * * stacks * ds 45 stack istkptr ds 8 init tos iretadr ds 2 init addr of ret addr * *