	.TITLE	LSFORM.P11

	;LSFORM - PREFIX MODULE FOR LPFORM.P11 FOR LS11
	;	CENTRONIX PRINTER
	;DATE: 		EDIT:		BY: MHB/JDM

LPFORM	=	1		; FORMS CONTROL IN
LS	=	1		; 1 OR MORE LS11'S

LPMULT	=	0		; 0 IF ONLY 1 PRINTER, 1 IF TWO PRINTERS


	.TITLE	LPFORM.P11	LINE-PRINTER DRIVER

	;COPYRIGHT 1972,1973 BY DIGITAL EQUIPMENT CORPORATION,
	;	MAYNARD, MASS.

	;DATE:		EDIT:		BY:	MHB/JDM

	.ASECT

	VECTOR	200,LPTINT,PR4	;SET UP INTERUPT VECTOR FOR LP0:

	.IFNZ	LPMULT
	VECTOR 170,LPTINT,PR5+1		;VECTOR FOR SECOND LINE PRINTER
	.ENDC	;LPMULT

	.CSECT	LP

	.GLOBL	LPTGO,LPTSER,LPTHNG,LPTS10			;INTERNAL

	.GLOBL	RTI3,SAVREG,RESRTI,IOFINI,TABBER,STORE	;(MONITOR)
	.GLOBL	CLRBUF,FETCH,FREBUF,RESREG
	.GLOBL	LPTDDB,LPTIMR,LPTUPC,LPTDEV,LPSTS	;(TABLES)
	.GLOBL	TTYS20,TTYS30				;(TTY)

	.IFNDF	LPFORM
LPFORM	=	0		;IF HE DOESN'T KNOW ABOUT IT
	.ENDC
.IIF	NDF	LPMULT	LPMULT=0
.IIF	NDF	LS	LS=0

LPTIMO	=	5		;LS11 FORM FEED TAKES A WHILE
LPTS22:	MOV	(SP)+,R2	;GET BACK THE SAVED CHARACTER
LPTS10:	JSR	R5,FREBUF	;IS THERE ENOUGH BUFFERS
	.BYTE	DDOUT+BC,2
	BCS	LPTS11		;IF NOT, THEN EXIT NOW
	.IFZ	LPFORM
	BIC	#-177-1,R2	;CLEAR ANY EXCESS BITS
	.ENDC
	.IFNZ	LPFORM
	TSTB	R2		;IS THIS A CONTROL CHARACTER?
	BPL	LPTS21		;IF NORMAL, THEN CONTINUE
	JSR	R5,FREBUF	;IF CONTROL, ARE THERE EXTRA BUFFERS?
	.BYTE	DDOUT+BC,4
	BCS	LPTS11		;IF NOT, THEN QUIT NOW
	BIC	#-177-1,R2	;CLEAR THE SIGN (CONTROL CHARACTER) BITS
	CLR	-(SP)		;MAKE A FULL WORD OF 0 ON STACK
	MOVB	DDVERC(R1),(SP)	;NOW STACK HAS THE MAX POSITION
	SUB	R2,(SP)		;NOW FIND THE ROW WE WANT TO GO TO
	BLE	LPTS24		;UNLESS IT IS ILLEGAL, THEN IGNORE
LPTS23:	JSR	PC,LPTLF	;NOW SEND LINE FEEDS
	CMPB	DDVERT(R1),(SP)	;UNTIL THE VALUES MATCH
	BNE	LPTS23		;CONTINUE LINE FEEDS UNTIL THERE
LPTS24:	TST	(SP)+		;DUMP THE STACK ITEM (AND CARRY=0)
	RTS	PC		;AND EXIT
	.ENDC
LPTS21:	CMPB	R2,#177		;RUBOUT?
	BEQ	LPTS14		;IF SO, THEN IGNORE IT
	CMPB	R2,#15		;IS IT RETURN
	BEQ	LPTCR		;YES
	CMPB	R2,#12		;IS IT LINE FEED
	BEQ	LPTLF		;YES
	CMPB	R2,#14		;IS IT FORM FEED
	BEQ	LPTFF		;YES
	CMPB	R2,#11		;IS IT TAB
	BEQ	LPTAB		;YES
	.IFNZ	LPFORM
	BIT	#LPTCH0,(R1)	;TRANSFORM 0'S TO O'S?
	BEQ	LPTS16		;NOT THIS TIME
	CMPB	R2,#'0		;IF SO, IS THIS A 0?
	BNE	LPTS16		;NOPE
	MOV	#'O,R2		;YEP, SO CHANGE IT TO A O
	.ENDC
