******************************************************* * * * CITOH GRAPHICS PRINTER DRIVER * * * * USING ONLY THE TOP 4 PRINT PINS * * * * (Configured for the Sorcerer) * * * * Written by William King (November,1982) * * * ******************************************************* ; History ; ------- ; The original driver program was written using 8- ; bit data with a suitable cable to the printer. This ; seemingly obvious exploit lead to a friend's printer ; and my own printer breaking down beyond repair (I ; don't know why, nor did the printer repair people, ; very expensive). This prompted me to write a driver ; that used 7 bit data or less. This driver uses only ; the top 4 print pins (but still sending 7 bit data). ; Thus there are NO hardware mods required (i.e. the ; original print cable and settings may be used. ; ; Use ; --- ; The main driver routine may be called as a sub. ; by calling BASEAD+0 (i.e. 5000h in this case). ; The video output may be set to BASEAD+0 so all ; graphics data + text is printed 4 dot lines at a ; time (i.e. for Sorcerer SE O=5000 from monitor) ; The screen may be dumped to the printer as is by ; calling the routine at BASEAD+100h (i.e. 5100h in ; this case - note that it should be called via a ; program rather than direct running from moitor so as ; to preserve the entire screen display) ; ; Cable ; ----- ; Use the cable normally used for printing ASCII ; data (NO need for a special cable) ; ; Changes ; ------- ; The program may be reconfigured for other ; printers and other computers taking special note of ; the following points : ; (1) Alter line feed pitch code sequence at LFDATA ; (2) Alter here comes 8 data bytes for graphics ; code at GDATA ; (3) Alter screen width at SWIDTH ; (4) Alter # of lines on screen at LINES ; (5) Alter start address of screen at SCRTOP ; (6) Alter monitor equates as required * MONITOR EQUATES * VIDEO: EQU 0E01BH ;VIDEO OUTPUT KEYIN: EQU 0E009H ;GET A KEY ROUTINE MONWRM: EQU 0E003H ;MONITOR WARM START * HARDWARE EQUATES * PWIDTH: EQU 80 ;PRINTER WIDTH (SO IF NO ; HAS COME, BUFFER ; WILL NOT OVERFLOW !) SWIDTH: EQU 64 ;SCREEN WIDTH (FOR SCREEN ; DUMP) LINES: EQU 30 ;# OF LINES ON SCREEN SCRTOP: EQU 0F080H ;ADDR OF TOP OF SCREEN ASCLOW: EQU 0F800H ;LOWEST ASCII CHARACTER ; ADDRESS BASEAD: EQU 05000H ;BASE ADDRESS OF DRIVER ORG BASEAD ;SET BASE ADDR OF DRIVER START: JR POUT1-$ ;PAST SUBROUTINES * PRINTER DRIVER ROUTINE * DRIVE: PUSH AF PUSH AF DR1: IN A,(0FFH) BIT 7,A JR NZ,DR1-$ POP AF OR 080H OUT (0FFH),A AND 07FH OUT (0FFH),A OR 080H OUT (0FFH),A POP AF RET * SENDS DATA FOLLOWING THE CALL,TO PRINTER * DATA: POP HL ;FIRST BYTE OF DATA DAT1: LD A,(HL) ;GET DATA OR A ;LAST BYTE? JR Z,DAT2-$ ;YES,THEN BACK CALL DRIVE ;NO,THEN SEND BYTE TO PRT INC HL ;NEXT BYTE JR DAT1-$ ;KEEP GOING DAT2: INC HL ;NEXT BYTE JP (HL) ;JUMP THERE * MAIN PROGRAM * POUT1: CALL VIDEO ;CHAR TO SCREEN POUT2: PUSH HL PUSH DE PUSH BC PUSH AF CP ' ' ;CHAR >= SPACE? JR NC,COUNT-$ ;YES,THEN COUNT HOW MANY CP 00DH ;? JR Z,COUNT-$ ;YES,THEN DO THAT TOO! CP 00AH ;LF? JR Z,END-$ ;YES,THEN DO NOTHING CP 00CH ;CLEAR SCREEN? JR Z,END-$ ;YES,THEN DO NOTHING CALL DRIVE ;SEND CONTROL CHAR END: POP AF POP BC POP DE POP HL RET COUNT: CP 00DH ;IS IT A ? JR Z,PRINT-$ ;YES,THEN DO THE LINE LD B,A ;SAVE THE CHAR LD A,(BUFCNT) ;GET NUMB. CHARS IN BUFF. LD E,A ;GET TO E LD D,00 LD HL,BUFFER ;START OF BUFFER ADD HL,DE ;WHERE CHAR MUST GO LD (HL),B ;PUT CHAR IN BUFFER INC A ;COUNT = COUNT + 1 LD (BUFCNT),A ;SAVE IT BACK CP PWIDTH ;COUNT >= PRINTER WIDTH? JR C,END-$ ;NO,THEN BACK TO CALLER PRINT: CALL DATA ;SEND FOLLOWING DATA LFDATA: DB 01BH,054H,'08';LF PITCH = 8/144" DB 01BH,051H ;COMPRESSED PRINT !! DB 000H ;END CODE XOR A ;CLEAR: LD (FLAG),A ; FIRST PASS FLAG PASS1: LD A,(BUFCNT) ;GET BUFFER COUNTER OR A ;NO CHARS TO DO? JR Z,CR1-$ ;YES,THEN JUST SEND LD B,A ;GET COUNT TO B LD HL,BUFFER ;POINTER TO START OF BUFF PASS2: LD A,(HL) ;GET A CHAR CALL BITS ;DO TOP OR BOT. BITS INC HL DJNZ PASS2-$ ;SEND THEM OUT TILL DONE LD A,(FLAG) ;GET FLAG OR A ;FINISHED? JR NZ,CR2-$ ;YES,THEN DO A CPL ;SET FLAG TO A NZ VALUE LD (FLAG),A ;SAVE FLAG BACK LD A,0DH ;SEND A CR TO END LINE CALL DRIVE JR PASS1-$ ;DO SECOND PASS CR1: LD A,00DH ;SEND A CALL DRIVE CR2: LD A,00DH ;SEND A CALL DRIVE XOR A ;CLEAR: LD (BUFCNT),A ; BUFFER COUNT LD (FLAG),A ; PASS FLAG JP END ;BACK TO CALLER * ROUTINE TO ROTATE CHARACTER IN REGISTER A * * THEN SEND OUT HIGH OR LOW 4 BITS (TOP 4 PINS * * ON PRINTER),THUS ONLY USING THE TOP 4 PINS * BITS: PUSH HL PUSH BC PUSH AF PUSH AF CALL DATA ;SEND OUT FOLLOWING DATA GDATA: DB 01BH,053H,'0008' ;"HERE COMES 8 GRAPH. DB 000H ; DATA BYTES" POP AF BIT1: LD L,A ;GET CHAR TO L LD H,00 ;CLEAR H ADD HL,HL ADD HL,HL ADD HL,HL ;* 8 LD DE,ASCLOW ;LOWEST ASCII CHAR ADDR. ADD HL,DE ;GET ADDRESS OF CHAR PUSH HL ;SAVE ADDRESS LD C,080H ;BIT 7 SET PUSH BC ;SAVE MASK BIT2: LD E,00 ;CLEAR E (RESULT IN HERE) LD B,001H ;SET BIT 1 BIT3: LD A,(HL) ;GET CHARACTER DATA AND C ;MASK OUT ALL OTHER BITS JR Z,BIT4-$ ;NO BIT SET,THEN PAST LD A,E ;GET ANSWER OR B ;SET THE CORRECT BIT LD E,A ;SAVE RESULT BIT4: RL B ;SET NEXT BIT ON LEFT INC HL ;POINT TO NEXT DATA BYTE LD A,B OR A ;FINISHED THIS VERT. LINE JR NZ,BIT3-$ ;NO,THEN DO 8 BITS TOTAL LD A,(FLAG) ;FLAG ZERO=LOWER 4 BITS OR A ;ZERO? LD A,E ;GET DATA TO A JR NZ,BIT5-$ ;NO, MUST BE UPPER 4 BITS AND 00FH ;ZERO,THEN KEEP LOW BITS JR BIT6-$ ;JUMP BIT5: AND 0F0H ;NONZERO,THEN KEEP HIGH 4 SRL A SRL A SRL A SRL A ;MOVE HIGH 4 -> LOW 4 BIT6: CALL DRIVE ;SEND OUT DATA POP BC ;GET MASK BACK RR C ;SHIFT BITS TO RIGHT POP HL ;GET ADDRESS BACK PUSH HL PUSH BC LD A,C ;GET MASK OR A ;DONE 8 TIMES? JR NZ,BIT2-$ ;NO,THEN KEEP GOING POP BC ;RESTORE PUSHES/POPS POP HL POP AF POP BC POP HL RET ;RETURN TO CALLER * SCREEN DUMP ROUTINE * ORG BASEAD+100H ;NEED EVEN ADDRESS BEGIN: LD B,01 ;NO. OF COPIES BEG1: CALL SCREEN ;DO ONE COPY BEG2: CALL KEYIN ;KEYSCAN CP 'P' ;"P"? JR NZ,BEG2-$ ;NO,THEN WAIT DJNZ BEG1-$ ;DO TILL COPIES=0 JP MONWRM ;BACK TO MONITOR SCREEN: PUSH HL PUSH BC PUSH AF LD HL,SCRTOP ;TOP OF SCREEN LD C,LINES ;# OF LINES ON SCREEN XOR A ;CLEAR: LD (BUFCNT),A ; PRINT BUF COUNT SCRN1: LD B,SWIDTH ;WIDTH OF SCREEN SCRN2: LD A,(HL) ;GET CHAR CALL POUT2 ;SEND CHAR TO PRINTER INC HL DJNZ SCRN2-$ LD A,00DH ; CALL POUT2 ;SEND TO PRINTER DEC C ;DEC # OF LINES LD A,C ;GET # OF LINES TO A OR A ;END YET? JR NZ,SCRN1-$ ;NO,THEN DO ANOTHER LINE POP AF POP BC POP HL RET ;BACK TO COUNTING ROUT. * DATA AREA * BUFCNT: DEFS 1 ;BYTE COUNTER (IN BUFF) FLAG: DEFS 1 ;PASS FLAG BUFFER: DB 00 ;SPACE FOR BUFFER END