perm filename IO.PAL[1,VDS]1 blob sn#272346 filedate 1977-04-22 generic text, type C, neo UTF8
COMMENT āŠ—   VALID 00017 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00003 00002	IO - TELETYPE IO AND STRING MANIPULATION ROUTINES
C00006 00003	"INSTR" - VT05 INPUT ROUTINE 
C00009 00004	"HOLD" - VT05 ROUTINE TO TEMPORARILY SUSPEND PRINTING
C00010 00005	"RELSCN"- STRING TO FLOATING POINT NUMBER ROUTINE
C00013 00006		   [CONTINUATION OF "RELSCN"]
C00016 00007		   [CONTINUATION OF "RELSCN"]
C00019 00008	"INTSCN"- STRING TO INTEGER NUMBER ROUTINE
C00021 00009	"CLRCMA"- ROUTINE TO CLEAR COMMA BREAK CHARACTER FROM STRING 
C00022 00010	"FORMAT"&"RSTFOR" - ROUTINES TO SET AND RESTORE OUTPUT FORMAT 
C00024 00011	"CVF"   - FLOATING POINT NUMBER TO "F" FORMAT STRING ROUTINE 
C00027 00012	"CVE"   - FLOATING POINT NUMBER TO "E" FORMAT STRING ROUTINE 
C00030 00013	 	   [CONTINUATION OF "CVE"]
C00032 00014	"CVG"   - FLOATING POINT NUMBER TO "E" OR "F" FORMAT STRING  
C00034 00015	"PRTF"  - PRINTING ROUTINE USED BY "CVF", "CVE", & "CVG"
C00037 00016	"CVI"&"CVO"   - INTEGER NUMBER TO ASC STRING 
C00040 00017	LOCAL STORAGE AREA
C00044 ENDMK
CāŠ—;
;IO - TELETYPE IO AND STRING MANIPULATION ROUTINES

.TITLE  IO 

;***NOTE: ALL OF THE REGISTER DEFINITIONS REQUIRED BY THESE ROUTINES****
;***	CAN BE FETCHED BY DOING A ".INSRT HALHED[HAL,HE]"	********


;"CRLF" IS A SUBROUTINE FOR TYPING OUT ONE CARRIAGE RETURN AND LINE FEED 
;ON THE TELETYPE.

CRLF:	MOV	#CRLFX,SG	
	JSR	PC,TYPSTR
	RTS	PC

CRLFX:  .BYTE	15,12,0,0

;"TYPSTR" OUTPUTS A STRING, ENDING WITH A ZERO CHARACTER.  A POINTER TO
;THE START OF THE STRING MUST BE LOADED INTO R5.  CALLED USING THE PC.

TYPSTR:	MOV 	R0,-(SP)	
	BR	2$
1$:	JSR	PC,TYPCHR	;TYPE THIS CHARACTER
2$:	MOVB	(SG)+,R0	;GET A CHARACTER
	BNE	1$		;END OF LINE?
	MOV	(SP)+,R0
	RTS 	PC		;Done

TYPCHR:	TST 	OUTSW		;VT05 or console?
	BEQ 	TYPCH1	
	TSTB 	KBOS		;VT05: Is it available?
	BPL	TYPCHR		;No
	MOVB 	R0,KBOR		;Output a byte to it.
	CMP 	#12,R0		;Was it a line feed?
	BNE 	TYPRET		;If not that code, then done.
	CLR 	R0		;Otherwise, output 3 nulls.
	JSR 	PC,TYPCHR	;
	JSR 	PC,TYPCHR	;
	BR	TYPCHR		;Direct jump; it will return to caller.
TYPCH1:	TSTB 	OREG		;Console:  Ready?
	BNE 	TYPCHR		;No.
	MOVB 	R0,OREG		;Yes.  Output a byte to it.
	MOV	#1,172566	;Wake up pdp10 by generating interrupt
TYPRET:	RTS 	PC		;Return.
;"INSTR" - VT05 INPUT ROUTINE 

;STRING BYTE POINTER MUST BE  IN SG.  A CARRIAGE RETURN  IS ASSUMED TO
;BE  THE  ACTIVATION CHARACTER.  A  RUB OUT  IS  A  DELETING BACKSPACE
;CHARACTER.  AT  THE COMPLETION OF  THIS ROUTINE  A NULL CHARACTER  IS
;PLACED IN THE INPUT STRING.  SG IS LEFT UNCHANGED.

;REGISTERS USED:
;
; 	SG PASSES ARGUMENT AND IS NOT MODIFIED

INSTR:	MOV	R0,-(SP)
	MOV	SG,-(SP)
IN2:	TST 	OUTSW		;VT05 OR CONSOLE?
	BEQ 	CONSIN	
	TSTB	KBIS		;TEST IF KEYBOARD READY
	BEQ	IN2		;WAIT TILL IT IS
	MOVB	KBIR,R0		;GET A CHARACTER
	BR	GOTCAR
