Z80 software

See below for the printer driver I wrote for a simple wordprocessor.
The text is in a big buffer in memory. The paragraphs are seperated by a CR (#D) and pages by a FF (#C). Because the printer need CR/LF sequences there is taken care of this: see lines 179-182. Escape sequences to control the printer are embedded in the text buffer. Because these are not printed the line width is increased by the average length (=3) of these sequences: see lines 153-157.
The line width specified is the maximum line width so the word which is in excess of this width is not to be printed on the current line: see line 159. When there is just one word on the line which is in excess nothing would be printed. To take care of this there is a check on zero or negative width: see lines 160-168.
Page length is stored in MAXLIN and is set to the running value on lines 83-84 (init) and 176-177. The line width is passed from Basic through call (#F7F8) and is set to running value on lines 147-171 (this includes line width calculation). Indent space can only be set to 3 or 10: see lines 205-210 and for controling the indent and the left margin see lines 185-190 and 202-203.
Initialization is done in two parts. The first part initializes the textpointer: see lines 240-248. This routine uses the cursor group as also the main wordprocessor does. The return from the cursor group brings the control to the second part: see lines 81-89. This part takes care that the text pointer gets a legal value.

The nice thing about this routine and that's why I choose to publish it is the way the routines are called. The routine addresses are moved to the stack and RET will execute the routines. On line 94-95 LOOPPRT is first moved onto the stack. This takes care that after all the other routines are called there will be a return to here. Secondly LPTOUT is moved onto the stack. This is a BIOS routine that sends the character in register A to the printer. Graphics characters are stored in the text buffer with a value lower than #20: see lines 125-126. They have to be printed as <1><value+#40>: see lines 98-102 and 125-129. On lines 111-112 PRTCH is pushed onto the stack: this routine checks if a jump to a new line is ncessary.
On lines 113-124 there is a check for control characters that need special treatment: see line 228 for the characters and line 230 for the routine addressed. E.g. ESC and TAB should be printed directly and not be recognized as graphics: see lines 130-131. The RET on lines 126, 131,146 and others take care that all the routines on the stack are executed and there is a return to line 94: LOOPPRT.

			*F PRTPEN
		000	;
		001	; P R T P E N
		002	;
		003	; PRINT ROUTINES FOR MSXPEN-2
		004
		005	; AUTHOR:
		006	;   F. SEMPLONIUS
		007	;   JESSICAGANG 18
		008	;   2719 CA ZOETERMEER
		009	;
		010	; FUNCTION:
		011	;   THIS ROUTINE WHICH CAN BE ASSEMBLED STAND-ALONE OR INCLUDED
		012	;   BY MTPEN TAKES CARE OF PRINTING OF THE TEXT
		013	;
		014	; NOTES:
		015	;  IN STAND-ALONE MODE USE A TABEL SIZE OF 1000
		016	;
		017	; LAYOUT FILES:
		018	;
		019	;
		020	; DEFINITIONS AND MACRO'S
		021	;
0001		022	INCPRT1: EQV	1
		023	;
00A5		024	LPTOUT	EQU	#A5
000A		025	LF:	EQU	#A
000C		026	FF:	EQU	#C
000D		027	CR:	EQU	#D
		028	;
		029		IF	INCPRT1!1
		030	;
00AB		031	CNVCHR:	EQU	#AB
FCA6		032	GRPHED:	EQU	#FCA6
		033	;
		034	; LOCAL DEFINITONS
		035	;
0001		036	HDLINE:	EQU	1
000F		037	NLINE:	EQU	15
		038	;
		039	; VARIABLES TO BE ACCESSED BY BASIC
		040	;
8A00		041	MA:	EQU	#8A00
8A01		042	ENDTEXT: EQU	#8A01
8A03		043	MAXLIN:	EQU	#8A03
		044	;
		045	; SYMBOL ADDRESSES IN MTPEN
		046	;
961D		047	PT:	EQU	#961D
9C40		048	TEXT:	EQU	#9C40
		049	;
		050	; CHECK IF CURSOR IS WITHIN LIMITS
		051	; INPUT/OUTPUT:
		052	;   HL - ADDRESS TO CHECK
		053	;
9461	EB	059	CHKCUR:	EX	DE,HL		; CURSOR POINTER -> DE
9462	2A0091	060		LD	HL,(ENDTEXT)	; END OF TEXT POINTER
9465	0100FE	061		LD	BC,-NLINE-1*32
9468	09	062		ADD	HL,BC
9469	3620	063		LD	(HL)," "	; BE SURE LAST CHAR. IS BLANK
946B	E7	064		RST	#20		; HL-DE
946C	3801	065		JR	C,CHKC1		; IF C  WITHIN HIGH LIMIT
946E	EB	066		EX	DE,HL		; ELSE HIGH LIMIT TO HL
946F	ED5B9E96 067	CHKC1:	LD	DE,(STTEXT)	; START OF TEXT
9473	E7	068		RST	#20		; HL-DE
9474	D0	069		RET	NC		; IF NC WITHIN LIMITS
9475	E8	070		EX	DE,HL		; ELSE LOW LIMIT TO HL
9476	C9	071		RET

[PART DELETED]

		074	;
		075	; PRINTER ROUTINES	
		076	;
		077	; SECOND PART OF INIT
		078	; INPUTS:
		079	;   HL - START ADDRESS FOR PRINT TEXT
		080	;
949F	CD6194	081	PRTDR:	CALL	CHKCUR		; CHECK CURSOR (SEE ABOVE)
94A2	EB	082		EX	DE,HL		; TEXT POINTER -> DE
94A3	3A0291	083		LD	A,(MAXLIN)	; LINES PER PAGE
94A6	32A395	084		LD	(CURLIN),A	; TO COUNTER
94A9	21B294	085		LD	HL,LOOPPRT
94AC	E5	086		PUSH	HL		; DUMMY MOVED FROM STACK AT END OF PRTCH
94AD	E5	087		PUSH	HL		; RETURN TO LOOPPRT AFTER CHAR. IS PRINTED
94AE	0600	088		LD	B,0		; ROUTINES ASSUME B=0
94B0	184B	089		JR	PRTF		; SET LINE WIDTH
		090	;
		091	; MAIN LOOP FOR PRINT TEXT
		092	; NOTE: DE IS USED AS TEXTPOINTER
		093	;
94B2	21B294	094	LOOPPRT: LD	HL,LOOPPRT	; RETURN TO LOOPPRT TO
94B5	E5	095		PUSH	HL		;   TO DO LOOP PER CHAR.
94B6	21A500	096		LD	HL,LPTOUT	; PRINT CHAR. IN A
94B9	E5	097		PUSH	HL		;   DO THIS BEFORE RETURN TO LOOPPRT
94BA	21A6FC	098		LD	HL,GRPHED	; GET GRAPHICS CHAR.
94BD	7E	099		LD	A,(HL)		; AND CLEAR IT
94BE	3600	100		LD	(HL),0
94C0	B7	101		OR	A		; WAS THERE A GRAPHICS CHAR.?
94C1	C0	102		RET	NZ		; IF NZ YES -> PRINT IT
94C2	1A	103		LD	A,(DE)		; GET CHAR. FROM TEXT BUFFER
94C3	13	104		INC	DE		; POINT TO NEXT CHAR.
94C4	FE0C	105		CP	FF		; IS IT FORMFEED?
94C6	2009	106		JR	NZ,PRT1		; IF NZ NO
94C8	3AA095	107		LD	A,(CMD)
94CB	FE02	108		CP	2		; COMMAND PRINT CURRENT PAGE?
94CD	2824	109		JR	Z,PRTEXITA	; IF Z YES -> EXIT
94CF	3E0C	110		LD	A,FF		; RESTORE FORMFEED
94D1	21F894	111	PRT1:	LD	HL,PRTCH	; ROUTINE ADDRESS PRTCH
94D4	E5	112		PUSH	HL		; ON STACK
94D5	21F894	113		LD	HL,SRVTAB	; SPECIAL CHAR. JUMP TABLE
94D8	010800	114		LD	BC,NUMSRV	; NUMBER OF ENTRIES IN TABLE
94DB	EDB1	115		CPIR			; SPEC. CHAR. FOUND?
94DD	2008	116		JR	NZ,PRT5		; IF NZ NO
94DF	09	117		ADD	HL,BC		; CALC. ADDRESS THAT
94E0	09	118		ADD	HL,BC		;   POINTS TO ROUTINE ADDRESS
94E1	09	119		ADD	HL,BC
94E2	4E	120		LD	C,(HL)
94E3	23	121		INC	HL
94E4	66	122		LD	H,(HL)		; ROUTINE ADDRESS TO HL
94E5	69	123		LD	L,C		;   ...
94E6	E9	124		JP	(HL)		; JUMP TO IT
94E7	FE20	125	PRT5:	CP	#20		; GRAPHICS CHAR.?
94E9	D0	126		RET	NC		; IF NC NO
94EA	C640	127		ADD	A,#40
94EC	32A6FC	128		LD	(GRPHED),A	; IF YES -> STORE WITH OFFSET
94EF	3E01	129		LD	A,1		; GRAPHICS HEADER TO PRINTER
94F1		130	PRTTAB:				; TAB AND ESC ARE IN SPEC. TABLE
94F1	C9	131	PRTESC:	RET			;   AS NOT TO BE RECOGNIZED AS GRAPHICS
		132	;
		133	; RETURN TO BASIC
		134	;
94F2	E1	135	PRTEXIT: POP	HL		; PRTCH FROM STACK
94F3		136	PRTEXITA:
94F3	E1	137		POP	HL		; LPTOUT -> HL
94F4	E3	138		EX	(SP),HL		; ON STACK (REPLACES LOOPPRT)
94F5	3E0C	139		LD	A,FF		; TO PRINT FF
94F7	C9	140		RET
		141	;
		142	; GO TO NEW LINE OR PAGE IF NECESSARY
		143	;
94F8	21A495	144	PRTCH:	LD	HL,CURPOS	; ALREADY AT END OF LINE (EOL) ?
94FB	35	145		DEC	(HL)		;   ...
94FC	C0	146		RET	NZ		; IF NZ NO
94FD	3AF8F7	147	PRTF:	LD	A,(#F7F8)	; LINE WIDTH
9500	219F95	148		LD	HL,IS		; POINT TO INDENT SPACE
9503	96	149		SUB	(HL)		; SUBSTRACT FROM LINE WIDTH
9504	4F	150		LD	C,A		; -> BC
9505	EB	151		EX	DE,HL		; TEXTPOINTER -> HL
9506	E5	152		PUSH	HL		; SAVE ON STACK
9507	3E1B	153		LD	A,#1B		; ESC
9509	EDB1	154	PRT20:	CPIR			; SEARCH IT
950B	03	155		INC	BC		; INCREASE LINE WIDTH BY
950C	03	156		INC	BC		; 3 EVERY TIME ESC IS FOUND
950D	03	157		INC	BC
950E	EA0995	158		JP	PE,PRT20	; IF PE ESC FOUND -> REPEAT SEARCH
9511	CDBD95	159		CALL	WRDREV		; GO BACK ONE WORD (IN EXCESS OF MARGIN)
9514	D1	160		POP	DE		; RESTORE TEXT POINTER
9515	E5	161	PRT25:	PUSH	HL		; SAVE END OF LINE
9516	B7	162		OR	A		; CLEAR C-BIT
9517	ED52	163		SBC	HL,DE		; CALCULATE LINE WIDTH
9519	2802	164		JR	Z,PRT30		; IF Z ZERO WIDTH
951B	3006	165		JR	NC,PRT35	; IF NC POS WIDTH
951D	E1	166	PRT30:	POP	HL		; ON NEG. OR ZERO WIDTH
951E	CD5596	167		CALL	WRDFWD		; GO FORWARD ONE WORD
9521	18F2	168		JR	PRT25		; AND CHECK FOR NEG. WIDTH AGAIN
9523	7D	169	PRT35:	LD	A,L		; WIDTH -> A
9524	E1	170		POP	HL		; CLEAN STACK - PRPT END
9525	32A495	171		LD	(CURPOS),A	; STORE WIDTH
9528	21A395	172		LD	HL,CURLIN	; GO TO NEXT PAGE?
952B	35	173		DEC	(HL)
952C	060A	174		LD	B,LF		; ASSUME NO -> DO ONLY LINEFEED
952E	2006	175		JR	NZ,PRT40	; IF NZ GOOD ASSUMPTION
9530	3A0291	176		LD	A,(MAXLIN)	; NUMBER OF LINES ON A PAGE
9533	77	177		LD	(HL),A		; STORE THIS FOR RUNNING PAGE LENGTH
9534	060C	178		LD	B,FF		; PRINT FORMFEED
9536	3E0D	179	PRT40:	LD	A,CR
9538	CDA500	180		CALL	LPTOUT		; PRINT CARR. RETURN
953B	78	181		LD	A,B		; FF OR CR
953C	CDA500	182		CALL	LPTOUT		; PRINT IT
953F	3A0391	183		LD	A,(MA)		; MARGIN WIDTH
9542	219F95	184		LD	HL,IS
9445	86	185		ADD	A,(HL)		; ADD INDENT SPACE
9546	47	186		LD	B,A
9547	3E20	187	PRT43:	LD	A,#20
9549	CDA500	188	PRT45:	CALL	LPTOUT		; PRINT SPACE
954C	10FB	189		DJNZ	PRT45		; LOOP FOR MARGIN AND IS WIDTH
954E	E1	190		POP	HL		; LPTOUT FROM STACK
954F	C9	191		RET
		192	;
		193	; SERVICE ROUTINES FOR PRINTING SPECIAL CHARACTERS
		194	;
9550	3AA095	195	PRTFF:	LD	A,(CMD)		; ENTER HERE ON FORMFEED
9553	FE03	196		CP	3		; COMMAND 3; PRINT ONE PAGE ONLY?
9555	289B	197		JR	Z,PRTEXIT	; IF Z YES -> EXIT
9557	289B	198		LD	A,1		; NO
9559	32A395	199		LD	(CURLIN),A	; FORCE FORM FEED
955C	3E01	200	PRTCR:	LD	A,1		; ENTER HERE ON CARR. RETURN
955E	32A495	201		LD	(CURPOS),A	; FORCE NEW LINE
9561	AF	202		XOR	A		; ON FF OR CR
9562	329F95	203		LD	(IS),A		;   SET INDENT SPACE TO ZERO
9565	C9	204		RET
9566	3E0A	205	GRAPHI:	LD	A,3		; SET INDENT SPACE TO 3
9568	21	206		DEFB	#21		; SKIP NEXT INSTR.
9569	3E0A	207	GRAPHJ:	LD	A,10		; SET INDENT SPACE TO 10
956B	329F95	208		LD	(IS),A		; STORE IT
956E	3E20	209		LD	A,#20		; PRINT SPACE FOR INDENT SET CMD
9570	C9	210		RET
		211	;
9571	EB	212	CENTER:	EX	DE,HL		; ENTER HERE ON CENTER COMMAND
9572	E5	213		PUSH	HL		; TEXT POINTER ON STACK
9573	3E0D	214		LD	A,#D
9575	CD6196	215		CALL 	WRDFWDA		; SEARCH FORWARD FOR CARR. RETURN
9578	D1	216		POP	DE		; RESTORE TEXTPOINTER
9579	B7	217		OR	A		; CLEAR C-BIT
957A	ED52	218		SBC	HL,DE		; CALCULATE LINE WIDTH
957C	7D	219		LD	A,L		; -> A
957D	1F	220		RRA			; DIVIDE BY 2
957E	329F95	221		LD	(IS),A		; STORE THIS VALUE AS INDENT SPACE
9581	3E01	222		LD	A,1
9583	32A495	223		LD	(CURPOS),A	; FORCE CARR. RETURN
9586	C9	224		RET
		225 	;
		226	; JUMP TABLE FOR SPECIAL CHARACTERS
		227	;
9587	0C0D1B	228	SRVTAB:	DEFB	#C,#D,#1B,#9,188,198,220,0
0008		229	NUMSRV	EQU	$-SRVTAB
958F	F29466	230		DEFW	PRTEXIT,GRAPHI,GRAPJ,CENTER,PRTTAB,PRTESC,PRTCR,PRTFF
959F	00	231	IS:	DEFB	0
95A0	00	232	CMD:	DEFB	0
95A1	0000	233	PRPT:	DEFW	0
95A3	00	234	CURLIN:	DEFB	0
95A4	00	235	CURPOS:	DEFB	0
		236	;
		237	; INITIALIZE FOR PRINTER - FIRST PART
		238	;
95A5	219F94	239	INITPR:	LD	HL,PRTDR	; ENTER VIA JUMP TABLE HERE FROM BASIC
95A8	E5	240		PUSH	HL		; ADDRESS SECOND PART OF INIT
95A9	2A3B97	241		LD	HL,(PT)		; CURSOR LOCATION IN TEXT
95AC	0600	242		LD	B,0		; REQUIRED FOR CURSOR ROUTINES
95AE	3AF9F7	243		LD	A,(#F7F9)
95B1	32A095	244		LD	(CMD),A		; GET COMMAND
95B4	3D	245		DEC	A		; DECREMENT BY 1
95B5	2813	246		JR	Z,BEGIN		; IF ZERO PRINT ALL TEXT -> CURSOR TO BEGIN
95B7	3D	247		DEC	A		; COMMAND = 2 ?
95B8	201B	248		JR	NZ,SCRUP	; IF NZ NO (=3) -> PRINT SCREEN
		370	;
		371	; CURSOR GROUP (ON ENTRY B = 0)
		372	;
95BA	3E0C	373	PAGEUP:	LD	A,#C		; DO PAGE UP (SEARCH FORM FEED)
95BC	11	374		DEFB	#11
95BD	3E20	375	WRDREV:	LD	A," "		; WORD BACKWARD (SEARCH SPACE)
95BF	48	376		LD	C,B		; BC = 0 (SEARCH ON 256 BYTES)
95C0	2B	377	WRDREVA: DEC	HL
95C1	2B	378	WRDREV1: DEC	HL		; GO BACKWARD UNTIL NO SPACE FOUND
95C2	BE	379		CP	(HL)		;   ...
95C3	28FC	380		JR	Z,WRDREV1	; 
95C5	EDB9	381		CPDR			; SEARCH BACKWARD
95C7	23	382		INC	HL		; SET POINTER NOT TO POINT AT LAST CHAR.
95C8	23	383		INC	HL		;   OF PREVIOUS WORD BUT START OF CURRENT
95C9	C9	384		RET
95CA	60	385	BEGIN:	LD	H,B		; BEGIN OF TEXT CHKCUR WILL MAKE
95CB	68	386		LD	L,B		; POINTER RIGHT
95CC	C9	387		RET
95CD	2A0091	388	ENDT:	LD	HL,(ENDTEXT)	; POINT TO END OF TEXT
95D0	C9	389		RET
95D1	014003	390	SCRDOWN: LD	BC,32*10+512	; SCREEN DOWN
95D4	11	391		BEFB	#11		; SKIP NEXT INSTR.
95D5	0EC0	392	SCRUP:	LD	C,-32*10+256	; SCREEN UP
95D7	05	393		DEC	B		; PROPAGATE CARRY
95D8	11	394		DEFB	#11		; SKIP NEXT INSTR.
95D9	0EFF	395	LEFT:	LD	C,-1		; CURSOR LEFT
95DB	11	396		DEFB	#11		; SKIP NEXT INSTR.
95DC	0EF0	397	UP:	LD	C,-16		; CURSOR UP
95DE	05	398		DEC	B		; PROPAGATE CARRY
95DF	11	399		DEFB	#11		; SKIP NEXT INSTR.
95E0	0E01	400	RIGHT:	LD	C,1		; CURSOR RIGHT
95E2	11	401		DEFB	#11		; SKIP NEXT INSTR.
95E3	0E10	402	DOWN:	LD	C,16		; CURSOR DOWN
95E5	09	403		ADD	HL,BC		; CALCULATE NEW POINTER
95E6	C9	404		RET
Previous page | Index | Next page