LPTS16:	.IFNZ	LPMULT
	CMPB	R2,#140		;IS THIS A LOWER CASE CHARACTER?
	BLOS	LPTS15		;LEAVE IT ALONE IF NOT
	BIT	#LPTUCO,(R1)	;CONVERSION REQUESTED?
	BEQ	LPTS15		;NO
	.ENDC	;LPMULT
	.IFZ	LPMULT
	CMPB	R2,#LPTUPC	;IS THIS A LOWER CASE CHARACTER
	BLOS	LPTS15		;IF NOT, THEN LEAVE IT ALONE
	.ENDC	;LPMULT
	BIC	#40,R2		;ELSE MAKE IT UPPER CASE
LPTS15:	BIT	R2,#140		;IS THIS A PRINTING CHARACTER
	BEQ	LPTS30		;IF NOT, THEN IGNORE IT
LPTS20:	DECB	DDHORZ(R1)	;BUMP THE HORIZONTAL POSITION
	BNE	LPTS12		;IF O.K., THEN GO STORE THAT CHARACTER
	MOV	R2,-(SP)	;ELSE SAVE THE CHARACTER
	MOV	#LPTS22,-(SP)	;AND RETURN TO LPTS22 LATER
LPTLF:	.IFNZ	LS
	JSR	PC,LPTS40	;SEE IF EXTRA CR NEEDED
	.ENDC	;LS
	MOV	#12,R2		;NOW WE SEND OUT A LINE FEED
	DECB	DDVERT(R1)	;COUNT THIS AS A LINE
	BNE	LPTCR		;NOT END OF FORM YET
	.IFZ	LPFORM
LPTFF:
	.ENDC
LPTFF1:	.IFNZ	LS
	JSR	PC,LPTS40	;SEE IF EXTRA CR NEEDED
	.ENDC	;LS
	MOVB	DDVERC(R1),DDVERT(R1);RESET THE VERTICAL POSITION
LPTCR:	MOVB	DDHORC(R1),DDHORZ(R1);AND RESET THE HORIZ POSITION
LPTS12:	JSR	R5,STORE	;NOW STORE THE CHARACTER
	+	DDOUT+FP	;INTO LPT BUFFER
	.IFZ	LS
LPTS30:
	.ENDC	;LS
LPTS14:	CLC			;INDICATE GOODNESS
LPTS11:	RTS	PC		;AND EXIT

	.IFNZ	LPFORM
LPTFF:
	.IFNZ	LS
	BIT	#LPTSFT,(R1)		;SIMULATE FORM CONTROL?
	BEQ	LPTFF1			;NO
	.ENDC	;LS
	CMPB	DDVERC(R1),#66.	;REGULAR?
	BEQ	LPTFF1		;YES, DO HARDWARE FORM FEED
	BR	LPTS14		;NO, IGNORE CHARACTER
	.ENDC
	.IFNZ	LS
LPTS30:	BIT	#LPTLS,(R1)	;IS THIS LS11?
	BEQ	LPTS14		;NO
	CMPB	R2,#13		;VERT TAB?
	BNE	LPTS12		;JUST SEND IT
	JSR	PC,LPTS40	;CHECK FOR LINE DUMPED
	BR	LPTS12		;NOW SEND IT

LPTS40:	CMPB	DDHORZ(R1),DDHORC(R1)	;BEGINNING OF LINE?
	BEQ	LPTS11		;YEP
	MOV	R2,-(SP)		;SAVE CHAR
	MOV	#15,R2		;SEND CR
	JSR	PC,LPTCR
	MOV	(SP)+,R2	;RESTORE CHAR
	RTS	PC
	.ENDC	;LS