CONSIN:	MOV	IREG,R0		;BYTE FROM PDP10?
	BEQ	IN2		;NO
	CLR	IREG
GOTCAR:	BIC     #177600,R0	;MASK OFF - MAKE IT 7 BITS
	CMP	R0,#177		;COMPARE TO BS CHARACTER
	BNE	IN3		;SKIP IF ITS NOT
	CMP	SG,(SP)		;CHECK IF ANY CHARACTERS IN BUFFER
	BEQ	IN2		;FORGET BACK SPACE IF NO CHAR.
	DEC     SG   		;REMOVE LAST CHARACTER IN BUFFER
	MOV	SG,-(SP)
	MOV	#DBS,SG		;PERFORM A DELETING BACKSPACE
	JSR	PC,TYPSTR
	MOV	(SP)+,SG
	BR      IN2
IN3:	CMP	R0,#15		;COMPARE TO CR CHARACTER
	BEQ     IN4   		;CONTINUE READING IF ITS NOT A CR
	CMP	R0,#40		;CHECK IF CHARACTER LEGAL
	BLT	IN2		;IGNOR IF IT IS
    	MOVB	R0,(SG)+	;SAVE THE CHARACTER
	JSR	PC,TYPCHR	;ECHO CHARACTER
	BR 	IN2		;CONTINUE READING
IN4:	MOVB	R0,(SG)+	;END OF STRING,PUT IN A CR 
	CLRB	(SG)		;PUT IN A NULL CHARACTER
      	JSR	PC,CRLF		;TYPE CR/LF
	MOV	(SP)+,SG
	MOV	(SP)+,R0
	RTS	PC		;RETURN

DBS:	.BYTE	10,40,10,0
;"HOLD" - VT05 ROUTINE TO TEMPORARILY SUSPEND PRINTING

;IF A CHARACTER HAS BEEN TYPED ON THE VT05 KEYBOARD, THIS ROUTINE GOES
;INTO A BUSY WAIT LOOP UNTIL ANOTHER CHARACTER IS TYPED.  BOTH CHARACTERS
;ARE LOST.  IF NO CHARACTER HAS BEEN TYPED, THIS ROUTINE RETURNS 
;IMMEDIATELY.

;REGISTERS USED:
;
;	NONE

HOLD:	TSTB	KBIS		;TEST IF CHARACTER TYPED
	BEQ	HLDDNE		;RETURN IF NO CHARACTER
	CLRB	KBIR
	TSTB	KBIS		;ELSE WAIT TILL ANOTHER CHARACTER TYPED
	BEQ	.-4
	CLRB	KBIR
HLDDNE:	RTS	PC



;END OF "HOLD"
;"RELSCN"- STRING TO FLOATING POINT NUMBER ROUTINE

;THE FLOATING POINT NUMBER MUST BE OF THE FORM SIII.DDDESXX WHERE S IS
;THE SIGN OF THE NUMBER, III IS THE INTEGER FIELD,  DDD IS THE DECIMAL
;FIELD,  AND SXX  IS THE EXPONENT  AND ITS SIGN.   THE LENGTH OF  EACH
;FIELD IS VARIABLE  BUT ONLY THE FIRST 8 DIGITS  ARE USED IN COMPUTING
;THE F.P.   NUMBER.  EMPTY FIELDS ARE PERMITTED AND ALL LEADING SPACES
;AND ZEROS ARE IGNORED.  THE LOCATION OF THE FIRST  BYTE OF THE STRING
;MUST  BE LOADED INTO  SG BEFORE  CALLING "RELSCN".   AFTER EXECUTION,
;THIS ROUTINE LEAVES THE F.P. NUMBER IN REGISTER AC0 AND SG POINTS  TO
;THE BYTE FOLLOWING THE LAST DIGIT.  THE C BIT IS USED TO INDICATE AN 
;ERROR CONDITION.  IF NO NUMBER WAS FOUND BEFORE ENCOUNTERING A COMMA
;OR NULL CHARACTER, THE C BIT IS SET OTHERWISE THE C BIT IS CLEARED ON
;EXITING THIS ROUTINE.  "RELSCN" IS CALLED USING THE PC.

;REGISTERS USED:
;
;	AC0,SG PASS ARGUMENTS, NO OTHER REGISTERS AFFECTED


;"DIGIT" CHECKS FOR ASC DIGIT AND CONVERTS TO INTEGER IF IT IS

.MACRO DIGIT NOTDIG
	CMP	R0,#60		;COMPARE TO ASC ZERO
	BLT	NOTDIG		;SKIP IF OUT OF RANGE
	CMP	R0,#71		;COMPARE TO ASC 9
	BGT	NOTDIG		;SKIP IF OUT OF RANGE
	BIC	#60,R0		;MASK OUT ASC BASE
