Metropoli BBS
VIEWER: floppy.mar MODE: TEXT (ASCII)
	.TITLE	LAB5
;+
;
; 35.477 COMPUTER HARDWARE DESIGN LAB #5.
;
; I/O ROUTINES FOR Q-BUS FLOPPY CONTROLLER.
;
; WRITTEN SPRING 1992 BY NIMAL RATNAYAKE, DOUG SHOAF, JOHN WILSON.
;
;-
	.PSECT	ABS,LONG	;ADDRESSES ARE ABSOLUTE
	.DSABL	GBL		;UNDEFINED SYMBOLS CAUSE ERROR
;
; DEFINE THE SYMBOLS
;
NTRK=	35		;NUMBER OF TRACKS PER DISK
NSEC=	16		;NUMBER OF SECTORS PER TRACK
SECLEN=	128		;SECTORS ARE 128 BYTES (SINGLE DENSITY)
;
; DEVICE REGISTERS.
;
FDCSR=	^X20001E78	;COMMAND/STATUS REGISTER
FDCSRH= FDCSR+1		;HIGH BYTE OF CSR
FDTRK=	FDCSR+2		;WD 1771 TRACK REGISTER (BYTE)
FDSEC=	FDCSR+4		;WD 1771 SECTOR REGISTER (BYTE)
FDDAT=	FDCSR+6		;WD 1771 DATA REGISTER (BYTE)
;
; INTERRUPT VECTOR LOCATIONS.
;
; VECTORS ARE .LONG'S CONTAINING THE LONGWORD-ALIGNED (MULTIPLE OF 4)
; ADDRESS OF THE INTERRUPT SERVICE ROUTINE IN BITS <31:2>.  THE LOW 2 BITS MUST
; BE 00 TO USE THE KERNEL STACK;  OTHER VALUES DO OTHER THINGS, IN PARTICULAR
; 10 WILL CAUSE A JUMP TO USER MICROCODE, SO MAKE SURE THE SERVICE ROUTINE
; STARTS ON A LONGWORD BOUNDARY (ADDRESS=MULTIPLE OF 4)!
;
VEC$A=	^X2B0		;INTERRUPT A VECTOR
VEC$B=	^X2B4		;INTERRUPT B VECTOR
;
; INTERNAL PROCESSOR REGISTER NUMBERS, ACCESSED WITH MTPR INSTRUCTION
; (N.B. SECOND OPERAND IS POINTER TO REG SO MUST BE IMMEDIATE!).
; THESE MUST BE INITIALIZED BEFORE INTERRUPTS WILL WORK.
PR$_SCBB=^X11		;SYSTEM CONTROL BLOCK BASE (INIT TO 0)
PR$_IPL=^X12		;INTR PRIORITY LEVEL (INIT TO 13 TO ALLOW FLOPPY INTRS)
;
; THE NEXT FOUR PROCESSOR REGISTERS CONTROL THE CONSOLE TERMINAL INTERFACE.
; (NOT ALL VAXEN IMPLEMENT THESE BUT THE KA640 DOES)
;
RXCS=	^X20		;UART RECEIVER CONTROL/STATUS REG (BIT 7 = READY)
RXDB=	^X21		;UART RECEIVER DATA BUFFER REG (LOW BYTE = CHAR)
TXCS=	^X22		;UART TRANSMITTER CONTROL/STATUS REG (BIT 7 = READY)
TXDB=	^X23		;UART TRANSMITTER DATA BUFFER REG (LOW BYTE = CHAR)
;
; ASCII CHARACTERS
;
CTRLC=	^O3		;CONTROL/C (ABORT FROM PROMPT)
BEL=	^O7		;BELL (7 OCTAL)
BS=	^O10		;BACKSPACE
LF=	^O12		;LINE FEED
CR=	^O15		;CARRIAGE RETURN
RUB=	^O177		;RUBOUT
;
STACK=	^X1000		;STACK BUILDS DOWN BELOW FIRST ROUTINE
;
; ROUTINE TO SEEK TO TRACK 34 USING POLLED I/O (NO INTERRUPTS).
;
	.=^X1000		;START WITH "S 1000"
