.TITLE FISEMU FIS EMULATOR FOR RSX-11M .IDENT '800921' .ENABL LC ; This program permanently installs the necessary code into an ; RSX-11M system to thereafter emulate the Floating Instruction ; Set (FIS) available on the PDP-11/40, /35 and LSI-11. ; ; No executive adaptation or resysgening is necessary. Simply ; run this program once as part of system startup and any task ; can then execute FIS instructions. ; ; This priveleged program creates a permanent dynamic region ; for holding the emulation code. It also patches one ; instruction into the illegal instruction trap processing ; routine of the executive and places a two instruction ; vector in executive pool for control transfer. ; ; ; To assemble: ; MAC FISEMU = [200,200]RSXMC/PA:1, [x,y]FISEMU ; ; ; To build: ; >TKB ; FISEMU/PR = FISEMU ; LB:[1,54]RSX11M.STB, [1,1]EXELIB/LB ; / ; WNDWS = 1 ; STACK = 50 ; // ; .NLIST BEX .MCALL QIOW$C, EXIT$S .MCALL CRRG$C, CRAW$C .MCALL RDBBK$, WDBBK$ .ENABL LSB START: CRRG$C RDB ; Create a region to hold code BCC 10$ ; BR on no directive error MOV @#$DSW,R0 IOT 10$: BIT #RS.CRR,RDB+R.GSTS ; Check if region created BNE 20$ QIOW$C IO.WVB,5,5,,,, ; Warning message BR 20$ M1: .ASCII 'Error creating FIS region -- probably already exits' .ASCII <15><12>'Program continuing' M1SZ = .-M1 .EVEN 20$: MOV RDB+R.GID,WDB+W.NRID ; Copy region ID CRAW$C WDB ; Create addr window and map BCC 30$ MOV @#$DSW,R0 IOT 30$: ; Copy the instruction processing code into the region MOV #CODE,R0 ; Addr of first word of code MOV WDB+W.NBAS,R1 ; Addr of first word of region MOV #CODESZ/2,R2 ; Number of words to move 40$: MOV (R0)+,(R1)+ ; Move word SOB R2,40$ ; Loop ; Complete the FIS vector block by adding the physical ; address of the region. MOV UISAR6,VBMAP ; Save the two word instruction in the executive's illegal ; instruction trap processing routine that we will be replacing ; by a JMP. Put the instruction into our processing code. MOV $ILINS+4,INS ; Instruction at $ILINS MOV $ILINS+6,INS+2 ; (Assume 2 word instruction) ; Switch to system state (Kernal mode on mapped systems) SWSTK$ 70$ ; Allocate pool space to hold FIS vector instructions MOV #VBSIZ,R1 ; Vector block size CALL $ALOCB BCS 60$ ; Br if cant allocate ; Copy the instruction of the FIS vector block into pool MOV #VB,R2 ; Addr of first word MOV R0,R3 ; Addr of pool block MOV #VBSIZ/2,R1 ; Number of words 50$: MOV (R2)+,(R3)+ ; Copy to allocated pool block SOB R1,50$ ; Loop ; Patch a JMP instruction to this code into the executive's ; illegal instruction trap processing routine. MOV #137,$ILINS+4 ; JMP @#VB instruction MOV R0,$ILINS+6 ; to $ILINS+4 CLC ; Clear carry means success 60$: ROR STAT ; Put carry bit into STAT RETURN ; Return to user state 70$: ; Tell operator of any possible failure BCC 80$ QIOW$C IO.WVB,5,5,,,, BR 80$ M2: .ASCII 'ERROR, pool allocation for FIS vector block failed' M2SZ = .-M2 .EVEN 80$: EXIT$S ; Finished ; Dynamic region should remain .DSABL LSB STAT: .WORD 0 ; Setup a Window Definition Block (WDB) WDB: WDBBK$ 6, 128.,, 0, 0, ; ; APR = 6 ; Size = 128. blocks (4K words) ; No region ID ; Offset for mapping = 0 ; Length for mapping = 0 (default) ; Status bits to do mapping with write access ; Define a Region Definition Block for the region that will ; hold the illegal instruction processing software. RDB: RDBBK$ <+1>,FIS,,,177717 ; ; Size = +1 big enough to hold all code ; Region name = 'FIS' ; Default system partition ; Status bits to attach with write access and ; to prevent deletion of region ; Default protection word = read/write for owner ; FIS Vector Block -- This is a block of instructions which ; are placed permanently in executive dynamic memory and is ; linked to by a JMP instruction patched into the executive's ; illegal instruction trap processing routine. ; The code in this block merely does some quick mapping and ; then transfers control to the actual trap processing ; routines in our specially prepared dynamic region. ; The code in this block MUST be position independent (PIC). VB: MOV #0,@#KISAR5 ; Set new APR5 mapping VBMAP = .-4 ; to our region JMP @#120000 ; Go to our trap routine VBSIZ = .-VB ; This is the code that processes our special 'illegal' instructions. ; This code is copied into a permanent region and is invoked ; by a JMP from our vector block code in executive pool. ; ; Every illegal instruction attempted on the processor will ; cause a hardware trap. The executive's trap processing ; is intercepted so that we can specially process some ; instructions for our application. In this case we are ; emulating the PDP-11/40 Floating Instruction Set (FIS). ; ; At entry, the DIRSV$ has already been done so all registers ; have been saved and the processor is at PR0 level in ; system state (Kernal mode). ; The stack holds the following: ; ; 16.(SP) = PS saved by trap ; 14.(SP) = PC saved by trap ; 12.(SP) = Saved R5 ; 10.(SP) = Saved R4 ; 8.(SP) = Saved R3 ; 6.(SP) = Saved R2 ; 4.(SP) = Saved R1 ; 2.(SP) = Saved R0 ; 0.(SP) = Return to $DIRSV ; ; ; The following code must be position independent (PIC) and ; must not exceed 4K words in length. CODE: ; Reject this instruction if the caller is in kernal mode BIT #40000,16.(SP) BNE NOKERN ; Br if not kernel mode ILEGAL:: INS: .WORD 0,0 ; Replaced exec instruction JMP @#$ILINS+10 ; Continue exec trap routine NOKERN: ; Determine if the illegal instruction is one that we wish ; to process MOV 14.(SP),R5 ; Get PC of task MFPI -(R5) ; Get the instruction MOV (SP)+,R0 ; In R0 MOV R0,R1 BIC #37,R0 ; Isolate non-variable part CMP R0,#075000 ; Is it an FIS instruction? BNE ILEGAL ; No, reject it MOV R1,R0 BIC #^C<7>,R1 ; Clear all but arg register field CMP R1,#6 ; Special case if register is R6 BNE 30$ MFPI SP ; Use MFPI to get contents of R6 MOV (SP)+,R2 BR 40$ 30$: ASL R1 ; Word offset for register ADD SP,R1 ; Get saved register from stack MOV 2(R1),R2 40$: ADD #8.,R2 ; Point above arg stack MFPI -(R2) ; Get two real numbers: MFPI -(R2) ; A MFPI -(R2) ; and MFPI -(R2) ; B MOV SP,R5 ; Point R5 to these ASR R0 ; Isolate instr qualifier field ASR R0 BIC #^C<6>,R0 ADD PC,R0 ADD #,R0 ; Point to entry in FINS table MOV (R0),R0 ; Subroutine addr (relocated) ADD PC,R0 SUB #.,R0 ; Subroutine addr (absolute) MOV R1,-(SP) ; Save R1 MOV R2,-(SP) ; Save R2 JMP (R0) ; Go to the FIS subroutine ; R5 points to real arguments ; Return here when divide by zero error encountered FINER: MOV SP,R3 ; Make R3 non-zero MOVB #13,R4 ; FIS condition codes BR FIN ; Return here when exponent overflow encountered FINOVR: MOVB #2,R4 ; Set V bit in user's PS BR FINO ; Return here when exponent underflow encountered FINUND: MOVB #12,R4 ; Set V & N bits in user's PS BR FINO ; Return here when FIS operation is successful and no ; overflow or underflow errors have occured. FINOK: TST 8.(SP) ; Test result high word MFPS R4 ; Save N and Z for user's PS FINO: CLR R3 FIN: MOV (SP)+,R2 ; Restore R2 MOV (SP)+,R1 ; Restore R1 ADD #4,SP ; Remove B ADD #4,R2 ; Point to A in user's arg stack MTPI (R2)+ ; Copy local A to user's A MTPI (R2) ; (this is the result) ; Adjust the user's argument stack: ; Normally only remove B, but in case of divide by zero ; error then leave stack untouched. TST R3 ; R3 <> 0 if divide by zero error BNE 30$ SUB #2,R2 ; Addr of user's A CMP R1,#6 ; Special case if arg is R6 BNE 10$ MOV R2,-(SP) MTPI SP ; Adjust user's R6 BR 20$ 10$: MOV R2,2(R1) ; Adjust user's arg register 20$: 30$: MOVB R4,16.(SP) ; Put status into user's PS ; If the V bit is set in the resulting status then an FIS error ; has occured and we must cause a floating point SST for the task. BIT #2,R4 ; Test V bit in result status BNE FISTRP ; Br if set RETURN ; Else no error just return ; Cause a floating point synchronous system trap for the task FISTRP: .IF DF F$$LTP ; If exec was sysgened with FIS ; then take advantage of ; existing code in exec. JMP @#$FLTRP+4 .IFF ; else reproduce necessary code MOV #S.CFLT,-(SP) ; Fault code JMP @#$TRP04+14 .ENDC FINS: ; Table of FIS subroutine addresses ADDR SUBR MULR DIVR ;******************************** SUBR **************************** SUBR: TST (R5) ; CHECK IF SUBTRACTING ZERO BNE 10$ ; BR IF NOT JMP FINOK ; RESULT := A 10$: ADD #100000,(R5) ; NEGATE REAL ON TOP ; NOW ADD THEM ;******************************* ADDR ******************************* ; ; REAL ADDITION: R := A + B ; ; INPUT: ; 6(R5), 4(R5) = A ; 2(R5), (R5) = B ; ; OUTPUT: ; R5 INCREMENTED BY 4 ; 2(R5), (R5) = R ADDR: TST (R5) ; B = ZERO ? BNE 1$ ; NO ADD #4,R5 ; YES, JUST SKIP IT BR ENDADR 1$: TST 4(R5) ; A = ZERO? BNE 2$ ; NO MOV (R5)+,2(R5) ; RESULT := B MOV (R5)+,2(R5) BR ENDADR 2$: CALL EXPTOP ; R1 := E(B) (EXPONENT OF B) ; R0(8) := SIGN OF B CALL EXPNTOP ; R2 := E(A) ; R0(0) := SIGN OF A ; REARRANGE NUMBERS IF NECER5ARY SO THAT SMALLER NUMBER ; IS IN (R5), 2(R5). CMP R2,R1 ;EXPONENTS EQUAL? BGT ADR2 BLT ADR1 CMP 4(R5),(R5) ;COMPARE FRACTIONS BMI ADR1 BGT ADR2 CMP 6(R5),2(R5) ;SECOND PART OF FRACTIONS BHIS ADR2 ADR1: MOV (R5)+,-(SP) ;WE HAVE TO INTERCHANGE A AND B MOV (R5)+,-(SP) MOV 2(R5),-(R5) MOV 2(R5),-(R5) MOV (SP)+,6(R5) MOV (SP)+, 4(R5) ;INTERCHANGE FRACTIONS MOV R2,-(SP) MOV R1,R2 MOV (SP)+,R1 ;INTERCHANGE EXPONENTS SWAB R0 ;INTERCHANGE SIGN BYTES ADR2: TST R0 ;BOTH SIGNS 'PLUS'? BEQ ADR3 CMP R0, #401 ;OR BOTH SIGNS 'MINUS'? BEQ ADR3 NEG 2(R5) ;NEGATE THE SMALLER FRACTION ADC (R5) NEG (R5) ADR3: CLR -(SP) ;CLEAR FOR CARRY BITS SUB R2, R1 BEQ ADR5 ;NO SHIFTING NEG R1 ;SHIFT COUNTER CMP R1, #26. ;BIG DIFFERENCE IN EXPONENTS? BPL ADR6 ;YES ADR4: ASR (R5) ROR 2(R5) ;DIVIDE BY 2^(E(A)-E(B)) ROR (SP) ;STORE CARRY BIT DEC R1 BNE ADR4 ;LOOP ADR5: ADD 2(R5),6(R5) ;ADD FRACTIONS ADC 4(R5) ADD (R5),4(R5) ADR6: CMP (R5)+,(R5)+ MOV (SP)+, R1 ;PUT CARRY BITS IN R1 CALL NORM ;NORMALIZE AND PACK IN (R5), 2(R5) ENDADR: JMP FINOK ;******************************* MULR ***************************** MULR: TST 4(R5) ;ZERO? BEQ MPR1 TST (R5) ;SECOND OPERAND ZERO? BNE MPR2 MPR1: CMP (R5)+,(R5)+ ;REMOVE SECOND OPERAND CLR (R5) CLR 2(R5) ;ZERO RESULT BR ENDMPR MPR2: CALL EXPTOP CALL EXPNTOP ;GET EXPONENTS IN R2,R3 ;AND SIGNS IN R0 ADD R1, R2 ;COMPUTE RAW EXPONENT ADD #10, R2 MOV R0,-(SP) ;SAVE SIGNS MOV #24.,-(SP) ;SHIFT COUNT CLR R0 CLR R1 MPR3: ASL R0 ;R0 = LEAST SIGNIFICANT PART ROL R1 ;THEN COMES R1, 6(R5) AND 4(R5) ROL 6(R5) ROL 4(R5) ;DOUBLE PRECISION SHIFT BIT #400,4(R5) ;MOST SIGNIFICANT BIT BEQ MPR4 ADD 2(R5), R0 ADC R1 ADC 6(R5) ADC 4(R5) ADD (R5), R1 ADC 6(R5) ADC 4(R5) MPR4: DEC (SP) BGT MPR3 ;GO AGAIN TST (SP)+ ;REMOVE COUNT CLRB 5(R5) ; MOV (SP)+, R0 ;RESTORE SIGNS CMP (R5)+,(R5)+ ;REMOVE SECOND OPERAND CALL SIGNS ;GET RESULT SIGN IN R0 ENDMPR: JMP FINOK ;***************************** SIGNS ****************************** ;REGISTER USE: R0 ONLY ;R2, R0 ARE PAR5ED TO NORM SIGNS: TST R0 BEQ SGN0 ;BOTH 'PLUS' ASL R0 CMP R0, #1002 BEQ SGN0 ;BOTH 'MINUS' MOV #1, R0 SGN0: CALL NORM ;NORMALIZE REAL ENDSGN: RETURN ;*************************** DIVR ***************************** ; ; REAL DIVIDE: R := A / B ; ; INPUT: ; 6(R5), 4(R5) = A ; 2(R5), (R5) = B DIVR: TST 4(R5) BEQ DVR1 ; A IS ZERO --> NOTHING TO DO TST (R5) ; DENOMINATOR ZERO? BNE DVR2 ; NO, GO ON JMP FINER ; DIVIDE BY ZERO ERROR DVR1: CMP (R5)+,(R5)+ ; REMOVE B CLR 2(R5) ; ZERO RESULT JMP FINOK DVR2: CALL EXPTOP ; R1 := E(B) (EXPONENT OF B) ; R0(8) := SIGN OF B CALL EXPNTOP ; R2 := E(A) ; R0(0) := SIGN OF A MOV R0,-(SP) ; SAVE SIGNS SUB R1,R2 ; E(R) := E(A) - E(B) - 2 SUB #2,R2 MOV R2,-(SP) ; SAVE E(R) MOV R3,-(SP) ; SAVE R3 MOV R4,-(SP) ; SAVE R4 MOV (R5)+,R2 ; LOAD B MOV (R5)+,R3 MOV (R5)+,R0 ; LOAD A MOV (R5),R1 CLR -(R5) ; INITIALIZE RESULT (R) CLR R4 ; DIVIDE A BY B BY SHIFTED SUBTRACTION TO OBTAIN 26 BIT QUOTIENT. ; 26 BITS ARE REQUIRED BECAUSE RESULT FRACTION CAN BE IN RANGE ; 0.5 TO 2.0-SMALLREAL SINCE A AND B ARE IN RANGE 0.5 TO 1.0-SMALLREAL. MOV #26.,-(SP) ; LOOP COUNT DVR3: CMP R0,R2 ;; IF A > B THEN BLO 20$ ;; BHI 10$ ;; CMP R1,R3 ;; BLO 20$ ;; 10$: SUB R3,R1 ;; BEGIN SBC R0 ;; A := A - B ; SUB R2,R0 ;; INC R4 ;; R := R + 1 20$: ;; END; ASL R1 ;; A := A * 2 ; ROL R0 ;; ASL R4 ;; R := R * 2 ROL (R5) ;; DEC (SP) ;; BNE DVR3 ; LOOP TST (SP)+ MOV R4,2(R5) ; SAVE LOW PART OF RESULT CLR R1 ; CARRY REGISTER MOV (SP)+,R4 ; RESTORE R4 MOV (SP)+,R3 ; R3 MOV (SP)+,R2 ; E(R) MOV (SP)+,R0 ; SIGNS CALL SIGNS ;SIGN AND NORMALIZE ENDDVR: JMP FINOK ;******************************* EXPTOP ***************************** ;EXPECTS A REAL AT (R5), 2(R5). ;SIGN AND EXPONENT ARE TAKEN FROM THE REAL AND STORED ;IN R0 AND R1. REAL FRACTION IS LEFT AT (R5), 2(R5) EXPTOP: CLR R0 ;CLEAR SIGNS MOV (R5), R1 ASL R1 ROL R0 ; PUT SIGN IN R0 HIGH BYTE ; GP-V6:30 SWAB R0 ; GP-V6:30 CLRB R1 SWAB R1 ;EXPONENT OF SECOND REAL SUB #200, R1 ;PURE EXPONENT CLRB 1(R5) BIS #200, (R5) ;HIDDEN BIT RETURN ;***************************** EXPNTOP *************************** ;EXPECTS A REAL AT 4(R5), 6(R5) ;SIGN AND EXPONENT ARE RETURNED IN R0 AND R2 ;REAL FRACTION LEFT AT 4(R5), 6(R5) EXPNTOP: MOV 4(R5), R2 ASL R2 ADC R0 ;SIGN OF DESTINATION CLRB R2 SWAB R2 ;EXPONENT SUB #200, R2 CLRB 5(R5) BIS #200, 4(R5) ;HIDDEN BIT RETURN ;*************************** NORM ****************************** ;(UNNORMALIZED) REAL FRACTION EXPECTED AT (R5), 2(R5) ;BINARY EXPONENT IN R2, SIGN IN R0. R1 CONTAINS CARRY BIT. ;A NORMALIZED REAL IS LEFT IN (R5), 2(R5) NORM: ADD #200, R2 ;EXCER5 200 TST (R5) ;FRACTION ZERO? BNE NRM1 ;NO TST 2(R5) ;MAYBE BEQ NRM7 ;YES NRM1: CMP (R5), #400 ;FRACTION OVERFLOW? BPL NRM3 ;YES. NRM2: CMP (R5), #200 ;NORMALIZED? BPL NRM4 ASL R1 ;GET CARRY BIT ROL 2(R5) ;SCALE ROL (R5) ;LEFT DEC R2 ;ADJUST EXPONENT BR NRM2 ;GO AGAIN NRM3: ASR (R5) ;SCALE ROR 2(R5) ;RIGHT ROR R1 ;STORE CARRY BIT INC R2 BR NRM1 NRM4: ASL R1 ;ROUND BCC NRM8 ADC 2(R5) ADC (R5) CLR R1 BR NRM1 ;RENORMALIZE NRM8: CMP R2, #377 ;EXPONENT OVERFLOW? BLE NRM5 ;NO JMP FINOVR ;YES NRM5: TST R2 ;EXPONENT UNDERFLOW? BPL NRM6 ;NO JMP FINUND ;YES NRM6: BICB #200,(R5) ;REMOVE SIGNIFICANT BIT SWAB R2 ASR R0 ;SIGN ROR R2 ;RIGHT POSITION BIS R2,(R5) ;PACK EXPONENT NRM7: RETURN CODESZ = .-CODE .IIF GT CODESZ-8192. .ERROR CODESZ ; Too much code .END START