* S154C -- IBM 2741 COMPATIBLE DRIVER FOR TYPESPHERE 154, * CORRESPONDENCE CODE TERMINAL. * Version 79.5.7.2340 * * NEXT VERSION SHOULD SPEED UP CARRIAGE RETURN AND IMPLEMENT * THE "SUPPRESS AUTO-LINEFEED" FEATURE FOR WORDWIZARD * THIS VERSION IS WORDWIZARD COMPATIBLE, BUT DON'T USE THE * ".under" COMMAND. * * Based on SolPrinter 3 Driver * 1.0 (mod 1) * * * Equates * * Conditions * TRUE equ 00001H FALSE equ 00000H * BUSY equ 0FFFFH DONE equ 00000H * * ASCII Characters * CHnull equ 000H CHdel equ 07FH CHcr equ 00DH CHlf equ 00AH CHff equ 00CH CHfle equ 001H ;forced line ending CHnolf equ 0FFH ;no linefeed after cr CHesc equ 01BH CHsp equ 020H ;space CHtil equ 07EH ;tilde CHbs equ 008H ;backspace * * Selectric Characters * SCcr equ 0EDH ;crlf SCidl equ 0FDH ;idle SCbs equ 0DDH ;backspace SCtab equ 0EFH ;tab SClf equ 0EEH ;index (linefeed) SCsp equ 0C0H ;space * * 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) * * PTDOS equates * nlst copy NPTDEFS lst * UCBIT EQU 40H ;UPPER CASE BIT IN TABLE A ENTRIES LCBIT EQU 80H ;LOWER CASE BIT IN TABLE A ENTRIES OSBIT EQU 00H ;OVERSTRIKE BITS IN TABLE A ENTRIES SRBIT EQU 20H ;SPECIAL ROUTINE BITS IN TABLE A ENTRIES EOA EQU 34H ;SELECTRIC EOA CODE EOT EQU 3CH ;SELECTRIC EOT CODE UC EQU 1CH ;SELECTRIC UC SHIFT CHARACTER BKSP EQU 1DH ;SELECTRIC BACKSPACE * * the program origin * org 07800H ;BY PTC CONVENTION, PRINTER DRIVER IS AT 7800H-7FFF * * 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 initialization * * ADDRESS VECTOR -- must immediately follow driver table * ATBLA DW TBLA ;ASCII TABLE ATBLO DW TBLO ;OVERSTRIKE TABLE ATBLS DW TBLS ;SPECIAL ROUTINE TABLE * 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 cancel rz call wblock write any residue jmp dummy ignore eof return ret * * close -- close the printer driver * close call cantst test for cancel 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 - set-vertical-increment is ignored * * 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 rz . ignored but supported * cpi CScb jnz ctrle error, Control/Status op not supported mvi a,TRUE sta cancel set cancel 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 'yield' * * * yield -- this saves the state of the machine for the printer * driver and restores the state for PTDOS. * yield 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 equ $ *Initialize terminal. Should also check for EOA on input port. MVI A,EOA ;put terminal in Receive state CALL SENDA MVI A,0 STA CURSOR ;cursor at left margin MVI A,LCBIT STA CASE ;terminal starts in lower case mvi a,TRUE sta lffg set linefeed flag to TRUE *The processing loop. 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 in a special way. * process EQU $ ;CHARACTER IS IN REG A ON ENTRY HERE. MOV B,A ;SAVE IT IN B LDA mode ORA A JZ PRO1 ;NOT WP MODE, SO SKIP * * WP MODE HERE * MOV A,B ;GET CHAR BACK CPI CHfle ;forced line ending RZ . ;ignore fle CPI CHtil ;tilde JNZ PRO2 MVI B,CHsp ;convert tilde to blank PRO2 EQU $ PRO1 EQU $ CALL ASCII ;OUTPUT FROM B RET . ;PROCESS DONE * * ASCII--OUTPUT THE ASCII CHAR FROM REG B. RECURSIVE. * ASCII PUSH PSW ;SAVE REGISTERS FOR RECURSION PUSH B PUSH D PUSH H MOV E,B ;MOVE CHAR TO E MVI D,0 LHLD ATBLA ;COMPUTE ADDRESS IN TBLA DAD D MOV B,M ;FETCH ENTRY FROM TABLE A CALL ACODE ;OUTPUT THE A-TABLE CODE FROM REG B POP H POP D POP B POP PSW RET . ;END ASCII * * ACODE -- SEND TABLE-A CODE FROM B REGISTER. RECURSIVE. * ACODE EQU $ PUSH PSW PUSH B PUSH D PUSH H *DECODE TABLE ENTRY FOR OUTPUT LDA CASE ;TEST FOR CHAR IN CURRENT CASE ANA B JZ W4 ;JUMP IF ENTRY & CASE = 0 *ENTRY IS IN CURRENT CASE CALL SENDB ;NOTE 2 HIGH ORDER BITS WILL BE IGNORED JMP ACODI *ENTRY IS NOT IN CURRENT CASE W4 MVI A,UCBIT+LCBIT ;TEST FOR CHAR IN EITHER CASE ANA B ;EXAMINE 2 HIGH ORDER BITS JZ W6 ;JUMP IF ENTRY HAS BOTH BITS ZERO RAL ;ENTRY MUST BE OPPOSITE CASE MVI A,UC ;CREATE APPROPRIATE SHIFT CHARACTER JNC W5 ;JUMP IF ENTRY IS UCASE ORI 3 ;SET 2 LOW ORDER BITS TO MAKE LC SHIFT W5 EQU $ PUSH B ;PROTECT CHAR CALL SENDA ;SEND IT LDA CASE XRI UCBIT+LCBIT ;COMPLEMENT CASE STA CASE ;SAVE CASE POP B ;RESTORE CHAR CALL SENDB ;SEND CHAR JMP ACODI *ENTRY IS SPECIAL OR OVERSTRIKE W6 MVI A,SRBIT ;ENTRY IS STILL IN B ANA B ;CHECK FOR SPECIAL ROUTINE BIT JZ W7 ;JUMP TO OVERSTRIKE HANDLER *ENTRY IS SPECIAL ROUTINE MVI A,1FH ;LOAD MASK ANA B ;EXTRACT INDEX RAL . ;MULT BY 2 MOV E,A ;PUT IT IN DE XRA A MOV D,A LHLD ATBLS DAD D ;ADD IT TO TABLE S BASE ADDRESS CALL GOHL ;CALL THE ROUTINE. It must increment cursor itself. JMP ACODR ;RETURN *ENTRY IS OVERSTRIKE W7 MVI A,1FH ;MASK LOW ORDER 5 BITS ANA B ;EXTRACT OVERSTRIKE NUMBER (0-31) RAL ;DOUBLE IT MOV E,A XRA A MOV D,A LHLD ATBLO DAD D ;ADDRESS OF ENTRY IN TABLE O MOV B,M ;GET FIRST CHAR. MUST NOT BE SAME OVERSTRIKE CALL ASCII ;NOTE:RECURSIVE MVI B,CHbs ;GET ASCII BACKSPACE CALL ASCII INX H MOV B,M ;GET SECOND CHARACTER, MAY BE A DIFFERENT O'STRIKE CALL ASCII ;OUTPUT IT JMP ACODI *INCREMENT CURSOR AND RETURN ACODI LDA CURSOR INR A STA CURSOR *RESTORE REGISTERS AND RETURN ACODR POP H POP D POP B POP PSW RET . ;END ACODE * * * 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 yield 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 character call cantst test for cancel state jnz putc0 no, continue putc3 pop psw ret . cancel state, do nothing putc0 call tod test output status jz putc1 Z flag 0 means BUSY, wait till' DONE call yield give the PTDOS task a chance to run call cantst jz putc3 if in cancel state, return and do nothing jmp putc0 putc1 pop psw ani 07FH call sob set output BUSY ret * * * cantst - test the cancel flag * cantst lda cancel 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 *note: in Sol3 driver, following test also included IOscs+IOsdr *but they have been dropped here because my cable didn't connect *those signals. To restore them: *ani IOspe+IOscs+IOsdr *cpi IOsbe+0+0 *My printer relies upon nulls (idle characters) rather than hand *-shaking the status lines to delay for lengthy carriage moves. ani IOsbe examine only this bit... cpi IOsbe 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 cancel * mvi a,DONE set input status to DONE sta status * call task initialize the control structure * ret . thats it * * * UTILITY SUBROUTINES * SENDA EQU putc ;SENDS CHAR TO SERIAL PORT FROM A. SENDB MOV A,B JMP SENDA * * GO TO ROUTINE WHOSE ADDRESS IS IN BYTES POINTED TO BY HL * GOHL MOV A,M ;HL POINTS TO ADDRESS CONSTANT IN TABLE INX H MOV H,M MOV L,A ;JUMP ADDRESS IS NOW IN HL PCHL ;GO TO HL. THE ROUTINE SHOULD RETURN TO THE CALLER * * *TABLES * * TABLE S: SPECIAL ROUTINES * *ENTRIES ARE SUBROUTINE ADDRESSES. * * ON RETURN: ALL REGISTERS MAY BE CHANGED. * SUBROUTINE MUST INCREMENT CURSOR AS NEEDED. * TBLS EQU $ DW SRunk ;CODE 20=UNKNOWN CONTROL CHARACTER OR UNPRINTABLE DW SRbs ; 21=BACKSPACE DW SRtab ; 22=TAB DW SRlf ; 23=INDEX (LINEFEED) DW SRvt ; 24=VERTICAL TAB DW SRff ; 25=FORM FEED DW SRcr ; 26=CARRIAGE RETURN DW SRsp ; 27=SPACE DW SRign ; 28=IGNORE THIS CHARACTER *END TBLS * SRunk EQU $ MVI B,OSqe ;questionmark & equalsign CALL ACODE ;outputs and increments cursor also RET * SRbs EQU $ ;BACKSPACE LDA CURSOR ORA A RZ . ;IGNORE IF CURSOR IS ZERO NOW (DON'T BS BEYOND MARGIN) DCR A STA CURSOR MVI A,BKSP CALL SENDA RET * SRtab EQU $ JMP SRsp ;tab not implemented yet; treat as a space. * SRlf EQU $ JMP SRign ;ignore linefeeds * SRvt EQU $ JMP SRign ;ignore vertical tabs * SRff EQU $ JMP SRcr ;treat as a CR in this version * SRcr EQU $ ;this version knows nothing about suppressing lf MVI A,SCcr ;selectric character: crlf CALL SENDA MVI A,14 ;SEND 14 IDLES AFTER CRLF. NEXT VERSION SHOULD SEND * ONLY ENOUGH NULLS TO ALLOW CARRIAGE TRAVEL NEEDED. * IN OTHER WORDS, KEEP TRACK OF CURRENT COLUMN AND * USE FORMULA: NULLS=TRAVEL+1, WHERE TRAVEL IS IN * INCHES. SHOULD DO LIKEWISE FOR TAB. If already in * first column, send INDEX character instead, and it * only requires one NULL (IDLE). PUSH PSW SRcr0 POP PSW DCR A JZ SRcr1 PUSH PSW MVI A,SCidl ;idle CALL SENDA JMP SRcr0 SRcr1 XRA A STA CURSOR ;CURSOR=0 RET SRsp EQU $ ;preliminary version doesn't accumulate spaces MVI A,SCsp CALL SENDA LDA CURSOR INR A STA CURSOR RET SRign EQU $ ;SPECIAL ROUTINE DUMMY CMP A ;SET Z FLAG RET . ;END SKIP * *END OF SPECIAL ROUTINES * * TABLE O: OVERSTRIKE CODES * *ENTRIES ARE PAIRS OF ASCII CODES. THE PUTB ROUTINE WILL OUTPUT *THE FIRST CODE FOLLOWED BY A BACKSPACE AND THE SECOND CODE. *EITHER CODE MAY BE ANOTHER OVERSTRIKE, BUT CIRCULAR REFERENCES *WILL DESTROY THE CONTENTS OF MEMORY. * TBLO EQU $ DB 28H,2DH ; OVERSTRIKE 0 (- OPEN BRACE DB 29H,2DH ; 1 )- CLOSE BRACE DB 27H,2DH ; 2 '- REVERSE QUOTE DB 2FH,2DH ; 3 /- REVERSE SLASH DB 22H,27H ; 4 "' TILDE DB 5BH,5DH ; 5 ][ VERTICAL BAR DB 3FH,3DH ; 6 ?= UNPRINTABLE OSqe equ 6 ; overstrike 6 *END OVERSTRIKES * * TABLE A: ASCII CONVERSION TABLE * *ENTRIES ARE OF THE FOLLOWING FORMS: * BITS: 76543210 *OVERSTRIKE 000iiiii WHERE iiiii=OVERSTRIKE # *SPECIAL 001jjjjj WHERE jjjjj=SPECIAL ROUTINE # *UPPER CASE CHAR 01ssssss WHERE ssssss=SELECTRIC CODE *LOWER CASE CHAR 10ssssss WHERE ssssss= " " *EITHER CASE 11ssssss WHERE ssssss= " " *ALL SELECTRIC CODES IN REVERSE, THAT IS 1248AB BITS. * TBLA EQU $ ;ASCII:SELECTRIC DB 28H ;00=NULL : SPECIAL #8=IGNORE DB 20H ;01= : SPECIAL #0=UNKNOWN DB 20H ;02 DB 20H ;03 DB 20H ;04 DB 20H ;05 DB 20H ;06 DB 20H ;07 DB 21H ;08=BS :SPECIAL #1 DB 22H ;09=TAB :SPECIAL #2 DB 23H ;0A=LF :SPECIAL #3 DB 24H ;0B=VT :SPECIAL #4 DB 25H ;0C=FF :SPECIAL #5 DB 26H ;0D=CR :SPECIAL #6 DB 20H ;0E= :SPECIAL #0 DB 20H ;0F= : " DB 20H ;10= : " DB 20H ;11= : " DB 20H ;12= : " DB 20H ;13= : " DB 20H ;14= : " DB 20H ;15= : " DB 20H ;16= : " DB 20H ;17= : " DB 20H ;18= : " DB 20H ;19= : " DB 20H ;1A= : " DB 20H ;1B=ESC : " DB 20H ;1C= : " DB 20H ;1D= : " DB 20H ;1E= : " DB 20H ;1F= : " DB 27H ;20=SP :SPECIAL ROUTINE #7=SPACE DB 60H ;21=! :! UPPER CASE 1 KEY DB 49H ;22=" :" DB 70H ;23=# :# DB 44H ;24=$ :$ DB 48H ;25=% :% DB 68H ;26=& :& DB 89H ;27=' :' DB 74H ;28=( :( DB 64H ;29=) :) DB 78H ;2A=* :* DB 53H ;2B=+ :+ DB 0BBH ;2C=, :, LOWER CASE ONLY DB 0B7H ;2D=- :- DB 91H ;2E=. :. LOWER CASE ONLY DB 87H ;2F=/ :/ DB 0A4H ;30=0 :0 DB 0A0H ;31=1 :1 DB 90H ;32=2 :2 DB 0B0H ;33=3 :3 DB 84H ;34=4 :4 DB 88H ;35=5 :5 DB 98H ;36=6 :6 DB 0A8H ;37=7 :7 DB 0B8H ;38=8 :8 DB 0B4H ;39=9 :9 DB 6BH ;3A=: :: DB 0ABH ;3B=; :; DB 7BH ;3C=< :< UPPER CASE COMMA KEY DB 93H ;3D== := DB 51H ;3E=> :> UPPER CASE PERIOD KEY DB 47H ;3F=? :? DB 50H ;40=@ :@ DB 79H ;41=A DB 76H ;42=B DB 7AH ;43=C DB 6AH ;44=D DB 4AH ;45=E DB 73H ;46=F DB 63H ;47=G DB 66H ;48=H DB 59H ;49=I DB 43H ;4A=J DB 5AH ;4B=K DB 46H ;4C=L DB 61H ;4D=M DB 52H ;4E=N DB 45H ;4F=0 DB 4BH ;50=P DB 5BH ;51=Q DB 69H ;52=R DB 65H ;53=S DB 42H ;54=T DB 72H ;55=U DB 71H ;56=V DB 75H ;57=W DB 62H ;58=X DB 67H ;59=Y DB 54H ;5A=Z DB 41H ;5B=[ : [ LOWER CASE 1/2 KEY DB 03H ;5C=\ : OVERSTRIKE #3 /- DB 81H ;5D=] : ] UPPER CASE 1/2 KEY DB 58H ;5E=^ : ^ UPPER CASE 6 KEY DB 77H ;5F=_ : UNDERSCORE DB 02H ;60=REVERSE QUOTE : OVERSTRIKE #2 '- DB 0B9H ;61=a DB 0B6H ;62=b DB 0BAH ;63=c DB 0AAH ;64=d DB 08AH ;65=e DB 0B3H ;66=f DB 0A3H ;67=g DB 0A6H ;68=h DB 99H ;69=i DB 83H ;6A=j DB 9AH ;6B=k DB 86H ;6C=l DB 0A1H ;6D=m DB 92H ;6E=n DB 85H ;6F=o DB 8BH ;70=p DB 9BH ;71=q DB 0A9H ;72=r DB 0A5H ;73=s DB 82H ;74=t DB 0B2H ;75=u DB 0B1H ;76=v DB 0B5H ;77=w DB 0A2H ;78=x DB 0A7H ;79=y DB 94H ;7A=z DB 00H ;7B={ : OVERSTRIKE #0 (- DB 05H ;7C=| : OVERSTRIKE #5 ][ DB 01H ;7D=} : OVERSTRIKE #1 )- DB 04H ;7E=~ : OVERSTRIKE #4 "' DB 28H ;7F=DEL : SPECIAL #8=IGNORE * * 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 cancel ds 1 cancel state flag vi ds 1 vertical increments per LF STATE DS 1 ;STATE OF THE 2741 TERMINAL CASE DS 1 ;CURRENT CASE BIT =80H OR 40H CURSOR DS 1 ;CURRENT LOCATION OF LOGICAL CURSOR (0-255) * * stacks * ds 100 stack istkptr ds 8 init tos iretadr ds 2 init addr of ret addr * END