Trailing-Edge
-
PDP-10 Archives
-
SRI_NIC_PERM_SRC_1_19910112
-
7/galaxy-sources/glxint.mac
There are 37 other files named glxint.mac in the archive. Click here to see a list.
TITLE GLXINT - Operating system interface for GALAXY
SUBTTL Preliminaries
; COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1975, 1988.
; ALL RIGHTS RESERVED.
;
; THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED
; ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE AND 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. NO TITLE TO AND OWNERSHIP OF THE SOFTWARE IS HEREBY
; TRANSFERRED.
;
; THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE
; AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT
; CORPORATION.
;
; DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ITS
; SOFTWARE ON EQUIPMENT THAT IS NOT SUPPLIED BY DIGITAL.
;This module provides commonly used routines that are dependent
; upon the operating system.
SEARCH GLXMAC ;GET NECESSARY SYMBOLS
PROLOG(GLXINT,INT) ;GENERATE PROLOG CODE
SEARCH ORNMAC ;GET WTO SYMBOLS
EXTERNAL GLXVRS
INTMAN==:0 ;Maintenance edit number
INTDEV==:133 ;Development edit number
VERSIN (INT) ;Generate edit number
Subttl Table of Contents
; Table of Contents for GLXINT
;
; Section Page
;
;
; 1. Revision History . . . . . . . . . . . . . . . . . . . 3
; 2. Entry Points Found in GLXINT . . . . . . . . . . . . . 4
; 3. Local Definitions . . . . . . . . . . . . . . . . . . 5
; 4. Module Storage . . . . . . . . . . . . . . . . . . . . 6
; 5. I%INIT - Continue Library Initialization . . . . . . . 7
; 6. Detach from FRCLIN . . . . . . . . . . . . . . . . . . 9
; 7. SETTRP - Setup for APR Trapping . . . . . . . . . . . 10
; 8. IINIT - Initialize the interrupt system data base . . 12
; 9. I%IOFF-I%ION - Turn interrupt system off and on . . . 13
; 10. Processor for each interrupt level . . . . . . . . . . 14
; 11. I%EXIT - Exit from the program . . . . . . . . . . . . 15
; 12. I%NOW - Get time of day . . . . . . . . . . . . . . . 16
; 13. I%SLP - Dismiss the program for a while . . . . . . . 17
; 14. I%TIMR Timer queue manipulation routines . . . . . . . 18
; 15. I%HOST - Get Host Name/Number of Central Site . . . . 22
; 16. I%JINF - Canonical Job Information . . . . . . . . . . 23
; 17. I%JINF ROUTINES FOR THE -10 . . . . . . . . . . . . . 24
; 18. I%JINF SPECIAL ROUTINES FOR THE -20 . . . . . . . . . 25
; 19. WTPACD, WTOOCD ACTION ROUTINES . . . . . . . . . . . . 28
SUBTTL Revision History
COMMENT \
105 Remove I%RLIM as it won't be needed with the new PFH.
***** Release 4.2 -- begin maintenance edits *****
***** Release 5.0 -- begin development edits *****
110 5.1002 28-Dec-82
Move to new development area. Clean up edit organization.
111 5.1063 30-Nov-83
Rearrange default table for the IB. Add default for new bit IB.SYS.
Based on IB.SYS and DB.SYS in debug word, set/don't set process as
system process in the initialization code.
112 5.1074 31-Jan-84
Return with S1 containing the version of the library.
113 5.1094 13-Feb-84
Correct edit 112 so that S1 contains the version of the library and not
the contents of the memory location whose value equals that of the
version number.
114 5.1133 9-APR-84
Define GLXVRS as external.
115 5.1148 21-Jun-84
Fix bug in testing code which accidently causes private world processes
to hog too much of the system.
116 5.1200 6-Feb-85
Set bit IB.NAC to zero which causes GTJFNs to be called without setting
bit GJ%ACC.
***** Release 5.0 -- begin maintenance edits *****
120 Increment maintenance edit level for version 5 of GALAXY.
***** Release 6.0 -- begin development edits *****
130 6.1021 19-Oct-87
Change routine WTPOBJ to process remote LPT name blocks as part of
its processing of object blocks.
131 6.1096 21-Nov-87
Add routine WTPNHD which processes the remote node name block for
the $QACK and $QWTO macros.
132 6.1108 1-Dec-87
Change WTPNHD to correctly store the message length.
133 6.1225 8-Mar-88
Update copyright notice.
\ ;End of revision history
SUBTTL Entry Points Found in GLXINT
ENTRY I%INIT ;INITIALIZE THE MODULE
ENTRY I%NOW ;GET TIME OF DAY
ENTRY I%EXIT ;EXIT FROM PROGRAM
ENTRY I%ION ;INTERRUPTS ON
ENTRY I%IOFF ;INTERRUPTS OFF
ENTRY I%SLP ;SLEEP FOR A WHILE
ENTRY I%TIMR ;CREATE OR CHECK FOR TIMER ENTRY
ENTRY I%INT1 ;CREATE ALL ENTRIES
ENTRY I%INT2 ;FOR INTERRUPT LEVELS
ENTRY I%INT3 ;
ENTRY I%SOPR ;SEND TO OPR ROUTINE.
ENTRY I%WTO ;ACK, WTO, WTOR MSG PROCESSOR
ENTRY I%HOST ;GET HOST NAME/NUMBER
ENTRY I%JINF ;CANONICAL JOB INFO BLOCK
SUBTTL Local Definitions
;Since the number of levels of interrupt differs from system to system,
; all code that deals with interrupt levels is under the DOLEV macro.
; To use this macro, define X(LVL) to generate the proper code for one
; level, using LVL as the suffix. Then the invokation of DOLEV will
; create redundant code for each level wanted (INT.LV defined in GLXMAC).
; (INT.LV and INT.MX defined in GLXMAC)
DEFINE DOLEV (LVLS<INT.LV>)<
LSTOF.
ZZ==1 ;;START AT LEVEL 1
REPEAT LVLS,<
X(\ZZ) ;;EXPAND DEFINED CODE FOR EACH LEVEL
ZZ==ZZ+1 ;;STEP TO NEXT LEVEL
>
LSTON.
> ;END OF DOLEV DEFINITION
SUBTTL Module Storage
EXT RSEFLG ;RETURN SEND ERROR FLAG
$DATA INTBEG,0 ;START OF ZEROABLE $DATA SPACE
DEFINE X(LVL)<
$DATA LEVPL'LVL,IPL.SZ ;;PUSHDOWN LIST FOR EACH LEVEL
$DATA SAVAC'LVL,20 ;;AC SAVE AREA FOR EACH LEVEL
$DATA INTPC'LVL,1 ;;INTERRUPT PROCESSOR PC
> ;END OF PER LEVEL DEFINITIONS
DOLEV ;;EXPAND FOR EACH VALID LEVEL
$GDATA TRPPDP,3 ;SAVED PUSH DOWN POINTER AND PDL
$GDATA MYJOB ;MY JOB NUMBER
$GDATA LOGTIM ;Jobs logged in time
$DATA TIMLST ;TIMER LIST
$DATA TIMWAK ;NEXT WAKEUP TIME
$DATA TIMPC ;TIME DISPATCH PC
$DATA AWOKEN ;USED FOR SLEEP/WAKE CODE
$GDATA BASINT ;BASE OF INTERRUPT SYSTEM
$GDATA INTRPC ;INTERRUPT PC ADDRESS
$DATA PRMADR ;WTO PARM ADDRESS
$DATA RETADR ;Holds return PC
$DATA THSPRM ;Address of current WTO parameter
$DATA S1%S2,2 ;WTO SAVE AREA FOR S1, S2.
$DATA WTOBLT ;OBJECT BLK END ADDRESS FOR WTO BLT
$DATA STF ;Save for TF during WTO
$DATA MSGADR ;WTO MESSAGE ADDRESS.
$DATA BYTPTR ;WTO MSG BYTE PTR.
$DATA BYTCNT ;WTO MSG BYTE COUNT.
$DATA WTOSAB,SAB.SZ ;WTO SAB BLOCK.
$DATA INTEND,0 ;END OF ZEROABLE $DATA SPACE
$GDATA IIB,IB.SZ ;FULL SIZED IB
$GDATA D%END,0 ;Last location in the data pages
SUBTTL I%INIT - Continue Library Initialization
;CALL IS: S1/ LENGTH OF THE USER SUPPLIED IB
; S2/ USER SUPPLIED IB ADDRESS
;
;TRUE RETURN: ALWAYS
; S1/ VERSION OF THE LIBRARY
I%INIT: PUSHJ P,.SAVE2## ;SAVE TWO REGISTERS
DMOVE P1,S1 ;SAVE IB LENGTH AND LOCATION
MOVE S1,[INTBEG,,INTBEG+1] ;BLT PTR TO ZEROABLE $DATA SPACE
SETZM S1,INTBEG ;FIRST LOCATION
BLT S1,INTEND-1 ;BLT THE REST
DEFINE DEFAULTS <
LSTOF.
XX IB.OUT,FWMASK,T%TTY ;;$TEXT OUTPUT ROUTINE
XX IB.FLG,IT.OCT,0 ;;OPEN TERMINAL FOR S%CMND
XX IB.FLG,IP.STP,0 ;;ORION GETS STOP CODES FLAG
XX IB.FLG,IB.DPM,0 ;;USE JOB NUMBER AS PID
XX IB.FLG,IB.NPF,0 ;;DON'T SET UP GLXPFH
XX IB.FLG,IB.SYS,0 ;;Don't set up as a system process
XX IB.FLG,IB.NAC,0 ;;Don't normally restrict access to JFNs
XX IB.INT,FWMASK,0 ;;INTERRUPT VECTORS
XX IB.PIB,FWMASK,0 ;;PID block address
XX IB.ERR,FWMASK,0 ;;USER $TEXT ERROR EXIT ROUTINE
XX IB.PRG,FWMASK,'NONAME' ;;PROGRAM NAME
LSTON.
>
DEFINE XX (LOC,MSK,DEF,%L1) <
CAIG P1,LOC ;;SUPPLIED BY USER?
JRST %L1 ;;NO -- SUPPLY OUR DEFAULT
LOAD S1,LOC'(P2),MSK ;;YES -- GET WHAT THE SUPPLIED
SKIPN S1 ;;NULL FIELD?
%L1: MOVX S1,DEF ;;YES -- SUPPLY OUR DEFAULT
STORE S1,IIB+LOC,MSK ;;STORE IN PERSONAL IB
SUPPRESS %L1
> ;END SETDEF
DEFAULTS ;SET INTERNAL DEFAULTS
SETOM S1 ;SET FOR MY JOB
MOVX S2,JI.JNO ;GET THE JOB NUMBER
PUSHJ P,I%JINF ;GET THE DATA IN S2
MOVEM S2,MYJOB ;SAVE MY JOB NUMBER
TOPS10<
MOVX S2,JI.JLT ;GET LOGGED IN TIME
$CALL I%JINF
SKIPF
MOVEM S2,LOGTIM
DMOVE S1,INT.D ;Point to full IB
PUSHJ P,DETACH ;Try to detach from FRCLIN
> ;END TOPS10
; Here to decide if to set system process
LOAD S1,IIB+IB.FLG,IB.SYS ;Get the bit to indicate system process
JUMPE S1,INIT.2 ;If not set, nothing else to do
SKIPN DEBUGW ;Are we debugging?
JRST INIT.1 ;No, go set system process
LOAD S1,DEBUGW,DB.SYS ;Get the system process override bit
JUMPE S1,INIT.2 ;If not set, do not set sys. proc.
; Here to set system process
INIT.1: SETZ S2, ;Clear "priority word"
TXO S2,JP%SYS ;Set system process bit
MOVEI S1,.FHSLF ;For ourselves
SPRIW ;And do it
ERCAL [$WARN (<Failed to set as a system process>)
$RET]
INIT.2: DMOVE S1,INT.D ;POINT TO FULL IB
PUSHJ P,.INIT## ;INITIALIZE THE COMMON MODULE
DMOVE S1,INT.D ;POINT TO FULL IB
PUSHJ P,M%INIT## ;INITIALIZE THE MEMORY SYSTEM
DMOVE S1,INT.D ;POINT TO FULL IB
PUSHJ P,T%INIT## ;INITIALIZE THE TEXT MODULE
DMOVE S1,INT.D ;POINT TO FULL IB
PUSHJ P,IINIT ;INITIALIZE THE INTERRUPT SYSTEM
DMOVE S1,INT.D ;POINT TO FULL IB
PUSHJ P,L%INIT## ;INITIALIZE THE LINKED LIST MODULE
DMOVE S1,INT.D ;POINT TO FULL IB
PUSHJ P,C%INIT## ;INITIALIZE THE COMMUNICATIONS MODULE
DMOVE S1,INT.D ;POINT TO FULL IB
PUSHJ P,F%INIT## ;INITIALIZE THE FILE MODULE
DMOVE S1,INT.D ;POINT TO FULL IB
PUSHJ P,K%INIT## ;INITIALIZE THE TERMINAL KEYBOARD MODULE
DMOVE S1,INT.D ;POINT TO FULL IB
PUSHJ P,S%INIT## ;INIT THE COMMAND SCANNER
MOVX S1,<SI.FLG+SP.OPR> ;SEND TO SPECIAL PID ...OPR
MOVEM S1,WTOSAB+SAB.SI ;SAVE IN WTOSAB
SETZM WTOSAB+SAB.PD ;CLEAR PID WORD
MOVE S1,[GLXVRS] ;RETURN WITH LIBRARY VERSION
$RETT ;RETURN TO CALLER
INT.D: EXP IB.SZ,IIB ;Common args for the initializers
SUBTTL Detach from FRCLIN
; Detach the program if we're running on FRCLIN (no-op for TOPS-20).
; Call: PUSHJ P,DETACH
;
DETACH:
TOPS10< MOVNI S1,1 ;-1 means us
GETLCH S1 ;Get our line characteristics
ANDX S1,UX.UNT ;Keep just the unit number
MOVX S2,%CNFLN ;GETTAB to return FRCLIN TTY number
GETTAB S2, ;Get it
$RETF ;Can't - just return
CAME S1,S2 ;Are we running on FRCLIN ?
$RETT ;No - return
HRLZS S1 ;Setup line#,,0 for detach
ATTACH S1, ;Detach from FRCLIN
$RETF ;Oh well...
MOVSI S1,.STWTC ;GET FUNCTION CODE TO SET WATCH
SETUUO S1, ;SET WATCH NONE
JFCL ;HOPE NOTHING TYPES OUT
> ;End of TOPS-10 conditional
$RETT ;Return
SUBTTL SETTRP - Setup for APR Trapping
SETTRP:
TOPS10 <
MOVEI S1,TRPADR ;GET APR TRAP ADDRESS
MOVEM S1,.JBAPR## ;STORE IT
MOVX S1,AP.POV+AP.ILM+AP.NXM ;GET TRAP TYPES
APRENB S1, ;ENABLE THEM
$RETT ;RETURN
> ;END TOPS10 CONDITIONAL
TOPS20 <
SKIPN S1,BASINT ;INTERRUPT SYSTEM PRESENT
$RETT ;NO..IGNORE SETUP
HRRZ S1,S1 ;GET CHANNEL TABLE ADDRESS
MOVE S2,[1,,TRPPDL] ;TRAP ADDRESS FOR INTERRUPTS
SKIPN .ICPOV(S1) ;PDL OVERFLOW SETUP?
MOVEM S2,.ICPOV(S1) ;SAVE TRAP ADDRESS
MOVE S2,[1,,TRPIIT] ;TRAP ADDRESS FOR INTERRUPTS
SKIPN .ICILI(S1) ;ILLEGAL INSTRUCTION?
MOVEM S2,.ICILI(S1) ;SAVE TRAP ADDRESS
MOVE S2,[1,,TRPIMR] ;TRAP ADDRESS FOR INTERRUPTS
SKIPN .ICIRD(S1) ;ILLEGAL MEMORY READ?
MOVEM S2,.ICIRD(S1) ;SAVE TRAP ADDRESS
MOVE S2,[1,,TRPIMW] ;TRAP ADDRESS FOR INTERRUPTS
SKIPN .ICIWR(S1) ;ILLEGAL MEMORY WRITE?
MOVEM S2,.ICIWR(S1) ;SAVE TRAP ADDRESS
MOVEI S1,.FHSLF ;GET MY PROCESS HANDLE
MOVX S2,<1B<.ICPOV>!1B<.ICILI>!1B<.ICIRD>!1B<.ICIWR>>
AIC ;ACTIVATE THE CHANNELS
ERJMP SETT.E ;ERROR
HLRZ S1,BASINT ;GET LEVEL TABLE
MOVE S1,(S1) ;GET ADDRESS OF LEVEL PC SAVE
MOVEM S1,INTRPC ;SAVE INTRPC
$RETT ;RETURN
SETT.E: $STOP(CSP,Cannot Activate Panic Channels)
>;END TOPS20
; Here on TOPS-10 APR traps
;
TOPS10 <
TRPADR: PORTAL .+1 ;Allow execute-only operation
EXCH TF,.JBCNI ;Get APR CONI at trap, save TF
TXNE TF,AP.POV ;PDL overflow ?
JRST TRPPDL ;Yes
TXNE TF,AP.ILM ;Ill mem ref ?
JRST TRPILM ;Yes
TXNE TF,AP.NXM ;Non-existant memory ?
JRST TRPNXM ;Yes
EXCH TF,.JBCNI ;Restore JOBDAT location and TF
$STOP (APT,<Unknown APR trap^I/TRPPC/ APR CONI = ^O12R0/.JBCNI/>)
TRPPDL: EXCH TF,.JBCNI ;Restore JOBDAT location and TF
MOVEM P,TRPPDP ;STORE PUSH DOWN POINTER
MOVE P,[IOWD 2,TRPPDP+1] ;SET UP TEMPORARY PDL
$STOP (PDL,<Pushdown list overflow^I/TRPPC/>)
MOVE P,TRPPDP ;RELOAD USER'S PDL POINTER
POPJ P, ;THE FOOL IS TRYING TO CONTINUE
TRPILM: EXCH TF,.JBCNI ;Restore JOBDAT location and TF
$STOP (ILM,<Illegal memory reference^I/TRPPC/>)
TRPNXM: EXCH TF,.JBCNI ;Restore JOBDAT location and TF
$STOP (NXM,<Non-existant memory^I/TRPPC/>)
TRPPC: ITEXT (< at PC ^O/.JBTPC,RHMASK/>)
>;END TOPS10 CONDITIONAL
TOPS20 <
TRPPDL: MOVEM P,TRPPDP ;STORE PUSH DOWN POINTER
MOVE P,[IOWD 2,TRPPDP+1] ;SET UP TEMPORARY PDL
$STOP (PDL,<Pushdown list overflow>)
MOVE P,TRPPDP ;RELOAD USER'S PDL POINTER
POPJ P, ;RETURN?
TRPIIT: $BGINT 1 ;SETUP ILLEGAL INSTRUCTION
PUSHJ P,TRPSET ;SETUP TRAP
MOVE P,SAVAC1+17 ;GET ORIGINAL STACK BACK
$STOP(IST,Illegal Instruction Trap^I/TRPPC/)
TRPIMR: $BGINT 1 ;SETUP ILLEGAL MEMORY READ
PUSHJ P,TRPSET ;SETUP TRAP
MOVE P,SAVAC1+17 ;GET ORIGINAL STACK BACK
$STOP(IMR,Illegal Memory Read^I/TRPPC/)
TRPIMW: $BGINT 1 ;SETUP ILLEGAL MEMORY WRITE
PUSHJ P,TRPSET ;SETUP TRAP
MOVE P,SAVAC1+17 ;GET ORIGINAL STACK BACK
$STOP(IMW,Illegal Memory Write^I/TRPPC/)
TRPPC: ITEXT (< at PC ^O/INTRPC,RHMASK/ Stack ^O/SAVAC1+17/>)
TRPSET: PUSH P,S1 ;SAVE S1
MOVE S1,@INTRPC ;GET THE PC
MOVEM S1,INTRPC ;SAVE THE PC
POP P,S1 ;RESTORE S1
POPJ P, ;RETURN
>;END TOPS20
SUBTTL IINIT - Initialize the interrupt system data base
;Information in the IB must be remembered for operation of the interrupt
; system. Also, since the entries to the interrupt level setup routines
; are in impure storage, they must be set up.
; CALL IS: S1/ Size of the IB
; S2/ Address of the IB
;
; TRUE RETURN: Always
IINIT: SETOM AWOKEN ;ALWAYS PRETEND SOMETHING HAPPENED
MOVE S1,IB.INT(S2) ;GET THE BASE OF THE INTERRUPT SYSTEM
MOVEM S1,BASINT ;STORE FOR LATER
JUMPE S1,SETTRP ;IF NO INTERRUPT SYSTEM,FINISH UP
PUSHJ P,SETINT ;SET IT UP FOR USER
JUMPT SETTRP ;SET APR TRAPS AND RETURN IF OK
$STOP(CSI,Cannot set up interrupt system)
SUBTTL I%IOFF-I%ION - Turn interrupt system off and on
;When interrupts can not be accepted, they can be switched on
; and off via these routines.
;CALL IS: NO ARGUMENTS
;TRUE RETURN: ALWAYS
TOPS10 <
I%ION: SKIPA S1,[PS.FON] ;FLAG TO TURN ON SYSTEM
I%IOFF: MOVX S1,PS.FOF ;FLAG TO TURN OFF SYSTEM
SKIPN BASINT ;DID USER ENABLE INTERRUPTS?
$RETT ;NO, JUST RETURN
PISYS. S1, ;ALTER THE STATE
$RETE(CEI) ;Failed,,return
$RETT ;AND RETURN
SETINT: PIINI. S1, ;HERE TO SET UP VECTOR
$RETF ;FALSE IF CANNOT SET IT UP
$RETT ;OTHERWISE, ALL IS OK
> ;END TOPS10 CONDITIONAL
TOPS20 <
I%ION: SKIPN BASINT ;SKIP IF USER ENABLED INTERRUPTS
$RETT ;AND RETURN
MOVX S1,.FHSLF ;FOR MYSELF
EIR ;TURN ON INTERRUPTS
ERJMP [$RETE(CEI)] ;Failed,,return
$RETT
I%IOFF: SKIPN BASINT ;SKIP IF WE ARE DOING INTERRUPTS
$RETT ;AND RETURN
MOVX S1,.FHSLF ;FOR MYSELF
DIR ;DISABLE INTERRUPTS
ERJMP [$RETE(CEI)] ;Failed,,return
$RETT ;RETURN AFTER CHANGE
SETINT: MOVE S2,S1 ;GET LEVTAB,,CHNTAB OF CALLER
MOVX S1,.FHSLF ;AND FOR MYSELF,
SIR ;ESTABLISH THE INTERRUPT SYSTEM
ERJMP .RETF ;IF IT FAILS, SAY SO
$RETT ;OTHERWISE, TAKE GOOD RETURN
> ;END TOPS20 CONDITIONAL
SUBTTL Processor for each interrupt level
;Each level of interrupt starts off with a $BGINT instruction
;which does a JSR to the appropriate I%INTx routine. These in turn
;call the continuation routines which set the DEBRK code as a co-routine.
;When interrupt processing is done for this level, a $DEBRK is done
;which does the proper post interrupt processing.
DEFINE X(LVL)<
I%INT'LVL:
IFGE INT.LV-LVL,<
POP P,INTPC'LVL ;;SAVE INTERRUPT PROCESSOR PC
MOVEM 0,SAVAC'LVL ;;SAVE AC 0 AWAY
MOVE 0,[XWD 1,1+SAVAC'LVL] ;;BLT POINTER TO SAVE THE ACS
BLT 0,17+SAVAC'LVL ;;SAVE ALL ACS
MOVE 17,[IOWD IPL.SZ,LEVPL'LVL] ;;SET UP INTERRUPT LEVEL PDL
PUSH P,[Z DBRK'LVL] ;;SET UP CO-ROUTINE RETURN
JRST @INTPC'LVL ;;AND CONTINUE
DBRK'LVL: ;;HERE WHEN INTERRUPT IS OVER
PORTAL .+1 ;;CLEAR PUBLIC
TOPS20 < ;;WAKE UP CODE FOR TOPS-20
SETOM AWOKEN ;;WE HAVE A WAKE UP COMING
MOVEI T1,SLP1 ;;LABEL FOR FORCED WAKE UP
HLRZ S2,BASINT ;;GET LEVTAB'S ADDRESS
ADDI S2,LVL-1 ;;GET OFFSET TO THIS LEVEL'S POINTER
HRRZ S2,0(S2) ;;GET WHERE PC IS STORED
HRRZ S1,0(S2) ;;GET PC INTERRUPTED FROM
CAIL S1,SLP0 ;;INSIDE SLEEP CODE BLOCK?
CAILE S1,SLP1 ;;
SKIPA ;;NO, NO NEED TO ALTER PC
HRRM T1,0(S2) ;;ELSE STORE NEW PC TO FORCE WAKE-UP
> ;END TOPS20 CONDITIONAL
MOVE 17,[XWD SAVAC'LVL,0] ;;RESTORE THE ACS
BLT 17,17 ;;OF PREVIOUS CONTEXT
TOPS20 <
DEBRK ;;DISMISS THE INTERRUPT
ERCAL S..NIP ;;IF DEBRK FAILS
> ;END TOPS20 CONDITIONAL
TOPS10 <
DEBRK. ;;DISMISS THE INTERRUPT
PUSHJ P,S..DUF ;IF UUO FAILS
PUSHJ P,S..NIP ;IF NONE IN PROGRESS
> ;END TOPS10 CONDITIONAL
> ;END IFGE INT.LV-LVL
IFL INT.LV-LVL,<
$STOP(IN'LVL,Level LVL interrupts not supported)
> ;END IFL INT.LV-LVL
> ;END OF X DEFINITION
DOLEV (INT.MX) ;EXPAND CODE OR STOP CODE FOR ALL LEVELS
$STOP(NIP,No interrupt is in progress) ;COMMON STOP CODES
$STOP(DUF,DEBRK UUO failed)
SUBTTL I%EXIT - Exit from the program
;This routine provides a non-continuable exit from the calling
; program.
;CALL IS: No argument
;
;NO RETURN IS PROVIDED
I%EXIT:
TOPS10 <
PJOB S1, ;Get my job number
MOVN S1,S1
JOBSTS S1,
TDZA S1,S1
TXNE S1,JB.ULI ;Am I logged in?
JRST IEXIT ;Yes..then just exit
MOVEI S1,[ASCIZ/.KJOB
./]
$CALL K%SOUT
LOGOUT
>
IEXIT: RESET
$HALT ;STOP THE PROCESS
MOVEI S1,[ASCIZ/? Can't continue
/]
PUSHJ P,K%SOUT ;DUMP THE MESSAGE
JRST IEXIT ;LOOP BACK
SUBTTL I%NOW - Get time of day
; Return local date/time in Smithsonian Universal date/time format
; CALL IS: No arguments
;
; TRUE RETURN: S1/ Greenwich time and date in UDT format
;
I%NOW:
TOPS10 < ;TOPS-10 ONLY
MOVX S1,%CNDTM ;GET UNIVERSAL DATE/TIME (GMT)
GETTAB S1, ;THE MONITOR
$STOP(DTU,Date/Time unavailable)
> ;END OF TOPS-10 CONDITIONAL
TOPS20 < ;TOPS-20 ONLY
GTAD ;GET DATE AND TIME
> ;END OF TOPS-20 CONDITIONAL
$RETT ;RETURN WITH UDT IN S1
SUBTTL I%SLP - Dismiss the program for a while
;When programs need to suspend operation for a time or want to block
; indefinitely, they should use the I%SLP routine.
; Any interrupts will cause the end of sleeping, as will certain
; spurious conditions. Programs using I%SLP should not depend
; on premature wake-up not happening.
; An additional reason for waking on the 10 may be wakeup codes accepted
; HIBER. Specifically, HIBER will wakeup on terminal character input and
; on PTY input. This is specifically needed on the 10 to permit interrupting
; the user on tty input to allow ipcf messages to be processed.
;CALL IS: S1/ flags ,, Number of seconds to sleep, or 0 for infinite
;
;TRUE RETURN: Always
; S1/ Number of seconds till next timer wakeup time
; All other AC's are preserved
I%SLP: $SAVE S2 ;Save S2
HRRZ S2,S1 ;Get only the time to sleep
TOPS10< ANDX S1,<HB.RPT+HB.RTC> > ;Use only bits allowed
TOPS20< SETZM S1 > ;Currently no flags on TOPS20
IMULI S2,^D1000 ;Set to milliseconds
SKIPN TIMWAK ;Timer event waiting?
JRST SLP0 ;No - go to sleep
$SAVE <T1,T2,T3,T4> ;Save some more AC's
MOVE T1,S1 ;Save the flags
MOVE T2,S2 ;Save the current time to sleep
$CALL I%NOW ;Get the current time
CAML S1,TIMWAK ;Time for a wakeup?
JRST SLPDSP ;Yes .. Go check requests
MOVE T3,TIMWAK ;Get the wakeup time
SUB T3,S1 ;Make it time till wakeup
IMULI T3,^D333 ;Convert to milliseconds
SKIPE S2,T2 ;Fetch old sleep time and skip if 0
CAML S2,T3 ;Sleep wakeup before timer wakeup?
MOVE S2,T3 ;No - get timer wakeup
MOVE S1,T1 ;Restore the flags
SLP0: CAILE S2,^D60*^D1000 ;Don't sleep for more than 60 seconds
MOVEI S2,^D60*^D1000 ;Nice try
HRR S1,S2 ;Set up for monitor call
TOPS10 <
HIBER S1, ;DO HIBERNATE FOR SLEEPING
JFCL
> ;END TOPS10 CONDITIONAL
TOPS20 <
SKIPE AWOKEN ;SEE IF A WAKE UP HAS OCCURRED
JRST SLP1 ;YES, DON'T SLEEP AT ALL
SKIPN S1 ;TIMED SLEEP?
WAIT ;NO, SLEEP INDEFINITELY
DISMS ;ELSE SLEEP FOR SPECIFIED SECONDS
JFCL ;USE A LOCATION
SLP1: SETZM AWOKEN ;CLEAR "NEED WAKE UP" FLAG
> ;END TOPS20 CONDITIONAL
SLPDSP: SKIPG TIMPC ;Want to execute routine?
JRST SLPRET ;No..just return
MOVEI S1,0 ;Yes..get the entry
$CALL I%TIMR ;Is it time?
JUMPF SLPRET ;No..just return
CAILE S1,.TIMPC ;Simple safety check
$CALL @.TIMPC(S2) ;Call the routine
PORTAL SLPDSP ;Ignore skip returns
PORTAL SLPDSP ;Process all expired entries
SLPRET: MOVE S1,TIMWAK ;Return next wakeup time
$RETT
SUBTTL I%TIMR Timer queue manipulation routines
;This routine is called to add an entry to the timer event queue
;and to return expired events from the queue.
;To add an entry to the timer queue:
;ACCEPTS S1/ Length of entry to be added to queue
; S2/ Address of entry to be added to queue
;RETURNS TRUE Entry has been added to the timer queue
; FALSE ERIFN$ Invalid function was requested
; ERARG$ Invalid argument was specified
; ERTME$ Requested time has already expired
;To get and delete an expired entry from the timer queue:
;ACCEPTS S1/ Zero
;RETURNS TRUE S1/ Length of entry which has expired
; S2/ Address of the entry
; FALSE ERTMN$ No timer events have expired
I%TIMR: $SAVE <P1,P2,P3,P4> ;Save some acs
DMOVE P1,S1 ;Save calling arguments
SKIPN S1,TIMLST ;Get the timer list
$CALL L%CLST ;No list..go get one
MOVEM S1,TIMLST ;Remember we have it
MOVE S2,TIMWAK ;Get wakeup time
CAMN P1,[-1] ;Just want the list number?
$RETT ;Yes..return it
$CALL L%FIRST ;Position to first entry
JUMPF TIMR.1 ;No entries..proceed
SKIPGE .TIPSI(S2) ;Marked for deletion?
$CALL L%DENT ;Yes..get rid of it
TIMR.1: JUMPE P1,TIMCHK ;Want to check the queue?
CAIGE P1,1 ;At least one word?
$RETE (ARG) ;No..return the error
LOAD S1,.TIFNC(P2),TI.FNC ;Get the requested function
CAIL S1,.TIMRT ;Within range?
CAILE S1,.TIMAL
$RETE (IFN) ;No..invalid function
PJRST @TIMTBL(S1) ;Yes..do the function
TIMTBL: PJRST TIMRT ;Interrupt after runtime
PJRST TIMEL ;Add entry after n milliseconds
PJRST TIMDT ;Add an entry at specific UDT
PJRST TIMDD ;Delete entries at specific UDT
PJRST TIMBF ;Delete entries before spec UDT
PJRST TIMAL ;Delete all entries
TIMCHK: MOVE S1,TIMLST ;Yes..get the list index
$CALL L%FIRST ;Get the first entry
JUMPF TIMCH3 ;Oops..kill the list and return
MOVE P2,S2 ;Remember the address
SKIPN TIMWAK ;Any wakeup time set?
JRST TIMCH4 ;No..return nothing to do
$CALL I%NOW ;Yes..get the current time
CAMGE S1,TIMWAK ;First entry expired?
JRST TIMCH4 ;Nothing to do..just return
SETOM .TIPSI(P2) ;Mark entry for deletion
MOVE S1,TIMLST ;Get list index
$CALL L%SIZE ;Get the size of this entry
MOVE P1,S2 ;Remember entry size
SETZM TIMWAK ;Clear wakeup time
SETZM TIMPC ;Clear dispatch flag
MOVE S1,TIMLST ;Get the list index
$CALL L%NEXT ;Get the next entry
JUMPF .+5
MOVE S1,.TITIM(S2) ;Set new wake time
MOVEM S1,TIMWAK
SKIPLE S1,.TIMPC(S2) ;Set new PC word
MOVEM S1,TIMPC
MOVE S1,P1 ;Return size of entry
MOVE S2,P2 ; and address of entry
$RETT
TIMCH3: SETZM TIMWAK ;Clear wakeup time
SETZM TIMPC ; and PC word
TIMCH4: $RETE(TMN) ;Nothing to do
;These routines will add an entry to the timer queue
;TIMEL Add an entry to expire after N milliseconds
TIMEL: CAIGE P1,.TITIM+1 ;Argument list large enough?
$RETE(ARG)
MOVE S1,.TITIM(P2) ;Get number of milliseconds
IDIVI S1,^D333 ;Convert to 1/3 seconds
MOVE P3,S1 ;Remember this
$CALL I%NOW ;Get current date and time
ADD P3,S1 ;UDT now in P3
JRST TIMDTE ;Fall into common code
;TIMDT Add an entry to expire at a specific UDT
TIMDT: CAIGE P1,.TITIM+1 ;Argument list large enough?
$RETE(ARG) ;No..return the error
MOVE P3,.TITIM(P2) ;Get requested UDT
TIMDTE: MOVE S1,TIMLST ;Get the list index
$CALL L%FIRST ;Position to first entry
JUMPF TIMD4 ;None there..go create one
TIMD1: CAMLE P3,.TITIM(S2) ;Right position for this entry?
JRST TIMD3 ;No..check the next
CAMN P3,.TITIM(S2) ;Is it identical?
CAIE P1,.TIMPC+1 ;Have a PC word and no data?
JRST TIMD2 ;No..go create entry
MOVE P4,.TIMPC(P2) ;Yes..get PC word
CAME P4,.TIMPC(S2) ;Don't make duplicate entry
JRST TIMD3 ;Put this one at the end
$RETE(TMA) ;Entry already exists
TIMD2: MOVE S2,P1 ;Get size of entry
$CALL L%CBFR ;Create the entry
JRST TIMD5 ;Finish up
TIMD3: $CALL L%NEXT ;No..Get the next entry
JUMPT TIMD1
TIMD4: MOVE S1,TIMLST ;Put entry at end of list
MOVE S2,P1 ;Get required size of entry
$CALL L%CENT ;Create it
TIMD5: ADDI P1,-1(S2) ;Get destination address
HRL P2,S2 ;Make BLT pointer
MOVS P2,P2
BLT P2,0(P1) ;Copy arguments
MOVEM P3,.TITIM(S2) ;Save expiration UDT
TIMD6: $SAVE <S1,S2> ;Save for return
PJRST TIMDTX ;Set wakup time and exit
;TIMRT Request an interrupt after N milliseconds of runtime
TIMRT: $RETE(IFN) ;Runtime is unsupported
;TIMBF Deletes all entries before specific UDT
;TIMDD Deletes all entries for a specific UDT
TIMBF: SKIPA P4,[CAMG P3,.TITIM(S2)] ;Delete before time
TIMDD: MOVE P4,[CAME P3,.TITIM(S2)] ;Delete specific time
CAIGE P1,.TITIM+1 ;Must have time word
$RETE(ARG) ;Return the error
MOVE S1,TIMLST ;Get the list index
MOVE P3,.TITIM(P2) ;Get requested time
$CALL L%FIRST ;Get the first entry
JUMPF TIMALX ;Reset the flags
TIMDD1: XCT P4 ;Want to delete this request?
JRST TIMDD3 ;No..check the next
CAIG P1,.TIMPC ;Have a PC word?
JRST TIMDD2 ;No..delete the entry
MOVE S2,.TIMPC(S2) ;[63] Yes..get the word
CAMN S2,.TIMPC(P2) ;They must match
TIMDD2: $CALL L%DENT ;Yes..zap it
TIMDD3: $CALL L%NEXT ;Check the next
JUMPT TIMDD1 ;Back to check the next
;Set wakeup time and return
;TIMDTX Sets wakup time and returns
TIMDTX: MOVE S1,TIMLST
$CALL L%FIRST ;Position to first entry
JUMPF TIMALX ;None..reset the flags
MOVE S1,.TITIM(S2) ;Set the wakeup time
MOVEM S1,TIMWAK
SETZM TIMPC ;Clear dispatch flag
SKIPLE S1,.TIMPC(S2) ;Want to execute this request
MOVEM S1,TIMPC ;Yes..remember this
$RETT
;TIMAL Kill all entries in the timer queue
TIMAL: MOVE S1,TIMLST ;Get the list address
$CALL L%FIRST
SKIPF
$CALL L%DENT ;Else delete all entries
JUMPT .-1
TIMALX: SETZM TIMWAK ;Clear wakeup time
SETZM TIMPC ;Clear dispatch flag
$RETT
SUBTTL I%HOST - Get Host Name/Number of Central Site
;THIS ROUTINE WILL RETURN THE NODE NAME AND NUMBER (-10 ONLY)
;FOR THE CENTRAL SITE.
;
;CALL: NO ARGUMENTS
;
;RETURN: S1/ HOST NAME IN SIXBIT
; S2/ HOST NUMBER
;
IFN FTUUOS,<
I%HOST: MOVEI S2,.GTLOC ;GET LOCATION OF JOB 0
GETTAB S2, ;...
JRST NOHOST ;No network if this fails
MOVE S1,S2 ;Copy node numer
$CALL CNVNOD ;Convert S1 to node name
JUMPF NOHOST ;Use local defaults
$RETT
CNVNOD:: $SAVE <T1,T2,T3,T4> ;Convert S1 to its compliment
MOVE T1,[.NDRNN,,T2] ;Function is convert name/num
MOVEI T2,2 ;2 Args specified
MOVE T3,S1 ;Put the node number in T3
NODE. T1, ;Get the sixbit
SKIPA ;Failed,,look into the error
JRST [MOVE S1,T1 ;Win,,get answer in S1
$RETT ] ;Return
CAMN T1,[.NDRNN,,T2] ;Are networks supported ???
SKIPE S1 ;No,,is the node number 0 ??
$RETE(NSN) ;Network support or non zero node number
MOVE S1,['LOCAL '] ;Use local as default
$RETT ;return
>;END FTUUOS
IFN FTJSYS,<
I%HOST: PUSHJ P,.SAVET ;SAVE THE T REGS
MOVX S1,.NDGLN ;GET LOCAL NODE NAME JSYS CODE
MOVEI S2,TF ;GET ARGUMENT BLOCK ADDRESS
HRROI TF,T1 ;MAKE BYTE POINTER TO T1
NODE ;GET THE LOCAL NODE NAME
ERJMP NOHOST ;NO NETWORKS
MOVE T3,[POINT 7,T1] ;GET POINTER TO NODE NAME
MOVE T4,[POINT 6,S1] ;GET OUTPUT POINTER
SETZ S1, ;SET OUTPUT BUFFER TO NULLS
HOST.1: ILDB S2,T3 ;GET AN INPUT BYTE
JUMPE S2,HOST.2 ;NULL,,GO FINISH UP
SUBI S2,40 ;MAKE IT SIXBIT
IDPB S2,T4 ;SAVE IT
JRST HOST.1 ;AND GO PROCESS ANOTHER
HOST.2: SETZ S2, ;0 FOR NODE NUMBER
$RETT ;AND RETURN
>;END FTJSYS
NOHOST: MOVE S1,['LOCAL '] ;Use local as default
SETZ S2,
$RETT
SUBTTL I%JINF - Canonical Job Information
;This Call is designed to provide a system independent way of getting Job
;information.
;
; CALL : S1/ JOB NUMBER OR -1 FOR CURRENT JOB
; S2/ FUNCTION CODE
;
;
; RETURN TRUE: S1/ JOB NUMBER PRESERVED FROM CALL
; S2/ RETURNED VALUE FOR FUNCTION
; RETURN FALSE: S1/ ERROR CODE
;
; DEFINED ERROR CODES
;
; ERUJI$ - UNDEFINED JOB INFO FUNCTION
; ERIJN$ - INVALID JOB NUMBER
I%JINF: CAIL S2,JI.MIN ;CHECK FUNCTION RANGE
CAILE S2,JI.MAX ;WITHIN BOUNDS
$RETE(UJI) ;UNDEFINED JOB INFO FUNCTION
MOVE S2,JINFTB-1(S2) ;GET THE DATA
SKIPL S2 ;FUNCTION CODE OR ROUTINE
JRST GJBGTB ;FUNCTION CODE DO THE WORK
HRRZS S2 ;GET ROUTINE ADDRESS
PJRST (S2) ;PROCESS THE FUNCTION
TOPS10<
GJBGTB: HRL S2,S1 ;PLACE JOB NUMBER IN LEFT HALF
GETTAB S2, ;GET THE INFO
$RETE(IJN) ;INVALID JOB NUMBER
$RETT ;RETURN TRUE
>;END TOPS10
TOPS20<
GJBGTB: $SAVE T1 ;SAVE T1
MOVE T1,S2 ;GET THE FUNCTION CODE
MOVSI S2,-1 ;1 WORD TO RETURN
HRRI S2,T1 ;RESULT IN T1
GETJI ;GET THE INFO
$RETE(IJN) ;INVALID JOB NUMBER
MOVE S2,T1 ;GET RETURNED DATA
$RETT ;RETURN TRUE
>;END TOPS20
;JOB INFO FUNCTION DISPATCH TABLE
DEFINE X(A,B,C),<
JI.'A==JI.'A ;GET SYMBOLS
TOPS10<C>
TOPS20<B>
>;END X
JINFTB: JBTAB ;EXPAND THE TABLE
SUBTTL I%JINF ROUTINES FOR THE -10
TOPS10<
;GET THE PATH DIRECTORY
GJBPTH: PUSHJ P,.SAVET ;SAVE THE T REGS
MOVS T1,S1 ;PUT JOB NUMBER IN T1
HRRI T1,.PTFRD ;READ DIRECTORY PATH
MOVSI S2,3 ;LENGTH OF BLOCK
HRRI S2,T1 ;ADDRESS OF BLOCK
PATH. S2, ;DO THE FUNCTION
$RETE(IJN) ;INVALID JOB NUMBER
MOVE S2,T3 ;GET THE PPN
$RETT ;RETURN TRUE
;GET THE CONTROLLING JOB NUMBER
GJBCJB: MOVE S2,S1 ;GET JOB NUMBER
CTLJOB S2, ;GET CONTROLLING JOB
$RETE(IJN) ;INVALID JOB NUMBER
$RETT ;CONTROLLING JOB OR -1 IF NOT CONTROLLED
;GET THE JOB NUMBER OF MY JOB
GJBJNO: SKIPL S2,S1 ;CHECK IF FOR ME
$RETE(IJN) ;INVALID JOB NUMBER
PJOB S2, ;GET THE JOB NUMBER
$RETT ;RETURN TRUE
GJBTLC: $SAVE <T1> ;SAVE AN AC
MOVE T1,S1 ;SAVE THE JOB NUMBER
SETZM S2 ;RETURN A ZERO FOR EARLY FAILURE
TRMNO. S1, ;GET THIS JOB'S TERMINAL #
$RETE(TLU) ;ERROR IF NO TERMINAL
GTNTN. S1, ;FIND OUT WHERE THAT TTY LIVES
$RETE(TLU) ;ERROR IF NO NODE,,TERMINAL
HLRZS S1 ;GET JUST THE TERM #
$CALL CNVNOD ;Convert S1 to sixbit
$RETIF ;Return any failures
MOVE S2,S1 ;Return node name in S2
MOVE S1,T1 ;Return Job number in S1
$RETT
;GET THE JOBS TERMINAL NUMBER
GJBTTY: MOVE S2,S1 ;SAVE THE JOB NUMBER
TRMNO. S2, ;GET THE TERMINAL NUMBER
JRST GJBT.1 ;ERROR..CHECK FOR DETACHED
TRZ S2,.UXTRM ;MAKE TERMINAL NUMBER
$RETT ;RETURN TRUE
GJBT.1: MOVN S2,S1 ;GET NEGATIEV JOB NUMBER IN S1
JOBSTS S2, ;DO JOBSTS UUO
$RETE(IJN) ;INVALID JOB NUMBER
TXNN S2,JB.UJA ;JOB NUMBER ASSIGNED
$RETE(IJN) ;INVALID JOB NUMBER
SETOM S2 ;-1 IF DETACHED
$RETT ;RETURN
GJBVER::MOVE S1,.JBVER ;Yes, get our version
$RETT ;Done
GJBRTM: SKIPGE S1 ;Want our job (-1)?
SETZ S1, ;Yes, adjust to RUNTIm UUO convetion
MOVE S2,S1 ;SAVE THE NUMBER AND GET VALUE IN S2
RUNTIM S2, ;Ask the monitor
$RETT ;Give it to user
GJBLOC: MOVEI S2,.GTLOC ;Function is get my location
$CALL GJBGTB ;Do the GETTAB
$RETIF ;Return any failure
EXCH S1,S2 ;Put number in S1
$CALL CNVNOD ;Convert to sixbit
$RETIF ;Return any failure
EXCH S1,S2 ;Else return sixbit in S2
$RETT ;With job number in S1
> ;End TOPS10
SUBTTL I%JINF SPECIAL ROUTINES FOR THE -20
TOPS20<
GJBLOC:
PUSHJ P,.SAVET ;SAVE THE ACS
HRRI T1,.JILLO ;GET THE FUNCTION CODE
MOVSI S2,-1 ;1 WORD TO RETURN
HRRI S2,T2 ;RESULT IN T2
HRROI T2,T3 ;POINTER TO T3
GETJI ;GET THE INFO
$RETE(IJN) ;INVALID JOB NUMBER
MOVE T1,[POINT 7,T3] ;SETUP INPUT POINTER
MOVE TF,[POINT 6,S2] ;GET OUTPUT POINTER
SETZ S2, ;SET OUTPUT BUFFER TO NULLS
GJBL.1: ILDB T2,T1 ;GET AN INPUT BYTE
JUMPE T2,.RETT ;NULL,,GO FINISH UP
SUBI T2,40 ;MAKE IT SIXBIT
IDPB T2,TF ;SAVE IT
JRST GJBL.1 ;AND GO PROCESS ANOTHER
GJBTLC: $SAVE <S1>
$CALL I%HOST
MOVE S2,S1 ;ONLY KNOW ABOUT OUR HOST FOR NOW
$RETT
GJBVER:: MOVX S1,.FHSLF ;Yes, aim at my process
GEVEC ;Get my entry info
HLRZ S1,S2 ;Get length
CAIN S1,(JRST) ;Is it an old entry vector (JRST start)
JRST [MOVE S1,137 ;Yes, get version ala TOPS-10
$RETT] ;Give that to user
CAIGE S1,2 ;Does it contain a version?
TDZA S1,S1 ;No, return 0
MOVE S1,2(S2) ;Yes, get it
$RETT ;Done
>;END TOPS20
SUBTTL I%WTO - ACK, WTO, WTOR MSG PROCESSOR
;THIS ROUTINE WILL GET A PAGE FROM THE MEMORY MANAGER, SET IT UP
;AS AN ACK, WTO OR WTOR MESSAGE AND THEN CALL $TEXT TO CREATE
;THE MESSAGE BODY.
I%WTO: PUSH P,(P) ;Copy return PC
POP P,RETADR ;And save for final POPJ
POP P,PRMADR ;GET THE PARM ADDRESS.
DMOVEM S1,S1%S2 ;SAVE THE TRASH AC'S.
MOVEM TF,STF ;SAVE TF ACROSS WTO
PUSHJ P,M%GPAG ;GET A PAGE FOR IPCF.
MOVEM S1,WTOSAB+SAB.MS ;SAVE THE PAGE ADDRESS.
MOVEI S2,.OHDRS ;GET OFFSET TO MSG BLOCKS.
STORE S2,.MSTYP(S1),MS.CNT ;SAVE IT IN THE MSG.
ADDI S2,ARG.HD(S1) ;Get addr of first free in msg
MOVEM S2,MSGADR ;Save for building
DEFINE NXTWTO(HERE),<
IFNB <HERE>,<NXTWT:> ;;If this is a definition, just define return loc
IFB <HERE>,<JRST NXTWT>;;Else just return
>;END DEFINE NXTWTO
NXTWTO(HERE) ;Define the loop location for the action routines
AOS S1,PRMADR ;BUMP OVER THE 'JRST'
;Get addr of this entry
SKIPN S1,(S1) ;End of list?
JRST IWTOFN ;Yes, all done
MOVEM S1,THSPRM ;Save arg for computing effective addr
DMOVE S1,S1%S2 ;Get back to user context
MOVE TF,STF ;And get caller's TF
MOVEI S1,@THSPRM ;Get addr from block
EXCH S1,THSPRM ;Save for action routine
LDB S1,[POINT 9,S1,8] ;Get op-code field
CAIL S1,WO.MIN ;Is it ..
CAILE S1,WO.MAX ; .. in range?
$STOP (WFO,<WTO Function ^O/S1/ Out of range at address ^O/PRMADR,RHMASK/>)
JRST @WTDSP-WO.MIN(S1) ;In range, do the work, and return via
;NXTWTO We'd like to do a PUSHJ here,
;but that would destroy the user's
;stack context
WTDSP: DEFINE .EAWTO(SUF,CODE),<$SET(WO.'SUF'-WO.MIN,,WTP'SUF')>
$BUILD WO.MAX-WO.MIN+1
ALLWTO
$EOB
;Here when all thru processing the user blocks
IWTOFN: PUSHJ P,I%WT.3 ;Send the message to OPR
PUSH P,RETADR ;Fix up stack for user again
DMOVE S1,S1%S2 ;Get back the users scratch regs
MOVE TF,STF ;Get back caller's TF
POPJ P, ;Go back to call + 1
;Action routines for each of the op-code types in the WTO macro
;Action routine for setting the message type
WTPMTY: MOVE S1,WTOSAB+SAB.MS ;Get address of message
MOVE S2,THSPRM ;Get addr of parameter (immediate argument)
STORE S2,.MSTYP(S1),MS.TYP ;Fill in message type
NXTWTO ;Try for next parameter
;Action routine for building the message type line
WTPTYP: MOVEI S1,.WTTYP ;Get code for type block
JRST IWTX.1 ;And do the $TEXT
;Action routine for building the remote node name block
WTPNHD: MOVE S1,@THSPRM ;[131]Pick up node name
MOVE S2,MSGADR ;[131]Pick up the block address
MOVEM S1,ARG.DA(S2) ;[131]Store the node name
MOVEI S1,2 ;[131]Pick up the block length
ADDM S1,MSGADR ;[131]Point to the next block
MOVSS S1 ;[131]Move block length to LH
PUSH P,S1 ;[131]Save for total message length
HRRI S1,.WTNHD ;[131]Pick up the block type
MOVEM S1,ARG.HD(S2) ;[131]Store in the message
MOVE S2,WTOSAB+SAB.MS ;[131]Pick up the message address
AOS .OARGC(S2) ;[131]Increment the argument count
POP P,S1 ;[131]Pick up the block length
ADDM S1,.MSTYP(S2) ;[132]Add to message length
NXTWTO ;[131]Continue scanning the WTO blocks
;Action routine for building the text block
WTPTXT: MOVEI S1,.WTTXT ;Get code for text block
IWTX.1: MOVE S2,MSGADR ;Get addr of message
STORE S1,ARG.HD(S2),AR.TYP ;Save the block type
ADD S2,[POINT 7,ARG.DA] ;CREATE A BYTE PTR TO THE DATA AREA.
MOVEM S2,BYTPTR ;AND SAVE IT.
SETZM BYTCNT ;Clear the # bytes put into message
DMOVE S1,S1%S2 ;Get back to caller's context
MOVE TF,STF ;And get caller's TF
$TEXT (IWTODP,<^I/@THSPRM/^0>) ;Fill in the text
MOVE S1,BYTCNT ;Get # chars moved
IDIVI S1,5 ;Convert to words
SKIPE S2 ;Any remainder?
AOS S1 ;Yes, take another word
ADDI S1,ARG.DA ;Account for arg header block
;Fall thru to add variable block
;Here to add a block whose length is in S1 to the message
IWTO.A: MOVE S2,MSGADR ;Get back start of arg block
STORE S1,ARG.HD(S2),AR.LEN ;Set length of block
ADDM S1,MSGADR ;Next block goes farther down
MOVE S2,WTOSAB+SAB.MS ;Get addr of entire message
AOS .OARGC(S2) ;Indicate another arg block is here
PUSH P,T1 ;Save a reg for a second
LOAD T1,.MSTYP(S2),MS.CNT ;Get old length of message
ADDI T1,(S1) ;Account for this block
STORE T1,.MSTYP(S2),MS.CNT ;Update message length
POP P,T1 ;Restore scratch reg
NXTWTO ;Continue scanning the WTO blocks
;Action routine for setting the header flags .MSFLG
WTPMFL: DMOVE S1,S1%S2 ;Get back to caller's context
MOVE TF,STF ;And get caller's TF
MOVE S1,@THSPRM ;Get arg word passed
WTPMF1: MOVE S2,WTOSAB+SAB.MS ;And aim at message again
IORM S1,.MSFLG(S2) ;Store the flags
NXTWTO ;Continue
;Action routine for setting the message flags
WTPFLG: DMOVE S1,S1%S2 ;Get back to caller's context
MOVE TF,STF ;And get caller's TF
MOVE S1,@THSPRM ;Get arg word passed
WTPFL1: MOVE S2,WTOSAB+SAB.MS ;And aim at message again
IORM S1,.OFLAG(S2) ;Store the flags
NXTWTO ;Continue
;Action routine for filling in the ack code
WTPACK: DMOVE S1,S1%S2 ;Get back to caller's context
MOVE TF,STF ;And get caller's TF
MOVE S1,@THSPRM ;Get the users ack code
MOVE S2,WTOSAB+SAB.MS ;Aim at message again
STORE S1,.MSCOD(S2) ;Stuff it in
NXTWTO ;Continue
;Action routine for adding the Object block
WTPOBJ: DMOVE S1,S1%S2 ;Get back to caller's context
MOVE TF,STF ;And get caller's TF
HRLI TF,@THSPRM ;Get start adrs of users obj block
MOVE S1,MSGADR ;Get start of next block
MOVX S2,.WTOBJ ;Get block type
STORE S2,ARG.HD(S1),AR.TYP ;Save in block header
MOVEI S1,ARG.DA(S1) ;Point to the block data
HRR TF,S1 ;Set dest. for BLT to data area
ADDI S1,OBJ.SZ-1 ;Compute terminating adrs for BLT
HRRZM S1,WTOBLT ;Save in memory (not in an AC)
DMOVE S1,S1%S2 ;Get back to caller's context
BLT TF,@WTOBLT ;Move in the Obj block
MOVEI S1,OBJ.SZ+ARG.DA ;Get size of space added
HRRZ S2,THSPRM ;[6000]Pick up block address
MOVE TF,OBJ.TY(S2) ;[6000]Pick up object type
TXNN TF,.DQLPT ;[6000]Is this a DQS LPT?
TXNE TF,.LALPT ;[6000]No, is it a LAT LPT?
SKIPA ;[6000]Yes, update the block code
PJRST IWTO.A ;[6000]No, Update the message
WTPO.1: $CALL FINOBB ;[6000]Finish building object block
ADDI S2,OBJ.SZ ;[6000]Point to the name block
MOVE S1,MSGADR ;[6000]Point to current message block
MOVE TF,S1 ;[6000]Save as destination address
HRLI TF,ARG.HD(S2) ;[6000]Pick up the source address
LOAD S2,ARG.HD(S2),AR.LEN ;[6000]Pick up the block length
ADD S1,S2 ;[6000]Add to start of destination adr
BLT TF,-1(S1) ;[6000]Copy over block
$CALL CHNTYP ;[6000]Change to WTO block code
MOVE S1,S2 ;[6000]Pick up block length
PJRST IWTO.A ;[6000]Finish up the message
FINOBB: PUSH P,T1 ;[6000]Save a reg for a second
MOVE T1,MSGADR ;[6000]Get back start of arg block
STORE S1,ARG.HD(T1),AR.LEN ;[6000]Set length of block
ADDM S1,MSGADR ;[6000]Next block goes farther down
MOVE T1,WTOSAB+SAB.MS ;[6000]Get addr of entire message
AOS .OARGC(T1) ;[6000]Indicate another arg block is here
LOAD TF,.MSTYP(T1),MS.CNT ;[6000]Get old length of message
ADDI TF,(S1) ;[6000]Account for this block
STORE TF,.MSTYP(T1),MS.CNT ;[6000]Update message length
POP P,T1 ;[6000]Restore scratch reg
$RET
CHNTYP: $SAVE <P1> ;[6000]Save this AC
HRRZ S1,THSPRM ;[6000]Pick up object block address
MOVE P1,OBJ.TY(S1) ;[6000]Pick up object type
TXNE P1,.DQLPT ;[6000]Is this a DQS LPT?
JRST CHNT.1 ;[6000]Yes, go pick up its code
MOVEI P1,OBJ.SZ(S1) ;[6000]Point to name block
LOAD P1,ARG.HD(P1),AR.TYP ;[6000]Pick up the type of name
MOVEI S1,.WTPOR ;[6000]Assume it is a PORT
CAIE P1,.KYPOR ;[6000]Is it?
MOVEI S1,.WTSER ;[6000]No, it is a SERVICE name
SKIPA ;[6000]Skip over the DQS code
CHNT.1: MOVEI S1,.WTDQS ;[6000]Pick up the DQS code
MOVE P1,MSGADR ;[6000]Pick up address of block to change
STORE S1,ARG.HD(P1),AR.TYP ;[6000]Update its WTO block code
$RET ;[6000]Return
; IWTODP - $TEXT ACTION ROUTINE TO BUILD THE ACK, WTO, & WTOR.
;THIS ROUTINE IS THE ACTION ROUTINE FOR $TEXT. IT BUILDS THE
;MESSAGE BLOCKS.
IWTODP: IDPB S1,BYTPTR ;SAVE THE BYTE IN THE MSG.
AOS BYTCNT ;BUMP BYTE COUNT
$RETT ;RETURN QUICK !!
SUBTTL WTPACD, WTOOCD ACTION ROUTINES
WTPOCD: SKIPA S2,[EXP .WTOCD] ;OBJECT TYPE BLOCK
WTPACD: MOVEI S2,.WTACD ;APPLICATION CODE BLOCK
JRST WTPN.1 ;USE THE COMMON ROUTINE
SUBTTL MORE WTO ACTION ROUTINES
WTPJBN: SKIPA S2,[EXP .WTJOB] ;Get block type - JOB
WTPNOD: MOVX S2,.WTDES ;Get block type - DEST NODE
WTPN.1: MOVE S1,MSGADR ;Get first free in message
STORE S2,ARG.HD(S1),AR.TYP ;Save either block type
DMOVE S1,S1%S2 ;Get back to caller's context
MOVE TF,STF ;Get back reg 0, too.
MOVE S2,@THSPRM ;Get job # or SIXBIT node name
MOVE S1,MSGADR ;Get first free in message
STORE S2,ARG.DA(S1) ;Save in block
MOVEI S1,ARG.DA+1 ;Get length of block (Hdr + 1 data)
PJRST IWTO.A ;Update message length, arg counts
I%SOPR: MOVEM S1,WTOSAB+SAB.MS ;SAVE THE PAGE ADDRESS IN THE SAB.
I%WT.3: STKVAR <<PAGEF>> ;PAGE/PACKET WTO FLAG
MOVEI S1,PAGSIZ ;GET SIZE OF MESSAGE
MOVEM S1,WTOSAB+SAB.LN ;SAVE IN LENGTH WORD OF WTOSAB
SETZM PAGEF ;CLEAR PACKET MODE FLAG WORD
MOVE S1,WTOSAB+SAB.MS ;GET THE MESSAGE ADDRESS
LOAD S1,.MSTYP(S1),MS.CNT ;GET THE MESSAGE LENGTH
CAMLE S1,MAXPAK## ;CAN WE SEND IT AS A PACKET ???
JRST I%WT.4 ;NO,,SEND IT AS A PAGE
MOVEM S1,WTOSAB+SAB.LN ;YES,,SAVE THE MSG LENGTH IN THE SAB
SETOM PAGEF ;SET THE PACKET MODE IPCF FLAG
I%WT.4: MOVEI S1,SAB.SZ ;PICK UP THE SAB SIZE.
MOVEI S2,WTOSAB ;PICK UP THE SAB ADDRESS.
PUSHJ P,C%SEND ;SEND THE WTO.
JUMPT [SKIPN PAGEF ;MSG WAS SENT OK,,WAS IT A PACKET ??
$RETT ;NO,,THEN JUST RETURN
MOVE S1,WTOSAB+SAB.MS ;YES,,GET THE MESSAGE ADDRESS
PJRST M%RPAG ] ;RETURN THE PAGE AND EXIT
SKIPE RSEFLG ;SEND FAILED,,DO WE RETURN ??
JRST [MOVE S1,WTOSAB+SAB.MS ;YES,,GET THE MESSAGE ADDRESS
PUSHJ P,M%RPAG ;RETURN THE PAGE
$RETF ] ;AND RETURN
CAIE S1,ERRQF$ ;NO -- IS IT RECIEVE OR
CAIN S1,ERSQF$ ; SEND QUOTA ERROR ???
JRST I%WT.4 ;YES -- RETRY
CAIE S1,ERNSP$ ;IS IT NO SUCH PID
CAIN S1,ERSLE$ ;OR SYSTEM LIMITS EXCEEDED?
JRST I%WT.4 ;YES -- RETRY
$FATAL (Send to ORION failed) ;DIE !!
INT%L: ;LABEL THE LITERAL POOL.
LSTOF.
LIT
LSTON.
CEND=:.-1 ;LABEL LAST OTS LOCATION
END