.TITLE ODTRSX
.SBTTL FPODT -- FLOATING-POINT OPEN/CLOSE
.ENABL LC
.LIST CND
; Author: C J Doran
; Sira Ltd., South Hill, Chislehurst, Kent, BR7 5EH, England.
; Tel: +44 1 467 2636, Telex: 896649, Fax: +44 1 467 6515
;
; Free of copyright, except for DEC's bits.
;
; Extends ODT to recognise two extra commands for floating-point numbers:-
;
; {
}[
; opens the given , or re-opens the current one
; if omitted, as a floating-point word or words, and
; prints according to the character:-
; \ Unbiassed floating-point exponent, in octal,
; / 1-word floating number, as used by immediate
; instructions LDF #^F1.5,F0 etc.,
; E 2-word number (single-precision),
; D 4-word number (double-procision).
;
; The following special addresses are recognised:-
; $0-$5 open the corresponding floating registers,
; $S opens the floating-point status register,
; $W opens the FP exception address and register.
;
; ]
; closes the currently open location, storing
; (if given) in the number of bytes determined by the
; previous open mode (default 2-words), or as specified
; by using '\', 'E', or 'D' as exponent symbol.
; Except for exponent mode ('\') and status, which are
; read in octal, any valid floating-point number format
; is recognised.
;
; The must be carriage-return, line-feed,
; or up-arrow, with the usual ODT effect. When opening next or
; previous locations, the address is updated as follows:
; by 2 bytes if 1-word format, or $S or $W open,
; by 4 or 8 if 2- or 4-word format,
; as previous if exponent examined,
; next register if $0-$5 opened.
;
; Any illegal character, including embedded spaces, will be
; treated as an error and flagged with '?' in the usual way.
; Since it is not possible to write to FEA, or FEC, an
; attempt to do this is illegal too.
;
;
; Define the following symbol if the largest floating-point number
; is to be recognised as 'INFINITY'. If so, then '?' will be
; accepted for this value by the close (]) processor. This
; is a special option for the Sira modification to RMCS CORAL-66
; allowing such programs to use the FP11A and FP11F floating-point processors.
; -infinity is also recognised, for the Sira plot processor.
R$$INF=0 ; If defined, recognise infinity
;
; Set the SYSTEM version number:
; 32 for RSX V3.2
; 40 for RSX V4.x, M+ V2.1, VAX-11 RSX V1.0
V$$RSN=50 ; 50 for RSX V5.0, M+ V3.0, VAX-11 RSX V2.0
;WARNING: DO NOT enable the following line. ODTID support is not complete --
; I/D space switching for FP fetch/store is not yet implemented.
;O$$DID=0 ; For ODTID, M+ V2.1
; Options other than the above are unsupported.
;
; ASSEMBLE AS:
;
; >MAC FPODT.POB=FPODT.PAT
;
; THEN INSTALL IN ODT BY:
;
; >PAT ODT.OBJ;2=ODT.OBJ;1,FPODT
;
; IN DIRECTORY LB:[1,1]. FOR V3.2, NOTE THAT ODT.OBJ;1 MUST BE TAKEN FROM
; THE ORIGINAL DISTRIBUTION MEDIA IF ANY PATCHES FROM "THE SOFTWARE
; DISPATCH" HAVE BEEN INCLUDED ALREADY. THIS LISTING INCORPORATES
; ARTICLE 5.5.1.1 FROM JULY 1980 (M05A AND M05B).
F0=%0 ; DEFINE THE F.P. REGISTERS
F1=%1
F2=%2
F3=%3
F4=%4
F5=%5
LF=12 ; ASCII line-feed
CR=15 ; ASCII carriage-return
ESC=33 ; ASCII escape
CSI=233 ; Multinational CSI character
; Set instruction and data space locations SYMB, according to version.
; Note: V4.0 and V5.0 addresses are identical.
.IF EQ V$$RSN-32
.MACRO SETLOC SYMB V3.2 V4.0 ID
SYMB=$$$CDE+V3.2
.ENDM SETLOC
.MACRO SETDAT SYMB V3.2 V4.0 ID
SYMB=$$$ODT+V3.2
.ENDM SETDAT
.IFF ; GE V$$RSN-40
.IF DF O$$DID
.MACRO SETLOC SYMB V3.2 V4.0 ID
SYMB=$$$CDE+ID
.ENDM SETLOC
.MACRO SETDAT SYMB V3.2 V4.0 ID
SYMB=$$$ODT+ID
.ENDM SETDAT
.IFF
.MACRO SETLOC SYMB V3.2 V4.0 ID
SYMB=$$$CDE+V4.0
.ENDM SETLOC
.MACRO SETDAT SYMB V3.2 V4.0 ID
SYMB=$$$ODT+V4.0
.ENDM SETDAT
.ENDC
.ENDC
; DECODE changed from IOT to TRAP 0 in RSX V5.0 etc.
.IF GE V$$RSN-50
.MACRO DECODE
TRAP 0
.ENDM DECODE
.IFF
.MACRO DECODE
IOT
.ENDM DECODE
.ENDC
.IF DF O$$DID
.PSECT $ODTCD,RW,I
$$$CDE=.
.PSECT $ODTDT,RW,D
$$$ODT=.
.IFF
.PSECT $$$ODT,RW,I,GBL,REL,OVR
$$$ODT=.
$$$CDE=.
.ENDC
.IF EQ V$$RSN-32
.PAGE
.SBTTL PATCHES FROM THE SOFTWARE DISPATCH
; COPYRIGHT (C) 1979, 1980
; DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.
;
; MODIFICATIONS:
;
; MO5A - WAIT FOR I/O TO COMPLETE IF CONTEXT SWITCHING
; HAS BEEN DISABLED
;
; MO5B - DON'T DETACH TERMINAL IF IT WAS ATTACHED UPON ENTRY
;
.IDENT /M05A/
.=$$$ODT+4750
JMP PAT1
.=$$$ODT+5646
PAT1: EMT 377 ;EXECUTE WAIT DIRECTIVE
10$: TST IOSTAT ;HAS I/O COMPLETED?
BEQ 10$ ;NO
RTS PC ;
.=$$$ODT
.IDENT /M05B/
.PSECT $$$ODT,RW,I,GBL,REL,OVR
$$$ODT=.
.=$$$ODT+3516
JSR PC,O.DET ;ATTEMPT TO DETACH THE TERMINAL
.=$$$ODT+3740
JSR PC,O.ATT ;ATTEMPT TO ATTACH THE TERMINAL
.=$$$ODT+3754
JSR PC,O.DET ;ATTEMPT TO DETACH THE TERMINAL
.=$$$ODT+4640
ATDFLG: .WORD 0 ;SAVE ATTACH STATUS HERE
O.DET: MOV #IO.DET,DPBIOF ;SET DETACH FUNCTION
TSTB ATDFLG ;SEE IF WE WANT TO DO IT
BLE O.RET ;IF LE THEN DON'T DO IT
O.ATDT=$$$ODT+4656
O.RET=$$$ODT+4676
.=$$$ODT+5660
O.ATT: MOV #IO.ATT,DPBIOF ;SET ATTACH FUNCTION
CALL O.ATDT ;ATTEMPT THE ATTACH
MOVB IOSTAT,ATDFLG ;SAVE ATTACH STATUS
RTS PC ;
PATEND=.-$$$ODT ; END OF DEC'S PATCHES
.=$$$ODT
.PAGE
.IFF ; i.e. V4.0 or later
.IF DF O$$DID
O.DET=$$$CDE+4436 ; DETACH TI:
PATEND=5426 ; END OF OLD CODE
.IFF
O.DET=$$$CDE+4642 ; DETACH TI:
PATEND=5700 ; END OF OLD CODE
.ENDC
.ENDC ; V3.2
.SBTTL FLOATING-POINT ADDITIONS
; FREE OF COPYRIGHT AGAIN.
.IF EQ V$$RSN-32
.IDENT /M05F/
.IFF
.IF DF O$$DID
.IDENT /M02.1F/
.IFF
.IDENT /M06F/
.ENDC
.ENDC
; ODT'S WORKSPACE.
SETDAT O.UR0 60 60 60 ; USER REGISTER 0 STORED HERE
SETDAT O.UR5 72 72 72 ; USER REGISTER 5
SETDAT O.USP 74 74 74 ; USER SP
SETDAT O.UST 100 100 100 ; USER PS
SETDAT O.DSW 102 102 102 ; USER $DSW
SETDAT O.CAD 326 326 332 ; ADDRESS CURRENTLY OPEN
SETDAT O.DOT 330 330 334 ; LAST EXPLICITLY OPENED ADDRESS
SETDAT O.BW 332 332 336 ; LAST OPEN MODE, 1=BYTE, 2=WORD,
; 4 = SINGLE-PRECISION F.P., 8=DOUBLE
SETDAT O.OBW 354 356 360 ; SAME, BUT A BYTE
SETDAT DPBIOF 364 366 464 ; TI: QIO function
SETDAT DPBCNT 400 402 500 ; TI: QIO byte count
SETDAT IOSTAT 404 406 504 ; QIO I/O status block
SETDAT CHRBUF 410 412 510 ; TI: character buffer
.IF DF O$$DID
O.LOOK=$$$ODT+420 ; TABLE ADDRESS FOR LOOKUP
.PSECT $ODTCD,RW,I
.ENDC
; OVERLAY MAIN COMMAND DECODER TO GIVE US A TRAP FOR AN UNKNOWN
; COMMAND (UNKNOWN, THAT IS TO THE ORIGINAL ODT).
SETLOC . 1630 1632 754
O.USR: JSR PC,O.USER ; ERROR -- TRY USER COMMAND
SETLOC O.NEWC 1666 1670 1012 ; COME HERE FOR NEW COMMAND
SETLOC . 1720 1722 1050
BCS O.USR ; TRY USER IF NOT KNOWN
; EXTEND REGISTER SAVE AND RESTORE TO INCLUDE F.P. REGS TOO.
SETLOC . 3706 3710 3144
JMP O.SVF ; SAVE THE FLOATING REGISTERS
O.SVRR: ; COME BACK HERE
SETLOC . 3754 3756 3212
JSR PC,O.RSF ; RESTORE FLOATING REGS
SETLOC . 4754 5006 4550 ; GET A CHAR FROM TERMINAL TO %0
O.GET: CLRB CHRBUF ; Look at hi byte of CHRBUF
SWAB CHRBUF ; clearing it for next time
MOVB CHRBUF,R0 ; to see if anything saved (after esc)
BNE 2$ ; Yes, use it
MOV #IO.RAL!TF.RNE,DPBIOF ; Read all bits (for CSI), but never echo
JSR PC,O.V200 ; Look for VT2xx escape sequences
2$:
SETLOC . 5036 5070 4636
BCS DOECHO ; No substitution if not escape
SETLOC DOECHO 5044 5076 4644
; ADDRESSES OF SOME USEFUL ODT SUBROUTINES.
SETLOC O.EXIT 3512 3514 2750 ; Exit to MCR
SETLOC EXPCOM 4400 4402 3730 ; COMPUTE EXPRESSION
SETLOC GETNUM 4462 4464 4012 ; GET A NUMBER FROM THE KEYBOARD
SETLOC LOOKUP 4526 4530 4056 ; LOOK UP CHAR IN %0 IN TABLE
SETLOC O.CRLF 4700 4724 4466 ; TYPE CR/LF
SETLOC O.TYPE 4704 4730 4472 ; TYPE 2 CHARS IN %0
SETLOC O.FTYP 4712 4736 4500 ; TYPE 1 CHAR IN %0
SETLOC DOAQIO 4724 4750 4512 ; Execute TI: QIO function
SETLOC O.RORA 5112 5144 4704 ; TYPE %0 AS AN ADDRESS
SETLOC O.CADW 5266 5320 5066 ; TYPE %0 AS AN OCTAL WORD
SETLOC O.CADB 5304 5336 5104 ; TYPE %0 AS AN OCTAL BYTE
; NOW START THE FLOATING-POINT THING PROPERLY
.=$$$CDE+PATEND ; END OF OLD CODE [ + DEC'S LAST PATCH]
; O.USER IS NOW CALLED ON ANY ERROR, WITH %0 CONTAINING THE
; UNRECOGNISABLE BYTE TYPED IF THE ERROR WAS DETECTED AT COMMAND
; LEVEL, " ?" FOR ANY OTHER (E.G. MP TRAP).
O.USER: CMPB %0,#'[ ; OPEN FLOATING?
BEQ O.FOPN ; YES, GO DO IT
CMPB %0,#'] ; CLOSE FLOATING?
BNE O.FERR ; NO, REALLY AN ERROR
; (OTHER USER COMMAND CHARS COULD BE DETECTED HERE.)
; CLOSE FLOATING LOCATION, ENTERING NEW VALUE, IF GIVEN.
O.FCLS: JSR PC,O.FCAD ; GET OPEN ADDRESS
BVS O.FERR ; FEA/FEC CAN'T BE CHANGED
BCC 10$ ; BRANCH IF NOT STATUS
JSR PC,GETNUM ; CARRY => STATUS, GET OCTAL NO
TST %2 ; WAS THERE ONE?
BEQ O.FNXT ; NO, JUST CLOSE
MOV %4,@%5 ; YES, STORE NEW STATUS
BR O.FNXT ; AND CLOSE
10$: TSTB O.FFM ; TEST MODE
BNE 20$ ; BRANCH UNLESS EXPONENT
JSR PC,GETNUM ; GET NEW EXPONENT
TST %2 ; MAKE SURE THERE WAS ONE
BEQ O.FNXT ; NO, DO NEXT THING
ADD #200,%4 ; YES, BIAS THE EXPONENT
SWAB %4 ; PUT IT IN THE HIGH BYTE
ASR %4 ; SHIFT RIGHT ONCE
BIC #100177,%4 ; AND GET RID OF THE UNWANTED BITS
BIC #77600,@%5 ; HERE AND IN DESTINATION
BIS %4,@%5 ; PUT IN THE NEW EXPONENT
BR O.FNXT ; ALL DONE
20$: JSR PC,GETFLO ; GET AN F.P. NUMBER
TST %2 ; IF ANY?
BEQ O.FNXT ; NONE GIVEN, JUST CLOSE
MOVB O.FFM,%1 ; LOAD I/O MODE (1,2, OR 3)
DECB %1 ; MAKE IT 0,1, OR 2
CMPB %1,#2 ; DOUBLE-PRECISION MODE?
BNE 30$ ; NO, BRANCH
STD F0,@%5 ; YES, STORE DP
BR O.FNXT ; DONE
30$: BHI O.FERR ; BUG IF MODE OUT OF RANGE
; 1-WORD OR SINGLE-PRECISION. DON'T USE STCDF BECAUSE IT CHANGES INFINITY TO 0!
STD F0,-(SP) ; PUSH 4 WORDS
MOV (SP)+,(%5)+ ; STORE AT LEAST 1
DECB %1 ; 1-WORD (%1 NOW 0)?
BMI 40$ ; YES, DONE
MOV @SP,@%5 ; NO, STORE SECOND TOO
40$: CMP (SP)+,(SP)+ ; PURGE STACK OF 3 WORDS
CMP (SP)+,-(%5) ; AND RESET RESULT POINTER, %5
; EXIT STORE MODE.
; VALID TERMINATORS (IN %0) ARE CR=CLOSE, LF=CLOSE-OPEN NEXT, AND
; '^'=CLOSE-OPEN PREVIOUS.
O.FNXT: JSR PC,O.UPBW ; UPDATE O.BW & O.OBW
CMPB %0,#CR ; CARRIAGE-RETURN TERMINATOR?
BEQ O.FDCD ; YES, GO GET ANOTHER COMMAND
CMPB %0,#LF ; LINE-FEED?
BEQ 10$ ; YES, BRANCH
CMPB %0,#'^ ; NO, MUST BE UP-ARROW
BNE O.FERR ; BUG IF NOT
SUB O.BW,O.CAD ; SETUP PREVIOUS ADDRESS
BR 20$ ; CONTINUE IN COMMON WITH LF
10$: ADD O.BW,O.CAD ; LF -- SETUP NEXT ADDRESS
20$: JSR PC,O.CRLF ; NEW LINE ANYWAY
MOV O.CAD,%0 ; GET CURRENT ADDRESS
MOV %0,O.DOT ; SET UP DOT
JSR PC,O.RORA ; PRINT CURRENT ADDRESS
MOVB #'[,%0 ; LOAD THE OPEN SYMBOL
JSR PC,O.FTYP ; AND TYPE IT
JSR PC,O.FCAD ; GET NEXT ADDRESS
BVS O.FOPE ; BRANCH SPECIALLY FOR FEC/FEA
BCS O.FOPS ; OR STATUS
MOVB O.FFM,%1 ; NEITHER, GET FLOATING I/O MODE
MOVB FLOCHR(%1),%0 ; CHARACTER
JSR PC,O.FTYP ; TYPE IT AND GO FOR
BR O.FOPG ; GENERAL CASE, BYPASSING GET CHAR
; ERROR. TYPE " ?" AND GO BACK TO COMMAND LEVEL
O.FERR: MOV #" ?,%0 ; LOAD 2 CHARS
JSR PC,O.TYPE ; TYPE THEM
O.FDCD: DECODE ; BACK HOME
; '[' PROCESSOR -- TYPE AN F.P. NUMBER AT CURRENT ADDRESS.
O.FOPN: TST %2 ; WAS AN ADDRESS GIVEN?
BEQ 10$ ; NO, BRANCH
JSR PC,EXPCOM ; YES, COMPLETE EXPRESSION
MOV %4,O.CAD ; SET UP CAD
MOV %4,O.DOT ; AND DOT
10$: JSR PC,O.FCAD ; GET FLOATING ADDRESS
BCS O.FOPS ; CARRY SET MEANS F.P. STATUS
BVC O.FOPQ ; V MEANS FEA/FEC, BRANCH IF NOT
O.FOPE: MOV (%5)+,%0 ; ELSE GET FEC & ADDRESS FEA
CMP %0,#14. ; MAKE SURE IT'S A VALID FEC
BHI 10$ ; NO, PRINT AN OCTAL NUMBER
BIT #1,%0 ; VALID ONES ARE EVEN
BNE 10$ ; PRINT ODD ONES IN OCTAL
MOV FECOND(%0),%0 ; GET A 2-CHAR MNEMONIC
JSR PC,O.TYPE ; FOR THE GOOD ONES
MOV #": ,%0 ; FINISH WITH COLON
JSR PC,O.TYPE ; AND SPACE
BR 20$ ; THEN THE FEA
10$: JSR PC,O.CADW ; PRINT THE STRANGE ONES
20$: MOV @%5,%0 ; GET FEA
JSR PC,O.RORA ; PRINT THAT AS AN ADDRESS
MOVB #'],%0 ; CAN'T WRITE TO FEA/FEC, SO
JMP O.FTYP ; SAY CLOSED AND RTS TO O.DCD
O.FOPS: MOV @%5,%0 ; PRINT STATUS
JSR PC,O.CADW
O.FOS1: JSR PC,O.UPBW ; UPDATE O.BW & O.OBW
BR O.FOD1 ; SPECIAL CASES DONE
; IF NEITHER OF THE SPECIAL CASES, GET ANOTHER CHARACTER TO SEE
; WHICH FLOATING MODE IT IS.
O.FOPQ: JSR PC,O.GET ; GET A CHAR
.IF DF O$$DID
MOV #FLOCHR,O.LOOK ; SET TABLE '\', '/', 'E', 'D'
JSR PC,LOOKUP ; LOOK IT UP
.IFF
JSR %5,LOOKUP ; LOOK IT UP
+ FLOCHR ; IN THE TABLE '\', '/', 'E', 'D'
.ENDC
BCS O.FERR ; ERROR IF NOT THERE
ASR %1 ; REMOVE LOOKUP'S *2
MOVB %1,O.FFM ; STORE FLOATING MODE
O.FOPG: JSR PC,O.SPCE ; TYPE A SPACE
MOVB FLOSIZ(%1),%1 ; GET NO OF BYTES
BEQ 10$ ; UNLESS EXPONENT ONLY,
JSR PC,O.UPBW ; UPDATE O.BW & O.OBW
; MAKE SURE THE LOCATION CONTAINS A CORRECT FORMAT F.P. NUMBER,
; SINCE WE MUSTN'T LOAD AN UNDEFINED VALUE INTO AN F.P. REGISTER.
10$: MOV @%5,%0 ; GET 1ST WORD OF NO
BIC #177,%0 ; STRIP THE TOP BITS OF MANTISSA
CMP %0,#100000 ; DOES THAT LEAVE US WITH SIGN SET,
BNE 20$ ; EXPONENT=0? BRANCH IF NOT
MOV #O.FUND,%1 ; IF IT DOES, WE HAVE AN UNDEFINED
BR O.TEXT ; SO PRINT 'undefined'
20$: TSTB %1 ; EXPONENT MODE?
BNE 40$ ; NO, BRANCH
ASL %0 ; YES, SHIFT THE HI WORD 1 LEFT
SWAB %0 ; THEN DOWN TO LO BYTE
BEQ 30$ ; UNLESS SPECIAL CASE OF F.P. 0.0,
SUB #200,%0 ; GET RID OF THE BIAS
30$: JSR PC,O.CADB ; PRINT AN UNBIASSED EXPONENT BYTE
BR O.FOD1 ; DONE
; PRINT 1-, 2-, OR 4-WORD FLOATING VALUE.
40$: ASR %1 ; HALVE BYTE COUNT FOR WORDS
CLRD -(SP) ; CLEAR 4 WORDS ON STACK
MOV SP,%2 ; ADDRESS THE STACK
42$: MOV (%5)+,(%2)+ ; AND COPY MEMORY THERE
DECB %1 ; %1 GIVES NO OF NON-ZERO WORDS
BNE 42$ ; (1, 2, OR 4)
LDD (SP)+,F0 ; GET ALL 4 INTO F0
CFCC ; CHECK SIGN
BPL 45$ ; OK IF POSITIVE
JSR PC,MINUS ; OUTPUT - SIGN IF -VE
ABSD F0 ; AND CONTINUE WITH ABSOLUTE VALUE
45$:
.IF DF R$$INF ; IF RECOGNISING INFINITY
CMPD O.DINF,F0 ; COMPARE WITH D.P. INFINITY
.IFTF
MOV #16.,%2 ; LOAD THE NUMBER OF DIGITS
CMPB O.FFM,#3 ; ASSUMED D.P., BUT WAS IT?
BEQ 50$ ; YES, BRANCH
ASR %2 ; NO, HALVE NO OF DIGITS
.IFT
CMPD O.SINF,F0 ; RECOMPARE WITH S.P. INFINITY
50$: CFCC ; IS IT INFINITY?
BEQ O.TYPI ; YES, PRINT 'infinity'
.IFF
50$: ; REF LABEL
.ENDC
JSR PC,TYPFLO ; TYPE FLOATING NO
; FLOATING OPEN DONE, TELL ODT THAT NOTHING HAPPENED TO CONCERN
; IT, AND RETURN FOR A NEW COMMAND.
O.FODN: JSR PC,O.SPCE ; FINISH WITH A SPACE
O.FOD1: CLR %2 ; SAY NOTHING TYPED
TST (SP)+ ; IGNORE RETURN ADDRESS
JMP O.NEWC ; GO FOR NEW COMMAND
; TYPE MESSAGE "Undefined" OR "Infinity".
.IIF DF R$$INF,O.TYPI: MOV #O.FINF,%1 ; ADDRESS "Infinity"
O.TEXT: MOVB (%1)+,%0 ; GET NEXT CHAR
BEQ O.FODN ; DONE IF NULL
JSR PC,O.FTYP ; ELSE TYPE IT
BR O.TEXT ; AND GET ANOTHER
; SUBROUTINES.
; SET %5 TO POINT TO ADDRESS OF CURRENTLY-OPEN CELL, GIVEN BY
; ODT IN LOCATION O.CAD, NOTING THE SPECIAL CASES:-
; O.UR0 TO O.UR5 MUST BE MAPPED TO F.P. EQVTS,
; O.UF0 TO O.UF5 (GIVEN BY $0-$5),
; O.DSW MAPS TO O.FEC/O.FEA (GIVEN BY $W),
; O.UST MAPS TO O.FPS (GIVEN BY $S).
;
; SET FLAGS TO INDICATE:
; CARRY SET LOCATION IS FPS,
; V SET LOCATION IS FEC/FEA.
O.FCAD: MOV O.CAD,%5 ; GET CURRENT ADDRESS
BIT #1,%5 ; IS IT ODD?
BNE O.FERR ; ERROR IF SO
CLRB O.FBW ; CLEAR FORCE MODE BYTE
CMP %5,#O.DSW ; $W?
BHI 30$ ; NORMAL ADDRESS IF HIGHER
BNE 10$ ; TRY AGAIN IF NOT $W
MOV #O.FEC,%5 ; IT WAS, MAP ONTO FEC
MOVB #2,O.FBW ; FORCE 2-WORD ADVANCE
SEV ; FLAG $W BY SETTING V
RTS PC ; ON EXIT
10$: CMP %5,#O.UST ; $S?
BNE 20$ ; NO, TRY REGISTERS
MOV #O.FPS,%5 ; YES, MAP TO FPS
MOVB #2,O.FBW ; FORCE WORD MODE AGAIN
SEC ; FLAG $S BY SETTING CARRY
RTS PC ; ON EXIT
20$: CMP %5,#O.UR5 ; USER %5?
BHI 30$ ; HIGHER MEANS NORMAL ADDRESS
CMP %5,#O.UR0 ; AS DOES LOWER THAN USER %0
BLO 30$
SUB #O.UR0,%5 ; USER REGISTER, FIND WHICH
ASL %5 ; WORD OFFSET FROM U.UR0
ASL %5 ; *4 IS OFFSET FROM U.UF0
SUB #O.UF0,%5 ; ADDRESS REQD IS #U.UF0-OFFSET
NEG %5 ; = -(OFFSET-U.UF0)
MOVB #2,O.FBW ; 2-BYTES TO NEIGHBOURS
30$: .WORD CLC!CLV ; CLEAR CARRY & V FOR GENERAL CASES
RTS PC ; AND RETURN
; UPDATE O.BW AND O.OBW BY THE NUMBER OF BYTES CORRESPONDING TO
; THE CURRENTLY-OPEN FLOATING MODE, UNLESS FORCING TO SOME
; SPECIAL VALUE, GIVEN BY O.FBW<>0 = NUMBER REQD.
O.UPBW: MOVB O.FBW,%4 ; SPECIAL BYTE UPDATE?
BNE 10$ ; YES, BRANCH
MOVB O.FFM,%4 ; NO, GET OPEN MODE
MOVB FLOSIZ(%4),%4 ; AND SO NO OF BYTES
10$: MOVB %4,O.OBW ; YES, ADJUST O.OBW
MOV %4,O.BW ; AND ITS WORD COUNTERPART
RTS PC ; AND RETURN
; GET A FLOATING-POINT NUMBER FROM THE TERMINAL TO F0, AND
; WITH TERMINATOR (CR, LF, OR '^') IN %0. %2 GIVES THE
; NUMBER OF CHARACTERS TYPED (LESS TERMINATOR). IF AN EXPONENT
; SYMBOL ('/', 'E', OR 'D') IS GIVEN, O.FFM IS SET TO 1, 2, OR 3,
; RESPECTIVELY.
;
; DEVELOPED FROM DECUS 11-113, SUBROUTINE FREAD.
GETFLO: CLR %3 ; EXPONENT COUNTER
MOV #-1,%2 ; DIGITS COUNTER LESS TERMINATOR
CLR -(SP) ; CLEAR SIGN FLAG
CLR -(SP) ; CLEAR SWITCH (SET BY E OR.)
CLR -(SP) ; SET BY E IN INPUT STRING
CLR -(SP) ; EXPONENT SIGN
; FLAGS ARE ON STACK:
EXPSGN=0 ; TOP OF STACK
SWE=2 ; 2ND WORD
SWITCH=4 ; 3RD WORD
SIGN=6 ; 4TH WORD
CLRD F0 ; CLEAR F0
LDD #^F1,F2 ; SET F2 TO 1
JSR PC,GET ; FETCH FIRST CHARACTER
L0: CMPB %0,#'+ ; + SIGN?
BEQ L1 ; YES, IGNORE IT
CMPB %0,#'- ; MINUS SIGN?
BNE L1A ; BRANCH IF NOT
INC SIGN(SP) ; ELSE SET SIGN FLAG
L1: JSR PC,GET ; GET NEXT CHARACTER
L1A:
.IF DF R$$INF ; IF RECOGNISING INFINITY
CMPB %0,#'? ; '?' ?
BNE L1B ; NO, NOT INFINITY
LDD O.DINF,F0 ; YES, LOAD INFINITY
JSR PC,GET ; NEXT CHAR IS TERMINATOR
BR FINB ; DONE
.ENDC
L1B: CMPB #'E,%0 ; LOOK FOR AN 'E'
BEQ EE2 ; SINGLE-PRECISION MODE
CMPB #'/,%0 ; '/' IS ALSO EXPONENT SYMBOL
BEQ EE1 ; 1-WORD MODE
CMPB #'D,%0 ; SO IS 'D'
BEQ EE3 ; DOUBLE-PRECISION
CMPB #'.,%0 ; LOOK FOR A DECIMAL POINT
BEQ DP
CMPB #'-,%0 ; LOOK FOR A MINUS
BEQ MINA
CMPB #'+,%0 ; LOOK FOR A PLUS
BEQ L1 ; IGNORE IT
CMPB %0,#'0 ; LESS THAN '0'
BLT FINB ; IS A TERMINATOR
CMPB %0,#'9 ; AS IS >'9'
BGT FINB ; BRANCH IF TERMINATOR
BIC #177760,%0 ; SET RANGE 0-9
TST SWITCH(SP)
BNE SVAL ; BRANCH IF SWITCH IS SET
LDCID %0,F1 ; MUST BE A NUMBER, PUT IN F1
MULD #^F10,F0 ; MULTIPLY F0 BY 10
ADDD F1,F0 ; AND ADD C(F1)
BR L1 ; CONTINUE
FINB: CMPB %0,#CR ; MAKE SURE TERMINATOR
BEQ FINC ; IS A LEGAL ONE
CMPB %0,#LF
BEQ FINC
CMPB %0,#'^
BNE ERRF ; FATAL ERROR IF NOT
FINC: DIVD F2,F0 ; SCALE VALUE
TST SWE(SP) ; IS E SWITCH SET?
BNE EXP ; SET EXPONENT IF SET
L4: TST SIGN(SP) ; CHECK SIGN OF NUMBER
BEQ L3
NEGD F0
L3: ADD #10,SP ; PURGE STACK
RTS PC ; EXIT
DP: TST SWITCH(SP) ; HAVE E OR . ALREADY?
BNE FINB ; ANOTHER . IS TERMINATOR
INC SWITCH(SP) ; SET SWITCH NE 0
BR L1
EE1: MOV #1,%0 ; RECORD 1-WORD MODE
BR EE
EE2: MOV #2,%0 ; SINGLE-PRECISION MODE
BR EE
EE3: MOV #3,%0 ; OR DOUBLE-PRECISION
EE: MOVB %0,O.FFM ; SET UP MODE
INC SWITCH(SP)
INC SWE(SP) ; INCREMENT E SWITCH
BR L1
MINA: TST SWE(SP) ; ANOTHER '-', IS E SWITCH SET?
BEQ ERRF ; ERROR IF NOT
INC (SP) ; INDICATE SIGN TO BE NEGATIVE
BR L1
SVAL: TST SWE(SP) ; CHECK SWITCHES
BNE SE ; BRANCH IF E SWITCH IS SET
LDCID %0,F1 ; HANDLE NUMBER NORMALLY
MULD #^F10,F2 ; BUT KEEP TRACK OF FRACTION IN F2
MULD #^F10,F0
ADDD F1,F0
BR L1
SE: MOV %3,-(SP) ; ADD DIGIT TO EXPONENT.
ASL %3 ; MULTIPLY %3 BY 10
ASL %3 ; BY THE SHIFT-AND-ADD METHOD
ADD (SP)+,%3 ; TO AVOID AN EIS INSTRUCTION
ASL %3
ADD %0,%3 ; THEN ADD NEXT DIGIT
BR L1
EXP: TST %3 ; SEE IF EXPONENT IS ZERO
BEQ L4 ; SKIP NEXT PART IF IT IS
TST (SP) ; CHECK SIGN OF E PART
BEQ L6
FL1: DIVD #^F10,F0 ; DIVIDE BY TEN
DEC %3
BNE FL1
BR L4
L6: MULD #^F10,F0 ; MULTIPLY BY TEN
CFCC ; CHECK FOR OVERFLOW
BVS ERRF ; WHICH IS ERROR
DEC %3
BNE L6
BR L4
; GET CHARACTER, COUNTING THEM IN %2.
GET: INC %2 ; INCREMENT DIGITS COUNT
JMP O.GET ; GET CHARACTER
ERRF: JMP O.FERR ; JUMP ON ERROR
; TYPE THE FLOATING-POINT VALUE IN F0 IN EXPONENT FORMAT, WITH A
; MAXIMUM NUMBER OF DIGITS GIVEN BY THE ENTRY VALUE OF %2.
; SIGN IS PRINTED SEPARATELY -- F0 MUST BE POSITIVE.
TYPFLO: MOV #"0.,%0 ; LOAD "0."
JSR PC,O.TYPE ; TYPE 2 CHARS
CLR %3 ; CLEAR EXPONENT COUNTER
ABSD F0 ; TAKE ABSOLUTE VALUE ONLY
CFCC ; ZERO?
BEQ 40$ ; NO SCALING IF 0.0
; SCALE NUMBER TO LIE BETWEEN 0.1 AND 0.999...
CMPF #^F1.0,F0 ; >1.0?
CFCC
BGT 30$ ; NO, BRANCH
; NUMBER IS >=1.0, DIVIDE BY 10.0 UNTIL IT IS LESS
20$: DIVD #^F10.0,F0 ; DIVIDE BY 10.0
INC %3 ; NOTE IN EXPONENT
CMPD #^F1.0,F0 ; IN RANGE NOW?
CFCC
BLE 20$ ; NO, TRY AGAIN
BR 40$ ; YES, GO PRINT
; NUMBER IS <1.0, GET IT INTO RANGE 0.1 TO 0.999...
30$: CMPD TENTH,F0 ; C.F. 1/10
CFCC
BLE 40$ ; BRANCH IF IN RANGE
MULD #^F10.0,F0 ; ELSE SCALE UP
DEC %3 ; COUNT IN EXPONENT
BR 30$ ; AND SCALE AGAIN
; NUMBER IS IN RANGE, PRINT %2 DIGITS
40$: MODD #^F10.0,F0 ; GET DIGIT TO F1
STCDI F1,%0 ; FETCH INTEGER PART
JSR PC,DIGIT ; TYPE AS ASCII DIGIT
TSTD F0 ; TEST REMAINDER
CFCC ; ONLY TRAILING ZEROES LEFT?
BEQ 45$ ; YES, TYPE EXPONENT
DEC %2 ; NO, CONTINUE COUNTING DIGITS
BNE 40$
; NOW PRINT EXPONENT IN %3
45$: MOVB O.FFM,%0 ; GET F.P. MODE
MOVB FLOCHR(%0),%0 ; AND THUS EXPONENT SYMBOL
JSR PC,O.FTYP ; TYPE IT
TST %3 ; IS EXPONENT NEGATIVE?
BPL 50$ ; NO, BRANCH
JSR PC,MINUS ; YES, PRINT - SIGN
NEG %3 ; AND MAKE EXPONENT +VE
; TYPE EXPONENT AS 1 OR 2 DECIMAL DIGITS
50$: CLR %0 ; CLEAR TENS
52$: CMP %3,#10. ; ANY TENS LEFT?
BLT 55$ ; NO, GO PRINT
SUB #10.,%3 ; YES, TAKE OUT A 10
INC %0 ; REMEMBERING IT
BR 52$ ; AND TEST AGAIN
55$: TST %0 ; ANY TENS?
BEQ 57$ ; NO, SUPPRESS LEADING 0
JSR PC,DIGIT ; YES, TYPE TENS DIGIT
57$: MOV %3,%0 ; LOAD UNITS DIGIT
DIGIT: ADD #'0,%0 ; CONVERT TO AN ASCII DIGIT
JSR PC,O.FTYP ; TYPE DIGIT
RTS PC ; AND EXIT
MINUS: MOVB #'-,%0 ; LOAD '-' SIGN
JMP O.FTYP ; TYPE IT AND RETURN
O.SPCE: MOVB #' ,%0 ; LOAD SPACE
JMP O.FTYP ; TYPE IT AND RETURN
; EXTRA CODE EXECUTED BY O.SVR ON ENTRY TO ODT TO SAVE F.P.
; REGISTERS ETC.
O.SVF: MOV #O.FEA+2,SP ; USE SP TO ADDRESS F.P. REGS
STST -(SP) ; SAVE FEC/FEA
STFPS -(SP) ; SAVE F.P. STATUS
LDFPS #40200 ; SET FPU MODE=D.P., NO INTERRUPTS
STD F0,-(SP) ; SAVE USER'S F.P. REGS
STD F1,-(SP)
STD F2,-(SP)
STD F3,-(SP)
LDD F4,F0 ; COPY F4
STD F0,-(SP) ; TO SAVE IT
LDD F5,F0 ; AND F5 SIMILARLY
STD F0,-(SP) ; SINCE CAN'T PUSH THEM DIRECTLY
MOV #O.USP,SP ; LOAD CPU REGISTER SAVE AREA PTR
JMP O.SVRR ; FOR USE BY O.SVR
; EXTRA CODE CALLED FROM O.RSR TO RESTORE F.P. REGISTERS ETC. ON
; EXIT FROM ODT.
O.RSF: JSR PC,O.DET ; DETACH TERMINAL
MOV #O.UF5,%0 ; ADDRESS FLOATING SAVE AREA
LDD (%0)+,F0 ; GET F5
STD F0,F5 ; THE ROUND-ABOUT WAY
LDD (%0)+,F0 ; AND F4
STD F0,F4 ; THE SAME WAY
LDD (%0)+,F3 ; PICK UP THE REST DIRECTLY
LDD (%0)+,F2
LDD (%0)+,F1
LDD (%0)+,F0
LDFPS @%0 ; FINALLY FPS (CAN'T DO FEA/FEC)
RTS PC ; BACK TO O.RSR
.PAGE
.SBTTL VT2XX FUNCTION KEY RECOGNITION
O.V200: JSR PC,DOAQIO ; Read a char }
TSTB IOSTAT ; All OK? } replaced
BPL 1$ ; If PL yes }
JMP O.EXIT ; Assume EOF and get out } instructions
1$: MOVB CHRBUF,R0 ; Fetch character }
CMPB R0,#CSI ; Escape sequence introducer?
BEQ 5$ ; Yes, expect '2'
CMPB R0,#ESC ; Escape?
BNE 15$ ; No, handle it normally, whatever it is
JSR PC,DOAQIO ; Yes, get next char
BIC #177600,CHRBUF ; Strip parity bit
CMPB CHRBUF,#'[ ; Is it '['?
BEQ 5$ ; Yes, esc [ is same as CSI
SWAB CHRBUF ; Else save char for next time
BR 20$ ; Return with ESC this time
5$: JSR PC,DOAQIO ; Get next char
BICB #200,CHRBUF ; Strip parity bit
CMPB CHRBUF,#'2 ; Should be '2'
BNE 10$ ; Error if it isn't
INC DPBCNT ; 2 bytes to finish up
JSR PC,DOAQIO ; Get the important digit
DEC DPBCNT ; All other QIOs do 1 byte at a time
BIC #100200,CHRBUF ; Strip parity bits
CMP CHRBUF,#"3~ ; Did we get 3~?
BEQ 15$ ; Yes, let O.GET change 233 to 33
MOV #LF,R0 ; No, try for an LF
CMP CHRBUF,#"5~ ; Given by 5~
BEQ 15$ ; Exit if so
10$: MOVB #'U&37,R0 ; Anything else becomes control/U
15$: CLRB CHRBUF+1 ; Nothing saved
20$: RTS PC ; Exit with char or substitute
.PAGE
.SBTTL DATA AREA
.IF DF O$$DID
.PSECT $ODTDT,RW,D
.=$$$ODT+1020
.ENDC
O.FUND: .ASCIZ "Undefined"
.IIF DF R$$INF,O.FINF: .ASCIZ "Infinity"
FLOCHR: .BYTE '\, '/, 'E, 'D ; (END OF TABLE MARKED BY FLOSIZ'S 0)
FLOSIZ: .BYTE 0, 2, 4, 8.
O.FFM: .BYTE 2 ; FLOATING PRECISION, DEFAULT SINGLE
O.FBW: .BYTE 0 ; FORCE O.BW IN SPECIAL CASES
.EVEN
.IF DF R$$INF
O.DINF: .WORD 077777,177777,177777,177777 ; D.P. INFINITY
O.SINF: .WORD 077777,177777,000000,000000 ; S.P. INFINITY
.ENDC
TENTH: .FLT4 0.1 ; 0.1, FOR USE BY TYPFLO
FECOND: .WORD "OK,"OP,"DZ,"IC,"OF,"UF,"UV,"MT ; EXCEPTION NMEMONICS
; USER F.P. REGISTERS AND STATUS -- ORDER IS IMPORTANT!
O.UF5: .BLKW 4 ; USER F5
O.UF4: .BLKW 4 ; USER F4
O.UF3: .BLKW 4 ; USER F3
O.UF2: .BLKW 4 ; USER F2
O.UF1: .BLKW 4 ; USER F1
O.UF0: .BLKW 4 ; USER F0
O.FPS: .WORD 0 ; FLOATING POINT STATUS
O.FEC: .WORD 0 ; FLOATING EXCEPTION CODE
O.FEA: .WORD 0 ; FLOATING EXCEPTION ADDRESS
.=$$$ODT
.END