.TITLE FPODT .IDENT /1001/ .MCALL QIOW$S,DIR$,QIO$,WTSE$ ;************************************************* ;** ** ;** FORTRAN IV PLUS ON-LINE DEBUGGER ** ;** ** ;** FOR RSX-11D AND RSX-11M ** ;** ** ;************************************************* ;THIS OBJECT MODULE CAN BE LINKED INTO A FORTRAN ; PROGRAM BY THE TASK BUILDER TO ALLOW DEBUGGING ; FORTRAN WITH MANY OF THE SAME FEATURES THAT ; ODT PROVIDES FOR DEBUGGING MACRO PROGRAMS. ; ; PROGRAMERS: JERRY CONNERS/WARREN FRIEDLAND ; .GLOBL RCI$,LCI$,ICI$,SST,$DSW,$OTSV .GLOBL ENF$,EOLST$,IOVR$,IOVI$,STOP$ W.NAM=2 IOLUN= 5 ;DEFAULT LUN TO USE FOR FODT I/O IOEFN= 30. ;EVENT FLAG TO USE FOR I/O ;THIS MACRO PROVIDES A SIMPLE METHOD OF PRINTING ; FIXED MESSAGES ON THE USER TERMINAL. .MACRO .PRINT TEXT,?LBL1,?LBL2 JSR R5,PRINT .WORD LBL2-LBL1 LBL1: .ASCII TEXT LBL2: .EVEN .ENDM .PRINT ; ; ; DEBUG INITIALIZATION ROUTINES ; REDIRECT TRAP VECTORS AND HANDLE USER'S TRAPS .PSECT FPODT:: MOV $SST+14,SST ;SAV OTS TRAP ADDR MOV #INTECP,$SST+14 ;PUT NEW ADDR IN SST TABLE RTS PC ;RETURN SST: .WORD 0 ;OTS TRAP ADDRESS BASE: .WORD 0 ;BASE ADDR FOR VARIBLE DISPLAY ; ;THIS ROUTINE SETS UP THE ERROR TRACEBACK INFORMATION ; UPON ENTRY INTO A FORTRAN SUBROUTINE. IT REPLACES ; THE FORTRAN IV OTS ROUTINE BY THE SAME NAME. INTECP: CMP #128.*2,@SP ;LOW BYTE *2 OF TRAP INSTUCTION ;FROM EXEC BHI 1$ ;USER CODE JMP @SST ;GOTO OTS ; START USER CODE 1$: ADD #2,SP ;LOOK AT NEXT WORD MOV (SP),TEMP ; MOV CONTENTS OF SP TO WORD TEMP TST @TEMP ; IS TEMP LESS THAN ZERO ? BLE 3$ ; YES MOV @TEMP,@$OTSV ; NO, IT IS A MOV INSTRUCTION BR 4$ ; BRANCH 3$: INC @$OTSV ; INCREMENT SEQUENCE NUMBER 4$: ADD #2,(SP) ; GO TO NEXT INSTRUCTION ; LET PROPRAM FALL THROW TO FODT ; ;THIS IS THE START OF THE "FODT" CODE. ; FODT: MOV R0,-(SP) ;SAVE REGISTERS MOV R1,-(SP) MOV R2,-(SP) MOV R3,-(SP) MOV R4,-(SP) MOV R5,-(SP) ADD MODE,PC ;DISPATCH TO ROUTINE BR INIT ;M=0, FIRST TIME ENTERED BR CKSTEP ;M=2, CHECK FOR "STEP" STOP BR CKBRK ;M=4, CHECK FOR "BREAKPT" STOP ;WE COME HERE THE FIRST TIME "FODT" IS ENTERED TO ; IDENTIFY OURSELVES TO THE USER. THIS WILL ; HAPPEN BEFORE THE FIRST FORTRAN STATEMENT IS ; EXECUTED BUT AFTER THE "$NAM" ROUTINE AND ; THE CALL DEBUG STATEMENT HAS INITIALIZED ; THE FORTRAN WORK AREA AND I/O. ; INIT: DIR$ #TTOUT ;PRINT THE IDENT STRING DIR$ #IOWAIT ;WAIT FOR IT BR IDENT ;GO SHOW MAIN LINE NO. ;WE COME HERE WHEN WE ARE LOOKING FOR A BREAKPOINT. ; AS EACH FORTRAN STATEMENT IS EXECUTED, WE CHECK ; THE SEQUENCE NUMBER AND ROUTINE NAME TO SEE IF ; IT HAS BEEN SPECIFIED AS A BREAKPOINT. IF IT ; HAS NOT, WE SIMPLY RESUME. ;THE WORK AREA POINTER TO THE CURRENT ROUTINE ; NAME (RAD50) WILL BE ZERO IF WE ARE IN THE ; MAIN PROGRAM. ; CKBRK: CMP @$OTSV,BSEQ ;IS IT THE RIGHT SEQ #? BNE RESUME ;NO, JUST CONTINUE MOV $OTSV,R3 ;YES, GET WORK AREA PTR MOV W.NAM(R3),R2 ;GET NAME POINTER BNE 40$ ;BRANCH IF NOT IN MAIN TST BNAM1 ;IN MAIN, IS BKPT IN MAIN? BNE RESUME ;NO, NOT A MATCH BR 100$ ;YES, BREAK HERE 40$: ADD #4,R2 CMP (R2)+,BNAM1 ;DOES 1ST HALF MATCH? BNE RESUME ;NO, GO ON CMP @R2,BNAM2 ;YES, DOES 2ND HALF MATCH? BNE RESUME ;NO, NOT BREAK POINT 100$: DEC REPCNT ;SHALL WE BREAK NOW? BNE RESUME ;NO, MAYBE NEXT TIME BR IDENT ;YES, GO TELL WHERE WE ARE ;WE COME HERE WHEN WE ARE STEPPING THROUGH THE CODE ; ONE (OR SEVERAL) STATEMENT AT A TIME. WE SIMPLY ; CHECK TO SEE IF THE STEP COUNT GOES TO ZERO AND ; IF SO WE STOP AND PRINT THE LOCATION. ; CKSTEP: DEC REPCNT ;MORE STEP BEFORE STOP? BNE RESUME ;YES, JUST COUNT DOWN ;WE COME HERE TO PRINT OUT THE NAME OF THE ROUTINE ; AND THE SEQUENCE NUMBER OF THE STATEMENT WE ; HAVE STOPPED AT. WE HAVE TO CONVERT THE RAD50 ; ROUTINE NAME TO ASCII AND ALSO ENCODE THE ; SEQUENCE NUMBER IN ASCII. ; IDENT: MOV #ABUF,R5 ;POINT TO ASCII BUFFER MOV #5015,(R5)+ ;INSERT CR, LF MOVB #'(,(R5)+ ;INSERT LEFT PAREN JSR PC,NAME ;ENCODE ROUTINE NAME MOV @$OTSV,R0 ;GET SEQUENCE # JSR R5,DECNUM ;ENCODE # IN ASCII .WORD 4 ; 4 DECIMAL DIGITS MOVB #'),(R5)+ ;ADD RIGHT PAREN JSR PC,PRINTB ;PRINT THE BUFFER ;FALL THRU TO PROMPT ;WE COME HERE TO INDICATE THAT WE ARE READY FOR ; A NEW COMMAND. WE SIMPLY PRINT THE PROMPT ; AND INITIALIZE THE ARGUMENTS. ; PROMPT: .PRINT <<15><12><137>> ;CR, LF, PROMPT MOV #ARG3+2,R0 ;POINT PAST ARG3 CLR -(R0) ;ZERO ARG3 CLR -(R0) ;ZERO ARG2 CLR -(R0) ;ZERO ARG1 MOV R0,ARGPTR ;FILL ARG1 FIRST BIC #FL.OCT,FLAGS ;DEFAULT TO DECIMAL ARGS ;FALL THRU TO INWAIT ;WE COME HERE TO WAIT FOR THE USER TO TYPE A ; CHARACTER ON THE TERMINAL. INPUT IS PROCESSED ; ONE CHARACTER AT A TIME. IF THE CHARACTER ; IS VALID, WE DISPATCH TO THE PROPER PRO- ; CESSING ROUTINE THRU "COMTBL". ; INWAIT: DIR$ #TTIN ;WAIT FOR CHAR DIR$ #IOWAIT ;WAIT FOR IT TST IOCNT ;DID HE TYPE TERMINATOR? BEQ PROMPT ;YES, JUST RE-PROMPT MOV INBUF,R0 ;NO, GET CHAR CODE BIC #177600,R0 ;MASK 7-BIT ASCII CMP R0,#140 ;IS IT LOWER CASE ASCII? BLT 20$ ;NO, IT'S OK SUB #40,R0 ;YES, CONVERT TO UPPER CASE 20$: MOV R0,R1 ;SAVE A COPY CMP R0,#12 ;IS IT A LINE FEED? BNE 40$ ;NO, GO CHECK IT JMP NXTVAR ;YES, OPEN NEXT VARIABLE 40$: SUB #40,R0 ;IS IT A PRINTING CHAR? BMI BAD ;NO, DON'T ACCEPT IT CMP R0,#77 ;IS IT IN RANGE? BGT BAD ;NO, BAD COMMAND ASL R0 ;YES, GET WORD INDEX JMP @COMTBL(R0) ;DISPATCH TO ROUTINE ;WE COME HERE TO LEAVE THE DEBUGGER AND RE-ENTER ; THE FORTRAN THREADED CODE. ; RESUME: MOV (SP)+,R5 ;RESTORE REGISTERS MOV (SP)+,R4 MOV (SP)+,R3 MOV (SP)+,R2 MOV (SP)+,R1 MOV (SP)+,R0 GOBACK: RTT ;RE-ENTERFORTRAN ;WE COME HERE IF THE USER TYPES ANYTHING THAT IS ; ILLEGAL OR UNRECOGNIZABLE. ; BAD: .PRINT ;SHOW PUZZLEMENT BR PROMPT ;GO TRY AGAIN ;WE COME HERE WHEN THE USER TYPES A DIGIT. WE ; ENTER AT "OCDIG" FOR VALID OCTAL DIGITS (0-7) ; AND AT "DECDIG" FOR 8 AND 9. THUS WE CAN ; CHECK FOR INVALID DIGITS IN OCTAL MODE. ;WE MULTIPLY THE OLD VALUE OF ARG BY 8 OR 10 ; DEPENDING ON THE CURRENT RADIX MODE, AND ; ADD THE NEW DIGIT TO IT. ; DECDIG: BIT #FL.OCT,FLAGS ;EXPECTING OCTAL? BNE BAD ;YES, REJECT 8 OR 9 OCDIG: SUB #60,R1 ;CONVERT ASCII TO BINARY MOV @ARGPTR,R3 ;GET CURRENT ARG BIT #FL.OCT,FLAGS ;ARE WE IN OCTAL MODE? BNE 80$ ;YES, MULT BY 8 MUL #10.,R3 ;NO, MULT BY 10 BR 100$ ;SKIP OCTAL 80$: ASH #3,R3 ;FAST MULT BY 8 100$: ADD R1,R3 ;ADD IN NEW DIGIT MOV R3,@ARGPTR ;STORE NEW VALUE BR INWAIT ;GO WAIT FOR MORE ;WE COME HERE WHEN THE USER TYPES AN ARGUMENT ; SEPARATOR (; OR ,). WE PREPARE TO ACCEPT ; A NEW ARGUMENT BY BUMPING THE POINTER TO ; POINT TO THE NEXT ONE AND RESET THE "FL.OCT" ; FLAG SO THE FOLLOWING INPUT WILL DEFAULT ; TO DECIMAL. ; NXTARG: BIC #FL.OCT,FLAGS ;DEFAULT TO DECIMAL ADD #2,ARGPTR ;POINT TO NEXT ARG CMP ARGPTR,#ARG3 ;DO WE HAVE 3 ALREADY? BHI BAD ;YES, TELL HIM NO GO BR INWAIT ;NO, GO WAIT FOR MORE ;WE COME HERE WHEN HE TYPES "S" TO STEP THRU ; HIS PROGRAM. WE SET THE MODE TO REMEMBER ; THAT WE ARE STEPPING AND SET THE REPETITION ; COUNT FROM ARG1. ; STEP: MOV #2,MODE ;STEP THRU STATEMENTS BR REP ;GO SHARE CODE ;WE COME HERE TO PROCEED FROM THE CURRENT STOP. ; IT'S JUST LIKE "STEP" ABOVE EXCEPT THAT THE ; MODE IS DIFFERENT. ; PROCED: MOV #4,MODE ;LOOKING FOR BREAKPOINT REP: MOV ARG1,REPCNT ;SET REPETITION COUNTER BNE 40$ ;OK IF NON-ZERO INC REPCNT ;IF ZERO, USE 1 40$: BR RESUME ;BACK TO FORTRAN ;WE COME HERE WHEN THE USER TYPES IN A V ;TO CHANCE THE VARIABLE BASE ADDRESS ; VARBAS: MOV ARG1,BASE ;ENTER VARIABLE BASE JMP PROMPT ; ;WE COME HERE WHEN THE USER TYPES THE "B" COMMAND ; TO SET OR REMOVE A BREAKPOINT. ARG1 IS USED ; AS THE SEQUENCE NUMBER OF THE STATEMENT TO ; BE TRAPPED. IF ARG1 IS ZERO, WE ASSUME HE ; WANTS TO REMOVE THE BREAKPOINT. ;IF ARG1 IS NONZERO, WE USE IT AND ASK HIM FOR ; THE NAME OF THE ROUTINE IN WHICH THIS BREAK- ; POINT IS TO BE SET. WE HAVE NO WAY TO CHECK ; THAT THE NAME IS THAT OF A VALID ROUTINE, SO ; HE HAD BETTER TYPE IT CORRECTLY OR THE ; PROGRAM WILL NEVER HIT THE BREAKPOINT. ; BRKPT: MOV ARG1,BSEQ ;GET BKPT SEQ # BEQ PROMPT ;IF ZERO, IT'S REMOVED CMP BSEQ,#9999. ;IS # REASONABLE? BHI BAD ;NO, REJECT IT GETNAM: .PRINT DIR$ #NAMIN ;ASK FOR ROUTINE NAME DIR$ #IOWAIT ;WAIT FOR IT MOV IOCNT,R0 ;GET INPUT COUNT BNE 80$ ;BRANCH IF NOT NULL CLR BNAM1 ;NULL MEANS THE BREAK- BR PRMT1 ; POINT IS IN "MAIN" 80$: CMPB ABUF,#'- ;IS IT A DASH? BEQ PRMT1 ;YES, USE PREVIOUS ROUTINE ADD #ABUF,R0 ;POINT PAST STRING 100$: CLRB (R0)+ ;CLEAR UNFILLED BYTE CMP R0,#ABUF+6 ;ARE WE PAST NAME? BLOS 100$ ;NO, CLEAR ANOTHER BYTE MOV #ABUF,R2 ;POINT TO ASCII NAME MOV #BNAM1,R3 ;POINT TO RAD50 BUFFER RTOA: MOV #2,R0 ;INIT WORD COUNT 20$: MOV #3,R1 ;INIT CHAR/WD COUNT CLR R5 ;INIT RAD50 WORD 30$: MOVB (R2)+,R4 ;GET NEXT ASCII CHAR BEQ 120$ ;NULL BECOMES NULL BIC #177600,R4 ;MASK 7-BIT ASCII CMP R4,#140 ;IS IT LOWER CASE ASCII? BLT 35$ ;NO, IT'S OK SUB #40,R4 ;YES, CONVERT TO LOWER CASE 35$: SUB #100,R4 ;IS IT A LETTER? BGT 100$ ;MAYBE, GO CHECK ADD #20,R4 ;NO, CHECK DIGITS BMI BADNAM ;TOO LOW FOR DIGIT CMP R4,#11 ;IS IT 60-71? BGT BADNAM ;NO, NOT RAD50 CHAR ADD #36,R4 ;YES, GET RAD50 CODE BR 120$ ;GO INSERT IT 100$: CMP R4,#32 ;IS IT ABOVE 132? BGT BADNAM ;YES, NOT RAD50 120$: MUL #50,R5 ;PREVIOUS X 50(8) ADD R4,R5 ;INSERT NEW CODE SOB R1,30$ ;3-CHAR LOOP MOV R5,(R3)+ ;DEPOSIT RAD50 WORD SOB R0,20$ ;2-WORD LOOP PRMT1: JMP PROMPT ;GET NEXT COMMAND BADNAM: .PRINT <<15><12>/INVALID NAME, TRY AGAIN./> BR GETNAM ;GO TRY AGAIN ;WE COME HERE WHEN THE USER TYPES THE "L" COMMAND ; TO CHANGE THE LUN ON WHICH "FODT" DOES I/O. ; LUNSET: MOVB ARG1,R0 ;GET NEW LUN # BLE 50$ ;BRANCH IF UNREASONABLE MOV TTOUT+Q.IOLU,R1 ;SAVE OLD LUN # MOV R0,TTOUT+Q.IOLU ;SET NEW OUTPUT LUN # .PRINT <<12>\FODT I/O TERMINAL\<15>> TST $DSW ;DID QIO SUCCEED? BMI 40$ ;NO, CHANGE BACK TSTB IOSTAT ;DID OUTPUT SUCCEED? BPL 60$ ;YES, FINISH CHANGING 40$: MOV R1,TTOUT+Q.IOLU ;NO, BACK TO OLD LUN # 50$: JMP BAD ;GO SHOW ERROR CONDITION 60$: MOV R0,TTIN+Q.IOLU ;FIX INPUT QIO MOV R0,NAMIN+Q.IOLU ;FIX NAME INPUT QIO BR PRMT1 ;GO PROMPT ON NEW LUN ;WE COME HERE WHEN THE USER TYPES "O" TO SIGNIFY ; THAT THE FOLLOWING ARGUMENT IS TO BE INTER- ; PRETED AS OCTAL DIGITS. WE SET A FLAG WHICH ; IS TESTED EACH TIME A DIGIT IS TYPED. ; OMODE: BIS #FL.OCT,FLAGS ;SET "OCTAL" FLAG JMP INWAIT ;GO GET MORE INPUT ;WE COME HERE WHEN THE USER INDICATES HE WANTS ; TO GET OUT OF THE TASK ALTOGETHER BY TYPING ; "X". ; EXIT: JMP STOP$ ;EXIT THROUGH FORTRAN ;WE COME HERE IF THE USER WANTS A REAL VARIABLE ; OPENED. WE USE A COMMON SUBROUTINE TO SETUP ; FOR REAL VARIABLES AND GET THE ACTUAL ADDRESS. ; REAL: JSR R5,VARADR ;SETUP "OPNXXX" PARAMS .WORD 4,RVAR BR OPEN ;WE COME HERE IF THE USER WANTS TO OPEN AN ; INTEGER VARIABLE. ; INTEGR: JSR R5,VARADR ;SETUP "OPNXXX" PARAMS .WORD 2,IVAR BR OPEN ;GO OPEN IT ;WE COME HERE IF HE WANTS TO HAVE AN INTEGER ; VARIABLE PRINTED IN OCTAL FORMAT. ; OCTAL: JSR R5,VARADR ;SETUP "OPNXXX" FOR OCTAL .WORD 2,OVAR BR OPEN ;GO PRINT OCTAL ;WE COME HERE IF HE TYPES "A" TO HAVE A 16-BIT ; WORD DISPLAYED AS TWO ASCII CHARACTERS. ; ASCII: JSR R5,VARADR ;SETUP "OPNXXX" FOR ASCII .WORD 2,AVAR BR OPEN ;GO DISPLAY ASCII ;WE COME HERE WHEN HE TYPES "F" TO HAVE AN I*4 ;VARIABLE PRINTED ; FOUR: JSR R5,VARADR ;SETUP "OPNXXX" FOR I*4 .WORD 4,FVAR BR OPEN ;GO DISPLAY I*4 ;WE COME HERE WHEN HE TYPES "Y" TO HAVE A BYTE ;VARIABLE DISPLAYED ; YBYTE: MOV #1,ODD ; SET ODD FLAG JSR R5,VARADR ;SETUP "OPNXXX" FOR A BYTE .WORD 1,YVAR .EVEN BR OPEN ;GO DISPLAY A BYTE ;WE COME HERE WHEN HE TYPES LINE FEED TO OPEN THE ; NEXT VARIABLE. WE ASSUME IT IS THE SAME TYPE ; AS THE LAST VARIABLE OPENED. ; NXTVAR: ADD OPNSIZ,OPNADR ;POINT TO NEXT VARIABLE INC OPNELM ;FIX ELEMENT NUMBER BR ELNUM ;GO PRINT ELMNT# + CONTENTS ;WE COME HERE WHEN HE TYPES UP ARROW (^) TO OPEN ; THE VARIABLE PRECEDING THE LAST ONE OPENED. ; LASVAR: SUB OPNSIZ,OPNADR ;BACK UP TO LAST VAR DEC OPNELM ;FIX ELEMENT NUMBER ;FALL THRU TO ELNUM ;THIS SUBROUTINE PRINTS THE ELEMENT NUMBER OF THE ; VARIABLE ABOUT TO BE PRINTED. ; ELNUM: MOV #ABUF,R5 ;POINT TO ASCII BUFFER MOVB #'(,(R5)+ ;INSERT LEFT PAREN MOV OPNELM,R0 ;GET ELEMENT NUMBER JSR R5,DECNUM ;ENCODE BINARY TO ASCII .WORD 5 ;ENCODE 5 DECIMAL DIGITS MOVB #'),(R5)+ ;ADD RIGHT PAREN JSR PC,PRINTB ;PRINT ELEMENT NUMBER ;FALL THROUGH TO OPEN ;THIS ROUTINE OPENS A VARIABLE AND DISPLAYS THE ; CONTENTS FOR THE USER. IT USES THE "OPNXXX" ; VARIABLES FOR ALL INFORMATION ABOUT THE ; VARIABLE. ;IF A SEGMENT FAULT TRAP IS CAUSED BY ACCESSING THE ; VARIABLE, WE WILL FIND OURSELVES AT "BADADR" ; BECAUSE THE SST WAS SETUP BY "INIT". ; OPEN: MOV OPNTYP,R0 ;GET PTR TO PARAM STRING BNE 20$ ;SKIP IF IT HAS BEEN SETUP JMP BAD ;NOT SET, GIVE ERROR ; ; 20$: MOV @0(R0),TTOUT+Q.IOPL+2 ;SET QIO LENGTH MOV OPNADR,ENCVAR ;SETUP VARIABLE ADDRESS MOV @(R0)+,-(SP) ;PUSH BYTE CNT ADDR MOV (R0)+,-(SP) ;PUSH FORMAT ADDR MOV (R0)+,ENCTV ;SET CORRECT CONVERSION MOV #ABUF,-(SP) ; PUSH ARAY ONTO STACK JSR PC,ENF$ ; ENCODE MOV ENCVAR,-(SP) ; PUSH ENCODED VARIABLE ONTO STACK JSR PC,@ENCTV ;I/O LIST JSR PC,EOLST$ ;END OF LIST JSR PC,PRINTC ;PRINT THE VARIABLE VALUE PRMT2: JMP PROMPT ;GO WAIT FOR MORE ENCVAR: 0 ;ADDR OF VAR TO ENCODE ENCTV: 0 ;GOTO CORRECT CONVERSION ROUTINE ;COME HERE IF THE ADDRESS OF THE VARIABLE TO BE ; OPENED IS OUTSIDE THE TASK LIMITS OR ODD. ; BADADR: .PRINT CLR OPNTYP ;ZERO OPEN INFO BR PRMT2 ;GO PROMPT FOR COMMAND ;THIS SUBROUTINE IS USED TO SETUP THE "OPNXXX" ; PARAMETERS DESCRIBING A VARIABLE TO BE OPENED. ;THE FORMAT OF THE CALL IS: ; JSR R5,VARADR ; .WORD (LENGTH OF VARIABLE IN BYTES) ; .WORD (ADDR OF PARAM LIST FOR VARIABLE TYPE) ; VARADR: MOV ARG2,R1 ;GET ELEMENT # BEQ 40$ ;OK IF ZERO DEC R1 ;ELSE ADJUST FOR ZERO ORIGIN 40$: MOV R1,OPNELM ;SAVE ARRAY ELEMENT NUMBER-1 INC OPNELM ;ADJUST FOR 1-ORIGIN INDEXING MOV @R5,OPNSIZ ;SAVE VAR SIZE MUL (R5)+,R1 ;GET OFFSET FROM ELMT 1 MOV (R5)+,OPNTYP ;SAVE PTR TO PARAM STRING MOV ARG1,R0 ;GET RELATIVE VAR ADDR TST ARG3 ;DID HE GIVE ABSOLUTE BASE? BEQ 50$ ;NO, USE CURRENT ROUTINE BASE ADD ARG3,R0 ;YES, ADD BASE TO OFFSET BR 60$ ;SKIP ROUTINE OFFSET 50$: ADD BASE,R0 ;MAKE IT ABS ADDR 60$: ADD R1,R0 ;ADD OFFSET TO ELEMENT CMP #1,ODD ;BYTE VARIABLE ? BNE 70$ ;NO MOV #0,ODD ;CLEAR ODD FLAG BR 80$ 70$: BIT #1,R0 ;IS THE ADDRESS ODD? BNE BADADR ;YES, GIVE ADDRESS ERROR 80$: MOV R0,OPNADR ;SAVE ABS ADDR OF ELMT RTS R5 ;ALL SET TO OPEN .NLIST BEX ;THESE ARE THE PARAMETERS NEEDED TO OPEN THE ; VARIOUS TYPES OF VARIABLES AND ENCODE THEM ; INTO A SUITABLE FORMAT FOR OUTPUT TO THE ; USER'S TERMINAL. ;***** REAL ***** RVAR: RSIZ ;ADDR OF REAL FIELD SIZE RFMT ;ADDR OF REAL FORMAT IOAR$ ;ADDR OF REAL CONVERSION ROUTINE RSIZ: .WORD 14. ;SIZE CONSTANT RFMT: .BYTE 50,16,7,12 ;COMPILED G14.7 FORMAT .EVEN ;***** INTEGER ***** IVAR: ISIZ ;ADDR OF INTEGER FIELD SIZE IFMT ;ADDR OF INTEGER FORMAT IOAI$ ;ADDR OF INTEGER CONV ROUTINE ISIZ: .WORD 10. ;SIZE CONSTANT IFMT: .BYTE 42,12,12,0 ;COMPILED I10 FORMAT .EVEN ;***** OCTAL ***** OVAR: OSIZ ;ADDRESS OF OCTAL FIELD SIZE OFMT ;ADDR OF OCTAL FORMAT IOAI$ ;ADDR OF INTEGER CONV ROUTINE OSIZ: .WORD 10. ;OCTAL FIELD SIZE OFMT: .BYTE 40,12,12,0 ;COMPILED O10 FORMAT .EVEN ;***** ASCII ***** AVAR: ASIZ ;ADDR OF ASCII FIELD SIZE AFMT ;ADDR OF ASCII FORMAT IOAI$ ;ADDR OF INTEGER CONV ROUTINE ASIZ: .WORD 6 ;ASCII FIELD SIZE AFMT: .BYTE 230,3,34,2,12,0 ; FORMAT(4X,A2) .EVEN ;**** I*4 **** FVAR: FSIZ ;ADDR OF I*4 FIELD SIZE FFMT ;ADDR OF I*4 COMPILED FORMAT IOAJ$ ;ADDR OF I*4 CONV ROUTINE FSIZ: .WORD 14. ;SIZE CONSTANT FFMT: .BYTE 42,16,12,0 ;COMPILED I14 FORMAT .EVEN ;**** BYTE **** YVAR: BSIZ ;ADDR OF BYTE FIELD SIZE BFMT ;ADDR OF BYTE COMPILED FORMAT IOAB$ ;ADDR OF BYTE CONV ROUTINE BSIZ: .WORD 6 ;SIZE CONSTANT BFMT: .BYTE 230,1,42,4,12,0 ;FORMAT (2,I4) .EVEN .LIST BEX ;THIS SUBROUTINE WILL CONVERT A NUMBER IN R0 TO ITS ; ASCII REPRESENTATION IN A BUFFER POINTED TO BY ; R5. THE NUMBER CAN BE CONVERTED TO A REPRESENTATION ; IN ANY RADIX FROM 1 TO 10. ;THREE DIFFERENT ENTRY POINTS ARE PROVIDED. ; THE "OCNUM" AND "DECNUM" ENTRY POINTS ARE PROVIDED ; FOR ENCODING NUMBERS INTO OCTAL AND DECIMAL ; RESPECTIVELY. THEY SET THE RADIX AUTOMATICALLY ; AND EXPECT TO BE CALLED WITH "JSR R5" AND HAVE ; THE WORD SPECIFYING THE NUMBER OF DIGITS IN ; THE WORD FOLLOWING THE JSR. ; ; JSR R5,OCNUM (OR DECNUM) ; .WORD 3 (OR 100003 FOR LEADING ZEROES) ; ;THE THIRD ENTRY POINT IS "ENCOD". IT IS A GENERAL ; PURPOSE ENTRY WHICH ALLOWS SETTING BOTH THE ; NUMBER OF DIGITS AND THE RADIX. THESE TWO ; PARAMETERS MUST BE PUSHED ON THE STACK AND ; THEN THE SUBROUTINE IS CALLED WITH "JSR PC". ; ; MOV #DIGITS,-(SP) ;PUSH # OF DIGITS ; MOV #RADIX,-(SP) ;PUSH RADIX ; JSR PC,ENCOD ; ;FOR ALL THREE ENTRY POINTS R0 MUST CONTAIN THE ; NUMBER TO BE ENCODED, AND R5 MUST POINT TO THE ; BUFFER WHERE THE ASCII STRING IS TO BE BUILT. ;ALL REGISTERS ARE UNCHANGED EXCEPT THAT UPON ; RETURN R5 WILL POINT TO THE NEXT BYTE AFTER ; THE ENCODED NUMBER STRING. ;LEADING ZEROES WILL BE SUPPRESSED IN THE ; ASCII REPRESENTAION UNLESS THE SIGN BIT ; OF THE WORD SPECIFYING THE NUMBER OF DIGITS ; IS A ONE. ; SUPPRESS LEADING ZEROES - 3 ; MAINTAIN LEADING ZEROES - 100003 ; OCNUM: MOV (R5)+,-(SP) ;GET # OF DIGITS MOV #8.,-(SP) ;PUSH THE RADIX BR DN40 ;GO SHARE CODE DECNUM: MOV (R5)+,-(SP) ;GET # OF DIGITS MOV #10.,-(SP) ;PUSH RADIX DN40: MOV 4(SP),-(SP) ;SAVE OLD R5 MOV R5,6(SP) ;SAVE PC RETURN ADDR MOV (SP)+,R5 ;GET OLD R5 BACK ENCOD: MOV R2,-(SP) ;SAVE R2 MOV 4(SP),R2 ;GET DIGIT COUNT IN R2 MOV R0,4(SP) ;SAVE R0 MOV R3,-(SP) ;SAVE R3 MOV 4(SP),R3 ;GET RADIX IN R3 MOV R1,4(SP) ;SAVE R1 MOV R4,-(SP) ;SAVE R4 MOV R2,R4 ;GET COPY OF DIGIT COUNT 20$: MOV R0,R1 ;GET DIVIDEND IN R1 CLR R0 ;CLEAR HIGH DIVIDEND DIV R3,R0 ;DIVIDE BY RADIX MOV R1,-(SP) ;SAVE REMAINDER ON STACK DECB R4 ;COUNT # OF DIGITS BNE 20$ ;LOOP IF NOT DONE 40$: MOV (SP)+,R0 ;GET DIGIT OFF STACK BNE 60$ ;PROCESS NORMALLY IF NONZERO TST R2 ;IS IT A LEADING ZERO? BMI 60$ ;NO, MAKE IT A ZERO MOVB #40,(R5)+ ;YES, MAKE IT A SPACE BR 80$ ;GO TO END OF LOOP 60$: ADD #60,R0 ;CONVERT # TO ASCII DIGIT MOVB R0,(R5)+ ;INSERT DIGIT IN STRING BIS #100000,R2 ;REMEMBER NONZERO DIGIT 80$: DECB R2 ;COUNT # OF DIGITS BNE 40$ ;LOOP IF NOT DONE CMPB -1(R5),#40 ;WAS # ALL ZEROES? BNE 100$ ;NO, IT'S OK MOVB #60,-1(R5) ;YES, MAKE LAST DIGIT ZERO 100$: MOV (SP)+,R4 ;RESTORE REGISTERS MOV (SP)+,R3 MOV (SP)+,R2 MOV (SP)+,R1 MOV (SP)+,R0 RTS PC ;DIGITS ARE IN STRING ;WE COME HERE WHEN THE USER TYPES "H" FOR HELP ; ;HELP: .PRINT <15><12> PRINT HELP INSTRUCTIONS HELP: NOP JMP PROMPT ;THIS SUBROUTINE WILL GET THE NAME OF THE ROUTINE ; WE ARE CURRENTLY IN AND CONVERT IT FROM RAD50 ; TO ASCII IN THE BUFFER POINTED TO BY R5. ;IT USES R0-R5 AND LEAVES R5 POINTING PAST THE ; NAME STRING IN THE BUFFER. ; NAME: MOV $OTSV,R3 ;GET WORK AREA POINTER MOV W.NAM(R3),R2 ;GET NAME POINTER ADD #4,R2 ; TST (R2) ; BNE 40$ ;BRANCH IF NOT NULL MOV #DEFNAM,R2 ;NULL, USE ".MAIN." 40$: MOV #2,-(SP) ;INIT WORD COUNTER 60$: MOV #3,R3 ;INIT CHAR COUNTER MOV (R2)+,R1 ;GET RAD50 WORD ADD #3,R5 ;POINT PAST 3RD CHAR 80$: CLR R0 ;CLEAR HIGH DIVIDEND DIV #50,R0 ;DIVIDE BY RADIX MOVB RTBL(R1),-(R5) ;LOOKUP ASCII CHAR MOV R0,R1 ;MAKE QUOTIENT LOW DIV SOB R3,80$ ; 3 CHAR LOOP ADD #3,R5 ;POINT PAST CHARS DEC @SP ;COUNT WORDS BNE 60$ ;GET NEXT WORD TST (SP)+ ;CLEAR STACK 120$: RTS PC ;NAME IS IN "ABUF" DEFNAM: .RAD50 /.MA/ ; DEFAULT NAME OF MAIN .RAD50 /IN./ ; PROGRAM .NLIST BEX ;THIS IS A RAD50 TO ASCII LOOKUP TABLE RTBL: .BYTE ' ,'A,'B,'C,'D,'E,'F,'G .BYTE 'H,'I,'J,'K,'L,'M,'N,'O .BYTE 'P,'Q,'R,'S,'T,'U,'V,'W .BYTE 'X,'Y,'Z,'$,'.,' ,'0,'1 .BYTE '2,'3,'4,'5,'6,'7,'8,'9 .LIST BEX ;THIS SUBROUTINE WILL SEND A MESSAGE TO THE ; TERMINAL WHERE THE USER IS RUNNING. IT ; IS CALLED BY "JSR R5,PRINT". THUS, UPON ENTRY ; R5 IS POINTING TO THE WORD FOLLOWING THE CALL ; WHICH CONTAINS THE NO. OF BYTES IN THE MESSAGE. ; THAT WORD IS FOLLOWED BY THE MESSAGE ITSSELF. ;IT RETURNS TO THE 1ST EVEN ADDRESS PAST THE END ; OF THE MESSAGE STRING. PRINT: MOV (R5)+,TTOUT+Q.IOPL+2 ;SET BYTE COUNT FOR TTOUT MOV R5,TTOUT+Q.IOPL ;SETUP BUFFER ADDRESS DIR$ #TTOUT ;SEND THE MESSAGE DIR$ #IOWAIT ;WAIT FOR IT ADD -2(R5),R5 ;POINT TO 1 PAST STRING INC R5 ;BUMP IN CASE ITS ODD BIC #1,R5 ;FORCE IT TO BE EVEN RTS R5 ;RETURN FROM PRINTING ;THIS SUBROUTINE WILL PRINT A STRING WHICH HAS ; BEEN BUILT IN "ABUF". THE POINTER PAST THE ; END OF THE STRING MUST BE IN R5. ; PRINTB: SUB #ABUF,R5 ;GET BYTE COUNT MOV R5,TTOUT+Q.IOPL+2 ;SET QIO COUNT PRINTC: MOV #ABUF,TTOUT+Q.IOPL ;SET BUF ADDR DIR$ #TTOUT ;PRINT THE BUFFER DIR$ #IOWAIT ;WAIT FOR IT RTS PC ;IT'S PRINTED ;THIS IS THE DISPATCH TABLE FOR ALL VALID ASCII ; CHARACTERS THE USER MIGHT TYPE IN ; COMTBL: INWAIT ;SPACE BAD ; ! BAD ; " BAD ; # BAD ; $ BAD ; % BAD ; & BAD ; ' BAD ; ( BAD ; ) BAD ; * BAD ; + NXTARG ; , BAD ; - BAD ; . ELNUM ; / OCDIG ; 0 OCDIG ; 1 OCDIG ; 2 OCDIG ; 3 OCDIG ; 4 OCDIG ; 5 OCDIG ; 6 OCDIG ; 7 DECDIG ; 8 DECDIG ; 9 OMODE ; : NXTARG ; ; BAD ; < BAD ; = BAD ; > BAD ; ? BAD ; @ ASCII ; A BRKPT ; B BAD ; C BAD ; D BAD ; E FOUR ; F PROCED ; G HELP ; H INTEGR ; I BAD ; J BAD ; K LUNSET ; L BAD ; M BAD ; N OCTAL ; O PROCED ; P BAD ; Q REAL ; R STEP ; S BAD ; T BAD ; U VARBAS ; V BAD ; W EXIT ; X YBYTE ; Y BAD ; Z BAD ; [ BAD ; \ BAD ; ] LASVAR ; ^ BAD ; _ .NLIST BEX ;THESE ARE INTERNAL VARIABLES USED BY FODT ; MODE: .WORD 0 ;DETERMINE ACTION UPON ENTRY ODD: .WORD 0 ;ODD BASE ADDRESS CHECK DISABLE FLAG(BYTE OPERATIONS ONLY) TEMP: .WORD 0 ; VARIABLE TO TEST THE CONTENTS OF SP REPCNT: .WORD 0 ;NUMBER OF TIMES REMAINING TO ; REPEAT THE CURRENT OPERATION FLAGS: .WORD 0 ;INTERNAL OPERATIONAL FLAGS FL.OCT= 40000 ;SET FOR OCTAL INPUT ARGPTR: .WORD ARG1 ;POINT TO CURRENT ARG ARG1: .WORD 0 ;ARGUMENTS ENTERED BY THE USER ARG2: .WORD 0 ; ARE CONSTRUCTED HERE ARG3: .WORD 0 BSEQ: .WORD 0 ;SEQ # OF BREAKPOINT BNAM1: .WORD 0 ;2-WORD RAD50 NAME OF BNAM2: .WORD 0 ; ROUTINE TO HAVE BREAKPOINT OPNADR: .WORD 0 ;ABS ADDR OF OPEN VARIABLE OPNSIZ: .WORD 0 ;SIZE OF OPEN VAR IN BYTES OPNTYP: .WORD 0 ;POINTER TO FORMAT PARAMS OPNELM: .WORD 0 ;ELEMENT # OF OPEN VARIABLE ;BUFFERS AND DPB'S ;NOTE - THE BUFFER ADDRESS AND BYTE COUNT PARAMETERS ; FOR TTOUT ARE MODIFIED BY "PRINT" AND "PRINTB". ; TTOUT: QIO$ IO.WVB,IOLUN,IOEFN,,IOSTAT,, TTIN: QIO$ IO.RVB,IOLUN,IOEFN,,IOSTAT,, NAMIN: QIO$ IO.RVB,IOLUN,IOEFN,,IOSTAT,, IOWAIT: WTSE$ IOEFN ;WAIT FOR I/O COMPLETION IOSTAT: .WORD 0 ;TERMINAL I/O STATUS IOCNT: .WORD 0 ;TERMINAL I/O BYTE COUNT ABUF: .ASCII <15><12>/FODT DEBUGGER/ .BLKB ABUF+30.-. .EVEN INBUF: .WORD 0 ;TERMINAL 1-CHAR INPUT BUF .END