.ENDM

;"CKSIGN" CHECKS FOR A - OR + CHARACTER AND SETS SIGN APPROPRIATELY

.MACRO CKSIGN ISSIGN,NTSIGN,SIGN
	CMP	#53,R0		;IGNOR "+" CHARACTER
	BEQ	ISSIGN
	CMP	#55,R0		;CHECK IF ITS A "-" CHAR.
	BNE	NTSIGN		;EXIT IF ITS NOT
	INC	SIGN		;ELSE SET SIGN NON-ZERO
	BR 	ISSIGN
.ENDM

;START OF "RELSCN"

RELSCN:	MOV	R0,-(SP)	;SAVE REGISTERS
	MOV	R1,-(SP)
	MOV	R2,-(SP)
      	MOV	R3,-(SP)	
      	CLR	R2 		;RESET DIGIT COUNT
	MOV	#1,R3		;SET DECIMAL POINT FLAG
	   [CONTINUATION OF "RELSCN"]

	MOV	#-1,R1		;INDICATE NO DIGITS ENCOUNTERED
 	CLRF	AC0		;CLEAR THE NUMBER ACCUM
	CLR	MSIGN		;ASSUME MANTISSA POSITIVE

;PICK UP A CHARACTER AND CHECK FOR SIGN

PICK:	MOVB	(SG)+,R0	;PICK UP A CHARACTER
	TST	R1		;CHECK IF DIGIT ENCOUNTERED
	BEQ	CHKDG		;SKIP IF TRUE
	CKSIGN	PICK,CHKDG,MSIGN	;CHECK FOR + OR - SIGN

;CHECK IF CHARARCTER IS A DIGIT

CHKDG:	DIGIT	CHKDP		;SKIP TO CHKDP IF NOT A DIGIT
	MULF	TEN,AC0		;MULT DIGIT SUM BY 10
	ASH	#2,R0		;MULTIPLY INDEX BY 4
	ADDF	DGLST(R0),AC0	;ADD THE F.P. TO ACCUM
	CLR     R1    		;INDICATE DIGIT ENCOUNTERED
	SUB     #4,R2		;DECREMENT DIGIT COUNT
	JMP	PICK		;GO GET ANOTHER CHARACTER

;CHECK IF THE CHARACTER IS A DECIMAL POINT

CHKDP:	CMP	#56,R0		;COMPARE CHARACTER TO DECIMAL PT
	BNE	RNORM		;SKIP IF NOT D.P.
      	TST	R3		;CHECK IF DECIMAL POINT ALREADY SET
	BEQ	RNORM		;IF RESET THIS MUST BE A THE END OF THE MANT.
	CLR	R2		;START COUNTING FRACTIONAL DIGITS
	CLR	R3		;INDICATE D.P. SET
	CLR	R1		;INDICATE DIGIT ENCOUNTERED
	JMP	PICK		;GO GET ANOTHER CHARACTER

;CORRECT NUMBER FOR POWER OF TEN IF DIGITS FOUND

RNORM:	TST	R1		;CHECK IF DIGITS FOUND
	BNE	CHKEX		;SKIP IF NONE
	TST	R3		;CHECK IF DECIMAL POINT SET
	BNE	CHKEX		;DONT NORMALIZE IF NO D.P.
    	MULF	TENLST(R2),AC0	;CORRECT DECIMAL POINT

;CHECK IF E SIGN ENCOUNTERED

CHKEX:	CMP	#105,R0		;COMPARE TO E CHARACTER
	BNE	CHKDN		;SKIP IF NOT E
	TST	R1   		;CHECK IF NO DIGITS BEFORE E
	BEQ	EXCN
	LDF	TENLST,AC0	;SET AC0=1 IF EXPONENT BUT NO DIGITS
	   [CONTINUATION OF "RELSCN"]

	CLR	R1		;INDICATE DIGITS ENCOUNTERED
EXCN:	CLR	ESIGN		;ASSUME EXPONENT POSITIVE
	CLR	R3		;CLEAR EXPONENT ACCUMULATOR
	MOVB	(SG)+,R0	;GET NEXT CHARACTER
	CKSIGN	PIC2,DIG2,ESIGN	;CHECK FOR SIGN CHARACTER
PIC2:	MOVB	(SG)+,R0	;SIGN INCOUNTERED, GET NEXT CHAR.
DIG2:	DIGIT	NORM		;EXTRACT DIGIT 
	MUL	#10.,R3		;MULT EXPON REG BY 10.
	ADD	R0,R3		;ADD DIGIT TO EXPONENT REG
	JMP	PIC2		;GO GET ANOTHER CHARACTER