LPTAB:	.IFNZ	LS
	MOV	#40,R2		;ILLEGAL CHARS DON'T SPACE ON LS
	.ENDC	;LS
	JSR	R5,TABBER	;DO THE TABBING
	+	LPTS20		;TO THIS ROUTINE FOR OUTPUT
	BR	LPTS14		;AND EXIT

;LINE-PRINTER- USER INTERFACE
;MOVE CHARACTERS FROM USER BUFFER TO MONITOR BUFFER
;TRANSLATING ODD CHARACTERS AS NECESSARY
;WHEN BUFFER IS FILLED (OR USER BUFFER EMPTY), START PRINTER

LPTSER:	TST	(R1)		;RETURN FROM HUNG LPT?
	BMI	LPTS01		;YES--GIVE HIM A NASTY PMESSAGE
	TST	(R5)+		;ANYTHING LEFT TO TRANSFER
	BEQ	LPTS02		;NO - FORCE AN INTERRUPT
	JSR	PC,TTYS20	;GET A CHARACTER FROM USER BUFFER
	JSR	PC,LPTS10	;AND MAKE SURE IT IS PROCESSED PROPERLY
	BCS	LPTS02		;IF IT DIDN'T FIT, START LPT
LPTS03:	JSR	R3,TTYS30	;RESTORE R3, ION, UPDATE COUNTS
	+	JSLPT		;JBWAIT BIT TO SET IF BUFFER FULL
	BR	LPTSER		;CHARACTER ACCEPTED; PROCEED.

LPTS01:	BIC	#DDSTAT,(R1)	;CLEAR HUNG BIT FOR NEXT TIME
	MOV	#HNGDEV,@IOSTS	;JOB IS RUNNING NOW
	BR	LPTS04		;GET BACK TO USER VIA RTI3

;START THE LINE PRINTER BY ENABLING INTERRUPT
;AND START THE COUNT DOWN TIMER IN CASE LPT IS OFF-LINE
;IF ENTERED WITH C=0, WE'VE EXHAUSTED USER BYTE COUNT, SO EXIT
;IF C=1, THEN MONITOR BUFFER IS FULL, SO UPDATE USER PARAMETERS

LPTGO:	.IFNZ	LPMULT
	MOV	@#PS,R2		;SAVE THE DAMN C BIT
	MOVB	DDUNT(R1),R4	;MAKE A UNIT INDEX
	ASL	R4		;TO WORD TABLE
	MOV	#LPTIMO,LPTIMR(R4)	;START COUNTDOWN TIMER
	BISB	#100,@LPSTS(R4)	;AND ENABLE LPT INTERRUPT
	MOV	R2,@#PS		;RETRIEVE THE DAMN C BIT
	.ENDC	;LPMULT
	.IFZ	LPMULT
	MOV	#LPTIMO,LPTIMR	;START COUNTDOWN TIMER
	BISB	(PC),@#LPS	;AND ENABLE LPT INTERRUPT
	.ENDC	;LPMULT
	RTS	PC

LPTS02:	JSR	PC,LPTGO	;START THE PRINTER
	BCS	LPTS03		;PROCEED WITH TRANSFERRING CHARS
LPTS04:	JMP	RTI3		;NO MORE CHARACTERS TO MOVE