SEEK:	; WAIT UNTIL 1771 IS READY (SHOULD BE READY ALREADY)
	CLRB	@#FDCSRH	;CLEAR THE CSR/FIFO SETTINGS
10$:	MOVB	@#FDCSR,R0	;READ STATUS
	BLBS	R0,10$		;IF BIT 0 IS 1 (BUSY) WAIT
	MOVB	#34,@#FDDAT	;LOAD TRACK NUMBER
	MOVB	#^X13,@#FDCSR	;SEEK COMMAND
	; BRIEF DELAY TO GIVE THE "BUSY" BIT TIME TO TURN ON
	MOVL	#20,R0		;WAIT LOOP COUNT
20$:	SOBGTR	R0,20$		;SIT 'N SPIN
	; WAIT FOR THE "BUSY" BIT TO TURN OFF
30$:	MOVB	@#FDCSR,R0	;READ STATUS
	BLBS	R0,30$		;IF LOW BIT SET (BUSY) WAIT
	HALT
;
; ROUTINE TO SEEK TO TRACK 0 USING POLLED I/O (NO INTERRUPTS).
;
	.=^X2000		;START WITH "S 2000"
RECAL:	; WAIT UNTIL 1771 IS READY (SHOULD BE READY ALREADY)
	CLRB	@#FDCSRH	;CLEAR THE CSR/FIFO SETTINGS
10$:	MOVB	@#FDCSR,R0	;READ STATUS
	BLBS	R0,10$		;IF BIT 0 IS 1 (BUSY) WAIT
	MOVB	#^X03,@#FDCSR	;RECALIBRATE COMMAND
	; BRIEF DELAY TO GIVE THE "BUSY" BIT TIME TO TURN ON
	MOVL	#20,R0		;WAIT LOOP COUNT
20$:	SOBGTR	R0,20$		;SIT 'N SPIN
	; WAIT FOR THE "BUSY" BIT TO TURN OFF
30$:	MOVB	@#FDCSR,R0	;READ STATUS
	BLBS	R0,30$		;IF LOW BIT SET (BUSY) WAIT
	HALT
;
; SAME AS ABOVE ONLY USES INTERRUPT "A" TO DETECT COMPLETION.
;
; IF INTERRUPT "A" NEVER HAPPENS THIS ROUTINE WILL SPIN FOREVER,
; TYPE "BREAK" TO HALT.
;
	.=^X3000		;START WITH "S 3000"
RECAL1:	; INIT INTERRUPT SYSTEM
	MOVL	#STACK,SP	;SET STACK POINTER
	CLRB	@#FDCSRH	;CLEAR THE CSR/FIFO SETTINGS
	MTPR	#^X0,#PR$_SCBB	;SET SYS CTRL BLK BASE ADDRESS TO 0
	MTPR	#^X13,#PR$_IPL	;SET INTR PRIORITY LEVEL TO 13
	MOVL	#INTA,@#VEC$A	;SET INTERRUPT VECTOR A
	CLRB	@#DONE		;INTA HASN'T RUN YET
	MOVW	#^X1003,@#FDCSR	;INTR ENA=1,RECALIBRATE
10$:	TSTB	@#DONE		;HAS INTR A TRIGGERED?
	BEQL	10$		;LOOP IF NOT
	HALT
;
; FILL SECTOR BUFFER FROM KEYBOARD.
;
	.=^X4000		;START WITH "S 4000"
FILL:	MOVL	#FILLPR,R0	;POINT AT PROMPT
	MOVL	#6,R1		;LENGTH=6 CHARS
	JSB	@#PRINT		;PRINT THE PROMPT
	MOVL	#BUFFER,R3	;POINT AT BUFFER
	MOVL	#SECLEN,R4	;BYTE COUNT
10$:	JSB	@#GETC		;GET A CHARACTER
	CMPB	R0,#RUB		;RUBOUT?
	BEQL	30$		;YES
	CMPB	R0,#CR		;CR?
	BEQL	40$
	MOVB	R0,(R3)+	;WRITE IT
	JSB	@#PUTC		;ECHO THE CHARACTER	
	SOBGTR	R4,10$		;LOOP FOR EACH BYTE