NORM:	TST	ESIGN		;CHECK SIGN OF EXPONENT
	BEQ	.+4
	NEG	R3		;COMPLEMENT EXPONENT IF - SIGN
	ASH	#2,R3		;MULT. INDEX BY 4 FOR F.P. NUMBERS
	MULF	TENLST(R3),AC0	;ADJUST EXPONENT OF NUMBER
	JMP	CDONE		;EXIT ROUTINE

;CHECK IF END OF STRING OR COMMA ENCOUNTERED

CHKDN:	TST     R0		;COMPARE CHARACTER TO A NULL CHARACTER
	BEQ	CDONE		;EXIT IF IT IS, THIS IS THE END OF THE STR
	CMP	#54,R0		;COMPARE TO ","
	BEQ	CDONE		;EXIT IF IT IS
	TST	R1		;TEST IF ANY DIGITS YET
	BLT	PICK		;IF NONE, KEEP SCANNING

;NO MORE DIGITS - APPLY CORRECT SIGN TO NUMBER

CDONE:	DEC	SG		;POINT TO BREAK CHARACTER
    	TST	MSIGN		;TEST SIGN OF MANTISSA
	BEQ	.+4
	NEGF	AC0		;COMPLEMENT NUMBER IF SIGN NEGATIVE
       	TST	R1		;TEST IF NO NUMBER ENCOUNTERED
	BEQ	.+4
	SEC			;SET C REGISTER IF NO NUMBER FOUND
       	MOV	(SP)+,R3	;RESTORE REGISTERS
	MOV	(SP)+,R2
     	MOV	(SP)+,R1
     	MOV	(SP)+,R0
	RTS	PC		;RETURN


;END OF "RELSCN"
;"INTSCN"- STRING TO INTEGER NUMBER ROUTINE

;THE INTEGER NUMBER MUST BE OF THE FORM SIII WHERE S IS THE SIGN OF THE
;NUMBER, AND III IS THE INTEGER FIELD.  ALL LEADING SPACES AND  ZEROS
;ARE IGNORED.  THE LOCATION OF THE FIRST BYTE OF THE STRING MUST BE 
;LOADED INTO REGISTER SG BEFORE CALLING "INTSCN".  AFTER EXECUTION,
;THIS ROUTINE LEAVES THE INTEGER NUMBER IN R0 AND SG POINTS TO
;THE BYTE FOLLOWING THE LAST DIGIT.  THE C BIT IS USED TO INDICATE AN 
;ERROR CONDITION.  IF NO NUMBER WAS FOUND BEFORE ENCOUNTERING A COMMA
;OR NULL CHARACTER, THE C BIT IS SET.  ALSO, IF THE INTEGER NUMBER IS
;TOO LARGE, THE C BIT IS SET, OTHERWISE THE C BIT IS CLEARED ON EXITING
;THIS ROUTINE.  "INTSCN" IS CALLED USING THE PC.

;REGISTERS USED:
;
;	R0,SG PASS ARGUMENTS AND ARE ALTERED
;	AC0 IS GARBAGED

INTSCN:	JSR	PC,RELSCN	;CONVERT STRING NUMBER TO FLOATING POINT
	BCC	.+4
	RTS	PC		;EXIT IF NO NUMBER FOUND
	STCFI	AC0,R0		;ELSE CONVERT NUMBER TO INTEGER
	CFCC			;TRANSFER CODITIONAL CODES
	RTS	PC		;RETURN


;END OF "INTSCN"
;"CLRCMA"- ROUTINE TO CLEAR COMMA BREAK CHARACTER FROM STRING 

;"CLRCMA" CAN BE CALLED FOLLOWING "RELSCN" TO ADJUST THE STRING
;POINTER IN SG TO SKIP OVER THE COMMA CHARACTER WHICH IS USED
;TO SEPARATE NUMBERS IN THE SAME INPUT STRING.  SG MUST BE 
;POINTING AT THE INPUT STRING.  NO OTHER REGISTERS ARE EFFECTED.

CLRCMA:	TSTB	(SG)		;CHECK IF AT END OF STRING
	BNE	.+4	
	RTS	PC		;RETURN IF END OF STRING
	CMPB	#54,(SG)+	;COMPARE TO COMMA CHARACTER
	BNE	CLRCMA		;BRANCH IF IT ISN'T
	RTS	PC		


;END OF "CLRCMA"
;"FORMAT"&"RSTFOR" - ROUTINES TO SET AND RESTORE OUTPUT FORMAT 

;THE TOTAL NUMBER OF CHARACTERS TO BE WRITTEN (WIDTH) SHOULD BE
;LOADED INTO R0 AND THE NUMBER OF DECIMAL DIGITS (DIGITS) SHOULD
;BE LOADED INTO R1 BEFORE CALLING THIS ROUTINE.  IN ALL CASES,
;WIDTH SHOULD BE GREATER THAN OR EQUAL TO DIGIT+2.  "FORMAT" IS
;CALLED BY USING THE PC.