;WHEN THE LINE-PRINTER TIMES OUT (IF IT'S OFF-LINE),
;WE ENTER THE FOLLOWING ROUTINE FROM THE TIMER SERVICE

LPTHNG:	.IFNZ	LPMULT
	MOV	R0,R1		;MAKE UNIT INDEX
	SUB	#LPTIMR,R1	;FROM DEVICE CLOCK POINTER
	MOV	LPTDEV(R1),R1	;GET DDB
	.ENDC	;LPMULT
	.IFZ	LPMULT
	MOV	#LPTDDB,R1	;AND GET LPT DDB ADDRESS
	.ENDC	;LPMULT
LPTHN1:	JSR	R5,CLRBUF	;REMOVE ANY SMALL BUFFERS IN USE
	+	DDOUT+EP	;DDB ADDRESS
	JSR	R5,IOFINI	;FINISH HIM OFF
	+	JSLPT		;GIVE HIM HUNG DEVICE ERROR
	BIS	#DDSTAT,(R1)	;SET HUNG FLAG FOR LPT:
	RTS	PC		;RETURN TO TIMER SERVICE
;LINE PRINTER INTERRUPT SERVICE
;WE FEED MORE CHARACTERS TO PRINTER IF WE HAVE THEM
;IF THERE IS AN ERROR, WE GIVE USER "DATERR"
;IF PRINTER IS OFF LINE, USER GETS "HNGDEV"

LPTINT:	.IFNZ	LPMULT
	MOV	@#PS,-(SP)	;SAVE THE NEW STATUS
	.ENDC	;LPMULT
	JSR	R5,SAVREG	;ENTERRED FROM HARD INTERRUPT
	.IFNZ	LPMULT		;THIS CODE APPEARS ALSO AT TTYPOL
	MOV	6*2(SP),R3	;GET DEV NUMBER
	BIC	#-37-1,R3	;MASK FROM PRIORITY WORD
	ASL	R3		;WORD INDEX
	CLR	LPTIMR(R3)	;RESET TIMER
	MOV	LPTDEV(R3),R1	;GET DDB ADDRESS
	MOV	LPSTS(R3),R0	;LP STATUS REG ADDRESS
	.ENDC	;LPMULT
	.IFZ	LPMULT
	CLR	LPTIMR		;CLEAR TIME-OUT CLOCK
	MOV	#LPTDDB,R1	;GET LPT DDB ADDRESS
	MOV	#LPS,R0		;AND POINTER TO STATUS
	.ENDC	;LPMULT
	TST	(R0)		;HARDWARE ERROR?
	BMI	LPTI06		;YES - GIVE USER "DATERR"
	BIC	#DDSTAT,(R1)	;NOT AN ERROR SO CLEAR ERROR BIT
LPTI01:	TSTB	(R0)		;READY FOR CHARACTER?
	BPL	LPTI03		;NO - START TIMING OUT
	JSR	R5,FETCH	;GET A CHARACTER
	+	DDOUT+FP	;FROM PRINTER BUFFER
	BCS	LPTI02		;BUFFER IS EMPTY
	MOVB	R2,2(R0)	;OUTPUT THE CHARACTER
	.IFNZ	LS
	CMPB	@(PC)+,@-(PC)	;DELAY
	CMPB	@(PC)+,@-(PC)	;DELAY
	.ENDC	;LS
	BR	LPTI01		;AND ON TO NEXT CHARACTER

LPTI03:	.IFNZ	LPMULT
	MOV	#LPTIMO,LPTIMR(R3)	;RESTART THE TIME-OUT
	.ENDC	;LPMULT
	.IFZ	LPMULT
	MOV	#LPTIMO,LPTIMR	;RESTART THE TIME-OUT
	.ENDC	;LPMULT
	TST	@DDOUT+EP(R1)	;SEE IF CHAINED
	BNE	LPTI05		;NO RUNNING IF NOT
LPTI04:	JSR	R5,IOFINI	;YES- RESTART JOB
	+	JSLPT		;BY SETTING JSLPT IN JBSTAT
	BR	LPTI05		;RESTORE REGS AND EXIT

LPTI06:	.IFNZ	LPMULT
	JSR	PC,LPTHN1	;DDB ALREADY AVAILABLE
	.ENDC	;LPMULT
	.IFZ	LPMULT
	JSR	PC,LPTHNG	;INDICATE "HUNG" PRINTER
	.ENDC	;LPMULT
	CLR	(R0)		;NO MORE LPT INTERRUPTS
LPTI05:	.IFNZ	LPMULT
	JSR	R5,RESREG	;RESTORE WORLD
	TST	(SP)+		;GET RID OF STATUS
	RTI
	.ENDC	;LPMULT
	.IFZ	LPMULT
	JMP	RESRTI		;EXIT FROM INTERRUPT
	.ENDC	;LPMULT

LPTI02:	CLR	(R0)		;NO MORE LPT INTERRUPTS
	BR	LPTI04		;START HIM UP WITH NO ERROR

	.END

