.TITLE FPEM FPE FOR RSX11M .IDENT /GE003F/ ;GLENN C. EVRHART ; LAST EDIT 15-OCT-82 .IF NDF,X$STOP .MCALL STOP$S .PRINT ;FPEM USES STOP DIRECTIVE. UNSTOP IT TO RESTORE TRAPS. .IFF .PRINT ;FPEM USES SPND DIRECTIVE. RESUME IT TO RESTORE TRAPS. .ENDC .PRINT ;WHEN RUNNING FPEM, BE SURE IT IS FIXED AND NOT SHUFFLABLE! THIS .PRINT ;MEANS RUNNING IN THE BOTTOM OF GEN OR IN ITS OWN DEDICATED .PRINT ;PARTITION. IF FPEM IS SHUFFLED THE SYSTEM USUALLY CRASHES! ; ;DEFINE X$$HDR (NORMALLY IN 11M+ V2) FOR EXTERNAL HEADER SUPPORT ;DEFINE U$ID FOR USER MODE I/D SPACE SUPPORT AND K$ID FOR KNL I/D SUPPORT ; DEFINE R$XMV4 FOR RSX11M V4 (NOTE: NOT M+ V2) ; ALTERNATIVE FOR 11M V4: ; DEFINE P$LAS TO HANDLE TASK HDR LOCATION RESETS IN TASK... ; IF R$XMV4 IS NOT DEFINED, THE HEADER USED TO STORE FLOATING POINT ;VALUES IS IN THE LOW ADDRESS SPACE OF THE TASK. IF IT IS DEFINED, ; THE HEADER WILL BE THE ONE IN KERNEL SPACE (KERNEL D SPACE IF KERNEL ; I/D SPACE IS ENABLED). THIS CHANGE IS NEEDED FOR RSX11M V4 BECAUSE NOW ; SOME DEC CODE (VIRTUAL ARRAYS) USES LOW ADDRESS SPACE IN THE TASK. ;R$XMV4=0 ;UNCOMMENT FOR RSX11M V4 .IF NDF,X..DF$ .IIF DF,X$$HDR, U$ID=0 ;M+ V2 NORMALLY HAS BOTH... .IIF DF,X$$HDR, K$ID=0 .ENDC ; ;LAST-MINUTE KLUDGE FOR RSX11M+ V2 ;IF V$ID DEFINED, USE AN INTERRUPT VECTOR ABOVE THE REAL ONES ;AT ADDRESS V$VEC (DEFAULT 700) FOR INTERRUPT TRANSFER BLOCK .IIF NDF,V$VEC,V$VEC=700 ;NOTE: EVEN WHEN FPEM EXITS, ITS INTERRUPT TRANSFER AREA IS NOT FREED ;FROM POOL. RECOMMEND FIXING IT, RUNNING IT IN STARTUP.CMD ONLY, AND ;NEVER SAVING THE SYSTEM WITH IT HAVING BEEN STARTED. IF V$ID IS DEFINED, ;IT SIMPLY STEALS SOME INTERRUPT VECTORS (WHOSE ORIGINAL CONTENTS ARE ;DESTROYED BUT SHOULD ONLY POINT TO NONSENSE INTERRUPT LOCATION), SO ;AT LEAST NO POOL GETS LOST. ;FOR USE OF FPEM WITH F4P OR F77, INCLUDE "F4PEIS" IN YOUR BUILDS OR ;IN YOUR COPY OF F4POTS OR F77OTS. THIS WILL ALLOW IT TO WORK AND NOT ;ASK FOR A FLOATING POINT EXCEPTION AST, WHICH RSX WON'T GRANT (IT WAS ;SYSGENNED WITHOUT FPU SUPPORT SO IT WOULDN'T ISSUE ANY FPU INSTRUCTIONS, ;REMEMBER). IF YOU BUILD RSX11M+ WITH FPU SUPPORT, FPEM WILL MOST LIKELY ;CRASH, SINCE THERE ISN'T ANY FPU THERE AND FPEM ASSUMES A TASK CONTEXT ;WITH A HEADER IS THERE TO ACT AS F.P. ACCUMULATORS. ; KDSPR0=172360 ;KERNEL DATA SPACE APR0 KDSPR6=KDSPR0+6+6 ;KNL D APR6 UDSPR0=177660 ;USER D APR0 UDSPR6=UDSPR0+12. ;USER D APR6 ; ; *********** ; THIS VERSION HAS ALL INTERRUPTS TO 244 ARBITRARILY DISABLED ; TO PREVENT SYSTEM CRASHES WHEREVER RSX11M IS NOT GENERATED TO ; HANDLE FLOATING POINT AST'S. ; ; GCE ; ; ; THIS IS A PROTOTYPE (FUDGED UP) VERSION OF FPE FOR RSX 11M. ; ; IT IS INCOMPLETE AND IN SOME CASES INCORRECT. ; *** ; THIS VERSION OF THE FLOATING POINT EMULATOR HAS BEEN PUT ; TOGETHER BY G. EVERHART TO RUN MORE-OR-LESS CORRECTLY UNDER ; RSX11M (V3.1). IT HAS ERROR CODE AND WILL WORK WITH THE FOLLOWING ; CAVEATS: ; 1. IT NEVER GENERATES F.P. EXCEPTIONS. THIS CANNOT EASILY BE ; "FIXED" SINCE THE EMULATOR DOES NOT CALL $INTSV AND RUNS AT ; PRIORITY 7. HOWEVER, RSX NEED NOT BE GENERATED WITH FPP SUPPORT. ; 2. RSX SHOULD NOT BE GENERATED FOR FPP SUPPORT, BUT TASKS USING ; THIS EMULATOR SHOULD HAVE THE /FP SWITCH IN THEIR TASKBUILDS. ; THE EMULATOR USES THE F.P. SAVE AREA IN THE TASK HEADER AS FP ; ACCUMULATOR STORAGE; NO RSX CONTEXT ACTION IS NEEDED. HOWEVER, ; TKB WILL NOT DEFAULT TO /FP IF THE RSX11M SYSTEM DOES NOT HAVE ; IT. ; 3. THE EMULATOR RUNS AT PRIORITY 7 TO ALLOW IT TO CATCH ODD ; ADDRESS OR REAL ILLEGAL INSTRUCTION ERRORS WHILE RUNNING. IT ; WILL NOT CRASH THE SYSTEM, BUT MAY DEGRADE PERFORMANCE SOMEWHAT. ; IT WAS BUILT WITH THE CONSTRAINT THAT RSX11M SHOULD NOT NEED ANOTHER ; SYSGEN FOR IT TO BE USED. JUST ASSEMBLE AND BUILD, THEN RUN THE ; EMULATOR. YOUR MACHINE WILL APPEAR TO HAVE AN FPP. NOTE THAT ; F4P AND FOR SEEM NOT TO MIND GETTING ERRORS WHEN THE ASK TO ; SPECIFY F.P. AST'S. HOWEVER, ZERO DIVISION WILL NOT BE DETECTED ; SINCE F4P USES THE TRAP TO SAY WHEN THAT HAPPENS. ; NOTE THAT YOU SHOULD INSERT THE "F4PEIS" MODULES IN YOUR ; F4P OTS TO ALLOW THIS VERSION TO WORK SINCE F4P NOW (V2.5, V3) ; WILL OTHERWISE FAIL IF THE SPECIFY F.P. AST REQUEST FAILS. WITH ; THE EIS VERSION OF THE OTS THIS IS NOT CHECKED & ALL GOES WELL. ; THIS VERSION HAS BEEN TESTED ON 11/40, 11/34, ETC. ; NOTE TOO THAT THE EMULATOR IS SLOWER THAN SOFTWARE EMULATED ; F.P. A LA THE FOR OTS DUE TO LOTS OF TIMES DOING FLOATING ; LOADS AND STORES. USE THE EMULATOR ONLY WHERE SOFTWARE FLOATING ; POINT IS OTHERWISE UNAVAILABLE (F4P IN MOSTLY-INTEGER PROGRAMS ; FOR EXAMPLE, OR FOR COMPATIBILITY ON 11/40 CPU'S.) ; 4. NOTWIHSTNDING THE ABOVE, THE EMULATOR HAS BEEN IN USE FOR ; SOME TIME NOW WITH NO EVIDENCE OF ERRORS OR ILL EFFECTS ON ; EITHER THE SYSTEM OR THROUGHPUT, WITH 9 TERMINALS IN FAIRLY ; HEAVY USE. ; GLENN C. EVERHART 3/15/1979 ; ; ; ASSEMBLY: ; >MAC FPEM=[1,1]EXEMC.MLB/ML,[200,200]RSXMC,[10,10]FPEM ; > ; ; TASK BUILD: ; >RUN $BIGTKB ; . ; . ; TKB>FPEM/-FP/-CP/PR=FPEM,[1,54]RSX11M.STB ; TKB>// ; ; ;note: If using RSX11M+ V2 with this package, do not allow any ;external headers! This package assumes it can access F.P. save areas ;in pool and doesn't have the APR left over to access them anywhere ;else. It is not modified for M+ V2 since the M+ configurations are most ;likely to have F.P. hardware anyway. A suggested mod: ; copy F.P. save areas to local store by filling in ;APR6 with $sahdb and accessing hdr with $sahpt, then copying data, ;and then copy back when done. APR6 is already saved and restored ;so the local copy can be used instead of one in pool. Just leave r0 ;pointing there during the run and fix it up so the local copy gets ;put into the task before exit. ; .MCALL HDRDF$,PCBDF$,TCBDF$,SPND$S,EXIT$S HDRDF$ TCBDF$ PCBDF$ PRI=340 VECT=10 KAPR5=172352 UAPR5=177652 ;NOTE: IF F.P. ERR NEEDS TO BE LOGGED, YOU MAY BE ABLE TO ALLOW A TRAP ;VIA 244 SIMILAR TO THE WAY THIS PGM DOES IT TO 10. HOWEVER, IT SHOULD ;REMAIN AT PRIO 7 UNLESS THE RSX EXECUTIVE IS MODIFIED TO ALLOW ODD ADDRESS ;ERRORS TO BE RETURNED TO THE EMULATOR. ; -- GCE. NODE:; JSR R5,@#$INTSV ; .WORD 100 MOV R5,-(SP) ;ERROR ON KNL STACK CRASHES RSX, SO... MOV R4,-(SP) ;EMULATE $INTSV BUT STAY ON USER STACK. ; MOVB #340,@#PSW JSR PC,N2 ;CALL REAL INT. SVC. MOV (SP)+,R4 MOV (SP)+,R5 RTI N2: MOV @#KAPR5,-(SP) ;**** DO NOT SEPARATE THE FOLLOWING 2 LINES OF CODE: PROG=.+2 MOV #0,@#KAPR5 KDAPR5=KDSPR0+10. .IF DF,V$ID MOV @#KDSPR0+12.,KD6 ;STORE KNL D APR6 .ENDC .IIF DF,K$ID, MOV @#KDAPR5,KD5 ;NOTE AT PRI 7 HERE .IIF DF,K$ID, MOV PROG, @#KDAPR5 ;**** DO NOT SEPARATE THE FOLLOWING 2 LINES OF CODE: INTX=.+2 JSR PC,@#INTR KDAPR5=KDSPR0+10. .IIF DF,K$ID, MOV KD5,@#KDAPR5 ; .IIF DF,K$ID, MOV (SP),@#KDAPR5 MOV (SP)+,@#KAPR5 .IF DF,V$ID MOV KD6,@#KDSPR0+12. ;RESTORE KNL D APR6 .ENDC RTS PC KD5: .WORD 0 ;STORE KNL DATA APR5 HERE .IF DF,V$ID KD6: .WORD 0 ;STORAGE FOR KNL D APR6 .ENDC ENODE=. X..=NODE-ENODE-68. .IF GT, X.. .ERROR ;NODE TOO LONG, NEED TO INCREASE ALLOCATED SIZE FROM 68 DEC. .ENDC ;NODE TO TRAP TRAPS TO 4 DURING OPERATION: NODE4: ;ASSUMES ALREADY MAPPED TO THIS TASK... ;SPRING BY CALLING SETTRP ;UNSPRING BY UNSTTP ; ASSUMES "IFERR" MACRO USED. MOV (SP),-(SP) ;COPY OLD PC ADD #2,@SP ;PASS BRANCH INSTRUCTION MOV @(SP)+,(SP) ;REPLACE TRAP WITH NEW ADDRESS MOV SYS4,@#4 MOV SYS250,@#250 ;REPLACE RSX TRAPS FOR EXIT FROM HERE... RTI ;RETURN. EASY, WASN'T IT...? SYS4: .WORD 0 SYS250: .WORD 0 ;NOTE-- 6 AND 252 SHOULD BE PRIO 7 NOW ;LEAVE THEM ALSO ALONE SETTRP: ; BISB #340,@#PSW ;GO TO PRI7 MOV #NODE4,@#4 MOV #NODE4,@#250 RTS PC UNSTTP: MOV SYS4,@#4 MOV SYS250,@#250 ; BICB #0,@#PSW ;BACK TO RUN PRIO = 100 RTS PC START: MOV @#UAPR5,PROG MOV PROG,SAPR MOV @#4,SYS4 ;SAVE SYSTEM ERROR ADDRESSES MOV @#250,SYS250 ;FOR USE LATER... MOV VECT,SYSTP MOV VECT+2,SYSPS 10$: CLR R0 MOV #68.,R1 .IF NDF,V$ID CALL $ALOCB BCS ERR .IFF MOV #V$VEC,R0 ;SET UP TO USE INTERRUPT VECTORS FOR ITB IF ;USING M+ V2 SINCE KNL I SPACE ONLY OVERMAPS ;KNL D SPACE IN APR 0. KLUDGE, BUT SHOULD ;WORK (I HOPE)... .ENDC MOV R0,NADR ASR R1 MOV #NODE,R2 20$: MOV (R2)+,(R0)+ SOB R1,20$ MOV NADR,VECT MOV #PRI,VECT+2 .IF DF,X$STOP SPND$S ;GIVE UP CPU VIA SUSPEND .IFF STOP$S ;GIVE UP CPU VIA STOP .ENDC ;RESTORE VECTORS AFTER RESUME OR UNSTOP (WHICHEVER WAS USED TO UNDO STP/SPN) MOV SYSTP,VECT MOV SYSPS,VECT+2 ;REALLY OUGHTA CALL BLOCK DEALLOCATE HERE BUT I'M LAZY... EXIT$S NADR: 0 SAPR: 0 INTR: JMP FPISR ERR: EXIT$S .SBTTL 1.1 MACRO CALLS AND DEFINITIONS ; ; MACRO CALLS AND DEFINITIONS ; .MACRO PUSH ARG MOV ARG,-(SP) .ENDM .MACRO POP ARG MOV (SP)+,ARG .ENDM ; .MACRO IFERR ARG BR .+4 ; CONTINUE IF NO ERROR .WORD ARG+ASF3 ; ADDRESS OF ERROR ROUTINE JSR PC,UNSTTP ;UNSET TRAPS .ENDM ; .MACRO MOVTU ARG1,ARG2 PUSH ARG1 JSR PC,SETTRP ;ALLOW TO CATCH TRAPS .IF NDF,U$ID MTPI ARG2 .IFF MTPD ARG2 .ENDC IFERR ODAD1 ; CHECK FOR LEGAL ADDRESSES .ENDM ; .MACRO CLRWRD NUM,REG ; CLEAR NUM WORDS ; REG = (RN) .REPT NUM-1 ; AUTO INC. NUM-1 TIMES CLR REG+ .ENDR CLR REG .ENDM ; ; .MACRO TSTOVF ?A,?B BVC A ; TEST FOR OVERFLOW ON ROUND CALL TOVER A: BCC B CALL TOVER B: .ENDM ; .MACRO TRKTST ARG1,ARG2 ; TEST TO SEE IF TRUNCATE BIT SET BIT #40,ARG1 ; IS THE TRUNCATE BIT SET? BNE ARG2 ; IF SO, SKIP PAST ROUNDING .ENDM ; .SBTTL 1.2 SYMBOL DEFINITIONS ; PRIOR=40 PCOFF=6+10 ; PCOFFSET=2*N+2 (N=#OF REGISTERS SAVED) PCOFF2=2*7+2+10 PAR3K=172346 PAR2K=172344 PDR2K=172304 ASF2=40000 ASF3=0000 PSW=177776 MODFHW=0 ; DEFINE THIS TO EMULATE QUESTIONABLE HARDWARE ; ; NOTE: THE FLOATING POINT HARDWARE WILL NOT INTERRUPT FOR ; AN OVERFLOW ENCOUNTERED IN THE MODF/MODD INSTRUCTIONS. ; IF AN OVERFLOW HAS OCCURED, THE INTEGER WILL BE < 1 ; SINCE THE EXPONENT IS OFF BY 400 OCTAL. DEFINING MODFHW ; EMULATES THIS STRANGE BEHAVIOR. IF IT IS NOT DEFINED, ; AN OVERFLOW WILL CAUSE AN AST AS IN OTHER INSTRUCTIONS ; (ASSUMING THE INTERRUPT ON OVERFLOW BIT IS SET). ; .SBTTL 4. SYSTEM RETURN CODE SPCASE: MOV PCOFF(SP),R1 ; GET THE PC MFPI -(R1) ; PUT INSTR. THAT CALLED ON STACK POP R1 ; R1 HAS THE INSTRUCTION .IF NDF CHECKH MOV R1,R0 ; COPY INSTR .IIF DF STAT MOV R1,INSTR BIC #77,R0 ; CLEAR OUT ADDRESSING CMP #170300,R0 ; SEE IF STST WAS EXCICUTED IN KERNEL BNE POPOUT ; IF IT WASN'T QUIT .ENDC .IF DF CHECKH BIT #^C075077,R1 ; USE AN 11/40 FP INSTR. TO FAULT BNE POPOUT ; IF NOT THAT, GIVE UP BIC #177700,R1 ; MAKE IT AN STST BIS #170300,R1 ; LEAVE DEST ALONE .ENDC MOV #FAKFPS+ASF3,R0 ; SETUP A FAKE FPSW ADDRESS JMP NOTNO ; GO PROCESS POPOUT: POP R1 ; RETURN REGISTERS BEFORE QUITING POP R0 TST (SP)+ ; SKIP PAST NODE RETURN TST (SP)+ ; MOV (SP)+,@#KAPR5 ; RETURN KAPR5 TST (SP)+ ; SKIP PAST SST EXIT POP R4 POP R5 SYSRTN: MOVB (PC)+,@(PC)+ ; GIVE SYSTEM THE EXPECTED STATUS SYSPS: 0 PSW JMP @(PC)+ ; GO TO SYSTEM RETURN NODE SYSTP: 0 NODADR: 0 .SBTTL 5. ISR TABLES FPXCOD: 0 ; FLOATING POINT EXCEPTION CODE FXM: 0 FAKFPS: 100000 ; FAKE FLOATING POINT STATUS .IF DF,X$$HDR HDR$FP: .BLKW 25. ;SAVE AREA FOR TASK HDR FP REGS. .ENDC ; OPERA: LDFPSX+ASF3,STFPSX+ASF3,STSTX+ASF3,CLRFX+ASF3,TSTFX+ASF3 ABSFX+ASF3,NEGFX+ASF3 MULFX+ASF3,MULFX1+ASF3,MULFX2+ASF3,MULFX3+ASF3 MODFX+ASF3,MODFX1+ASF3,MODFX2+ASF3,MODFX3+ASF3 ADDFX+ASF3,ADDFX1+ASF3,ADDFX2+ASF3,ADDFX3+ASF3 LDFX+ASF3,LDFX1+ASF3,LDFX2+ASF3,LDFX3+ASF3 SUBFX+ASF3,SUBFX1+ASF3,SUBFX2+ASF3,SUBFX3+ASF3 CMPFX+ASF3,CMPFX1+ASF3,CMPFX2+ASF3,CMPFX3+ASF3 STFX+ASF3,STFX1+ASF3,STFX2+ASF3,STFX3+ASF3 DIVFX+ASF3,DIVFX1+ASF3,DIVFX2+ASF3,DIVFX3+ASF3 STEXPX+ASF3,STEXP1+ASF3,STEXP2+ASF3,STEXP3+ASF3 STCFIX+ASF3,STCFI1+ASF3,STCFI2+ASF3,STCFI3+ASF3 STCFDX+ASF3,STCFD1+ASF3,STCFD2+ASF3,STCFD3+ASF3 LDEXPX+ASF3,LDEXP1+ASF3,LDEXP2+ASF3,LDEXP3+ASF3 LDCIFX+ASF3,LDCIF1+ASF3,LDCIF2+ASF3,LDCIF3+ASF3 LDCDFX+ASF3,LDCDF1+ASF3,LDCDF2+ASF3,LDCDF3+ASF3 KISAR6=172354 .SBTTL 6. START OF ISR ROUTINE FPISR: PUSH R0 ; SAVE REGISTERS PUSH R1 ;FIRST JUNK THIS IF FROM KERNEL .IF DF,JK$KNL BIT #30000,@#177776 ;SEE IF PREVIOUS MODE WAS KERNEL BEQ POPOUT ;EXIT IF FROM KERNEL .IF EQ,1 BNE 5000$ ;IF NE, NO, WE WERE CALLED FROM USER/SUPER ;KERNEL CALLED FP INST. IGNORE IT. BR POPOUT ;GO LET KNL FIGURE THIS ISN'T VALID. 5000$: .ENDC .ENDC ; MOV @#$HEADR,R0 .IF DF M$$MGE MOV @#$TKTCB,R1 .IIF DF,P$LAS, MOV T.OFF(R1),-(SP) ;PUSH OFFSET TO TASK IMAGE MOV T.PCB(R1),R1 .IF NDF,X$$HDR ; KERNEL APR6 POINTS DURING OPERATION AT THE TASK HEADER TO ALLOW THE ; FP SAVE AREA TO BE ACCESSED VIA R0 (H.FPSA IS AN APR6 OFFSET). ; A SUBSIDIARY CONDITIONAL (NORMALLY OFF) CALLED E$VAL. WILL ALLOW ; COMPUTING THIS. NORMALLY FILL IN THE APPROPRIATE RSX11M CONSTANT. ; THE RSX11M+ CODE DOES THINGS DIFFERENTLY WITH A LOCAL COPY OF FP SAVE ;AREA. ; N.B. - THIS AREA IS NOT CONDITIONED FOR 11M+ V1 AND WILL NEED WORK. .IF NDF,R$XMV4 MOV P.REL(R1),@#KISAR6 .IFF .IF DF,E$VAL. MOV P.REL(R1),-(SP) ;GET KERNEL SPACE ADDRESS ASH #-6,(SP) ;SHIFT DOWN 6 PLACES BIC #^C7777,(SP) ;GUARANTEE LEGAL RANGE MOV (SP)+,@#KISAR6 ;FILL IN KNL APR6 TO MAP IT RIGHT .IFF MOV #1400,@#KISAR6 ;FILL IN APR6 WITH APPROPRIATE KERNEL SPACE OFFSET .ENDC .ENDC .ENDC .IIF DF,P$LAS, ADD (SP)+,@#KISAR6 ;ADD OFFSET TO TASK IMAGE .ENDC .IF NDF,X$$HDR MOV H.FPSA(R0),R0 ; R0 HAS POINTER TO FP SAVE AREA BEQ POPOUT ; GIVE IT TO THE SYSTEM IF NO FP AREA .IFF .IIF NDF, K$ID,MOV $SAHDB,@#KISAR6 ; FILL IN KNL APR6 .IIF DF, K$ID, MOV $SAHDB,@#KDSPR6 MOV $SAHPT,R0 ;POINT AT HEADER BEQ POPOUT MOV H.FPSA(R0),R0 ; GET FP SAVE AREA BEQ POPOUT ;IF NONE, LEAVE...CANT EMULATE FPU MOV R2,-(SP) MOV R3,-(SP) MOV #HDR$FP,R2 ;COPY TASK FP SAVE AREA INSIDE FPEM MOV #25.,R3 ;25 WORDS (6 AC'S + 1 STATUS WORD) 1$: MOV (R0)+,(R2)+ ;COPY ALL OF FP REGS FOR TASK SOB R3,1$ ; MOV (SP)+,R3 MOV (SP)+,R2 ;FIXUP REGS + STACK MOV #HDR$FP,R0 ;POINT R0 AT OUR COPY OF FP SAVE AREA ;(NOTE WE'RE MAPPED IN BOTH I AND D SPACE AT ONCE) .IF DF,M$$MGE ; (EXTRA WORK REALLY BELOW SINCE APR6 HEADER POINTER IS NOT REALLY USED ; UNTIL WE EXIT.) .IIF NDF,K$ID, MOV P.REL(R1),@#KISAR6 ;FIXUP KNL APR6 .IIF DF,K$ID, MOV P.REL(R1),@#KDSPR6 .ENDC .ENDC ; ADD #ASF2-ASF3,R0 ; CORRECT R0 EXPLICITLY FOR ASF2 MAP MOV 16(SP),R1 ; R1 HAS CURRENT PC MFPI -(R1) ; GET FAULTING INSTRUCTION MOV R1,(PC)+ ; SAVE PC OF INSTRUCTION PCSAVE: 0 ; NEXT INSTRUCTION LOCATION POP R1 ; R1 HAS THE INSTR. THAT CALLED BGE POPOUV ; FP INSTR.S ARE AT LEAST NEGATIVE CMP #170000,R1 ; ALSO LESS THAN THIS BGT POPOUV ; GIVE BACK TO SYSTEM BIT #7700,R1 ; IS THIS A NO OPERAND INSTR.? BEQ NO ; NO IT'S GOT NO OPERAND NOTNO: PUSH R2 ; SAVE ANOTHER REGISTER PUSH R3 MOV 16(SP),-(SP) MOV 22(SP),-(SP) ;NEXT GETS SP AND I/D SPACE DOESN'T MATTER... MFPI SP MOV R1,R2 ; COPY INSTR. CLR NMB ; FOR USE IN GET SUBROUTINE MOV #200,R3 ; MOST COMMON FPSR MASK MOV #10,R5 MOV R0,R4 ; POINT TO FP SAVE AREA BIC #170077,R1 ; PICK DISTINGUISHING PART OF INSTR. ASH #-5,R1 ; SHIFT IT SO IT BECOMES AN OFFSET ADD #OPERA+ASF3,R1 ; NOW A REAL ADDRESS JMP @-(R1) ; GO TO THE PROPER ROUTINE NO: DECB R1 ; DECODE NO OPERAND INSTRUCTIONS BGE NO1 ; BRANCH IF NOT CFCC CFCCX: MOV (R0),R1 ; GET CONTENTS OF FPSR BIC #177760,R1 ; MASK ALL BUT LOW 4 BITS BIC #17,PCOFF+2(SP) ; CLEAR OUT PRESENT STATUS BIS R1,PCOFF+2(SP) ; SET THE BITS IN TASKS PSW ;GENERAL EXIT POINT BACK TO USER AFTER F.P. CALCULATION. FPEXIT: .IF DF,X$$HDR MOV R2,-(SP) .IIF NDF,K$ID, MOV $SAHDB,@#KISAR6 ;POINT AT TASK HDR AGAIN .IIF DF, K$ID, MOV $SAHDB, @#KDSPR6 MOV $SAHPT,R0 ;POINT AT IT... BEQ 2$ MOV H.FPSA(R0),R0 ;GET F.P. SAVE AREA ADDR BEQ 2$ ;ZERO JUST QUITS MOV #25.,R1 ;RESTORE ALL WORDS MOV #HDR$FP,R2 ;OUR COPY... 1$: MOV (R2)+,(R0)+ ;RESTORE TO USER SOB R1,1$ 2$: MOV (SP)+,R2 .ENDC POP R1 ; RETURN REGISTERS POP R0 RETURN NO1: BNE NO2 ; BRANCH IF NOT SETF SETFX: BIC #200,(R0) ; CLEAR FD BIT IN FPSR BR FPEXIT NO2: CMPB #10,R1 ; BLE NO3 ; IT IS NOT SETI DECB R1 ; MAKE SURE THIS IS SETI BNE ILLIN ; BRANCH IF ILLEGAL INSTRUCTION SETIX: BIC #100,(R0) ; CLEAR FL BIT IN FPSR BR FPEXIT ; DONE NO3: BLT SETLX ; BRANCH IF SETL SETDX: BIS #200,(R0) ; SET FD BIT IN FPSR POP R1 ; RETURN REGISTERS POP R0 RETURN POPOUV: JMP POPOUT SETLX: CMPB R1,#11 ; MAKE SURE THIS IS SETL BNE ILLIN ; BRANCH IF ILLEGAL INSTRUCTION BIS #100,(R0) ; SET FL BIT IN FPSR BR FPEXIT ; DONE ILLIN: BIS #100000,(R0) ; SET ERROR BIT MOV #2,FPXCOD ; SET EXCEPTION CODE BIT #40000,(R0) ; IS INHIBIT INTERRUPT SET? .IF DF,F$$AST ;IF FLOATING AST ALLOWED... (GCE) BNE FPEXIT ; IF SO JUST EXIT QUIETLY .IFF ; GCE NO FLOATING AST BR FPEXIT ;NEVER GET AST (GCE) .ENDC ;GCE MOV @#244,4(SP) ; SETUP TO GO AST POP R1 POP R0 MOV #34340,@#PSW JMP @(SP)+ ; GO .SBTTL 7. SINGLE AND DOUBLE OPERAND ROUTINES .SBTTL 7.1 ABSF,NEGF,LDFPS,TSTF,LDF,STFPS,STST,CLRF ;---------------------------------------------------------------- ABSFX: INC NMB ; WANT AN ADDRESS CALL GET ; GET IT BCS ABSFY ; MODE 0 JSR PC,SETTRP MFPI (R1) ; GET FIRST NUMBER IFERR ODAD1 ; CHECK FOR LEGAL ADDRESSES BIC #100000,(SP) ; MAKE SURE IT IS POSITIVE MOV (SP),NUMB ; WILL WANT TO SET CONDITION CODES MTPI (R1) ; PUT ABS VALUE BACK BR TSTFY ; SET CONDITION CODES ABSFY: BIC #100000,(R1) ; MAKE POSITIVE MOV (R1),NUMB ; SAVE ABS VALUE BR TSTFY ;---------------------------------------------------------------- NEGFX: INC NMB ; WANT AN ADDRESS CALL GET ; BCS NEGFZ ; GO DO MODE 0 JSR PC,SETTRP MFPI (R1) ; GET NUMBER IFERR ODAD1 ; CHECK FOR LEGAL ADDRESSES ADD #100000,(SP) ; DO NEGATE MOV (SP),NUMB ; SAVE RESULT MTPI (R1) ; PUT BACK IN USER TASK BR TSTFY ; SET CONDITION CODES NEGFZ: ADD #100000,(R1) ; DO NEGATE MOV (R1),NUMB ; BR TSTFY ; GO SET CODES ;---------------------------------------------------------------- LDFPSX: MOV #2,R5 ; MAX AUTOINCREMENT IS 2 CALL GETX ; GET IT MOV NUMB,(R0) ; SAVE STATUS BCC FPEX2 ; DONE IF NOT MODE 0 MOV (R4),(R0) ; GET NUMBER FROM A RESISTER ON THE STACK BR FPEX2 ;---------------------------------------------------------------- TSTFX: CALL GET BR TSTFY ;---------------------------------------------------------------- LDFX3: ADD R5,R4 LDFX2: ADD R5,R4 LDFX1: ADD R5,R4 LDFX: TST (R4)+ ; AC0 MOV R4,TMP3 ; SAVE POINTER TO AC CALL GET MOV TMP3,R2 ; GET AC ADDRESS BIT #200,(R0) ; SINGLE OR DOUBLE BNE LDDX ; BRANCH ON DOUBLE CLR 2(R2) ; CLEAR OUT REGISTER MOV #NUMB+ASF3,R3 ; GET ADDRESS OF NUMBERS LDFY: MOV (R3)+,(R2)+ ; LOAD THE NUMBERS DEC TMP1 BGT LDFY ; TSTFY: BIC #17,(R0) ; CLEAR OUT CURRENT CONDITION CODES TSTFY2: BIT #77600,NUMB ; CHECK FOR ZERO IN EXPONENT --> 0 FRAC BNE 10$ ; NOT ZERO BIS #4,(R0) ; SET ZERO INDICATOR 10$: TST NUMB ; NOW IS IT NEGATIVE? BGE FPEX2 ; NO BIS #10,(R0) ; SET NEGATIVE BIT FPEX2: MTPI SP ; MOV (SP)+,22(SP) MOV (SP)+,16(SP) POP R3 POP R2 .IF NDF,X$$HDR POP R1 ; RETURN REGISTERS POP R0 RETURN ; RETURN TO USER .IFF JMP FPEXIT .ENDC LDDX: CLRWRD 4,(R2) ; CLEAR OUT THE FAC MOV TMP3,R2 ; GET THE TOP OF FAC AGAIN MOV #NUMB+ASF3,R3 ; POINT TO NUMBER BR LDFY ; GO LOAD ;---------------------------------------------------------------- STFPSX: MOV #2,R5 ; WANT ONLY AN ADDRESS INC NMB ; WANT AN ADDRESS CALL GETX ; GET THE ADDRESS BCS STFPSY ; MODE 0 IS DIFFERENT MOVTU (R0),(R1) ; STORE STATUS IN USER AREA BR FPEX2 ; DONE STFPSY: MOV (R0),(R4) ; PUT IT IN A REGISTER BR FPEX2 ; DONE ;---------------------------------------------------------------- STSTX: MOV #-1,R3 ; NO PARTICULAR BIT TO TEST ASR R5 ; AUTO INC. BY 4 ALWAYS INC NMB ; WANT AN ADDRESS CALL GET ; GET ADDRESS BCS STSTY ; BRANCH IF MODE 0 MOVTU FPXCOD,(R1)+ ; PUT FEC IN USER AREA DEC TMP1 ; WANT FEA ALSO? BEQ FPEX2 ; EVIDENTLY NOT MOVTU PCSAVE,(R1) ; YES - PUT IT IN USER AREA +2 BR FPEX2 ; LEAVE STSTY: MOV FPXCOD,(R4) ; PUT FEC IN A REGISTER BR FPEX2 ; AND LEAVE ;---------------------------------------------------------------- CLRFX: BIC #17,(R0) ; CLEAR OUT CONDITION CODES BIS #4,(R0) ; SET ZERO CONDITION CODE INC NMB ; WANT AN ADDRESS CALL GET BCS CLRFZ ; MODE 0 PROCESSING CLRFY: CLR -(SP) ; ALL OTHER MODES PROCESSED JSR PC,SETTRP MTPI (R1)+ ; PUT THE ZERO IN IFERR ODAD1 ; CHECK FOR LEGAL ADDRESSES DEC TMP1 ; DECREMENT THE WORD COUNT BGT CLRFY ; CONTINUE TILL FINISHED BR FPEX2 ; DONE CLRFZ: CLR (R1)+ ; PUT THE ZERO IN THE HEADER DEC TMP1 BGT CLRFZ ; CONTINUE TILL DONE BR FPEX2 ; FINISHED ;---------------------------------------------------------------- .SBTTL 7.2 MULF ;---------------------------------------------------------------- MULGET: MOV R4,TMP3 ; SAVE POINTER TO AC CALL GET ; GET THE NUMBER PUSH R0 ; SAVE FPSW POINTER MOV TMP3,R0 ; SETUP POINTER TO FAC MOV #NUMB+ASF3,R1 ; SETUP POINTER TO FSRC BIT #200,@(SP) ; CHECK MODE BEQ MULF ; BRANCH IF SINGLE PRECISION CLR MODFLG ; THIS IS MULD NOT MODF OR MODD JMP MULDX ; GO DO DOUBLE MULDM0: MOV #NUMB+ASF3,R1 ; MUST COPY THE FSRC TO SCRATCH AREA MOV (R2)+,(R1)+ ; MOVE IT MOV (R2)+,(R1)+ MOV (R2)+,(R1)+ MOV (R2),(R1) ; DONE PUSH R0 ; SAVE POINTER MOV R4,R0 ; POINT TO FAC WITH R0 MOV R4,TMP3 ; SAVE POINTER TO AC MOV #NUMB+ASF3,R1 ; R1 POINTS TO BEGINNING OF FSRC CLR MODFLG JMP MULDX ; GO DO DOUBLE MULTIPLY MULFX3: ADD R5,R4 ; PROPER AC MULFX2: ADD R5,R4 ; PROPER AC MULFX1: ADD R5,R4 ; PROPER AC MULFX: TST (R4)+ ; AC0 CLR FXM ; CLEAR FPE FLAG BIT #70,R2 ; CHECK FOR MODE0 BNE MULGET ; IF NOT MODE 0 ,DO REGULAR THINGS BIC #77770,R2 ; CLEAR ALL BUT REGISTER AND MSB ASL R2 ; SHIFT TO MAKE AN OFFSET ROL R2 ; PUT IN CARRY TO ADD 2 ASL R2 ; SHIFT IS DONE ADD R0,R2 ; R2 HAS THE POINTER TO FSRC BIT #200,(R0) ; FLOATING OR DOUBLE? BNE MULDM0 ; BRANCH IF DOUBLE MOV R2,R1 ; R1 POINTS TO FSRC PUSH R0 ; SAVE POINTER MOV R4,R0 ; POINT TO FAC WITH R0 MOV R4,TMP3 ; SAVE POINTER TO AC MULF: MOV (R0)+,R4 ; HIGH ORDER FAC MOV (R0),R5 ; LOW ORDER FAC ASHC #1,R4 ; GET THE SIGN OUT ROL -(SP) ; SAVE IT ON THE STACK PUSH R4 ; WANT EXPONENT ON THE STACK CLRB (SP) ; CLEAR OUT FRACTION SWAB (SP) ; PUT IT IN THE LOW ORDER BYTE BEQ MULZRO ; ANSWER IS ZERO ASHC #7,R4 ; LEFT JUSTIFY THE FAC PUSH R5 ; SAVE LOW ORDER FAC ON STACK BIS #100000,R4 ; PUT IN HIDDEN BIT PUSH R4 ; SAVE HIGH ORDER FAC ON STACK MOV (R1)+,R2 ; GET HI ORDER FSRC MOV (R1),R3 ; LOW ORDER FSRC ASHC #1,R2 ; SHIFT OUT SIGN ADC 6(SP) ; STORE FINAL SIGN MOV R2,R1 ; GET THE EXP OF FSRC CLRB R1 ; GET RID OF FRACTION SWAB R1 ; RIGHT JUSTIFY BEQ MULZR2 ; ANSWER IS ZERO ADD R1,4(SP) ; STORE THE SUM OF THE EXPONENTS ASHC #7,R2 ; LEFT JUSTIFY THE FSRC BIS #100000,R2 ; PUT IN HIDDEN BIT CLR (R0) ; CLEAR PLACE IN FAC FOR ANSWER CLR -(R0) ; TST R3 ; TEST LOW ORDER FSRC BEQ MULA2Z ; BRANCH IF ZERO MUL R3,R4 ; GET HI(FAC)*LO(FSRC) ADD R3,R4 ; ADD LO(FSRC) TO HI WORD OF RESULT ; THIS MUST BE DONE SINCE HI(FAC) ; IS REALLY POSITIVE EVEN THOUGH IT ; APPEARS NEGATIVE TO THE MUL INSTR. TST R3 ; WAS LO(FSRC) INTERPRETED AS MINUS? BPL MULA2P ; IF NOT O.K. ADD (SP),R4 ; IF SO, CORRECT FOR IT BY ADDING ; HI(FAC) TO HIGH WORD OF MULTIPLICATION MULA2P: MOV R4,2(R0) ; PUT IN HI(FAC)*LO(FSRC) MULA2Z: MOV 2(SP),R4 ; PUT LO(FAC) IN R4 BEQ MULB2Z ; BRANCH IF ZERO MUL R2,R4 ; GET HI(FSRC)*LO(FAC) ADD 2(SP),R4 ; ADD LO(FAC) SINCE HI(FSRC)REALLY + TST 2(SP) ; SEE IF LO(FSRC) WAS MISTAKEN FOR NEGATIVE BPL MULB2P ; NO -- NO PROBLEM ADD R2,R4 ; PUT IN CORRECTION MULB2P: ADD R4,2(R0) ; ADD IN HI(FSRC)*LO(FAC) ADC (R0) ; THERE MAY BE A CARRY MULB2Z: MOV R2,R4 ; NOW GET HI(FAC)*HI(FSRC) ADD R2,(R0) ; ADD HI(FSRC) TO RESULT MUL (SP),R4 ; MULT. HI(FAC)*HI(FSRC) ADD (SP)+,(R0)+ ; ADD HI(FAC) TO RESULT ADD R5,(R0) ; PUT IN LOW ORDER ADC -(R0) ; INCLUDE CARRY ADD R4,(R0) ; PUT IN HIGH ORDER TST (SP)+ ; POP LO (FAC) POP R4 ; GET EXPONENT ROL 2(R0) ; GET RID OF NORMAL BIT ROL (R0)+ ; BCS MULNRM ; BRANCH IF IT WAS FOUND ROL (R0) ; SHIFT AGAIN ROL -2(R0) ; MUST HAVE IT NOW DEC R4 ; ADJUST EXPONENT MULNRM: SUB #200,R4 ; GET RID OF EXTRA EXCESS 128. BGT MULNU ; BRANCH ON NO UNDERFLOW CALL UNDER ; HANDLE UNDERFLOW MULNU: CMP #377,R4 ; CHECK FOR OVERFLOW BGE MULOK ; BRANCH IF NO OVERFLOW CALL OVER ; PROCESS OVERFLOW MULOK: CLRB (R0) ; SHIFT THE THING RIGHT BISB -2(R0),(R0) ; MOVE BYTES SWAB (R0) ; PROPER ORDER TST -(R0) ; POINT TO FIRST WORD CLRB (R0) ; ROOM FOR EXPONENT BISB R4,(R0) ; EXPONENT IN SWAB (R0) ; EXPONENT ON THE LEFT ROR (SP)+ ; PUT SIGN IN CARRY ROR (R0)+ ; PUT THE SIGN IN ROR (R0) ; TRKTST @(SP),10$ ; CHECK TRUNCATE BIT ADC (R0) ; ROUND ADC -(R0) ; TSTOVF ; CHECK FOR OVERFLOW 10$: JMP ADDOUT ; GO FINISH MULZR2: CMP (SP)+,(SP)+ ; SET STACK PROPERLY MULZRO: CMP (SP)+,(SP)+ ; DONE CLR (R0) ; SET TO ZERO CLR -(R0) ; FAC = 0 NOW JMP ADDOUT OVER: MOV #10,FPXCOD ; PUT IN FEC BIC #17,@4(SP) ; CLEAR OUT CC'S BIS #2,@4(SP) ; SET V BIT MOV #1000,FXM ; SET FPSW MASK RETURN ; CONTINUE WITH REGULAR PROCESSING TOVER: MOV #10,FPXCOD ; PUT IN FEC BIC #17,@2(SP) ; THIS ROUTINE HAS DIFFERENT STACK FROM BIS #2,@2(SP) ; THE OVER SUBROUTINE MOV #1000,FXM ; SET FPSW MASK RETURN ; CONTINUE WITH REGULAR PROCESSING ;---------------------------------------------------------------- .SBTTL 7.3 MULD ;---------------------------------------------------------------- MULDX: MULDX1: ASL (R0) ; SHIFT LEFT FAC ROL -(SP) ; SAVE SIGN ON STACK CLR -(SP) ; MAKE ROOM FOR THE EXPONENT MOVB 1(R0),(SP) ; SAVE EXPONENT BEQ MULDZR ; BRANCH IF ANSWER IS ZERO SWAB (R0) ; WISH TO LEFT JUSTIFY THE FAC SEC ; ROR (R0)+ ; PUT IN HIDDEN BIT MOVB 1(R0),-2(R0) ; SHIFT LEFT 1 BYTE TO JUSTIFY SWAB (R0)+ ; PROPER ORDER MOVB 1(R0),-2(R0) ; SWAB (R0)+ ; MOVB 1(R0),-2(R0) ; SWAB (R0) ; DONE CLRB (R0) ; CLEAR OUT LOWEST BYTE ASL (R1) ; SHIFT LEFT FSRC ADC 2(SP) ; GET SIGN OF RESULT TSTB 1(R1) ; IS THE FSRC = 0? BNE MULDNZ ; BRANCH IF NOT MULDZR: CMP (SP)+,(SP)+ ; CLEAR STACK OF UNWANTED ITEMS MOV TMP3,R0 ; GET ADDRESS OF FAC CLR (R0)+ ; CLEAR FAC CLR (R0)+ CLR (R0)+ CLR (R0)+ ; DONE TST MODFLG ; THIS COULD BE A MOD INSTR. BNE 10$ ; BRANCH IF IT IS JMP ADDOUT ; ELSE GO FINISH 10$: MOV TMP3,R1 ; FAC ADDRESS SUB (SP),R1 ; MUST CHECK FOR EVEN FAC BIT #10,R1 ; IS IT ODD? BNE 20$ ; IF IT IS ODD, WE ARE DONE CLRWRD 4,(R0) ; IF EVEN, CLEAR THE INTEGER REGISTER 20$: JMP ADDOUT ; GO FINISH MULDNZ: CLR R2 ; R2!R3!R4!R5 WILL ACCUMULATE ANSWER CLR R3 ; GET THE HIGH ORDER READY CLR R4 ; USE R4 FOR SOME TEMP STUFF BISB 1(R1),R4 ; GET EXPONENT ADD R4,(SP) ; GET THE SUM OF THE EXPONENTS MOVB #1,1(R1) ; PUT IN NORMALIZE BIT ROR (R1) ; THERE SWAB (R1)+ ; LEFT JUSTIFY THE FSRC MOVB 1(R1),-2(R1) ; SHIFT LEFT ONE BYTE SWAB (R1)+ ; PROPER ORDER MOVB 1(R1),-2(R1) ; SWAB (R1)+ ; MOVB 1(R1),-2(R1) ; SWAB (R1) ; DONE CLRB (R1) ; CLEAR OUT LOW BYTE SUB #6,R0 ; POINT BACK TO THE TOP OF FAC PUSH (R0)+ ; FAC1 PUSH (R1) ; FSRC4 CALL MULT ; GO MULTIPLY -- RETURN RESULT TO STACK POP R4 ; RESULT TO LOW HALF OF 4 WORD ACCUMULATOR POP R5 ; PUSH (R0)+ ; FAC2 PUSH -(R1) ; FSRC3 CALL MULT ; FAC2*FSRC3 ADD (SP)+,R4 ; ADD TO LOW HALF ADC R3 ADD (SP)+,R5 ADC R4 ; MAY HAVE CARRY ADC R3 ; PUSH (R0)+ ; FAC3 PUSH -(R1) ; FSRC2 CALL MULT ; FAC3*FSRC2 ADD (SP)+,R4 ; ADD IN ADC R3 ADD (SP)+,R5 ADC R4 ADC R3 PUSH (R0) ; FAC4 PUSH -(R1) ; FSRC1 CALL MULT ; FAC4*FSRC1 ADD (SP)+,R4 ; ADD IN ADC R3 ADD (SP)+,R5 ADC R4 ADC R3 MOV R4,R5 ; DIVIDE BY 2**16 MOV R3,R4 CLR R3 ; DONE PUSH -(R0) ; FAC3 PUSH (R1)+ ; FSRC1 CALL MULT ; FAC3*FSRC1 ADD (SP)+,R4 ADC R3 ADD (SP)+,R5 ADC R4 ADC R3 PUSH -(R0) ; FAC2 PUSH (R1)+ ; FSRC2 CALL MULT ; FAC2*FSRC2 ADD (SP)+,R4 ADC R3 ADD (SP)+,R5 ADC R4 ADC R3 PUSH -(R0) ; FAC1 PUSH (R1) ; FSRC3 CALL MULT ; FAC1*FSRC3 ADD (SP)+,R4 ADC R3 ADD (SP)+,R5 ADC R4 ADC R3 PUSH (R0)+ ; FAC1 PUSH -(R1) ; FSRC2 CALL MULT ; FAC1*FSRC2 ADD (SP)+,R3 ADC R2 ADD (SP)+,R4 ADC R3 ADC R2 ; ADDING TO MIDDLE 2 WORDS NOW PUSH (R0) ; FAC2 PUSH -(R1) ; FSRC1 CALL MULT ; FAC2*FSRC1 ADD (SP)+,R3 ADC R2 ADD (SP)+,R4 ADC R3 ADC R2 PUSH -(R0) ; FAC1 PUSH (R1) ; FSRC1 CALL MULT ; FAC1*FSRC1 ADD (SP)+,R2 ; HIGHEST WORD ADD (SP)+,R3 ADC R2 ; FRACTION MULTIPLICATION DONE POP R1 ; PUT SUM OF EXPONENTS IN R1 ASL R5 ; SHIFT OUT NORMAL BIT ROL R4 ROL R3 ROL R2 ; DONE BCS MULDNM ; BRANCH IF FOUND ASL R5 ROL R4 ROL R3 ROL R2 ; DONE DEC R1 ; ADJUST EXPONENT MULDNM: TST MODFLG ; IS THIS MULD OR MODF/MODD? BEQ MULD ; BRANCH IF MULD INSTRUCTION JMP MODFY ; GO DO MOD INSTRUCTION MULD: SUB #200,R1 ; GET RID OF EXTRA EXCESS 128. BGT MULDNU ; BRANCH ON NO UNDERFLOW CALL UNDER ; SET UNDERFLOW FLAGS MULDNU: CMP #377,R1 BGE MULDOK ; BRANCH ON NO OVERFLOW CALL OVER ; SET OVERFLOW MULDOK: CALL MULDMD ; GO SHIFT RIGHT AND INSERT EXPONENT TSTOVF ; CHECK FOR OVERFLOW MULDOT: MOV R2,(R0)+ ; SAVE THE ANSWER IN THE FAC MOV R3,(R0)+ MOV R4,(R0)+ MOV R5,(R0) JMP ADDOUT MULT: PUSH R4 ; SAVE REGISTERS PUSH R5 CLR -(SP) ; CLEAR HIGH PRODUCT MOV 10(SP),R4 ; MULTIPLICAND BEQ MZ ; BRANCH IF 0 BGT MPLUS ; BRANCH IF PLUS TST 12(SP) ; TEST MULTIPLIER BEQ MZ ; 0 BGT MNEG1 ; + BR MNEG MPLUS: TST 12(SP) ; TEST MULTIPLIER BEQ MZ BGT MLTQ ADD R4,(SP) ; CORRECTION BR MLTQ MNEG: ADD R4,(SP) ; MNEG1: ADD 12(SP),(SP) ; MLTQ: MUL 12(SP),R4 ; GET PRODUCT MDONE: ADD (SP)+,R4 ; ADD HIGH ORDER PARTS MOV R4,6(SP) ; RETURN ANSWER ON STACK MOV R5,10(SP) ; POP R5 ; RETURN REGISTERS POP R4 RETURN MZ: CLR R4 ; ZERO CLR R5 BR MDONE MULDMD: CLRB R5 ; SHIFT EVERYTHING RIGHT BISB R4,R5 ; SWAB R5 CLRB R4 BISB R3,R4 SWAB R4 CLRB R3 BISB R2,R3 SWAB R3 CLRB R2 BISB R1,R2 ; PUT THE EXPONENT IN SWAB R2 ; PROPER ORDER ROR 2(SP) ; GET THE SIGN MOV (SP)+,(SP) ; SET RETURN ROR R2 ; PUT IT IN ROR R3 ROR R4 ROR R5 TRKTST @2(SP),10$ ; CHECK TRUNCATE -- BRANCH IF SET ADC R5 ; ROUND IT ADC R4 ADC R3 ADC R2 ; DONE RETURN 10$: CLC RETURN ; RETURN ;---------------------------------------------------------------- .SBTTL 7.4 MODF,MODD ;---------------------------------------------------------------- MODFX3: ADD R5,R4 ; PROPER AC MODFX2: ADD R5,R4 ; PROPER AC MODFX1: ADD R5,R4 ; PROPER AC MODFX: TST (R4)+ ; AC0 MOV #1,MODFLG ; SET MOD INSTRUCTION FLAG CLR FXM ; INITIALIZE FPSW MASK MOV R4,TMP3 ; SAVE POINTER TO AC CALL GET PUSH R0 ; SAVE FPSW POINTER MOV TMP3,R0 ; POINT TO FAC MOV #NUMB+ASF3,R1 ; POINT TO FSRC JMP MULDX1 ; GO MULTIPLY ; MODFY: MOV #59.,TMP2 ; SET THE NUMBER OF PRODUCT BITS BIC #37,R5 ; GET RID OF EXTRA PRECISION LIKE HARD. BIT #200,@2(SP) ; CHECK FLOATING OR DOUBLE BNE MODD ; BRANCH IF DOUBLE CLR R5 ; SINGLE PRECISION KEEPS 48. BITS MOV #48.,TMP2 ; SET THE NUMBER OF PRODUCT BITS TO 48. MODD: SUB #200,R1 ; GET RID OF EXTRA EXCESS 128. BGT MODNU ; BRANCH ON NO UNDERFLOW CALL UNDER ; SET UNDERFLOW MODNU: .IF NDF MODFHW CMP #377,R1 ; CHECK FOR OVERFLOW BGE MODNO ; BRANCH ON NO OVERFLOW CALL OVER ; SET OVERFLOW .ENDC MODNO: SUB #200,R1 ; GET THE MINIMUM SHIFT COUNT BGT MODFZ ; BRANCH IF THERE IS SHIFTING TO DO ADD #200,R1 ; RESTORE EXPONENT CALL MULDMD ; NO SHIFT NEEDED SUB (SP),R0 ; CHECK FOR EVEN/ODD FAC BIT #10,R0 ; BNE MODDUN ; BRANCH IF ODD REGISTER MOV TMP3,R0 ; GET ADDRESS OF FAC BACK ADD #10,R0 ; GET ADDRESS OF FAC+1 (FAC IS EVEN HERE) CLRWRD 4,(R0) ; CLEAR THE INTEGER REGISTER MODDUN: MOV TMP3,R0 ; R0 HAS ADDRESS OF FAC CALL MODSAV ; SAVE THE FRACTION JMP ADDOUT ; GO FONISH MODFZ: CMP R1,TMP2 ; HOW BIG IS THE INTEGER? BLE MODSHF ; SHIFT IF NOT TOO BIG CLRWRD 4,(R0) ; OTHERWISE ZERO THE FRACTION REGISTER ADD #200,R1 ; RESET EXPONENT MOV TMP3,R0 ; CHECK FOR EVEN/ODD FAC SUB 2(SP),R0 BIT #10,R0 BEQ MODINT ; BRANCH IF EVEN FAC JMP ADOUT ; FINISHED IF ODD FAC MODINT: CALL MULDMD ; ASSEMBLE THE INTEGER .IIF NDF MODFHW TSTOVF ; THERE MAY BE OVERFLOW ON ROUND MOV TMP3,R0 ; FAC ADD #10,R0 ; FAC+1 CALL MODSAV ; SAVE INTEGER JMP ADDOUT ; GO FINISH MODSHF: PUSH R1 ; SAVE SHIFT COUNT SUB 4(SP),R0 ; IS THE FAC EVEN OR ODD? BIT #10,R0 BNE MODSH ; GO SHIFT IF ODD MOV TMP3,R0 ; MUST SAVE THE FRACTION ADD #10,R0 ; POINT TO FAC+1 MOV R2,(R0)+ ; SAVE THE FRACTION IN FAC+1 MOV R3,(R0)+ MOV R4,(R0)+ MOV R5,(R0) ; DONE MOV R1,EFAC ; SAVE THE SHIFT COUNT MOV 2(SP),EFSRC ; SAVE A COPY OF THE SIGN MOV TMP3,R0 ; POINT TO FAC AGAIN DEC MODFLG ; FLAG EVEN FAC PROCESSING MODSH: CMP R1,#16. ; CAN WORDS BE SHIFTED? BLE MODSS ; NO MOV R3,R2 ; SHIFT WORDS MOV R4,R3 MOV R5,R4 CLR R5 ; CLEAR OUT BOTTOM WORD SUB #16.,R1 ; ADJUST SHIFT COUNT BR MODSH MODSS: CMP R1,#8. ; SHIFT BY BYTE? BLE MODSS1 ; NO SWAB R2 ; SHIFT LEFT ONE BYTE CLRB R2 SWAB R3 BISB R3,R2 CLRB R3 SWAB R4 BISB R4,R3 CLRB R4 SWAB R5 BISB R5,R4 CLRB R5 ; CLEAR OUT BOTTOM BYTE SUB #8.,R1 ; ADJUST SHIFT COUNT MODSS1: ASL R5 ; SHIFT LEFT ROL R4 ROL R3 ROL R2 ; DONE DEC R1 ; CHANGE COUNT BGT MODSH ; SHIFT TILL PAST THE INTEGER BCS MODSHD ; DONE SHIFTING IF NORMAL BIT FOUND MODSH1: INC (SP) ; BUMP SHIFT COUNT CMP (SP),TMP2 ; ANY NEED TO LOOK FURTHER FOR NORMAL BIT? BGT MODZEX ; NO, THERE IS NO FRACTION DEC R1 ASL R5 ROL R4 ROL R3 ROL R2 BCC MODSH1 ; KEEP LOOKING FOR NORMAL MODSHD: TST (SP)+ ; RESET STACK ADD #200,R1 ; PUT IN EXCESS 128. MODCF: CALL MULDMD ; GO PUT EXPONENT AND FRACTION TOGETHER TST MODFLG ; EVEN OR ODD FAC? BNE MODDUN ; BRANCH ON ODD -- JUST SAVE FRACTION CALL MODSAV ; FIRST, SAVE THE FRACTION MOV TMP3,R0 ; GET ADDRES OF FAC ADD #10,R0 ; FAC+1 MOV EFAC,R1 ; SHIFT COUNT MOV #4,R4 ; SETUP WORD COUNTER SUB #2,R1 ; ADJUST SHIFT COUNT BLT MODZIF ; BRANCH IF THE INTEGER IS 1 MOV #77777,R5 ; SETUP THE SHIFT MASK MODIC: CMP R1,#14. ; DETERMINE WHICH WORD NEEDS BITS MASKED BLE MODSHM ; R1 LESS MEANS MASK IN THIS WORD TST (R0)+ ; BYPASS THIS WORD DEC R4 ; DECREMENT WORD COUNT SUB #16.,R1 ; ADJUST SHIFT COUNT BLT MODZIF ; BRANCH IF ENTIRE WORD TO BE ZEROED BR MODIC ; NEXT WORD MODSHM: NEG R1 ; SHIFT RIGHT ASH R1,R5 ; SHIFT THE MASK RIGHT BIC R5,(R0)+ ; CLEAR OUT FRACTION BITS DEC R4 ; REDUCE WORD COUNT BEQ MODZD ; BRANCH DONE MODZIF: CLR (R0)+ ; CLEAR REMAINING FRACTION BITS DEC R4 ; DECREMENT WORD COUNT BNE MODZIF ; ZERO UNTIL DONE MODZD: MOV EFAC,R1 ; GET THE EXPONENT ADD #200,R1 ; EXCESS 128. BACK MOV -(R0),R5 ; PUT THE INTEGER FRACTION IN REGISTERS MOV -(R0),R4 MOV -(R0),R3 MOV -(R0),R2 ; DONE PUSH EFSRC ; SIGN TO STACK CALL MULDMD ; ASSEMBLE THE INTEGER CALL MODSAV ; SAVE THE INTEGER JMP ADDOUT ; GO FINISH MODZEX: TST (SP)+ ; RESET STACK CLR R1 CLR (SP) ; SET THE SIGN TO ZERO BR MODCF ; GO ASSEMBLE FRACTION MODSAV: MOV R2,(R0)+ ; SAVE THE FRACTION OR INTEGER MOV R3,(R0)+ BIT #200,@2(SP) ; **** RIGHT IN SPIRIT ONLY BEQ 10$ ; **** MOV R4,(R0)+ MOV R5,(R0) ; SAVED RETURN 10$: TRKTST @2(SP),20$ ROL R4 ADC -(R0) ADC -(R0) 20$: RETURN ; GO FINISH UP MODFLG: 0 ;---------------------------------------------------------------- .SBTTL 7.5 SUBF,ADDF ;---------------------------------------------------------------- SUBFX3: ADD R5,R4 ; PROPER AC SUBFX2: ADD R5,R4 ; PROPER AC SUBFX1: ADD R5,R4 ; PROPER AC SUBFX: TST (R4)+ ; AC0 CLR FXM ; CLEAR FPE FLAG MOV R4,TMP3 ; SAVE POINTER TO AC CALL GET ; ADD #100000,NUMB ; CHANGE SIGN OF FSRC BR ADSUBE ; GO ADD ;------------------------------------------------------------------ ADDGET: MOV R4,TMP3 ; SAVE POINTER TO AC CALL GET ; GET IT ADSUBE: MOV TMP3,R5 ; ADDRESS OF FAC PUSH R0 ; SAVE FPSW POINTER CLR -(SP) ; SAVE SIGNS ON STACK MOV #NUMB+ASF3+2,R4 ; POINT TO SECOND WORD OF FSRC BIT #200,(R0) ; CHECK FOR DOUBLE BEQ ADDF ; BRANCH IF FLOATING CMP (R4)+,(R4)+ ; POINT TO BOTTOM OF DOUBLE FSRC JMP ADDDX ; GO DO DOUBLE ADD ADDDM0: MOV (R2)+,(R4)+ ; SAVE THE FSRC IN SCRATCH AREA MOV (R2)+,(R4)+ MOV (R2)+,(R4)+ MOV (R2),(R4) JMP ADDDX ; GO ADD ADDFX3: ADD R5,R4 ; PROPER AC ADDFX2: ADD R5,R4 ; PROPER AC ADDFX1: ADD R5,R4 ; PROPER AC ADDFX: TST (R4)+ ; AC0 CLR FXM ; FPE FLAG CLEARED BIT #70,R2 ; CHECK FOR MODE 0 BNE ADDGET ; BRANCH IF NOT MODE0 BIC #77770,R2 ; CLEAR ALL BIT REGISTER AND MSB ASL R2 ; SHIFT TO GET AN OFFSET ROL R2 ; PUT IN ACRRY TO ADD 2 ASL R2 ADD R0,R2 ; NOW HAVE THE FSRC POINTER MOV R4,R5 ; NEW POINTER TO FAC MOV R4,TMP3 ; SAVE POINTER TO AC MOV #NUMB+ASF3,R4 ; SAVE THE FSRC IN SCRATCH PUSH R0 ; SAVE FPSW POINTER CLR -(SP) ; SAVE SIGNS ON STACK BIT #200,(R0) ; CHECK FOR FLOATING OR DOUBLE BNE ADDDM0 ; BRANCH ON DOUBLE MOV (R2)+,(R4)+ MOV (R2),(R4) ADDF: CLR R2 ; CLEAR PLACE FOR EXPONENTS CLR R3 ; ASL (R4) ; SHIFT FSRC ROL -(R4) ; BISB 1(R4),R3 ; R3 HAS EXP. OF FSRC BEQ ADOUT ; FSRC=0 MEANS WE'RE FINISHED ROLB (SP) ; NO SUCH LUCK -- SAVE THE SIGN ASL 2(R5) ; SHIFT FAC ROL (R5) ; BISB 1(R5),R2 ; R2 HAS EXP. OF FAC BNE ADA2NZ ; IF NOT ZERO GO CONTINUE RORB (SP) ; RECREATE FSRC ROR (R4) ; ROR 2(R4) ; HAVE IT AGAIN MOV (R4)+,(R5)+ ; MOVE FSRC TO FAC SINCE THAT IS ANSWER MOV (R4),(R5) ; BR ADOUT ; ALL DONE ADA2NZ: ROLB 1(SP) ; SAVE SIGN OF FAC IN HIGH BYTE OF STACK MOVB #1,1(R4) ; PUT IN HIDDEN BIT AND CLEAR OUT EXP. MOVB #1,1(R5) ; IN BOTH FSRC AND FAC SUB R3,R2 ; SUBTRACT EXP.S -- R2/EFAC-EFSRC BGT ADEXPA ; BRANCH IF FAC HAS BIG EXPONENT MOV (R5),R0 ; FAC HAS LITTLE EXP. -- MOV FRAC TO REGS. MOV 2(R5),R1 ; R0!R1 HAS THE FRAC OF THE ; NUMBER WITH THE SMALLEST MAGNITUDE MOV (R4)+,(R5) ; MOVE LARGE MAGNITUDE NUMBER TO FAC MOV (R4),2(R5) ; DONE BR ADECHK ; GO CHECK SIGNS ADEXPA: ADD R2,R3 ; R3 CONTAINS LARGEST EXP. MOV (R4)+,R0 MOV (R4),R1 ; R0!R1 HAS FRAC OF SMALLEST NUMBER (ABS) NEG R2 ; R2 IS TO BE RIGHT SHIFT AMOUNT SWAB (SP) ; SIGN OF BIG NUMBER ON THE RIGHT ADECHK: CMPB 1(SP),(SP) ; SIGNS EQUAL? BEQ 10$ ; BRANCH IF SO NEG R1 ; NEGATE ADC R0 NEG R0 CLR TMP2 ; CARRY SAVER 10$: TST R2 ; SHIFT AMOUNT BEQ ADSHTD ; NONE NEEDED ---> BRANCH CMP #-25.,R2 ; IS IT WORTH IT TO SHIFT? BGT ADNRMD ; NO -- ANSWER IS THE BIG NUMBER ASHC R2,R0 ; DO THE SHIFT ROR TMP2 ; SAVE THE CARRY ADSHTD: ADD R0,(R5)+ ; ADD THINGS UP ADD R1,(R5) ADC -(R5) ; DONE CMPB 1(SP),(SP) ; COMPARE SIGNS BNE ADSUB ; IF NOT SAME GO CLEAN UP BIT (R5),#1000 ; WAS THERE A CARRY PAST NORMAL BIT? BEQ ADNRMD ; BRANCH IF NOT ASR (R5) ; SHIFT RIGHT ROR 2(R5) ; INC R3 ; BUMP EXPONENT ADNRMD: BIT #177400,R3 ; TEST FOR OVERFLOW BEQ ADOK ; BRANCH ON NO OVERFLOW CALL OVER ; HANDLE OVERFLOW ADOK: MOVB R3,1(R5) ; PUT EXP IN FAC ROR (SP) ; PUT IN SIGN OF BIG NUMBER ROR (R5)+ ; PUT SIGN IN FAC ROR (R5) ; TRKTST @2(SP),ADOUT ; CHECK TRUNCATE -- BRANCH IF SET ADC (R5) ; ADC -(R5) ; BVC ADNOV ; CHECK FOR OVERFLOW CALL OVER ; ADNOV: BCC ADOUT CALL OVER ; ADOUT: TST (SP)+ ; RESET STACK ADDOUT: POP R0 ; RETURN FPSW POINTER MOV @TMP3,NUMB ; GET READY FOR C.C. TEST TST FXM ; WAS THERE AN FPE? BNE 10$ ; INVESTIGATE FURTHER IF THERE WAS JMP TSTFY ; IF NOT, LEAVE 10$: BIT FXM,(R0) ; WAS THE INTERRUPT ENABLED? BEQ ADOUT2 ; BRANCH IF NOT BIS #100000,(R0) ; INTERRUPT BIT WAS SET ADDDIV: BIT #40000,(R0) ; WAS THE INHIBIT INTERRUPT BIT SET? BR ADOUT3 ; YES -- LEAVE TST NUMB ; SET N AND Z BITS AS APPROPRIATE BGE 10$ ; NOT NEGATIVE BIS #10,(R0) ; SET N 10$: BNE 20$ ; NOT ZERO BIS #4,(R0) ; SET Z .IF DF,F$$AST 20$: MOV @#244,16(SP) ; PUT ADDRESS ON TOP OF KPAR3 .IFF ;NO ACTION 20$: .ENDC JMP FPEOUT ; GO INTERRUPT ADOUT2: CMP #12,FPXCOD ; WAS THERE AN UNDERFLOW? BNE ADOUT3 ; BRANCH IF NOT MOV TMP3,R1 ; GET FAC ADDRESS CLRWRD 4,(R1) ; CLEAR THE FAC BIC #17,(R0) ; CLEAR CC'S CLR NUMB ADOUT3: JMP TSTFY2 ; GO SET C.CS WITHOUT CLEARING ADSUB: TST (R5) ; TEST SIGN OF RESULT BGT ADBIT9 ; IF POSITIVE SIGN IS OK BEQ ADZTST ; CHECK FOR ZERO RESULT NEG 2(R5) ; GET ABSOLUTE VALUE ADC (R5) ; NEG (R5) ; SWAB (SP) ; SWITCH SIGNS ADBIT9: BIT (R5)+,#400 ; CHECK FOR NORMAL BIT BNE ADUTST ; BRANCH IF FOUND DEC R3 ; DECREASE EXPONENT ASL TMP2 ; GET CARRY ROL (R5) ; DOUBLE FRACTION ROL -(R5) ; BR ADBIT9 ; CHECK FOR NORM BIT AGAIN ADZTST: TST (R5)+ ; POINT TO SECOND WORD TST (R5) ; CHECK FOR ZERO HERE BEQ ADZERO ; IT'S ZERO ALRIGHT SWAB (R5) ; SAVE NORMALIZE SOME TIME BISB (R5),-2(R5) ; MOVE BITS TO THE LEFT CLRB (R5) ; TST -(R5) ; POINT TO TOP OF FAC SUB #10,R3 ; ADJUST THE EXPONENT BR ADBIT9 ; ADUTST: TST -(R5) ; BUMP POINTER TST R3 ; UNDERFLOW OCCUR? BGT ADNRMD ; NO -- GO FINISH UP CALL UNDER ; UNDERFLOW FLAGS SET BR ADOK ; CONTINUE PROCESSING ADZERO: CLR (R5)+ ; PUT IN ZERO CLR (R5) ; BR ADOUT ; DONE ;---------------------------------------------------------------- .SBTTL 7.6 ADDD ;---------------------------------------------------------------- ADDDX: CLR EFSRC ; CLEAR OUT EXPONENTS CLR EFAC ; ASL (R4) ; SHIFT FSRC ROL -(R4) ; ROL -(R4) ; ROL -(R4) ; BISB 1(R4),EFSRC ; GET EXPONENT OF FSRC BEQ ADDA1Z ; IF 0 ARE ESSENTIALLY DONE ROLB (SP) ; SAVE SIGN ADD #6,R5 ; POINT TO BOTTOM OF FAC ASL (R5) ; SHIFT FAC ROL -(R5) ; ROL -(R5) ; ROL -(R5) ; BISB 1(R5),EFAC ; SAVE EXPONENT OF FAC BNE ADD2NZ ; BRANCH IF NOT 0 RORB (SP) ; RECONSTRUCT THE FSRC ROR (R4)+ ; ROR (R4)+ ; ROR (R4)+ ; ROR (R4) ; ADD #6,R5 ; POINT TO BOTTOM OF FAC MOV (R4),(R5) ; MOVE FSRC TO FAC MOV -(R4),-(R5) ; MOV -(R4),-(R5) ; MOV -(R4),-(R5) ; ADDA1Z: TST (SP)+ ; GET RID OF SIGNS .IIF NDF STAT BR ADDOUT ; GO FINISH .IIF DF STAT JMP ADDOUT ADD2NZ: ROLB 1(SP) ; SAVE SIGN OF FAC MOVB #1,1(R4) ; PUT IN HIDDEN BIT AND CLEAR OUT EXP. MOVB #1,1(R5) ; SUB EFSRC,EFAC ; SUBTRACT EXPONENTS BGT ADDEXA ; BRANCH IF EFAC IS LARGEST MOV (R5)+,R0 ; MOVE SMALLER # INTO REGISTERS MOV (R5)+,R1 ; (IT IS FAC IN THIS CASE) MOV (R5)+,R2 ; BY SMALLER, I MEAN SMALLER ABSOLUTE VALUE MOV (R5),R3 ; ADD #6,R4 ; POINT TO BOTTOM OF FSRC MOV (R4),(R5) ; MOVE FSRC TO FAC MOV -(R4),-(R5) ; MOV -(R4),-(R5) ; MOV -(R4),-(R5) ; MOV EFSRC,R4 ; R4 HAS THE LARGEST EXPONENT BR ADDSCK ; GO CHECK SIGN ADDEXA: MOV (R4)+,R0 ; MOV FSRC TO REGISTERS MOV (R4)+,R1 ; NOTE THAT IT IS THE SMALLER NUMBER MOV (R4)+,R2 ; MOV (R4),R3 ; MOV EFAC,R4 ; R4 HAS THE LARGEST EXPONENT ADD EFSRC,R4 ; ADD WHAT WAS TAKEN AWAY SWAB (SP) ; SWITCH SIGNS NEG EFAC ; MAKE ROTATE COUNT NEGATIVE ADDSCK: CMPB 1(SP),(SP) ; CHECK FOR SAME SIGNS BEQ ADDECK ; NEG R3 ; NEGATE SMALL NUMBER ADC R2 ; ADC R1 ADC R0 NEG R2 ADC R1 ADC R0 NEG R1 ADC R0 NEG R0 ; DONE CLR TMP2 ; CARRY HOLDER ADDECK: TST EFAC ; TEST SHIFT COUNT BEQ ADDSHD ; IF 0 SKIP ALL THE SHIFT BUSINESS CMP #-57.,EFAC ; IS THE SMALL NUMBER JUST TOO SMALL? BLE ADDSHT ; NO -- GO SHIFT MOVB R4,1(R5) ; RECONSTRUCT LARGE NUMBER ROR (SP)+ ; GET SIGN ROR (R5)+ ; ROR (R5)+ ROR (R5)+ ROR (R5) ; DONE JMP ADDOUT ; GO FINISH UP ADDSHT: CMP #-8.,EFAC ; SEE HOW MANY BITS ARE TO BE SHIFTED BLE ADDSR8 ; BRANCH IF NOT MORE THAN 1/2 WORD TST R0 ; CONTINUE HERE IF MORE THAN THAT SXT -(SP) ; PUT THE SIGN EXTENSION ON THE STACK ADDSH1: CMP #-16.,EFAC ; ONE WORD? BLT ADDS16 ; BRANCH IF NOT MORE THAN 1 WORD TO SHIFT MOV R3,TMP2 ; SAVE THE LOW ORDER WORD (CARRY INFO) MOV R2,R3 ; SHIFT ONE WORD AT A TIME MOV R1,R2 MOV R0,R1 MOV (SP),R0 ; INSERT SIGN EXTEND ADD #16.,EFAC ; UPDATE THE EXPONENT BNE ADDSH1 ; GO TRY TO DO IT AGAIN TST (SP)+ ; IF 0, SHIFTING IS ALL DONE ASL TMP2 ; SET CARRY BIT RIGHT BR ADDSHD ; HENCE BEHAVE THAT WAY ADDS16: CMP #-3,EFAC ; HOW MANY TO SHIFT NOW? BLE ADDS8A ; BRANCH IF NOT MORE THAN 3 MOV R5,(SP) ; SAVE R5 OVER TOP OF SIGN EXTEND PUSH R4 ; SAVE EXPONENT PUSH EFAC ; PUT SHIFT AMOUNT ON STACK MOV R1,R4 ; SAVE R1 ASHC (SP),R0 ; SHIFT HIGH ORDER MOV R2,R5 ; SAVE R2 ASHC (SP),R4 ; SHIFT DOUBLE REG. MOV R2,R4 ; MOV R5,R2 ; R2 DONE MOV R3,R5 ; SET UP LOW ORDER ASHC (SP)+,R4 ; DO LOW ORDER MOV R5,R3 ; POP R4 ; RETURN EXPONENT POP R5 ; RETURN POINTER TO FAC BR ADDSHD ; DONE WITH SHIFT ADDS8A: TST (SP)+ ; GET STACK RIGHT ADDSR8: ASR R0 ; SHIFT RIGHT UNTIL FINISHED ROR R1 ; ROR R2 ROR R3 ; INC EFAC ; SHIFT COUNTER INCEMENTED BLT ADDSR8 ; ADDSHD: ROR TMP2 ; SAVE THE CARRY BIT ADD #6,R5 ; POINT TO BOTTOM OF FAC ADD (R5),R3 ; DO THE ADDITION ADC R2 ADC R1 ADC R0 ADD -(R5),R2 ADC R1 ADC R0 ADD -(R5),R1 ADC R0 ADD -(R5),R0 ; ADDITION IS DONE CMPB 1(SP),(SP) ; CHECK FOR SAME SIGNS BNE ADDSUB ; GO FIXUP SUBTRACT BIT #1000,R0 ; WAS THERE CARRY INTO EXP PART BEQ ADDNRD ; BRANCH IF NOT ASR R0 ; SHIFT RIGHT ROR R1 ROR R2 ROR R3 INC R4 ; ADJUST THE EXPONENT ADDNRD: SWAB R4 ; MOVE EXPONENT TO HIGH BYTE BEQ ADDNFL ; BRANCH IF NO OVERFLOWN EXPONENT CALL OVER ADDNFL: BISB R0,R4 ; R4 NOW HAS FIRST WORD ROR (SP)+ ; GET THE SIGN ROR R4 ; PUT THE SIGN IN ROR R1 ROR R2 ROR R3 TRKTST @(SP),ADDPUT ; CHECK TRUNCATE -- BRANCH IF SET ADC R3 ; ROUND IT ADC R2 ADC R1 ADC R4 ; ROUNDING DONE TSTOVF ; CHECK FOR OVERFLOW ADDPUT: MOV R4,(R5)+ ; PUT THE ANSWER IN THE FAC MOV R1,(R5)+ ; MOV R2,(R5)+ MOV R3,(R5) JMP ADDOUT ; GO CHECK FOR ERRORS,INTERRUPTS,C.C'S ADDSUB: TST R0 ; CHECK SIGN OF RESULT BGT ADDBT9 ; POSITIVE IS O.K. BEQ ADDZT ; CHECK FOR ZERO NEG R3 ; IT IS NEGATIVE -- TAKE ABS. VALUE ADC R2 ADC R1 ADC R0 NEG R2 ADC R1 ADC R0 NEG R1 ADC R0 SWAB (SP) ; SWITCH SIGN NEG R0 BEQ ADDZT ; CHECK FOR ZERO ADDBT9: BIT R0,#400 ; CHECK FOR NORMAL BIT BNE ADDUT ; GO CHECK FOR UNDERFLOW WHEN FOUND DEC R4 ; REDUCE EXPONENT ASL TMP2 ; ROLL BACK CARRY INFO ROL R3 ; DOUBLE FRACTION ROL R2 ROL R1 ROL R0 BR ADDBT9 ; GO LOOK FOR NORMAL BIT AGAIN ADDZT: SUB #8.,R4 ; REDUCE EXPONENT TST R1 ; BNE ADDZT1 ;BRANCH IF ONLY R0=0 SUB #16.,R4 ; REDUCE EXPONENT AGAIN MOV R2,R1 ; BNE ADDZT2 ; BRANCH IF R2 NOT 0 SUB #16.,R4 ; TST R3 ; TEST LAST WORD BEQ ADDZRO ; IT IS ZERO BISB R3,R1 ; MOVE BYTES TO R0,R1 SWAB R1 SWAB R3 ; BISB R3,R0 ; CLR R3 ; MAKE ALL OTHERS 0 BR ADDBT9 ; ADDZT2: MOV R3,R2 ; CLR R3 ; ADDZT1: SWAB R1 ; BISB R1,R0 ; MOVE ALL BYTES LEFT CLRB R1 ; SWAB R2 BISB R2,R1 ; CLRB R2 SWAB R3 BISB R3,R2 CLRB R3 BR ADDBT9 ; ADDUT: TST R4 ; WAS THERE UNDERFLOW? BGT ADDNRD ; BRANCH IF NOT CALL UNDER ; UNDERFLOW BR ADDNFL ; CONTINUE ADDZRO: CLR (SP) ; SET SIGN PLUS CLR R4 ; CLEAR EXPONENT BR ADDNFL EFSRC: 0 EFAC: 0 ;---------------------------------------------------------------- .SBTTL 7.7 CMPF,STF,DIVF ;---------------------------------------------------------------- CMPFX3: ADD R5,R4 ; PROPER AC CMPFX2: ADD R5,R4 ; PROPER AC CMPFX1: ADD R5,R4 ; PROPER AC CMPFX: TST (R4)+ ; AC0 MOV R4,TMP3 ; SAVE POINTER TO AC CALL GET ; GET THE NUMBER MOV TMP3,R4 ; ADDRES OF FAC MOV #NUMB+ASF3,R5 ; ADDRESS OF (FDEST) MOV (PC),R3 ; 00XXXX...XXXX01 MOV (R5)+,R1 ; GET HIGH ORDER OF FIRST BGE CMPPOS ; BRANCH IF FIRST NUMBER + ASL R3 ; REMEMBER FIRST NUMBER - MOV (R4)+,R2 ; GET HIGH ORDEROF SECOND BLT CMPSAM ; BRANCH IF BOTH ARE SAME BR CMPNEG ; RESULT IS NEGATIVE CMPPOS: MOV (R4)+,R2 ; GET HIGH ORDER OF SECOND BLT CMPPLS ; RESULT IS + CMPSAM: CMP R1,R2 ; COMPARE HIGH ORDERS BNE CMPOUT ; NOT EQUAL CMP (R5)+,(R4)+ ; NEXT WORD BNE CMPOUT ; BIT #200,(R0) ; CONTINUE COMPARING? BEQ CMPCLR ; NO -- THE FLOATING NUMBERS ARE EQUAL CMP (R5)+,(R4)+ ; THIRD WORD BNE CMPOUT CMP (R5),(R4) ; LAST BNE CMPOUT CMPCLR: CLR R3 ; FLAG AS EQUAL CMPOUT: ROR R3 ; SAVE C AND TEST SECOND ARG - BCS CMPPLS ; SET + CMPNEG: NEG R3 ; REVERSE C BIT CMPPLS: TST R3 ; SET CONDITION CODES MOV @#PSW,R2 ; COPY THEM BIC #^C17,R2 ; CLEAR ALL BUT CONDITION CODES BIC #17,(R0) ; CLEAR CURRENT C.C'S OUT BIS R2,(R0) ; SET NEW ONES JMP FPEX2 ; ALL DONE ;---------------------------------------------------------------- STFX3: ADD R5,R4 ; PROPER AC STFX2: ADD R5,R4 ; PROPER AC STFX1: ADD R5,R4 ; PROPER AC STFX: TST (R4)+ ; AC0 INC NMB ; WANT AN ADDRESS MOV R4,TMP3 ; SAVE POINTER TO AC CALL GET ; MOV TMP3,R2 ; AC ADDRESS BCS STFZ ; BRANCH IF MODE 0 STFY: MOVTU (R2)+,(R1)+ ; PUT NUMBER IN TASK AREA DEC TMP1 ; CHECK DONE BGT STFY JMP FPEX2 ; ALL DONE STFZ: MOV (R2)+,(R1)+ ; MOVE WITHIN HEADER DEC TMP1 BGT STFZ ; DONE? JMP FPEX2 ; YES ;---------------------------------------------------------------- DIVFX3: ADD R5,R4 ; PROPER AC DIVFX2: ADD R5,R4 ; PROPER AC DIVFX1: ADD R5,R4 ; PROPER AC DIVFX: TST (R4)+ ; AC0 CLR FXM ; CLEAR FPSW MASK MOV R4,TMP3 ; SAVE POINTER TO AC CALL GET ; GET IT PUSH R0 ; SAVE THE FPSW POINTER BIT #200,(R0) ; TEST MODE BEQ DIVF ; BRANCH IF SINGLE JMP DIVDX ; GO DO DOUBLE DIVIDE DIVF: MOV #NUMB+ASF3,R3 ; POINT TO FSRC (DENOMINATOR) MOV TMP3,R2 ; POINT TO NUMERATOR (FAC) CLR -(SP) ; MAKE ROOM FOR THE SIGN ASL (R3) ; GET SIGN OF DENOMINATOR ROL (SP) ; SAVE IT CLR -(SP) ; ROOM FOR THE EXPONENT BISB 1(R3),(SP) ; PUT EXPONENT ON STACK BEQ DIVCHK ; BRANCH ON DIVIDE BY 0 NEG (SP) ; NEGATE THE EXPONENT SWAB (R3) ; LEFT JUSTIFY THE DENOMINATOR SEC ; PUT IN THE NORMAL BIT ROR (R3)+ ; MOVB 1(R3),-2(R3) ; MOVE LEFT SWAB (R3) ; CLRB (R3) ; CLEAR OUT BOTTOM BYTE CLR R0 ; R0!R1 WILL HOLD NUMERATOR FRACTION CLR R1 ; ASL (R2) ; SHIFT NUMERATOR LEFT ADC 2(SP) ; GET FINAL SIGN BISB 1(R2),R1 ; GET EXPONENT OF NUMERATOR BEQ DIVZRO ; BRANCH IF ANSWER IS ZERO ADD R1,(SP) ; GET SUM OF EXPONENTS CLR R1 ; RESET R1 BISB (R2),R0 ; MOVE NUMERATOR FRACTION TO REGS. SWAB R0 ; (LEFT JUSTIFIED) SEC ; NORMAL BIT ROR R0 ; IN BISB 3(R2),R0 ; SECOND BYTE IN BISB 2(R2),R1 ; THIRD AND LAST BYTE IN SWAB R1 ; PROPER ORDER ROR R0 ; MAKE SURE NUMERATOR AND DENOM. PLUS ROR R1 ; ROR -(R3) ; ROR 2(R3) ; DONE CMP R0,(R3)+ ; COMPARE HI NUMER. AND DENOM. BCS DIVDHI ; BRANCH IF DENOM. BIGGER ROR R0 ; DIVIDE NUMERATOR BY 2 ROR R1 ; SO THAT IT IS LESS THAN DENOM. INC (SP) ; ADJUST EXPONENT DIVDHI: CLC ; CLEAR FOR ROTATES ROR (R3) ; MAKE LOW HALF OF DENOM PLUS TST -(R3) ; POINT TO FIRST WORD ROR R0 ; SCALE THE NUMERATOR FOR DIVIDE ROR R1 MOV R0,R4 ; NUMERATOR TO DIVIDEND MOV R1,R5 ; DIV (R3)+,R4 ; DIVIDE MOV R5,R1 ; SAVE REMAINDER MOV R4,R0 ; SAVE QUOTIENT MUL (R3),R4 ; GET Q*LO(DENOM) ASR R1 ; SCALE REMAINDER SUB R1,R4 ; Q*D-R ASHC #-1,R4 ; SCALE DIV -(R3),R4 ; (Q*D-R)/C NEG R4 ; ASHC #-14.,R4 ; UNSCALE ADD R0,R4 ; DIVNBT: ASHC #1,R4 ; BMI DIVNB ; BRANCH FOR NORMAL BIT DEC (SP) ; ADJUST EXPONENT BR DIVNBT ; KEEP LOOKING DIVNB: ASHC #-7,R4 ; ALIGN FRACTION MOV R4,(R2) ; SAVE HI ORDER ANSWER MOV (SP)+,R4 ; GET EXPONENT ADD #200,R4 ; PUT IN EXCESS 128. BGT DIVNU ; BRANCH ON NO UNDERFLOW CALL UNDER ; HANDLE UNDERFLOW DIVNU: CMP #377,R4 ; HOW ABOUT OVERFLOW? BGE DIVOK ; BRANCH IF NO OVERFLOW CALL OVER ; HANDLE OVERFLOW DIVOK: MOVB R4,1(R2) ; PUT EXPONENT IN ROR (SP)+ ; GET SIGN ROR (R2)+ ; SAVE IT ROR R5 ; MOV R5,(R2) ; SAVE THE SECOND WORD TRKTST @(SP),10$ ; CHECK TRUNCATE - BRANCH IF SET ADC (R2) ; ROUND ADC -(R2) ; TSTOVF ; TEST FOR OVERFLOW 10$: JMP ADDOUT DIVZRO: CMP (SP)+,(SP)+ ; GET RID OF SIGN AND EXPONENT CLRWRD 2,(R2) ; FORCE TO EXACTLY ZERO JMP ADDOUT ; GO FINISH AND EXIT DIVCHK: MOV #4,FPXCOD ; SET FEC CMP (SP)+,(SP)+ ; GET RID OF EXPONENT AND SIGN BIC #17,@(SP) ; CLEAR OUT CC'S BIS #100004,@(SP) ; SET Z BIT POP R0 ; RESTORE R0 MOV @TMP3,NUMB ; PLACE THIS FOR STATUS CHECK JMP ADDDIV ; LEAVE UNDER: MOV #12,FPXCOD ; SET FEC MOV #2000,FXM ; SET MASK BIC #17,@4(SP) ; CLEAR OUT OLD CC'S RETURN DIVDZR: CMP (SP)+,(SP)+ ; GET RID OF SIGN AND EXPONENT CLRWRD 4,(R4) ; SET TO ZERO JMP ADDOUT ; DONE ;--------------------------------------------------------------- .SBTTL 7.8 DIVD ;---------------------------------------------------------------- DIVDX: MOV TMP3,R4 ; POINTER TO FAC (NUMERATOR) MOV #NUMB+ASF3,R5 ; POINTER OT FSRC (DENOMINATOR CLR R0 ; R0!R1!R2!R3 TO CONTAIN NUM. FRACTION CLR R1 CLR R2 CLR R3 ASL (R5) ; SHIFT LEFT DENOMINATOR ROL -(SP) ; SAVE SIGN CLR -(SP) ; MAKE ROOM FOR EXPONENT BISB 1(R5),(SP) ; SAVE EXPONENT BEQ DIVCHK ; BRANCH ON DIVIDE BY ZERO NEG (SP) ; NEGATE EXPONENT SWAB (R5) ; LEFT JUSTIFY DENOMINATOR SEC ; PUT IN HIDDEN BIT ROR (R5)+ ; IN MOVB 1(R5),-2(R5) ; SHIFT LEFT SWAB (R5)+ ; MOVB 1(R5),-2(R5) SWAB (R5)+ MOVB 1(R5),-2(R5) SWAB (R5) ; DONE CLRB (R5) ; CLEAR LOW BYTE SUB #6,R5 ; POINT TO TOP OF FSRC ASL (R4) ; SHIFT NUMERATOR ADC 2(SP) ; GET FINAL SIGN BISB 1(R4),R3 ; GET EXPONENT OF NUMERATOR BEQ DIVDZR ; BRANCH IF ANSWER IS ZERO ADD R3,(SP) ; ADD EXPONENTS CLR R3 ; BISB (R4),R0 ; LEFT JUSTIFY NUMERATOR TO REGISTERS SWAB R0 ; SEC ; PUT IN NORMAL BIT ROR R0 BISB 3(R4),R0 BISB 2(R4),R1 SWAB R1 BISB 5(R4),R1 BISB 4(R4),R2 SWAB R2 BISB 7(R4),R2 BISB 6(R4),R3 SWAB R3 ; DONE CLRWRD 3,(R4) ; CLEAR FAC TO PREPARE FOR ANSWER CMP -(R4),-(R4) ; POINT BACK TO TOP OF FAC CMP R0,(R5)+ ; COMPARE NUMERATOR AND DENOMINATOR BHI DIVDDL ; BRANCH IF DENOM IS SMALLER BLO DIVDDH ; BRANCH IF DENOM IS LARGER CMP R1,(R5)+ ; TEST NEXT WORD BHI DIVDDL ; BRANCH DEN LO BLO DIVDDH ; BRANCH DEN HI CMP R2,(R5)+ ; COMPARE NEXT BHI DIVDDL ; BRANCH DEN LO BLO DIVDDH ; BRANCH DEN HI CMP R3,(R5) ; LAST WORD BHI DIVDDL ; BRANCH DEN LO BNE DIVDDH ; BRANCH DEN HI INC (SP) ; INCREMENT EXPONENT BR DIVDF1 ; SAME DIVDDL: ROR R0 ; DIVIDE NUMERATOR BY 2 ROR R1 ; WANT NUMER < DENOM ROR R2 ROR R3 INC (SP) ; ADD TO EXPONENT DIVDDH: PUSH #9. ; DO FIRST 9 QUOTIENT BITS CALL DIV ; GET PARTIAL QUOTIENT MOVB (SP),(R4) ; SAVE ALL BUT NORMAL BIT IN FAC TST (SP)+ ; MOVE PAST QUOTIENT TST (SP)+ ; DONE YET? BNE DIVDF1 ; BRANCH IF SO PUSH #16. ; GET NEXT WORD OF QUOTIENT CALL DIV TST (R4)+ ; POINT TO SECOND WORD OF FAC POP (R4)+ ; STORE SECOND WORD OF QUOTIENT TST (SP)+ ; DONE YET? BNE DIVDF1 ; BRANCH IF SO PUSH #16. ; GET NEXT WORD CALL DIV POP (R4)+ ; SAVE IN FAC TST (SP)+ ; DONE YET? BNE DIVDF1 ; YES PUSH #16. ; LAST WORD CALL DIV POP R3 ; LAST WORD TO R3 TST (SP)+ ; POP THE STACK BR DIVDFL DIVDF1: CLR R3 ; EMPTY LAST WORD DIVDFL: POP R2 ; GET EXPONENT MOV TMP3,R4 ; POINT TO TOP OF FAC ADD #200,R2 ; PUT EXCESS 128. INTO EXPONENT BGT DIVDNU ; BRANCH IF NO UNDERFLOW CALL UNDER ; SET UNDERFLOW DIVDNU: CMP #377,R2 ; CHECK FOR OVERFLOW BGE DIVDOK ; BRANCH IF NO OVERFLOW CALL OVER ; SET OVERFLOW FLAGS DIVDOK: MOVB R2,1(R4) ; PUT EXPONENT IN ROR (SP)+ ; GET SIGN ROR (R4)+ ; SAVE IT ROR (R4)+ ROR (R4)+ MOV R3,(R4) ; R3 HAS BOTTOM WORD OF ANSWER ROR (R4) TRKTST @(SP),10$ ; CHECK TRUNCATE - BRANCH IF SET ADC (R4) ; ROUND ADC -(R4) ADC -(R4) ADC -(R4) TSTOVF ; CHECK FOR OVERFLOW 10$: JMP ADDOUT ; GO FINISH DIV: MOV (SP),-(SP) ; COPY RETURN ADDRESS PUSH R4 ; SAVE FAC POINTER DIV1: MOV #NUMB+ASF3,R5 ; SET POINTER TO DENOMINATOR ASL R4 ; SHIFT LEFT QUOTIENT ASL R3 ; SHIFT LEFT NUMERATOR ROL R2 ROL R1 ROL R0 ; DONE BCS GO ; ALWAYS GOES FIRST TIME CMP (R5)+,R0 ; COMPARE DENOM AND NUMER BHI NOGO ; BRANCH IF DIVISOR LARGER BLO GO ; BRANCH IF DIVISOR SMALLER CMP (R5)+,R1 ; COMPARE LOW ORDERS SIMILARLY BHI NOGO BLO GO CMP (R5)+,R2 BHI NOGO BLO GO CMP (R5),R3 BHI NOGO BEQ NEQD ; BRANCH IF NUMER=DENOM GO: MOV #NUMB+ASF3+6,R5 ; POINT TO BOTTOM OF FAC SUB (R5),R3 ; NUMER=NUMER-DENOM SBC R2 SBC R1 SBC R0 SUB -(R5),R2 SBC R1 SBC R0 SUB -(R5),R1 SBC R0 SUB -(R5),R0 ; DONE WITH SUBTRACTION INC R4 ; SET A BIT IN THE QUOTIENT NOGO: DEC 6(SP) ; DECREMENT COUNT BGT DIV1 ; REPEAT PROCESS TILL DONE ALLDUN: MOV R4,4(SP) ; PUT QUOTIENT ON STACK POP R4 ; RETURN ORIGINAL R4 RETURN ; NEQD: INC R4 ; INSERT LAST 1 BIT IN QUOTIENT BR EQ1 EQ2: ASL R4 ; FINISH OUT QUOTIENT WITH 0'S EQ1: DEC 6(SP) ; DECREMENT COUNTER BGT EQ2 ; FINISHED? INC 6(SP) ; SET NO MORE NUMERATOR FLAG BR ALLDUN ; GO BACK ;--------------------------------------------------------------- .SBTTL 7.9 STEXP,STCFI ;---------------------------------------------------------------- STEXP3: ADD R5,R4 ; PROPER AC STEXP2: ADD R5,R4 ; PROPER AC STEXP1: ADD R5,R4 ; PROPER AC STEXPX: TST (R4)+ ; AC0 MOV (R4),R3 ; GET THE FIRST WORD OF THE # IN THE AC ASH #-7,R3 ; RIGHT JUSTIFY THE EXPONENT BIC #177400,R3 ; MAKE SURE THERE IS JUST THE EXPONENT SUB #200,R3 ; NOT EXCESS 200 ANYMORE MOV R3,TMP3 ; SAVE THE EXPONENT MOV #2,R5 ; SET FLAG FOR GETADDRESS ROUTINE INC NMB ; WANT AN ADDRESS CALL GETX ; GET THE ADDRESS BCS STEXPY ; MODE 0 BRANCH MOVTU TMP3,(R1) ; PUT EXPONENT IN TASK BR .+6 STEXPY: MOV TMP3,(R4) ; SAVE EXPONENT IN A GENERAL REGISTER TST TMP3 ; SET CONDTION CODES MOV @#PSW,R2 ; GET PSW STETST: BIC #177760,R2 ; CLEAR ALL BUT CONDITION CODES BIC #17,(R0) ; CLEAR ONLY CONDITION CODES IN FPSW BIS R2,(R0) ; PUT THE CODES IN FPSW BIC #17,PCOFF2+2(SP) ; BIS R2,PCOFF2+2(SP) ; SAVE THE CONDITON CODES IN USER PSW JMP FPEX2 ; DONE ;--------------------------------------------------------------- STCFI3: ADD R5,R4 ; PROPER AC STCFI2: ADD R5,R4 ; PROPER AC STCFI1: ADD R5,R4 ; PROPER AC STCFIX: TST (R4)+ ; AC0 CLR FXM ; CLEAR FE FLAG PUSH R2 ; SAVE THE DESTINATION FIELD MOV R4,R5 ; GET ADDRESS OF FAC MOV (R5)+,R1 ; FIRST WORD FROM FAC MOV (R5)+,R2 ; SECOND MOV (R5)+,R3 ; THIRD CLRB R3 ; DON'T NEED THIS LEAST SIGNIFICANT BYTE BISB R2,R3 ; MOVE BYTE 3 DOWN CLRB R2 ; CLEAR WHERE BYTE 3 WAS BISB R1,R2 ; MOVE BYTE 1 DOWN BIS #200,R2 ; MAKE SURE HIDDEN BIT IS THERE SWAB R2 ; R1/ BYTE1:BYTE2 SWAB R3 ; R2/BYTE3:BYTE4 ROL R1 ; ROLL SIGN OUT ROL R4 ; SAVE IT IN R4 CLRB R1 ; GET RID OF FRACTION SWAB R1 ; R1/ EXPONENT SUB #237,R1 ; MAKE EXP A SHIFT COUNT BGT STCK ; PROBABLE OVERFLOW -- GO CHECK CLC ; CLEAR CARRY ROR R2 ; MAKE POSITIVE ROR R3 ; (SINCE MOST SIG. BIT IS ROLLED RIGHT) CMP #-37,R1 ; IS THIS A NUMBER LESS THAN ONE? BGE STZERO ; YES -- GO SET IT TO 0 ASHC R1,R2 ; GET THE NUMBER IN R2 & R3 BIT #100,(R0) ; IS THIS INTEGER OR LONG MODE? BNE STLONG ; BRANCH ON LONG TST R2 ; THIS MUST BE ZERO FOR INTEGER BNE STOVER ; HANDEL OVERFLOW NEG R3 ; THIS SHOULD BE NEGATIVE BPL STOVER ; IF NOT, OVERFLOW BVC STISGN ; IF NOT 100000, BRANCH ROR R4 ; 100000 IS LEAGL OR NOT DEPENDING ON SGN BCC STOVER ; IF IT WAS POSITIVE IT IS AN OVERFLOW BR STIPUT ; GO PUT IT IN STISGN: ROR R4 ; GET APPROPRIATE SIGN FOR OTHER CASES BCS .+4 ; LEAVE IT NEGATIVE NEG R3 ; MAKE IT POSITIVE STIPUT: MOV R3,NUMB ; SAVE THE INTEGER POP R2 ; RESTORE THE DESTINATION MOV #4,R5 ; SET MAX. AUTO INC. INC NMB ; WANT AN ADDRESS MOV #100,R3 ; TEST LONG OR INTEGER CALL GET ; GET THE ADDRESS BCS STMZ ; GO DO MODE 0 MOV #NUMB+ASF3,R2 ; ADDRESS OF NUMBER(S) MOV TMP1,R5 ; SAVE THE WORD COUNT FOR LATER STP: MOVTU (R2)+,(R1)+ ; PUT NUMBER IN USER AREA SOB R5,STP ; DONE YET? STCTS: TST NUMB ; SET CONDITION CODES FOR RETURN MOV @#PSW,R2 ; SAVE THEM IN R2 DEC TMP1 ; ONE WORD O OR TWO? BEQ STCEC ; BRANCH IF ONE TST NUMB+2 ; IF TWO, MAKE SURE ENTIRE THING IS 0 BEQ STCEC ; BEFORE SETTING THE Z BIT BIC #4,R2 ; -- HERE CLEAR THE Z BIT SINCE WORD 2 ; IS NOT ZERO STCEC: TST FXM ; WAS A CONVERSION ERROR ENCOUNTERED? BEQ STETST ; NO -- GO SET CONDITION CODES & QUIT INC R2 ; SET CARRY BIT #400,(R0) ; DO WE INTERRUPT ON THIS CONDITION? BEQ STETST ; NO -- JUST HAVE THE CARRY SET BIT #40000,(R0) ; IS INHIBIT INTERRUPT BIT SET? BR STETST ; YES -- LEAVE BIC #177760,R2 ; CLEAR ALL BUT CC'S BIC #17,PCOFF2+2(SP) BIS R2,PCOFF2+2(SP) ; SET CC'S IN PSW FPE: BIS #100000,(R0) ; FLAG ERROR IN FPSW BIC #177760,R2 ; PUT CONDITION CODES IN FPSW BIC #17,(R0) ; CLEAR OUT OLD ONES BIS R2,(R0) ; THERE NOW .IF DF,F$$AST MOV @#244,16(SP) ; COVER KPAR3 WITH ADDRESS .ENDC JMP FPEOUT ; GO SET UP SO SYSTEM CAN MAKE AN AST STMZ: MOV NUMB,(R4) ; PUT NUMBER IN USER REGISTER BR STCTS ; * STLONG: ROR R4 ; GET THE SIGN BCC STLPUT ; BRANCH IF POSITIVE NEG R3 ; MAKE THE DOUBLE WORD NEGATIVE ADC R2 ; NEG R2 ; DONE STLPUT: MOV R2,NUMB ; SAVE THE LONG INTEGER MOV R3,NUMB+2 ; LOW ORDER IS SECOND BR STIPUT+4 ; GO GET ADDRESS ; STCK: DEC R1 ; IS THIS THE DOUBLE WORD MAX. NEGATIVE? BNE STOVER ; NO WAY NEG R2 ; IF SO, THIS MUST BE 100000 BVC STOVER ; BRANCH IF NOT TST R3 ; THIS WOULD NEED TO BE 0 BNE STOVER ; BRANCH IF NOT ROR R4 ; LAST REQUIREMENT IS SIGN BE NEGATIVE BCS STLPUT ; HOORAY -- IT IS -- GO PUT IT IN ; STOVER: MOV #6,FPXCOD ; PUT IN THE FEC INC FXM ; SET OVERFLOW FLAG STZERO: CLR NUMB ; PUT ZEROS IN CLR NUMB+2 ; BOTH WORDS BR STIPUT+4 ; GO GET ADDRESS AND STUFF ;--------------------------------------------------------------- .SBTTL 7.10 STCFD,LDCDF,LDEXP,LDCIF ;---------------------------------------------------------------- STCFD3: ADD R5,R4 ; PROPER AC STCFD2: ADD R5,R4 ; PROPER AC STCFD1: ADD R5,R4 ; PROPER AC STCFDX: TST (R4)+ ; AC0 MOV R4,TMP3 ; SAVE POINTER TO AC BIT R3,(R0) ; IS CURRENT MODE DOUBLE OR FLOAT BNE STCDFX ; CONVERT FROM DOUBLE TO FLOATING ASL R5 ; A.I. BY 10 INC NMB ; WANT AN ADDRESS CALL GET ; GET THE ADDRESS MOV TMP3,R2 ; GET ADDRESS OF FAC BCS STCFDY ; BRANCH ON MODE 0 MOVTU (R2)+,(R1)+ ; PUT THE NUMBER IN USER AREA MOVTU (R2)+,(R1)+ ; SECOND WORD CLR -(SP) ; FILL WITH ZEROES JSR PC,SETTRP MTPI (R1)+ ; IFERR ODAD1 ; CHECK FOR LEGAL ADDRESSES CLR -(SP) ; LAST WORD JSR PC,SETTRP MTPI (R1) ; DONE IFERR ODAD1 ; CHECK FOR LEGAL ADDRESSES JMP TSTFY ; GO SET CONDITION CODES STCFDY: MOV (R2)+,(R1)+ ; MOVE FAC TO FAC IN MODE 0 MOV (R2)+,(R1)+ ; CLRWRD 2,(R1) ; FILL WITH ZEROES STCFDZ: JMP TSTFY ; STCDFX: CLR FXM ; CLEAR FPE FLAG MOV R4,R5 ; GET FAC ADDRESS TRKTST (R0),STCDFY ; TEST TRUNCATE - BRANCH IF SET ROL 4(R5) ; ROUND ADC 2(R5) ; ADC (R5) ; ROUNDING COMPLETE BCS STCDFV ; BRANCH ON OVERFLOW BVS STCDFV ; STCDFY: MOV #4,R5 ; GET THE ADDRESS INC NMB ; WANT AN ADDRESS CALL GET MOV TMP3,R2 ; GET FAC ADDRESS AGAIN BCS STCDFZ ; BRANCH IF MODE IS 0 MOVTU (R2)+,(R1)+ ; MOVE NUMBER TO USER MOVTU (R2),(R1) ; STCDFB: TST FXM ; WAS THERE AN EXCEPTION? BNE .+6 ; BRACHH IF SO JMP TSTFY ; GO SET CONDITION CODES -- BIT #1000,(R0) ; INTERRUPT? BEQ STCDFO ; IF NOT LEAVE BIT #40000,(R0) ; INHIBIT ALL INTERRUPTS SET? BNE STCDFO ; IF SO, DON'T INTERRUPT MOV #6,R2 ; SET ZERO CONDITION CODE TST @TMP3 ; SEE ABOUT SETTING NEGATIVE BGE 10$ MOV #16,R2 10$: JMP FPE STCDFO: JMP TSTFY2 ; LEAVE V BIT SET STCDFV: INC FXM ; SET FEC FLAG ADD #100000,(R5) ; PUT SIGN RIGHT BIC #17,(R0) ; CLEAR CONDITION CODES BIS #2,(R0) ; AND SET V MOV #10,FPXCOD ; SET UP THE RIGHT FEC BR STCDFY ; CONTINUE NORMAL PROCESS STCDFZ: MOV (R2)+,(R1)+ ; MOVE FAC TO FAC MOV (R2),(R1)+ ; DONE CLRWRD 2,(R1) ; CLEAR OUT REMAINDER OF FAC BR STCDFB ;--------------------------------------------------------------- LDCDF3: ADD R5,R4 ; PROPER AC LDCDF2: ADD R5,R4 ; PROPER AC LDCDF1: ADD R5,R4 ; PROPER AC LDCDFX: TST (R4)+ ; AC0 MOV R4,TMP3 ; SAVE POINTER TO AC BIT R3,(R0) ; TEST MODE BNE LDCFDX ; BRANCH IF MODE IS DOUBLE ASL R5 ; INCREMENT REGISTERS BY 20/2 CALL GET ; GO GET NUMBER MOV #NUMB+ASF3,R5 ; R5 HAS ADDRESS OF NUMBER CLR FXM ; CLEAR FPE FLAG TRKTST (R0),LDCDFY ; IF TRNK SET, DON'T ROUND ROL 4(R5) ; ROUND ADC 2(R5) ; ADC (R5) ; BCS LDCDFV ; BRANCH ON OVERFLOW BVS LDCDFV ; LDCDFY: MOV TMP3,R2 ; R2 HAS ADDRESS OF FAC MOV (R5)+,(R2)+ ; MOV THE WORD IN MOV (R5),(R2)+ ; SECOND ONE CLRWRD 2,(R2) ; CLEAR OUT THE REST OF THE REGISTER BR STCDFB ; GO FINISH LDCDFV: INC FXM ; SET THE FPE FLAG MOV #10,FPXCOD ; PUT IN FEC BIC #17,(R0) ; CLEAR OUT CONDITION CODES BIS #2,(R0) ; SET THE V BIT ADD #100000,(R5) ; GET THE SIGN RIGHT BR LDCDFY ; CONTINUE WITH REGULAR PROCESSING LDCFDX: ASR R5 ; INCREMENT BY 4 CALL GET ; GET THE NUMBER MOV #NUMB+ASF3,R2 ; GET ADDRESS OF NUMBER MOV TMP3,R1 ; ADDRESS OF FAC JMP STCFDY ;--------------------------------------------------------------- LDEXP3: ADD R5,R4 ; PROPER AC LDEXP2: ADD R5,R4 ; PROPER AC LDEXP1: ADD R5,R4 ; PROPER AC LDEXPX: TST (R4)+ ; AC0 MOV #2,R5 ; NEED ONE NUMBER MOV R4,TMP3 ; SAVE POINTER TO AC CALL GETX ; GET IT MOV NUMB,R3 ; R3 HAS THE NUMBER BCC .+4 ; ASSUMING IT WAS NOT MODE 0 MOV (R4),R3 ; IF MODE 0, R3 GETS THE NUMBER HERE ADD #200,R3 ; CHANGE TO EXCESS 200 NOTATION ASH #7,R3 ; SHIFT IT TO PROPER POSITION BIC #100177,R3 ; CLEAR OUT ANY EXTRAS MOV TMP3,R5 ; R5 HAS ADDRESS OF AC BIC #077600,(R5) ; CLEAR OUT ANY EXISTING EXPONENT BIS R3,(R5) ; PUT THE NUW ONE IN MOV (R5),NUMB ; PREPARE TO SET CONDITION CODES JMP TSTFY ; GO DO IT ;--------------------------------------------------------------- LDCIF3: ADD R5,R4 ; PROPER AC LDCIF2: ADD R5,R4 ; PROPER AC LDCIF1: ADD R5,R4 ; PROPER AC LDCIFX: TST (R4)+ ; AC0 ASR R3 ; CHECK INTEGER OR LONG BIT IN FPSW ASR R5 ; MAX AUTO INCREMENT IS 4 MOV R4,TMP3 ; SAVE POINTER TO AC CALL GET ; MOV TMP3,R5 ; R5 HAS FAC ADDRESS MOV (R4),R2 ; PUT NUMBER IN R2 (MODE 0) BCS 10$ ; WAS IT RIGHT -- IF SO BRANCH MOV NUMB,R2 ; PUT NON MODE 0 NUMBER IN 10$: BIT #100,(R0) ; INTEGER OR LONG MODE? BNE LDCLF ; BRANCH IF LONG TST R2 ; CLEAR CARRY BIT BGT LDPOS ; BRANCH IF NUMBER IS POSITIVE BEQ LDZERO ; BRANCH IF NUMBER IS 0 NEG R2 ; NUMBER IS NEGATIVE -- MAKE IT POSITIVE LDPOS: ROL R4 ; SAVE THE SIGN IN R4 MOV #221,R3 ; R3 HAS MAX EXPONENT LDNORM: ASL R2 ; NORMALIZE THE INTEGER DEC R3 ; SUBTRACT ONE FROM EXP. FOR EACH SHIFT BCC LDNORM ; KEEP SHIFTING UNTIL FINISHED CLR 2(R5) ; CLEAR OUT SECOND WORD MOVB R2,3(R5) ; SAVE THE LOW ORDER FRACTION CLRB R2 ; CLEAR OUT LOW ORDER FRACTION BISB R3,R2 ; PUT IN EXPONENT SWAB R2 ; PUT EXPONENT ON RIGHT SIDE OF R2 ROR R4 ; LOAD SIGN INTO CARRY BIT ROR R2 ; PUT THE SIGN IN MOV R2,(R5)+ ; STORE FIRST WORD ROR (R5) ; SHIFT CARRY TO SECOND WORD TST (R5)+ ; POINT TO NEXT WORD BR .+6 ; CLEAR OUT REMAINING LDZERO: CLRWRD 4,(R5) ; CLEAR IT MOV R2,NUMB ; WANT TO SET CONDITION CODES JMP TSTFY ; GO DO IT LDCLF: BCS LD027 ; CLEAR SECOND WORD IF MODE 0 DEC TMP1 ; TMP1 IS WORD COUNT BEQ LD027 ; CLEAR SECOND WORD IF IMMEDIATE MODE MOV NUMB+2,R3 ; SECOND WORD IS FROM USER FOR ALL OTHERS BR .+4 ; CONTINUE LD027: CLR R3 ; SECOND WORD IS CLEARED TST R2 ; DECIDE THE SIGN BGT LDCPOS ; POSITIVE BEQ LDC0 ; UPPER HALF IS ZERO -- GO TEST LOWER NEG R3 ; MAKE A NEGATIVE NUMBER POSITIVE ADC R2 ; NEG R2 ; SEC ; SET FOR SIGN LDCPOS: ROL -(SP) ; SAVE SIGN ON THE STACK MOV #241,R4 ; SET MAX EXPONENT LDCNRM: DEC R4 ; DECREMENT EXPONENT FOR EACH SHIFT ASL R3 ; LOW ORDER ROL R2 ; HIGH ORDER BCC LDCNRM ; SHIFT UNTIL NORMALIZED CLR 4(R5) ; MAKE ROOM FOR RESULTS MOVB R3,5(R5) ; PUT IN LEAST SIGNIFICANT PART CLRB R3 ; MAKE ROOM BISB R2,R3 ; SECOND MOST SIGNIFICANT PART CLRB R2 ; MAKE ROOM BISB R4,R2 ; PUT IN EXPONENT SWAB R2 ; NOW PUT THINGS IN PROPER ORDER SWAB R3 ; SAME HERE ROR (SP)+ ; PUT SIGN IN CARRY BIT ROR R2 ; SHIFT EVERYTHING ONE TO PUT IN SIGN ROR R3 ; ROR 4(R5) ; ALL DONE MOV R2,(R5)+ ; PUT IN FIRST WORD MOV R3,(R5)+ ; PUT IN SECOND WORD BIT #200,(R0) ; WANT DOUBLE OR FLOATING? BEQ LDZERO+4 ; FOR FIX, ERASE THE LEAST SIGNIFICANT TST (R5)+ ; POINT TO LAST WORD OF FAC BR LDZERO+6 ; CLEAR LAST WORD OF FAC FOR DOUBLE LDC0: TST R3 ; IS THE WHOLE THING ZERO? BEQ LDZERO ; YES -- GO ZERO THE FAC BR LDCPOS ; NO -- IT'S JUST A SMALL NUMBER ; NUMB: .BLKW 4 TMP1: 0 TMP2: 0 TMP3: 0 NMB: 0 .SBTTL 8. GET ADDRESS OR NUMBERS FROM TASK ; THE UNIVERSAL SOURCE/DESTINATION GETTER ; ; IT'S PORPOSE IS TO GET THE NUMBER OR ADDRESS THAT IS NEEDED ; BY THE FLOATING POINT ROUTINES. ; ; R2 HAS A COPY OF THE INSTRUCTION ; R3 HAS THE FPSW MASK (SHORT OR LONG MODE REAL OR INTEGER) ; R5 IS THE MAXIMUM POSSIBLE AUTOINCREMENT COUNT ; GET: BIT R3,(R0) ; TEST APPROPRIATE BIT IN FPSR BNE GETX ; IT SHOULD BE MAX ASR R5 ; TOO BIG -- DIVIDE BY 2 GETX: .IF DF STAT ; STATISTICS BIT #200,(R0) BNE LSL BR GETT LSL:GETT: .ENDC MOV R5,TMP1 ; SAVE COUNT ASR TMP1 ; MAKE IT A WORD COUNT MOV R2,R3 ; BREAK SRC/DST APART BIC #177770,R2 ; R2 HAS THE REGISTER MOV SP,R4 ; COPY THE STACK POINTER FOR LATER USE TST (R4)+ ; ADD TWO SINCE WITHIN A SUBROUTINE MOV R2,TMP2 ; SAVE A COPY OF REG. # CMP #7,R2 ; PC ADDRESSING TAKES SPECIAL CARE BEQ PCADRM ; NEG R2 ; ALL REGS ARE ON THE STACK ADD #6,R2 ; COMPUTE THE OFFSET TO THEM ASL R2 ; ADD R2,R4 ; NOW R4 POINTS TO THE SELECTED REG. HAVREG: BIC #177707,R3 ; R3 HAS THE MODE BEQ MODE0 ; BRANCH IF MODE0 MOV (R4),R1 ; NOW FOR ALL CASES, R1 HAS THE REGISTER ; CONTENTS AND R4 HAS THE POINTER TO ; THAT REGISTER (STORED ON CURRENT STACK) ; ; NOW MODE CONSIDERATIONS ASR R3 ; MAKE THE MODE AN OFFSET ASR R3 ; ADD #MODAD+ASF3+2,R3 ; GET ADDRESS TO JMP TO JMP @-(R3) ; GO TO PROPER MODE HANDLING ROUTINE MODAD: MODE0+ASF3,MODE1+ASF3,MODE2+ASF3,MODE3+ASF3 MODE4+ASF3,MODE5+ASF3,MODE6+ASF3,MODE7+ASF3 ; PCADRM: MOV #2,R5 ; SET MAX INCREMENT AT 2 NEG R2 ; SET REGISTER=PC FLAG ADD #PCOFF2,R4 ; R4 POINTS TO PC BR HAVREG ; MODE0: MOV TMP2,R1 ; GET REGISTER NUMBER ASL R1 ; NEED AN OFFSET ASL R1 ASL R1 ADD R0,R1 ; NOW HAVE THE ADDRESS TST (R1)+ ; SKIP PAST STATUS TST NMB ; ADDRESS OR NUMBER BNE M0 MOV #NUMB+ASF3,R3 ; PUT IN NUMB ADD R5,PC ; BRANCH TO PROPER PLACE NOP BR 10$ BR 20$ NOP MOV (R1)+,(R3)+ MOV (R1)+,(R3)+ MOV (R1)+,(R3)+ MOV (R1),(R3) SEC RETURN 10$: MOV (R1),(R3)+ CLR (R3)+ CLR (R3)+ CLR (R3) SEC RETURN 20$: MOV (R1)+,(R3)+ MOV (R1),(R3)+ CLR (R3)+ CLR (R3) M0: SEC ; LET THE CALLER KNOW THIS IS MODE 0 RETURN MODE7: MFPI @PCOFF2+2(SP) ; GET OFFSET ADD (SP)+,R1 ; POP STACK TO GET FINAL ADDRESS ADD #2,PCOFF2+2(SP) ; INCREMENT PC TST R2 ; IF REGISTER IS PC -- TAKE CARE BGE M7C ADD #2,R1 ; THIS WAS CHANGED IN INSTR DECODING M7C: JSR PC,SETTRP .IF NDF,U$ID MFPI (R1) ; MODE 7 -- GET OTHER ADDRESS .IFF MFPD (R1) ; MODE 7 - GET OTHER ADDR FROM USER D SPC .ENDC IFERR ODAD1 ; ODD ADDRESS OR SEGMENT ERROR CATCHER POP R1 ; GOT IT BR NORA MODE6: MFPI @PCOFF2+2(SP) ; GET OFFSET ADD (SP)+,R1 ; POP STACK TO GET FINAL ADDRESS ADD #2,PCOFF2+2(SP) ; INCREMENT PC TST R2 ; IF REGISTER IS PC -- TAKE CARE BGE NORA ADD #2,R1 ; THIS WAS CHANGED IN INSTR DECODING .IIF DF STAT BR NORA MODE1:NORA: TST NMB ; WANT A NUMBER OR ADDRESS? BNE NONUM ; GO GET NUMBER GETNUM: MOV #NUMB+2+ASF3,R3 ; CLEAR OUT NUMB CLRWRD 3,(R3) MOV #NUMB+ASF3,R3 ; STORE THE NUMBERS MOV TMP1,R5 ; WORD COUNT PUTNUM: JSR PC,SETTRP .IF NDF,U$ID MFPI (R1)+ ; GET THE NUMBERS .IFF MFPD (R1)+ ; GET THE NUMBERS (FROM USER D SPACE) .ENDC IFERR ODAD1 ; CHECK FOR LEGAL ADDRESS POP (R3)+ ; SOB R5,PUTNUM ; STORE AS MANY AS NEEDED ON THE STACK NONUM: RETURN ; YES MODE3: JSR PC,SETTRP .IF NDF,U$ID MFPI (R1) ; GET OTHER ADDRESS .IFF MFPD (R1) ; GET OTHER ADDRESS OUT OF DATA SPACE .ENDC IFERR ODAD1 ; RECOVER FROM ODD ADR OR SEGMENT FAULT POP R1 ; THIS IS SECOND ONE ADD #2,(R4) ; UPDATE REGISTER BR NORA ; MODE2: ADD R5,(R4) ; UPDATE REGISTER MOV R5,TMP1 ; UPDATE WORD COUNT IN CASE IT IS MODE7 ASR TMP1 ; BYTES TO WORDS BR NORA ; MODE5: SUB #2,(R4) ; UPDATE REGISTER JSR PC,SETTRP SUB #2,R1 ; UPDATE ADDRESS .IF NDF,U$ID MFPI (R1) ; GET FIRST ADDRESS .IFF MFPD (R1) .ENDC IFERR ODAD1 ; IN CASE OF ERROR POP R1 ; GET SECOND ADDRESS BR NORA ; MODE4: SUB R5,(R4) ; UPDATE THE REGISTER SUB R5,R1 ; ADDRESS CHANGES TOO BR NORA ; GO FINISH ODDADR: ODAD1: MOV @#4,20(SP) ; SET UP ADDRESS (WIPE OUT KPAR3) TST (SP)+ ; FORGET ABOUT EVER RETURNING FPEOUT: MTPI SP ; GIVE THE USER HIS REGISTERS BACK POP R5 POP R4 POP R3 POP R2 .IF NDF,X$$HDR POP R1 POP R0 MOV #34340,@#PSW ; JMP @(SP)+ .IFF JMP FPEXIT .ENDC .END START