20$:	MOVL	#CRLF,R0	;POINT AT CR+LF
	MOVL	#2,R1		;LENGTH=2
	JSB	@#PRINT		;ECHO A CRLF
	HALT			;AND HALT
30$:	; THEY TYPED RUBOUT -- DELETE PREVIOUS CHARACTER
	CMPL	R4,#SECLEN	;AT BEGINNING OF LINE ALREADY?
	BEQL	10$		;YES, IGNORE
	MOVL	#BKSPBK,R0	;POINT AT BACKSPACE-SPACE-BACKSPACE
	MOVL	#3,R1		;LENGTH=3 CHARS
	JSB	@#PRINT		;WIPE OUT PREVIOUS CHARACTER
	DECL	R3		;BACK UP POINTER
	INCL	R4		;BUMP FREE COUNTER
	BRB	10$		;AROUND FOR MORE
40$:	; THEY TYPED CR -- PAD REST OF BUFFER WITH BLANKS
	MOVC5	#0,(R3),#^A' ',R4,(R3) ;OH BABY (SEE MANUAL FOR INFO ON MOVC5)
	BRB	20$		;ECHO CR+LF AND HALT
FILLPR:	.ASCII	/DATA? /
;
; ROUTINE TO READ/WRITE THE FIFO USING INTERRUPT "B".
;
; WRITES THE FIRST 64 BYTES OF BUFFER (LOADED BY FILL) INTO THE FIFO'S,
; THEN HALTS; WHEN THE USER TYPES "C" (CONTINUE), READS THE FIFO'S BACK
; INTO THE SECOND 64 BYTES OF BUFFER AND PRINTS THE DATA READ.
;
	.=^X5000		;START WITH "S 5000"
RWFIFO:	; INIT INTERRUPT SYSTEM
	MOVL	#STACK,SP	;SET STACK POINTER
	CLRB	@#FDCSRH	;DISABLE INTERRUPTS
	MOVL	#INTB$W,@#VEC$B	;SET INTERRUPT VECTOR B (WRITE ROUTINE)
	MTPR	#^X0,#PR$_SCBB	;SET SYS CTRL BLK BASE ADDRESS TO 0
	MTPR	#^X13,#PR$_IPL	;SET INTR PRIORITY LEVEL TO 13
	MOVL	#BUFFER,@#POINTR ;ADDRESS OF BEGINNING OF BLOCK
	MOVL	#64,@#COUNTR	;BYTE COUNT
	MOVB	#^XE8,@#FDCSRH	;SET FIFO=1, FFD=1, FIFO-RESET=1, INTR ENB=1
10$:	TSTL	@#COUNTR	;TRANSFERRED ALL BYTES?
	BNEQ	10$		;LOOP IF NOT
	HALT	;;; USER MAY EXAMINE REGISTERS AND <C>ONTINUE
	MOVL	#INTB$R,@#VEC$B	;SET INTERRUPT VECTOR B
	MOVL	#BUFFER+64,@#POINTR ;ADDRESS OF BUFFER INTO WHICH TO READ
	MOVL	#64,@#COUNTR	;BYTE COUNT
	MOVB	#^X88,@#FDCSRH	;SET FIFO=1,FFD=0,INTR ENB=1
20$:	TSTL	@#COUNTR	;TRANSFERRED ALL BYTES?
	BNEQ	20$		;SPIN UNTIL DONE
	; PRINT OUT THE DATA READ
	MOVL	#BUFFER+64,R0	;POINT AT THE PART WE JUST READ
	MOVL	#64,R1		;LENGTH
	JSB	@#PRINT
	MOVL	#CRLF,R0	;CR+LF
	MOVL	#2,R1		;LENGTH=2 CHARS
	JSB	@#PRINT
	HALT
