.MCALL .MODULE .MODULE UB,VERSION=12,COMMENT=,AUDIT=YES ; Copyright (c) 1998 by Mentec, Inc., Nashua, NH. ; All rights reserved ; ; This software is furnished under a license for use only on a ; single computer system and may be copied only with the ; inclusion of the above copyright notice. This software, or ; any other copies thereof, may not be provided or otherwise ; made available to any other person except for use on such ; system and to one who agrees to these license terms. Title ; to and ownership of the software shall at all times remain ; in Mentec, Inc. ; ; The information in this document is subject to change without ; notice and should not be construed as a commitment by Digital ; Equipment Corporation, or Mentec, Inc. ; ; Digital and Mentec assume no responsibility for the use or ; reliability of its software on equipment which is not supplied ; by Digital or Mentec, and listed in the Software Product ; Description. ; ; Edit Who Date Description of modification ; ---- --- ---- --------------------------- ; 001 WLD 12-APR-1991 In ALLOC, relax test on UBHOLD ; by changing BEQ to BLOS after ; CMP #1,UBHOLD. ; In RING, record R1 instaed of @R1 ; since recording @R1 causes trap ; at boot-time. Also, eliminate ; unexecutable code in RING. ; ; 012 ARB 06-Jan-1997 Corrected $MEMSZ check from ; 256K Words to 256K Bytes ;-- ;+ ; THIS HANDLER PERFORMS UNIBUS ADDRESS MAPPING FOR RT-11. ;- MMG$T = 1 ;FORCE XM TIM$IT = 0 ;BOOTSTRAP RESTRICTION - NO TIMER SUPPORT ERL$G = 0 ;BOOTSTRAP RESTRICTION - NO ERROR LOGGING .SBTTL .MCALL SECTION .MCALL .DRDEF .ASSUME .EXIT .GVAL .ADDR .BR .SBTTL MACRO DEFINITIONS .SBTTL ... BUFFER MACROS .MACRO BPOOL BUFFER: .REPT UMRS-1 .WORD .+BUFSIZ $REL .-2 .+BUFSIZ UBX .WORD 0 .ENDR .WORD 0 .WORD 0 .ENDM .SBTTL ... DEBUG MACROS DEBUG =: 0 .MACRO REPORT NAME .IF NE DEBUG MOV #"NAME,-(SP) CALL RING TST (SP)+ .ENDC .ENDM .SBTTL ... LODCALL ;+ ; Macro LODCALL loads a LOAD-CODE overlay and executes ; the named subroutine. If an error is detected during ; the read (RDOVLY), control is directed to the RTNERR ; label. ;- .MACRO LODCALL routine in overlay MOV #,R1 CALL RDOVLY BCS RTNERR CALL > .ENDM .SBTTL ... RMCALL ;+ ; Macro RMCALL calls a routine in RMON ;- .MACRO RMCALL routine MOV @#routine,-(SP) $REL .-2 routine UBR CALL @#LowCal $REL .-2 LowCal UBR TST (SP)+ .ENDM .SBTTL ... ...... ;+ ; Macro ...... allows us to use this string of dots to indicate ; an unconditional transfer of control. ;- .MACRO ...... .ENDM .SbTtl ... $REL ; For XM $REL generates several relocation lists and performs some ; relocation at assembly time: ; ; 1) A single list from the $REL references marked UB. This list ; works the same way as list 1) under SJ/FB/RTEM above. Note ; that only UB marked $REL entries are in this list under XM. ; ; 2) A second list from the $REL references marked RMON. This list ; works the same way as list 2) above. Note that RMONX is a ; separate list under XM. ; ; 3) All the entries for $REL marked UBX are statically relocated ; at assembly time since the address of UBX is fixed at 20000 ; (the first address in PAR1). There is not list, the locations ; are modified by .Words generated by $REL. ; ; 4) A third list from the $REL references marked RMONX. This list ; works the same as list 2) above, except it is relocated at ; INSTALL time. ; ; 5) A fourth list from the $REL references marked UBR. This list ; works the same as list 1) above, except that an "old bias" ; value OLDBASE is subtracted out as part of the relocation, ; since this relocation is done to the "resident" part and may ; be repeated several times. ; ; +-----------------------+ ; | |----+ ; | | |UBX ; | "U B X" |<---+ ; | |-----------+ ; 20000: | |<---+ | ; +-----------------------+ | | ; | | | ; |RMONX | | ; V | | ; +-----------------------+ | | ; | | | | ; | | | | ; | "R M O N" | |UBX |UBR ; | | | | ; @JRMON: | | | | ; +-----------------------+ | | ; ^ | | ; |RMON | | ; | | | ; +-----------------------+ | | ; | |----+ | ; | |<----------+ ; | "UBDRV" |----+ ; | | |UB ; ??????: | |<---+ ; +-----------------------+ ; UB.Cnt = 0 ; UB relocation counter RM.Cnt = 0 ; RMON relocation counter UBR.Cnt = 0 ; UB root from hidden counter UBX.Cnt = 0 ; UB hidden counter RMX.Cnt = 0 ; RMON from hidden counter ;+ ; $REL ; ; Used to mark words to relocate in the handler ; ; $Rel Loc Value Base ; ; Loc -- location of word to relocate ; Value -- value to relocate it to ; Base -- base relocation on (UB, UBR, UBX, RMON, or RMONX) ; ; ;;; UB marks references to root code (from root code) ; UBR marks references to root code (from hidden code) ; UBX marks references to the hidden code (from root or hidden code) ;;; RMON marks references to RMON (from root code) ;;; RMONX marks references to RMON (from hidden code) ;- .Macro $Rel Loc Value Base .....1 = . . = Loc .If IDN UB.Cnt = UB.Cnt+1 .Irp x <\UB.Cnt> UB.'x: .Word Value-UBBase .EndR . = .....1 .MExit .EndC; IDN .If IDN RM.Cnt = RM.Cnt+1 .Irp x <\RM.Cnt> RM.'x: .Word Value .EndR . = .....1 .MExit .EndC; IDN .If IDN UBX.Cnt = UBX.Cnt+1 .Irp x <\UBX.Cnt> UX.'x: .Word Value-UBXBase+P1Addr .EndR . = .....1 .MExit .EndC; IDN .If IDN UBR.Cnt = UBR.Cnt+1 .Irp x <\UBR.Cnt> UR.'x: .Word Value-UBBase .EndR . = .....1 .MExit .EndC; IDN .If IDN RMX.Cnt = RMX.Cnt+1 .Irp x <\RMX.Cnt> RMX.'x: .Word Value .EndR . = .....1 .MExit .EndC; IDN .Error ; Unknown B A S E "Base"; .EndM $Rel .SBTTL SYSTEM EQUATES ;+ ; HARDWARE DEFINITIONS ;- BLK =: 1000 ; bytes in a block KTGRAN =: 32.*2 ; bytes in a KT11 chunk P1ADDR =: 20000 ; 1st virtual address in PAR1 KISAR1 =: 172342 ; Kernel Active Page Reg 1 PS =: 177776 ; Processor Status Word UMRS =: 32. ; TOTAL NUMBER OF UMRS SR3 =: 172516 ; MMU STATUS REGISTER 3 UMR.ON =: 000040 ; turn on UNIBUS mapping ;+ ; GLOBAL REGION DEFINITION BLOCK OFFSETS ;- GR.Siz =: 0 ; Offset to SIZE word GR.Adr =: 2 ; Offset to ADDRESS GR.Sta =: 4 ; Offset to STATUS GR.Prv =: 100000 ; PRIVATE region GR.Nam =: 6 ; Offset to NAME GR.Esz =: 10. ; Region Block size ;+ ; .FIXDF (SYSTEM.MAC) ;- $CNFG2 =: 000370 ; RMON OFFSET OF SECOND CONFIG WORD $PNPTR =: 000404 ; RMON OFFSET OF $PNAME TABLE $MEMSZ =: 000420 ; RMON OFFSET OF MEMORY SIZE WORD $MEMPT =: 000430 ; Pointer to memory tables CORPTX =: 4 P1$EXT =: 000432 ; RMON OFFSET to P1EXT routine $P1EXT =: 0 ; Offset to Ptr to P1EXT routine $BLMPT =: -2 ; Offset to Ptr to BLOCK MOVE $XALPT =: -6. ; Offset to Ptr to Region allocation $QHOOK =: 000456 ; RMON OFFSET OF POINTER TO QHOOKS $H2UB =: 000460 ; RMON OFFSET OF ENTRY VECTOR POINTER $CNFG3 =: 000466 ; RMON OFFSET OF THIRD CONFIG WORD ;+ ; .UBVDF (SYSTEM.MAC) ;- UB.GET =: 000000 ; OFFSET OF GETUMR ENTRY VECTOR UB.ALL =: 000002 ; OFFSET OF ALLUMR ENTRY VECTOR UB.RLS =: 000004 ; OFFSET OF RLSUMR ENTRY VECTOR ;+ ; .ZUBDF (SYSTEM.MAC) ;- UB.IDD =: 000000 ; UB DATA TABLE ID UB.VDD =: ^rUBD ; VALUE OF DATA TABLE ID UB.JOB =: UB.IDD+2 ; JOB FLAG BYTES UB.UCT =: UB.JOB+10 ; UMRS ALLOCATED COUNT UB.PCT =: UB.UCT+2 ; PERMANENT UMRS ALLOCATED COUNT UB.TCT =: UB.PCT+2 ; TEMPORARY UMRS ALLOCATED COUNT UB.QCT =: UB.TCT+2 ; NUMBER OF UMRS PENDING ALLOCATION UB.PST =: UB.QCT+2 ; POINTER TO FIRST PERMANENT UMR UB.UMR =: UB.PST+2 ; FIRST UMR SLOT IN TABLE UB.IOP =: 177777 ; VALUE FOR UMR POINTING TO I/O PAGE UB.NQS =: UB.UMR+<40*2> ; OFFSET OF COUNT OF INTERNAL QUEUES UB.QSZ =: 000004 ; SIZE OF EACH QUEUE IN BYTES UB.QUE =: UB.NQS+2 ; START 9421-QUEUE AREA UB.JBQ =: UB.QUE+<4*4> ; START OF JOB-QUEUE AREA ;+ ; .QHKDF (SYSTEM.MAC) ;- QH.CBR =: 000000 ; BR .+6 (FOR CA) QH.CNX =: 000002 ; NEXT CA HOOK OR 0 FOR END OF CA LIST QH.CPB =: 000004 ; BR TO BYPASS CALL TO HANDLER QH.UBR =: 000006 ; BR .+4 (FOR UB) QH.UNX =: 000010 ; NEXT UB HOOK OR 0 FOR END OF LIST QH.CBV =: BR+2 ; VALUE FOR QH.CBR QH.UBV =: BR+1 ; VALUE FOR QH.UBR FH.CBR =: 000000 ; BR .+4 (FOR CA) FH.CNX =: 000002 ; 0 (NO MORE HOOKS FOR CA) FH.UBR =: 000004 ; BR .+4 (FOR UB) FH.UNX =: 000006 ; NEXT UB HOOK FH.UBP =: 000010 ; BR TO BYPASS COMPLT CODE FH.UCO =: 000012 ; CONTINUE WITH COMPLT CODE FH.CBV =: BR+1 ; VALUE FOR FH.CBR FH.UBV =: BR+2 ; VALUE FOR FH.UBR UH.UBR =: 000000 ; BR .+4 (FOR UB) UH.UNX =: 000002 ; NEXT UB HOOK UH.UBV =: BR+1 ; VALUE FOR UH.UBR AH.UBR =: 000000 ; BR .+4 (FOR UB) AH.RQE =: 000002 ; POINTER TO REQUE2 (FOR UB) AH.UBV =: BR+1 ; VALUE FOR AH.UBR ;+ ; .CF2DF (SYSTEM.MAC) ;- BUS =: 000100 ; =0, THIS IS A UNIBUS MACHINE ;+ ; .CF3DF (SYSTEM.MAC) ;- CF3.UI =: 000020 ; UB IS SET NO INSTALL CF3.UA =: 000040 ; UB IS ACTIVE CF3.UB =: 000100 ; UB IS LOADED CF3.DM =: 000200 ; ANY INSTALLED HANDLERS USE DMA CF3.64 =: 000400 ; THIS IS A 64-UNIT MONITOR ;+ ; .SFCDF (SYSTEM.MAC) ;- SF.CTL =: 000365 ; CONTROL SPFUN CODE SF.TAB =: 000372 ; TABLE SPFUN CODE ;+ ; .CSWDF (SYSTEM.MAC) ;- HDERR$ =: 000001 ; HARD ERROR BIT INDX$M =: 000076 ; MASK FOR DEVICE TABLE INDEX ;+ ; .HS2DF (SYSTEM.MAC) ;- HS2.KI =: 000002 ; NO KMON UNLOAD ;+ ; .HF2DF (SYSTEM.MAC) ;- HF2.DM =: 010000 ; H1.FG2 WORD FLAG FOR DMA HANDLER HF2.SD =: 000002 ; H1.FG2 WORD FOR TABLE OF STANDARD SPFUNS HF2.SR =: 004000 ; H1.FG2 WORD FLAG FOR SERIAL HANDLER HF2.LD =: 000004 ; H1.FG2 WORD FOR POINTER TO LD TABLE HF2.64 =: 040000 ; H1.FG2 WORD INDICATING 64-UNIT HANDLER HF2.ND =: 000010 ; H1.FG2 WORD FOR TABLE OF NSPFUNS ;+ ; .DSPDF (SYSTEM.MAC) ;- DSP.TY =: 003400 ; TYPE WORD OF .DRSPF ENTRY ;+ ; .CHNDF (SYSTEM.MAC) ;- C.UNIT =: 000011 ; OFFSET INTO CCB OF DEVICE UNIT # ;+ ; .QELDF (SYSTEM.MAC) ;- Q.2MSK =: 000160 ; MASK FOR HIGH 3 BITS OF 64-UNIT # ;+ ; .ZLDDF (SYSTEM.MAC) ;- LD.FLG =: 000004 ; OFFSET INTO LD DATA TABLE OF 1ST FLAG WORD LD.NDX =: 000077 ; MASK FOR INDEX FIELD LD.UNI =: 037400 ; MASK FOR UNIT FIELD ;+ ; EQUATES FOR SYSCOM ;- RMONPT =: 54 ; POINTER TO RMON $SYPTR =: 54 ; POINTER TO RMON (SYSTEM.MAC's name) .SBTTL INTERNAL EQUATES ;+ ; UBDATA TABLE EQUATES AND INFORMATION ;- ; JOB FLAG EQUATES B.SERI =: 1 ; BIT 0 = 0, JOB IS SET NO SERIAL ; = 1, JOB IS SET SERIAL ; SET/RESET BY UB SET CODE ; RESET BY UB ABORT CODE B.NSPF =: 2 ; BIT 1 = 0, NSPFUN IS NOT OUTSTANDING ; = 1, NSPFUN IS OUTSTANDING ; SET/RESET BY DRBEG, CHKQUE ; RESET BY UB ABORT CODE ; THE UBDATA TABLE HAS ONE ONE WORD ENTRY PER EACH OF THE 40(8) UMRS. ; TABLE ENTRIES INDICATE IF ASSOCIATED UMRS ARE FREE OR IN USE. IF ; FREE, TABLE ENTRIES INDICATE WHETHER A UMR IS PERMANENT OR TEMPORARY, ; A GROUP HEAD OR A GROUP MEMBER, AND THE NUMBER OF ENTRIES IN THE ; GROUP ASSOCIATED WITH THE UMR. IF THE UMR ASSOCIATED WITH THE TABLE ; ENTRY IS ALLOCATED, THEN IT IS ALLOCATED TO EITHER A HANDLER OR A ; QEL. IF IT IS ALLOCATED TO A QEL THEN IT CONTAINS THE ADDRESS OF ; THAT QEL. IF IT IS ALLOCATED TO A HANDLER THEN IT CONTAINS THE ; ADDRESS OF THE $PNAME TABLE SLOT FOR THE HANDLER. IF A TABLE ENTRY ; IS FREE, THEN IT HAS BIT 0 = 1. ; ; AT LOAD TIME, THE TEMPORARY UMRS ARE ORGANIZED INTO GROUPS OF 1, ; 2, 4 AND 9. THE PERMANENT UMRS ARE ORGANIZED INTO ONE GROUP OF ; THE LARGEST POSSIBLE SIZE OF UNALLOCATED PERMANENT UMRS. AS ; PERMANENT UMRS ARE ALLOCATED, THE SIZE OF THIS GROUP DECREASES. ; AS UMRS ARE FREED AND THE UNALLOCATED PERMANENT UMRS BECOME FRAG- ; MENTED, ADDITIONAL GROUPS OF PERMANENT UMRS ARE CREATED. GRPFRE =: 000001 ; GROUP IS FREE GRPHEA =: 000002 ; UMR IS GROUP HEAD GRPPRM =: 000200 ; GROUP IS PERMANENT GRPONE =: 000400 ; GROUP SIZE IS ONE GRPTWO =: 001000 ; GROUP SIZE IS TWO GRPFOU =: 002000 ; GROUP SIZE IS FOUR GRPNIN =: 004400 ; GROUP SIZE IS NINE GETTMP =: GRPFRE!GRPHEA ; GET TEMPORARY GROUP GETPRM =: GRPFRE!GRPHEA!GRPPRM ; GET PERMANENT GROUP ;+ ; UB STATE WORD EQUATES ;- UNLOAD =: 0 ; UB IS NOT LOADED LD1INP =: 1 ; UB LOAD PART 1 IS IN PROGRESS LD1CMP =: 2 ; UB LOAD PART 1 IS COMPLETED LD2INP =: 3 ; UB LOAD PART 2 IS IN PROGRESS LD2CMP =: 4 ; UB LOAD PART 2 IS COMPLETED ;+ ; BUFFER EQUATES ;- MAXBUF =: UMRS ; NEED ONE BUFFER PER POSSIBLE GROUP B.LINK =: 0 ; POINTER TO NEXT BUFFER B.TABL =: B.LINK+2 ; POINTER TO FREED UBDATA ENTRY BUFSIZ =: B.TABL+2 ; SIZE OF BUFFER ;+ ; MISCELLANEOUS EQUATES >>>CHECK FOR SOME OF THESE IN SYSTEM.MAC ;- MAXPRM =: 22. ; MAXIMUM NUMBER OF PERMANENT UMRS MAXJOB =: 10 ; MAXIMUM NUMBER OF JOBS POSSIBLE NUMQUE =: 12. ; NUMBER OF UB INTERNAL QUEUES C.9421 =: 4 ; NUMBER OF QUEUES IN 9421-Q C.JOB =: 8. ; NUMBER OF QUEUES IN JOB-Q C.RPQ =: 32. ; NUMBER OF QUEUES IN RPQ CALOPC =: CALL!37 ; CALL OPCODE FOR 1ST WORD OF QHOOKS UB.ID =: 065 ; DEVICE IDENTIFIER FOR UB UB$VEC =: 0 ; UB DOES NOT HAVE A VECTOR... UMRLO =: 140000 ; FREE VALUE FOR UMR BITS <15-0> UMRHI =: 000077 ; FREE VALUE FOR UMR BITS <5-0> PRMUMR =: 177 ; PERMANENT UMRS REQUESTED MASK PSW =: 177776 ; >>> IS IT IN SYSTEM.MAC? PRIO7 =: 340 ; >>> DITTO? JOBMSK =: 74000 ; >>> DITTO? SLOTS =: 32. ; NUMBER OF HANDLER SLOTS LDREQU =: 100000 ; THIS QEL IS A LD REQUE .SBTTL PSECT Ordering ;***************************************************************************** .Save .PSect UBDvr RW,I,LCL,REL,CON ; Normal driver code psect .PSect SetOvr RW,I,LCL,REL,CON ; Start of overlay code psects .PSect UBX RW,I,LCL,REL,CON ; High Memory psect UBXBase: .Restore ;***************************************************************************** .SBTTL .DRXXX CALLS .NLIST MEB ;+ ; NAME: UB ; CODE: UB.ID (NUMERIC DEVICE IDENTIFIER VALUE) ; STAT: ABTIO$, SUPPORTS SPFUNS, READ ONLY, WRITE ONLY ; SIZE: 0 ; CSR: 170200 ; VEC: NOT APPLICABLE ;- .DRDEF UB,\UB.ID,,0,170200,0 ;+ ; FETCH: NO (UB MAY NOT BE FETCHED) ; LOAD: UBLOAD (UB HAS A LOAD ROUTINE) ; ; NOTE: KMON WILL NOT ALLOW THE USER TO ; UNLOAD UB SINCE IT RESIDES ABOVE ; THE BASE OF RMON. ;- .DRPTR FETCH=*NO*, LOAD=UBLOAD ;+ ; ; CLASS: DVC.PS (PSUEDO HANDLER) ; MOD: ??? ; DATA: UBDATA (STARTING ADDRESS OF THE DATA TABLE) ; TYPE: UBD (UB DATA TABLE) ; KMON: NOINSTALL ;- .DREST CLASS=DVC.PS,,DATA=UBDATA,TYPE=UBD,STAT2= ;+ ; UB SUPPORTS THE CONTROL SPFUN (365) ; >>> NOT IMPLEMENTED FOR V5.5 ;- ; ;.DRSPF SF.CTL ;+ ; UB SUPPORTS THE SPFUN TO ACCESS A DATA TABLE (372) ;- .DRSPF SF.TAB .SBTTL UB INSTALLATION SECTION .ENABL LSB ;+ ; PERFORM THE FOLLOWING INSTALLATION CHECKS: ; 1. UNIBUS MACHINE. ; 2. GREATER THAN 256KB MEMORY. ; 3. UMR REGISTERS EXIST. ; ; EXIT: C FLAG SET IF REQUIREMENTS NOT MET. ;- .DRINS UB,<170200,170376> BR 20$ ; IT'S ERROR TO ENTER AT DATA ENTRY MOV @#RMONPT,R0 ; R0 -> START OF PSEUDO-FIXED AREA BIC #CF3.UI,$CNFG3(R0) ; PREPARE FOR UB SET INSTAL TST (PC)+ ; IS UB SET NO INSTALL? NOINST: .WORD 0 ; NOINST <> 0 IF YES BEQ 10$ ; BRANCH IF SET INSTAL BIS #CF3.UI,$CNFG3(R0) ; SHOW IT'S SET NOINSTAL BR 20$ ; AND REFUSE TO INSTAL 10$: BIT #BUS,$CNFG2(R0) ; UNIBUS MACHINE? BNE 20$ ; NO, DON'T INSTALL UB CMP $MEMSZ(R0),#10000 ; AT LEAST 256KB OF MEMORY? ;012 BCS 20$ ; NO, DON'T INSTALL UB TST (PC)+ ; RESET CARRY, SKIP NEXT INSTRUCTION 20$: SEC ; SET CARRY RETURN ; RETURN .ASSUME . LE 400,MESSAGE=<;UB INSTALLATION AREA OVERFLOW> .SBTTL UB SET COMMAND SECTION .ENABLE LSB ;+ ; UB ACCEPTS THE SET UB [NO]INSTAL COMMAND ;- .DRSET INSTAL,NOP,SETINS,NO ;+ ; UB ACCEPTS THE SET UB [NO]SERIAL=N COMMAND ;- .DRSET SERIAL,7,SETSER, ;+ ; >>> NOT IMPLEMENTED FOR VERSION 5.5 ; >>> USE SET UB NOINSTAL ; ; UB ACCEPTS THE SET UB OFF COMMAND ;- ; ;.DRSET OFF,NOP,SETOFF ; ;+ ; ; >>> NOT IMPLEMENTED FOR VERSION 5.5 ; >>> USE SET UB INSTAL ; ; UB ACCEPTS THE SET UB ON COMMAND ;- ; ;.DRSET ON,NOP,SETON ;+ ; UB ACCEPTS THE SET UB PERM COMMAND ;- .DRSET PERM,NOP,SETPRM, ;+ ; UB ACCEPTS THE SET UB [NO]BPT COMMAND ;- .DRSET HALT,NOP,SETHAL,NO ;+ ; SETINS: ;- .ENABL LSB SETINS: CLR R0 ; ENTRY FOR SET UB INSTALL BR 10$ MOV PC,R0 ; ENTRY FOR SET UB NO INSTALL 10$: MOV R0,NOINST ; TELL THE INSTALL CODE RETURN ;+ ; SETSER: ;- .ENABL LSB SETSER: CLR R1 ; FLAG SERIAL ENTRY BR 10$ ; AND SKIP NO SERIAL ENTRY MOV #1,R1 ; FLAG NO SERIAL ENTRY 10$: ASR R0 ; JOB NUMBER PASSED? BCS 40$ ; NO, EXIT WITH C-FLAG SET CMP R3,R0 ; NUMBER TOO BIG? BCS 40$ ; YES, EXIT WITH C-FLAG SET .ADDR #JOBFLG,R3 ; R3 -> UB RELOCATION LIST ADD R0,R3 ; R3 -> JOB FLAGS WORD TST R1 ; SERIAL OR NO SERIAL? BNE 20$ ; BRANCH IF NO SERIAL BISB #B.SERI,@R3 ; SET IT SERIAL BR 30$ ; AND ALL DONE 20$: BICB #B.SERI,@R3 ; SET IT NO SERIAL 30$: TST (PC)+ 40$: SEC RETURN ;+ ; ;>>> SET ON AND SET OFF NOT SUPPORTED FOR VERSION 5.5 ; ; SETOFF: ;- ; ;.ENABL LSB ;SETOFF: ; RETURN ; ;+ ; SETON: ;- ; ;.ENABL LSB ;SETON: ; RETURN ;+ ; SETPRM: ; ;- .ENABL LSB SETPRM: MOV R0,UBPERM ; TELL UB HOW MANY PERMANENT UMRS RETURN ;+ ; SETHAL: ; ;- .ENABL LSB SETHAL: CLR R1 ; HALT ENTRY BR 10$ ; SKIP NO HALT ENTRY MOV #240,R1 ; NOHALT ENTRY 10$: MOV R1,UBHALT ; TELL UB WHICH IT IS RETURN .ASSUME . LE 1000,MESSAGE=<;UB SET AREA OVERFLOW> .SBTTL QUEUE ENTRY POINT ;+ ; QUEUE ENTRY POINT ;- .ENABL LSB .DRBEG UB UBBASE =: UBSTRT+6 ; BASE FOR UB RELOCATION REPORT UB ; DEBUG UBHALT: NOP ; FOR SET UB [NO]HALT Call MapX ; Map high memory region Jmp @#BEGIN ; Go to start of DRBEG code $REL .-2 BEGIN UBX ...... .SBTTL UB ENTRY VECTOR .IF NE DEBUG .WORD RING-UBVECT ; THIS ALLOWS OTHER HANDLERS TO .BR UBVECT ; REPORT IN THE RING BUFFER BY .ENDC ; ACCESSING IT AS -2 FROM UBVECT UBVECT::BR GETUMV ; CALL TO GETUMR ...... .ASSUME . EQ BR ALLUMV ; CALL TO ALLUMR ...... .ASSUME . EQ .BR RLSUMV ; CALL TO RLSUMR RLSUMV: REPORT RL ;DEBUG MOV #RLSUMR,-(SP) $REL .-2 RLSUMR UBX BR GoHigh ...... GETUMV: REPORT GT ; DEBUG MOV #GETUMR,-(SP) $REL .-2 GETUMR UBX BR GoHigh ...... ALLUMV: REPORT AL ; DEBUG MOV #ALLUMR,-(SP) $REL .-2 ALLUMR UBX BR GoHigh ...... ; Monitor Calls arrive here A2UBDL: REPORT A2 ; DEBUG MOV #A2UBDX,-(SP) $REL .-2 A2UBDX UBX BR GoHigh ...... Q2UBAL: REPORT Q2 ; DEBUG MOV #Q2UBAX,-(SP) $REL .-2 Q2UBAX UBX BR GoHigh ...... C2UBDL: REPORT C2 ; DEBUG MOV #C2UBDX,-(SP) $REL .-2 C2UBDX UBX BR GoHigh ...... U2UBRQ: REPORT U2 ; DEBUG MOV #U2UBRX,-(SP) $REL .-2 U2UBRX UBX .BR GoHigh ; Map to high memory, then call a UB subroutine whose address is ; is on the stack. When the routine returns, mapping is restored ; by falling into UnMapX. GoHigh: Call MapX ; Map our high region Call @(SP)+ ; call the real routine. NOP .Br UnMapX ; unmap the high region and return. UnMapX: ; *** Restore mapping *** MOV R0,-(SP) ; SAVE REGISTER Mov @#PSW,-(SP) ; SAVE CURRENT PSW BIS #PRIO7,@#PSW ; UP PRIORITY MOV PAR1SP,R0 ; R0 BECOMES PAR1 OLD STACK POINTER MOV (R0)+,@#KISAR1 ; LOAD OLD PAR1 CMP #PAR1SP,R0 ; STACK UNDERFLOW? $REL .-2 PAR1SP UB BCC 20$ ; NO, CONTINUE 10$: HALT ; YES, CROAK BR 10$ 20$: MOV R0,PAR1SP ; UPDATE STACK POINTER 30$: Mov (SP)+,@#PSW ; save condition codes across UnMapX MOV (SP)+,R0 Return ...... MapX: ; *** Map UBX region *** MOV R0,-(SP) ; SAVE REGISTER MOV @#PSW,-(SP) ; SAVE PSW BIS #PRIO7,@#PSW ; GO TO PRIORITY 7 MOV PAR1SP,R0 ; R0 IS PAR1 STACK POINTER Mov @#KISAR1,-(R0) ; save current mapping MOV R0,PAR1SP ; UPDATE STACK POINTER CMP #,R0 ; STACK OVERFLOW? $REL .-2 PAR1SP-32 UB BCS 50$ ; NO, CONTINUE 40$: HALT ; YES, TERMINATE BR 40$ 50$: MOV (SP)+,@#PSW ; RESTORE PSW MOV (SP)+,R0 ; RESTORE R0 Mov #.-.,@#KISAR1 ; and change to HIGH mem region P1New =: .-4 ; value to use for PAR1 60$: Return ...... . = . + 32 ; ALLOCATE SPACE FOR STACK PAR1SP: .WORD PAR1SP ; AND STACK POINTER $REL .-2 PAR1SP UB UBDone: Call UnMapX ; Unmap high mem region .DRFIN UB ; and return Q element ...... ; Pseudo interrupt entry - USED ONLY AT ABORT TIME NOP ; ABORT CODE ENTRY UBINT: NOP REPORT IN ; DEBUG Call MapX ; map to high memory Jmp @#UBINTX ; go to routine there $REL .-2 UBINTX UBX ...... .DSABL LSB .SBTTL DATA STRUCTURE DEFINITIONS - LOW MEMORY UBPERM: .WORD -1 ; MANIPULATED BY SET CODE. ; IF < 0 UB WILL HAVE NORMAL UMR GROUPING ; OTHERWISE UBPERM = THE NUMBER OF PERMANENT ; UMRS TO RESERVE FOR INSTALLED HANDLERS. ;+ ; UB DATA TABLE ;- UBDATA: .WORD UB.VDD ; UB DATA TABLE FORMAT INDICATOR JOBFLG: .BLKB MAXJOB ; FLAG BYTE FOR EACH JOB * UMRCNT: .WORD 0 ; NUMBER OF UMRS IN USE PRMCNT: .WORD 0 ; NUMBER OF PERMANENT UMRS IN USE TMPCNT: .WORD 0 ; NUMBER OF TEMPORARY UMRS IN USE QUECNT: .WORD 0 ; NUMBER OF QELS AWAITING UMR ALLOCATION PSTART: .WORD 0 ; OFFSET FROM PSTART+2 TO 1ST PERMANENT UMR .BLKW UMRS-1 ; ALLOCATE 31 SLOTS FOR QEL ADDRESSES .WORD UB.IOP ; IOPAGE UMR TABLE ENTRY MARKS END OF TABLE ENDTAB: .BYTE NUMQUE ; NUMBER OF INTERNAL QUEUES IN USE .BYTE 0 ; RESERVED .EVEN ;+ ; GRPMAP: ; ; TABLE OF 10 1-BYTE ENTRIES, THE FIRST OF WHICH IS A DUMMY. ; TABLE OFFSETS CORRESPOND TO THE NUMBER OF UMRS REQUIRED ; FOR A QEL. TABLE ENTRIES INDICATE THE SMALLEST UMR GROUP ; THAT CAN SATISFY A PARTICULAR REQUEST. THEY ARE ALSO USED ; AS OFFSETS INTO THE Q.OFFS TABLE. ; ; FOR EACH ENTRY: ; BIT 0 = 1 INDICATES BIT 0 OF Q.CSW = 1. ; BIT 1 = 1 INDICATES BIT 0 OF Q.LINK = 1. ; ; THE LOW 5 BYTES OF THE TABLE ARE INITIALIZED BY UBLOAD. THE ; HIGH 5 BYTES INITIALIZED STATICALLY (THERE IS ALWAYS 1 GROUP ; OF 9 UMRS) ; ; THE MEANING OF BITS 0 OF Q.LINK AND Q.CSW IN THE QEL ARE ; GIVEN BELOW: ; ; | Q.LINK BIT 0 = 0 |Q.LINK BIT 0 = 1 ; --------------------------------------------------------- ; Q.CSW BIT 0 = 0 | NEED 1 UMR | NEED 4 UMRS ; --------------------------------------------------------- ; Q.CSW BIT 0 = 1 | NEED 2 UMRS | NEED 9 UMRS ; --------------------------------------------------------- ;- GRPMAP: .BYTE 0,0,0,0,0,3,3,3,3,3 .EVEN ;+ ; Pointers to locations within resident monitor. ;- $PNMPT: .WORD 0 ; -> $PNAME TABLE IN RMON $ENTPT: .WORD 0 ; -> $ENTRY TABLE IN RMON REQADR: .WORD 0 ; -> REQUE IN RMON (USED BY CHKQUE) ;+ ; Miscellaneous definitions ;- UBSTAT: .WORD UNLOAD ; UB STATE WORD (does this have to be here?) DTABSZ: .WORD 0 ; VALUE OF $SLOT*2 ; **WARNING** ; THE NEXT DEFINITIONS ARE ORDER DEPENDENT! ; THEY ARE REQUIRED TO BE MEMORY RES- ; IDENT FOR COMMUNICATION BETWEEN ; LOAD1 AND LOAD2. THEY COULD, PERHAPS, ; BE USED FOR SOMETHING ELSE AFTER LOAD2. NUMGP1: .BYTE 6 ; NUMBER OF GROUPS OF ONE UMR NUMGP2: .BYTE 4 ; NUMBER OF GROUPS OF TWO UMRS NUMGP4: .BYTE 2 ; NUMBER OF GROUPS OF FOUR UMRS NUMGP9: .BYTE 1 ; NUMBER OF GROUPS OF NINE UMRS NUMPRM: .BYTE 0 ; NUMBER OF PERMANENT UMRS: INSTALLED HANDLERS NUMPSY: .BYTE 0 ; NUMBER OF PERMANENT UMRS: SY .EVEN .SBTTL Low Memory Service Routines .IF NE DEBUG .ENABL LSB RINDEX: .WORD 0 ; INDEX OF NEXT RING ENTRY RINGBF: .BLKW <40*5> ; RING BUFFER .WORD -1 RING: MOV @#PSW,-(SP) BIS #340,@#PSW MOV R0,-(SP) MOV RINDEX,R0 MOV 6(SP),RINGBF(R0) ; Record token. $REL .-2 RINGBF UB ADD #2,R0 MOV 2(SP),RINGBF(R0) ; Record PSW at entry. $REL .-2 RINGBF UB ADD #2,R0 MOV R1,RINGBF(R0) ; Record R1 (or your favorite $REL .-2 RINGBF UB ADD #2,R0 ; location). MOV UBCQE,RINGBF(R0) ; STORE QEL ON UBCQE (UB DRBEG) $REL .-2 RINGBF UB ADD #2,R0 MOV #-1,RINGBF(R0) ; STORE MARKER $REL .-2 RINGBF UB ADD #2,R0 CMP R0,#<40*5*2> BCS 10$ CLR R0 10$: MOV R0,RINDEX MOV (SP)+,R0 MOV (SP)+,@#PSW RETURN .ENDC ;NE DEBUG ;+ ; GTHF2L ; Low memory service routine for GETHF2 ; Unmap high mem for a moment to make other handlers (which may ; have been fetched into PAR1) visible. ; ; On entry, R3 points to the fourth word of the XX handler ; On exit, R3 contains zero if there is no extended data in XX's ; DRBEG, or the address of the extended data. ;- .Enabl LSB GTHF2L: CALL MapCor ; Map to kernel PAR1 CMP @R3,#240 ; CONDITION CODE INSTRUCTION? BLO 10$ ; NO, NO EXTENDED DATA CMP #277,(R3)+ ; CONDITION CODE INSTRUCTION? BLO 10$ ; NO, NO EXTENDED DATA CMP @R3,#400 ; BR WITH POSITIVE DISPLACEMENT? BLO 10$ ; NO, NO EXTENDED DATA CMP #577,(R3)+ ; BR WITH POSITIVE DISPLACEMENT? BHIS 20$ ; AND GO TO COMMON EXIT 10$: CLR R3 ; CLEAR OUT TABLE ENTRY 20$: RETURN ; and return to GETHF2 through ...... ; coroutine ; Low memory service routine for REQTYP ; Enter with R3 = kernel address ; Exit with R5 = value at that address, and condition codes set GHWord: Mov #200,@#KISAR1 ; use kernel PAR1 mapping Mov @R3,R5 ; get handler word Mov P1New,@#KISAR1 ; Restore high memory mapping Tst R5 ; test the value obtained Return ; and return to REQTYP ...... ; Low memory service routine for calling RMON. The address of ; the routine to be called is on the stack. LowCal: Mov #200,@#KISAR1 ; restore last mapping Call @2(SP) ; call the RMON routine Br ToHi ; return to high memory code ...... ; Low memory service routine provides access to RMON's $PUTWRD. ; ENTER WITH @SP = RETURN ADDRESS, 2(SP) = DATA TO PUT. PUTWRD: MOV #200,@#KISAR1 ; RESTORE RMON'S MAPPING MOV 2(SP),-(SP) ; REVERSE STACKED WORDS MOV 2(SP),4(SP) ; MOV (SP)+,@SP ; CALL @$PTWRD ; WRITE WORD MOV P1NEW,@#KISAR1 ; RESTORE UB'S PAR1 RETURN ...... ; Mapping Coroutine for use by these low memory routines. MapCor: Mov #200,@#KISAR1 ; Institute kernel mapping Call @(SP)+ ; Resume caller's code ToHi: Mov P1New,@#KISAR1 ; until it finishes. Return ...... ;+ ; ; QD.FRO: (for LQE's in handler DRBEG areas) ; QD.FRX: (for LQE's in UB's queues) ; ; ENTRY: R5 -> LQE OF QUEUE ; ; EXIT: IF C-FLAG = 0 THEN R4 -> QEL DEQUEUED FROM FRONT ; OF SPECIFIED QUEUE. ; ; IF C-FLAG = 1 THEN QUEUE WAS EMPTY. ;- .ENABL LSB QD.FRO: CALL MapCor ; Map to kernel PAR1 QD.FRX: TST (R5)+ ; POINT TO CQE, TEST QUEUE EMPTY BEQ 20$ ; QUEUE EMPTY, EXIT WITH C-FLAG SET MOV @R5,R4 ; R4 -> QEL FROM FRONT OF QUEUE MOV Q$LINK(R4),@R5 ; CQE -> NEXT QEL BNE 10$ ; BRANCH IF QUEUE STILL NOT EMPTY CLR -(R5) ; IT'S EMPTY SO CLEAR LQE TOO 10$: CLR Q$LINK(R4) ; CLEAR QEL'S LINK WORD TST (PC)+ ; SHOW GOT QEL 20$: SEC ; SHOW DIDN'T GET ONE RETURN ; (through coroutine MapCor) ;+ ; ; QE.FRO: (for LQE's in handler DRBEG areas) ; QE.FRX: (for LQE's in UB's queues) ; ; ENTRY: R4 -> QEL ; R5 -> LQE OF QUEUE ; ; EXIT: QEL ENQUEUED TO FRONT OF SPECIFIED QUEUE. ; ;- .ENABL LSB QE.FRO: CALL MapCor ; Map to kernel PAR1 QE.FRX: TST (R5)+ ; POINT TO CQE, TEST QUEUE EMPTY BNE 10$ ; NOT EMPTY MOV R4,@R5 ; INIT CQE MOV R4,-(R5) ; AND LQE BR 20$ 10$: MOV @R5,Q$LINK(R4) ; NEW FRONT -> OLD FRONT MOV R4,@R5 ; INITIALIZE CQE 20$: RETURN ; (through coroutine MapCor) .DSABL LSB .SBTTL END of (low)memory resident part of UB .DREND UB .SBTTL UBX Data - Queues, Pointers, etc. .SAVE .PSECT UBX BYPASS: .WORD 0 ; BYPASS UB SERREQ: .WORD 0 ; THIS IS REQUE OF A SERIAL QEL REQ.0: .WORD 0 ; DUMMY REQ.1: .WORD 0 REQ.2: .WORD 0 REQ.3: .WORD 0 REQ.4: .WORD 0 REQ.5: .WORD 0 REQ.6: .WORD 0 REQ.7: .WORD 0 REQ.8: .WORD 0 REQ.9: .WORD 0 ; BUFFER POOL FOR TRACKING UBDATA ENTRIES FREED WHILE UBHOLD=1. CHKPND: .WORD 0 ; QUEUE OF FREED UBDATA ENTRIES FREQUE: .WORD BUFFER ; QUEUE OF FREE BUFFERS $REL .-2 BUFFER UBX BPOOL ; CREATE BUFFER POOL HERE ;WARNING: THE FOLLOWING QUEUES ARE POSITION DEPENDENT!!! DON'T MOVE THEM!!! UBIQUE: Q.9421: .BLKW C.9421*UB.QSZ/2 ; ALLOCATE SPACE FOR 9421-Q QUEUES JOB.Q: .BLKW C.JOB*UB.QSZ/2 ; ALLOCATE SPACE FOR JOB-Q QUEUES RPQ: .BLKW C.RPQ*UB.QSZ/2 ; ALLOCATE RPQ FOR EACH POSSIBLE HANDLER ;END OF POSITION DEPENDENT QUEUES!!! ;+ ; TABLE OF POINTERS TO ACTIVE HANDLER'S H1.FG2 WORDS. ;- HF2TAB: .BLKW SLOTS ; MAKE ROOM FOR A POINTER TO EACH HF2.FG WORD UBHOLD: .WORD 0 ; UB INTERNAL QUEUE HOLD INDICATOR ; = 0, INTERNAL QUEUE NOT HELD ; >= 1, INTERNAL QUEUE HELD ; < 0, ERROR! ABTJOB: .WORD 0 ; ABORTING JOB ABTCHN: .WORD 0 ; ABORTING CHANNEL ABTQEL: .WORD 0 ; A QEL IS BEING ABORTED MAXNUM: .WORD 0 ; LARGEST # OF UMRS REQUIRED TO FUFILL REQUEST MAXQUE: .WORD 0 ; LARGEST # QELS EVER ON THE UB INTERNAL QUEUE ;+ ; OFFSET #QUEUES ; TABLE GIVING OFFSETS INTO 9421-Q ; ------ ------- ; AND MAX # OF QUEUES (9421 & JOB) TO SCAN Q.OFFS: .BYTE 14, 11 ; GROUP OF ONE .BYTE 10, 12 ; GROUP OF TWO .BYTE 4, 13 ; GROUP OF FOUR .BYTE 0, 14 ; GROUP OF NINE .SBTTL DRBEG CODE in HIGH MEMORY REGION .ENABL LSB BEGIN:: NOP ; Suitable for BPT or HALT MOV #UBLQE,R5 ; R5 -> UBLQE $REL .-2 UBLQE UBR CALL @#QD.FRO ; R4 -> QEL? $REL .-2 QD.FRO UBR BCC 10$ ; YES, CONTINUE JMP RETMON ; NO, QUEUE EMPTY 10$: MOV @Q$CSW(R4),R2 ; YES, GET CSW FROM QEL BIC #^C,R2 ; R2 = HANDLER'S DEVICE TABLE INDEX ADD @#$PNMPT,R2 ; R2 -> PNAME ENTRY FOR HANDLER $REL .-2 $PNMPT UBR CMP @R2,#<^rUB> ; IS THIS THE ENTRY FOR UB? BNE 20$ ; NO, SKIP PROCESSING FOR UB ;+ ; SPFUNS FOR UB ARE PROCESSED HERE. ;- MOV #UBLQE,R5 ; R5 -> UBLQE $REL .-2 UBLQE UBR CALL @#QE.FRO ; PUT IT BACK $REL .-2 QE.FRO UBR TSTB Q$FUNC(R4) ; IS THIS AN SPFUN? BEQ 160$ ; NO, GO MARK WITH ERROR & DRFIN CMPB Q$FUNC(R4),#SF.TAB ; IS IT "RETURN DATA TABLE" SPFUN? BNE SFEXIT ; NO, GO DRFIN JMP SFTAB ; YES, GO PROCESS IT ;+ ; PROCESS QELS DESTINED FOR XX: ;- 20$: CALL HOLD ; HOLD UB INTERNAL QUEUE CALL ISSERI ; IS JOB SERIAL? BCC 30$ ; YES, GO DO SERIAL STUFF CALL XXSERI ; NO, BUT IS HANDLER SERIAL? BCS 110$ ; NO, SKIP SERIAL STUFF 30$: CMP SERREQ,R4 ; IS THIS A REQUE? BNE 40$ ; NO, GO CHECK FOR EMPTY JOB QUEUE CLR SERREQ ; YES, CLEAR OUT BYPASS BR 70$ ; AND GO ALLOCATE 40$: CALL FNDJBQ ; R5 -> QEL'S JOB-Q TST @R5 ; QUEUE EMPTY? BNE 50$ ; NO, GO QUEUE THIS ELEMENT CALL ISNSPF ; NON-STANDARD SPFUN OUTSTANDING? BCS 70$ ; NO, GO TRY TO ALLOCATE 50$: CALL REQTYP ; GET TYPE OF REQUEST TST R0 ; CHECK IT BEQ 55$ ; BRANCH IF NON-DMA BPL 60$ ; BRANCH IF STANDARD I/O 55$: CLR R0 ; MAKE WORD COUNT IN RANGE BR 100$ ; AND GO QUEUE IT 60$: MOV R5,-(SP) ; SAVE QUEUE POINTER MOV Q$WCNT(R4),R5 ; HOW MANY UMRS DO WE NEED? CALL GETNUM ; THE ANSWER IS IN R0 MOV (SP)+,R5 ; BR 100$ ; GO QUEUE IT UP 70$: MOV R0,-(SP) ; SAVE REGISTER CALL REQTYP ; GET REQUEST TYPE TST R0 ; IS IT A DMA NSPFUN? BPL 80$ ; NO, CONTINUE MOV #1,R0 ; SET NSPFUN OUTSTANDING FOR JOB CALL SETNSP ; MOV (SP)+,R0 ; RESTORE REGISTER CALL GRQADR ; R2 -> $ENTRY ENTRY FOR XX: BCS 160$ ; ERROR, RETURN WITH HARD ERROR MOV @R2,R2 ; R2 = $ENTRY TABLE VALUE BR 140$ ; AND ENQUEUE TO XX: 80$: MOV (SP)+,R0 ; RESTORE REGISTER BR 110$ ;+ ; JOB IS SERIAL AND EITHER JOB-Q FOR QEL'S JOB IS NOT EMPTY ; OR A NON-STANDARD SPFUN IS OUTSTANDING ON ITS JOB-Q. ;- 90$: CALL FNDJBQ ; R5 -> JOB-Q FOR QEL 100$: CALL FQE.RE ; ENQUEUE QEL TO END OF JOB-Q BR 150$ ; GO PURGE CHQ AND EXIT ;+ ; EITHER JOB IS NOT SERIAL OR JOB IS SERIAL AND ALL PREVIOUS QUEUE ; ELEMENTS FOR THE SERIAL JOB HAVE THEIR UMR REQUIREMENTS FUFILLED. ;- 110$: CALL GRQADR ; R2 -> XXLQE/XXCQE BCS 160$ ; IF ERROR, DRFIN WITH HARD ERROR MOV @R2,-(SP) ; STACK XXLQE/XXCQE FOR REQUE MOV R0,-(SP) ; SAVE JOBNUM FOR REQUE MOV Q$WCNT(R4),R5 ; PASS THE WORD COUNT TO GETNUM CALL GETNUM ; R0 = NUMBER OF UMRS FOR THIS REQUEST MOV R0,-(SP) ; STACK NUMBER OF UMRS MOV Q$PAR(R4),R1 ; R1 = PAR POINTER MOV #GETTMP,R3 ; R3 SHOWS TEMPORARY ALLOCATION CALL ALLOC ; R5 -> UMRS TO ALLOCATE? BCS 120$ ; NO, ALLOCATION FAILED CLR R3 ; ADDRESS TYPE = PAR VALUE CALL TMPINI ; YES, INIT UMRS, CLEAR C-FLAG 120$: MOV (SP)+,R3 ; R3 = NUMBER OF UMRS REQUESTED MOV (SP)+,R0 ; REQUE REQUIRES R0 = JOBNUM MOV (SP)+,R2 ; REQUE REQUIRES R2 = XXLQE/XXCQE BCC 130$ ; BRANCH IF ALLOCATION SUCCEEDED ;+ ; ALLOCATION FAILED. ENQUEUE THIS QEL TO THE 9421-Q OR JOB-Q. ;- MOV R3,R0 ; R0 = NUMBER OF UMRS REQUESTED CALL ISSERI ; IS JOB SERIAL? BCC 90$ ; YES, GO DO SERIAL ENQUEUE CALL XXSERI ; NO, IS HANDLER SERIAL? BCC 90$ ; YES, GO DO SERIAL ENQUEUE CALL FND9421 ; R5 -> 9421-Q FOR QEL CALL FQE.PR ; ENQUEUE BY PRIORITY BR 150$ ; GO EXIT ;+ ; ALLOCATION WAS SUCCESSFUL. UPDATE Q$PAR AND REQUE QEL TO XX:. ; TO DO THIS, MUST HAVE R2 -> XX ENTRY AND R4 -> QEL AND R0 = JOBNUM. ;- 130$: MOV R1,Q$PAR(R4) ; MAKE Q$PAR A UMR POINTER ADD R3,@#UMRCNT ; COUNT TOTAL UMRS ALLOCATED $REL .-2 UMRCNT UBR ADD R3,@#TMPCNT ; COUNT TEMPORARY UMRS ALLOCATED $REL .-2 TMPCNT UBR BIC #LDREQU,Q$FUNC(R4) ; CLEAR UB INTERNAL FLAG 140$: ADD #4,@SP ; POINT TO REQUE RETURN 150$: MOV R0,-(SP) ; SAVE IMPORTANT REGISTERS MOV R2,-(SP) MOV R4,-(SP) CALL PRGCHQ ; PURGE THE CHQ AND UNHOLD UBIQUE MOV (SP)+,R4 ; RESTORE REGISTERS MOV (SP)+,R2 MOV (SP)+,R0 RetMon: NOP CALLR @#UNMAPX ; Return to monitor $REL .-2 UNMAPX UBR ...... ;+ ; UB:'S SPFUN COMPLETION ;- 160$: BIC #LDREQU,Q$FUNC(R4) ; CLEAR UB INTERNAL FLAG BIS #HDERR$,@Q$CSW(R4) ; MARK WITH HARD ERROR SFEXIT: ABRTEX: NOP JMP @#UBDone ; and jump to low mem $REL .-2 UBDone UBR ...... .DSABL LSB .SBTTL ABORT SUBROUTINES ;+ ; UBABRT SUBROUTINE ; ; SUBROUTINE TO PERFORM ABORT PROCESSING FOR UB. THE FOLLOWING ; ACTIONS ARE PERFORMED: ; ; o 9421-Q, JOB-Q, RPQs ARE PURGED OF QELS FOR ; JOB IF ABORT BY JOB, OR JOB AND CHANNEL IF ABORT BY ; JOB AND CHANNEL. ; o CLEAR NON-STANDARD SPFUN OUTSTANDING FLAG FOR ; ABORTING JOB. ; ; ENTRY: R4 = JOBNUM ; R5 = CSW POINTER IF ABORT BY CHANNEL ** OR ** ; 0 IF ABORT BY JOB ; ;- .ENABLE LSB UBINTX: MOV R0,-(SP) ; SAVE REGISTERS MOV R1,-(SP) MOV R2,-(SP) MOV R3,-(SP) CLR ABTQEL ; INITIALIZE EXIT FLAG SWAB R4 ; PUT JOBNUM IN BITS 11-14 ASL R4 ASL R4 ASL R4 MOV R4,ABTJOB ; STORE ABORTING JOB MOV R5,ABTCHN ; STORE ABORTING CHANNEL MOV #UBIQUE,R5 ; R5 -> 1ST INTERNAL QUEUE $REL .-2 UBIQUE UBX MOV #C.9421+C.JOB+C.RPQ,R2 ; R2 = NUMBER OF QUEUES CALL HOLD ; HOLD UB 10$: CALL ABTQUE ; ABORT QUEUE CMP (R5)+,(R5)+ ; POINT TO NEXT QUEUE SOB R2,10$ ; BRANCH IF MORE TO DO MOV ABTJOB,R1 ; R1 = JOB # IN BITS 11-14 CLR R0 ; CLEAR NSPFUN OUTSTANDING FLAG CALL SETNSP ; AND DO IT CALL PRGCHQ ; PURGE CHQ AND UNHOLD UB MOV (SP)+,R3 ; RESTORE REGISTERS MOV (SP)+,R2 MOV (SP)+,R1 MOV (SP)+,R0 TST ABTQEL ; WAS ANYTHING ABORTED? BNE ABRTEX ; YES, .DRFIN IT BR RetMon ; Simple Return to Monitor ...... .DSABL LSB ;+ ; ABTQUE: ; ; ABORT QUEUE ELEMENTS ON A PARTICULAR QUEUE. ; ; ENTRY: R5 -> LQE OF QUEUE ON WHICH TO ABORT ; ; EXIT: R2 PRESERVED! ;- .ENABLE LSB ABTQUE: MOV R5,R1 ; R1 -> LQE TST (R1)+ ; QUEUE EMPTY? BEQ 110$ ; YES, ALL DONE CLR R3 ; R3 -> PREVIOUS QEL MOV @R1,R4 ; R4 -> QEL 10$: CALL MATCH ; ABORT THIS ONE? BCC 20$ ; YES MOV R4,R3 ; R3 = NEW PREVIOUS BR 80$ ; GO SET UP FOR NEXT TRY 20$: INC ABTQEL ; INCREMENT EXIT FLAG MOV R5,-(SP) ; SAVE LQE POINTER TST R3 ; REMOVING 1ST QEL IN QUEUE? BNE 40$ ; NO, GO CHECK MIDDLE OR END CMP R5,#RPQ ; IS THIS QEL PENDING ALLOC? $REL .-2 RPQ UBX BCC 30$ ; NO, DO NORMAL DEQUEUE CALL FQD.FR ; YES, DO FUNNY DEQUEUE BR 70$ ; AND GO ENQUEUE TO UB 30$: CALL @#QD.FRX ; DO NORMAL DEQUEUE $REL .-2 QD.FRX UBR BR 70$ ; AND GO ENQUEUE TO UB 40$: CMP R5,#RPQ ; IS IT PENDING ALLOCATION? $REL .-2 RPQ UBX BCC 50$ ; NO, DON'T TOUCH QUECNT DEC @#QUECNT ; YES DECREMENT QUECNT $REL .-2 QUECNT UBR 50$: TST Q$LINK(R4) ; LAST QEL? BNE 60$ ; NO, GO DEQUEUE FROM MIDDLE BIC #177776,Q$LINK(R3) ; YES, CLEAR LINK FIELD OF PREV MOV R3,@R5 ; LQE -> NEW LAST BR 70$ ; AND PUT IT ON UBLQE/UBCQE 60$: MOV Q$LINK(R3),-(SP) ; SAVE PREVIOUS LINK FIELD MOV Q$LINK(R4),Q$LINK(R3) ; PREVIOUS -> NEXT ASR (SP)+ ; WAS BIT 0 SET? BCC 70$ ; NO, THEN DON'T SET IT BIS #1,Q$LINK(R3) ; SET IT 70$: MOV #UBLQE,R5 ; POINT TO UBLQE/UBCQE $REL .-2 UBLQE UBR MOV R3,-(SP) ; SAVE POINTER TO NEXT QEL CALL @#QE.REA ; ENQUEUE TO UB $REL .-2 QE.REA UBX MOV (SP)+,R3 ; RESTORE POINTER TO NEXT QEL MOV (SP)+,R5 ; RESTORE ABORTING QUEUE POINTER 80$: TST R3 ; AT BEGINNING OF QUEUE? BNE 90$ ; NO, SKIP NEXT MOV @R5,R4 ; YES, GET NEXT QEL BR 100$ ; TRY NEXT 90$: MOV Q$LINK(R3),R4 ; R4 -> NEXT QEL 100$: BIC #1,R4 ; CLEAR FUNNY BIT BNE 10$ ; AND TRY NEXT 110$: RETURN ; BYE BYE .DSABL LSB ;+ ; MATCH: ; ; ENTRY: R4 -> QEL ; ABTJOB = JOBNUM IN BITS 11-14 ; ABTCHN = ADDRESS OF ABORTING CSW ; ; EXIT: R2 PRESERVED! ; C-FLAG = 0 IF THIS QEL SHOULD BE ABORTED ; - AND - THOSE FUNNY BITS ARE ; CLEARED OUT. ; C-FLAG = 1 OTHERWISE ;- .ENABLE LSB MATCH: MOV Q$FUNC(R4),-(SP) ; STACK JOBNUM BIC #^C,@SP ; CLEAR EXTRANEOUS INFO CMP ABTJOB,(SP)+ ; IS IT A MATCH? BNE 20$ ; NO, EXIT TST ABTCHN ; ABORT BY CHANNEL? BEQ 10$ ; NO, ABORT THIS QEL MOV Q$CSW(R4),-(SP) ; YES, GET CSW POINTER BIC #1,@SP ; CLEAR OUT FUNNY BIT CMP (SP)+,ABTCHN ; CSW POINTERS MATCH? BNE 20$ ; NO, EXIT 10$: BIC #1,Q$CSW(R4) ; CLEAR OUT FUNNY BITS BIC #1,Q$LINK(R4) BIC #LDREQU,Q$FUNC(R4) ; CLEAR UB INTERNAL FLAG TST (PC)+ ; SHOW MATCH 20$: SEC ; SHOW NO MATCH RETURN .SBTTL Q2UBAL SUBROUTINE ;+ ; Q2UBAL: ; ; FUNCTION: POINT RETURN R2 TO XX ENTRY OR UB ENTRY. ; ; CALLED BY: QMANGR QHOOK ; ; AT ENTRY: POINTER TO QEL IS ON THE STACK ; R2 -> FORTH WORD OF XX: ; ; AT EXIT: POINTER TO QEL IS ON THE STACK ; R0,R3,R4 ARE PRESERVED ; IF THE QEL IS TO BE ENQUEUED TO UB: THEN ; R2 -> FORTH WORD OF UB: ; OTHERWISE ; R2 -> FORTH WORD OF XX: ;- .ENABLE LSB Q2UBAX: MOV R0,-(SP) ; SAVE REGISTERS MOV R2,-(SP) MOV R3,-(SP) MOV R4,-(SP) MOV 14(SP),R4 ; R4 -> QEL CMP R4,BYPASS ; BYPASS THIS QEL? BNE 10$ ; NO CLR BYPASS ; YES, IT ONLY HAPPENS ONCE BR 40$ ; ENQUEUE TO XX: CMP R4,SERREQ ; SERIAL REQUE? BNE 10$ ; NO CLR SERREQ ; YES, IT ONLY HAPPENS ONCE BR 40$ ; ENQUEUE TO XX: 10$: CALL GETHF2 ; INITIALIZE HF2TAB ENTRY CALL REQTYP ; GET TYPE OF REQUEST BCS 40$ ; BRANCH IF XX: NOT DMA CALL ISSERI ; JOB SERIAL? BCC 30$ ; YES, SKIP TYPE TEST CALL XXSERI ; HANDLER SERIAL? BCC 30$ ; YES, SKIP TYPE TEST TST R0 ; NO, TEST TYPE OF REQUEST BEQ 20$ ; NON-DMA, ENQ TO XX BPL 30$ ; .READX, .WRITX OR DMA SPFUN 20$: BIC #LDREQU,Q$FUNC(R4) ; CLEAR OUT UB INTERNAL FLAG CAUSE BR 40$ ; SEEKS, SPEC DIR, NSPFUNS AND ; NON-DMA SPFUNS ALL GO TO XX: 30$: MOV #UBLQE,4(SP) ; .READx, .WRITx or .SPFUN AND $REL .-4 UBLQE UBR ; ALL SERIAL REQUESTS GO TO UB 40$: MOV (SP)+,R4 ; RESTORE REGISTERS MOV (SP)+,R3 MOV (SP)+,R2 MOV (SP)+,R0 RETURN .SBTTL C2UBDL SUBROUTINE ;+ ; ; C2UBDL: ; ; DEALLOCATE UMRS ASSOCIATED WITH COMPLETING QEL. ; ; CALLED BY: COMPLT QHOOK ; ; AT ENTRY: R1 -> HANDLER CQE ; ;- .ENABLE LSB C2UBDX: MOV R0,-(SP) ; SAVE R0 MOV R1,-(SP) ; SAVE R1 MOV R2,-(SP) ; SAVE R2 MOV R3,-(SP) ; SAVE R3 MOV R4,-(SP) ; SAVE R4 MOV R5,-(SP) ; SAVE R5 ;+ ; IF UBIQUE IS HELD THEN REINITIALIZE THE ENTRY AND ADD IT TO LIST OF ; UBDATA TABLE ENTRIES TO BE CHECKED FOR ALLOCATION BEFORE UNHOLDING UB. ;- MOV @#PSW,-(SP) ; GET READY TO BIS #PRIO7,@#PSW ;;; LOCK OUT INTERRUPTS TST UBHOLD ;;; UBIQUE HELD? BEQ 30$ ;;; NO, GO HOLD IT MOV (SP)+,@#PSW ;;; RESTORE INTERRUPTS MOV R1,R3 ; R3 -> XXCQE CALL @#GHWORD ; R5 -> QEL FROM XXCQE $REL .-2 GHWORD UBR MOV R5,R1 ; R1 -> QEL CALL FNDQEL ; SEARCH FOR QEL IN TABLE BCS 40$ ; NOT THERE SUB R3,@#UMRCNT ; ADJUST TOTAL # ALLOCATED COUNT $REL .-2 UMRCNT UBR SUB R3,@#TMPCNT ; ADJUST # TEMPORARY ALLOCATED COUNT $REL .-2 TMPCNT UBR CALL REINIT ; REINITIALIZE ENTRY TST @#QUECNT ; ANYONE WAITING FOR ALLOCATION? $REL .-2 QUECNT UBR BEQ 40$ ; NO, ALL DONE MOV #FREQUE,R5 ; YES, GET A BUFFER FROM FREE LIST $REL .-2 FREQUE UBX MOV @#PSW,-(SP) ; GET READY TO BIS #PRIO7,@#PSW ;;; RAISE PRIORITY CALL GETBUF ;;; TRY TO GET R4 -> BUFFER BCC 20$ ;;; BRANCH IF GOT IT 10$: HALT ;;; FIX THIS BR 10$ ;;; INFINITE LOOP! 20$: MOV (SP)+,@#PSW ;;; RESTORE PRIORITY MOV R0,B.TABL(R4) ; POINT BUFFER TO NEWLY FREED ENTRY MOV #CHKPND,R5 ; POINT TO CHKPND $REL .-2 CHKPND UBX MOV @#PSW,-(SP) ; GET READY TO MOV #PRIO7,@#PSW ;;; RAISE PRIORITY CALL PUTBUF ;;; PUT BUFFER ON CHECK PENDING QUEUE MOV (SP)+,@#PSW ;;; RESTORE PRIORITY BR 40$ ; AND ALL DONE ;+ ; UBIQUE NOT HELD -- HOLD IT AND CONTINUE WITH THE C2UBDL OPERATION ;- 30$: CALL HOLD ;;; HOLD UBIQUE MOV (SP)+,@#PSW ;;; RESTORE INTERRUPTS MOV R1,R3 CALL @#GHWORD $REL .-2 GHWORD UBR ; Get pointer to Q-elem MOV R5,R1 CALL CLEAN ; FREE ANY ALLOCATED UMRS CALL PRGCHQ ; PURGE CHQ, UNHOLD UBIQUE 40$: MOV (SP)+,R5 ; RESTORE REGISTERS MOV (SP)+,R4 MOV (SP)+,R3 MOV (SP)+,R2 MOV (SP)+,R1 MOV (SP)+,R0 RETURN ; DONE WITH DEALLOCATION .SBTTL A2UBDL SUBROUTINE ;+ ; ; A2UBDL: ; ; DEALLOCATE UMRS ASSOCIATED WITH ABORTING QEL. ; ; CALLED BY: IOQABT QHOOK ; ; AT ENTRY: R4 -> Q.LINK FIELD OF ABORTING QEL ; ;- .ENABLE LSB A2UBDX: MOV R0,-(SP) ; SAVE R0 MOV R1,-(SP) ; SAVE R1 MOV R2,-(SP) ; SAVE R2 MOV R3,-(SP) ; SAVE R3 MOV R4,-(SP) ; SAVE R4 MOV R5,-(SP) ; SAVE R5 CMP (R4)+,(R4)+ ; R1 -> Q.BLKN FIELD MOV R4,R1 MOV @#PSW,-(SP) ; SAVE PSW BIS #PRIO7,@#PSW ; LOCK OUT INTERRUPTS CALL HOLD ; HOLD UBIQUE MOV (SP)+,@#PSW ; RESTORE INTERRUPTS CALL CLEAN ; CLEAN QEL FROM TABLE CALL PRGCHQ ; PURGE CHQ, UNHOLD UBIQUE MOV (SP)+,R5 ; RESTORE REGISTERS MOV (SP)+,R4 MOV (SP)+,R3 MOV (SP)+,R2 MOV (SP)+,R1 MOV (SP)+,R0 RETURN .SBTTL U2UBRQ SUBROUTINE ;+ ; ; U2UBRQ: ; ; CALLED BY: HOOKED BY RMON BEFORE UNHOLDING XX: ; ; AT ENTRY: R1 -> HANDLER'S HOLD WORD (WORD 3) ; ; AT EXIT: RPQ IS PURGED UNTIL IT IS EMPTY ; R1, R4 PRESERVED FOR RMON ; ;- .ENABL LSB U2UBRX: MOV R1,-(SP) ; SAVE THE HOLD WORD MOV R4,-(SP) ; SAVE REGISTER TST (R1)+ ; R1 -> 4TH WORD OF HANDLER MOV @#DTABSZ,R3 ; R3 = SLOT*2 $REL .-2 DTABSZ UBR CLR R0 ; R0 WILL HOLD SLOT NUMBER MOV @#$ENTPT,R2 ; R2 -> $ENTRY TABLE $REL .-2 $ENTPT UBR 10$: CMP R1,(R2)+ ; IS THIS OUR ENTRY? BEQ 20$ ; YES, EXIT THIS LOOP INC R0 ; NO, INCREMENT SLOT NUMBER SOB R3,10$ ; AND KEEP LOOKING BR 50$ ; THIS'LL NEVER HAPPEN!! 20$: ASL R0 ; R0 = OFFSET INTO RPQ ASL R0 MOV #RPQ,R5 ; R5 -> RPQS $REL .-2 RPQ UBX ADD R0,R5 ; R5 -> RPQ FOR HANDLER MOV R5,-(SP) ; STACK IT 30$: MOV @#PSW,-(SP) ; SAVE PSW BIS #PRIO7,@#PSW ; DISABLE INTERRUPTS CALL @#QD.FRX ; TRY TO GET A QEL $REL .-2 QD.FRX UBR BCS 40$ ; BRANCH IF RPQ EMPTY MOV (SP)+,@#PSW ; RESTORE PSW MOV @SP,R5 ; RESTORE RPQ POINTER RMCALL REQADR ; Call REQUE entry in QMANGR MOV @SP,R5 ; R5 -> RPQ BR 30$ ; AND TRY FOR ANOTHER 40$: ADD #4,SP ; CLEAN STACK 50$: MOV (SP)+,R4 ; RESTORE REGISTERS MOV (SP)+,R1 RETURN .SBTTL GETUMR SUBROUTINE ;+ ; ; GETUMR: ; ; ROUTINE TO ALLOCATE UMRS FOR NON-STANDARD SPFUNS. ; ; o ENTERED IN SYSTEM STATE WITH PRIORITY OF 0. CALLED BY ; XX DRBEG. ; ; o RETURN IS MADE TO XX: WITH C = 0 IF UMRS ARE ALLOCATED AND ; THE HANDLER MAY CONTINUE PROCESSING THE QEL. RETURN IS ; MADE WITH C = 1 IF THE HANDLER SHOULD CHECK IT'S LQE/CQE ; FOR ANOTHER QEL TO PROCESS. ; ; AT ENTRY: R0 = Q.WCNT EQUIVALENT ; R1 = Q.PAR EQUIVALENT OR PHYSICAL ADDRESS LOW ; R2 = UNUSED OR PHYSICAL ADDRESS HIGH ; R3 = ADDRESS TYPE INDICATOR ; = 0 IF R1 IS PAR VALUE, R2 IS UNUSED ; = 1 IF R1, R2 CONTAIN PHYSICAL ADDRESS ; R4 = QEL POINTER, QEL MUST BE ON XXCQE ; ; AT EXIT: ; IF C = 0, R1 = NEW VALUE FOR Q.PAR AND R2 IS UNUSED ; ** OR ** ; R1 = UNIBUS VIRTUAL ADDRESS LOW AND ; R2 = UNIBUS VIRTUAL ADDRESS HIGH ; R4 PRESERVED ; R0, R2, R3, R5 TRASHED ; IF C = 1, QEL IS REMOVED FROM XXCQE & QUEUED IN UB ; ALL REGISTERS TRASHED ;- .ENABLE LSB GETUMR: TST R0 ; WORD COUNT OF ZERO? BNE 20$ ; NO, CONTINUE CALL ISSERI ; IS JOB SERIAL? BCC 10$ ; YES, GO RESET BIT CALL XXSERI ; NO, IS HANDLER SERIAL? BCS 110$ ; NO, JUST EXIT 10$: MOV Q$FUNC(R4),R1 ; R1 = WORD WITH JOBNUM IN IT BIC #^C,R1 ; CLEAR ALL BUT JOB NUMBER CLR R0 ; SET NSPFUN OUTSTANDING = FALSE CALL SETNSP BR 110$ ; AND GO TO GOOD EXIT 20$: MOV @Q$CSW(R4),R5 ; R5 = CSW BIC #^C,R5 ; GET SLOT NUMBER ADD @#$PNMPT,R5 ; R5 -> XX'S $PNAME ENTRY $REL .-2 $PNMPT UBR CMP @R5,#<^rLD> ; DOES THIS CSW POINT TO LD? BNE 30$ ; NO, SO IT ISN'T A REQUE BIS #LDREQU,Q$FUNC(R4) ; YES, MARK AS REQUE 30$: MOV R0,R5 ; R5 = WORD COUNT CALL GETNUM ; R0 = NUMBER OF UMRS NEEDED MOV R0,-(SP) ; STACK NUMBER OF UMRS NEEDED MOV R3,-(SP) ; SAVE ADDRESS TYPE INDICATOR MOV #GETTMP,R3 ; ALLOCATING TEMPORARY UMRS CALL HOLD ; HOLD UBIQUE CALL ALLOC ; R5 -> UMRS TO ALLOCATE? MOV (SP)+,R3 ; R3 = ADDRESS TYPE INDICATOR BCS 40$ ; NO, UNABLE TO ALLOCATE CALL TMPINI ; YES, INIT TEMPORARY UMRS, SET C-FLAG 40$: MOV (SP)+,R0 ; R0 = NUMBER OF UMRS NEEDED BCC 80$ ; BRANCH IF ALLOCATION SUCCESSFUL CALL GTSLOT ; R1 = SLOT # OF XX: MOV R1,R5 ; COPY IT TO R5 ADD @#$ENTPT,R5 ; R5 -> XX:'S DEVICE TABLE ADDRESS $REL .-2 $ENTPT UBR MOV @R5,R5 ; R5 -> XXLQE CALL @#QD.FRO ; DEQUEUE IT $REL .-2 QD.FRO UBR CALL ISSERI ; JOB SERIAL? BCC 50$ ; YES, GO ENQUEUE TO JOB-Q CALL XXSERI ; IS HANDLER SERIAL? BCS 60$ ; NO, GO ENQUEUE TO 9421-Q 50$: CALL FNDJBQ ; R5 -> JOB-Q FOR QEL CALL FQE.FR ; ENQUEUE TO FRONT OF QUEUE BR 70$ ; AND GO EXIT 60$: CALL FND9421 ; R5 -> 9421-Q FOR QEL CALL FQE.PR ; ENQUEUE BY PRIORITY 70$: CALL PRGCHQ ; PURGE CHQ, UNHOLD UBIQUE BR 120$ ; AND EXIT 80$: ADD R0,@#UMRCNT ; ADD TO TOTAL ALLOCATED $REL .-2 UMRCNT UBR ADD R0,@#TMPCNT ; ADD TO TEMPORARY ALLOCATED $REL .-2 TMPCNT UBR MOV R1,-(SP) ; SAVE NEW ADDRESS VALUE CALL ISSERI ; JOB SERIAL? BCC 90$ ; YES, RESET NSPFUN OUTSTANDING FLAG CALL XXSERI ; NO, BUT IS HANDLER SERIAL? BCS 100$ ; NO, SKIP NSPFUN OUTSTANDING STUFF 90$: MOV Q$FUNC(R4),R1 ; R1 = WORD WITH JOBNUM IN IT BIC #^C,R1 ; CLEAR OUT EXTRANEOUS BITS CLR R0 ; SET NSPFUN OUTSTANDING = FALSE CALL SETNSP ; 100$: BIC #LDREQU,Q$FUNC(R4) ; CLEAR OUT REQUE FLAG MOV R2,-(SP) ; MOV R4,-(SP) ; SAVE QEL POINTER CALL FNDJBQ ; GET POINTER TO JOB-Q CALL PRGJBQ ; PURGE IT CALL PRGCHQ ; PURGE CHQ, UNHOLD UBIQUE MOV (SP)+,R4 ; RESTORE QEL POINTER MOV (SP)+,R2 ; RESTORE NEW ADDRESS VALUE MOV (SP)+,R1 ; 110$: TST (PC)+ ; CLEAR CARRY, SKIP NEXT 120$: SEC ; SET CARRY RETURN .SBTTL ALLUMR SUBROUTINE ;+ ; ; ALLUMR: ; ; AT ENTRY: R0 = NUMBER OF UMRS TO ALLOCATE. ; R1 = BITS 0-15 OF 22-BIT BASE ADDRESS ; R2 = BITS 16-21 OF 22-BIT BASE ADDRESS ; R4 = ADDRESS OF $PNAME TABLE ENTRY ; ; AT EXIT: IF C = 0 THEN R1 = BITS 0-15 OF UNIBUS VIRTUAL ADDRESS ; R2 = BITS 16,17 OF UNIBUS VIRTUAL ADDRES ; R0,R3,R4,R5 TRASHED ; IF C = 1 THEN UNABLE TO ALLOCATE UMRS AND ; R0 - R5 TRASHED ; ;- .ENABLE LSB ALLUMR: BIC #1,R1 ; ADDRESS MUST BE WORD ALIGNED MOV #GETPRM,R3 ; SHOW WE WANT PERMANENT UMRS MOV R0,-(SP) ; SAVE NUMBER NEEDED CALL HOLD ; HOLD UBIQUE CALL ALLOC ; R5 -> UMRS TO ALLOCATE? BCS 10$ ; NO, COULDN'T GET THEM CALL PRMINI ; YES, INITIALIZE PERMANENT UMRS, SET C-FLAG 10$: MOV (SP)+,R0 ; RESTORE NUMBER NEEDED BCS 20$ ; BRANCH IF COULDN'T GET 'EM ADD R0,@#UMRCNT ; COUNT TOTAL UMRS ALLOCATED $REL .-2 UMRCNT UBR ADD R0,@#PRMCNT ; COUNT PERMANENT UMRS ALLOCATED $REL .-2 PRMCNT UBR MOV R1,-(SP) ; SAVE UNIBUS VA LOW MOV R2,-(SP) ; SAVE UNIBUS VA HIGH CALL PRGCHQ ; PURGE CHQ AND UNHOLD UBIQUE MOV (SP)+,R2 ; RESTORE UNIBUS VA HIGH MOV (SP)+,R1 ; RESTORE UNIBUS VA LOW CLC ; SHOW GOT THEM BR 30$ ; AND DO COMMON EXIT... 20$: CALL PRGCHQ ; PURGE CHQ AND UNHOLD UBIQUE SEC ; SHOW COULDN'T GET THEM 30$: RETURN ; SPLIT .SBTTL RLSUMR SUBROUTINE ;+ ; ; RLSUMR: ; ; SUBROUTINE TO RELEASE PERMANENT UMRS. ; ; AT ENTRY: R1 -> HANDLER'S $PNAME TABLE ENTRY. ; ; AT EXIT: R0 - R5 TRASHED ; ; COMMENT: SHOULD UB BE HELD? ; ;- .ENABLE LSB RLSUMR: CALL FNDQEL ; IS QEL IN TABLE? BCS 10$ ; NO, GO TO EXIT SUB R3,@#UMRCNT ; ADJUST TOTAL ALLOCATED COUNT $REL .-2 UMRCNT UBR SUB R3,@#PRMCNT ; ADJUST PERMANENT ALLOCATED COUNT $REL .-2 PRMCNT UBR CALL REGROUP ; MERGE GROUPS IF NECESSARY CALL REINIT ; REINITIALIZE UMRS AND UBDATA 10$: RETURN ; DONE RELEASING .SBTTL SPFUN SF.TAB (372) SUBROUTINE ;+ ; ; SFTAB: ; ; AT ENTRY: R4 -> QEL ; ; AT EXIT: UB DATA TABLE RETURNED TO CALLER ; ; CALLED WITH: .SPFUN AREA,CHAN,FUNC,BUF,WCNT,BLK ; WHERE: FUNC = SF.TAB (372) ; BUF = ADDRESS OF USER BUFFER ; WCNT = MAXIMUM NUMBER OF WORDS ; TO RETURN ; ;- .ENABL LSB SFTAB: MOV #,R0 ; R0 = # BYTES TO XFER ASR R0 ; GET # WORDS ADC R0 CMP R0,Q$WCNT(R4) ; USER BUFFER BIG ENOUGH? BCC 10$ ; YES, CONTINUE MOV Q$WCNT(R4),R0 ; NO, XFER WCNT WORDS 10$: MOV #UBDATA,R5 ; R5 -> UBDATA $REL .-2 UBDATA UBR CALL HOLD ; LOCK IT UP 20$: MOV (R5)+,-(SP) ; STACK WORD TO XFER CALL @#PUTWRD $REL .-2 PUTWRD UBR SOB R0,20$ ; BRANCH IF MORE LEFT TO DO CALL PRGCHQ ; ELSE PURGE CHQ AND UNHOLD JMP SFEXIT ; DONE, GO .DRFIN ; MOV #,R5 ; R5 = # BYTES TO XFER ; ASR R5 ; GET # WORDS ; ADC R5 ; CMP R5,Q$WCNT(R4) ; USER BUFFER BIG ENOUGH? ; BCC 10$ ; YES, CONTINUE ; MOV Q$WCNT(R4),R5 ; NO, SEND SPECIFIED SIZE ; MOV #P1ADDR/100,R1 ; KERNEL PAR1 VALUE ; MOV #UBDATA,R2 ; DISPLACEMENT ;$REL .-2 UBDATA UBR ; MOV Q$MEM(R4),R3 ; USER BUFFER PAR1 VALUE ; MOV Q$BUFF(R4),R4 ; USER BUFFER DISPLACEMENT ; CALL HOLD ; LOCK-UP UBDATA ; CALL @BLKMV ; MOVE THE DATA ; CALL PRGCHQ ; CLEAR OUT THE CHQ ; JMP SFEXIT ; DONE ;+ ; GETNUM: ; ; ; AT ENTRY: R5 = WORD COUNT FROM QEL ; R4 -> QEL ; AT EXIT: R0 = EXACT NUMBER OF UMRS REQUIRED ; R5 IS TRASHED ; Q$LINK(R4) AND Q$CSW(R4) ARE INITIALIZED ; ALL OTHER REGISTERS ARE PRESERVED ;- .ENABLE LSB GETNUM: TST R5 ; GET OPERATION TYPE BPL 10$ ; SKIP NEGATION IF READ NEG R5 ; GET THE ACTUAL SIZE 10$: ADD #100,R5 ; ALLOW FOR WORST CASE DISPLACEMENT MOV #1,R0 ; INITIALIZE THE UMR COUNTER 20$: SUB #10000,R5 ; SUBTRACT ONE UMR'S WORTH BLOS 30$ ; BRANCH TO GOOD RETURN IF DONE INC R0 ; COUNT IT BR 20$ ; AND SEE IF NEED ANOTHER 30$: CMP MAXNUM,R0 ; IT THIS THE LARGEST SIZE REQUEST RECEIVED? BCC 40$ ; NO, CONTINUE MOV R0,MAXNUM ; YES, RECORD IT 40$: MOV R0,R5 ; R5 = INDEX INTO REQUEST ARRAY ASL R5 ; MAKE IT WORD OFFSET ADD #REQ.0,R5 ; R5 -> ENTRY REQUEST ARRAY $REL .-2 REQ.0 UBX INC @R5 50$: RETURN ; ALL DONE. ;+ ; CLEAN: ; ; SEARCH FOR QEL OR HANDLER $PNAME TABLE ENTRY POINTER IN UBDATA. ; IF FOUND REINITIALIZE UBDATA ENTRY, ASSOCIATED UMRS, AND ; ALLOCATE FREED UMRS TO A QEL FROM UB INTERNAL QUEUE. ; ; CALLED BY: C2UBDL, A2UBDL ; ; AT ENTRY: R1 -> QEL OR HANDLER $PNAME TABLE ENTRY POINTER ; ; AT EXIT: ; ;- .ENABLE LSB CLEAN: CALL FNDQEL ; SEARCH FOR QEL IN TABLE BCS 10$ ; BRANCH IF NOT THERE SUB R3,@#UMRCNT ; ADJUST TOTAL # ALLOCATED COUNT $REL .-2 UMRCNT UBR SUB R3,@#TMPCNT ; ADJUST # TEMPORARY ALLOCATED COUNT $REL .-2 TMPCNT UBR CALL REINIT ; REINITIALIZE UBDATA AND UMRS CALL CHKQUE ; TRY TO ALLOCATE FREED UMRS 10$: RETURN ;+ ; FNDQEL: ; ; SEARCH FOR QEL OR HANDLER $PNAME TABLE ENTRY POINTER IN UBDATA, ; KEEPING COUNT OF GROUP SIZE, ACTUAL NUMBER OF UMRS FREED, AND ; RETAINING A POINTER TO THE FIRST QEL THAT MATCHES. ; ; AT ENTRY: R1 -> QEL OR HANDLER $PNAME TABLE ENTRY POINTER ; ; AT EXIT: R4 PRESERVED ; IF C-BIT = 0 THEN GROUP FOUND -- AND -- ; ; R0 -> 1ST INSTANCE OF QEL (OR $PNAME POINTER) ; IN UBDATA. ; R2 = GROUP SIZE. ; R3 = ACTUAL NUMBER OF UMRS ALLOCATED. ; ; IF C-BIT = 1 THEN GROUP NOT FOUND ; ;- .ENABLE LSB FNDQEL: CLR R3 ; R3 WILL HOLD ACTUAL UMR COUNT MOV #-1,R2 ; R2 WILL HOLD THE GROUP SIZE - 1 MOV #UBDATA+UB.UMR,R0 ; R0 -> UBDATA $REL .-2 UBDATA+UB.UMR UBR 10$: CMP #UB.IOP,@R0 ; AT END OF TABLE? BEQ 40$ ; YES, GO CHECK RESULTS CMP R1,(R0)+ ; ARE WE DEALLOCATING THIS ONE? BNE 20$ ; NO, SKIP UMRS USED COUNT INC R3 ; YES, INCREMENT UMRS USED COUNT BR 30$ ; AND GO COUNT IT 20$: TST R2 ; HAD WE ALREADY FOUND A MATCH? BMI 10$ ; NO, GO LOOK AT THE NEXT ENTRY MOV -2(R0),R4 ; R4 = NON-MATCHING TABLE ENTRY ASR R4 ; IS ITS UMR FREE? BCC 40$ ; NO, ALL DONE ASR R4 ; YES, IS IT A GROUP HEAD, TOO? BCS 40$ ; YES, ALL DONE 30$: INC R2 ; NO, COUNT IT BNE 10$ ; BR IF NOT THE FIRST ONE WE'VE FOUND MOV R4,-(SP) ; SAVE WORK REGISTER MOV R0,-(SP) ; SAVE 2 PAST POINTER TO 1ST ONE BR 10$ ; AND GO LOOK AT THE NEXT ONE ;+ ; IF R2 <> -1 THEN MATCH FOUND, R0 -> TABLE ENTRY AFTER 1ST NON-MATCH, ; R2 = GROUP SIZE - 1, THERE IS A POINTER TO FIRST MATCH + 2 ON THE STACK, ; AND R3 = NUMBER OF UMRS JUST FREED. ;- 40$: TST R2 ; DID WE FIND ANYTHING? BMI 50$ ; NO, TIME TO SPLIT INC R2 ; GET REAL COUNT SUB #2,@SP ; ADJUST POINTER TO 1ST OCCURRENCE MOV (SP)+,R0 ; R0 -> 1ST OCCURENCE MOV (SP)+,R4 ; RESTORE R4 TST (PC)+ ; CLEAR C-FLAG, SKIP NEXT INSTRUCTION 50$: SEC ; SET C-FLAG RETURN ; AU RESERVOIR ;+ ; REGROUP: REGROUP PERMANENT UMRS IF NECESSARY. ; ; CALLED BY: RLSUMR ; ; AT ENTRY: R0 -> GROUP HEADER OF FREED GROUP. ; R2 = GROUP SIZE OF FREED GROUP. ; R3 = NUMBER OF UMRS JUST FREED. ; ; ; AT EXIT: R0 -> GROUP HEADER OF NEW GROUP. ; R2 = GROUP SIZE NEW GROUP. ; R3 = UNCHANGED. ; ;- .ENABLE LSB REGROUP:MOV R0,-(SP) ; SAVE GROUP POINTER ASL R2 ; MAKE IT OFFSET INTO TABLE ADD R2,R0 ; POINT TO NEXT GROUP ASR R2 ; IT'S GROUP SIZE AGAIN CMP @R0,#UB.IOP ; NEXT GROUP END OF TABLE? BEQ 10$ ; YES, NO REGROUPING FORWARD CMPB @R0,#GETPRM ; NEXT GROUP NEED REGROUPING? BNE 10$ ; NO, NO REGROUPING FORWARD CLRB @R0 ; YES, CLEAR OUT FLAGS BYTE SWAB @R0 ; GET CROUP SIZE IN LOW BYTE ADD @R0,R2 ; AND INCREMENT THE SIZE COUNT 10$: MOV @SP,R0 ; GET 1ST OCCURRENCE FROM STACK MOV -(R0),R0 ; R0 = LAST ENTRY OF PREVIOUS GROUP BIT #GRPFRE,R0 ; LAST ENTRY IN GROUP FREE? BEQ 20$ ; NO, DON'T REGROUP BACKWARDS CLRB R0 ; CLEAR OUT HEADER INFO SWAB R0 ; AND PUT SIZE BYTE IN LOW BYTE ASL R0 ; MAKE IT AN OFFSET MOV @SP,-(SP) ; PUSH OUR POINTER SUB R0,@SP ; AND POINT TO THE GROUP HEADER CMPB #GETPRM,@(SP)+ ; DOES IT REQUIRE REGROUPING? BNE 20$ ; NO, GO ON SUB R0,@SP ; GET NEW POINTER ASR R0 ; MAKE IT A COUNTER AGAIN ADD R0,R2 ; AND ADJUST COUNTER 20$: MOV (SP)+,R0 ; R0 = NEW POINTER RETURN ; EXIT ;+ ; REINIT: ; ; REINITIALIZE NEWLY FREED UMR GROUP IN UBDATA. REINITIALIZE UMRS, TOO. ; ; AT ENTRY: R0 -> 1ST INSTANCE OF QEL OR $PNAME POINTER IN TABLE. ; R1 -> QEL OR HANDLER $PNAME TABLE ENTRY POINTER. ; R2 = GROUP SIZE. ; R3 = NUMBER OF UMRS FREED. ; ; AT EXIT: R0 -> 1ST INSTANCE OF QEL OR $PNAME POINTER IN TABLE. ; R2 = GROUP SIZE. ; UMR GROUP IS REINITIALIZED. ; ;- .ENABLE LSB REINIT: MOV R2,-(SP) ; SAVE GROUP SIZE MOV R2,R3 ; R3 = GROUP SIZE IN LOW BYTE SWAB R2 ; SET UP TABLE ENTRY MOV R0,R4 ; COPY ADDRESS OF 1ST MATCH TO R4 SUB #UBDATA+UB.UMR,R4 ; GET UBDATA TABLE OFFSET OF 1ST MATCH $REL .-2 UBDATA+UB.UMR UBR MOV R4,-(SP) ; SAVE UBDATA OFFSET ASR @SP ADC @SP ASL R4 ; MAKE IT UMR OFFSET ADD #UB$CSR,R4 ; MAKE IT UMR POINTER CMP (SP)+,@#PSTART ; PERMANENT OR TEMPORARY UMR? $REL .-2 PSTART UBR BMI 10$ ; TEMPORARY BIS #GRPPRM,R2 ; SET PERMANENT FLAG 10$: BIS #GRPFRE,R2 ; SET FREE FLAG AND GROUP HEADER FLAG MOV R0,-(SP) ; SAVE POINTER TO 1ST INSTANCE 20$: MOV R2,(R0)+ ; STORE IT IN TABLE MOV #UMRLO,(R4)+ ; REINIT UMR LOW MOV #UMRHI,(R4)+ ; AND UMR HI SOB R3,20$ ; AND GO DO ANOTHER, IF NECESSARY BIS #GRPHEA,@(SP) ; CAN ONLY HAVE ONE HEAD PER GROUP MOV (SP)+,R0 ; R0 -> 1ST INSTANCE MOV (SP)+,R2 ; RESTORE GROUP SIZE RETURN ; ADIEU ;+ ; ALLOC: ; ; ROUTINE TO ALLOCATE UMRS. ; ; AT ENTRY: R0 = NUMBER OF UMRS FOR THIS REQUEST ; R1 = PAR POINTER OR HANDLER BUFFER ADDRESS LOW ; R2 = 0 OR HANDLER BUFFER ADDRESS HIGH ; R3 = GETPRM OR GETTMP ; R4 -> QEL OR HANDLER ; ; AT EXIT: R4 PRESERVED ; IF C-BIT = 0 THEN UMRS ARE ALLOCATED AND ; R5 -> HEAD OF UMR GROUP. ; IF C-BIT = 1 THEN UMRS ARE NOT ALLOCATED AND ; R5 -> UB.IOP IN UBDATA. ; ;- .ENABLE LSB ALLOC: ;+ ; SEARCH FOR A MATCH TO INCOMING QEL OR XX: $PNAME TABLE ENTRY POINTER. ;- MOV R2,-(SP) ; SAVE ADDRESS INFO HI MOV R0,-(SP) ; SAVE GROUP SIZE MOV R1,-(SP) ; SAVE ADDRESS INFO LOW MOV R3,-(SP) ; SAVE TYPE OF REQUEST MOV R4,R1 ; R1 -> QEL OR $PNAME TABLE ENTRY CALL FNDQEL ; IS IT IN UBDATA? MOV (SP)+,R3 ; RESTORE TYPE OF REQUEST MOV (SP)+,R1 ; BCS 40$ ; NOT IN UBDATA, GO ALLOCATE CMP R3,#GETTMP ; CONTINUE IF TEMPORARY UMR BEQ 5$ ; MOV (SP)+,R0 ; ELSE RESTORE REGISTERS MOV (SP)+,R2 ; BR 80$ ; AND REFUSE THE REQUEST 5$: CMP #1,UBHOLD ; IT'S IN UBDATA, CHECK UBHOLD BCS 20$ ; UBHOLD SHOULD BE > 1 10$: HALT ; IT'S NOT SO CROAK BR 10$ ; FOR EVER AND EVER 20$: MOV R0,R5 ; R5 -> MATCHING UBDATA ENTRY MOV (SP)+,R0 ; RESTORE GROUP SIZE CMP R2,R0 ; GROUP BIG ENOUGH? MOV (SP)+,R2 ; *C* RESTORE R2 BCC 70$ ; YES, GO EXIT 30$: HALT ; >>> FATAL SYSTEM OR HANDLER ERROR! BR 30$ ; >>> LOOP TILL YOUR GUTS ROT OUT ;+ ; INCOMING QEL OR HANDLER NOT IN TABLE. TRY TO ALLOCATE UMRS FOR IT. ;- 40$: CMP #1,UBHOLD ; CHECK UBHOLD BLOS 60$ ; BR if UBIQUE held. 50$: HALT ; IT'S NOT SO CROAK BR 50$ ; FOR EVER AND EVER 60$: MOV (SP)+,R0 ; RESTORE GROUP SIZE MOV (SP)+,R2 ; RESTORE ADDRESS INFO CALL FNDGRP ; R5 -> UMRS FOR QEL BCS 80$ ; UNSUCCESSFUL, GO EXIT 70$: TST (PC)+ ; RESET C FLAG AND RETURN 80$: SEC ; FLAG NO UMRS AVAILABLE FOR REQUEST RETURN ;+ ; ; TMPINI: INITIALIZE UBDATA TABLE ENTRIES AND UMRS FOR ; TEMPORARY REQUEST. ; ; ENTRY: R0 = NUMBER OF UMRS ; R1 = BUFFER'S PAR VALUE OR PHYSICAL ADDRESS LOW ; R2 = 0 OR PHYSICAL ADDRESS HIGH ; R3 = ADDRESS TYPE INDICATOR ; R4 -> QEL ; R5 -> UBDATA ENTRY FOR 1ST UMR ; ; EXIT: R1 = NEW VALUE FOR Q.PAR ; R4 PRESERVED ; C-FLAG CLEAR ;- .ENABL LSB TMPINI: MOV R0,-(SP) ; SAVE NUMBER OF UMRS MOV R5,-(SP) ; SAVE UBDATA TABLE ENTRY POINTER 10$: MOV R4,(R5)+ ; UBDATA -> QEL OR HANDLER SOB R0,10$ ; LOOP IF NOT DONE INITIALIZING MOV (SP)+,R5 ; R5 -> UBDATA TABLE ENTRY MOV (SP)+,R0 ; R0 = NUMBER OF UMRS ;+ ; GET POINTER TO ACTUAL UMR(S) AND INITIALIZE THEM. ;- TST R3 ; TEST PHYSICAL ADDRESS VERSUS PAR BGT PHYINI ; PHYSICAL, GO DO PERMANENT TYPE INIT SUB #UBDATA+UB.UMR,R5 ; GET OFFSET TO UBDATA ENTRY $REL .-2 UBDATA+UB.UMR UBR ASL R5 ; MAKE IT AN OFFSET TO THE 1ST UMR MOV R5,-(SP) ; SAVE OFFSET FOR RETURN UMR POINTER ADD #UB$CSR,R5 ; R5 -> OUR UMR 20$: MOV R1,R2 ; R2 = R1 = PAR VALUE CLR R3 ; CLEAR OUT HIGH UMR VALUE MOV R0,-(SP) ; SAVE UMR COUNTER MOV #6,R0 ; SET UP COUNTER 30$: ASL R2 ; MULTIPLY BY TWO ROL R3 ; PUT CARRY INTO HIGH REGISTER SOB R0,30$ ; DO IT 6 TIMES MOV (SP)+,R0 ; RESTORE UMR COUNTER MOV R2,(R5)+ ; INITIALIZE UMR LOW MOV R3,(R5)+ ; INITIALIZE UMR HIGH ADD #200,R1 ; GET READY FOR POSSIBLE NEXT ADDRESS ADC R3 SOB R0,20$ ; BRANCH IF NOT DONE YET MOV (SP)+,R1 ; GET OFFSET OF UMR ASH #5,R1 ; MAKE IT AN INDEX IN BITS 7-11 CLC ; ALWAYS RETURN WITH C-FLAG CLEAR! RETURN ; EXIT ;+ ; ; PRMINI: INITIALIZE UBDATA TABLE ENTRIES AND UMRS FOR ; PERMANENT REQUEST. ; ; ENTRY: R0 = NUMBER OF UMRS ; R1 = BITS 0-15 OF BASE ADDRESS ; R2 = BITS 16-21 OF BASE ADDRESS ; R4 -> $PNAME TABLE ENTRY ; R5 -> UBDATA ENTRY FOR 1ST UMR ; ; EXIT: R1 = BITS 0-15 OF UNIBUS VA ; R2 = BITS 16,17 OF UNIBUS VA ; C-FLAG CLEAR ; ;- .ENABL LSB PRMINI: MOV R5,-(SP) ; SAVE UBDATA TABLE ENTRY POINTER MOV R0,-(SP) ; SAVE NUMBER OF UMRS REQUESTED 10$: MOV R4,(R5)+ ; UBDATA -> QEL OR HANDLER SOB R0,10$ ; LOOP IF NOT DONE INITIALIZING MOV @SP,R0 ; R0 = GROUP SIZE AGAIN CMP #UB.IOP,@R5 ; ARE WE AT END OF TABLE? BEQ 40$ ; YES, DON'T NEED TO REGROUP THEN BIT #GRPFRE,@R5 ; NEXT UMR FREE? BEQ 40$ ; NO, DON'T NEED TO REGROUP BIT #GRPHEA,@R5 ; YES, IS IT ALSO A GROUP HEADER? BNE 40$ ; YES, DON'T REGROUP ;+ ; MAKE A NEW GROUP OF PERMANENT UMRS... ;- CLR -(SP) ; CLEAR OUT STACK MOVB 1(R5),@SP ; PUT SIZE BYTE ON STACK SUB R0,@SP ; TOP OF STACK = # ENTRIES TO SIZE MOV @SP,R0 ; R0 = # ENTRIES TO SIZE SWAB @SP ; PUT SIZE IN HIGH BYTE BIS #GETPRM,@SP ; ADD SOME GROUP CHARACTERISTICS DATA MOV @SP,(R5)+ ; INITIALIZE GROUP HEADER BIC #GRPHEA,@SP ; CLEAR GROUP HEADER BIT 20$: DEC R0 ; DECREMENT GROUP COUNTER BEQ 30$ ; BRANCH IF NO MORE TO INITIALIZE MOV @SP,(R5)+ ; OTHERWISE, INITIALIZE NEXT ONE BR 20$ ; AND SEE IF THERE'S ANOTHER TO DO 30$: TSTB (SP)+ ; BALANCE STACK 40$: MOV (SP)+,R0 ; R0 = NUMBER OF UMRS MOV (SP)+,R5 ; R5 -> UBDATA TABLE ENTRY ;+ ; GET POINTER TO ACTUAL UMR(S) AND INITIALIZE THEM. ; ; R0 = # UMRS REQUESTED ; R1 = PHYSICAL ADDRESS LOW ; R2 = PHYSICAL ADDRESS HIGH ;- PHYINI: 50$: SUB #UBDATA+UB.UMR,R5 ; GET OFFSET TO UBDATA ENTRY $REL .-2 UBDATA+UB.UMR UBR MOV R5,-(SP) ; STACK UMR INDEX * 2 ASL R5 ; MAKE IT AN OFFSET TO THE 1ST UMR ADD #UB$CSR,R5 ; R5 -> OUR UMR 60$: MOV R1,(R5)+ ; INIT UMR LOW MOV R2,(R5)+ ; INIT UMR HIGH ADD #20000,R1 ; BASE ADDRESS FOR NEXT UMR ADC R2 ; SOB R0,60$ ; GO INITIALIZE IT, MAYBE MOV (SP)+,R1 ; RESTORE UMR INDEX * 2 CLR R2 ; CLEAR OUT HIGH WORD MOV #12.,-(SP) ; SET UP SHIFT COUNTER 70$: ASL R1 ; AND SHIFT INDEX * 2 TO BITS 13-18 ROL R2 DEC @SP BNE 70$ TST (SP)+ ; CLEAN STACK CLC ; CLEAR C-FLAG RETURN ; EXIT ;+ ; CHKQUE: ; ; ROUTINE TO LOOK FOR A QEL THAT WILL FIT A NEWLY FREED UMR GROUP, ; AND ALLOCATE THE GROUP IF FOUND. CHKQUE EXAMINES THE FIRST QEL ; ON EACH QUEUE, STARTING WITH THE 9421-QUEUE THAT CONTAINS QELS ; REQUIRING THE SAME GROUP SIZE AS THE NEWLY FREED GROUP, UNTIL ; IT HAS EITHER FOUND A MATCH OR IT HAS RUN OUT OF QUEUES. ; ; ENTRY: R0 -> 1ST UBDATA TABLE ENTRY FOR NEWLY FREED GROUP ; R2 = GROUP SIZE ; ALL REGISTERS AVAILABLE ; EXIT: ALL REGISTERS TRASHED PROBABLY ; ;- .ENABL LSB CHKQUE: MOV R0,-(SP) ; STACK UBDATA POINTER MOV R2,R0 ; R0 = GROUP SIZE CALL FND9421 ; R5 -> 9421-Q; R3 = # QS TO SEARCH TST (R5)+ ; R5 -> 9421-Q'S CQE CALL MAPGRP ; R1 = GRPMAP VALUE FOR RELEASED GROUP 10$: MOV @R5,R4 ; R4 -> QEL FROM CQE BEQ 20$ ; TRY NEXT QUEUE IF THIS ONE'S EMPTY MOV R1,-(SP) ; SAVE GRPTAB TABLE VALUE CALL ISNSPF ; IS NSPFUN OUTSTANDING? MOV (SP)+,R1 ; RESTORE TABLE VALUE BCC 20$ ; YES, NSPFUN OUTSTANDING, TRY NEXT MOV Q$LINK(R4),-(SP) ; ACCESS Q.LINK OF QUEUED ELEMENT BIC #177776,@SP ; CLEAR ALL BUT IMPORTANT BIT MOV Q$CSW(R4),-(SP) ; GET Q$CSW ASR (SP)+ ; SET C-FLAG FROM Q$CSW ROL @SP ; AND ROLL IT INTO STACKED WORD CMP (SP)+,R1 ; COMPARE SIZES BLE 30$ ; A FIT! GO INITIALIZE! 20$: CMP (R5)+,(R5)+ ; POINT TO NEXT QUEUE DEC R3 ; ONE LESS QUEUE TO SEARCH BEQ 40$ ; ALL DONE, NO MATCH BR 10$ ; GO LOOK AT NEXT QUEUE ; R4 -> QEL WHICH WILL USE THIS GROUP 30$: MOV R4,@(SP) ; INITIALIZE UBDATA ENTRY CMP R5,#JOB.Q ; IS THIS A JOB-Q? $REL .-2 JOB.Q UBX BCS 35$ ; NO, GO DO THE REQUE TST SERREQ ; OPERATION SHOULD BE SERIAL BEQ 34$ ; IT IS, CONTINUE 31$: HALT ; IT ISN'T, SO HALT BR 31$ ; FOREVER AND EVER 34$: MOV R4,SERREQ ; SHOW UB THIS IS SERIAL 35$: CALL DEREQ ; DEQUEUE FROM JOB-Q, REQUEUE TO XX: CMP R5,#JOB.Q ; IS THIS A JOB-Q? $REL .-2 JOB.Q UBX ; BCS 40$ ; NO, JUST RETURN CALL PRGJBQ ; YES, PURGE IT 40$: TST (SP)+ ; FIX STACK RETURN ;+ ; ; PRGCHQ: ; ; CALLED BY: ROUTINES THAT HOLD UB ; ; AT ENTRY: UB IS HELD ; ; AT EXIT: CHKQUE IS EMPTY ; UB IS UNHELD ;- .ENABL LSB PRGCHQ: 10$: MOV #CHKPND,R5 ; R5 -> CHKPND QUEUE $REL .-2 CHKPND UBX MOV @#PSW,-(SP) ; GET READY TO BIS #PRIO7,@#PSW ;;; RAISE PRIORITY CALL GETBUF ;;; R4 -> BUFFER? BCS 20$ ;;; NO, ALL DONE MOV (SP)+,@#PSW ;;; YES, RESTORE PRIORITY MOV B.TABL(R4),R0 ; R0 -> TABLE ENTRY MOV #FREQUE,R5 ; RETURN BUFFER TO FREE LIST $REL .-2 FREQUE UBX MOV @#PSW,-(SP) ; GET READY TO BIS #PRIO7,@#PSW ;;; RAISE PRIORITY CALL PUTBUF ;;; MOV (SP)+,@#PSW ;;; RESTORE PRIORITY BIT #GRPFRE,@R0 ; GROUP STILL FREE? BEQ 10$ ; NO!!! TST @#QUECNT ; ANYBODY WAITING FOR UMRS? $REL .-2 QUECNT UBR BEQ 10$ ; NO!!! MOVB 1(R0),R2 ; GET SIZE OF FREED ENTRY CALL CHKQUE ; TRY TO ALLOC FREE GROUP TO IT BR 10$ ; GO TRY FOR ANOTHER FREED GROUP 20$: CALL UNHOLD ;;; YES, UNHOLD UB MOV (SP)+,@#PSW ;;; RESTORE OLD PRIORITY RETURN ;+ ; ; PRGJBQ: ; ; ENTRY: R5 -> JOB-Q TO PURGE ; ; EXIT: JOB-Q PURGED UNTIL EITHER NSPFUN IS DISCOVERED ; OR REQUEST FOR UMRS THAT CANNOT BE ALLOCATED IS ; DISCOVERED. ;- .ENABL LSB PRGJBQ: 10$: TST (R5)+ ; TEST FOR QUEUE EMPTY; ADVANCE TO CQE BEQ 80$ ; EMPTY, ALL DONE MOV @R5,R4 ; R4 -> QEL CALL ISNSPF ; NON-STANDARD SPFUN OUTSTANDING? BCC 80$ ; YES, ALL DONE CALL REQTYP ; GET TYPE OF REQUEST TST R0 ; TEST TYPE OF REQUEST BEQ 40$ ; SEEK OR SPEC. DIR, NON-DMA N/SPFUN BPL 20$ ; READ, WRITE, OR DMA SPFUN, GO ALLOC MOV #1,R0 ; SHOW WANT NSPFUN OUTSTANDING = TRUE MOV Q$FUNC(R4),R1 ; R1 = WORD WITH JOBNUM IN IT BIC #^C,R1 ; CLEAR OUT EXTRANEOUS BITS CALL SETNSP ; SET NSPFUN OUTSTANDING FOR JOB-Q BIC #LDREQU,Q$FUNC(R4) ; CLEAR UB INTERNAL FLAG TST BYPASS ; THESE THINGS SHOULD HAPPEN SERIALLY BEQ 15$ ; BRANCH IF THEY DO 13$: HALT ; OTHERWISE HALT BR 13$ ; FOREVER AND EVER 15$: MOV R4,BYPASS ; TELL Q2UBAX TO BYPASS THIS QEL CALL DEREQ ; DEQUEUE FROM JOB-Q; REQUE TO XX BR 80$ ; SPLIT 20$: MOV R5,-(SP) ; SAVE QUEUE POINTER MOV Q$WCNT(R4),R5 ; PASS THE WORD COUNT TO GETNUM CALL GETNUM ; R0 = NUMBER OF UMRS FOR THIS REQUEST MOV R0,-(SP) ; STACK NUMBER OF UMRS MOV Q$PAR(R4),R1 ; R1 = PAR POINTER MOV #GETTMP,R3 ; R3 SHOWS TEMPORARY ALLOCATION CALL ALLOC ; R5 -> UMRS TO ALLOCATE? BCS 30$ ; NO, ALLOCATION UNSUCCESSFUL CLR R3 ; ADDRESS TYPE = PAR VALUE CALL TMPINI ; YES, INIT TEMPORARY UMRS, SET C-FLAG 30$: MOV (SP)+,R0 ; RESTORE NUMBER OF UMRS MOV (SP)+,R5 ; RESTORE QUEUE POINTER BCS 70$ ; BRANCH IF UNSUCCESSFUL MOV R1,Q$PAR(R4) ; MAKE Q$PAR A UMR POINTER ADD R0,@#UMRCNT ; UPDATE TOTAL UMRS ALLOCATED $REL .-2 UMRCNT UBR ADD R0,@#TMPCNT ; UPDATE TEMPORARY UMRS ALLOCATED $REL .-2 TMPCNT UBR 40$: BIC #LDREQU,Q$FUNC(R4) ; CLEAR UB INTERNAL FLAG TST BYPASS ; THIS STUFF SHOULD HAPPEN SERIALLY BEQ 60$ ; IT DOES 50$: HALT ; IT DOESN'T, LOGIC ERROR BR 50$ ; HALT FOREVER AND EVER 60$: MOV R4,BYPASS ; TELL Q2UBAX TO BYPASS THIS QEL CALL DEREQ ; DEQUEUE FROM JOB-Q; REQUE TO XX: BR 10$ ; GO EXAMINE NEXT QEL, IF ANY 70$: CALL QELINI ; INITIALIZE Q$LINK AND Q$CSW 80$: RETURN ;+ ; ; DEREQ: ; ; DEQUEUE QEL FROM QUEUE POINTED TO BY R5. REQUE QEL TO XX: ; ; CALLED BY: PRGJBQ ; ; ENTRY: R4 -> QEL TO REQUE ; R5 -> CQE OF ITS CURRENT QUEUE ; ; EXIT: R0-R4 TRASHED (PROBABLY) ; R5 -> LQE OF CURRENT QUEUE ; R5 INTACT ;- .ENABL LSB DEREQ: TST -(R5) ; POINT TO LQE MOV R5,-(SP) ; IT'S PRUDENT TO STACK LQE POINTER CALL FQD.FR ; DEQUEUE THIS QEL CALL REQUE ; REQUE THIS QEL TO XX: MOV (SP)+,R5 ; RESTORE LQE POINTER RETURN ;+ ; ; REQUE: ; ; REQUE QEL TO XX:. THE REQUE ENTRY POINT IN RMON IS CALLED. THIS ; ENTRY IS TWO WORDS BEFORE THE LD REQUE ENTRY. IT INCLUDES THE ; CALL TO KPSAVE, WHICH IS NECESSARY TO BALANCE THE STACK ON RETURN ; FROM QMANGR. ; ; CALLED BY: PRGJBQ, CHKQUE ; ; ENTRY: R4 -> QEL TO REQUE ; ; EXIT: R0-R5 TRASHED (PROBABLY) ; ;- .ENABL LSB REQUE: BIC #LDREQU,Q$FUNC(R4) ; CLEAR OUT REQUE FLAG CALL GRQADR ; R2 = REQUE ADDRESS ;>>> BCS ???? ; MARK W/ HARD ERROR & DRFIN? MOV @R2,R2 ; MOV Q$FUNC(R4),R0 ; PARAM FOR REQUE: R0 = JOBNUM BIC #^C,R0 ; ;; TST -2(R2) ; IS THE HANDLER HELD? mov R3,-(SP) mov r2,r3 tst -(r3) call @#ghword $rel .-2 ghword UBR mov (sp)+,r3 tst r5 ; IS THE HANDLER HELD? BPL 10$ ; NO, GO DO THE REQUE MOV #RPQ,R5 ; YES, WE MUST HAVE INTERRUPTED IT $REL .-2 RPQ UBX ; ENQUEUE TO END OF RPQ[SLOT #] ADD R3,R5 ; R5 -> RPQ[SLOT #] ; DON'T RAISE PRIORITY SINCE UB IS HELD & NO OTHER COMPLTS CAN GET HERE NOW? CALL @#QE.REA ; ENQUEUE TO THE END OF THE RPQ $REL .-2 QE.REA UBX BR 20$ ; BRANCH TO EXIT 10$: RMCALL REQADR ; Call REQUE entry in QMANGR 20$: RETURN ;+ ; ; GRQADR: GET REQUE ADDRESS FOR QUEUE ELEMENT. ; ; CALLED BY: DRBEG, REQUE ; ; ENTRY: R4 -> QEL TO REQUE ; ; EXIT: R2 -> XX ENTRY. ; R1 IS TRASHED. ; C-FLAG = 0 IF NO ERROR; ; C-FLAG = 1 IF XX IS LD AND ; THERE IS NO POINTER TO THE ; LD DATA TABLE. ; ;- .ENABL LSB GRQADR: CALL GTSLOT ; R1 = SLOT NUMBER OF XX: BCS 10$ ; BRANCH IF ERROR MOV @#$ENTPT,R2 ; R2 -> $ENTRY TABLE $REL .-2 $ENTPT UBR ADD R1,R2 ; R2 -> $ENTRY FOR HANDLER TST (PC)+ ; GOOD EXIT 10$: SEC ; BAD EXIT RETURN ;+ ; ; GTSLOT: RETURN SLOT NUMBER OF XX: ; ; ENTRY: R4 -> QEL ; ; EXIT: IF C-FLAG = 0 THEN R1 = SLOT NUMBER. ; IF C-FLAG = 1 THEN XX: IS LD AND ; LD HANDLER NOT V5.5+ COMPATIBLE. ; R0,R2,R3,R4,R5 PRESERVED. ; ;- .ENABL LSB GTSLOT: MOV R3,-(SP) ; SAVE REGISTERS MOV R5,-(SP) ; ; MOV @Q$CSW(R4),R1 ; R1 = CSW MOV Q$CSW(R4),R1 ; R1 -> CSW BIC #1,R1 ; CLEAR OUT LOW BIT MOV @R1,R1 ; R1 = CSW BIC #^C,R1 ; R1 = OFFSET INTO DEVICE TABLES BIT #LDREQU,Q$FUNC(R4) ; LD REQUE? BEQ 10$ ; NO, INDEX IS IN R1 MOV HF2TAB(R1),R3 ; R3 -> LD'S H1.FG2 WORD $REL .-2 HF2TAB UBX BEQ 20$ ; ERROR IF IT DOESN'T EXIST CALL @#GHWORD ; R5 = H1.FG2 WORD $REL .-2 GHWORD UBR BIT #HF2.LD,R5 ; V5.5 LD HANDLER? BEQ 20$ ; ERROR IF NOT ADD #6,R3 ; POINT TO LD TABLE ADDRESS CALL @#GHWORD ; R5 = LD TABLE ADDRESS $REL .-2 GHWORD UBR MOV R5,R3 ; R3 = LD TABLE FILE ADDRESS SUB #<1006-LD.FLG>,R3 ; MAKE IT A MEMORY ADDRESS ADD @#$ENTPT,R1 ; $REL .-2 $ENTPT UBR ADD @R1,R3 ; CALL UNWIND ; R1 = INDEX NUMBER OF XX: 10$: TST (PC)+ ; GOOD EXIT 20$: SEC ; BAD EXIT MOV (SP)+,R5 ; *C* RESTORE REGISTERS MOV (SP)+,R3 ; *C* RETURN ;+ ; ; UNWIND: STARTING WITH THE UNIT NUMBER OBTAINED ; FROM THE CSW, RETURN THE SLOT NUMBER OF ; THE DESTINATION HANDLER. ; ; ENTRY: R3 -> LDDATA TABLE ; R4 -> QEL ; ; EXIT: R1 = SLOT NUMBER ; R3, R5 TRASHED ; ;- .ENABL LSB UNWIND: MOV @Q$CSW(R4),-(SP) ; STACK CSW BIC #^C,@SP ; OFFSET INTO DEVICE TABLES MOV R3,-(SP) ; STACK LDDATA TABLE POINTER MOV Q$CSW(R4),R1 ; R1 -> CSW MOVB C.UNIT(R1),R1 ; R1 = 1ST LD UNIT NUMBER 10$: ASL R1 ; MAKE A LD DATA TABLE OFFSET ADD R1,R3 ; R3 -> LD DATA ENTRY CALL @#GHWORD ; R5 = LD DATA ENTRY $REL .-2 GHWORD UBR MOV R5,R1 ; R1 = LD DATA ENTRY BIC #^C,R1 ; R1 = TABLE INDEX OF HANDLER CMP R1,2(SP) ; IS IT LD'S SLOT NUMBER? BNE 20$ ; NO, DONE UNWINDING MOV @SP,R3 ; RESTORE LDDATA TABLE POINTER MOV R5,R1 ; R1 = LDDATA TABLE ENTRY BIC #^C,R1 ; CLEAR ALL BUT THE UNIT NUMBER SWAB R1 ; PUT IT IN LOW BYTE BR 10$ ; TRY AGAIN 20$: ADD #4,SP ; CLEAN THE STACK RETURN .SBTTL QUEUE PROCESSING SUBROUTINES ;+ ; ; QE.REAR: ; ; ENTRY: R4 -> QEL ; R5 -> LQE OF RPQ ; ; EXIT: QEL ENQUEUED TO REAR OF SPECIFIED QUEUE ; R3 IS DESTROYED ;- .ENABL LSB QE.REA: CLR Q$LINK(R4) ; CLEAR OUT LINK TO NEXT MOV @R5,R3 ; R3 -> LAST QUEUE ELEMENT BNE 10$ ; BRANCH IF QUEUE NOT EMPTY MOV R4,(R5)+ ; FILL IN LQE MOV R4,(R5)+ ; AND CQE BR 20$ ; AND DONE WITH IT 10$: MOV R4,Q$LINK(R3) ; OLD LAST -> NEW LAST MOV R4,@R5 ; LQE -> NEW LAST 20$: RETURN ;+ ; ; FQD.FR: ; ; ENTRY: R4 -> QEL ; R5 -> LQE OF FUNNY QUEUE (9421-Q OR JOB-Q) ; ; EXIT: QEL DEQUEUED FROM FRONT OF SPECIFIED QUEUE ; BITS 0 OF Q.LINK AND Q.CSW ARE CLEARED. ;- ; .ENABL LSB FQD.FR: TST (R5)+ ; POINT TO CQE, TEST QUEUE EMPTY BEQ 20$ ; QUEUE EMPTY, EXIT WITH C-FLAG SET DEC @#QUECNT ; ONE LESS QEL PENDING ALLOCATION $REL .-2 QUECNT UBR MOV @R5,R4 ; R4 -> QEL FROM FRONT OF QUEUE BIC #1,Q$LINK(R4) ; CLEAR BIT 0 OF Q.LINK FIELD BIC #1,Q$CSW(R4) ; CLEAR BIT 0 OF Q.CSW FIELD MOV Q$LINK(R4),@R5 ; CQE -> NEXT QEL BNE 10$ ; BRANCH IF QUEUE STILL NOT EMPTY CLR -(R5) ; IT'S EMPTY SO CLEAR LQE TOO 10$: CLR Q$LINK(R4) ; CLEAR QEL'S LINK WORD TST (PC)+ ; SHOW GOT QEL 20$: SEC ; SHOW DIDN'T GET ONE RETURN ;+ ; ; FQE.FR: ; ; ENTRY: R0 = NUMBER OF UMRS REQUIRED ; R4 -> QEL ; R5 -> LQE OF FUNNY QUEUE (9421-Q OR JOB-Q) ; UBIQUE IS HELD ; ; EXIT: QEL ENQUEUED TO FRONT OF SPECIFIED QUEUE ; BITS 0 OF Q.LINK AND Q.CSW FIELDS INITIALIZED ; UBIQUE IS HELD ;- .ENABL LSB FQE.FR: INC @#QUECNT ; ONE MORE QEL PENDING UMR ALLOC. $REL .-2 QUECNT UBR CMP MAXQUE,@#QUECNT ; TIME TO UPDATE MAXQUE? $REL .-2 QUECNT UBR BCC 10$ ; NO, CONTINUE MOV @#QUECNT,MAXQUE ; YES, COPY IT IN $REL .-4 QUECNT UBR 10$: TST (R5)+ ; ADVANCE TO CQE, TEST QUEUE EMPTY BNE 20$ ; BRANCH IF NOT EMPTY MOV R4,@R5 ; INITIALIZE CQE MOV R4,-(R5) ; INITIALIZE LQE BR 30$ ; AND EXIT FQE.F1: 20$: MOV @R5,Q$LINK(R4) ; NEW FRONT POINTS TO OLD FRONT MOV R4,@R5 ; INITIALIZE NEW FRONT 30$: CALL QELINI ; INITIALIZE BIT 0 Q.CSW AND Q.LINK RETURN ;+ ; ; FQE.RE: ; ; ENTRY: R0 = NUMBER OF UMRS REQUIRED ; R4 -> QEL ; R5 -> LQE OF FUNNY QUEUE ; UBIQUE IS HELD ; ; EXIT: QEL ENQUEUED TO REAR OF SPECIFIED QUEUE ; EITHER 9421-Q OR JOB-Q ; BITS 0 OF Q.LINK AND Q.CSW FIELDS INITIALIZED ; UBIQUE IS HELD ; R3 IS DESTROYED ;- .ENABL LSB FQE.RE: INC @#QUECNT ; ONE MORE QEL PENDING ALLOC. $REL .-2 QUECNT UBR CMP MAXQUE,@#QUECNT ; TIME TO UPDATE MAXQUE? $REL .-2 QUECNT UBR BCC 10$ ; NO, CONTINUE MOV @#QUECNT,MAXQUE ; YES, COPY IT IN $REL .-4 QUECNT UBR 10$: CLR Q$LINK(R4) ; CLEAR OUT LINK FIELD MOV @R5,R3 ; R3 -> LAST QUEUE ELEMENT BNE 20$ ; BRANCH IF QUEUE NOT EMPTY MOV R4,(R5)+ ; FILL IN LQE MOV R4,(R5)+ ; AND CQE BR 30$ ; AND DONE WITH IT FQE.R1: 20$: CMP -(R3),-(R3) ; R3 -> LINK FIELD OF QEL MOV @R3,-(SP) ; SAVE LINK FIELD OF OLD LAST MOV R4,@R3 ; OLD LAST -> NEW LAST ASR @R3 ; SHIFT IT ONCE TO RIGHT ASR (SP)+ ; GET BIT 0 ROL @R3 ; AND ROLL IT INTO LINK FIELD MOV R4,@R5 ; LQE -> NEW LAST 30$: CALL QELINI RETURN ;+ ; ; FQE.PR: ; ; ENTRY: R0 = NUMBER OF UMRS REQUIRED ; R4 -> QEL ; R5 -> LQE OF FUNNY QUEUE ; UBIQUE IS HELD ; ; EXIT: QEL ENQUEUED TO SPECIFIED QUEUE BY JOB PRIORITY ; EITHER 9421-Q OR JOB-Q ; BITS 0 OF Q.LINK AND Q.CSW FIELDS INITIALIZED ; UBIQUE IS HELD ; R1, R3, R5 DESTROYED ;- .ENABL LSB FQE.PR: INC @#QUECNT ; ONE MORE QEL PENDING ALLOC. $REL .-2 QUECNT UBR CMP MAXQUE,@#QUECNT ; TIME TO UPDATE MAXQUE? $REL .-2 QUECNT UBR BCC 10$ ; NO, CONTINUE MOV @#QUECNT,MAXQUE ; YES, COPY IT IN $REL .-4 QUECNT UBR 10$: MOV R5,R1 ; R1 -> LQE TST (R1)+ ; QUEUE EMPTY? BNE 20$ ; NO, BRANCH MOV R4,@R1 ; YES, INITIALIZE CQE MOV R4,-(R1) ; INITIALIZE LQE BR 60$ ; AND ALL DONE 20$: MOV @R1,R3 ; R3 -> QEL AT CQE CMP Q$FUNC(R3),Q$FUNC(R4) ; COMPARE JOBNUMS BHIS 30$ ; QUEUED ONE IS >= NEW ONE TST (R5)+ ; ADVANCE POINTER TO CQE BR FQE.F1 ; AND TO FRONT OF QUEUE 30$: MOV R3,R1 ; R1 IS TRAILER MOV Q$LINK(R1),R3 ; R3 -> NEXT QEL BIC #1,R3 ; MAKE IT A REAL POINTER BNE 40$ ; BRANCH IF R3 NOT NULL MOV R1,R3 ; R3 -> OLD LAST BR FQE.R1 ; GO PUT IT AT END OF QUEUE 40$: CMP Q$FUNC(R3),Q$FUNC(R4) ; COMPARE JOBNUMS BHIS 30$ ; QUEUED ONE IS >= NEW ONE ASR Q$LINK(R1) ; SET C=FLAG IF BIT 0 = 1 MOV R4,Q$LINK(R1) ; PREVIOUS ONE -> NEW ONE BCC 50$ ; SKIP NEXT IF BIT 0 WASN'T SET BIS #1,Q$LINK(R1) ; AND SET IT IF IT WAS 50$: MOV R3,Q$LINK(R4) ; NEW ONE -> NEXT ONE 60$: CALL QELINI ; INITIALIZE BITS 0 OF Q$LINK & Q$CSW RETURN ; THAT'S ALL FOLKS! ;+ ; ; QELINI: ; ; ROUTINE TO INITIALIZE BITS 0 OF A QEL'S Q.LINK AND Q.CSW FIELDS ; ; ENTRY: R0 = NUMBER OF UMRS REQUESTED ; R4 -> QEL ; ; EXIT: REGISTERS PRESERVED ;- .ENABL LSB QELINI: MOV R1,-(SP) ; SAVE R1 CALL MAPGRP ; R1 -> GRPMAP ASRB R1 ; BIT 0 SET? BCC 10$ ; NO, DON'T SET BIT 0 IN Q.CSW BIS #1,Q$CSW(R4) ; SET BIT 0 IN Q.CSW 10$: ASRB R1 ; BIT 1 SET? BCC 20$ ; NO, DON'T SET BIT 0 IN Q.LINK BIS #1,Q$LINK(R4) ; SET BIT 0 IN Q.LINK 20$: MOV (SP)+,R1 ; RESTORE R1 RETURN .SBTTL BUFFER PROCESSING ROUTINES ;+ ; GETBUF: ; ; INPUT: R5 -> 1 WORD QUEUE HEADER ; PRIORITY 7 ; ; OUTPUT: C-FLAG = 1 IF QUEUE EMPTY ; C-FLAG = 0 IF QUEUE NOT EMPTY ; AND R4 -> BUFFER FROM HEAD OF QUEUE ;- .ENABL LSB GETBUF: MOV @R5,R4 ;R4 -> BUFFER BEQ 10$ ;BRANCH IF NONE THERE MOV @R4,@R5 ;FILL IN NEW QUEUE HEAD CLR @R4 ;CLEAR OUT LINK TO NEXT TST (PC)+ 10$: SEC RETURN ;+ ; PUTBUF: ; ; INPUT: R4 -> BUFFER ; R5 -> 1 WORD QUEUE HEADER ; PRIORITY 7 ; ; OUTPUT: BUFFER IS AT HEAD OF SPECIFIED QUEUE ;- .ENABL LSB PUTBUF: MOV @R5,@R4 ;UPDATE NEW QUEUE HEAD POINTER TO NEXT MOV R4,@R5 ;STORE NEW QUEUE HEAD RETURN .SBTTL HF2TAB ROUTINES ;+ ; GETHF2: ; ; FUNCTION: INITIALIZE HF2TAB WITH POINTER TO XX:'S H1.FG2 WORD. ; IF HANDLER HAS NO EXTENDED DRBEG THEN THE TABLE ; ENTRY IS INITIALIZED TO ZERO. ; ; CALLED BY: Q2UBAL FOR ALL QUEUE ELEMENTS ; ; AT ENTRY: R2 -> XX ENTRY ; R4 -> QEL ; ; AT EXIT: R2 PRESERVED ; R1,R3 TRASHED ;- .ENABL LSB GETHF2: BIC #LDREQU,Q$FUNC(R4) ; CLEAR OUT LD REQUE FLAG MOV @Q$CSW(R4),R3 ; R3 = CSW BIC #^C,R3 ; R3 = INDEX ADD @#$PNMPT,R3 ; R3 -> $PNAME ENTRY $REL .-2 $PNMPT UBR CMP @R3,#<^RLD> ; CSW -> LD? BNE 5$ ; NO ADD @#DTABSZ,R3 ; R3 -> $ENTRY ENTRY $REL .-2 DTABSZ UBR CMP @R3,R2 ; IS IT A REQUE? BEQ 5$ ; NO, CONTINUE BIS #LDREQU,Q$FUNC(R4) ; YES, MARK QEL 5$: CALL GTSLOT ; R1 = SLOT NUMBER OF XX BCS 20$ ; BRANCH ON ERROR 10$: MOV @#$ENTPT,R3 ; R3 -> $ENTRY TABLE $REL .-2 $ENTPT UBR ADD R1,R3 ; R3 -> $ENTRY FOR HANDLER MOV @R3,R3 ; R3 -> 4TH WORD OF XX: BIT (R3)+,(R3)+ ; R3 -> EXTENDED .DRBEG DATA CALL @#GTHF2L ; Go to low mem code to peek $REL .-2 GTHF2L UBR ; into other handlers MOV R3,HF2TAB(R1) ; Store HF2TAB entry $REL .-2 HF2TAB UBX TST (PC)+ 20$: SEC RETURN ;+ ; REQTYP: ; ; FUNCTION: RETURN THE REQUEST TYPE OF THE QUEUE ELEMENT. ; ; CALLED BY: Q2UBAL, PRGJBQ ; ; AT ENTRY: R4 -> QEL ; ; AT EXIT: R1,R3 TRASHED ; IF C-FLAG = 0 THEN HANDLER IS DMA -- AND -- ; R0 = 1 MEANS .READX, .WRITX OR .SPFUN ; R0 = 0 MEANS SPECIAL DIR. REQUEST, SEEK ; OR NON-DMA N/SPFUN ; R0 = -1 MEANS DMA NON-STANDARD SPFUN ; ; IF C-FLAG = 1 THEN HANDLER IS NOT DMA -- OR -- ; HANDLER DOES NOT HAVE EXTENDED DRBEG ; AREA AND IS THEREFORE NOT V5.5 ; COMPATIBLE. ; ;- .ENABL LSB REQTYP: MOV R2,-(SP) ; SAVE REGISTERS MOV R5,-(SP) CALL GTSLOT ; R1 = SLOT NUMBER OF XX MOV HF2TAB(R1),R3 ; R3 -> HANDLER'S H1.FG2 WORD $REL .-2 HF2TAB UBX BEQ 70$ ; BRANCH IF NO EXTENDED DRBEG CALL @#GHWORD $REL .-2 GHWORD UBR BIT #HF2.DM,R5 ; DOES THIS HANDLER DO DMA? BEQ 70$ ; NO, ENQUEUE TO XB ;+ ; HANDLER HAS EXTENDED DRBEG SECTION AND HANDLER IS DMA. ;- MOV #1,R0 ; SET-UP R1 FOR RETURN MOVB Q$FUNC(R4),R2 ; R2 = FUNCTION BYTE CALL .64UNIT ; 64-UNIT MONITOR? BCS 10$ ; NO, CONTINUE BIT #HF2.64,R5 ; 64-UNIT HANDLER? BEQ 10$ ; NO, CONTINUE BICB #,R2 ; CLEAR OUT HIGH 3 UNIT # BITS BPL 20$ ; DO READX, WRITX, SPEC. DIR. OR SEEK BISB #,R2 ; MAKE SPFUN IN RANGE OF 360-377 BR 30$ ; JOIN UP W/ NORMAL SPFUN PROCESSING 10$: TSTB R2 ; IS IT A SPFUN? BMI 30$ ; YES, GO TEST FOR STANDARD SPFUN 20$: BNE 50$ ; BRANCH IF SPECIAL DIRECTORY TST Q$WCNT(R4) ; IS IT .READX, .WRITX, OR .SEEK? BEQ 50$ ; SEEK, GO EXIT BR 60$ ; READX OR WRITX, GO EXIT 30$: CMP (R3)+,(R3)+ ; POINT TO SPFUN TABLE POINTER BIT #HF2.SD,R5 ; TABLE OF STANDARD SPFUNS EXIST? BEQ 40$ ; NO, GO CHECK NSPFUN TABLE CALL SPFCHK ; GO SEE IF OURS IS IN TABLE BCC 60$ ; IT IS, GO DO DMA SPFUN EXIT 40$: BIT #HF2.ND,R5 ; TABLE OF NSPFUNS EXIST? BEQ 50$ ; NO, GO TO NON-DMA SPFUN EXIT CMP (R3)+,(R3)+ ; POINT TO NSPFUN TABLE POINTER CALL SPFCHK ; IS OURS IN NSPFUN TABLE? BCS 50$ ; NO, GO DO NON-DMA SPFUN EXIT DEC R0 ; DMA NON-STANDARD SPFUN EXIT 50$: DEC R0 ; SEEK, SPEC DIR, NON-DMA N/SPFUN EXIT 60$: TST (PC)+ ; READX, WRITX, DMA SPFUN EXIT 70$: SEC ; NOT DMA OR NOT V5.5 EXIT MOV (SP)+,R5 ;*C* RESTORE REGISTERS MOV (SP)+,R2 ;*C* RETURN ;+ ; SPFCHK: ROUTINE TO CHECK A .DRSPF EXTENSION TABLE IN XX: ; TO SEE IF INCOMING N/SPFUN IS IN THE TABLE. ; ; CALLERS: REQTYP ; ; ENTRY: R1 = SLOT NUMBER FOR XX: ; R2 = SPFUN CODE OF QEL ; R3 -> OFFSET OF .DRSPF EXTENSION TABLE IN EXTENDED .DRBEG ; R4 -> QEL ; R5 -> CONTENT OF H1.FG2 WORD ; ; EXIT: R0,R1,R2,R3,R4,R5 PRESERVED ; C = 0 MEANS SPFUN CODE IN R2 IS IN TABLE ; C = 1 MEANS NOT IN TABLE ;- .ENABL LSB SPFCHK: MOV R1,-(SP) ; SAVE REGISTERS MOV R3,-(SP) MOV R5,-(SP) CALL @#GHWORD ; R5 = OFFSET TO EXTENSION TABLE $REL .-2 GHWORD UBR MOV R5,R3 SUB #1006,R3 ; R3 = FILE OFFSET TO EXTENSION TABLE ADD @#$ENTPT,R1 ; R1 -> $ENTRY TABLE ENTRY FOR XX: $REL .-2 $ENTPT UBR ADD @R1,R3 ; R3 -> .DRSPF EXTENSION TABLE 10$: CALL @#GHWORD ; R5 = DRSPF EXTENSION TABLE VALUE $REL .-2 GHWORD UBR TST R5 ; AT END OF TABLE? BEQ 30$ ; BRANCH TO "IT'S NOT THERE" EXIT TST (R3)+ ; ADVANCE .DRSPF EXTENSION TABLE POINTER MOVB R2,R1 ; R1 = QEL'S SPFUN CODE SWAB R1 ; GET IT IN HIGH BYTE FOR COMPARISON XOR R5,R1 ; CLEAR ALL MATCHING BITS BIC #003777,R1 ; LOOK ONLY AT HIGH FIVE BITS BNE 10$ ; IF THEY DON'T MATCH, GO LOOK AT NEXT ENTRY MOVB R2,R1 ; GET FUNCTION CODE AGAIN BIC #177770,R1 ; ISOLATE LOW OCTAL DIGIT .ADDR #BITABL,R1,ADD ; POINT TO BIT TABLE ENTRY BITB R5,@R1 ; IS BIT ON? BEQ 10$ ; NO, GO TRY NEXT TABLE ENTRY 20$: TST (PC)+ ; DO SPFUN IN TABLE EXIT 30$: SEC MOV (SP)+,R5 ;*C* RESTORE REGISTERS MOV (SP)+,R3 ;*C* MOV (SP)+,R1 ;*C* RETURN BITABL: .BYTE 1,2,4,10,20,40,100,200 ;+ ; ; .64UNIT: ; ; ENTRY: R4 -> QEL ; ; EXIT: ALL REGISTERS PRESERVED ; C-FLAG = 0 IF 64 UNIT MONITOR & HANDLER ; = 1 OTHERWISE ; ;- .ENABL LSB .64UNIT:MOV R3,-(SP) ; SAVE REGISTERS MOV R5,-(SP) MOV #$SYPTR,R3 ; GET POINTER TO FIXED AREA CALL @#GHWORD $REL .-2 GHWORD UBR MOV R5,R3 ADD #$CNFG3,R3 ; GET $CNFG3 CALL @#GHWORD $REL .-2 GHWORD UBR BIT #CF3.64,R5 ; IS THIS A 64-UNIT MONITOR? BNE 10$ ; NO TST (PC)+ ; YES 10$: SEC MOV (SP)+,R5 ;*C* RESTORE REGISTERS MOV (SP)+,R3 RETURN ;+ ; ; XXSERI: ; ; ENTRY: R4 -> QEL ; ; EXIT: R1 IS TRASHED ; R2 = XX ENTRY OR 0 ; C-FLAG = 0 IF HANDLER SERIAL ; = 1 IF HANDLER HAS NO EXTENDED DRBEG ; OR IF HANDLER NOT SERIAL ; ;- .ENABL LSB XXSERI: CALL GTSLOT ; R1 = HANDLER'S DEVICE TABLE INDEX MOV HF2TAB(R1),R1 ; DOES HANDLER HAVE EXTENDED DRBEG? $REL .-2 HF2TAB UBX BEQ 10$ ; NO, (GUESS IT CAN'T BE SERIAL THEN.) ; BIT #HF2.SR,@R1 ; HANDLER REQUIRE SERIALIZATION? ### ; BEQ 10$ ; NO, TAKE NO SERIAL EXIT mov r5,-(sp) mov r3,-(sp) mov r1,r3 ; ADDRESS OF HANDLER WORD call @#ghword $rel .-2 ghword UBR mov (sp)+,r3 bit #hf2.sr,r5 ; hANDLER REQUIRES SERIALIZATION? beq 20$ mov (sp)+,r5 TST (PC)+ ; HANDLER SERIAL EXIT 10$: SEC ; HANDLER NO SERIAL EXIT RETURN 20$: mov (sp)+,r5 br 10$ .SBTTL SET/READ JOB FLAGS SUBROUTINES ;+ ; ; ISSERI: ; ; ENTRY: R4 -> QEL ; ; EXIT: R1 IS TRASHED ; IF C-FLAG = 0 THEN JOB IS SERIAL ; IF C-FLAG = 1 THEN JOB IS NOT SERIAL ; ;- .ENABL LSB ISSERI: MOV Q$FUNC(R4),R1 ; R1 = WORD CONTAINING JOBNUM BIC #^C,R1 ; ISOLATE IT ASH #-12.,R1 ; MAKE IT OFFSET INTO JOB FLAG BYTES BITB #B.SERI,JOBFLG(R1) ; JOB SET SERIAL? $REL .-2 JOBFLG UBR BEQ 10$ ; NO, NO IT ISN'T TST (PC)+ ; JOB SERIAL EXIT 10$: SEC ; JOB NO SERIAL EXIT RETURN ; (THAT WAS FOR CONVENTION'S SAKE) ;+ ; ; ISNSPF: ; ; ENTRY: R4 -> QEL ; ; EXIT: R1 IS TRASHED ; IF C-FLAG = 0 THEN NSPFUN IS OUTSTANDING ; IF C-FLAG = 1 THEN NSPFUN IS NOT OUTSTANDING ; ;- .ENABL LSB ISNSPF: MOV Q$FUNC(R4),R1 ; R1 = WORD CONTAINING JOBNUM BIC #^C,R1 ; ISOLATE IT ASH #-12.,R1 ; MAKE IT OFFSET INTO JOB FLAG BYTES BITB #B.NSPF,JOBFLG(R1) ; JOB HAS NSPFUN OUTSTANDING? $REL .-2 JOBFLG UBR BEQ 10$ ; IT DOESN'T TST (PC)+ ; NSPFUN OUSTSTANDING EXIT 10$: SEC ; NSPFUN NOT OUTSTANDING EXIT RETURN ;+ ; ; SETNSP: ; ; ENTRY: R0 = 0 FOR NON-STANDARD SPFUN OUTSTANDING = FALSE ; 1 FOR NON-STANDARD SPFUN OUTSTANDING = TRUE ; R1 = JOBNUM IN BITS 11-14 ; EXIT: R1 IS TRASHED ; NSPFUN IS MARKED AS OUTSTANDING OR NOT FOR JOB-Q ; ;- .ENABL LSB SETNSP: ASH #-12.,R1 ; MAKE IT OFFSET INTO JOB FLAG BYTES TST R0 ; SET OR CLEAR FLAG? BNE 10$ ; BRANCH TO SET BICB #B.NSPF,JOBFLG(R1) ; FLAG NSPFUN NOT OUTSTANDING $REL .-2 JOBFLG UBR BR 20$ 10$: BISB #B.NSPF,JOBFLG(R1) ; FLAG NSPFUN OUTSTANDING $REL .-2 JOBFLG UBR 20$: RETURN .SBTTL LOCATE INTERNAL QUEUE SUBROUTINES ;+ ; ; FND9421: ; ; ENTRY: R0 = NUMBER OF UMRS REQUESTED ; ; EXIT: R3 = # OF QUEUES TO SEARCH ; R5 -> LQE OF 9421-Q FOR QEL ; R1 TRASHED ;- .ENABL LSB FND9421: CALL MAPGRP ; R1 = GROUP MAP VALUE ASL R1 ; MAKE IT INTO Q.OFFS TABLE OFFSET MOV #Q.OFFS,R3 ; R3 -> TABLE OF QUEUE OFFSETS $REL .-2 Q.OFFS UBX ADD R1,R3 ; R3 -> TABLE ENTRY MOVB (R3)+,R5 ; R5 = OFFSET OF 9421-Q MOVB (R3)+,R3 ; R3 = # OF QUEUES TO GO TO LAST JOB-Q ADD #Q.9421,R5 ; R5 -> 9421-Q FOR REQUEST $REL .-2 Q.9421 UBX RETURN ;+ ; ; MAPGRP: ; ; ENTRY: R0 = NUMBER OF UMRS REQUESTED ; ; EXIT: R1 = GRPMAP VALUE FOR NUMBER REQUESTED ; ;- .ENABL LSB MAPGRP: MOV #GRPMAP,R1 ; R1 -> GRPMAP $REL .-2 GRPMAP UBR ADD R0,R1 ; INDEX INTO GRPMAP MOVB @R1,R1 ; R1 = TABLE VALUE RETURN ;+ ; ; FNDJBQ: ; ; ENTRY: R4 -> QEL ; ; EXIT: R5 -> JOB-Q FOR QEL ; ;- .ENABL LSB FNDJBQ: MOV Q$FUNC(R4),R5 ; R5 = WORD CONTAINING JOBNUM BIC #^C,R5 ; CLEAR ALL BUT JOBNUM ASH #-10.,R5 ; MAKE IT = TO PRIORITY * 4 SUB #<7*4>,R5 ; REVERSE IT NEG R5 ; MAKE IT POSITIVE ADD #JOB.Q,R5 ; ADD JOB-Q START TO OFFSET $REL .-2 JOB.Q UBX RETURN ;+ ; >>> THIS CODE WAS INTENDED FOR USE WHEN UB FUNCTIONALITY ; >>> SPECIFIED SERIALIZATION BASED ON JOB AND CHANNEL. ; >>> THE CURRENT SPECIFICATION IS FOR SERIALIZATION BASED ; >>> ON JOB ONLY. ; ; FNDCHN: ; ; ENTRY: R4 -> QEL ; R5 -> JOB-Q FOR QEL ; ; EXIT: C-FLAG = 0 MEANS MATCHING CHANNEL FOUND ; C-FLAG = 1 MEANS MATCHING CHANNEL NOT FOUND ; R4, R5 PRESERVED ;- .ENABL LSB ;FNDCHN:MOV R5,-(SP) ; STACK LQE POINTER ; TST (R5)+ ; ADVANCE TO CQE; TEST EMPTY ; BEQ 30$ ; IF EMPTY EXIT W/CHAN NOT FOUND ; MOV @R5,R5 ; R5 -> QEL ;10$: MOV Q$CSW(R5),-(SP) ; STACK CSW POINTER ; BIC #1,@SP ; CLEAR BIT 0 INFORMATION ; CMP (SP)+,Q$CSW(R4) ; DO CSW ADDRESSES MATCH? ; BEQ 20$ ; YES, DO CHANNEL FOUND EXIT ; MOV Q$LINK(R5),R5 ; POINT TO NEXT QEL ; BIC #1,R5 ; CLEAR BIT 0 INFORMATION ; BEQ 30$ ; IF NULL, DO CHANNEL NOT FOUND EXIT ; BR 10$ ; GO CHECK THIS ONE OUT ;20$: TST (PC)+ ; FLAG CHANNEL FOUND ;30$: SEC ; FLAG CHANNEL NOT FOUND ; MOV (SP)+,R5 ; RESTORE QUEUE POINTER ; RETURN ;+ ; ; FNDGRP: ; ; ENTRY: R0 = NUMBER OF UMRS FOR THIS REQUEST ; R3 = GETPRM OR GETTMP ; R4 -> QEL OR HANDLER ; ; ; EXIT: REGISTERS EXCEPT FOR R5 ARE PRESERVED ; C-FLAG = 0 MEANS R5 -> UMR GROUP ; C-FLAG = 1 MEANS FREE UMR GROUP NOT FOUND ;- .ENABL LSB FNDGRP: MOV #UBDATA+UB.UMR,R5 ; GET THE BEGINNING OF UBDATA $REL .-2 UBDATA+UB.UMR UBR 10$: CMPB R3,@R5 ; IS IT THE TYPE WE'RE LOOKING FOR? BEQ 30$ ; YES, GO SEE IF IT'S OUR SIZE 20$: TST (R5)+ ; NO, POINT TO NEXT TABLE ENTRY CMP #UB.IOP,@R5 ; AT END OF TABLE? BNE 10$ ; NO, GO CHECK OUT THIS ENTRY BR 50$ ; YES, GO TO GROUP NOT FOUND EXIT 30$: CMPB 1(R5),R0 ; IS SHOULD BE >= OUR NEED BCS 20$ ; ALAS, IT IS NOT... GO CHECK NEXT ONE 40$: TST (PC)+ ; CLEAR CARRY, SKIP NEXT INSTRUCTION 50$: SEC ; SET CARRY RETURN ; AU REVOIR MON AMI .SBTTL HOLD/UNHOLD UB ROUTINES ;+ ; HOLD: ROUTINE TO HOLD UB ;- .ENABL LSB HOLD: INC UBHOLD ;DO IT RETURN ;+ ; UNHOLD: ROUTINE TO UNHOLD UB ;- .ENABL LSB UNHOLD: TST UBHOLD ;UB HELD? BGT 20$ ;YES, GO UNHOLD 10$: HALT ;EXPIRE BR 10$ 20$: DEC UBHOLD ;AND DO IT RETURN .DSABL LSB .SBTTL UB LOAD CODE .PSECT SETOVR ;+ ; UBLOAD:: ; ; UBLOAD IS CALLED TWICE BY THE BOOTSTRAP. INTERRUPTS ARE ; NOT DISABLED DURING INITIALIZATION OF UBDATA DURING THE ; SECOND LOAD PROCEDURE BECAUSE BSTRAP DOES WAIT MODE I/O. ; ; THE FIRST CALL PERFORMS THE FOLLOWING TASKS: ; ; o RELOCATES POINTERS WITHIN UB. ; o PERFORMS UMR GROUPING WITH PERMANENT UMRS FOR SY: ; o INITIALIZES THE UBDATA TABLE AND THE UMRS. ; o CONNECTS UB TO THE SYSTEM. ; o LOADS UP THE RMON QHOOKS IN QMANGR. ; ; THE SECOND CALL PERFORMS THE FOLLOWING TASKS: ; ; o IF THE INSTALLED HANDLERS REQUIRE PERMANENT ; UMRS THEN RE-GROUPS THE UMRS AND RE-INITIALIZES ; THE UBDATA TABLE. ; ; A UBSTAT WORD IS MAINTAINED TO RECORD THE STATE OF THE UB ; INITIALIZATION PROCESS. IT IS USED DURING INITIALIZATION ; OF UBDATA TABLE. ; ; ENTRY: ; ; R0 CONTAINS STARTING ADDRESS OF THE CURRENT RUNNING ; HANDLER SERVICE ROUTINE. ; R1 IF BIT 15 = 0 THEN THIS IS UB LOAD PART 1 AND ; BITS 0-3 ARE A COUNT OF THE NUMBER OF PERMANENT ; UMRS REQUIRED BY SY. IF BIT 15 = 1 THEN THIS ; IS UB LOAD PART 2 AND BITS 0-5 ARE A COUNT OF ; THE NUMBER OF PERMANENT UMRS REQUIRED BY ALL OTHER ; INSTALLED HANDLERS. ; R2 CONTAINS THE VALUE $SLOT*2 (THE LENGTH OF THE $PNAME ; TABLE IN BYTES. ; R3 TYPE OF ENTRY. ; R4 ADDRESS OF READ FROM SYSTEM DEVICE ROUTINE. ; R5 POINTER TO $ENTRY TABLE SLOT FOR THIS HANDLER. ; ;- .ENABLE LSB ; UB Load Code Enters here: UBLOAD:: MOV R4,(PC)+ ; Save address of BSTRAP READ BRDRTN: .WORD 0 MOV R5,(PC)+ ; Save $ENTRY SENTRY: .WORD 0 MOV R2,(PC)+ ; Save $SLOT*2 SSLOT: .WORD 0 MOV @R5,R0 ; R0 -> START OF UB INC (R0) ; NEW STATE IS LD1INP OR LD2INP TST R1 ; IS THIS LOAD 2? BMI DOLD2 ; YES, JUMP CALL DOLD1 ; NO, DO LOAD 1 BR 20$ ; AND SPLIT ...... .SBTTL DOLD2 - Second Call to UBLOAD DOLD2: TST (R0) ; IS UB SET PERM? BMI 5$ ; NO, DON'T MANIPULATE GROUPING MOV (R0),R1 ; YES, GET NUMBER OF PERMANENT UMRS 5$: BIC #^C,R1 ; MASK # PERMANENT UMRS BEQ 20$ ; NONE REQUESTED, DONE LOAD 2 TST (R0) ; OUTSTANDING TEMPORARY UMRS? BNE 30$ ; YES, RETURN ERROR MOV R1,-(SP) ; SAVE # PERMANANT UMRS FOR HANDLERS MOVB (R0),R1 ; R1 = NUMBER PERMANENT UMRS FOR SY MOV #,R2 ; R2 = TOTAL NUMBER UMRS (NOT IOPAGE) SUB R1,R2 ; R2 = NUMBER TEMPORARY UMRS MOV #,R3 ; R3 = OFFSET TO UBDATA ADD R0,R3 ; R3 -> UBDATA 10$: CLR (R3)+ ; CLEAR OUT UBDATA ENTRIES SOB R2,10$ ; FOR ALL TEMPORARY UMRS ADD (SP)+,R1 ; R1 = TOTAL NUMBER PERMANENT UMRS MOV @#RMONPT,R4 ; R4 -> START OF RMON CALL INITBL ; RE-INIT UBDATA TABLE 20$: INC (R0) ; NEW STATE IS EITHER LD1CMP OR LD2CMP TST (PC)+ ; CLEAR CARRY AND SKIP NEXT RTNERR: 30$: SEC ; SET CARRY RETURN ;+ ; DOLD1: ; ; PERFORM UB LOAD PART ONE. ;- .ENABLE LSB ; R0 = UB base address DOLD1: MOV R1,(PC)+ ; Save no. of UMRs needed by SY SYUMRS:.WORD 0 LODCALL MAKREG in LBLK2 ; Load overlay, create UBX region BCS RTNERR ; get out if error ; Use the upper block of this USR buffer to read the UBX stuff from ; the handler file. Transfer it to the UBX region and $REL it. ; Then connect UB to the system. CALL READUP ; Read/Relocate UBX Code/Data ; (R3 now holds UB's base address) BCS RTNERR ; get out if error LODCALL RELOCT in LBLK2 MOV R3,R0 ; Put UB Base address back in R0 MOV SSLOT,R2 ; Let R2=$SLOT*2 LODCALL HOOKIN in LBLK1 RETURN ; From LOAD CODE Pass-1 .SBTTL RDOVLY - Read LOAD CODE overlay ;+ ; Read a LOAD CODE overlay into the USR buffer ; ; On entry, ; R1 = relative block no. of desired overlay ;- RDOVLY: MOV R0,-(SP) MOV R2,-(SP) MOV R3,-(SP) CALL UPSET ; determine starting block of UBX.SYS ADD R1,R0 ; and block of desired overlay MOV #256.,R1 ; word count .ADDR #LBLK1,R2 ; Buffer address CALL @BRDRTN ; Call BSTRAP's READ routine MOV (SP)+,R3 MOV (SP)+,R2 MOV (SP)+,R0 RETURN .SBTTL READUP - Move Psect UBX to High Memory ;+ ; READUP - Move Psect UBX to High Memory ; ; READUP is executed, as part of the BSTRAP LOAD process, out of the ; USR buffer. Thus it is guaranteed to be free of PAR1. ; ; On entry, ; R3 -> Handler + 6 (saved) ; R0,R1,R2,R4,R5 are destroyed ;- .ENABL LSB READUP::CALL UPSET ;Setup for the move ADD #UBXBAS/BLK,R0 ;Add block offset to start read MOV #UBXByt,R4 ;R4 = Size of XM psects MOV #P1ADDR,R5 ;starting virtual address MOV @#KISAR1,-(SP) ;Save mapping MOV (R3),@#KISAR1 ;Map to high memory MOV R3,-(SP) ;protect R3 CLR R3 10$: MOV #BLK,R1 ;Prepare to read 1 block. CMP R4,R1 ;Read less than 1 block ? BGE 20$ ;Yes, branch MOV R4,R1 ;Use the remaining byte count 20$: SUB R1,R4 ;Update bytes left. ASR R1 ;R1 = wordcount .ADDR #LODBUF,R2 ;R2 -> buffer to read MOV R1,-(SP) ;protect R1 from system read routine CALL @BRDRTN ;Read UBX MOV (SP)+,R1 ;*C* BCS 40$ ;jump if error 30$: MOV (R2)+,(R5)+ ;Store word SOB R1,30$ ;Loop till finished INC R0 ;Next block TST R4 ;Any more to read? BNE 10$ ;Branch if more 40$: MOV (SP)+,R3 ;*C* restore R3 to handler + 6 MOV (SP)+,@#KISAR1 ;*C* restore mapping RETURN .DSABL LSB ;+ ; UPSET - Setup to Move Psect UBX to High Memory ; ; This routine is called by READUP to do some of the ; address calculations for the move of psect UBX to high memory. ; ; Input: ; ; ; Output: ; R0 = block # where UB begins on system device ; R1,R2,R3 not altered ;- .ENABL LSB UPSET: MOV SENTRY,R2 ; $ENTRY value MOV SSLOT,R0 ; SLOT*2 ASL R0 ;R0 = *2 ADD R2,R0 ;R0 = $ENTRY + *2 ADD #2,R0 ;$ENTRY + *2 + 2 MOV @R0,R0 ;R0 -> Starting block UBX.SYS + 1 DEC R0 ;Subtract 1 RETURN ;Get out of buffer before we read!! .DSABL LSBB .SBTTL LOAD code - Second Block .ASSUME . LE UBLOAD+<1*BLK>, MESSAGE=<;UBX LOAD CODE overflow in 1st block> . = ; Start on even block boundary LODBUF: ; This area serves as the LOAD buffer LBLK1:: ; Load code BLOCK 1 (second block) ;+ ; HOOKIN: ; Initialize device table pointers. ; ; On entry: ; R0 = Loaded Handler Base Address ; R2 = $SLOT*2 ; ; On exit: ; R1,R3,R5 clobbered ;- .ENABL LSB HOOKIN:: MOV @#$SYPTR,R4 ; R4 -> START OF RMON MOV $PNPTR(R4),R3 ; R3 = RMON OFFSET TO $PNAME TABLE ADD R4,R3 ; R3 -> $PNAME TABLE MOV R3,<$PNMPT-UBBASE>(R0) ; $PNMPT -> $PNAME TABLE ADD R2,R3 ; R3 -> $ENTRY TABLE MOV R3,<$ENTPT-UBBASE>(R0) ; $ENTPT -> $ENTRY TABLE MOV R2,DTABSZ-UBBASE(R0) ; DTABSZ = SLOT*2 ;+ ; PERFORM GROUPING AND INIT UBDATA ;- MOV SYUMRS,R1 ; Get no. of UMRs needed by SY CALL INITBL ; INIT UBDATA TABLE ;+ ; INITIALIZE UMRS. NOTE: BSTRAP TURNS ON UNIBUS MAPPING ; JUST BEFORE IT IS READY TO START USING SYSTEM IO ROUTINES. ;- MOV #UB$CSR,R5 ; R5 -> 1ST UMR MOV #UMRS-1,R1 ; NUMBER OF UMRS TO LOAD 10$: MOV #UMRLO,(R5)+ ; LOAD EACH UMR MOV #UMRHI,(R5)+ ; WITH 17740000 SOB R1,10$ ; CLR (R5)+ ; LOAD I/O PAGE UMR CLR (R5)+ ; WITH ZERO ;+ ; CONNECT UB TO THE SYSTEM. ;- BIS #CF3.UB,$CNFG3(R4) ; SET CF3.UB BIT BIS #CF3.UA,$CNFG3(R4) ; SHOW UB ACTIVE MOV #,R1 ; R1 = UB OFFSET TO UBVECT ADD R0,R1 ; R1 -> UBVECT MOV R1,$H2UB(R4) ; INIT POINTER TO UB ENTRY VECTOR ;+ ; INITIALIZE THE RMON QHOOKS. ;- MOV $QHOOK(R4),R3 ; R3 -> RMON QHOOKS IN QMANGR MOV R3,-(SP) ; STACK IT MOV QH.CNX(R3),R3 ; R3 -> RMON QHOOKS IN COMPLT MOV R3,-(SP) ; STACK IT MOV FH.UNX(R3),R3 ; R3 -> RMON QHOOKS IN UNHOLD MOV R3,-(SP) ; STACK IT MOV UH.UNX(R3),R3 ; R3 -> RMON QHOOKS IN ABTQUE MOV AH.RQE(R3),(R0) ; LOAD REQUE ADDRESS MOV #CALOPC,AH.UBR(R3) ; LOAD CALL OPCODE MOV #,R1 ; R1 = OFFSET TO ABTQUE QHOOK ADD R0,R1 ; R1 -> ABTQUE QHOOK IN UB MOV R1,AH.RQE(R3) ; INIT DESTINATION OF HOOK IN ABTQUE MOV (SP)+,R3 ; R3 -> UNHOLD QHOOK MOV #,R1 ; R1 = OFFSET TO HOOK ADD R0,R1 ; R1 -> HOOKED ROUTINE IN UB MOV R1,UH.UNX(R3) ; INIT DESTINATION OF HOOK IN UNHOLD MOV #CALOPC,UH.UBR(R3) ; LOAD CALL OPCODE MOV (SP)+,R3 ; R3 -> COMPLT QHOOK MOV #,R1 ; R1 = OFFSET TO COMPLT QHOOK ADD R0,R1 ; R1 -> COMPLT QHOOK IN UB MOV R1,FH.UNX(R3) ; INIT DESTINATION OF HOOK IN COMPLT MOV #CALOPC,FH.UBR(R3) ; INSERT CALL OPCODE MOV (SP)+,R3 ; R3 -> QMANGR QHOOK MOV #,R1 ; R1 = UB OFFSET TO Q2UBAL ADD R0,R1 ; R1 -> Q2UBAL MOV R1,QH.UNX(R3) ; INIT DESTINATION OF QHOOK MOV #CALOPC,QH.UBR(R3) ; INSERT CALL OPCODE RETURN .DSABL LSB ;+ ; INITBL: ; ; PERFORM UMR GROUPING AND INITIALIZE THE UBDATA TABLE. ; THIS ROUTINE IS CALLED FOR BOTH LOAD 1 AND LOAD 2. ; ; ENTRY: R0 -> UB ENTRY POINT ; R1 = **TOTAL** NUMBER OF PERMANENT UMRS REQUESTED ; R4 -> RMON ; ; EXIT: R0 -> UB ENTRY ; ;- .ENABL LSB INITBL: CMP #MAXPRM,R1 ; DON'T TRY FOR MORE THAN MAX BCC 10$ ; BRANCH IF REQUEST O.K. MOV #MAXPRM,R1 ; ELSE ADJUST REQUEST 10$: CALL GRPUMR ; INITIALIZE GROUP COUNTS ;+ ; INITIALIZE UBDATA ;- MOV #,R2 ; R2 = OFFSET TO UBDATA ADD R0,R2 ; R2 -> UBDATA MOV #,R5 ; R5 = OFFSET TO NUMGP1 ADD R0,R5 ; R5 -> NUMGP1 MOV R0,-(SP) ; SAVE UB POINTER MOV (R0),-(SP) ; SAVE UB STATUS WORD MOV R0,-(SP) ; SAVE POINTER TO UB ADD #,@SP ; AND MAKE IT A POINTER TO PSTART MOV #GRPONE!GRPFRE,R0 ; FREE GROUP AND SIZE FLAGS CALL INITGP ; INITIALIZE MOV #GRPTWO!GRPFRE,R0 ; FREE GROUP AND SIZE FLAGS CALL INITGP ; INITIALIZE MOV #GRPFOU!GRPFRE,R0 ; FREE GROUP AND SIZE FLAGS CALL INITGP ; INITIALIZE MOV #GRPNIN!GRPFRE,R0 ; FREE GROUP AND SIZE FLAGS CALL INITGP ; INITIALIZE MOV R2,@(SP) ; PSTART->1ST PERM UMR OR END OF TABLE SUB #,@(SP) ; MAKE PSTART AN OFFSET SUB 4(SP),@(SP) ; THANK ME, GEORGE! ASR @(SP)+ ; MANY TIMES CMP #LD2INP,(SP)+ ; LOAD 2 IN PROGRESS? BEQ 20$ ; YES, INIT PERM UMRS FOR ALL HANDLERS INCB R5 ; NO, INIT PERM UMRS FOR SY 20$: MOVB @R5,R0 ; R0 = NUMBER OF PERM UMRS IN GROUP BEQ 30$ ; NO PERM UMRS TO INITIALIZE!!! MOVB R0,-(SP) ; NEED TO SAVE THIS VALUE*&^%$ MOVB #1,@R5 ; INIT ONE GROUP@!$! SWAB R0 ; PUT SIZE IN HIGH BYTE BIS #,R0 ; ADD PERM UMR AND FREE FLAGS, TOO CALL INITGP ; INITIALIZE MOVB (SP)+,-(R5) ; AND RESTORE IT, DORK-HEAD*&^%! 30$: MOV (SP)+,R0 ; POP UB POINTER RETURN ;+ ; GRPUMR: ; ; o GROUP THE NON-RESERVED (TEMPORARY) UMRS INTO GROUPS OF ; NINE, FOUR, TWO AND ONE BASED ON THE # PERMANENT UMRS. ; o ADJUST GRPMAP. ; ; AT ENTRY: R0 = POINTER TO UB ENTRY ; R1 = NUMBER OF PERMANENT UMRS ; R4 = POINTER TO RMON ; ; EXIT: REGISTERS PRESERVED ; NUMGP1,NUMGP2,NUMGP4,NUMGP9, ; NUMPRM, NUMPSY INITIALIZED ; ;- .ENABL LSB GRPUMR: MOV R1,-(SP) ; SAVE NUMBER OF PERMANENT UMRS MOV R4,-(SP) ; SAVE POINTER TO RMON ;+ ; INITIALIZE GROUP COUNTERS. ;- MOVB (R0),R4 ; R4 = # UMRS RESERVED BY SY: MOV R1,-(SP) ; SAVE NUMBER OF NEW PERMANENT UMRS SUB R4,@SP ; SUB # UMRS ALREADY ALLOCATED (0 IF LOAD 1) 10$: MOV #,R5 ; R5 = NUMGP1 OFFSET IN UB ADD R0,R5 ; R5 -> NUMGP1 .ADDR #GROUPS,R3 ; R3 -> GROUP SIZE TABLE MOV R1,-(SP) ; STACK INDEX ASL R1 ; MAKE R1 OFFSET INTO GROUPS TABLE ADD (SP)+,R1 ; EACH ENTRY IS 3 BYTES ADD R1,R3 ; R3 -> ENTRY MOVB (R3)+,(R5)+ ; INITIALIZE NUMGP1 FROM GROUP TABLE MOVB (R3)+,(R5)+ ; INITIALIZE NUMGP2 FROM GROUP TABLE MOVB (R3)+,(R5)+ ; INITIALIZE NUMGP3 FROM GROUP TABLE TSTB (R5)+ ; SKIP NUMGP9 CMP (R0),#LD1INP ;LOAD 1 IN PROGRESS? BNE 30$ ; BRANCH IF NO 20$: TSTB (R5)+ ; SKIP NUMPRM LOCATION 30$: MOVB (SP)+,(R5)+ ; NUMPRM OR NUMPSY = # OF PERMANENT UMRS ;+ ; ADJUST GRPMAP. ;- MOV #,R4 ; R4 -> OFFSET # 5 IN GRPMAP ADD R0,R4 ; MOV #,R1 ; R1 -> NUMGP9 ADD R0,R1 ; MOV #3,R2 ; R2 = GROUP CODE FOR GROUP OF 9 TSTB -(R1) ; ANY GROUPS OF 4? BEQ 40$ ; NO, REQUESTS OF 4 REQUIRE GROUP OF 9 DEC R2 ; YES, R2 = GROUP CODE FOR GROUP OF 4 40$: MOVB R2,-(R4) ; INITIALIZE GRPMAP FOR REQUEST FOR 4 MOVB R2,-(R4) ; INITIALIZE GRPMAP FOR REQUEST FOR 3 TSTB -(R1) ; ANY GROUPS OF 2? BEQ 50$ ; NO, USE PREVIOUS GROUP CODE DEC R2 ; YES, R2 = GROUP CODE FOR GROUP OF 2 50$: MOVB R2,-(R4) ; INITIALIZE GRPMAP FOR REQUEST FOR 2 TSTB -(R1) ; ANY GROUPS OF 1? BEQ 60$ ; NO, USE PREVIOUS GROUP CODE DEC R2 ; YES, REQUESTS FOR 1 GET GROUP OF 1 60$: MOVB R2,-(R4) ; INIT GRPMAP FOR GROUPS OF 1 MOV (SP)+,R4 ; RESTORE POINTER TO RMON MOV (SP)+,R1 ; RESTORE NUMBER OF PERMANENT UMRS RETURN ;+ ; INITGP: ; ; INITIALIZE TOTAL NUMBER OF UMR GROUPS OF A PARTICULAR SIZE ; ; ENTRY: R0 = NUMBER OF ENTRIES IN GROUP AND GROUP FREE INDICATOR ; R1 IS UNDEFINED ; R2 -> 1ST UBDATA TABLE ENTRY IN GROUP ; R5 -> GROUP COUNT (NUMGP1 THROUGH NUMPSY) ; ; EXIT: R0 = UNCHANGED ; R1 IS TRASHED ; R2 -> 1ST UBDATA TABLE ENTRY IN NEXT GROUP OR END OF TABLE ; R5 -> GROUP COUNT OF NEXT GROUP TO INITIALIZE ;- .ENABL LSB INITGP: MOVB (R5)+,R1 ; R1 = GROUP TOTAL BEQ 30$ ; BRANCH IF NO GROUPS OF THIS SIZE 10$: MOV R0,-(SP) ; STACK GROUP SIZE CLRB @SP ; CLEAR GROUP CHARACTERISTICS BYTE SWAB @SP ; PUT SIZE IN LOW BYTE BIS #GRPHEA,@R2 ; 1ST UMR IN GROUP IS GROUP HEAD 20$: BIS R0,(R2)+ ; INITIALIZE GROUP SIZE & GRPFRE DEC @SP BNE 20$ ; BRANCH IF NOT DONE WITH GROUP TST (SP)+ ; RESTORE STACK SOB R1,10$ ; GO DO NEXT GROUP IF NOT DONE 30$: RETURN .DSABL LSB ;+ ; THIS TABLE HAS 22 3-BYTE ENTRIES THAT INDICATE UMR GROUPING ; FOR FROM 0 - 22 PERMANENT UMRS. (GROUP OF 9 NOT INCLUDED IN ; TABLE SINCE THERE IS ALWAYS ONE GROUP OF 9.) ; ; GROUP SIZE: 1 2 4 PERMANENT UMRS ; ---------- ------ ------ ------ -------------- ;- GROUPS: .BYTE 6, 4, 2 ; 0 .BYTE 7, 3, 2 ; 1 .BYTE 6, 3, 2 ; 2 .BYTE 7, 4, 1 ; 3 .BYTE 6, 4, 1 ; 4 .BYTE 7, 3, 1 ; 5 .BYTE 6, 3, 1 ; 6 .BYTE 5, 3, 1 ; 7 .BYTE 6, 2, 1 ; 8 .BYTE 5, 2, 1 ; 9 .BYTE 4, 2, 1 ; 10 .BYTE 5, 1, 1 ; 11 .BYTE 4, 1, 1 ; 12 .BYTE 3, 1, 1 ; 13 .BYTE 6, 1, 0 ; 14 .BYTE 5, 1, 0 ; 15 .BYTE 4, 1, 0 ; 16 .BYTE 3, 1, 0 ; 17 .BYTE 4, 0, 0 ; 18 .BYTE 3, 0, 0 ; 19 .BYTE 2, 0, 0 ; 20 .BYTE 1, 0, 0 ; 21 .BYTE 0, 0, 0 ; 22 .EVEN ; *** End of LOAD CODE block 2 *** ; *** Begin extra LOAD CODE overlay *** .ASSUME . LE UBLOAD+<2*BLK>, MESSAGE=<;UBX LOAD CODE overflow in 2nd block> . = UBLOAD+<2*BLK> ; LOAD code overlay LBLK2:: .SBTTL MAKREG - Create UBX Region ;+ ; Make a global region in high memory and call it "UB $ ". ; ; On entry: ; R0 = base load address of UB ;- .Enabl LSB MAKREG::Mov R0,R3 ; let R3 hold base address of UB Mov @#$SYPTR,R1 ; point to RMON Mov $MEMPT(R1),R0 ; get offset to memory tables **GVAL** Add R1,R0 ; get real address Mov CorPtX(R0),R5 ; get offset to extended ALLOC**PEEK** Add R1,R5 ; and real address MOV P1$Ext(R1),R0 ; save P1EXT address for later 20$: Cmp #-1,(R5)+ ; look for end of free list **PEEK** Bne 20$ ; loop until found ; R5 now points to handler RCBs ; Search RCB table for an empty entry, and attach to it. 30$: ; look for an empty one Cmp #-1,@R5 ; end of list? **PEEK** Beq Rtn1 ; yes, failure Tst @R5 ; empty? **PEEK** Beq 40$ ; yes, got one to use Add #GR.Esz,R5 ; point to next ;GLA001 Br 30$ ; keep trying .......... 40$: Mov #UBXSiz,R2 ; area needed Mov R3,-(SP) ; save handler base Call $XALPT(R0) ; call routine to allocate it Mov (SP)+,R3 ;*C* Bcs Rtn1 ; failed .Assume GR.Siz EQ 0 Mov R2,(R5)+ ;*C* build RCB **POKE** .Assume GR.Adr EQ GR.Siz+2 Mov R1,(R5)+ ;*C* **POKE** Mov R1,(R3) ;*C* Save the PAR1 address .Assume GR.Sta EQ GR.Adr+2 Mov #GR.PRV,(R5)+ ;*C* set status to PRIVATE **POKE** .Assume GR.Nam EQ GR.Sta+2 Mov (PC)+,(R5)+ ;*C* put name in RCB **POKE .RModule ; our Rad50 name Mov #<^r$ >,@R5 ;*C* second part of name is $ **POKE Mov R3,R0 ;*C* Restore handler base to R0 Tst (PC)+ Rtn1: Sec Return ...... .Dsabl LSB .SBTTL $REL Processing ;+ ; UBX is in our region. Relocate memory references marked with $REL ; ; On entry, ; R3 -> HANDLER + 6 ... ;- .ENABL LSB RELOCT:: Mov @#KISAR1,-(SP) ;Save mapping Mov (R3),@#KISAR1 ; Map to high region Jsr R0,40$ ; point to LD relocation list **PIC** .............. ; never returns, R0 pointed to table ; *** The UB relocation list *** UB.Did = 1 UB.Lst: .Rept UB.Cnt .Irp x <\UB.Did> ;;;.IIf EQ UB.'x-UBBase .Error ; UB.'x was zero ; .Word UB.'x-UBBase .EndR UB.Did = UB.Did+1 .EndR .Word 000000 ; end of list ; *** The UBR relocation list *** UBR.Did = 1 UBR.Lst: .Rept UBR.Cnt .Irp x <\UBR.Did> .Word UR.'x $Rel .-2 UR.'x UBX .EndR UBR.Did = UBR.Did+1 .EndR .Word 000000 ; end of list ; *** The UB relocation code *** 40$: 50$: Mov (R0)+,R1 ; get next reloc list entry Beq 60$ ; done this list Add R3,R1 ; real address to locate Add R3,@R1 ; relocate value in address Br 50$ ; and do next .......... 60$: ; *** The UBR relocation code *** 70$: Mov (R0)+,R1 ; get next reloc list entry Beq 80$ ; done this list Add R3,@R1 ; relocate value in address Br 70$ ; and do next .......... 80$: Tst (SP)+ ; restore SP from JSR R0, ... Mov (SP)+,@#KISAR1 ;*C* restore mapping Return ; from READUP .DSABL LSB .ASSUME . LE UBLOAD+<3*BLK>, MESSAGE=<;UBX LOAD CODE overflow in MAKREG ovly> . = UBLOAD+<3*BLK> ; LOAD code overlay .SbTtl Align PSects on block boundaries ;***************************************************************************** .Psect UBDvr ; pad UBDvr up to block bound UBDvr ==: . ; display actual size .PSect SetOvr SetOvr ==: . ; display actual size .PSect UBX ; pad UBX up to block boundary UBXEnd =: . ; display actual size UBXByt =: ; size of region in bytes UBXSiz =: /KTGran ; amount to allocate ;***************************************************************************** .IIf NE UB.Cnt-UB.Did+1 .Error UB.Cnt-UB.Did+1; auto relocation error; .IIf NE UBR.Cnt-UBR.Did+1 .Error UBR.Cnt-UBR.Did+1; auto relocation error; ;.IIf NE RM.Cnt-RM.Did+1 .Error RM.Cnt-RM.Did+1; auto relocation error; ;.IIf NE RMX.Cnt-RMX.Did+1 .Error RMX.Cnt-RMX.Did+1; auto relocation error; .End