SUBTTL ULKBUF - Unlock buffers
; Unlock the buffers pointed at by the BR block in P3. May be called at
; interrupt level.
XRESCD ; [7173] This must be resident
ULKBUF: OPSTR <SKIPN T1,>,BRCP1,(P3) ; Get the first core page number
IFSKP.
XCALL (MSEC1,MULKCR) ; [7173] Unlock the page
ENDIF.
OPSTR <SKIPN T1,>,BRCP2,(P3) ; Get the second core page number
IFSKP.
XCALL (MSEC1,MULKCR) ; [7173] Unlock the second core page
ENDIF.
RET ; If zero, we are done
XSWAPCD ; [7173] Go swappable again

SUBTTL DOINT - Process pending PSI's
; This routine will unlock the currently open portal, and enable PSI's so that
; the NI% JSYS can be interrupted. Immediately after enabling interrupts, this
; routine will disable them and (almost) restart the JSYS.
DOINT: OKINT ; Take the interrupt
ULOAD P2,BXNXT,(P2) ; Get pointer to next BXB
USTOR P2,EIBCP,(P1) ; Update the BXB pointer
JRST NI0 ; Restart the JSYS

SUBTTL QUEBRB - Queue up BRB's
; This routine will queue a buffer request block onto a queue pointed at by
; T1. This routine should be called with interrupts off.
;
; Call: MOVX P3,BR block
; MOVX T1,pointer to queue header
; CALL QUEBRB
; <+1 Queue was empty. Ie: It went from empty to non-empty.>
; <+2 Queue was not empty.>
XRESCD ; [7173]
QUEBRB: SETZRO BRNXT,(P3) ; Zero pointer to next BR block
LOAD T2,XRQUE,(T1) ; Get pointer to last item of queue
STOR P3,BRNXT,(T2) ; Make last block on q point to this block
STOR P3,XRQUE,(T1) ; Make q end point to our block
CAME T1,T2 ; Was the queue empty?
AOS (P) ; Nope, give skip return
RET ; Yes, non-skip return
XRESCD ; [7434]
; Get the first BRB on the queue
DQBRB: PIOFF ; Keep interrupt level away
LOAD P3,XRQUH,(T1) ; Get address of first BRB
JUMPE P3,DQBRB1 ; Jump if q is empty
LOAD T2,BRNXT,(P3) ; Get address of next BR block
STOR T2,XRQUH,(T1) ; Make it be the new first
OPSTR <XMOVEI T3,>,XRQUH,(T1) ; Get address of queue header
SKIPN T2 ; Is the queue now empty?
STOR T3,XRQUE,(T1) ; Yes, fix the end pointer
PION ; Turn interrupts back on
RETSKP ; Give successful return
DQBRB1: PION ; Turn interrupts back on
RET ; Give q empty return
; Requeue a BRB by putting it on the head of the queue
RQBRB: PIOFF ; No interrupts
LOAD T2,XRQUH,(T1) ; Get first item on queue
STOR T2,BRNXT,(P3) ; Make our BR block point to the next item
SKIPN T2 ; Was the queue empty?
STOR P3,XRQUE,(T1) ; Yes, make this item be the last
STOR P3,XRQUH,(T1) ; Make our block be the first
PION
RET

SUBTTL ***** Hacks *****
; Hacks of the century go here!
; This is a cover routine for the stupid ASGJFR routine. This routine
; allocates one more word and increments the address before returning it
; to the caller. Arguments identical to ASGJFR.
GETJSF: ADDI T2,1 ; Get one more word
XCALL (MSEC1,ASGJFR) ; [7173] Get the memory
RET ; Sigh, can't get it
AOJA T1,RSKP ; Point to next word and return success
GIVJSF: SUBI T2,1 ; Point to header word
XCALLRET (MSEC1,RELJFR) ; [7173] All done