;
; READ A SECTOR FROM THE DISK.  USES INTERRUPTS A AND B.
;
; USER IS PROMPTED FOR TRACK AND SECTOR (IN DECIMAL), AND THE DATA READ
; ARE PRINTED ON THE CONSOLE TERMINAL.  IF THERE IS A READ ERROR THEN
; PRINT "ERR"; TYPE ^C TO HALT AND THEN EXAMINE THE DEVICE REGISTERS
; TO FIND OUT WHAT KIND OF ERROR IT WAS.
;
; THE DATA READ OVERWRITE WHATEVER WAS IN THE SECTOR BUFFER.
;
	.=^X6000		;START WITH "S 6000"
RDSEC:	JSB	@#TRKSEC	;GET TRACK, SECTOR FROM USER INTO R1, R2
	MOVL	#BUFFER,@#POINTR ;SET POINTER TO START OF BUFFER
	; INITIALIZE THE INTERRUPT SYSTEM
 	MOVL	#STACK,SP	;INIT STACK POINTER
	MOVL	#INTA,@#VEC$A	;INTERRUPT "A" SERVICE ROUTINE (SET DONE=1)
	MOVL	#INTB$R,@#VEC$B	;INTERRUPT "B" SERVICE ROUTINE (READ FIFO)
	MTPR	#^X0,#PR$_SCBB	;SET SYS CTRL BLK BASE ADDRESS TO 0
	MTPR	#^X13,#PR$_IPL	;SET INTR PRIORITY LEVEL TO 13
	; TELL 1771 TO SEEK TO THE SPECIFIED TRACK
	CLRB	@#FDCSRH	;CLEAR FIFO CONTROL BITS
	MOVB	R1,@#FDDAT	;GIVE TRACK NUMBER TO 1771
	MOVB	#^X13,@#FDCSR	;SEEK COMMAND (TO THAT TRACK)
	; BRIEF DELAY TO ALLOW "BUSY" BIT TO COME ON
	MOVL	#20,R0		;WAIT LOOP COUNT
20$:	SOBGTR	R0,20$		;SIT 'N SPIN
	; SPIN UNTIL "BUSY" BIT CLEARS AGAIN
30$:	MOVB	@#FDCSR,R0	;READ STATUS
	BLBS	R0,30$		;IF LSB IS 1 (BUSY) WAIT
	; TELL 1771 TO READ THE SPECIFIED SECTOR
	MOVL	#SECLEN,@#COUNTR ;SET COUNTER TO NUMBER OF BYTES TO TRANSFER
	CLRB	@#DONE		;CLEAR "DONE" SEMAPHORE
	MOVB	R2,@#FDSEC	;LOAD SECTOR REGISTER
	MOVW	#^XB88C,@#FDCSR	;FIFO=1,FFD=0,ENA=1,ENB=1,FIFO-RESET=1,READ
40$:	TSTB	@#DONE		;HAS INTR A OCCURRED YET?
	BEQL	40$		;IF NOT LOOP
	BITB	#^X9C,@#FDCSR	;CHECK STATUS: NOT RDY, REC NOT FND, CRC, LOST
	BNEQ	50$		;ERROR IF ANY ERROR BITS SET
	; PRINT THE DATA FROM THE SECTOR
	MOVL	#BUFFER,R0	;ADDRESS
	MOVL	#SECLEN,R1	;LENGTH
	BRB	60$		;SKIP
50$:	MOVL	#ERR,R0		;PRINT ERROR MESSAGE
	MOVL	#3,R1		;LENGTH
60$:	JSB	@#PRINT		;PRINT IT
	MOVL	#CRLF,R0	;POINT AT CR+LF
	MOVL	#2,R1		;LENGTH=2 CHARACTERS
	JSB	@#PRINT		;SKIP A LINE
	BRW	RDSEC		;AROUND FOR MORE
ERR:	.ASCII	/ERR/
;
; WRITE A SECTOR TO THE DISK.  USES INTERRUPTS A AND B.
;
; ANALOGOUS TO RDSEC; THE USER IS PROMPTED FOR TRACK AND SECTOR, AND
; THE CONTENTS OF THE SECTOR BUFFER ARE WRITTEN TO THAT SECTOR.
; ERRORS DETECTED AS ABOVE.
;
	.=^X7000		;START WITH "S 7000"