;REGISTERS USED:
;
;	R0,R1 PASS ARGUMENTS
;	NO OTHER REGISTERS AFFECTED

FORMAT:	MOV	WIDTH,OLDW	;SAVE THE OLD WIDTH
	MOV	DIG,OLDD	;   AND DIG
	SUB	#2,R0		;SUBTRACT SPACES FOR SIGN AND . FROM WIDTH
	MOV	R0,WIDTH	;SAVE WIDTH OF I/O STRING - 2
	MOV	R1,DIG		;SAVE THE NUMBER OF DECI. DIGITS
	CMP	R0,R1		;CHECK TO SEE THAT WIDTH.GE.DIGIT+2
	BGE	NFER		;SKIP IF SPACE ALLOWED, ELSE CORRECT
	MOV	SG,-(SP)	;TYPE OUT ERROR MESSAGE
	MOV	#FERM,SG
	JSR	PC,TYPSTR
	MOV	(SP)+,SG
	MOV	R1,WIDTH	;SET WIDTH=DIG+2
NFER:	RTS	PC		;RETURN

FERM:	.ASCIZ /
FORMATTING ERROR
/
	.EVEN


;"RSTFOR" - ROUTINE TO RESTORE LAST FORMAT

;THE PREVIOUS FORMAT BECOMES THE CURRENT FORMAT.  THE CURRENT
;FORMAT IS LOST FOREVER.  "RSTFOR" IS CALLED IN USING THE PC.

;REGISTERS USED:  NONE

RSTFOR:	MOV	OLDW,WIDTH	;RESTORE WIDTH
	MOV	OLDD,DIG	;RESTORE DIG
	RTS	PC		;RETURN


;END OF "FORMAT" &"RSTFOR"
;"CVF"   - FLOATING POINT NUMBER TO "F" FORMAT STRING ROUTINE 

;"CVF" - THE STRING GENERATED BY THIS ROUTINE IS SIMILAR TO "F" FORMAT
;IN  FORTRAN.  IT  IS ASSUMED  THAT THE NUMBER  TO BE CONVERTED  IS IN
;REGISTER AC0  AND SG  CONTAINS A  POINTER TO  THE FIRST  BYTE OF  THE
;OUTPUT STRING.  THE NUMBER OF  CHARACTERS WRITTEN SHOULD FIRST BE SET
;IN  A CALL  TO "FORMAT", ELSE  THE DEFAULT VALUES  ARE USED.   IF THE
;INTEGER PART  OF  THE  NUMBER EXCEEDS  THE  FORMAT LIMITS  THE  FIRST
;CHARACTER WRITTEN  IS A ">".   AFTER COMPLETION, "CVF"  LEAVES A NULL
;CHARACTER FOLLOWING THE NUMBER STRING.  REGISTER SG IS LEFT  POINTING
;AT THE NULL CHARACTER.

;REGISTERS USED:
;
;	SG,AC0 PASS ARGUMENTS AND ARE ALTERED
;	AC1 IS GARBAGED

CVF:	MOV	R1,-(SP)	;SAVE REGISTER
    	MOV	WIDTH,R1	;GET THE TOTAL NUMBER OF CHAR TO BE WRITTEN
	SUB	DIG,R1		;DETERMINE THE MAG. OF THE M.S. DIGIT
	MOV	R1,PT		;NOW HAVE # OF DIGITS BEFORE DECIMAL POINT
	ASH	#2,R1		;X 4, USE AS INDEX INTO F.P. TABLE
	DIVF	TENLST(R1),AC0	;NORMALIZE NUMBER TO BETWEEN 0 AND .99999999
	MOV	WIDTH,R1	;TOTAL # OF DIGITS TO R1
	MOV	R2,-(SP)	;SAVE THE REGISTERS
	MOV	R3,-(SP)
	JSR	PC,PRTF		;TYPE OUT THE DIGITS
	MOVB	#0,(SG)		;PUT A NULL CHARACTER AFTER THE STRING
	MOV	(SP)+,R3	;RESTORE THE REGISTERS
	MOV	(SP)+,R2
	MOV	(SP)+,R1
	RTS	PC		;RETURN



;END OF "CVF"
;"CVE"   - FLOATING POINT NUMBER TO "E" FORMAT STRING ROUTINE 

;"CVE" - SAME OPERATION AS "CVF" EXCEPT THAT OUTPUT IN FORTRAN "E" FORMAT