WRSEC:	JSB	@#TRKSEC	;GET TRACK, SECTOR FROM USER INTO R1, R2
	MOVL	#BUFFER,@#POINTR ;SET POINTER TO START OF BUFFER
	; INITIALIZE THE INTERRUPT SYSTEM
 	MOVL	#STACK,SP	;INIT STACK POINTER
	MOVL	#INTA,@#VEC$A	;INTERRUPT "A" SERVICE ROUTINE (SET DONE=1)
	MOVL	#INTB$W,@#VEC$B	;INTERRUPT "B" SERVICE ROUTINE (WRITE FIFO)
	MTPR	#^X0,#PR$_SCBB	;SET SYS CTRL BLK BASE ADDRESS TO 0
	MTPR	#^X13,#PR$_IPL	;SET INTR PRIORITY LEVEL TO 13
	; TELL 1771 TO SEEK TO THE SPECIFIED TRACK
	CLRB	@#FDCSRH	;CLEAR FIFO CONTROL BITS
	MOVB	R1,@#FDDAT	;GIVE TRACK NUMBER TO 1771
	MOVB	#^X13,@#FDCSR	;SEEK COMMAND (TO THAT TRACK)
	; BRIEF DELAY TO ALLOW "BUSY" BIT TO COME ON
	MOVL	#20,R0		;WAIT LOOP COUNT
20$:	SOBGTR	R0,20$		;SIT 'N SPIN
	; SPIN UNTIL "BUSY" BIT CLEARS AGAIN
30$:	MOVB	@#FDCSR,R0	;READ STATUS
	BLBS	R0,30$		;IF LSB IS 1 (BUSY) WAIT
	; TELL 1771 TO WRITE THE SPECIFIED SECTOR
	MOVL	#SECLEN,@#COUNTR ;SET COUNTER TO NUMBER OF BYTES TO TRANSFER
	CLRB	@#DONE		;CLEAR "DONE" SEMAPHORE
	MOVB	R2,@#FDSEC	;LOAD SECTOR REGISTER
	MOVW	#^XF8AC,@#FDCSR	;FIFO=1,FFD=1,ENA=1,ENB=1,FIFO-RESET=1,WRITE
40$:	TSTB	@#DONE		;HAS INTR A OCCURRED YET?
	BEQL	40$		;IF NOT LOOP
	BITB	#^XFC,@#FDCSR	;CHECK STATUS BITS: NOT RDY, WRT PROT, WRT FLT,
				; REC NOT FND, CRC, LOST DATA
	BNEQ	50$		;ERROR IF ANY ERROR BITS SET
	; PRINT THE DATA WRITTEN FOR CONFIRMATION
	MOVL	#BUFFER,R0	;ADDRESS
	MOVL	#SECLEN,R1	;LENGTH
	BRB	60$		;SKIP
50$:	MOVL	#ERR,R0		;ERROR MESSAGE
	MOVL	#3,R1		;LENGTH
60$:	JSB	@#PRINT		;PRINT IT
	MOVL	#CRLF,R0	;POINT AT CR+LF
	MOVL	#2,R1		;LENGTH
	JSB	@#PRINT		;SKIP A LINE
	BRW	WRSEC		;AROUND FOR MORE
;
; INTR A ("OPERATION COMPLETE") INTERRUPT SERVICE ROUTINE.
;
; SET "DONE" NON-ZERO AND TURN OFF INTR ENA
; (MAINLINE POLLS "DONE" TO SEE WHEN WE HAVE BEEN CALLED).
;
	.ALIGN	LONG
INTA:	MOVB	#1,@#DONE	;;SET "DONE" FLAG
	BICB	#^X10,@#FDCSRH	;;DISABLE FURTHER "A" INTERRUPTS
	REI
;
; INTR B ("FIFO READY") ISR FOR READING FROM FIFO.
;
; READ THE NEXT BYTE FROM THE FIFO, OR DISABLE FIFO INTERRUPTS
; IF ALL BYTES HAVE BEEN TRANSFERRED.
;
	.ALIGN	LONG
INTB$R:	MOVL	R0,-(SP)	;;SAVE R0
	MOVL	@#POINTR,R0	;;FETCH POINTER
	MOVB	@#FDDAT,(R0)+	;;READ A BYTE (ADDRESS IS IN POINTR)
	MOVL	R0,@#POINTR	;;POINT AT NEXT BYTE
	MOVL	(SP)+,R0	;;RESTORE
	DECL	@#COUNTR	;;DECREMENT COUNT
	BEQL	NOMORE		;;0, NO MORE INTS
	REI
;
; INTR B ("FIFO READY") ISR FOR WRITING TO FIFO.
;
; WRITE THE NEXT BYTE TO THE FIFO, OR DISABLE FIFO INTERRUPTS
; IF ALL BYTES HAVE BEEN TRANSFERRED.
;
	.ALIGN	LONG
INTB$W:	MOVL	R0,-(SP)	;;SAVE R0
	MOVL	@#POINTR,R0	;;FETCH POINTER
	MOVB	(R0)+,@#FDDAT	;;WRITE A BYTE (ADDRESS IS IN POINTR)
	MOVL	R0,@#POINTR	;;POINT AT NEXT BYTE
	MOVL	(SP)+,R0	;;RESTORE
	DECL	@#COUNTR	;;DECREMENT COUNT
	BEQL	NOMORE		;;0, NO MORE INTS
	; CUTENESS -- HANDLE NEXT BYTE NOW IF THERE IS ONE
	; INSTEAD OF WAITING FOR THE NEXT INTERRUPT
	BITB	#1,@#FDCSRH	;;"FIFO IR" BIT SET?
	BNEQ	INTB$W		;;YES, WRITE ANOTHER BYTE
	REI
;
NOMORE:	; BYTE COUNT EXHAUSTED, NO MORE INTS NEEDED (FROM INTB$R OR INTB$W)
	BICB	#8,@#FDCSRH	;;CLEAR "INTR ENB" BIT
	REI
;
; GET TRACK AND SECTOR FROM TERMINAL.
;
; RETURNS TRACK IN R1, SECTOR IN R2.  HALTS IF USER TYPES ^C.
;
TRKSEC:	; GET TRACK NUMBER
	MOVL	#TRKPRM,R0	;TRACK PROMPT
	MOVL	#TRKPRL,R1	;LENGTH
	JSB	@#PRINT		;DISPLAY PROMPT
	JSB	@#GETNUM	;GET NUMBER FROM USER
	CMPL	R0,#NTRK	;LESS THAN # OF TRACKS?
	BGEQU	TRKSEC		;RE-PROMPT IF NOT
	MOVL	R0,R6		;SAVE IF SO
10$:	; GET SECTOR NUMBER
	MOVL	#SECPRM,R0	;SECTOR PROMPT
	MOVL	#SECPRL,R1	;LENGTH
	JSB	@#PRINT		;DISPLAY PROMPT
	JSB	@#GETNUM	;GET NUMBER
	TSTL	R0		;0 NOT ALLOWED
	BEQL	10$
	CMPL	R0,#NSEC	;.LE. # OF SECTORS?
	BGTRU	10$		;RE-PROMPT IF NOT
	MOVL	R6,R1		;GET TRACK INTO R1
	MOVL	R0,R2		;SECTOR INTO R0
	RSB
;
; GET A NUMBER FROM THE KEYBOARD.
;
; RETURNED IN R0, R1-R4 TRASHED.
;
GETNUM:	CLRL	R4		;TOTAL SO FAR=0
	CLRL	R5		;# OF CHARACTERS DISPLAYED