CVE:	MOV	R1,-(SP)
     	MOV	R2,-(SP)	;SAVE THE REGISTERS
	MOV 	R3,-(SP)
        CLR     EXPON		;RESET EXPONENT COUNT
	MOV	#1,PT		;SET COUNT TO PRINT 1 NUMBER BEFORE DECIMAL PT
	MOV	WIDTH,R1	;SET COUNT FOR TOTAL NUMBER OF DIGITS TO BE SENT
	SUB	#4,R1		;ADJUST FOR EXPONENT
	TSTF	AC0		;CHECK IF NUMBER IS ZERO
	CFCC			;TRANSFER CONDITIONAL CODES TO CPU
	BEQ	EPRT		;START PRINTING IF NUMBER IS 0.0
     	STF	AC0,NUM		;GET THE NUMBER TO BE CONVERTED
	DEC	EXPON		;ADJUST EXPONENT FOR PRINTING 1 INT. DIGIT
	MOV	NUM,R2		;LOAD THE EXPONENT AND MSB OF THE NUMBER
	BIC	#100000,R2	;CONVERT TO ABSOLUTE VALUE
	SUB	#150,R2		;ADJUST EXPONENT DOWN
	BGE	.+4
	CLR	R2		;LEAVE IT POSITIVE
	MUL	#233,R2		;USE EXPONENT AND MSB AS INDEX INTO TEN TABLE
	CMP	R2,#76.		;COMPARE TO 1.0@38
	BLE	.+6
	MOV	#76.,R2		;IF LARGER, REPLACE BY 1.0@38
      	SUB	#38.,R2		;SHIFT INDEX INTO RANGE OF -38 TO +38
	ADD	R2,EXPON	;ADJUST EXPONENT COUNT
	ASH	#2,R2		;MULT INDEX BY 4 FOR FLOATING POINT NUMBERS
	DIVF	TENLST(R2),AC0	;NORMALIZE NUMBER INTO RANGE 0.0 TO 0.9999
	STF	AC0,AC1		;GET ABSOLUTE VALUE OF NUMBER
	ABSF	AC1
	CMPF	TENLST,AC1	;CHECK IF NUMBER LESS THAN 1.0
	CFCC			;TRANSFER CONDITIONAL CODES TO CPU
	BGT	EPRT		;IF ITS BETWEEN 0.0 AND .99999, GO TO PNTF
	DIVF	TEN,AC0		;ELSE MULT. BY 0.1 AND ADJUST EXPONENT
        INC	EXPON
 	   [CONTINUATION OF "CVE"]

EPRT:	JSR	PC,PRTF		;GO PRINT MANTISSA
	MOVB	#105,(SG)+	;PUT A "E" CHAR INTO THE STRING
	MOVB	#53,(SG)+	;ASSUME EXPONENT POSITIVE A OUTPUT A "+"
	MOV	EXPON,R3	;TEST SIGN OF EXPONENT
	BGE	XPRT		;SKIP IF POSITIVE
	MOVB	#55,-1(SG)	;REPLACE "+" WITH "-"
	NEG	R3    		;MAKE EXPONENT POSITIVE
XPRT:	CLR	R2		;CLEAR FOR DIVISION
     	DIV	#10.,R2		;SEPARATES TENS AND UNITS DIGIT
	BIS	#60,R2		;CONVERT TO ASC AND PUT IN I/O BUFFER
	MOVB	R2,(SG)+
	BIS	#60,R3
	MOVB	R3,(SG)+
	MOVB	#0,(SG)		;PUT IN A NULL CHARACTER
	MOV	(SP)+,R3	;RESTORE THE REGISTERS
	MOV	(SP)+,R2
	MOV	(SP)+,R1
	RTS	PC		;RETURN



;END OF "CVE"
;"CVG"   - FLOATING POINT NUMBER TO "E" OR "F" FORMAT STRING  

;"CVG" - DETERMINES IF THE NUMBER IN AC0 CAN BE WRITTEN BY "CVF", IF
;IT CAN, THEN CVF IS CALLED, ELSE THE NUMBER IS PRINTED USING "CVE".

CVG:	MOV	R1,-(SP)
    	LDF	AC0,AC1		;COPY THE  NUMBER
	CFCC			;TRANSFER THE CONDITIONAL CODES TO CPU
	ABSF	AC1		;CONVERT NUMBER TO ABSOLUTE VALUES
	BEQ	RUNF		;IF NUMBER = 0.0, EXECUTE CVF
	MOV	DIG,R1		;GET THE NUMBER OF DECIMAL DIGITS TO BE TYPED
	ASH	#2,R1		;MULT BY 4 TO USE A FLOATING POINT INDEX
	MULF	TENLST(R1),AC1	;CHECK IF NUMBER SMALLER THAN 1.0@-DIG
	CMPF	TENLST,AC1	;COMPARE TO 1.0
	CFCC			;TRANSFER CONDITIONAL CODES TO CPU
	BGT	RUNE		;IF LESS THAN 1.0@-DIG, PRINT USING CVE
	MOV	WIDTH,R1	;GET THE TOTAL NUMBER OF DIGITS TO BE PRINTED
	ASH	#2,R1		;USE THIS AS A F.P. INDEX
	NEG	R1
	MULF	TENLST(R1),AC1	;CHECK IF GREATER THAN WIDTH-DIG LONG
	CMPF	TENLST,AC1	;COMPARE TO 1.0
	CFCC			;TRANSFER CONDITIONAL CODES
	BGE	RUNF		;IF TOO LARGE, USE CVE
RUNE:	JSR	PC,CVE
	MOV	(SP)+,R1
	RTS	PC
RUNF:	JSR	PC,CVF
	MOV	(SP)+,R1
	RTS	PC


;END OF "CVG"
;"PRTF"  - PRINTING ROUTINE USED BY "CVF", "CVE", & "CVG"

PRTF:	TSTF	AC0		;TEST THE SIGN OF THE NUMBER
	MOVB	#40,MSIGN	;ASSUME SIGN POSITIVE
	CFCC			;TRANSFER THE CONDITIONAL CODES TO CPU
	ABSF	AC0		;CLEAR THE SIGN OF THE NUMBER
	BGE	.+10		
  	MOVB	#55,MSIGN	;IF NEGATIVE PUT IN "-" SIGN
	MODF	TEN,AC0		;COMPUTE M.S. INTEGER DIGIT
	CLR	R3		;INDICATE SIGN NOT YET WRITTEN
DIGLP:	TST	PT		;CHECK IF TIME TO PRINT DECIMAL POINT
	BNE	GETDG		;SKIP IF NOT
	TST	R3		;HAVE WE PRINTED SIGN YET?
	BNE	WTDP		;SKIP IF WE HAVE
	MOVB	MSIGN,(SG)+	;ELSE PRINT SIGN BEFORE DECIMAL POINT
	INC	R3		;INDICATE SIGN PRINTED
WTDP:	MOVB	#56,(SG)+	;PRINT DECIMAL POINT
GETDG:	STCFI	AC1,R2 		;SAVE M.S. INTEGER DIGIT
	CFCC			;CHECK FOR NUMBER TOO LARGE TO INTEGERIZE
	BCC	CHKSZ
TOLGE:	ADDF	AC1,AC0		;IF TWO LARGE, PUT IT BACK TOGETHER
	MODF	TENTH,AC0	;SCALE DOWN AND TRY INTEGERIZING AGAIN
	INC	R1		;PRINT OUT ONE MORE DIGIT
	INC	PT		;SHIFT DECIMAL POINT TO PUT IN EXTRA DIGIT
	TST	R3		;CHECK IF SIGN AND D.P. ALREADY WRITTEN
	BEQ	GETDG		;GO CHECK IF IN RANGE IF NOT WRITTEN
	CLR	R3		;CLEAR SIGN AND D.P.
	SUB	#2,SG		;ADJUST BYTE POINTER
	JMP	GETDG		;GO CHECK IF IN RANGE AGAIN
CHKSZ:	TST     R2              ;TEST INTEGER
	BLT	TOLGE		;IF TOO LARGE, GO SCALE AGAIN
	CMP	R2,#9.		;CHECK IF LESS THAN 9
	BGT	TOLGE		;SCALE IF GREATER THAN 9
      	MODF	TEN,AC0		;START COMPUTING NEXT INTEGER DIGIT
	TST	R3		;HAVE WE PRINTED SIGN YET?
	BNE	SETBS		;SKIP IF WE HAVE
	TST	R2		;CHECK IF LEADING ZERO
	BEQ	WTSP		;IF IT IS GO WRITE A SPACE CHARACTER
	MOVB	MSIGN,(SG)+	;FIRST CHARACTER, NOW PRINT SIGN
	INC	R3		;INDICATE SIGN PRINTED
SETBS:	BIS	#60,R2		;SET ASC ZERO BASE
	JMP	WTCH
WTSP:	MOVB	#40,R2		;WRITE A SPACE CHARACTER
WTCH:	MOVB	R2,(SG)+	;PUT CHARACTER IN I/O BUFFER
	DEC	PT		;DECREMENT DECIMAL POINT COUNT
	SOB	R1,DIGLP	;DONE WITH CHARACTERS?
	RTS	PC		;RETURN


;END OF "PRTF"
;"CVI"&"CVO"   - INTEGER NUMBER TO ASC STRING 

;"CVI"&"CVO" CONVERT THE INTEGER LOADED INTO R0 INTO A ASCII STRING 
;AND APPEND THE NUMBER STRING TO THE STRING POINTED TO BY SG.  SG IS
;LEFT POINTING AT A NULL CHARACTER.  A SAMPLE CALLING SEQUENCE
;FOLLOWS:
;
;		MOV	#NUM,R0		;LOAD NUMBER TO BE CONVERTED
;		MOV	#STRG,SG	;POINT TO OUTPUT STRING
;		JSR	PC,CVI
;
;"CVI" DOES A DECIMAL CONVERSION, WHILE "CVO" WORKS IN BASE 8.