10$:	JSB	@#GETC		;GET A CHARACTER
	CMPB	R0,#CR		;CR?
	BEQL	40$
	CMPB	R0,#RUB		;RUBOUT?
	BEQL	30$
	CMPB	R0,#^A'0'	;DIGIT, RIGHT?
	BLSSU	20$
	CMPB	R0,#^A'9'
	BGTRU	20$
	JSB	@#PUTC		;ECHO IT
	SUBB	#^A'0',R0	;CONVERT TO BINARY
	MULL	#10,R4		;TOTAL *10
	ADDL	R0,R4		;ADD IN THE NEW DIGIT
	INCL	R5		;CHAR COUNT *2
	BRB	10$		;LOOP
20$:	; IT WASN'T A DIGIT, CR OR RUBOUT
	MOVB	#BEL,R0		;RING BELL
	JSB	@#PUTC
	BRB	10$		;TRY AGAIN
30$:	; RUBOUT - DELETE PREVIOUS CHARACTER
	TSTL	R5		;IS THERE ONE?
	BEQL	10$		;NO
	DECL	R5		;YES, -1
	DIVL	#10,R4		;LOSE LAST DIGIT
	MOVL	#BKSPBK,R0	;BACKSPACE-SPACE-BACKSPACE
	MOVL	#3,R1		;LENGTH
	BSB	PRINT		;WIPE OUT THE CHAR
	BRB	10$		;AROUND FOR MORE
40$:	; END OF STRING
	MOVL	#CRLF,R0	;POINT AT CR+LF
	MOVL	#2,R1		;2 CHARACTERS
	BSB	PRINT		;ECHO IT
	MOVL	R4,R0		;COPY NUMBER TO R0
	RSB
;
; PRINT A STRING ON THE CONSOLE TERMINAL.
;
; R0	ADDRESS OF STRING
; R1	NUMBER OF CHARACTERS IN STRING
;
PRINT:	MFPR	#TXCS,R2	;GET CSR
	TSTB	R2		;"READY" BIT (BIT 7) SET YET?
	BGEQ	PRINT		;WAIT IF NOT
	MOVZBL	(R0)+,R2	;GET NEXT CHARACTER
	MTPR	R2,#TXDB	;WRITE IT
	SOBGTR	R1,PRINT	;LOOP
	RSB
;
; WAIT AND GET A CHARACTER FROM THE CONSOLE TERMINAL.
;
; IF THE CHARACTER IS CTRL/C THEN HALT.
;
; R0	RETURNS CHARACTER
;
GETC:	MFPR	#RXCS,R0	;GET CSR
	TSTB	R0		;CHAR READY?
	BGEQ	GETC		;NO
	MFPR	#RXDB,R0	;YES, GET IT
	MOVZBL	R0,R0		;CLEAR HIGH 24 BITS
	CMPB	R0,#CTRLC	;^C?
	BEQL	10$		;YES, HALT
	RSB
10$:	HALT
;
; WRITE A CHARACTER TO THE CONSOLE TERMINAL.
;
; R0	CHARACTER TO WRITE
;
PUTC:	MFPR	#TXCS,R1	;GET CSR
	TSTB	R1		;PORT READY FOR THE CHAR?
	BGEQ	PUTC		;NO
	MTPR	R0,#TXDB	;YES, PUT IT INTO THE TRANSMIT DATA BUFFER
	RSB
;
BKSPBK:	.BYTE	BS,^A' ',BS
CRLF:	.BYTE	CR,LF
TRKPRM:	.ASCII	/TRACK? /
TRKPRL=	.-TRKPRM
SECPRM:	.ASCII	/SECTOR? /
SECPRL=	.-SECPRM
;
	.=^X8000	;EXAMINE THESE LOCATIONS WITH "E/P/L <ADDR>"
POINTR:	.LONG		;POINTER TO NEXT BYTE TO READ OR WRITE "E/P/L 8000"
COUNTR:	.LONG		;COUNTER OF BYTES REMAINING TO TRANSFER "E/P/L 8004"
DONE:	.BYTE		;FLAG - NON-ZERO => DONE WITH OPERATION "E/P/B 8008"
;
	.=^X9000	;BUFFER LOCATION
BUFFER:	.BLKB	SECLEN	;HOLDS ONE SECTOR "E/P/B/N:7F 9000"
;
	.END
[ RETURN TO DIRECTORY ]