;REGISTERS USED:
;
;	R0, SG PASS ARGUMENTS AND ARE ALTERED

CVI:	MOV	R2,-(SP)	;SAVE REGISTER
	MOV	#10.,R2		;DO A DECIMAL CONVERSION
	BR	CVV

CVO:	MOV	R2,-(SP)	;SAVE REGISTER
	MOV	#8.,R2		;DO A OCTAL CONVERSION

CVV:	MOV	R1,-(SP)	;SAVE REGISTER
	TST	R0		;CHECK SIGN OF NUMBER
	BGE	ITISPL		;BRANCH IF POSITIVE
	NEG	R0		;ELSE COMPLEMENT
	MOVB	#55,(SG)+	;PUSH A "-" INTO STRING
ITISPL:	JSR	PC,DIVLP	;GO FORM STRING RECURSIVELY
	CLRB	(SG) 		;POINT TO A NULL CHARACTER AT END OF STG
	MOV	(SP)+,R1	;RESTORE REGISTERS
	MOV	(SP)+,R2
	RTS	PC		;ALL DONE

DIVLP:	MOV	R0,R1		;POSITION NUMBER FOR DIVISION
       	CLR	R0		;CLEAR FOR DIVISION
	DIV	R2,R0		;GET LSD
	ADD	#60,R1		;OR ASC BASE
	MOVB	R1,-(SP)	;SAVE DIGIT
	TST	R0
	BEQ	.+6		;SKIP IF ALL DONE
	JSR	PC,DIVLP	;REPEAT RECURSIVELY
	MOVB	(SP)+,(SG)+	;PUT DIGITS IN STRING
	RTS	PC


;END OF "CVI"
;LOCAL STORAGE AREA

MSIGN:	0		;SIGN OF CURRENT NUMBER
ESIGN:	0		;SIGN OF EXPONENT
EXPON:	0
NUM:	.WORD  0,0
WIDTH:	8. 		;DEFAULT NUMBER OF CHARACTERS IN OUTPUT STRING
DIG:	3		;DEFAULT NUMBER OF DECIMAL DIGITS
OLDW:	8.		;OLD VALUES OF WIDTH AND DIG
OLDD:	3
PT:	0		;NUMBER OF DIGITS BEFORE DECIMAL POINT

;SYSTEM LINE BUFFERS

INBUF:	.BLKW	42.
OUTBUF:	.BLKW	42.

;TABLE OF F.P. DIGITS FROM 0.0 TO 9.0

DGLST:	.WORD        0,     0, 40200,     0, 40400,     0, 40500,     0
	.WORD    40600,     0, 40640,     0, 40700,     0, 40740,     0
	.WORD    41000,     0, 41020,     0

;TABLE OF POWERS OF TEN

	.WORD      531,143735,  1410, 16352,  2252, 22045,  3124,126456
	.WORD	  4004,166075,  4646, 23514,  5517,130437,  6401,147263
	.WORD	  7242, 41140, 10112,151370, 10775,103666, 11636, 72322
	.WORD	 12506, 11006, 13367,113210, 14232,137025, 15101, 66632
	.WORD	 15761,144400, 16627, 16640, 17474,162410, 20354, 17113
	.WORD	 21223,111357, 22070, 73652, 22746,112625, 23620, 16575
	.WORD	 24464, 22334, 25341, 27023, 26214,136314, 27057,165777
	.WORD	 27733,163377, 30611, 70137, 31453,146167, 32326,137625
	.WORD	 33206, 33675, 34047,142654, 34721,133427, 35603, 11157
	.WORD	 36443,153412
TENTH:	.WORD	 37314,146315 
TENLST:	.WORD	 40200,     0 
TEN:	.WORD	 41040,     0
	.WORD	 41710,     0, 42572,     0, 43434, 40000, 44303, 50000
	.WORD	 45164, 22000, 46030,113200, 46676,136040, 47556, 65450
	.WORD	 50425,  1371, 51272, 41667, 52150,152245, 53021,102347
	.WORD	 53665,163041, 54543, 57651, 55416, 15712, 56261,121274
	.WORD	 57136,  5553, 60012,143443, 60655, 74354, 61530,153447
	.WORD	 62407,103170, 63251, 64026, 64123,141034, 65004, 54521
	.WORD	 65645, 67646, 66516,145617, 67401, 37472, 70241,107410
	.WORD	 71111,171312, 71774, 67574, 72635,142656, 73505, 33431
	.WORD	 74366,102337, 75232, 11414, 76100,113717, 76760,136702
	.WORD	 77626, 73231


;END OF "IO" PROGRAM