perm filename GOGOL[X,AIL]2 blob
sn#077599 filedate 1973-12-14 generic text, type T, neo UTF8
COMMENT ⊗ VALID 00060 PAGES VERSION 17-1(32)
RECORD PAGE DESCRIPTION
00001 00001
00013 00002 HISTORY
00022 00003 Command File Descriptions
00024 00004 Conditional Assembly Switches, Macros
00028 00005 Titles, Versions
00029 00006 AC Definitions
00030 00007 CDB, SIMIO Indices For IOSER, OTHER INDICES
00035 00008 Base (Low Segment) Data Descriptions -- Macros, Compil spec
00037 00009 Base (Low Segment) Data Descriptions - Params, Links, Size specs
00046 00010 Initialization Routines, Data
00048 00011 Sailor, Reent -- Allocation, Main Program Control
00051 00012 .SEG2. -- Get a second segment
00054 00013
00057 00014
00061 00015
00062 00016 Segment-Fetching Data
00065 00017
00066 00018 %ALLOC -- Main Allocation Routine
00072 00019
00079 00020
00084 00021
00089 00022 Utility Subroutines for allocation
00091 00023 %UUOLNK -- UUO Handler (Dispatch Vector Just Below)
00093 00024 DSCR OCTPNT, DECPNT UUO'S
00096 00025 DSCR PRINIT -- INTERFACE TO SYSTEM PRINTING FACILITIES
00097 00026 DSCR ERROR UUOS
00103 00027 DSCR CALLEDFROM -- PRINTS 'CALLED FROM' XXX 'LAST SAIL CALL AT'
00108 00028 Special Printing Routines For Error Handler
00112 00029 DSCR USERERR(VALUE,CODE,"MSG","RESPONSE")
00114 00030 Code to Handle Linkage to Editors
00117 00031 EXPORT VERSION OF EDITOR-INTERFACE
00121 00032 SAVE, RESTR, INSET -- General Utility Routines
00125 00033 Core Service Routines -- General Description
00130 00034 Special AC Declarations
00131 00035 Utility Routines
00136 00036
00140 00037 CORGET
00144 00038
00146 00039 CORINC, CANINC
00151 00040 CORREL
00156 00041 CORPRT, CORBIG
00159 00042 DSCR STRGC (REQUEST)
00165 00043 STRGC, Definitions
00166 00044 STRNGC -- Init, CALSGL, SGSWEP -- main loop through space sorting
00171 00045 STRNGC -- SWPLUP -- main sweep (string moving) loop
00173 00046 STRNGC -- SWPDUN -- expansion/contraction, parameter update
00177 00047 STRNGC -- STSTAT -- Finish Up, collect statistics
00179 00048 STRNGC Service routines -- SGSORT
00182 00049 STRNGC Service routines -- SPGC,STRMRK, etc. -- Descriptor providing routines
00187 00050 STRNGC Service routines -- SRTSPC -- space sorter
00191 00051 STRNGC Service routines -- SOURCE and DEST
00195 00052
00202 00053 STRNGC Service routines -- SGINS and SGREM
00204 00054 STRNGC Service routines -- STCLER and RESCLR
00206 00055 Some Runtime Routines Which Could Go Nowhere Else
00207 00056 Kounter Routines
00209 00057
00215 00058 DSCR POW, FPOW, LOGS, FLOGS. BOTH RETURN REALS.
00220 00059 DSCR EXP,ALOG -- FOR USE BY EXPONENTIATION ROUTINES & WORLD
00228 00060 DSCR VAL←CODE(OCTAL COMMAND, REFERENCE ARG)
00230 ENDMK
⊗;
COMMENT ⊗HISTORY
AUTHOR,FAIL,REASON
031 102100000040 ⊗;
DEFINE .VERSION <102100000040>
COMMENT ⊗
VERSION 17-1(32) 12-14-73 BY RHT BUG #QA# PARAM COUNT TO GC TRAP WRONG
VERSION 17-1(31) 12-14-73
VERSION 17-1(30) 12-12-73 BY RHT MOVE LPLK OUT OF MIDDLE OF XX AREA
VERSION 17-1(29) 12-11-73 BY rht make rfs happy
VERSION 17-1(28) 12-10-73 BY RFS BUG PU, PAGE 26
VERSION 17-1(27) 12-10-73
VERSION 17-1(26) 12-10-73
VERSION 17-1(25) 12-8-73 BY JRL REMOVE SPECIAL STANFORD CHARACTERS(WHERE POSSIBLE)
VERSION 17-1(24) 12-3-73
VERSION 17-1(23) 12-3-73
VERSION 17-1(22) 12-3-73
VERSION 17-1(21) 12-3-73
VERSION 17-1(20) 12-3-73 BY RFS ELIMINATE ALL III DISPLAY STUFF
VERSION 17-1(19) 12-2-73 BY KVL MAKE ERR DISPATCH TO ETV INSTEAD OF TV
VERSION 17-1(18) 12-2-73 BY RHT ALLOW MORE ROOM FOR HERES
VERSION 17-1(17) 12-1-73 BY RLS ADD CDB INDICES FOR SETPL FUNCTION
VERSION 17-1(16) 11-30-73 BY RHT FLUSH ERRSPC DECL IN SAILOR
VERSION 17-1(15) 11-30-73 BY RHT ADD A FEW MORE XX SPARES
VERSION 17-1(14) 11-28-73 BY RHT FIX USERERR RIGHT
VERSION 17-1(13) 11-26-73 BY RHT TRIVIAL IMPROVEMENT TO AC PUSH LOOP IN ERR HANDLER
VERSION 17-1(12) 11-25-73 BY RHT FEAT %AO% DO SETPR2 IF REMAP LOSES.
VERSION 17-1(11) 11-25-73 BY KVL ADD "A" AND "C" OPTIONS TO WATNOW LOOP OF ERR
VERSION 17-1(10) 11-24-73 BY RHT FEAT %AL% SET UP RF FOR OUTER BLOCK
VERSION 17-1(9) 11-24-73 BY RHT MOVE PHASE COUNTS TO HEAD
VERSION 17-1(8) 11-24-73
VERSION 17-1(7) 11-21-73 BY RHT MINOR FIXUP TO (NEW) USERERR
VERSION 17-1(6) 11-20-73 BY RFS CHANGE CHNL TO REG 10 TO FREE RF.
VERSION 17-1(4) 11-20-73 BY RFS ADD NEW EXPONENTIATION CODE; REENTRANT ERROR HANDLER
10/29/73 %AH% -- REE W/O STARTING
10/23/73 %AG% -- LEAPIS SWITCH IN $GITNO, NOT $ITNO
10/6/73 %AD% -- ALLOW LOWER CASE ANSWER TO "ALLOC"
9/18/73 MAKE END OF SAIL EXECUTION MESSAGE DO A CRLF FIRST
VERSION 17-1(3) 7-27-73 BY KVL PUTS IN SOME XX'S FOR HOLDING .LOG FILE INFO
VERSION 17-1(2) 7-27-73 BY KVL DECLARE ERSCPD IN LOWER
VERSION 17-1(1) 7-26-73 BY RHT ****** VERSION 17 STRIKES HERE *******
VERSION 16-2(65) 7-13-73 BY JRL HERE CORGET AND FRIENDS
VERSION 16-2(64) 7-13-73
VERSION 16-2(63) 7-13-73
VERSION 16-2(62) 6-28-73 BY JRL BUG #MW# PPMAX NOT EXTERALED IN SAILUP(EXPORT ONLY)
VERSION 16-2(61) 5-3-73 BY RHT ADD EXTRA THREE XX CELLS FOR INTRPT SYS
VERSION 16-2(60) 2-27-73 BY JRL REMOVE ..RVAL FROM XX AREA
VERSION 16-2(59) 2-12-73 BY JRL ADD ..RVAL TO XX AREA
VERSION 16-2(58) 1-8-73 BY JRL BUG #KV# CHECK FOR NULL INILNK IN .UNIT
VERSION 16-2(57) 12-2-72 BY RHT ENLARGE HERE TABLE
VERSION 16-2(56) 12-1-72 BY RHT ADD DEFSSS,DEFPSS,DEFQNT,DEFPRI TO XX AREA
VERSION 16-2(55) 11-30-72 BY RHT ADD XX ENTRY FOR NOPOLL
VERSION 16-2(54) 11-22-72 BY JRL BUG #KL# STACSV SAVED TOO MANY AC'S IN TOO FEW LOCATIONS
VERSION 16-2(53) 11-22-72
VERSION 16-2(52) 11-22-72
VERSION 16-2(51) 11-17-72 BY RHT MAKE USER INITIALIZATION A SEPARATE PROCEDURE
VERSION 16-2(50) 11-10-72 BY JRL ADD PROPS TO XX AREA
VERSION 16-2(49) 10-12-72 BY RHT ADD PPMAX FOR EXPO VERSION (NEEDED BY ED LNKG)
VERSION 16-2(48) 10-5-72 BY JRL MAKE GLUSER INTERNAL
VERSION 16-2(47) 10-3-72 BY RHT MAKE USER INIT WORK RIGHT
VERSION 16-2(46) 9-24-72 BY JRL FIX LIB ENTRIES FOR PROC. STR GAR COL
VERSION 16-2(45) 9-21-72 BY RHT SCREW UP THE COMPIL MACRO
VERSION 16-2(44) 9-21-72 BY JRL ADD SPRPDA TO SGC COMPIL MACRO
VERSION 16-2(43) 9-11-72 BY JRL ADD GINFTB,GDATM TO LOWER WHEN NO GLOB
VERSION 16-2(42) 9-5-72 BY JRL BAD FIX TO SGLKBK PROBLEM
VERSION 16-2(41) 8-21-72 BY RHT PUT IN JRL'S STACSV &STACRS
VERSION 16-2(40) 8-7-72 BY RHT CHANGE INILNK STUFF
VERSION 16-2(39) 8-7-72 BY KVL PRINT MSG BEFORE CANT CONTINUE ANY FURTHER MSG (P24)
VERSION 16-2(38) 7-3-72 BY DCS BUG #IC# ADD NEW MEANING TO NOSHRK(USER)
VERSION 16-2(37) 7-3-72 BY DCS BUG #IB# MAKE DEFAULT SYSTEM STACK SIZE BIGGER
VERSION 16-2(36) 7-2-72 BY JRL HAVE %ALLOC CALL LPINI IF NEEDED
VERSION 16-2(35) 6-20-72 BY DCS BUG #HU# BETTER TTY PRINTOUT
VERSION 16-2(34) 5-16-72 BY DCS BUG #HI# %ARRSRT TESTS RIGHT BIT FOR STR ARRAY NOW
VERSION 16-2(33) 5-11-72 BY DCS BUG #HE# MODIFY VERSION CHECKING, INSTALL VERSION 16
VERSION 15-6(23-32) 5-3-72 VARIOUS FIXES
VERSION 15-6(14-22) 2-21-72 VARIOUS FIXES
VERSION 15-6(13) 2-19-72 BY RHT THE BRAVE NEW WORLD
VERSION 15-2(12) 2-5-72 BY DCS BUG #GI# REMOVE TOPSTR
VERSION 15-2(11) 2-2-72 BY DCS BUG #GI# LEAVE SOME SLOP IN REMCHR SO CAT'LL BE MORE EFFICIENT
VERSION 15-2(10) 2-1-72 BY DCS REPLACE (FIXED) %ALLOC BLOCK ACCESSES BY SYMBOLIC HEAD-DEFINED ONES
VERSION 15-2(9) 1-30-72 BY DCS REPLACE %ALLOC -- INITIAL ALLOCATION
VERSION 15-2(8) 1-14-72 BY DCS BUG #GA# SEGMENTS HAVE .SEG EXTENSIONS, NOT .REL
VERSION 15-2(7) 1-3-72 BY DCS BUG #FX# REMOVE NEED FOR COM2, REORGANIZE SEGMENT-GETTING STUFF
VERSION 15-2(6) 12-26-71 BY DCS BUG #FU# REENABLE ACCESS FROM ERR UUO TO FTDEBUGGER
VERSION 15-2(5) 12-24-71 BY DCS BUG #FT# DSPLIN BETTER, TV AS VALID EDITOR
VERSION 15-2(4) 12-22-71 BY DCS BUG #FF# SIXPRT(14-15) TO ERR, IOERR ROUTS
VERSION 15-2(3) 12-22-71 BY DCS BUG #FS# REMOVE SAILRUN, COM2, ASSUME COMPILER
VERSION 15-2(2) 12-2-71 BY DCS ADD VERSION SETUP CODE
VERSION 15-2(1) 12-2-71 BY DCS INSTALL VERSION NUMBER
⊗;
SUBTTL Command File Descriptions
LSTON (GOGOL)
COMMENT ⊗
The following command files make runtime routines:
1. RUN
One assembly, get a non-library, non-2d-segment runtime package
RUNTIM=HEAD+ORDER+GOGOL+TRIGS+STRSER+IOSER+NWORLD+LEPRUN+MESPRO+WRDGET
2. SGMNT
Makes the non-global UPPER.REL and SAILOW.REL, which when
loaded and run and stuff become SAISGn.SEG and SAILOW.REL,
the 2d segment runtime routines
TAILOR=HEAD+FILSPC+TAILOR/NOLO
LOWER=HEAD+LOW+FILSPC+GOGOL/NOLO
TAILOR.REL,UPPER=HEAD+UP.FAI+ORDER+GOGOL+STRSER+IOSER+
NWORLD+LEPRUN+MESPRO+WRDGET
5. GSGMNT
Makes the global model SAILOW AND UPPER, otherwise like
SGMNT
Same, but add GLB after HEAD in all three.
6. SCISS.SAI
This SAIL program, when run, uses the runtime files to
make a LIBSAI.REL file, the SAIL (lower-segment) library
⊗
SUBTTL Conditional Assembly Switches, Macros
DSCR ** CONDITIONAL ASSEMBLY SWITCHES **
⊗
STSW(UPPER,0) ;NOT UPPER OR LOWER IF NEITHER SET
STSW(LOWER,0)
STSW(GLOBSW,0) ;ONLY GLOBAL IF SOMEBODY ELSE SAID SO
STSW(SEGS,0)
STSW(RENSW,0) ;RE-ENTRANT LIBRARY (HISEG) IF ON
STSW(LEAPSW,1) ;ASSUME LEAP
EXPO <
STSW(APRISW,1) ;THE APR INTERRUPT PACKAGE IS TO BE USED
>;EXPO
NOEXPO <
STSW(APRISW,0) ;USUALLY USE THE MOORER PACKAGE
>;NOEXPO
DSCR COMPIL(NAM,ENTRIES,EXTERNALS,DESCRIPTION,INTERNALS,HINHB)
CAL MACRO
PAR NAM IS 3 CHAR NAME -- TITLE WILL BE SAINAM
ENTRIES ARE LIST OF ENTRIES CONTAINED IN THIS
LIBRARY ASSEMBLY (INTERNALS IF NOT LIBRARY SETUP)
EXTERNALS (OPTIONAL) ARE EXTERNALS NEEDED FOR THIS ENTRY.
DESCRIPTION IS OPTIONAL, AND IS USED IN THE SUBTTL
IF PRESENT.
INTERNALS (OPTIONAL) DESCRIBE INTERNALS WHICH ARE NEVER ENTRIES.
HINHB (OPTIONAL ANYTHING), IF NON-BLANK, INHIBITS THE HISEG)
DES IF MAKING A LIBRARY, AND IF THIS FILE IS DESIRED
(SEE SCISS PROGRAM), A FILE OF THE NAME SAINAM.FAI
WILL BE MADE CONTAINING ALL THE PROGRAM TEXT FROM THE
COMPIL MACRO TO THE ENDCOM MACRO WHICH SHOULD FOLLOW
THE CODE FOR THIS ENTRY. ENDCOM DOES AN END IF
IN LIBRARY COMPILE MODE.
RES THE MACRO EXPANDS TO PROVIDE A TITLE AND THE
APPROPRIATE ENTRIES AND EXTERNALS FOR THIS ASSEMBLY.
ALSO A SUBTTL CONTAINING THE TITLE AND OPTIONAL
DESCRIPTION IS PROVIDED.
⊗
DEFINE COMPIL ' (NAM,ENT,EXT,DSCRP,INT,HINHB,DUMMY) <
IFIDN <DUMMY>,<> <
SUBTTL SAI'NAM -- DSCRP
IFE ALWAYS,<
IFDIF <><ENT>,<ENTRY ENT>
TITLE SAI'NAM
REN <
IFIDN <><HINHB>,<HISEG ;LOAD TO UPPER IF POSSIBLE>
>;REN
IFDIF <><EXT>,<EXTERN EXT>
>;IFE ALWAYS
NOLOW <
IFDIF <><INT>,<INTERN INT>
IFN ALWAYS,<
IFDIF <NAM><LOR>,<
IFDIF <><ENT>,<INTERNAL ENT>
>>
>;NOLOW
>;IFIDN <DUMMY>
>
DEFINE COMPXX ' (NAM,ENT,EXT,DSCRP,INT,HINHB)
<COMPIL(<NAM>,<ENT>,<EXT>,<DSCRP>,<INT>,<HINHB>)>
DEFINE ENDCOM (NAM) <
IFE ALWAYS,<
END
>;IFE ALWAYS
>
; SWITCHES TO CONTROL LIBRARY COMPILATION
IFNDEF ALWAYS,<?ALWAYS←←1>
IFN ALWAYS,<DEFINE ENTINT (X) <INTERNAL X>>
IFE ALWAYS,<DEFINE ENTINT (X) <ENTRY X>>
SUBTTL Titles, Versions
DSCR TITLES, VERSIONS
⊗
IFN ALWAYS,<
; "TITLE UPPER" IS FOUND IN UP.FAI FILE TO MAKE OUTER PROG TITLED
LOW <
TITLE LOWER
>;LOW
NOUP <
NOLOW <
TITLE RUNTIM -- SAIL RUNTIME ROUTINES
>;NOLOW
JOBVER←←137
LOC JOBVER
;;#HE# DCS 5-11-72 (1-2) MODIFY VERSION STUFF
.VERSION&777777000000 ;CURRENT VERSION NUMBER (LH ONLY)
RELOC
;;#HE# (1-2)
>;NOUP
>;ALWAYS NEQ 0
SUBTTL AC Definitions
DSCR AC DEFINITIONS
⊗
; AC DEFINITIONS FOR SERVICE AND RUNTIME ROUTINES
; ALL UUO ROUTS, IOSER COMMENTS
; CORE ROUTS,
; STRING GC,
; ALLOCATION
?FF←←0
?A←1 ;TEMPS FOR ALLES
?B←2 ; (SOMETIMES SAVED)
?C←3
?D←4
?E←5 ?X←5 ;MORE TEMPS
?Q1←6 ?Y←6
?Q2←7 ?Z←7
?Q3←10 ?CHNL←10 ;CHNL # FOR IOSER
?T←11 ?CDB←11 ;CHANNEL DATA BLOCK PTR
?T1←12 ;TRY TO KEEP 12(RF) VALID.
?LPSA←13 ;TEMP, PARAM AC
?TEMP←14 ;TEMP ONLY
?USER←15 ;PTR USER TABLE FOR RNTRNT ROUTS
?SP←16 ;STRING STACK
?P←17 ;SYSTEM STACK
SUBTTL CDB, SIMIO Indices For IOSER, OTHER INDICES
DSCR -- CDB, SIMIO INDICES FOR IOSER
DES The I/O routines obtain their information from the user via a
channel number -- the same kind used by the system. In order to
find byte pointers, counts, file names, etc., the channel number is
used to index into a block of core called a CDB (Channel Data Block).
This CDB is filled with good data during the OPEN operation.
The CDB, and all I/O buffers, are obtained from CORGET.
The CHANS table in the GOGTAB area is a 20 word block containing
pointers to the appropriate CDB's.
Since channel numbers must appear in the AC field of IO instructions,
one must construct IO insts. in impure places to retain re-entrancy.
XCT INDEX,SIMIO executes the appropriate IO instruction with the
channel number from AC CHNL, used by all routines. See SIMIO for
operational details.
⊗
; SIMIO INDICES
?IOSTATUS ←← 0 ;RETURN STATUS
?IOIN ←← 1 ;BUFFERED INPUT
?IODIN ←← 2 ;DUMP INPUT
?IOOUT ←← 3 ;BUFMODE OUT.
?IODOUT ←← 4 ;DUMP OUTPUT
?IOCLOSE ←← 5 ;CLOSE FILE
?IORELEASE←← 6 ;RELEASE FILE
?IOINBUF ←← 7 ;INBUF
?IOOUTBUF ←←10 ;OUTBUF
?IOSETI ←←11 ;USETI
?IOSETO ←←12 ;USETO
; 13 UNUSED
?IOOPEN ←←14 ;OPEN CHANNEL
?IOLOOKUP ←←15 ;LOOKUP FILE
?IOENTER ←←16 ;ENTER FILE
?IORENAME ←←17 ;RENAME FILE
; FORMAT OF CDBs
DMODE ←← 0 ;DATA MODE
DNAME ←← 1 ;DEVICE
BFHED ←← 2 ;HEADER POINTERS
OBPNT ←← 3 ;OUTPUT BUF. PTR
OBP ←← 4 ;OUTPUT BYTE PTR
OCOWNT ←← 5 ;OUTPUT BYTE CNT
ONAME ←← 6 ;OUTPUT FILE NAM
OBUF ←← 7 ;OUTPUT BUFFER LOC.
IBPNT ←←10 ;SAME FOR INPUT
IBP ←←11
ICOWNT ←←12
INAME ←←13
IBUF ←←14
ICOUNT ←←15 ;INPUT DATA COUNT LIMIT ADDRESS
BRCHAR ←←16 ;XWD TTYDEV FLAG, INPUT BREAK CHAR ADDR
TTYDEV ←←16 ;LH -1 IF DEVICE IS A TTY -- USED BY OUT
ENDFL ←←17 ;INPUT END OF FILE FLAG ADDR
ERRTST ←←20 ;USER ERROR BITS SPECIFICATION WORD
LINNUM ←←21 ;ADDR OF LINE NUMBER WORD (SETPL FUNCTION)
PAGNUM ←←22 ;ADDR OF PAGE NUMBER WORD (SETPL FUNCTION)
SOSNUM ←←23 ;ADDR OF SOS NUMBER WORD (SETPL FUNCTION)
↑IOTLEN ←←SOSNUM+1 ;LENGTH OF TABLE ENTRY
?LUPDL←30 ;LENGTH OF UUO PDL
?MINPDS←←=64 ;SMALLEST ALLOWABLE SYSTEM PDL SIZE
?DEFPDS←←=192 ;DEFAULT PDL SIZE
; String space header indices -- one header per String Space
?.HDRSIZ←←4 ;Header allocated in each string space
?.NEXT←←-1 ;Next string space
?.LIST←←-2 ;Used to link descriptors during GC
?.SIZE←←-3 ;Size of this space
?.STTOP←←-4;< ;=> 1 past last word this space (redundant)
SUBTTL Base (Low Segment) Data Descriptions -- Macros, Compil spec
DSCR DATA DESCRIPTIONS, TAILORED FOR TWO SEGMENT OPERATION
⊗
NOUP <
DEFINE SGLK (ROUT,NAM,INT) <
XX (NAM,ROUT,INT) ;NAME OF STRING DSCRPTR GENERATING ROUTINE
XX (,0,) ;PLACE TO PUT A LINK
LINK %SGROT,.-1 ;WHEREWITHAL TO GENERATE SAID LINK
>
>;NOUP
UP <
DEFINE SGLK (ROUT,NAM) <
XX (NAM,ROUT,)
XX (,0,)
>
>;UP
DEFINE XX (A,B,C,D) <
IFDIF <A><>,<? A :> B
IFDIF <C><>,< C A >
>
UP <
III←←140
DEFINE XX (A,B,C,D) <
IFDIF <A><>,<? A ← III >
III ←← III + 1
IFDIF <D><>,<III←III+D-1>
>
>;UP
COMPIL(LOR,<SAILOR,.SEG2.>
,<%UUOLNK,%ALLOC,%SPGC,%STRMRK,%ARRSRT,K.OUT,$PDLOV>
,<BASE DATA, INITIALIZATION CONTROL>
,<X11,X22,X33,X44>,INHIBIT)
SUBTTL Base (Low Segment) Data Descriptions - Params, Links, Size specs
; UNIVERSAL VARIABLES -- BASES OF MAJOR DATA STRUCTURES, GLOBAL FLAGS
XX (GOGTAB,0,INTERNAL) ;PTR TO USER TABLE
XX (DATM,0,INTERNAL) ;XWD 3,ADDR OF DATUM TABLE
XX (LKSTAT,0,INTERNAL) ;STATUS OF GLOBAL LEAP MODEL INTERLOCK (SHOULD BE IN GOGTAB
XX (INFTB,0,INTERNAL) ;POINT 9,ADDRESS INFOTAB TABLE(3)
XX (.SKIP.,0,INTERNAL) ;RECORD AUX RESULTS OF RUNTIMES
XX (RPGSW,0,INTERNAL) ;SET IF (JOBSA)+1 USED TO START
XX (%RENSW,0,INTERNAL) ;SET IF USER WANTS TO RENTER FOR ALLOC
XX (CONFIG,0,INTERNAL) ;0 FOR RUNTIME, <0 FOR COMPILER
XX (.ERRP.,0,INTERNAL) ;PLACE FOR USER TO PUT AN ERROR PROCEDURE
XX (.ERRJ.,0,INTERNAL) ;TRANSFER ADDRESS RETURNED BY USER PROC.
XX (%ERRC,0,INTERNAL) ;COMMUNICATION BETWEEN USERRR AND ERROR UUO.
XX (%RECOV,0,INTERNAL) ;HIGH ORDER BIT ON IF ERROR RECOVERABLE
XX (%ERGO,0,INTERNAL) ;SET IF IN CONTINUATION MODE.
XX (.ERSTP,0,INTERNAL) ;POINTER INTO ERROR STRING.
XX (.ERSTR,<BLOCK 20>,INTERNAL,20) ;ERROR MESSAGE STRING.
XX (.DTRT.,0,INTERNAL) ;DDT RETURN ADDRESS
;;% %
XX (.EXPINT,0,INTERNAL) ;CORE UUO TRAP ROUTINE ADDRESS (CMU-STYLE)
XX (.SGCINT,0,INTERNAL) ;STRING GC TRAP ROUTINE ADDRESS (")
XX (.TRACS,<BLOCK 12>,INTERNAL,12) ;CORE, STRNGC TRAP ROUTINE SAVE ACS
XX (RUNNER,0,INTERNAL) ;THE CURRENTLY RUNNING PROCESS(IF HAVE THEM)
XX (INTRPT,0,INTERNAL) ;MASK FOR INTERRUPT POLLING
XX (PROPS,0,INTERNAL) ;BYTE POINTER FOR ACCESSING PROPS(ITEM) ITEM IN 3
XX (NOPOLL,0,INTERNAL) ;NEQ 0 MEANS IGNORE CALL TO DDFINT
XX (DEFSSS,0,INTERNAL) ;DEFAULT S-STACK SIZE -- SET BY MAINPR
XX (DEFPSS,0,INTERNAL) ;DEFAULT P-STACK SIZE (FOR PROCESSES) -- DITTO
XX (DEFPRI,0,INTERNAL) ;DEFAULT PRIORITY -- DITTO
XX (DEFQNT,0,INTERNAL) ;DEFAULT QUANTUM -- DITTO
XX (OVPCWD,0,INTERNAL) ;SET BY APR INTERRUPT HANDLER (IF ANY)
NOEXPO <
IFE APRISW <
XX (XJBCNI,0,INTERNAL) ;JOBCNI TYPE THING FOR MOORER SYS (MOD BY F.WRIGHT)
XX (XJBTPC,0,INTERNAL) ;JOBTPC THING, ETC
XX (XJBAPR,0,INTERNAL) ;JOBAPR THING.
>;IFE APRISW
IFN APRISW <
XX (S15ARE,0)
XX (S16ARE,0)
XX (S17ARE,0)
>;IFN APRISW
>;NOEXPO
XX (XJBENB,0,INTERNAL) ;USED BY APR ENABLER FOR EXPORT SYSTEM
;SPARE LOWER LOCATIONS
XX (S2PARE,0)
XX (S3PARE,0)
XX (S4PARE,0)
XX (S5PARE,0)
XX (S6PARE,0)
XX (S7PARE,0)
XX (S8PARE,0)
XX (S9PARE,0)
XX (S10ARE,0)
XX (S11ARE,0)
XX (S12ARE,0)
XX (S13ARE,0)
XX (S14ARE,0)
GLOB <
XX (GSPARE,<BLOCK 2>,,2)
>;GLOB
NOGLOB <
XX (GDATM,0,INTERNAL) ;DUMMY GLOBAL DATUM TABLE SHOULD ALWAYS BE ZERO
GPROPS←GINFTB←GDATM ;DUMMY GLOBAL INFOTAB DITTO
INTERNAL GINFTB,GPROPS
>;NOGLOB
; STATIC LINKAGES -- FEATURE PROVIDED BY LOADER
; THESE ARE THE BASES OF ONE-WAY LINKED LISTS WHICH ALLOW ACCESS
; TO SELECTED DATA IN ALL LOADED MODULES
XX (STLNK,0,INTERNAL) ;1 ALL STRINGS TIED TOGETHER FOR STRNGC
XX (SPLNEK,0,INTERNAL) ;2 ALL SPACE REQUESTS (PDLS, ETC.)
XX (SETLET,0,INTERNAL) ;3 ALL SET VARIABLES TIED TOGETHER
XX (SGROT,0,INTERNAL) ;4 LIST OF STRNGC SORTER GENERATORS
XX (KTLNK,0,INTERNAL) ;5 ALL COUNTER BLOCKS
XX (INILNK,0,INTERNAL) ; INITIALIZATION ROUTINES (LPINI ONLY NOW)
; THESE OPS INFORM THE LOADER OF THE ABOVE BASE LOCATIONS.
NOUP <
LINKEND %STLNK,STLNK
LINKEND %SPLNK,SPLNEK
LINKEND %SETLK,SETLET
LINKEND %SGROT,SGROT
LINKEND %KTLNK,KTLNK
LINKEND %INLNK,INILNK
>;NOUP
; SOME ROUTINES WHICH GO ON THE SGROT LIST (SEE SGLK)
;↑SGLKBK
SGLK (%ARRSRT,SGLKBK,INTERNAL);ROUTINE TO COLLECT STRING ARRAYS
SGLK (%STRMRK) ;ROUTINE TO COLLECT STRING VARIABLES
SGLK (%SPGC) ;ROUTINE TO COLLECT STRING STACK
;HERE IS THE LIST OF DEFAULT SPACE ALLOCATION ENTRIES
XX (%SPL,<BLOCK $SPREQ-2>,INTERNAL,$SPREQ-2);DUMMY FIXED ADDR STUFF
XX (%STDLST,<BLOCK 2>,INTERNAL,2) ;BASE OF BUILT-IN REQUESTS
XX (,<XWD WNTPDP!MINSZ!USRTB,DEFPDS>) ;SYSTEM!PDL (SPECIAL, SEE BELOW)
XX (,<XWD [ASCIZ /SYSTEM PDL/],PDL>)
XX (,<XWD WNTPDP!USRTB!MINSZ,50>) ;STRING STACK
XX (,<XWD [ASCIZ /STRING PDL/],SPDL>)
XX (,<XWD WNTADR!WNTEND!USRTB!MINSZ,2000>);STRING!SPACE
XX (,<XWD [ASCIZ /STRING SPACE/],ST>)
XX (,0) ;THAT'S ALL
; LINK %SPLNK,%SPL ;%ALLOC DOES THIS EXPLICITLY SO THIS
;BLOCK WILL BE FIRST
;SOME RANDOM GLOBALLY USEFUL THINGS, WHICH UNFORTUNATELY HAVE TO
;BE IN FIXED LOCATIONS (FOR THE RUNTIMES TO FIND)
; MADE ALLPDL BIGGER (FROM 20) BECAUSE OF NEW UUO HANDLER
XX (ALLPDP,<IOWD 40,ALLPDL>,INTERNAL);USED FOR A WHILE DURING ALLOC
XX (ALLPDL,<BLOCK 40>,INTERNAL,40) ;AND IN PROCESS TERMINATION
XX (%ALLCHR,0,INTERNAL)
XX (%OCTRET,0,INTERNAL)
;SOME WONDERFULLY USEFUL CONSTANTS
XX (X11,<XWD 1,1>,INTERNAL)
XX (X22,<XWD 2,2>,INTERNAL)
XX (X33,<XWD 3,3>,INTERNAL)
XX (X44,<XWD 4,4>,INTERNAL)
EXPO <
XX (PPMAX,<BLOCK 3>,INTERNAL,3) ;FOR SCREWY EDITOR LINKAGE
>;EXPO
XX (APRACS,<BLOCK 20>,INTERNAL,20) ;APR INTERRUPT AC STORAGE
LOW <
EXTERNAL LPINI
LPLK: 0
LPINI
0
LINK %INLNK,LPLK
>;LOW
SUBTTL Initialization Routines, Data
COMMENT ⊗ The Run-Time I/O handling routines are re-entrant. This
means that any modifiable words or parameters particular to a given
user must come from the user's core image. The pointer to this area
will be found in GOGTAB in the lower segment. The I/O routines use
some of the AC'S in standard ways, described above with AC definitions.
⊗
DSCR SAILOR -- ALLOCATION AND INITIALIZATION ROUTINES
CAL JSR
DES
Part of this is not yet reentrant. In particular,
it is called by a JSR SAILOR
The functions of this routine are:
1. Get a second segment, if this is a SAISEG-program
2. Process space requests, allow user-override if REENTER used
to start.
3. Use %ALLOC to allocate requested regions.
4. Clear Kounters
5. Change starting and re-entry addresses,
6. PUSHJ to user program
7. Record Kounters, RESET and quit.
⊗
SUBTTL Sailor, Reent -- Allocation, Main Program Control
NOUP <
;SAIL job calls SAILOR first time, with RPGSW set up already
INTERNAL SAILOR
↑SAILOR: 0 ;JSR to SAILOR
JRST FRSTRT ;GET A SEGMENT, START UP
; REENTER to manually change allocation, and to flush REQUIREd segments
; Set Re-entry address
LOC 124 ;SET UP REENTER ADDRESS
REENT
RELOC
↑REENT: SETOM %RENSW ;RE-ENTER -- ASK FOR NEW ALLOC
;;% %2.! DCS 12-3-73 SIMPLE REENTER SEQUENCE
HRRZ TEMP,JOBSA ;SAME AS START, OTHERWISE
JRST (TEMP)
;SAIL STARTS HERE WHEN USER TYPES S<T<A<R<T>>>> AGAIN
↑RESTRT:TDZA TEMP,TEMP ;ESTABLISH OPERATING MODE
MOVNI TEMP,1 ;RPG MODE
MOVEM TEMP,RPGSW ;RECORD IT
FRSTRT: JSP P,.SEG2. ;GET SECOND SEGMENT
;; %AO% ;WILL SKIP RETURN IF DOES A SETPR2
;INSTEAD OF SEGMENT FETCHING
STRT: CALL6(RESET)
SETZM GOGTAB ;FORCE CORSER RE-INITIALIZATION
SETNIT ;GET TEMP STACK, IF NECESSARY
JSP 16,%ALLOC ;ALLOCATE AREAS
MOVEI A,RESTRT ;CHANGE JOBSA AND JOBREN
HRRM A,JOBSA ;"S" USES OLD ALLOCATION
;;%AL% .! THE OUTER BLOCK IS JUST A PROCEDURE
HRLOI RF,1 ;THE VERY OUTER BLOCK
PUSHJ P,@SAILOR ;CALL USER PROGRAM
PUSHJ P,K.OUT ;WRITE OUT THE COUNTERS
TERPRI <
End of SAIL execution>
CALL6 (0,RESET) ;CLEAR THE I/O WORLD
CALL6 (1,EXIT) ;QUIT QUIETLY
SUBTTL .SEG2. -- Get a second segment
COMMENT ⊗ Initialize the second segment, if there is none and if desired.
This occurs when the program is first started. This is a dummy routine
if not a SAISEG-program
⊗
INTERNAL .SEG2.
.SEG2.:
LOW <
SKIPE JOBHRL ;IS THERE A SEGMENT?
>;LOW
JRST (P) ; YES, GO AHEAD (OR ALWAYS, IF NOLOW)
>;NOUP
LOW <
COMMENT ⊗ Now, if global model, get segment specifications from space blocks
of compiled programs (via REQUIRE verbs in source code).
Segment name business is ignored in EXPO version, since segment and file
names are always equivalent (philosophical differences).
⊗
SEGTR: ;TRY AGAIN
GLOB <
SKIPN %RENSW ;IS LINK-TABLE AND/OR PREVIOUSLY COLLECTED
; INFORMATION INVALID??
JRST SEG3 ;NO
FOR II IN (SEGDEV,SEGFIL,SEGPPN,NMSAV) <
SETZM II
>
JRST ASKEM ;CLEAR ALL NON-USER SPECIFIED INFO
SEG3: SKIPN B,SPLNEK ;A SPACE BLOCK AROUND??
JRST ASKEM ; NO
GSGLP: SKIPE A,$SGD(B) ;DEVICE REQUEST
MOVEM A,SEGDEV
SKIPE TEMP,$SGF(B) ;FILE NAME FOR UPPER SEGMENT
MOVEM TEMP,SEGFIL
SKIPE TEMP,$SGPP(B) ;PPN FOR SAME
MOVEM TEMP,SEGPPN
SKIPE TEMP,$SGNM(B) ;SEGMENT NAME (UNUSED IN EXPO VERSION)
MOVEM TEMP,NMSAV
SKIPE B,(B) ;GO DOWN LINKED LIST
JRST GSGLP ; UNTIL EMPTY
>;GLOB
COMMENT ⊗ If not enough information was supplied (global model only),
ask questions of user to obtain file names, etc. Also (NOEXPO only),
try to ATTSEG to a segment of the desired name. In the EXPO version,
all this is combined in the GETSEG below.
⊗
NOEXPO < ;SEGMENT NAME NOT USEFUL TO EXPO SYSTEM
GLOB <
SKIPE A,NMSAV ;DID WE GET A SEGMENT?
JRST GOTEM ; YES, TRY TO LINK TO IT
ASKEM: SPRINT <SEGMENT LOGICAL NAME?>
JSR GGNAM ;GET A SEGMENT NAME.
GOTEM: MOVEM A,NMSAV
>;GLOB
NOGLOB <
MOVE A,[FILXXX] ;TRY TO FIND IT.
>;NOGLOB
CALL6(A,ATTSEG) ;
SKIPA ;NO LUCK
JRST (P) ;OK, DONE
HRRZ B,A ;GET FAILURE CODE.
CAIE B,1 ;AMBIGUITY?
JRST GETSE ;NO -- GET THE SEGMENT.
HLRZS A
CALL6(A,ATTSEG) ;
JSP A,ERSEG
JRST (P) ;OK, GOT IT
>;NOEXPO
EXPO <
ASKEM: ;MISPLACED LABEL
>;EXPO
GETSE: CALL6(RESET)
GLOB <
SKIPE A,SEGFIL ;WAS ONE "REQUIRE"D?
JRST THSFL ; YES, USE IT
SPRINT <SEGMENT FILE NAME?>
MOVE A,[FILXXX] ;DEFAULT
JSR GGNAM
THSFL: MOVEM A,SEGFIL ;NAME OF SEGMENT.
THSFL1: SKIPE A,SEGDEV ;WAS A DEVICE REQUESTED?
JRST THSDV ; YES
SPRINT <DEVICE?>
MOVE A,[SGDEVC] ;DEFAULT DEVICE
JSR GGNAM
MOVEM A,SEGDEV
CAMN A,['DSK '] ;ASK FOR PPN IF DISK
SKIPE SEGPPN ;AND PPN=0
JRST THSDV ;DON'T ASK, ALREADY THERE
SPRINT <PPN?>
MOVE A,[SGPPNN] ;DEFAULT PPN
JSR GGNAM
MOVEM A,SEGPPN
JRST THSFL1 ;NOW HAVE A DEVICE
THSDV: MOVEM A,INTT
MOVE A,[XWD SEGDEV,DEVSEG] ;MOVE LOOKUP SPEC IN
BLT A,SEGNAM+3
>;GLOB
NOGLOB <
SETZM SEGNAM+2
MOVE TEMP,[SGPPNN]
MOVEM TEMP,SEGNAM+3 ;SET UP PPN
HLLZS SEGNAM+1
>;NOGLOB
COMMENT ⊗ Now work is nearly done in EXPO system, but all sorts of hair
remains otherwise. In either case, now get segment in, get it into 2d
segment, name it right
⊗
NOEXPO <
INIT 1,17
INTT: SGDEVC ;GO GET THE RAW SEGMENT
0
JSP A,ERSEG
LOOKUP 1,SEGNAM
JSP A,ERSEG
MOVS A,SEGNAM+3 ;WORD COUNT
HRLM A,LIOD ;WORD COUNT FOR DUMP MODE.
MOVNS A
HRRO D,JOBREL ;FOR LATER
HRRM D,LIOD ;PLACE TO START DUMP MODE INPUT.
ADD A,JOBREL ;TO GET THE AMOUNT OF CORE NEEDED.
CALL6 (A,CORE) ;CORE UUO ----
JSP A,ERSEG
LOP22: INPUT 1,[LIOD: 0
0]
GLOB <
TLZ D,-1 ;NO, MAKE IT WRITEABLE IF GLOBAL MODEL.
>;GLOB
IFN NOPROT,<
TLZ D,-1 ;MAKE WRITEABLE IF REQUESTED TO
>;NOPROT NEQ 0
CALL6 (D,REMAP) ;
;;%AO% DO SETPR2 TO AVOID LOSSAGE WHEN NO JOB SLOTS LEFT
NOGLOB <
JRST [ ;
CALL6(RESET) ;SINCE A RESET LATER MEANS DISASTER
PUUO 3,[ ASCIZ/
COULD NOT DO REMAP TO GET A SAIL SEGMENT!
SETPR2 DONE INSTEAD. YOUR JOB SHOULD BE HAPPY SO LONG AS
IT DOES NOT DO A RESET OR OTHER BADNESS. GOOD LUCK.
ALSO, IF YOU WANT TO RUN THIS WAY, BEWARE OF RESTARTING.
/] ;BETTER WARN THE POOR PEOPLE
ADDI D,2 ;MAKE EVEN K & MAKE IT REL MODE
MOVS A,SEGNAM+3;
MOVN A,A ;SIZE
ORI A,1777 ;PUTS TO K BNDRY & WRITE PROT
HRLI D,(A) ;
SETPR2 D, ;FAKE THE SEGMENT
JRST [ PUUO 3,[ASCIZ/
SETPR2 LOST, TOO!
/]
JRST 4,1(P)]
MOVE A,JOBREL; SINCE SAIL COMPILER IS DUMB
HRRM A,JOBFF ; SAFE NOW???
JRST 1(P) ;HURRAH -- RETURN
;DO 1(P) TO AVOID THE RESET
]
>;NOGLOB
GLOB <
JSP A,ERSEG ;GLOBAL CANNOT GET AWAY WITH SETPR2
>;GLOB
;;%AO%
NOGLOB <
MOVE A,[FILXXX]
>;NOGLOB
GLOB <
MOVE A,NMSAV
>;GLOB
CALL6 (A,SETNM2)
JRST [MOVEI A,0
CALL6 (A,CORE2) ;CORE2
JSP A,ERSEG
GLOB <
SETOM %RENSW ;FORCE TTY RITUAL
>;GLOB
JRST SEGTR] ;TRY AGAIN.
CALL6(RESET)
>;NOEXPO
EXPO <
SETZM SEGNAM+4 ;CLEAR LAST TWO WORDS OF GETSEG BLOCK
SETZM SEGNAM+5
MOVEI A,DEVSEG ;GET READY
MOVEM P,SAVPP
CALL6 (A,GETSEG) ;GET THE SEGMENT
JSP A,ERSEG ; COULDN'T
MOVE P,SAVPP
; NO WAY TO RENAME 2D SEGMENT, SO DON'T WORRY ABOUT IT
>;EXPO
JRST (P) ;RETURN
;NOTE: ALSO HAVE A JRST (P) IN
; THE CODE FOR FEAT %AL%
>;LOW
EXPO <
NOUP <
INTERNAL TYPER.,ERRMSG
;THESE ARE BECUSE OF LIB40 CHANGES
; MADE CAPRICIOUSLY BY DEC
TYPER.:
ERRMSG:
JFCL
ERR <SOME FORTRAN ROUTINE HAS SEEN FIT TO COMPLAIN
ABOUT YOUR STYLE. COMPLAIN TO DEC THAT THEIR ERROR MESSAGE
PROCEDURE IS NOT SUFFICIENTLY GENERAL TO ALLOW GRACEFUL INTERFACE
WITH SAIL.>
>;NOUP
>;EXPO
SUBTTL Segment-Fetching Data
LOW <
NMSAV: 0 ;SAVE LOGICAL SEGMENT NAME HERE
SEGDEV: 0 ;SAVE UPPER SEGMENT DEVICE NAME HERE
SEGFIL: 0 ;SAVE UPPER SEGMENT FILE NAME HERE
NOEXPO <
SIXBIT /SEG/ ;ALWAYS
>;NOEXPO
EXPO <
SIXBIT /SHR/ ;DIFFERENT STROKES FOR ....
>;EXPO
0
SEGPPN: 0 ;SAVE UPPER SEGMENT PPN HERE
DEVSEG: SGDEVC ;USED ONLY BY EXPO'S GETSEG
SEGNAM: FILXXX
NOEXPO <
SIXBIT/SEG/
>;NOEXPO
EXPO <
SIXBIT /SHR/
>;EXPO
0
SGPPNN ;SPECIFIED PPN DEFAULT
EXPO <
0
0 ;SIX WORD BLOCK FOR GETSEG
SAVPP: 0 ;P SAVED HERE OVER GETSEG
>;EXPO
ERSEG: SPRINT <SAIL SEGMENT LOADING ERROR
>
GLOB<
SETOM %RENSW ;FORCE TTY RITUAL
>;GLOB
CALL6 (EXIT)
GLOB <
GGNAM: 0
TTCALL 4,C ;INCHWL.
CAIE C,15 ;IF NOTHING SPECIFIED,
MOVEI A,0 ; USE THE DEFAULT
SKIPA B,[POINT 6,A]
GGGO: TTCALL C ;GET CHAR
CAIN C,15
JRST [TTCALL C
JRST @GGNAM] ;RETURN ON CR.
CAILE C,140
SUBI C,40 ;CONVERT LOWER CASE.
SUBI C,40 ; CNVRT TO SIXBIT
IDPB C,B ;SAVE IT.
JRST GGGO
>;GLOB
>;LOW
ENDCOM(LOR)
LOW <
END
>;LOW
COMPIL(LUP,<%UUOLNK,%ALLOC,SAVE,RESTR,STACSV,STACRS,INSET,USERERR,$PDLOV,.UINIT>
,<CORGET,STCLER,GOGTAB,CONFIG,%ALLCHR,CAT,STRNGC,K.ZERO>
,<INITIALIZATION ROUTINES, UUO HANDLER, UTILITY ROUTINES>)
IFE ALWAYS,<
INTERNAL %ALLOC,DT.RET
; MORE EXTERNALS
EXTERNAL ALLPDP,SETLET,INILNK,XJBENB
EXTERNAL SPLNEK,%OCTRET,%RECOV,%ERRC,%RENSW,%ERGO
EXTERNAL .DTRT.,.ERSTR,.ERSTP,.ERRP.,.ERRJ.
EXTERNAL X11,X22,X44,CORINC,%STDLS,%SPL,KTLNK
EXPO <
EXTERNAL PPMAX
>;EXPO
>;IFE ALWAYS
NOLOW < ;PUT IN UPPER SEGMENT AND ALL THAT FOLLOWS....
UP <
;IF YOU CHANGE ANYTHING ABOVE THIS POINT, YOU WILL
;HAVE TO RELOAD. THIS IS THE UPPER SEGMENT DISPATCH TABLE FOR
;INTERNAL SYMBOLS.
USE DSPCH ;A PC FOR VECTOR JRSTS
USE
BLOCK =260 ;SPACE FOR THE JRSTS.
>;UP
SUBTTL %ALLOC -- Main Allocation Routine
DSCR %ALLOC
CAL JSP 16,%ALLOC
DES Processes space reqests, allocates the storage for stacks,
string space, etc. Sets certain universal environmental variables
The SPLNEK list, created by the LOADER from compiled requests, contains
REQUEST blocks. Space requests begin at location $SPREQ within each
block. The entries consist of two-word entries, viz:
-----------------------------
-- SPLNEK ptr -- | | next block | ---
-----------------------------
| |
| fixed LEAP allocation |
| data |
| |
| ... |
-----------------------------
$SPREQ: |OP1 |INDX | SIZe request |
|- - - - - - - - - - - - - - -|
| TEXt addr | RESult ADdRess| (if ¬STDSPC --
----------------------------- see below)
|OP2 ... | etc. |
-----------------------------
| ... more ops ... |
-----------------------------
| 0 terminates |
-----------------------------
OP is a 12-bit field (0:11), whose bits are interpreted as:
0 STDSPC if 1, get TEX,RESADR spec from standard entry
indexed by INDX field -- this is only a 1-word wntry.
1 WNTADR requests that the address of the allocated core be
returned in the specified RESADR field. RESADR is
then incremented.
2 WNTEND requests that the address of the first word not in the
allocated area be placed in RESADR field. RESADR bumped.
3 WNTPDP requests that a PDP computed from address and length be
returned in like manner.
4 USRTB indicates that the RESADRs are indices into the user
table -- (GOGTAB) should be added before use.
5 MINSZ indicates that the size specified here should be REPLACED
by the first subsequent non-zero request (not ADDED).
Default value for this area -- anything overrides.
INDX is a 6-bit field (12:17) used if STDSPC to cause the address to be
obtained from a spec (with its own OP and addr words) built into GOGOL.
This allows push-down list, string space, etc., sizes to be requested by
object modules without knowing the locations of their descriptors.
The indices represent:
1 SYSPD System push-down list (P)
2 SYSSPD String push-down list (SP)
3 STRSP String space size.
SIZ replaces any previous request with MINSZ on. Otherwise, its value is
added to an accumulated size for this address. The final result will
specify the size of the area.
SIZ<0 causes current entry to be disregarded.
TEX is the address of an ASCIZ string describing the use of the area.
It is used when the user REENTERs to ask him how much space he wants.
A non-zero value means that no overriding is possible for this area.
These requests are accumulated on the stack in two-word entries as:
-----------------------------
$SPREQ: |OP1 |INDX | RESult ADdRess|
|- - - - - - - - - - - - - - -|
| TEXt addr | accum size |
-----------------------------
Inconsistencies in request bits are not likely to be detected.
%ALLOC first processes the entire list, collecting cumulative information
about each RESADR requested, summing the size requests (with mods as
described for MINSZ above). Then it allocates space for each requested
area, allowing the user to override each if he REENTERed, and if there
is TEXt for that area. It finishes by performing some useful but
uninteresting bookkeeping.
⊗
; Get a Stack to hold requests in
HERE (%ALLOC)
MOVEI C,MINPDS ;ABOUT 64 WORDS
PUSHJ P,CORGET ;THIS USUALLY INITS THE USER TABLE
ERR <NO CORE FOR ALLOCATION>
PUSHJ P,PDPMAK ;A PUSH-DOWN POINTER
MOVE P,B ;DITCH THE ALLOC PDL
MOVEM B,PDL(USER) ;STORE TEMPORARILY
PUSH P,16 ;THE RETURN ADDRESS
ADD P,X22 ;ONE DUMMY ENTRY TO TERMINATE
SETZM -1(P) ;0 TERMINATES IT
; Loop to search the space request blocks
; Until further notice:
; T is ptr to next allocation block.
; T1 is ptr to next entry specification
; Q1 is modified T1 -- accounts for STDSPC specifications
; Q2 is incoming OP-size word
; A is ptr to next candidate stack list element
; Q3 and TEMP used to do RESADR search in already-requested stack list
MOVE T,SPLNEK ;LIST OF BLOCKS
MOVEM T,%SPL ;LINK BUILT-IN BLOCK EXPLICITLY
MOVEI T,%SPL ;ALLOCATE IT FIRST
%AL1: MOVEI T1,$SPREQ(T) ;PTR TO FIRST REQUEST
%AL2: SKIPN Q2,(T1) ;OP WORD
JRST NXTELT ;NO MORE THIS BLOCK
MOVE Q1,T1 ;SAVE ADDRESS OF REQUEST
TLNN Q2,STDSPC ;A BUILT-IN RESADR/TEXT?
AOJA T1,DRCT ; NO, GET IT HERE
; T1 incremented because 2-word entry -- Q1 still pnts to 1st word
; Here, there is only a 1-word entry -- the actual RESADR spec
; found by indexing into table.
LDB Q1,[POINT 6,Q2,17] ;THE INDEX
LSH Q1,1 ;2-WORD ENTRIES ALL
ADDI Q1,%STDLST ;HERE'S WHERE THEY LIVE
HLL Q2,(Q1) ;USE STANDARD BITS FROM HERE ON
TLZ Q2,MINSZ ;NEVER USED FOR MIN WHEN BY INDEX
; Now find the corresponding entry in the accumulated stack entries
; or add a new entry
DRCT: HRRZ Q3,1(Q1) ;ADDRESS OF RESULT
TLZE Q2,USRTB ;RESULT IN THE USER TABLE?
ADD Q3,GOGTAB ;YES
MOVEI A,-1(P) ;FOR SEARCH DOWN STACK
JRST %AL4 ;GO SEARCH
%AL3: CAIN Q3,(TEMP) ;SAME ADDR?
JRST %AL5 ;YES, UPDATE
SUBI A,2 ;BACK UP ONE
%AL4: SKIPE TEMP,(A) ;NEXT SAVED OP WORD
JRST %AL3 ;TRY THIS ONE
; First occurrence of this address, make a place for it
MOVEI A,1(P) ;BACK TO THE TOP
ADD P,X22 ;NEW ENTRY
SETZM (A)
SETZM 1(A) ;VIRGIN ENTRY
COMMENT ⊗
NMIN means MINSZ on in new spec, OMIN means it's on in stack spec
NSIZ mean that new size NEQ 0, OSIZ etc. -- then
NMIN and not OSIZ then OSIZ←NSIZ, OMIN←TRUE
NMIN and OSIZ then no change
not NMIN and NSIZ and OMIN then OSIZ←NSIZ, OMIN←FALSE
not NMIN and not NSIZ and OMIN then no change
not NMIN and not OMIN then OSIZ←NSIZ+OSIZ, OMIN←FALSE
In the sequel,
A pnts to current stack entry, T,T1,Q1 unchanged,
Q2 is NEWSIZ, will be accum SIZ and TEXt addr.
Q3 is NEWBITS,,RESADR, will be accumulated same.
TEMP will be old TEX,,SIZ word, LPSA old BITS,,ADR
⊗
%AL5: HLL Q3,Q2 ;NEW BITS,,RESADR
HRRES Q2 ;NEW SIZE
MOVE TEMP,1(A) ;OLD TEX,,SIZ
MOVE LPSA,(A) ;OLD BITS,,ADR
JUMPL Q2,AOJBAK ;NO ACTION ON NEGATIVE SIZE
TLNE Q3,MINSZ ;BEGIN THE HAIRY CASE STUDY
JRST INMIN ;MIN ON IN NEW
; ¬NMIN
TLZN LPSA,MINSZ ;¬NMIN, OMIN? -- OMIN←FALSE
JRST ADDIT ;not NMIN and not OMIN, ADD
JUMPN Q2,%AL6 ;not NMIN and OMIN, NSIZ?
TLOA Q3,MINSZ ;not NMIN and OMIN and not NSIZ,
; NMIN←TRUE, NSIZ+OSIZ=OSIZ
%AL6: HLLZS TEMP ;not NMIN and OMIN and NSIZ,
; OSIZ←FALSE,NSIZ+OSIZ=NSIZ,NMIN←FALSE
JRST ADDIT ;not NMIN and OMIN, EITHER NSIZ OR OSIZ
; NMIN
INMIN: TRNE TEMP,-1 ;OSIZ?
TLZA Q3,MINSZ ;NMIN and OSIZ, OSIZ unchg, NMIN←FALSE
TLZA LPSA,MINSZ ;NMIN and not OSIZ, OSIZ←NSIZ, NMIN←TRUE
MOVEI Q2,0 ;NMIN and OSIZ again, OSIZ unchg over add
ADDIT: OR Q3,LPSA ;COLLECT BITS
ADD Q2,TEMP ;AND SIZE
TLNN Q2,-1 ;ANY TEXT ADDR?
HLL Q2,1(Q1) ;NO, GET FROM OLD IF ANY
MOVEM Q3,(A) ;PUT NEW AWAY
MOVEM Q2,1(A)
AOJBAK: AOJA T1,%AL2 ;NEXT ELEMENT THIS BLOCK
NXTELT: SKIPN T,(T) ;NEXT BLOCK IN ALLOC LIST?
JRST NOELT ;NO MORE.
LEP <
;; %AG% .! LEAPIS USED TO BE STORED IN $ITNO
SKIPL $GITNO(T) ;LEAP REQUESTED?
JRST %AL1 ;NO.
MOVE B,GOGTAB ;WILL PLAY WITH USER TABLE
SETOM HASMSK(B) ;SOMEONE WANTS LEAP.
>;LEP
JRST %AL1 ;CONTINUE DOWN ALLOC BLOCKS.
NOELT:
; SINCE SYSTEM!PDL ALREADY ALLOCATED AND IN USE, INCREMENT IT IF THE
; REQUEST EXCEEDS THE DEFAULT
MOVE TEMP,PDL(USER)
PUSH P,4(TEMP)
PUSH P,5(TEMP) ;MAKE SURE P-REQUEST ON TOP
SETZM 4(TEMP) ;AND THAT IT DOESN'T HAPPEN TWICE
; NOW ALLOCATE THE SPACES, GET OVERRIDES
SETZM %ALLCHR ;NO QUESTIONS YET
SKIPN %RENSW ;WAS THERE A REENTER?
JRST NONTR ; NO
TERPRI
PRINT <ALLOC? >
PUUO 0,B ;ASK LEADING QUESTION AND GET ANSWER
TERPRI
;; %AD% RHT ALLOW LOWER CASE 10/4/73
TRZ B,40 ; SO CAN USE LOWER CASE
CAIN B,"Y" ;YES?
SETOM %ALLCHR ;YES
CAIN B,"N" ;NO, BUT LET ME SEE IT?
AOS %ALLCHR ;RIGHT
SETZM %OCTRET ;WHEN ON, NO MORE ASKING
NONTR:
ALOC: SKIPN T,-1(P) ;WERE THERE ANY ENTRIES?
JRST DONEE ; MAYBE, BUT NONE LEFT
MOVS A,(P) ;SIZE, TEXT
TRNE A,-1
SKIPL %ALLCHR ;IF TEXT ADDR AND WANTS TO DO IT,
JRST NOASK ; MUST ASK QUESTIONS
PUUO 3,(A) ;PRINT IT
;;% % DCS 12-1-73 (1-3) Enhance behavior of ALLOC sequence.
PRINT < (>
HLRZ C,A ;DEFAULT (+"REQUIRE"d) VALUE
DECPNT C ; "SYSTEM PDL (64) = "
PRINT <) = >
;;% % (1-3)
PUSHJ P,DECIN
HRL A,C ;REPLACE REQUESTED SIZE BY OVERRIDE
NOASK: HLRZ C,A ;IN CASE NOBODY ELSE DID
JUMPE C,PRIN ;DON'T ALLOCATE 0 AREAS
HRRZ TEMP,T ;DEST ADDR
CAIE TEMP,PDL(USER) ;THE ONE AND ONLY?
JRST NOEXP ; NO
;THIS IS THE SYSTEM!PDL REQUEST -- IT MUST OVERLAY THE CURRENTLY
; ALLOCATED STACK
HRRZ B,PDL(USER) ;GET PREV INITIAL CORGET ADDRESS
CAIGE C,MINPDS ;MUST BE BIGGER
MOVEI C,MINPDS ; SO MAKE IT BIGGER
HRL A,C ;KEEP EVERYBODY UP TO DATE
ADDI B,1 ;CORGET ADDR
CAIG C,MINPDS
JRST PDPRET ;NO PROBLEM
SUBI C,MINPDS ;AMOUNT TO INCREASE BY
;;# # 4-28-72 DCS UPDATE P'S SIZE FIELD
HRLZ TEMP,C ;UPDATE P RIGHT NOW
SUB P,TEMP ;SIZE FIELD ONLY
;;# # 4-28
PUSHJ P,CORINC ;INCREMENT TO PROPER SIZE
ERR <DRYROT -- NO CORE FOR SYSTEM!PDL>
ADDI C,MINPDS ;TOTAL SIZE
JRST PDPRET
NOEXP: PUSHJ P,CORGET ;GET A BLOCK
ERR <NO CORE AT ALLOCATION>
PDPRET: TLNN T,WNTADR ;WANT THE ADDRESS STORED?
JRST .+3
MOVEM B,(T) ;YES, STORE IT
ADDI T,1
TLNN T,WNTEND
JRST NOND
MOVE D,C ;SIZE
ADD D,B ;END ADDR
MOVEM D,(T)
ADDI T,1
NOND: PUSHJ P,PDPMAK
TLNE T,WNTPDP
MOVEM B,(T) ;WANTS PDP
PRIN:
;;% %.! DCS 12-1-73 (2-3) Enhance behavior of ALLOC Sequence.
;; Removed size printing code from here, moved it to (1-3) above
SUBJMP: SUB P,X22 ;SO MUCH FOR THAT ONE
JRST ALOC ;GET THE NEXT
DONEE: SKIPN %ALLCHR ;BLABBING?
JRST .+3 ; NO
TERPRI
TERPRI
SUB P,X44 ;PNT TO RETURN ADDRESS (DUMMY AND SYSPDL ENTRIES)
; FINAL BOOKKEEPING
SETZM %RENSW ;DON'T ASK EACH TIME
MOVE SP,SPDL(USER) ;STRING STACK POINTER
;;% % DCS 12-1-73 (1-1) New String Garbage Collector -- New initialization
MOVEI A,4 ;Update ST(USER) to include a .HDRSIZ-word
ADDB A,ST(USER) ; header, preceding ST(USER). Call new addr. "SPC".
HRLI A,(<POINT 7,0>) ;USER TABLE ENTRIES:
MOVEM A,TOPBYTE(USER) ; TOPBYTE ← POINT 7,SPC
HRRZM A,STLIST(USER) ; STLIST ← SPC
MOVE B,STTOP(USER) ; STINCR ← size(SPC)*5,,size(SPC)+.HDRSIZ
MOVEM B,.STTOP(A) ; STREQD ← size(SPC)/8*5,,size(SPC)/8
SUBI B,(A) ; REMCHR ← -(size(SPC)*5)+=15
MOVEM B,.SIZE(A) ;SPC's header entries:
SETZM .LIST(A) ; .LIST ← .NEXT ← 0
SETZM .NEXT(A) ; .SIZE ← size(SPC) (STTOP-new ST)
MOVEI TEMP,.HDRSIZ(B) ; .STTOP ← STTOP(USER)
HRRM TEMP,STINCR(USER)
LSH TEMP,-3
HRRM TEMP,STREQD(USER)
IMULI TEMP,5
HRLM TEMP,STREQD(USER)
IMULI B,5
HRLM B,STINCR(USER)
SUBI B,=15
MOVNM B,REMCHR(USER)
;;% % (1-1)
SKIPE CONFIG ;COMPILER?
SETOM SGLIGN(USER) ; YES, STRNGC AND FRIENDS MUST ALIGN STRINGS
HRROI TEMP,KTLNK
POP TEMP,KNTLNK(USER)
POP TEMP,SGROUT(USER)
POP TEMP,SETLNK(USER)
POP TEMP,SPLNK(USER)
POP TEMP,STRLNK(USER);TRANSFER LISTS TO USER TABLE
PUSHJ P,STCLER ;CLEAR OUT ALL STRINGS
MOVEI TEMP,7 ;INITIAL DIGS SETTING
MOVEM TEMP,DIGS(USER) ;FOR FLOATING POINT OUTPUT
MOVEI TEMP,CHANS(USER);IF CHNL HAS A VALID CHANNEL #,
HRLI TEMP,CHNL ; @CDBLOC(USER) REFERS TO ITS
MOVEM TEMP,CDBLOC(USER);CDB ADDR IN THE CHANS TABLE
SETZM XJBENB ; WHERE APR INTERRUPT ENABLINGS ARE REMEMBERED
SETZM %ERGO ;REINITIALIZE ERROR PRINTER
;;#HE# DCS 5-11-72 (2-2) MODIFY VERSION CHECKING, STORAGE METHODS
IFNDEF JOBVER,<EXTERNAL JOBVER>
MOVEI LPSA,SPLNEK ;For each element of the space
CHKVRS: SKIPN LPSA,(LPSA) ; list, if there is a non-zero
JRST ENDINT ; version request, use it (lh is
SKIPN TEMP,$VRNO(LPSA); SAIL version, rh is user version).
JRST CHKVRS ;But if there was a previous non-zero
HLL TEMP,JOBVER ; request, and if it is not the
EXCH TEMP,JOBVER ; same as this one, complain first.
TRNE TEMP,-1
CAMN TEMP,JOBVER
JRST CHKVRS
ERR <VERSION NUMBER MISMATCH>,1
JRST CHKVRS
;;#HE# (2-2)
ENDINT: PUSHJ P,K.ZERO ;NZERO OUT THE COUNTERS
INILST:
SKIPN TEMP,INILNK
POPJ P,
MOVE USER,GOGTAB ;JUST TO BE SURE
SKIPA A,[XWD -SYSPHS,0] ;XWD #SYS PHASES,0
DOPHS: HRRZ TEMP,INILNK ;LIST OF THEM
NXLNK:
PUSH P,TEMP ;SAVE LINK
NXIN: ADDI TEMP,1 ;LOOK AT NNEXT ENTRY
SKIPN B,(TEMP) ;END OF LINK LIST
JRST NXIN.1 ;YES
HLRZ C,B ;PHASE NUMBER OF THIS
CAIE C,(A) ;THIS PHASE
JRST NXIN ;NO
PUSH P,A
PUSH P,TEMP
PUSH P,USER
PUSHJ P,(B)
POP P,USER
POP P,TEMP
POP P,A
JRST NXIN ;GO DO NEXT IN THIS
NXIN.1: POP P,TEMP
HRRZ TEMP,(TEMP)
JUMPN TEMP,NXLNK
NXPHS: AOBJN A,DOPHS ;GO ON TO NEXT PHASE
POPJ P, ;
HERE(.UINIT)
MOVE A,[XWD -USRPHS,400000] ;DO USER PHASES
;; #KV# MAKE SURE LINK NON-NULL
SKIPN INILNK
POPJ P,
;; #KV#
JRST DOPHS
PDPMAK: MOVNS C
SUBI B,1 ;PDP
HRL B,C
POPJ P,
>;NOLOW
COMMENT ⊗ Utility Subroutines for allocation
⊗
DECIN:
OCTIN: AOS (P)
SKIPE %OCTRET ;IMMEDIATE RETURN?
POPJ P, ; YES
SETZB C,D
;;% % DCS 12-1-73 (3-3) Enhance behavior of ALLOC sequence
;; Use line mode input, remove inferior line-editing code.
OCTIN1: PUUO 4,B ; ;; INCHWL, was 0,B (INCHRW)
;; Removed rubout, ctrlo check
;;!HOOK! May need to put some back in for TENEX
CAIN B,175 ;ALTMODE?
JRST SETRET
CAIN B,12 ;LINE FEED?
JRST EPOP ;YES
CAIL B,"0"
CAILE B,"9" ;I KNOW IT'S CALLED OCTIN,
JRST OCTIN1 ; BUT INPUT IS IN DECIMAL!!
SETOM D ;FOUND SOMETHING LIKE A NUMBER
IMULI C,=10 ;GOOD OLD NUMBER CONVERSION
ADDI C,-"0"(B)
JRST OCTIN1 ;THIS IS A LOOP
SETRET: SETOM %OCTRET ;WILL RETURN IMMEDIATELY HENCEFORTH
TERPRI
EPOP: SKIPE D ;FIND ANYTHING?
SOS (P) ;YES
CPOPJ: POPJ P,
;; Removed rubout, ctrlo code from here
;;% % (3-3)
SUBTTL %UUOLNK -- UUO Handler (Dispatch Vector Just Below)
NOLOW < ;INCLUDE IN UPPER SEGMENT.....
HERE(%UUOLNK)
UUOCON: PUSH P,FF ;SAVE REGISTER 0
PUSH P,A ;AND REGISTER 1
MOVE FF,@JOBUUO ;ARGUMENT BEFORE CLOBBERING AC'S
LDB A,[POINT 9,JOBUUO,8] ;GET OP CODE.
; TRNE A,777760 ;SEE IF IN RANGE
; JRST ILLUUO ;ILLEGAL
JRST @UUOTBL(A) ;DISPATCH TO CORRECT ROUTINE.
RETM: POP P,D ;RESTORE SAVED AC'S
POP P,C
POP P,B
USRXIT: POP P,A
POP P,FF ;RESTORED AC'S
POPJ P, ;AND RETURN!
SAVM: PUSH P,B ;SAVE AC'S -- CALLED WITH JSP 0
PUSH P,C
PUSH P,D ;ENUF
PUSH P,[RETM]
JRST @FF ;RETURN
; UUO TABLE
UUOTBL: JRST ILLUUO ;0
JRST ILLUUO ;1
JRST FLOAQ ;2 -- FLOAT A NUMBER
JRST FIXQ ;3 -- FIX A NUMBER
JRST IOERRR ;4 -- I/O ERROR
JRST ERRR ;5 -- STANDARD ERROR UUO
JRST PSIXQ ;6 -- SIXBIT PRINT
JRST ARERRR ;7 -- ARRAY ERROR
JRST ILLUUO ;10
JRST DECPNQ ;11 -- PRINT DECIMAL NUMBER
JRST OCTPNQ ;12 -- PRINT OCTAL NUMBER
JRST ILLUUO ;13
JRST ILLUUO ;14
JRST PRINIT ;15 -- HANDLE TERMINAL
HERE($PDLOV) ;PLACE TO COME WHEN A STACK
MOVEI TEMP,TEMP ;IS EXHAUSTED.
POP TEMP,TEMP ;THIS WILL CAUSE PDLOV
JRST (USER) ;RETURN IF USER CAN.
DSCR OCTPNT, DECPNT UUO'S
PAR MOVE FF,ARG; JRST OCTPNQ -- RET VIA USRXIT
OR MOVE A,ARG; PUSHJ P,OCTO
RES DECPNT -- WORD TYPED IN DECIMAL
OCTPNT -- OCTAL
⊗
OCTPNQ: MOVE A,FF ;GET ARGUMENT
JSP FF,SAVM ;SAVE MORE AC'S
OCTO: SKIPA C,[PUUO 1,B]
OCTOB: MOVE C,[IDPB B,.ERSTP]
MOVEI FF,10 ;KEEP RADIX IN FF.
JRST PNT
DECPNQ: MOVE A,FF ;GET ARGUMENT
JSP FF,SAVM
DECO: SKIPA C,[PUUO 1,B]
DECOB: MOVE C,[IDPB B,.ERSTP]
MOVEI FF,=10
JUMPGE A,PNT ; GREATER 0.
MOVEI B,"-"
XCT C
MOVMS A ; FOO1 ← ABS(FOO1) ;
PNT: IDIV A,FF ;FAMOUS DEC RECURSIVE NUMBER PRINTER.
IORI B,"0"
HRLM B,(P)
SKIPE A
PUSHJ P,PNT
HLRZ B,(P)
XCT C ;EITHER PRINT IT OR STORE IT
POPJ P, ;RETURN TO RETM
DSCR FIX, FLOAT UUO'S (FIXQ,FLOAQ)
PAR MOVE FF,ARG ; JRST FIX/FLOA Q; RET VIA USRXIT
RES FIXED POINT EQUIVALENT IN AC SPECIFIED IN AC FIELD OF UUO
⊗
FIXQ: MULI FF,400 ;THIS ALGORITHM STOLEN FROM F4.
TSC FF,FF
EXCH FF,A
ASH FF,-243(A)
JRST FXFLT ;STORE IN RIGHT PLACE.
FLOAQ: IDIVI FF,400000
SKIPE FF
TLC FF,254000
TLC A,233000
FAD FF,A
FXFLT: LDB A,[POINT 4,JOBUUO,12] ;RESULT REGISTER
CAIG A,1 ;NUMBER OF AC'S SAVED
ADDI A,-1(P) ;ADJUST TO FIND STACK SPOT
MOVEM FF,(A) ;AND RETURN RESULT
JRST USRXIT ;AND RETURN TO USER
DSCR PRINIT -- INTERFACE TO SYSTEM PRINTING FACILITIES
INCLUDED HERE TO MAKE INTERCEPTION EASY FOR WHATEVER
PURPOSE AND TO MAKE CONVERSION TO TENEX EASY
⊗
PRINIT: ;IF NOT ASSEMBLED, FALL INTO ILLUUO
IFN 0,<
MOVE A,FF ;SAVE ARGUMENT
JSP FF,SAVM ;GET MORE AC'S
LDB C,[POINT 4,JOBUUO,12]
JRST @PTBL(C)
PTBL: GCH ;0 -- GET A CHAR
PCH ;1 -- PRINT A CHAR
0
PST ;3 -- PRINT A STRING
PST: TTCALL 3,@JOBUUO ;CALL SYSTEM
POPJ P,
PCH: TTCALL 1,A ;PRINT CHAR
POPJ P,
GCH: HRRZ B,JOBUUO ;GET EFF ADDRESS
CAIG B,D
ADDI B,-5(P) ;RELOCATE INTO STACK.
TTCALL 0,(B) ;AND READ A CHAR
POPJ P,
>
DSCR ERROR UUOS
PAR AC FIELD IS INDEX INTO ERROR ROUTINE
SID SAVES THE WORLD
DES THE ASCIZ STRING INDICATED BY THE EFFECTIVE ADDRESS IS TYPED. THEN
THE ERROR ROUTINE INDICATED BY THE AC FIELD IS EXECUTED.
IF `GO' IS NOT ON, THE USER IS ALLOWED TO RESPOND WITH ONE OF SEVERAL
ALTERNATIVES. ONE ALTERNATIVE IS CONTINUATION IF THE AC FIELD OF THE
UUO WAS ODD. OTHERWISE, NO CONTINUATION IS POSSIBLE. THE ACS AT THE
TIME OF CALL ARE RESTORED IF CONTINUATION OR `DDT' IS CHOSEN.
⊗
ILLUUO: MOVE A,[ERR <Illegal UUO>]
MOVEM A,JOBUUO
ERRR: JSP FF,SAVM ;SAVE MORE AC'S
LDB B,[POINT 4,JOBUUO,12] ;CODE IN AC FIELD
JRST ERRW
ARERRR: JSP FF,SAVM ;SAVE MORE AC'S
MOVSI D,4 ;PRINTING INSTRUCTIONS
MOVEI B,20 ;ERROR CODE -- FATAL
JRST ERRX
IOERRR: JSP FF,SAVM ;SAVE MORE AC'S
MOVEI B,16 ;ERROR CODE -- FATAL
ERRW: MOVEI D,0
ERRX: ROT B,-1 ;CONTINUE BIT TO SIGN BIT
MOVEM B,%RECOV ;AND SAVE FOR TESTING LATER
MOVE C,-6(P) ;RETURN ADDRESS
MOVEM C,.DTRT. ;SAVE AS DDT RETURN ADDRESS
MOVE C,[POINT 7,.ERSTR] ;POINTER TO ERROR STRING.
MOVEM C,.ERSTP
MOVEI A,[BYTE(7) 15,12,0]
PUSHJ P,PRA ;BEGIN EACH ERROR MESSAGE WITH CRLF.
MOVE A,JOBUUO ;GET UUO BACK
TLZN D,4 ;DO NOT PRINT EFF ADDR OF ARRAY UUO
PUSHJ P,PRA ;PRINT ACSIZ STRING INTO ERSTR
MOVE A,JOBUUO
PUSHJ P,@URTBL(B) ;AND DO SPECIAL-CASE STUFF
MOVEI A,[BYTE(7) 15,12,0]
PUSHJ P,PRA ;TERMINATE WITH CRLF
IDPB FF,.ERSTP ;AND A ZERO.
;#PU# ACCUMULATOR D WAS NOT ZERO FOR ORDINARY ERRORS.
SKIPE D,%ERRC ;IF USERRR LEFT A POINTER
JRST [MOVE D,1(D) ;GET BYTE POINTER
ILDB D,D ;GET FIRST RESPONSE CHARACTER
JRST .+1]
SKIPN .ERRP. ;DOES USER HAVE A ROUTINE?
JRST NOUSRR ;NO
MOVE C,[XWD D-15,D+1] ;AOBJN POINTER TO DO PUSHES
PUSH P,(C) ;PUSHES WILL CAUSE PDLOV
AOBJN C,.-1 ;COUNT DOWN
;CAN BLT OFF
MOVE USER,GOGTAB
MOVE C,[XWD -13,RACS] ;ALSO SAVE RUNTIME AC'S
ADDI C,(USER) ;RELOCATE
PUSH P,(C)
AOBJN C,.-1
PUSH P,UUO1(USER) ;SAVE RUNTIME RETURN ADDRESS
SETZM .ERRJ. ;ASSUME NO USER TRANSFER ADDRESS
MOVE A,-33(P) ;UUO RETURN ADDRESS
SUBI A,1
PUSH P,SP ;SAVE STRING STACK POINTER (OR,
;IF COMPILER, MAYBE PARSER STACK)
SKIPL CONFIG ;IF IN COMPILER, GENERATE
JRST .+4
MOVEI SP,(P) ;A FAKE STACK BECAUSE OF CONFLICT
HRLI SP,-5 ;WITH PARSE STACK
ADD P,X44
PUSH P,A ;ADDR OF UUO = ARG TO PROC.
HRRZ A,.ERSTP ;NOW COMPUTE LENGTH OF STRING
SUBI A,.ERSTR ;SAVED AWAY
IMULI A,5
LDB B,[POINT 6,.ERSTP,5]
IDIVI B,7
MOVN B,B
ADDI A,4(B) ;TOTAL NUMBER OF CHARACTERS (NOT INCL NULL)
PUSH SP,A ;TO STRING STACK.
PUSH SP,[POINT 7,.ERSTR]
SKIPN A,%ERRC ;TRACKS LEFT BY USERRR??
MOVEI A,[0
0] ;NO
PUSH SP,(A)
PUSH SP,1(A)
PUSHJ P,@.ERRP.
SKIPGE CONFIG ;IF IN COMPILER, THEN
SUB P,X44 ;BACK UP THE STACK.
POP P,SP ;RESTORE STRING STACK.
MOVE USER,GOGTAB
POP P,UUO1(USER) ;RESTORE THINGS
MOVEI B,12
MOVEI C,RACS+12(USER)
POP P,(C)
SUBI C,1
SOJGE B,.-2 ;TILL DONE
HRLZI FF,D+1-15(P) ;FROM HERE ON STACK
HRRI FF,D+1 ;FIRST AC TO RESTORE
BLT FF,15 ;GET THEM BACK
SUB P,[XWD 15-D,15-D] ;ADJUST
MOVEM A,D ;SAVE PRINTING INSTRUCTIONS
SKIPE B,.ERRJ. ;IF USER SPECIFIED RETURN ADDRESS
MOVEM B,-6(P) ;REPLACE CURRENT ONE.
NOUSRR:
TLZN D,1 ;IF NOT INHIBITED,
PUUO 3,.ERSTR ;PRINT ERROR STRING.
MOVE A,-6(P) ;RETURN ADDRESS
TLZN D,2 ;IF NOT INHIBITED,
PUSHJ P,CALLEDFROM ;PRINT SAIL MESSAGE
SETZM %ERRC ;NO MORE USERRR SPEC.
PUSHJ P,WATNOW ;GO GET A RESPONSE.
MOVEM A,-6(P) ;REPLACE RETURN ADDRESS
POPJ P,
HERE(DT.RET) ;JRST HERE TO GET BACK FROM DDT
JRST @.DTRT. ;GONE.
DSCR CALLEDFROM -- PRINTS 'CALLED FROM' XXX 'LAST SAIL CALL AT'
PAR WHERE XXX+1 IS PRESENTED IN AC A.
RES -- ONLY TYPING
SID DESTROYS A,B,C
⊗
CALLEDFROM:
PRINT <Called from >
MOVEI A,-1(A)
PUSHJ P,OCTO ;PRINT IT IN OCTAL
SKIPGE CONFIG ;RUNTIMES
JRST NOLSCL
PRINT < Last SAIL call at >
MOVE A,GOGTAB
HRRZ A,UUO1(A)
SOS A
PUSHJ P,OCTO
NOLSCL: TERPRI
POPJ P, ;END OF CALLEDFROM ROUTINE.
DSCR WATNOW -- ROUTINE TO GET AND PROCESS USER RESPONSES.
PAR RECOV IS >0 IF RECOVERY IMPOSSIBLE, <0 IF RECOVERY POSSIBLE
D,IF NON ZERO, HAS A RESPONSE CHARACTER IN IT.
RES RETURNS TO CALLER+1 IF TO GO TO DDT OR EXIT. IN THIS
CASE, AC 'A' HAS A NEW RETURN ADDRESS
RETURNS TO CALLER+2 IF USER SAID 'CONTINUE'
SID CLOBBERS FF,A
⊗
WATNOW: MOVE A,GOGTAB ;ADDRESS OF USER TABLE
HRRZ FF,TOPBYTE(A) ;CURRENT STRING POINTER
CAMLE FF,STTOP(A) ;IN RANGE?
JRST [TERPRI <String space exhausted unexpectedly.
Will restart now.>
MOVEI FF,[JRST @JOBREN]
MOVEM FF,-7(P) ;NEW RETURN ADDRESS.
JRST .+1]
SKIPE %ERGO ;CONTINUOUS CONTINUE?
JRST GOTRY ;AUTOMATIC CONTINUE SET
SKIPE A,D ;IF A RESPONSE CHARACTER IS SPECIFIED,
JRST RESGOT ;GO USE IT.
QUES: PUUO 2,A ;INCHRS
JRST PRMPT ;NO CHARACTER -- PROMPT
PUUO 11,0 ;CLEAR INPUT BUFFER
CAIN A,12 ;IF FEED, USE IT
JRST RESGOT ;CAN ONLY TYPE AHEAD LF.
PRMPT: MOVEI A,"?" ;PRINT ? FOR IRRECOVERABLE ERRORS,
SKIPGE %RECOV ; ↑ FOR RECOVERABLE ONES.
MOVEI A,"↑" ;SOMETHING PRINTABLE.
PUUO 1,A ;PRINT IT
PUUO 0,A ;GET RESPONSE CHAR
CAIN A,15 ;IF RESPONSE CR, THEN
PUUO 2,FF ; INCHRS
JFCL ; DON'T DO INCHRW HERE BECAUSE OF PTY'S
RESGOT: CAIL A,"a" ;lower case?
SUBI A,40 ;YES, CONVERT TO UPPER
CAIN A,"E" ;RE-EDIT?
JRST EDIT ; YES
CAIN A,"T" ;TVEDIT?
JRST TVEDIT
CAIN A,"S" ;START?
JRST STRTIT ;YES
CAIN A,"X" ;EXIT
JRST XIT
CAIN A,"D" ;DDT
JRST DDIT ;.
CAIE A,"A"
CAIN A,12 ;CONTINUE AUTOMATISCH?
SETOM %ERGO ;YES
CAIN A,"C" ;CONTINUE AT ALL COSTS?
JRST EPOPJ ;YES -- SKIP RETURN.
CAILE A,15 ;TRY TO CONTINUE?
JRST BADRSP ;INCORRECT RESPONSE
GOTRY: SKIPGE %RECOV ;CAN WE CONTINUE?
JRST EPOPJ ;YES -- SKIP RETURN
TERPRI <Can't continue>
JRST QUES
STRTIT: HRRZ A,JOBSA
JRST (A) ;AWAY WE GO!
DDIT: SKIPN JOBDDT
JRST [TERPRI <No DDT>
JRST QUES] ;NO SUCH ANIMAL
SKIPA A,[[JRST @JOBDDT]] ;PREPARE TO CALL DDT
XIT: MOVEI A,[CALL6 (EXIT)] ;PREPARE TO EXIT
POPJ P, ;NON SKIP RETURN.
EPOPJ: AOS (P) ;SKIP RETURN
POPJ P,
BADRSP: TERPRI <Reply [CR] to continue,
[LF] to continue automatically,
"D" for DDT, "E" to edit,
"X" to exit, "S" to restart>
JRST QUES ;GET ANOTHER RESPONSE.
SUBTTL Special Printing Routines For Error Handler
DSCR UUO ERROR MESSAGE ROUTINES AND THEIR INDICES (AC FIELD OF UUO)
SID CLOBBERS A,B,C,D
⊗
↑↑URTBL:UPOPJ ; 0- 1 -- NO ACTION
.PRSM ; 2- 3 -- PRINT SYMBOL PTD TO BY LPSA (SAIL)
PRASC ; 4- 5 -- PRINT SYMBOL PTD TO BY UUO INSTR
ACPRT ; 6- 7 -- PRNT VAL OF AC IN INSTR PRECDNG UUO
UUOPRT ;10-11 -- PRINT THE UUO
AC1PRT ;12-13 -- PRINT AC FIELD ASSUMING RETURN FROM
; CALL IS IN UUO1(GOGTAB)
SIXPRT ;14-15 --PRINT LPSA AS SIXBIT
IOER2 ;16-17 --SECOND HALF OF IOERR
ARER2 ;20-21 --SECOND HALF OF ARRERR
UUOPRT: PUSH P,A ;SAVE UUO
HLRZ A,A
PUSHJ P,OCTOB ;TYPE IT
POP P,A ;RESTORE
HRRZS A
JRST OCTOB ;TYPE IT TOO
DSCR PRSYM -- PRINT SYMBOL NAME
PAR SAIL SEMANTICS BLOCK ADDRESS IN LPSA
RES TYPES $PNAME STRING FROM BLOCK
SID DESTROYS A,B
⊗
$PNAME ←← 1
.PRSM: HRRI A,$PNAME(LPSA) ;PTR TO STRING DESCRIPTOR
PRASC: HRRZ B,(A) ;#CHARACTERS
MOVE A,1(A) ;STRING BP
MOVEI C,0 ;NO ADJUSTMENT
MOVE D,[IDPB FF,.ERSTP]
JRST PRSL1
IOER2: TLNN A,740 ;AC FIELD SPECIFIED?
POPJ P, ;NO -- DONE
;ELSE PRINT WHAT IS IN LPSA
SIXPRT: MOVE D,[IDPB FF,.ERSTP]
SKIPA A,[POINT 6,LPSA];GET FROM HERE
PSIX: HRLI A,(<POINT 6,0>) ;UUO ADDR IS ADDR OF SIXBIT
MOVEI C,40 ;ADJUSTMENT
MOVEI B,6 ;PRINT 6 CHARS
JRST PRSL1
PRSL: ILDB FF,A ;CHARACTER
ADDI FF,(C) ;ADJUSTMENT
XCT D ;PUSH TO ERROR STRING OR TYPE IT.
PRSL1: SOJGE B,PRSL
UPOPJ: POPJ P,
AC1PRT: MOVE A,GOGTAB ;GET USER TABLE PTR
SKIPA A,UUO1(A) ;SOMEONE STORED RIGHT THING HERE
ACPRT: HRRZ A,-7(P) ;RETURN ADDRESS
LDB A,[POINT 4,-2(A),12] ;AC # FROM PREV INSTR
CAIG A,D ;IF BIN SAVED AC'S
ADDI A,-6(P) ;RELOCATE
MOVE A,(A) ;PICK UP VALUE.
JRST DECOB ;PRINT IT IN DECIMAL
ARER2: PUSH P,A ;SAVE UUO
MOVEI A,[ASCIZ /Invalid index for array /]
PUSHJ P,PRA ;TO ERROR STRING.
MOVE A,(P) ;GET POINTER TO ARRAY NAME
PUSHJ P,PRASC ;PRINT ARRAY NAME
MOVEI A,[ASCIZ /. Index no. /]
PUSHJ P,PRA
POP P,A ;RESTORE UUO
LDB A,[POINT 4,A,12]
PUSHJ P,DECOB ;PRINT INDEX NUMBER
MOVEI A,[ASCIZ /. Value is /]
PUSHJ P,PRA
JRST ACPRT ;PRINT VALUE IN PRECEDING AC.
PSIXQ: MOVE A,JOBUUO ;UUO
JSP FF,SAVM ;GET STACK AND AC'S
MOVE D,[PUUO 1,FF] ;PRINT DIRECTLY
JRST PSIX ;TYPE IT.
PRA: HRLI A,(<POINT 7,0>) ;PUSH STRING TO ERROR BUFFER
ILDB FF,A
JUMPE FF,UPOPJ ;DONE AT ZZERO BYTE
IDPB FF,.ERSTP
JRST .-3 ;LOOP
DSCR USERERR(VALUE,CODE,"MSG","RESPONSE");
CAL SAIL
⊗
HERE (USERERR)
;; WE REALLY OUGHT TO HAVE ANOTHER UUO THAT CAN TAKE SOMETHING
;; OTHER THAN ASCIZ.
MOVE USER,GOGTAB
MOVEI A,1 ;BE SURE THAT DONT GC AT BAD TIME
AOSL REMCHR(USER) ;
PUSHJ P,STRNGC ;
IBP TOPBYTE(USER) ;BE SURE THAT HAVE NEITHER STRING AT TOP
PUSHJ P,INSET ;GET TO FW BNDRY
PUSH SP,[1] ;CONCATENATE A NULL TO END OF RSP STRING
PUSH SP,[POINT 7,[0]]
PUSHJ P,CAT
MOVE TEMP,-3(SP) ;EXCHANGE RESPONSE AND MSG STRINGS ON STACK
EXCH TEMP,-1(SP)
MOVEM TEMP,-3(SP)
MOVE TEMP,-2(SP)
EXCH TEMP,(SP)
MOVEM TEMP,-2(SP)
PUSHJ P,INSET ;
PUSH SP,[1] ;CONCATENATE A NULL FOR TTCALL
PUSH SP,[POINT 7,[0]]
PUSHJ P,CAT
MOVEI TEMP,-3(SP) ;ADDRESS OF RESPONSE STRING.
MOVEM TEMP,%ERRC ;SAVE FOR ERROR UUO.
POP P,UUO1(USER)
SKIPG TEMP,(P) ;IS CODE 0?
ERR. @(SP) ;YES, NO CONTINUATION POSSIBLE
CAIN TEMP,1 ;IS CODE 1?
ERR. 1,@(SP) ;YES, JUST PRINT ERROR, ALLOW CONT
CAIGE TEMP,2 ;IS IT SOMETHING ELSE
JRST USERBAK ;NO
MOVE TEMP,-1(P) ;YES, SET UP SO ERR. GUY WILL PRINT VALUE
ERR. 7,@(SP) ; AND DO IT
USERBAK:
SUB SP,X44
SUB P,X22
JRST @UUO1(USER) ;RETURN FROM ROUTINE.
SUBTTL Code to Handle Linkage to Editors
TVEDIT: TDZA 13,13 ;FLAG AS TV
EDIT: MOVNI 13,1
PUSH P,13
SETZB 13,14 ;PREPARE FOR PROVIDING
SETZB 15,16 ;STOPGAP WITH FILE NAME,
SETZB 11,12 ; PAGE AND LINE NUMBERS, SEQUENTIAL LINE #
PUUO 0,B ;SEE IF FILE NAME SPECIFIED
CAIE B,15 ;CR?
JRST GTNAM ; NO, NAME SPECIFIED
PUUO 0,B ;SNARF UP LINE FEED AFTER CR
SKIPL CONFIG ;IF IN THE COMPILER,
JRST GTIT
PUSH P,[0] ;USE SPECIAL CALL TO SET UP AC'S
PUSHJ P,@.ERRP. ;...
JRST GTIT ;GO PROCESS.
GTNAM: CAIE B," " ;DELETE LEADING BLANKS
JRST MKNAMM
PUUO 0,B
JRST GTNAM
MKNAMM: CAIN B,15 ;GO BACK ON CR
JRST AUTO
MOVE C,[POINT 6,13] ;COLLECT FILE NAME HERE
MKNLP: CAIE B," " ;DONE?
CAIN B,15
JRST GTIT1 ; YES
SUBI B,40
CAIN B,"."-40
SKIPA C,[POINT 6,14] ;ADJUST TO GET EXTENSION
IDPB B,C ;CHAR OF FILENAME
PUUO 0,B
JRST MKNLP
GTIT1: CAIN B,15
PUUO 0,B
GTIT: POP P,A ;TV/SOS FLAG
EXCH 13,14 ;EXT IN REG PRECEDING NAME?
;HERE TO RUN ANY PROGRAM, EITHER SOS OR COMPIL.
; REGISTERS HAVE GOODIES IN THEM:
; 13 FILE EXTENSION IN SIXBIT
; 14 FILE NAME IN SIXBIT
; 15 LINE NUMBER IN ASCII.
; 16 PAGE NUMBER (BINARY)
;IF AC 14 IS ZERO, THIS MEANS NO FILE HAS BEEN
; SPECIFIED, AND WE WILL USE "COMPIL" TO REPEAT THE
; LAST EDIT COMMAND (THIS IS NOT A FEATURE ON MOST
; STANDARD DEC SYSTEMS -- SEE R SPROULL)
NOEXPO <
MOVEI P,2
LOAD6 (2,<SYS>) ;ASSUME GET TO EDITOR VIA RPG
LOAD6 (4,<DMP>)
MOVEI 6,0
MOVEI 5,777777 ;TELLS RPG: "EDIT"
LOAD6 (3,<RPG>)
JUMPE 14,SWAPIT
MOVEI 5,1 ;START AT RPG LOC IN EDITOR
LOAD6 (3,<SOS>) ;NOW ASSUME SOS
JUMPL A,SWAPIT ;YES
LOAD6 (3,<E>) ;NO, TV (ACTUALY E.DMP)
MOVE 15,12 ;GET SEQUENTIAL LINE NUMBER
SWAPIT: CALL6 (P,SWAP) ;SEE YOU AROUND
>;NOEXPO
; ELSE FALL INTO EXPO VERSION ....
COMMENT ⊗ EXPORT VERSION OF EDITOR-INTERFACE
PROVIDED BY R. SPROULL, 11-18-70
SEE HIM FOR DETAILS ON DIDDLES TO CCL AND EDIT10
###### ??????? THIS PAGE CONTAINS CALLIs STILL ???????? ########
⊗
EXPO <
JUMPN 14,EDITG ;IF FILE, FIRE UP SOS
MOVE P,[XWD -1,[SIXBIT /SYS/
SIXBIT /COMPIL/
0
0
0
0 ]]
CALL6 (P,RUN) ;GO RUN IT.
JRST 4,0
EDITG: PUSHJ P,RPGDSK ;SET UP FOR FILE
MOVE 2,14 ;GET THE FILE
PUSHJ P,SXCON
MOVEI 1,"."
SKIPN 2,13 ;EXTENSION
JRST NOEXT
PUSHJ P,OUT1
HLLZS 2 ;EXTENSION.
PUSHJ P,SXCON
NOEXT: SKIPN 11 ;PROJ,PROG #
JRST NOPPN
MOVEI 1,"["
PUSHJ P,OUT1
HLRZ 1,11
PUSHJ P,OCTQ ;OUTPUT OCTAL
MOVEI 1,","
PUSHJ P,OUT1
HRRZ 1,11
PUSHJ P,OCTQ
MOVEI 1,"]"
PUSHJ P,OUT1
NOPPN: PUSHJ P,CRLF
JUMPE 15,GOED10 ;IF NO LINE NUMBER, DO NOT DO THIS.
MOVEI 1,"P"
PUSHJ P,OUT1
MOVE 2,15 ;LINE NUMBER
TRZ 2,1 ;FOR SURE?
ASCO: MOVEI 1,0
LSHC 1,7
PUSHJ P,OUT1
JUMPN 2,ASCO
MOVEI 1,"/"
PUSHJ P,OUT1
MOVE 1,16 ;PAGE NUMBER
PUSHJ P,OUTDEC
PUSHJ P,CRLF
GOED10: MOVE 1,PPMAX+2 ;SIZE
ADDI 1,4
IDIVI 1,5 ;TO WORDS
MOVNS 1
HRLS 1
HRR 1,PPMAX ;BUFFER START
ADDI 1,1
MOVEM 1,PPMAX+2
MOVSI 1,'EDT'
EXCH 1,PPMAX+1
MOVE 2,[XWD 3,PPMAX+1]
CALLI 2,44 ;WRITE IT
JRST DSKIT
EDT10R: MOVE P,[XWD 1,[SIXBIT /SYS/
SIXBIT /SOS/
0
0
0
0]]
CALL6 (P,RUN)
JRST 4,.
DSKIT: SETSTS 1,16 ;DO NOT LOSE BUFFERS
MOVEM 1,PPMAX+1
CALLI 2,30 ;JOB NUMBER
MOVSI 1,'EDT' ;TO FILE NAME
MOVEI 4,3
DGLP: IDIVI 2,=10
IORI 1,20(3)
ROT 1,-6
SOJG 4,DGLP
MOVSI 2,'TMP'
SETZB 3,4
ENTER 1,1
CALLI 12 ;FATAL
SETSTS 1,0
CLOSE 1,0 ;FINISH
JRST EDT10R
RPGDSK: CALLI
INIT 1,0
SIXBIT /DSK/
XWD PPMAX,0
CALLI 12
OUTBUF 1,0
OUTPUT 1,0
SETZM PPMAX+2
MOVEI 1," "
OUT1: AOS PPMAX+2
IDPB 1,PPMAX+1
POPJ P,
SXCON: MOVEI 1,0
LSHC 1,6
ADDI 1,40
PUSHJ P,OUT1
JUMPN 2,SXCON
POPJ P,
OCTQ: IDIVI 1,10
HRLM 2,(P)
SKIPE 1
PUSHJ P,OCTQ
HLRZ 1,(P)
ADDI 1,"0"
JRST OUT1
OUTDEC: IDIVI 1,=10
HRLM 2,(P)
SKIPE 1
PUSHJ P,OUTDEC
HLRZ 1,(P)
ADDI 1,"0"
JRST OUT1
CRLF: MOVEI 1,15
PUSHJ P,OUT1
MOVEI 1,12
JRST OUT1
>;EXPO
SUBTTL SAVE, RESTR, INSET -- General Utility Routines
DSCR SAVE
CAL PUSHJ
DES This routine saves registers 0-RF (12) in the user
RACS area. It also saves the return
address (-1(P)) in UUO1(USER), for traditional reasons,
for the error message printout routines.
Register USER is loaded but not saved, as is register
TEMP
⊗
↑SAVE: MOVE USER,GOGTAB ; LOAD PTR TO USER RE-ENTRANT TABLE
HRRZI TEMP,RACS(USER) ;XWD FF,SAVEADDR
BLT TEMP,RACS+RF(USER) ;SAVE FF THRU RF
MOVE TEMP,-1(P) ;RETURN ADDR FROM I/O CALL
MOVEM TEMP,UUO1(USER) ;STORE RETURN
POPJ P,
DSCR RESTR
PAR LPSA -- XWD FOR ADJUSTING P-STACK (#PARAMS+RETURN ADDR)
CAL JRST
RES ACS are restored from RACS, stack is adjusted using LPSA,
return is made through UUO1(USER)
⊗
↑RESTR: MOVSI TEMP,RACS(USER) ;XWD SAVEADDR,FF
CAME RF,RACS+RF(USER) ;TEMPORARY CHECK TO MAKE SURE NOT CLOBBERED.
ERR <DRYROT: RF CLOBBERED AT RESTR>,1
BLT TEMP,RF ;RESTORE
SUB P,LPSA ;ADJUST STACK
JRST @UUO1(USER) ;RETURN
DSCR STACSV
CAL PUSHJ
DES SAVES ACS 0-13 IN AREA STACS
SID DESTROYS 14,15
⊗
;; #KL# BY JRL (11-22-72) SAVE ONLY AC'S 0-13
↑STACSV:
MOVE 15,GOGTAB
HRRZI 14,STACS(15)
BLT 14,STACS+13(15)
POPJ P,
DSCR STACRS
CAL PUSHJ
DES RESTORES ACS 0-13 FROM AREA STACS
⊗
;; #KL# RESTORE ONLY 0-13
↑STACRS: MOVE 15,GOGTAB
HRLZI 14,STACS(15)
BLT 14,13
POPJ P,
DSCR INSET
CAL PUSHJ
RES String Space is adjusted so that next created string will start
on a full-word boundary.
SID USER PNTS TO GOGTAB
DES REMCHR is first adjusted, and STRNGC called if necessary.
Then TOPBYTE is adjusted.
⊗
↑INSET: MOVE USER,GOGTAB ;MAKE SURE
;;#GI# DCS 2-5-72 REMOVE TOPSTR
HLL TEMP,TOPBYTE(USER)
HRRI TEMP,[BYTE (7) 0,4,3,2,1,0]
ILDB TEMP,TEMP ;ADJUSTMENT NEEDED.
ADDM TEMP,REMCHR(USER) ;UPDATE REMCHR.
SKIPL TEMP,TOPBYTE(USER)
ADDI TEMP,1
HRLI TEMP,440700 ;POINT 7, WORD
MOVEM TEMP,TOPBYTE(USER) ;AND SAVE
POPJ P,
>;NOLOW
ENDCOM(LUP)
COMPIL(COR,<CORREL,CORGET,CORINC,CANINC,CORBIG>
,<.EXPIN,.TRACS,X11,GOGTAB>
,<CORGET, CORREL, ... -- CORE ALLOCATION ROUTINES>)
SUBTTL Core Service Routines -- General Description
DSCR BEGIN CORSER
⊗
IFN ALWAYS,<BEGIN CORSER>
Comment ⊗ These are the core allocation routines for both the compiler
and the code it compiles. Core comes in "BLOCKs." A block may be any
(reasonable) length, and has the following format:
HEAD: ptr to PREV,, ptr to NEXT ;if block not in use, free storage list pointers
SIZE ;GREATER 0 if free, LESS0 if in use
<SIZE-3 data words> ;whatever is to go here
x00000,, ptr to HEAD ;x=1 if in use, 0 if free
ptr to PREV is zero if this block is first on free storage list.
ptr to NEXT is zero if last
In the beginning, the world starts out as one big block, occupying space from
the end of the (GOGTAB) user table to @JOBREL. Once a MOVE USER,GOGTAB
has been done, LOWC(USER) and TOP(USER) indicate the total size of
available core. FRELST(USER) pnts at the first (only) block in free storage.
If GOGTAB is 0, CORGET will create a user table and make the remaining space
look like a BLOCK. It will create a user table and point GOGTAB at it.
It also assures that DDT symbols are below JOBSA(lh). Then it sets
JOBFF to =76K out of pure spite. Now CORGET operations may be issued.
CORGET is called with the desired size in SIZ (C). The free storage list is
searched for the first free block (BLK) satisfying the request. The
required block is taken from lower addresses of BLK and BLK is adjusted.
If requested size is within a few words of the free size, all of BLK is
given to the user. The resultant address is returned in THIS (B).
If there is no block on FRELST(USER) big enough, or if ATTOP(USER) NEQ 0, CORGET
checks XPAND(USER) for permission (0) to expand core. If granted, a new
block is formed at the top after obtaining more core. It is merged with
the top block if it is free, then the requested block is allocated from
it. CORGET is simple.
CORGET skips if it is successful. It does not skip if it needs to expand and
either XPAND(USER) NEQ 0 or the CORE UUO fails.
The secret is CORREL. No compacting is done, but CORREL will merge a returning
block with any neighboring free block. It can do this because it can
tell the status of each neighbor by looking at the size (POS if free)
field or x-bit (off if free). This tends to reduce checkerboarding.
CORREL is called with a pointer to the block to be released in THIS (B).
It returns nothing, nor does it ever skip.
CORBIG returns in SIZ the size of the largest available block. ⊗
NOLOW < ;INCLUDE IN UPPER SEGMENT.
SUBTTL Special AC Declarations
DEBCOR ←←0 ;SWITCH FOR CORE DEBUGGING ROUTINES.
; ACS
SIZ ←← 3 ;SIZE OF BLOCK BEING OBTAINED OR RELEASED
THIS ←← 2 ;POINTER TO SAME
NEXT ←← 1 ;POINTER TO SUCCESSOR
PREV ←← 5 ;POINTER TO PREDECESSOR
LAST ←← 6 ;POINTER TO NEXT-HIGHER NEIGHBOR
TRIVIAL ←←=10 ;AMOUNT WE'RE WILLING TO WASTE
SUBTTL Utility Routines
DSCR UNLINK
CAL PUSHJ
PAR ptr to Core block to be removed in AC THIS (2)
RES block is removed from CORSER free storage list
SID ACs NEXT (1) and PREV (5) are given appropriate values
⊗
UNLINK:
HRRZ NEXT,(THIS) ;PTR TO NEXT BLOCK
HLRZ PREV,(THIS) ;PTR TO PREVIOUS BLOCK
SKIPN PREV ;IF A PREV BLOCK DOES NOT EXIST,
MOVEI PREV,FRELST(USER) ; USE FRELST POINTER
HRRM NEXT,(PREV) ;CHANGE ITS NEXT FIELD
SKIPE NEXT ;IF A NEXT BLOCK EXISTS,
HRLM PREV,(NEXT) ; CHANGE ITS PREV FIELD
POPJ P, ;BLOCK IN "THIS" IS NO LONGER ON FRELST
DSCR RELINK
CAL PUSHJ
PAR AC THIS ptr to core block to be placed on free storage list
AC LAST ptr to last word of block +1
AC SIZ has size of this block
DES block is placed on CORSERs free storage list
SID AC NEXT (1) is given the appropriate value
⊗
RELINK:
HRRZM THIS,-1(LAST) ;X-BIT ← 0, RH ← PTR TO HEAD
MOVEM SIZ,1(THIS) ;GREATER 0 SIZE FIELD then FREE BLOCK
SKIPE NEXT,FRELST(USER) ;PLACE NEW BLOCK ON FRONT OF FRELST
HRLM THIS,(NEXT) ; IF THERE IS ONE
HRRZM NEXT,(THIS) ;POINT TO NEXT FROM THIS
HRRZM THIS,FRELST(USER) ;UPDATE FRELST POINTER
POPJ P, ;RETURN
DSCR CORE2I
CAL PUSHJ
DES Initializes second segment core if there is a global model
⊗
GLOB <
IFN 0,<
↑GLCOR:
SKIPE GLBPNT
POPJ P, ;ALREADY INITIALIZED.
MOVEM 16,GLUSER+LEABOT+16
MOVEI 16,GLUSER+LEABOT
BLT 16,GLUSER+LEABOT+15
;SHALL NOT CLOBBER ACCUMULATOR 1.
MOVEI 3,3(13) ;GET SIZE REQUIRED.PLUS SOME BECAUSE BLT LOSES.
PUSHJ P,CORE2 ;GET SECOND SEGMENT CORE.
JRST [TERPRI <NO CORE FOR GLOBAL MODEL>
CALL6 (EXIT)]
SUBI 2,1
MOVEM 2,GLBPNT ;AND RECORD IT.
SETZM 1(2) ;FIRST WORD.
HRRI 2,2(2) ;SECOND WORD.
HRLI 2,-1(2) ;FIRST WORD.
ADDI 3,-2(2) ;LENGTH.
BLT 2,(3) ;ZERO IT.....
MOVSI 16,GLUSER+LEABOT
BLT 16,16 ;RESTORE ALL LOADER'S AC'S AGAIN.
POPJ P, ;AND GO AWAY.
>
↑CORE2I:
PUSH P,USER
MOVE USER,[XWD GLUSER+LEABOT+20,GLUSER+LEABOT+21]
SETZM GLUSER+LEABOT+20
BLT USER,GLUSER+ZAPEND
POP P,USER ;NOW DATA AREA IS ZERO.
MOVEI USER,GLUSER ;SET UP FOR CORE2.
PUSHJ P,JUSTSAVE ;AND SAVE AC'S
SETOM CORLOK ;THE LOCK ...
SETOM GLBPNT ;AND THE SWITCH SAYING INITED.
MOVE THIS,TOP2 ;LAST ADDRESS IN SEC. SEG USED.
ADDI THIS,1
MOVEM THIS,LOWC(USER) ;SAVE FOR LATER
PUSHJ P,NEWB2 ;AND LINK UP.
JRST BUFRST ;ALL DONE INITIALIZING.
DSCR 2d SEGMENT CORE CONTROL STORAGE
⊗
CORLOK: 0
CR2BEG: BLOCK ZAPEND-ZAPBEG+1 ;AREA FOR ALL OTHERS.
↑↑GLUSER←CR2BEG-ZAPBEG ;AND THE MAGIC INDEX.
INTERNAL GLUSER
>;GLOB
DSCR BUFRST
CAL PUSHJ or JRST
RES restores ACs from CORSER routines, and returns
⊗
BUFRST:
IFN DEBCOR,<
SKIPE PRTCOR ;SHOULD WE DEBUG?
JFCL
>
MOVSI TEMP,BUFACS(USER)
BLT TEMP,LAST
POPJ P,
DSCR BUFSAV
CAL PUSHJ
RES Saves ACs for CORSER routine
Initializes CORSER storage, obtains USER TABLE if GOGTAB is 0
⊗
BUFSAV:
GLOB <
SKIPN GLBPNT ;HAS GLOBAL MODEL BEEN INITIALIZED?
PUSHJ P,CORE2I ;NO --INITIALIZE IT.
>;GLOB
SKIPE USER,GOGTAB ;CAN WE GO AHEAD?
JRST JUSTSAVE ; YES
Comment ⊗ Use SALTAB and forget the rest if SALTAB is there. Otherwise
set up a user table. Don't use THIS or SIZ (B or C). ⊗
NOEXPO <
MOVEI TEMP,=76*=1024 ;ONE REALLY MUST KNOW WHAT HE
>;NOEXPO
EXPO <
MOVEI TEMP,-1 ;FOR MAX CORE
>;EXPO
MOVEM TEMP,JOBFF ; IS DOING
; SKIPE USER,SALTAB ;OTHERS CAN SPECIFY SAIL SPACE
; MOVEM USER,GOGTAB ;SET UP GOGTAB IF SALTAB NON-ZERO
; JUMPN USER,JUSTSAVE ;DON'T GO THRU SAIL's ALLOCATION
; ASSUME THAT THE WORLD IS NEW
HLRZ USER,JOBSA ;USER TABLE ADDRESS
MOVEM USER,GOGTAB ;THIS TIME FOR SURE
SKIPN JOBDDT ;IF DDT IS IN CORE,
JRST NODDT ; MAKE SURE ITS SYMBOLS ARE PROTECTED
HRRZ TEMP,JOBSYM ;IF JOBSYM IS BELOW JOBFF, THEN
CAML TEMP,USER ; ASSUME ALL SYMBOLS ARE BELOW.
TERPRI <YOUR SYMBOLS ARE SOON TO BE OBLITERATED>
NODDT: MOVEI TEMP,ENDREN-CLER+=2000(USER) ;MAKE SURE
CAMGE TEMP,JOBREL ; ENOUGH CORE EXISTS
JRST CORTHER ; FOR USER TABLE
CALL6 (TEMP,CORE) ;GET ENOUGH
CORERR <DRYROT -- NO ROOM FOR USER TABLE>
CORTHER:
SETZM (USER) ;CLEAR USER TABLE
HRL TEMP,USER
HRRI TEMP,1(USER)
BLT TEMP,ENDREN-CLER(USER)
MOVEI THIS,ENDREN-CLER(USER) ;SET UP LIMITS OF FREE SPACE
MOVEM THIS,LOWC(USER) ; BOTTOM
PUSHJ P,NEWBLK ;MAKE NEW AREA INTO A FREE BLOCK
JRST JUSTSAVE ;SAVE ACS
GLOB <
NEWB2: CALL6 (LAST,SEGSIZ) ;FIND OUT HOW BIG.
TRO LAST,400000 ;SINCE ANDY DOES NOT GIVE ME THIS.
JRST NEWB1
>;GLOB
NEWBLK:
HRRZ LAST,JOBREL ;END OF BIG BLOCK
NEWB1: SETZM (THIS) ;POINTERS WORD IN BIG BLOCK
ADDI LAST,1 ;CONFORM TO "LAST" STANDARDS
MOVEM LAST,TOP(USER) ;TOP OF FREE SPACE
PUSH P,SIZ ;SAVE SIZE
MOVE SIZ,LAST ;COMPUTE SIZE OF NEW BLOCK
SUB SIZ,THIS ;SIZE OF BIG BLOCK
PUSHJ P,RELINK ;PUT ON FREE STORAGE LIST
POP P,SIZ ;GET SIZ BACK
POPJ P,
JUSTSAVE:
MOVEI TEMP,BUFACS(USER)
BLT TEMP,BUFACS+LAST(USER)
IFN DEBCOR,<
SKIPE PRTCOR ;SHOULD WE DEBUG?
PUSHJ P,CORPRT ; YES
>
POPJ P,
IFN DEBCOR,<
↑PRTCOR: 0
>
SUBTTL CORGET
DSCR CORGET
CAL PUSHJ
PAR size of desired block in AC C (3)
RES SUCCESS: addr of block in B, skip-return
FAILURE: no-skip
SID none, except when called with GOGTAB 0 -- should only be done by experts
DES a block of at least the required size is obtained using first-fit algorithm.
Up to 10 extra words may be returned, but this is not reflected in C.
⊗
HERE(CORGET)
IFN DEBCOR,<
SKIPE PRTCOR
TERPRI <CORGET: > ;TELL THE PEOPLE WHO YOU ARE
>
PUSHJ P,BUFSAV ;SAVE AC'S, INITIALIZE WORLD PERHAPS
GLOB <
SKIPN USCOR2(USER) ;ARE WE INSTRUCTED TO USE CORE2?
JRST COR21 ;NOPE -- GO AHEAD.
↑↑CORE2: SKIPN GLBPNT ;HAS IT BEEN INITIALIZED?
PUSHJ P,CORE2I ;NO -- BUT NOW.
AOSE CORLOK ;CAN WE GET THROUGH THE LOCK?
JRST [SOS CORLOK ;APPARENTLY NOT.
PUSHJ P,WAITQQ ;WAIT
JRST .-1]
MOVEI USER,GLUSER ;USE THIS VERSION OF USER.
PUSHJ P,JUSTSAVE ;JUST SAVE THE ACCUMULATORS.
>;GLOB
COR21: ADDI SIZ,3 ;3 WORDS FOR CONTROL INFO
SKIPE ATTOP(USER) ;IF USER REQUESTS IT, GET BLOCK
JRST EXPAND ; AT TOP OF CORE
MOVEI THIS,FRELST(USER) ;THIS WILL POINT TO THE FIRST GOOD BLOCK
GETLUP: HRRZ THIS,(THIS) ;PTR TO NEXT FREE BLOCK
JUMPE THIS,EXPAND ;TRY TO EXPAND CORE, NONE EXIST YET
CAMLE SIZ,1(THIS) ;WILL IT FIT?
JRST GETLUP ; NO, TRY NEXT
GETCOR: AOS (P) ;SUCCESS GUARANTEED
HRRZM THIS,BUFACS+THIS(USER) ;RESULT(ALMOST)
PUSHJ P,UNLINK ;UNLINK THIS BLOCK
MOVE LAST,1(THIS) ;REAL BLOCK SIZE
CAIGE LAST,TRIVIAL(SIZ) ;IS DIFFERENCE NEGLIGIBLE?
JRST [MOVSI TEMP,400000 ;YES, USE WHOLE THING --
ADD LAST,THIS ; MARK X-BIT TO INDICATE IN USE
HLLM TEMP,-1(LAST)
JRST GETOUT] ;AND GO FINISH OUT
MOVEM SIZ,1(THIS) ;NEW SIZE FOR RESULT
HRRZ TEMP,THIS ;SAVE START OF BLOCK (RESULT)
ADD THIS,SIZ ;NEW START FOR REMAINING FREE STUFF
SUB LAST,SIZ ;NEW SIZE FOR REMAINS
MOVE SIZ,LAST
ADD LAST,THIS ;NEW END FOR REMAINS
HRLI TEMP,400000 ;TURN X-BIT ON
MOVEM TEMP,-1(THIS) ;IN USER'S BRAND NEW BLOCK
PUSHJ P,RELINK ;RELINK REMAINS, RESTORE ACS
GETOUT: PUSHJ P,GETRST ;RESTORE ACS
SETZM (THIS) ;PTR RETRIEVED FROM STORAGE
MOVNS 1(THIS) ;SIZE NEG MEANS IN USE
ADDI THIS,2 ;USER DOESN'T SEE THIS HEADER
IFN DEBCOR,<
SKIPE PRTCOR
PUSHJ P,CORPRT
>
POPJ P, ;HERE'S YOUR BLOCK!
EXPAND: SKIPE XPAND(USER) ;IS IT ALLOWED TO EXPAND?
JRST GETRST ; NO, ERROR RETURN
PUSH P,SIZ ;SAVE TOTAL SIZE
HRRZ THIS,TOP(USER) ;THIS PNTS TO NEW BLOCK IF NEXT LOWER IS USED
SKIPGE -1(THIS) ;IS TOP BLOCK FREE?
JRST GETMOR ; NO, USE WHAT YOU HAVE
HRRZ THIS,-1(THIS) ;UNLINK THE
PUSHJ P,UNLINK ; TOP BLOCK
GETMOR: MOVE TEMP,THIS
ADDI TEMP,=1024(SIZ) ;GET MORE AND THEN SOME
POP P,SIZ ;GET THIS BACK BEFORE YOU FORGET
;;% %
TRPCAL (SIZ,TEMP,X11,X11,.EXPINT) ;TRAP TO USER IF DESIRED
GLOB <
CAIN USER,GLUSER ;THIS IS HOW WE TELL
JRST [CALL6 (TEMP,CORE2) ;GET SOME CORE
JRST GETRST ;HE SPAT UPON OUR HUMBLE REQUEST.
PUSHJ P,NEWB2 ;LINK IT UP
JRST GETM.1]
>;GLOB
CALL6 (TEMP,CORE) ;ASK FOR MORE
JRST GETRST ;CAN'T GET IT
;;% %
MOVNS TEMP
TRPCAL (SIZ,TEMP,X11,X11,.EXPINT) ;TRAP TO USER NOW THAT HAVE CORE
PUSHJ P,NEWBLK ;MAKE TOP LOOK LIKE FREE BLOCK
GETM.1: CAMLE SIZ,1(THIS) ;NOW SHOULD FIT
CORERR <DRYROT -- EXPAND CODE GLUBBED UP>
JRST GETCOR ;GO GET BLOCK
GETRST:
GLOB <
PUSHJ P,BUFRST ;RESTORE ACCUMULATORS.
CAIN USER,GLUSER ;WAS IT CORE2?
SOS CORLOK ;YES -- BACK UP COUNT.
MOVE USER,GOGTAB ;RESET IT TO USUAL.
POPJ P, ;
>;GLOB
JRST BUFRST
SUBTTL CORINC, CANINC
DSCR CORINC
CAL PUSHJ
PAR AC B -- Addr of block to be incremented
AC C -- amount if increase desired
RES SUCCESS: skip-return, extra core has been granted
FAILURE: no-skip
SID none
⊗
HERE(CORINC)
IFN DEBCOR,<
SKIPE PRTCOR
TERPRI <CORINC:>
>
PUSHJ P,JUSTSAVE ;SAVE ACS
MOVNI FF,1 ;WANT TO DO IT
JRST INCR
DSCR CANINC
CAL PUSHJ
PAR same as CORINC
RES No extra core is ever actually obtained
if entire request can be granted, skip-return
if some extra words available, no-skip, C contains possible increment
if no extra words available, no-skip, C contains 0
SID none except as described above
⊗
HERE(CANINC)
IFN DEBCOR,<
SKIPE PRTCOR
TERPRI <CANINC: >
>
PUSHJ P,BUFSAV
MOVEI FF,0 ;JUST WANT TO SEE IF IT'S POSSIBLE
; IF BLOCK IS AT TOP, CAN ALWAYS DO IT
INCR: SUBI THIS,2 ;POINT AT REAL BLOCK HEAD
GLOB <
TRNE THIS,400000 ;CHECK TO SEE IF CORE2
CORERR <NO CANINC SECOND SEGMENT SPACE>
>;GLOB
HRRZ LAST,THIS ;CHECK AT TOP
SUB LAST,1(THIS) ; ADDR OF END (SIZE IS NEG)
CAMGE LAST,TOP(USER) ;TOP BLOCK?
JRST MIDDLE ; NO
JUMPE FF,YESINC ;SUCCESS
MOVNS 1(THIS) ;MAKE IT LOOK FREE
ADD SIZ,1(THIS) ;TOTAL SIZE
HRRZS -1(LAST) ;MAKE END LOOK FREE
JRST EXPAND ;EXPAND AND RETURN
MIDDLE: SKIPGE TEMP,1(LAST) ;NEXT BLOCK FREE?
JRST NONEATALL ; NO, FAILURE
SUBI TEMP,3 ;AVAILABLE SIZE
CAMLE SIZ,TEMP ;IS THERE ENOUGH?
JRST MAYBE ; NO, FAILURE MAYBE
JUMPE FF,YESINC ;ALL OK, CAN DO, REPORT IT
CRXXB: MOVNS TEMP,1(THIS) ;MAKE IT LOOK FREE
PUSH P,(THIS) ;WILL RESTORE THIS IN CASE SOMEONE USED
PUSH P,THIS ;SAVE SIZE
PUSH P,SIZ ;AND POINTER
ADDM TEMP,(P) ;TOTAL SIZE DESIRED AFTER RETURN
MOVE SIZ,TEMP ;SIZE OF CURRENT "THIS"
HRRZ THIS,LAST ;MERGE "THIS" WITH "LAST"
PUSHJ P,UNLINK ;TAKE IT OFF FRELST
ADD LAST,1(THIS) ;AND INCREASE
ADD SIZ,1(THIS)
MOVE THIS,-1(P) ;RETRIEVE CURRENT BLOCK.
PUSHJ P,RELINK ;AND NOW RELINK ON FRELST.
POP P,SIZ
POP P,THIS
PUSHJ P,GETCOR ;GET THE BLOCK AGAIN, ONLY BIGGER
CORERR <DRYROT -- NEAR CRXXB> ;CAN'T HAPPEN
POP P,-2(THIS) ;GET POINTER WORD BACK
AOS (P) ;SUCCESS
POPJ P, ;BUFRST DONE BY GETCOR
YESINC: AOS (P) ;REPORT SUCCESS
IFN DEBCOR,<
SKIPE PRTCOR
PUSHJ P,CORPRT
>
JRST BUFRST
MAYBE: ADDI TEMP,3(LAST) ;GET TOP OF NEXT BLOCK AND SEE
CAMGE TEMP,TOP(USER) ;IF IT IS THE TOP ONE.
JRST NOTENUF ;NO -- FAIL UTTERLY.
JUMPE FF,YESINC ;GOT IT IF ONLY GOING TO HERE.
PUSH P,SIZ ;SAVE AMOUNT REQUESTED.
MOVEI SIZ,-3(TEMP) ;THIS IS THE SIZE OF THE BLOCK WE
SUB SIZ,LAST ;KNOW WE CAN GET.
MOVN TEMP,SIZ
ADDM TEMP,(P) ;(P) NOW HAS EXTRA REQUIRED.
PUSHJ P,CRXXB ;AND WE DO SOO
CORERR <DRYROT NEAR MAYBE> ; CAN'T HAPPEN.
POP P,SIZ ;RETRIEVE SIZE.
MOVNI FF,1 ;SINCE CRXXB DESTROYED IT.
JRST INCR ;AND GO THROUGH AGAIN
;THIS TIME IT WILL BE THE TOP BLOCK.
NOTENUF:
SUBI TEMP,3(LAST) ;UNDO WHAT WAS DONE ABOVE
SKIPA SIZ,TEMP ;CAN'T DO ALL, BUT CAN DO THIS MUCH
NONEATALL:
MOVEI SIZ,0 ;CAN'T DO ANYTHING
MOVEM SIZ,BUFACS+SIZ(USER)
JRST BUFRST
SUBTTL CORREL
DSCR CORREL
CAL PUSHJ
PAR addr of block to be released in B
RES block is released to free storage
SID none
DES the block is merged with any adjoining free blocks
⊗
HERE(CORREL)
IFN DEBCOR,<
SKIPE PRTCOR
TERPRI <CORREL: >
>
SKIPN USER,GOGTAB ;MUST BE SET UP HERE
CORERR <DRYROT -- CORREL CALLED WITH INITIALIZED WORLD>
GLOB <
TRNN THIS,400000 ;IS IT SECOND SEGMENT ADDRESS?
JRST NOSGR ;NO
MOVEI USER,GLUSER ;USE THIS ONE.
AOSE CORLOK ;SEE IF WE CAN GET IN.
JRST [SOS CORLOK
PUSHJ P,WAITQQ
JRST .-1]
NOSGR:
>;GLOB
PUSHJ P,JUSTSAVE ;SAVE ACS
; MERGE WITH LOWER NEIGHBOR (ADDRESS-WISE) IF POSSIBLE
SUBI THIS,2 ;USER THINKS IT STARTED 2 PAST
MOVN SIZ,1(THIS) ;SIZE OF THIS BLOCK
MOVE LAST,SIZ ;ADDRESS OF UPPER
ADD LAST,THIS ; NEIGHBOR
CAMGE THIS,LOWC(USER) ;IS ADDRESS IN RANGE?
CORERR <DRYROT -- ADDR TO CORREL TOO LOW>
CAME THIS,LOWC(USER) ;CAN THERE BE A LOWER BLOCK
SKIPGE -1(THIS) ; AND IF SO, IS IT FREE?
JRST UPPET ; NO, LOOK FOR UPPER BLOCK
HRRZ THIS,-1(THIS) ;PTR TO LOWER BLOCK
PUSHJ P,UNLINK ;UNLINK IT FROM LIST
ADD SIZ,1(THIS) ;INCREASE SIZE
; MERGE WITH UPPER NEIGHBOR IF POSSIBLE
UPPET: CAMLE LAST,TOP(USER)
CORERR <DRYROT -- ADDR TO CORREL TOO HIGH>
CAME LAST,TOP(USER) ;IS THERE AN UPPER BLOCK?
SKIPGE 1(LAST) ;AND IF SO, IS IT FREE?
JRST LNKRET ; NO, RELINK AND GO AWAY
UPPR: PUSH P,THIS
HRRZ THIS,LAST ;THIS PTR TO UPPER NEIGHBOR
PUSHJ P,UNLINK ;GET IT OUT
ADD LAST,1(THIS) ; INCREASE EXTENT
ADD SIZ,1(THIS) ; AND TOTAL SIZE
POP P,THIS ; GET HEADER POINTER BACK
LNKRET:
GLOB <
CAIN USER,GLUSER
JRST LNKRT ;IF SEC SEGMENT, NEVER SHRINK
>;GLOB
;;#IC# 7-3-72 DCS (1-1) ADD NEW MEANING TO NOSHRK(USER)
SKIPL TEMP,NOSHRK(USER) ;If NOSHRK(USER) is:
CAMG LAST,JOBREL ; <0, CORREL should not reduce core;
JRST LNKRT ; >0, its RH indicates the amount of
JUMPN TEMP,.+2 ; free space which should be
MOVEI TEMP,=2046 ; protected from release;
HRRZS TEMP ; =0, at least 2K should be protected.
CAIGE TEMP,4 ;Only the first and third alternatives
MOVEI TEMP,4 ; were previously available.
CAMGE SIZ,TEMP ;Don't bother if there is already
JRST LNKRT ; less free space available than
ADDI TEMP,(THIS) ; desired
;;% %
TRPCAL (SIZ,TEMP,X11,X11,.EXPINT)
;;#IC# (1-1)
CALL6 (TEMP,CORE)
ERR <DRYROT --CORSER&LNKRET>
;;% %
MOVNS TEMP
TRPCAL (SIZ,TEMP,X11,X11,.EXPINT)
MOVE LAST,JOBREL ; AND 2) ADJUST BLOCK TO INDICATE
ADDI LAST,1
MOVEM LAST,TOP(USER) ;AND RECORD NEW RESULTS.
MOVE SIZ,LAST ; THE CHANGE BEFORE RELINKING
SUB SIZ,THIS
LNKRT:
PUSHJ P,RELINK ;PUT IT BACK
IFN DEBCOR,<
SKIPE PRTCOR
PUSHJ P,CORPRT
>
JRST GETRST ;AND GO AWAY
SUBTTL CORPRT, CORBIG
IFN DEBCOR,<
↑CORPRT:
SETZM TOTFRE# ;TOTAL FREE STORAGE COUNT
TERPRI <FREE STORAGE: >
PUSH P,LPSA
MOVE USER,GOGTAB ;THIS STUFF IS DEBUGGING
MOVEI LPSA,FRELST(USER) ;JUNK FOR CORGET AND FRIENDS
CPLUP: HRRZ LPSA,(LPSA) ;IT SHOULD BE INTUITIVELY
JUMPE LPSA,DUNNN ;OBVIOUS
PRINT <START = >
OCTPNT LPSA
MOVE TEMP,1(LPSA)
ADDM TEMP,TOTFRE
PRINT < SIZE = >
OCTPNT TEMP
ADD TEMP,LPSA
PRINT < END = >
OCTPNT TEMP
TERPRI
JRST CPLUP
DUNNN:
PRINT <TOTAL FREE SIZE = >
OCTPNT TOTFRE
SETOM PRTCOR
TERPRI
CAMLE THIS,JOBREL
JRST DUNMOR
TERPRI <THIS BLOCK: >
PRINT <"THIS" = >
MOVE TEMP,THIS
OCTPNT TEMP
PRINT < C-SIZE = >
HRRZ TEMP,SIZ
OCTPNT TEMP
CAML THIS,JOBREL
JRST DUNMOR
HRREI LPSA,-2(THIS)
JUMPLE LPSA,DUNMOR
PRINT < BLOCK-SIZE = >
MOVN TEMP,1(LPSA)
OCTPNT TEMP
DUNMOR: TERPRI
POP P,LPSA
TTCALL 11,
TTCALL TEMP
TERPRI
POPJ P,
>
DSCR CORBIG
CAL PUSHJ
PAR NONE
RES LARGEST AVAILABLE BLOCK IN SIZ (3,C)
SID THIS (2,B) MUNGED
⊗
HERE(CORBIG) SKIPN USER,GOGTAB
CORERR <CORBIG: INITIALIZED WORLD>
MOVEI SIZ,0 ;"ZERO-LENGTH" BLOCK
MOVEI THIS,FRELST(USER)
BIGLUP: HRRZ THIS,(THIS)
JUMPE THIS,BIGDUN ;END OF FREELIST?
CAMGE SIZ,1(THIS)
MOVE SIZ,1(THIS) ;FIND MAX
JRST BIGLUP
BIGDUN: SUBI SIZ,3 ;WHAT HE SEES
POPJ P,
Comment ⊗ No other core routines should be necessary to provide
gross control over allocation. Programs obtaining
space from CORGET can carve the blocks up if necessary.
Please put your core back when you're done with it.
Thank You,
The Management
⊗
>;NOLOW
ENDCOM (COR)
IFN ALWAYS,<
BEND CORSER
>
COMPIL(SGC,<STRNGC,STRGC,STCLER,SGINS,SGREM,%SPGC1,%ARSR1>
,<.SGCIN,GOGTAB,X11,CORGET,CORREL,CORINC,X22,CORBIG,SPRPDA,INSET>
,<STRING GARBAGE COLLECTOR ROUTINES>
,<%SPGC,%STRMRK,%ARRSRT>)
DSCR STRGC (REQUEST)
CAL SAIL
PAR REQUEST -- length of string which must fit after STRNGC
RES Calls STRNGC, using REQUEST as A-argument
REMCHR not updated by REQUEST size after return
⊗
DSCR STRNGC
CAL PUSHJ
PAR A -- number of new characters needed
REMCHR(USER) -- has been updated by that number of chars
STREQD(USER) -- Additional characters required (see below).
STINCR(USER) -- Size (in words) of string space increments (see below).
Statistics:
SGCTIME -- Time of last garbage collect, in ms.
User must activate timing, by setting this cell to -1.
SGCTOTAL-- Total gc time, in ms., if timing active.
SGCNUM -- Number of strings collected, last gc.
SGCWASTE -- Number of unused but unavailable wds detected, last gc.
RES REMCHR (updated by request) and TOPBYTE are correct, there is room
to insert a string of the requested size, + STREQD additional chars.
SID none
DES STRNGC is two-pass. In the first, all string descriptors are found
and sorted into ascending sequence with respect to the locations of their
respective texts. Descriptors are found via the generating routines,
described in CALSG description below.
In the second pass, all string texts are moved down to fill any
unused space. All descriptors are adjusted to reflect the new locations.
If there is still not room to satisfy the request+REQD, a new block
(space), STINCR long, is allocated for strings, and TOPBYTE set to
point to it. Alternatively, if the compaction yielded some empty spaces,
they may be deleted, depending on the value of REQD, and the request.
String space thus dynamically expands and contracts to satisfy demand.
⊗
DSCR CALSG
PAR linked list of routine addresses based at SGROUT(USER)
RES each routine in list is called to provide string descriptors
to the linking routine, SGSORT.
SID SGSORT uses B,C, and TEMP, accepts input in A. Generating
routines may use A-T (11) and TEMP for their own devices.
D through T will not be changed by calls on SGSORT.
DES
Active strings are identified by the two-word descriptors which
are scattered throughout memory, some in variables, some in arrays,
some in stacks, some in LEAP storage, etc. STRNGC must look at
each descriptor during collection. It does it by calling, in sequence,
each of the routines on SGROUT, providing each with the address of a
routine which will add the descriptor to those STRNGC knows about. The
user (clever) can add or remove routines on the SGROUT list (see SGINS,
SGREM).
Each generating routine should do the following:
1) Place a string descriptor address in A
2) PUSHJ P,SGSORT or PUSHJ P,@-1(P) (addr provided on stack)
3) Repeat the process if it knows about more strings, else
4) Return with a POPJ (and a flourish)
The `standard' generating routines are:
SPSG -- collects the string stack
STRMRK -- collects string variables linked through SGLINK(USER)
ARRMRK -- collects string arrays found in ARRPDL
RINGSORT -- collects PNAMES from semantic blocks in compiler
DEFSRT -- collects saved input strings during macro recursion in compiler.
These routines should provide sufficient examples.
⊗
;STRGC, Definitions
NOLOW <
MLT←←=16 BKSZ←←5*MLT+1 ;BKSZ must always be so related to MLT
↑.CORERR:
CORERR <NO CORE FOR ALLOCATON>
HERE (STRGC)
EXCH A,-1(P) ;THE DESIRED A IS HERE
MOVE USER,GOGTAB
MOVEM RF,RACS+RF(USER);SAVE F REGISTER WHERE GC CAN FIND.
PUSHJ P,STRNGC ;COLLECT TRASH
SUB P,X22 ;BACK UP STACK
MOVNS A
ADDM A,REMCHR(USER)
MOVE A,1(P) ;GET ORIGINAL "A" BACK
JRST 2,@2(P) ;RETURN
;STRNGC -- Init, CALSGL, SGSWEP -- main loop through space sorting
HERE(STRNGC)
MOVE USER,GOGTAB
;!BUG TRAP! remove after reverence for F is established
CAME RF,RACS+RF(USER) ;ALL RUNTIMES SHOULD BOTH
ERR <DRYROT -- RF (R12) not saved in RACS at STRNGC>
;!END BUG TRAP! -- LATER THE NECESSITY TO SAVE WILL BE PHASED OUT.
MOVEM RF,RACS+RF(USER) ;WILL RESTORE AFTER SORTING ROUTINES
SKIPN SGCTIME(USER) ;User can
JRST SGC1
MOVEI TEMP,0 ;TIME SG STARTS
;!HOOK! Conditional assembly for CMU, TENEX system timing goes here.
CALL6 (TEMP,MSTIME)
MOVNM TEMP,SGCTIME(USER)
SGC1: MOVEM 11,SGACS+11(USER)
MOVEI 11,SGACS(USER)
BLT 11,SGACS+10(USER)
AOS TEMP,SGCCNT(USER) ;COUNT TIMES THROUGH GC
MOVNM TEMP,SGCCNT(USER) ;INDICATE THAT GC IS IN PROGRESS
;;% % CMU-TYPE TRAP CALL
SKIPN .SGCINT
JRST NOTRP
;;#QA# RHT & DCS THE ARGS TO THIS WERE WRONG
PUSH P,A ;SIZE OF REQUEST
PUSH P,0 ;CONVENTION IS 4 PARAMS
PUSH P,SGCCNT(USER)
PUSH P,0 ;SO PUSH SOME [CENSORED] UP
PUSHJ P,@.SGCINT
NOTRP:
;;% %
HRRZ TEMP,TOPBYTE(USER) ;MAKE SURE DIDN'T OVERFLOW
CAMG TEMP,STTOP(USER)
CAMGE TEMP,ST(USER)
ERR <TOPBYTE out of range at STRNGC -- will continue>,1
; List the String Descriptors
CALSG: MOVEI T,SGROUT(USER) ;GET LINKED LIST OF ROUTINE NAMES
PUSH P,T ;SAVE FIRST POINTER
PUSH P,[SGSORT] ;PROVIDE ACCESS TO SORTING ROUTINE
↑CALSGL:
SKIPN T,@-1(P) ;GO DOWN LIST UNTIL DONE
JRST ALLCOL ;DONE
HRRZM T,-1(P) ;SAVE NEW POINTER
PUSHJ P,@-1(T) ;CALL GENERATOR ROUTINE
MOVE RF,RACS+RF(USER) ;GET GOOD F BACK, ASSUMING GOOD USER
JRST CALSGL ;DO MORE THAN ONCE
ALLCOL: SUB P,X22 ;Remove temp, SGSORT address
; Sort all spaces
; Allocate a BKSZ-word bucket. Then, for each space, look at each
; descriptor, partition it (by starting location within the space)
; into one of the buckets, then sort it into the list of strings
; so partitioned, in an order specified in the SRTSPC comments.
; Finally, for each space, create a single linked list of sorted
; descriptors.
SGSWEP: MOVEI C,BKSZ
PUSHJ P,CORGET
STCORERR: ERR <String garbage collector can't get core>
MOVEM B,STBUCK(USER)
; Space Sorting Loop
MOVE B,STLIST(USER) ;Loop through all string spaces,
SETZM SGCNUM(USER) ;Strings handled count (not incl. const.)
;<** B => current space throughout
SPCLUP: PUSHJ P,SRTSPC ; sorting. When through, .LIST
SKIPE B,.NEXT(B) ; in the header of each space
JRST SPCLUP ; will be the sorted dscrptr lst.
;STRNGC -- SWPLUP -- main sweep (string moving) loop
; Move the strings, and update the descriptors. Two routines,
; SOURCE and DEST, maintain information about old and new string
; locations, respectively, and other state info needed to move the
; strings. Each is responsible for switching from space to space
; when necessary.
MOVE B,STBUCK(USER) ;Release the buckets (STBUCK=OFFSET, see blow).
PUSHJ P,CORREL
;Initialize source, destination space pointers.
MOVE B,STLIST(USER)
MOVE C,B
PUSHJ P,DSTSET
;**B is Source Space Pointer throughout
;**C is Destination Space pointer throughout
SWPLUP: PUSHJ P,SOURCE ;Identify a source "nest", return params
JRST SWPDUN ; and adjust descriptors, no-skip when done
PUSHJ P,DEST ;Identify a destination location, move the
JRST SWPLUP ; source nest there, and re-create all
; descriptors, adjusted for destination.
;STRNGC -- SWPDUN -- expansion/contraction, parameter update
SWPDUN:
;<** C => last dest. space
;** TOPBYTE, REMCHR correct for C's dest. space
; 1. Get room for request + desired free space (see ALLOC), either
; from a new space block, or from empty spaces between C's and
; A's, if there are any
; 2. Release from "C+1" to and including the last space (shrink string space)
; 3. Clean up, zero remaining free space, quit.
;!HOOK! Here, if you made a decision to move the last destination
; space, you should do it -- see below for more about this.
HLRZ D,STREQD(USER) ;Requested char count +
ADD D,SGACS+A(USER) ; STREQD (see p. 2) char count.
MOVE E,D
;**E is total required empty space -- valid until GRANTED, below.
GRANT: ADD D,REMCHR(USER) ;Granted, if total required
JUMPL D,GRANTED ; space exists in last DEST
PUSHJ P,WASTE ;Add up wasted space in DEST being left.
MOVE A,C ;Save space being abondoned
SKIPN C,.NEXT(C) ; space. Otherwise, move
JRST EXPSTR ; to next space, if any, and
GRTSET: PUSHJ P,DSTSET ; continue to try to grant
MOVE D,E ; request
JRST GRANT
;<** A => previous DEST Space, get another
EXPSTR: HLRZ C,STINCR(USER) ;STINCR (see p. 2) char count.
CAML E,C ;Is there going to be room?
ERR <String space expansion: request too big>
HRRZ C,STINCR(USER) ;STINCR word count, + .HDRSIZ
PUSHJ P,CORGET
JRST [PUSHJ P,CORBIG ;If for some reason we can't get
MOVEI B,.HDRSIZ+1(C) ; STINCR words, make sure that
IMULI B,5 ; a new block can at least satisfy
CAMGE B,E ; the request + STREQD.
ERR <String GC: no core to expand string space>
PUSHJ P,CORGET ;Will do, get it
ERR <DRYROT -- unexpected STRNGC core problem>
JRST .+1]
MOVEI B,.HDRSIZ(B) ;Adjust pointer to leave header,
SUBI C,.HDRSIZ ; set up header area parameters,
MOVEM C,.STTOP(B) ; link to previous area
MOVEM C,.SIZE(B)
ADDM B,.STTOP(B)
SETZM .NEXT(B)
SETZM .LIST(B)
MOVEM B,.NEXT(A)
MOVE C,B ;This becomes last destination
JRST GRTSET ;Go satisfy request, now guaranteed.
GRANTED:HRRZM C,ST(USER) ;Update ST, STTOP, release any
MOVE TEMP,.STTOP(C) ; spaces made unnecessary by diminished
MOVEM TEMP,STTOP(USER) ; active strings
SKIPN A,.NEXT(C) ;Get next space past last DEST, if any,
JRST STSTAT ; then clear any next space pointers.
SETZM .NEXT(C)
RELLUP: MOVEI B,-.HDRSIZ(A) ;Release any spaces which are
PUSHJ P,CORREL ; apparently no longer necessary.
SKIPE A,.NEXT(A)
JRST RELLUP
;STRNGC -- STSTAT -- Finish Up, collect statistics
STSTAT: ;Check that Full-word alignment produced
SKIPE SGLIGN(USER) ;Alignment also implies clearing
PUSHJ P,RESCLR ;Free space
MOVEI B,=15 ;Update REMCHR by initial request, plus a
ADD B,SGACS+A(USER) ; bit of slop (NOT by STREQD, which specifies
ADDB B,REMCHR(USER) ; free space -- slop is unfree, for safety.)
JUMPGE B,[ERR <DRYROT -- String GC Surprised at Untoward Occurrence>]
MOVMS SGCCNT(USER) ;Now indicate done with GC
SKIPN SGCTIME(USER) ;Timing active?
JRST NOTIME ;No
MOVEI TEMP,
;!HOOK! Insert, conditionally, other system timing calls
CALL6 (TEMP,MSTIME) ;Collect GC times
ADDB TEMP,SGCTIME(USER)
ADDM TEMP,SGCTOTAL(USER)
NOTIME:
;;% % CMU-STYLE TRAP -- I DON'T SUPPLY ALL THE SAME INFO AS LDE DID AT CMU
SKIPN .SGCINT
JRST QUITGC
MOVN TEMP,REMCHR(USER);SIZE OF GRANT, LESS ORIGINAL REQUEST
PUSH P,TEMP
PUSH P,SGACS+1(USER) ;ORIGINAL REQUEST
PUSH P,SGCCNT(USER) ;AS FAR AS I CAN TELL, JUST USING UP CELLS
PUSH P,SGCNUM(USER) ; IN THE CALL STACK
PUSHJ P,@.SGCINT
;;% %
QUITGC: MOVE USER,GOGTAB ;PARANOID
HRLZI 11,SGACS(USER) ;Restore and return
BLT 11,11
POPJ P,
;STRNGC Service routines -- SGSORT
;Sgsort
;<A is => descriptor
;1. Ignore constants
;2. Check legality, go easy on null strings
; issues: Recover gracefully from bad strings
; Report complete info about bad strings
; Try to supply name of descriptor source for
; bad strings (stack, vbl, array, other)
;3. In // with above, find proper string space for each str.
;4. Link in string # field (lh word 1) -- separate list for each space
SGSORT: HLLZ B,(A) ;don't collect constants
JUMPE B,SGRST
; Loop on string spaces, find the one containing this string
HRRZ TEMP,1(A)
MOVEI B,STLIST-.NEXT(USER)
SGLUP1: SKIPN B,.NEXT(B)
JRST NORANGE ;Range exhausted, bad string
CAML TEMP,B ;Address check of string bp
CAML TEMP,.STTOP(B) ; against both ends of each
JRST SGLUP1 ; space determines if string in range
INRANGE:SUB TEMP,B ;Convert bp to space-relative
IMULI TEMP,5 ; character count
HLLZ C,1(A)
TLNN C,777770 ;Make sure there are still byte ptr. bits
;Max possible start count is 4,,777777
JRST [MOVE A,A ;ERR type 7 gets AC # from here
ERR <SGSORT-- string encountered twice, descriptor addr = >,7
JRST SGRST] ;Don't handle again.
HRRI C,[BYTE(7) 0,1,2,3,4,5]
ILDB C,C ;Space-relative count fits in
ADD C,TEMP ; rh, lh 0 signals
MOVEM C,1(A) ; re-encounter (above)
MOVE C,.LIST(B) ;Insert descriptor, linked by
HRLM C,(A) ; string number field, into
HRRZM A,.LIST(B) ; list for this space
JRST SGRST
NORANGE:MOVE A,A ;String not in range, complain, NULL it,
ERR <String GC: Descriptor byte ptr. out of bounds, Addr. is >,7
SETZM (A) ; and go on.
SGRST: ADDI A,2 ;Auto-increment descriptor index
POPJ P,
;STRNGC Service routines -- SPGC,STRMRK, etc. -- Descriptor providing routines
; ------ SORT THE SP STACK ------
HERE(%SPGC) HRRZ A,SPDL(USER) ;START AT BASE OF STACK
↑%SPGC1:ADDI A,1
JRST SGTST ;AND WORK UP TO CURRENT POINTER
STRNGSTACKMARKLOOP:
PUSHJ P,SGSORT ;SORT IT INTO LIST
SGTST:
CAIGE A,(SP) ;DONE?
JRST STRNGSTACKMARKLOOP ;NO
GPOPJ: POPJ P, ;YES, GO ON TO NEXT TYPE
; ------ SAIL COMPILER SPECIAL SORTERS ARE IN COMSER ------
; ------ SORT THE VARIABLES ------
HERE (%STRMRK)
SKIPN T,STRLNK(USER) ;GET LINK
POPJ P, ; NO STRINGS AT ALL
STMKL1: HRRZ A,-1(T);< ;=>1ST STRING
HLRZ Q2,-1(T) ;# STRINGS THIS PROC
JRST SOJLP ;GO LOOP
STMKLP: PUSHJ P,SGSORT ;SORT VARIABLES INTO LIST
SOJLP: SOJGE Q2,STMKLP ;SORT UNTIL DONE WITH THIS PROC (SGSORT INCRS A)
STRMK4: HRRZ T,(T) ;NEXT PROCEDURE
JUMPN T,STMKL1 ; IF THERE IS ONE
POPJ P, ;DONE
COMMENT *
------ SORT STRING ARRAYS ------
THIS ROUTINE TRIPS DOWN THE DYNAMIC LINKS, LOOKING INTO
PROCEDURE DESCRIPTORS FOR STRING ARRAYS WHICH MIGHT HAVE BEEN ALLOCATED.
THEN IT LOOKS FOR ANY ARRAYS OWNED BY LEAP. THE FIRST
WORD OF EACH ARRAY BLOCK IS THE NUMBER OF DIMENSIONS IF THE
ARRAY IS A STRING ARRAY. THE WORD JUST PREVIOUS TO IT IS THE
(NEGATIVE) SIZE OF THE ARRAY.
*
INTERNAL %ARRSRT
HERE (%ARRSRT)
; HRRZ RF,RACS+RF(USER);REAL RF WITH LH= 0 (ASSUME SET UP 12-3-73)
↑%ARSR1:
PROCDO: HLRZ Q1,1(RF) ;FETCH PDA
CAIN Q1,SPRPDA ;IS IT SPROUTER??
POPJ P, ;YES
MOVE Q1,PD.LLW(Q1) ;WE HAVE TO DO SOMETHING -- PT AT LVI
CHK: SKIPN T,(Q1) ;GET ENTRY
JRST GODOWN ;0 MEANS OF PROC DESCR
;;#HI#.! 5-15-72 DCS WAS TESTING 200000 (TYPE 4?) BIT, WRONG BIT!
TLC T,100000 ;TYPE 2? (STRING ARRAY)
TLNE T,740000 ;
AOJA Q1,CHK ;NO
SKIPN A,@T ;THERE??
AOJA Q1,CHK ;NO
;;# # 5-3-72 DCS
SUBI A,1;< ;A=>2D WORD, FIRST ENTRY -- DCS 5-3-72
;;# #
SKIPL Q2,-1(A) ;BETTER BE THERE
ERR <DRYROT at Arrsrt>
PUSHJ P,ARPUTX ;GO SORT IT
AOJA Q1,CHK
GODOWN: HRRZ RF,(RF) ;NOTE THAT RESTR WILL PUT RF BACK
CAIE RF,-1 ;
JRST PROCDO ;-1 WILL SAY END
LARR: SKIPN E,ARYLS(USER) ;LEAPING LISTS
POPJ P, ;NONE
LAR1:
HLRZ Q2,(E) ;GET ADDRESS
;;# # 5-3-72 DCS SET UP A
MOVEI A,-1(Q2);< ;A=>1ST WORD, FIRST ENTRY
;;# #
SKIPL Q2,-2(Q2) ;BE SURE
ERR <DRYROT -- LEAPing error at ARRSRT>
PUSHJ P,ARPUTX ;GO SORT IT
LAR2: HRRZ E,(E) ;MERRILY WE LINK ALONG
JUMPN E,LAR1 ;
POPJ P, ;HOME AT LAST
ARPUTX:
HRRZS Q2 ;YES, GET TOTAL SIZE
LSH Q2,-1 ;NUMBER OF STRINGS
JRST ARSLP
ARS3: PUSHJ P,SGSORT ; BUT COLLECT NON-CONSTANTS
ARSLP: SOJGE Q2,ARS3 ;A INCREMENTED IN SGSORT, LOOP UNTIL DONE
POPJ P, ;ALL DONE WITH THIS ARRAY.
;STRNGC Service routines -- SRTSPC -- space sorter
;Space Sorter
;<** B => A string space, descriptor list is .list(b)
SRTSPC: MOVE A,STBUCK(USER) ;Clear bucket list
SETZM (A)
ADDI A,1
HRLI A,-1(A)
MOVEI C,BKSZ-2(A)
BLT A,(C)
SKIPN A,.LIST(B)
JRST SORTED
;<** A => word 1 of NEW descriptor
DSCLUP: AOS SGCNUM(USER) ;Count strings handled.
HLRZ FF,(A)
MOVE C,1(A)
MOVE E,C ;For later (below)
IMULI C,MLT
IDIV C,.SIZE(B) ;Compute bucket entry
ADD C,STBUCK(USER) ; (partition space among bckts)
MOVE Q1,C
HRRZ T,(A)
SGSLUP: MOVE D,C
HLRZ C,(C)
;<** Q1 => bucket entry, for end-pointer maintenance (just below)
;<** D => PREV descriptor, which has been seen
;<** C => NEXT descriptor, to be examined
;** E is starting count of NEW rel. to this space
;** T is length(NEW)
;Sort NEW into this bucket list such that its starting count is >=
; all which precede it, <= all which follow it. Where starting
; counts are equal, sort by descending length. This creates nests
; of strings to be handled by the sweep phase.
JUMPE C,[HRRM A,(Q1) ;** NEW will be end string,
JRST INSERT] ; keep track of it for linkage
CAMGE E,1(C)
JRST INSERT ;NEW begins before NEXT, insert
CAME E,1(C)
JRST SGSLUP ;NEW begins after NEXT, keep looking
HRRZ TEMP,(C)
CAMG T,TEMP ;Insert by descending length
JRST SGSLUP
; (JRST INSERT)
;<** A => NEW, 1st word
;<** C => NEXT, 1st word, or is 0
;<** D => PREV, 1st word, or bucket
;** E is start count from descriptor
;Standard one-way linked list insertion
INSERT: HRLM A,(D)
HRLM C,(A) ;Link is in lh of word 2 of descriptor
;Sort next descriptor from this space
MOVE A,FF
JUMPN A,DSCLUP
;Now use list pointers in buckets
; (each is <first,,last>)
; to create one sorted list -- store in .LIST(this space)
SORTED: MOVE C,STBUCK(USER) ;Starting at the end of the bucket
HRLI C,D ; array, look only at non-zero
MOVEI D,BKSZ-1 ; entries. Each iteration, retain
MOVEI A,0 ; the newest <first> pointer, having
LNKLUP: SKIPN E,@C ; placed the previous <first> pointer
JRST AOCHK ; into the list identified by the
HRLM A,(E) ; newest <last> pointer. The first
HLRZ A,E ; <first> pointer is 0
AOCHK: SOJGE D,LNKLUP
MOVEM A,.LIST(B)
POPJ P,
;STRNGC Service routines -- SOURCE and DEST
;SOURCE:
;<** B => source space
;<** .LIST(B) => first descriptor of next nest to move, or 0 (space done)
;
; 1. Move to next space, if necessary -- this one done. No-skip if no more.
; 2. Create BP to start of nest, save. Save first space-relative count.
; 3. Move down list, identify end of nest -- convert all descriptor
; counts to nest-relative counts
; 4. Update .LIST
; 5. Skip (found a nest) Return:
; A -- BP to source string (nest)
; D -- total # chars in nest
;< E -- =>first in nest -- last link in nest zeroed
; 6. Non-skip (no more nests) Return.
; 7. Don't change C!!!
SOURCE: MOVE E,.LIST(B)
JUMPE E,[SKIPN B,.NEXT(B)
POPJ P, ;no-skip, return
JRST SOURCE]
MOVE Q1,1(E)
IDIVI Q1,5
ADD Q1,B
HLL Q1,[PTBL1: POINT 7,0 ;!HOOK! IF PTBL OF SUBSTR AVAIL,
POINT 7,0,6 ; declare it external and use it
POINT 7,0,13 ; here -- tables are the same
POINT 7,0,20
POINT 7,0,27
POINT 7,0,35](Q2)
PUSH P,Q1
HRLS E
MOVN A,1(E)
HRRZ D,(E)
SUB D,A
ADDM A,1(E) ;Adjust 1st descr. location count to nest-rel.
;** A is -(nest start char)
;** D is Nest end char +1
;<<** E is => first elt of nest,, => current elt.
;** First nest descriptor already count-relative adjusted
;Loop until a descriptor is not in the nest
SRCLUP: HLRZ Q1,(E) ;Next elt.
JUMPE Q1,NONEST ;If end-loc in D does not reach the next
CAMG D,1(Q1) ; descriptor's location, nest is done
JRST NONEST ;(Adjoining, non-overlapping nests must be
HRRZ TEMP,(Q1)
ADD TEMP,1(Q1) ; moved separately because of full-word reqmt.
CAMGE D,TEMP ;Adjust nest-end location, if new string
MOVE D,TEMP ; extends beyond old nest
ADDM A,1(Q1) ;Adjust location count to nest-relative.
HRR E,Q1 ;Will be last descriptor in nest at NONEST
JRST SRCLUP
NONEST: HRRZM Q1,.LIST(B) ;Update list, retrieve BP, compute length,
HRRZS (E) ;Clear last elt in nest
HLRZS E ;Return ptr. to 1st, as advertised
ADD D,A ; skip-return as advertised
POP P,A
AOS (P)
POPJ P,
;DEST:
;** B inviolate
;<** C => dest space
;** TOPBYTE(USER) is free in current dest space
;** REMCHR(USER) is -(number remaining) in current dest space
;<** E is =>first in nest -- last elt. is zeroed
;** D is nest size in chars
;** A is nest source byte pointer
; 1. Adjust to FW bdry if SGLIGN
; 2. Find room, this dest space or next -- error if out of spaces.
; 3. Adjust REMCHR
; 4. Move nest, adjust TOPBYTE
; 5. Recreate BP for each descriptor
DEST: MOVE Q1,D ;SAVE LENGTH
;** Q1 is original nest length, will remain so until FIXLP 1st pass
DEST1: SKIPN SGLIGN(USER)
JRST NOLIGN
PUSHJ P,INSET ;Inset aligns TOPBYTE to full word,
PUSH P,D+1 ; but it should already be there really.
ADDI D,4 ;Move smallest multiple of 5 characters
IDIVI D,5 ; which hold nest.
IMULI D,5
POP P,D+1
;** D is nest length, possibly adjusted for sglign
NOLIGN: ADDM D,REMCHR(USER) ;Standard room test
SKIPGE REMCHR(USER)
JRST ISROOM
;!HOOK! If you decided to move the DEST being left (in DSTSET, see below),
; Do it now. Move it to (C)+OFFSET(USER).
NOROOM: PUSHJ P,WASTE ;Count waste in space being left
HRRZ C,.NEXT(C) ;Since we are moving strings "down",
JUMPE C,[ERR <DRYROT -- No more room for strings -- very strange>]
; running out of already existent
PUSHJ P,DSTSET ; space is a fatal error.
JRST DEST1 ;Try again, C, REMCHR, TOPBYTE are adjusted.
ISROOM: MOVE FF,TOPBYTE(USER)
CAME A,FF ;Avoid moving the nest to its previous
JRST MVTST ; location (expensive NO-OP).
JRST MVDON
MVLP: ILDB TEMP,A
IDPB TEMP,FF
MVTST: SOJGE D,MVLP
MOVE FF,TOPBYTE(USER) ;FF←BP of first char
MVDON: MOVSI A,40 ; in destination nest
MOVE D,E ;First, adjust TOPBYTE, then
MOVEI E,TOPBYTE-1(USER) ; the strings of the nest
LDB TEMP,[POINT 3,FF,5]
;<**E => current descriptor in nest or topbyte, starting with latter
;**A's LH is non-zero "string number" value -- strings aren't constants
;**FF is BP to 1st nest destination character.
;For each descriptor, Store string number, create a new byte pointer
; (algorithm stolen from SUBSTR routine)
TRC TEMP,4
JRST FIXTOP ;Start in middle to get topbyte
FIXLP: HLRZ D,(E)
;<**D => next descriptor
;**TEMP is character offset of FF-pointer in its word (for computing BP's)
HLLM A,(E) ;Update string number
MOVE Q1,1(E) ;Compute new BP -- see SUBSTR in STRSER
FIXTOP: MOVE T,FF
ADD Q1,TEMP
CAILE Q1,4
JRST [CAILE Q1,9
JRST [IDIVI Q1,5
ADD T,Q1
HLL T,PTBL1(Q2)
JRST PTWY]
SUBI Q1,5
AOJA T,.+1]
HLL T,PTBL1(Q1)
PTWY:
;!HOOK! ADD T,OFFSET(USER) ;activate when space-moving becomes reality.
;; !! But topbyte fix is messed up some by this, watch it.
MOVEM T,1(E) ;Store new BP, to descriptor or topbyte
MOVE E,D ;loop
JUMPN E,FIXLP
POPJ P,
;DSTSET:
;<** C => destination space
;Result: TOPBYTE(USER) is destination byte pointer -- to beginning of space
; REMCHR(USER) is -(size of space in characters)
DSTSET: HRLI C,(<POINT 7,0>)
MOVEM C,TOPBYTE(USER)
MOVN TEMP,.SIZE(C)
IMULI TEMP,5
MOVEM TEMP,REMCHR(USER)
;!HOOK! This is probably the best place to decide, perhaps to minimize
; checkerboarding or memory use, that the DEST just prepared should be
; moved to a new location. This move will not happen until the space
; has been filled, and all descriptors for it adjusted. Decide where
; to move the block, then put the difference between its future location
; and its current one into OFFSET(USER). The DEST routine will use this
; to adjust all descriptor byte pointers.
POPJ P,
;When leaving a DEST for a new one, keep track of the unfilled space
; within that space.
WASTE: PUSH P,TEMP+1
MOVN TEMP,REMCHR(USER) ;Unused characters this space
IDIVI TEMP,5 ;Just rough estimate.
POP P,TEMP+1
ADDM TEMP,SGCWASTE(USER)
POPJ P,
;STRNGC Service routines -- SGINS and SGREM
;Sgins, Sgrem
DSCR SGINS
CAL PUSHJ
PAR PUSH P,[routine name]
PUSH P,[addr of 2-word block]
RES block is used to place routine in the list of descriptor generators
for CALSG.
SID stack adjusted
⊗
HEREFK(SGINS,.SGINS)
PUSH P,-2(P) ;ADDR OF ROUTINE
PUSHJ P,SGREM ;NEVER LET IT BE IN TWICE
MOVE USER,GOGTAB
POP P,UUO1(USER)
POP P,LPSA;< ;=>LINK BLOCK FOR NEW ROUTINE
POP P,-1(LPSA) ;PUT ROUTINE ADDRESS AWAY
HRL LPSA,SGROUT(USER);GET OLD LINK POINTER
HLRM LPSA,(LPSA) ;PUT IN NEW LINK POSITION
HRRM LPSA,SGROUT(USER);PUT NEW POINTER IN LINK HEAD
JRST @3(P) ;RETURN
DSCR SGREM
CAL PUSHJ
PAR PUSH P,[routine addr]
RES routine is removed from list of descriptor generators, if it was on it
⊗
HEREFK(SGREM,.SGREM)
MOVE USER,GOGTAB
POP P,UUO1(USER)
POP P,TEMP ;ADDR TO BE REMOVED
MOVEI LPSA,SGROUT(USER);HEAD OF LIST
SGRL: MOVE USER,LPSA ;PREV←THIS
SKIPN LPSA,(USER) ;THIS←(PREV)
JRST @2(P) ;DIDN'T FIND IT
CAME TEMP,-1(LPSA) ;IS THIS THE ROUTINE?
JRST SGRL ;NO, GET NEXT
HRRZ TEMP,(LPSA) ;YES, REMOVE IT FROM LIST
HRRM TEMP,(USER)
JRST @2(P)
;STRNGC Service routines -- STCLER and RESCLR
DSCR STCLER
CAL PUSHJ
RES Clears all string variables on STRLNK(USER) to null strings
DES compiler only
⊗
HEREFK(STCLER,.STCLR) ;
SKIPE SGLIGN(USER) ;CLEAR REST?
PUSHJ P,RESCLR ;CLEAR REST OF STRING SPACE
SKIPN T,STRLNK(USER) ;PARALLELS STRNGC'S LOOP
POPJ P, ;CLOSELY
PUSH P,B ;JUST IN CASE
HRLZI B,-1 ;FOR TESTING STRING NO.
STC1: HRRZ A,-1(T)
HLRZ Q2,-1(T)
STCLLP: SOJL Q2,STCLD1
TDNE B,(A) ;DON'T COLLECT STRING CONSTANTS
SETZM (A)
ADDI A,2
JRST STCLLP
STCLD1: HRRZ T,(T)
JUMPN T,STC1
POP P,B
POPJ P,
DSCR RESCLR
CAL PUSHJ
DES Used after STRNGC. Clears remaining string space to 0 (compiler only)
⊗
RESCLR: SKIPL A,TOPBYTE(USER) ;CAN ZERO FIRST WORD IF 440700
ADDI A,1 ;ELSE START AT NEXT
SETZM (A)
HRLS A
ADDI A,1 ;BLT WORD
MOVE B,STTOP(USER) ;END OF STRING SPACE
BLT A,-1(B) ;ZERO!!
POPJ P,
INTERNAL BRKMSK
↑BRKMSK: 0
FOR @& JJ←=17,0,-1 <
<1 ⊗ (JJ+=18)> + (1 ⊗ JJ)>
>;NOLOW
ENDCOM (SGC)
IFN ALWAYS,<
NOLOW <
↑CORGET←CORGET
>;NOLOW
>;IFN ALWAYS
SUBTTL GOGOL
SUBTTL Some Runtime Routines Which Could Go Nowhere Else
DSCR BEGIN GOGOL
DES RUN-TIME ROUTINES WILL BE DESCRIBED BY SAIL MANUAL CALLING SEQUENCES ONLY
⊗
NOLOW <
IFN ALWAYS,<BEGIN GOGOL>
>;NOLOW
COMPIL(KNT,<K.ZERO,K.OUT>,<GETCHAN,GOGTAB>
,<K.ZERO, K.OUT -- PERFORMANCE COUNTING ROUTINES>)
COMMENT ⊗ Kounter Routines⊗
DSCR K.ZERO -- Zero out counters
CAL PUSHJ P,K.ZERO
RES The counter arrays of the sail program loaded are set to zero.
K.ZERO determines the location of the counter blocks via the loader
link chain (5) whose head is in the location KNTLNK(USER). If there
are no counters, the routine is essentially a NO-OP. SID All
registers used by K.ZERO are saved on entry and restored on exit. SEE
K.OUT
⊗
HERE(K.ZERO)
PUSH P,2 ;SAVE REGISTER 2
MOVE USER,GOGTAB
SKIPN 2,KNTLNK(USER) ;GET LINK TO COUNTERSS
JRST K.ZR2 ;THERE ARE NONE
PUSH P,3 ;SAVE OTHER REGS NEEDED
PUSH P,4
PUSH P,5
K.Z1: MOVE 3,2(2) ;GET SECOND IOWD OF HEADER BLOCK
MOVEI 4,2(3) ;GET <.KOUNT+1>
HRLI 4,-1(4) ;GET READY FOR BLT
HLRO 5,3 ;GET -COUNT
MOVN 5,5 ;MAKE THAT +COUNT
HRLI 5,3 ;PUT AN INDEX FIELD OF 3
SETZM -1(4) ;ZERO THE FIRST COUNTER
BLT 4,@5 ;ZERO THE REST
SKIPE 2,(2) ;GET THE NEXT SET OF COUNTERS
JRST K.Z1 ;ZERO THEM
POP P,5 ;RESTORE THE REGISTERS
POP P,4
POP P,3
K.ZR2: POP P,2
POPJ P, ;RETURN
DSCR K.OUT -- Write out counters
CAL PUSHJ P,K.OUT
RES The values of the statement counters are written out to the
disk. The IOWDs used to write them are also written out in
order to be able to know how many to read back in. The filename
is obtained from the header block of the first program loaded.
The data blocks have the following form:
--------------------------
| SIXBIT /FILNAM/ |
--------------------------
| LINK to other blocks |
--------------------------
| IOWD 1,.+1 |
--------------------------
| IOWD n,.KOUNT |
--------------------------
| 0 |
--------------------------
.KOUNT: | 1st counter |
--------------------------
| . . . |
| . . . |
--------------------------
| nth counter |
--------------------------
SID No registers are permanently modified.
⊗
HERE(K.OUT)
MOVE USER,GOGTAB
SKIPN KNTLNK(USER) ;ARE THERE ANY COUNTERS
POPJ P, ;NO
COMMENT ⊗ First save registers 0-16
⊗
MOVEM 16,17(P) ;SAVE IN THE STACK
MOVEI 16,1(P) ;GET READY TO STORE 0-15
BLT 16,16(P) ;DO IT
ADD P,[XWD 17,17] ;ADJUST STACK POINTER
TLNN P,400000 ;CHECK FOR OVERFLOW
ERR <PDL overflow in K.OUT routine>
COMMENT ⊗ Before the counters can be written out, it
is necessary to chain the blocks together in the
proper direction. Recall that there will be multiple
blocks only if the core image is the result of loading
multiple compilatons.
⊗
MOVE 2,KNTLNK(USER) ;GET LINK TO LAST BLOCK
SKIPN 1,(2) ;GET LINK TO PREV.
JRST .+5 ;THAT'S ALL
MOVEI 0,1(2) ;GET ADDR OF 1st IOWD OF THIS BLOCK
MOVEM 0,3(1) ;STORE BELOW 2nd IOQS OF PREV BLOCK
MOVE 2,1 ;CONTINUE
JRST .-5
COMMENT ⊗ At this point, 1(2) contains the start of a dump
mode command chain that will write out all of the counters.
-1(2) contains the filename for the counter file.
⊗
PUSHJ P,GETCHAN ;GET AN AVAILABLE CHANNEL
JUMPL 1,K.OERR ;NONE AVAILABLE
MOVE 0,[XWD K.OD1,3] ;MOVE CODE TO REGISTERS
BLT 0,16 ;SO THAT IT CAN BE SAFELY MODIFIED
DPB 1,[POINT 4,3,12] ;STORE CHANNEL NUMBER IN OPEN INSTR
DPB 1,[POINT 4,5,12] ;STORE CHANNEL NUMBER IN ENTER INSTR
MOVE 10,-1(2) ;PICK UP FILE NAME
JRST 3 ;OPEN AND ENTER,HOPEFULLY RETURNING TO .+1
K.O1: MOVE 0,[XWD K.OD2,3] ;DO IT AGAIN
BLT 0,7
DPB 1,[POINT 4,3,12] ;OUT INSTRUCTION
DPB 1,[POINT 4,6,12] ;RELEAS INSTRUCTION
JRST 3
COMMENT ⊗ The counters have been written out to the disk. It's
time to restore the registers and go home.
⊗
K.O2: MOVSI 16,-16(P) ;PREPARE TO RESTORE REGS
BLT 16,16 ; FROM THE STACK
SUB P,[XWD 17,17] ;ADJUST STACK POINTER
POPJ P, ;RETURN
K.OERR: IOERR <I/O error in writing counter file>
COMMENT ⊗ The following instructions are moved into
registers before they are executed, since the "channel"
portion of them must be modified at run time.
⊗
K.OD1: OPEN 0,14 ;(3) OPEN DISK ON SPECIFIED CHANNEL
JRST K.OERR ;(4) TROUBLE
ENTER 0,10 ;(5)
JRST K.OERR ;(6) RIGHT HERE IN RIVER CITY
JRST K.O1 ;(7) READY TO WRITE 'EM OUT
0 ;(10) FILLED IN WITH FILE NAME
SIXBIT /KNT/ ;(11) EXTENSION
0 ;(12)
0 ;(13)
17 ;(14) DUMP MODE
SIXBIT /DSK/ ;(15) DEVICE DISK
0 ;(16) NO BUFFERS
K.OD2: OUT 0,1(2) ;(3) WRITE OUT COUNTERS
JRST 6 ;(4) ALL OK
JRST K.OERR ;(5) PROBLEMS
RELEAS 0 ;(6) CLOSE FILE
JRST K.O2 ;(7) GO BACK TO K.OUT
ENDCOM (KNT)
COMPIL(POW,<FPOW,POW,LOGS,FLOGS,EXP$,LOG$>
,<X11,X22,X33,OVPCWD>,<POW, FPOW, LOGS, FLOGS -- EXPON. ROUTINES>)
DSCR POW, FPOW, LOGS, FLOGS. BOTH RETURN REALS.
SID CLOBBERS LPSA,TEMP,USER
CAL SAIL
DES CALLS GENERATED BY COMPILER FOR ↑ OPERATOR
FPOW: REAL←FPOW(INTEGER!EXPONENT,REAL!BASE)
POW: REAL← POW(INTEGER!EXPONENT,INTEGER!BASE)
LOGS: REAL← LOGS(REAL!EXPONENT,INTEGER!BASE)
FLOGS: REAL←FLOGS(REAL!EXPONENT,REAL!BASE)
SPECIAL CASES:
A↑0 = 1
0↑B = 0 IF B GEQ 0.
0↑B = INF. IF B<0 ; MESSAGE PRINTED
A↑B = (-1)↑B*|A|↑B IF A<0, B INTEGRAL
A↑B = REALPART(A↑B) IF A<0, B NOT INTEGRAL ; MESSAGE
MESSAGE IS PRINTED IF OVERFLOW OR UNDERFLOW HAPPENS.
IN THIS CASE, FIXUP IS MADE SO THAT ANSWER IS EITHER 0, +INF, OR
-INF.
⊗
IFN ALWAYS,< BEGIN UTILS>
HERE(FPOW)
SKIPA USER,-1(P) ;BASE
HERE(POW)
FLOAT USER,-1(P)
FPX: MOVM LPSA,-2(P) ;GET ABS(EXPONENT)
JUMPE LPSA,EXZERO ;0 EXPONENT
MOVSI A,(1.0) ;SET FOR FLOATING
JRST 2,@[FEXS] ;CLEAR AR FLAGS
FEXL: ASH LPSA,-1 ;PREPARE TO LOOK AT NEXT BIT.
FMPR USER,USER ;SQUARE BASE
JFOV FPOWOV ;OVERFLOW/UNDERFLOW
FEXS: TRZE LPSA,1 ;COLLECT PRODUCT?
FMPR A,USER ;YES
JFOV FPOWOV ;OVERFLOW?
JUMPN LPSA,FEXL ;LOOP UNTIL EXPONENT ZERO.
SKIPGE -2(P) ;POSITIVE EXPONENT?
JRST FEXDU1
POWRET: SUB P,X33
JRST @3(P)
FEXDU1: MOVM LPSA,A ;CHECK FOR OVERFLOW POSS.
CAMGE LPSA,[XWD 2400,1] ;SMALL NUMBER
JRST FPDOV ;CALL UNDERFLOW
MOVSI LPSA,(1.0) ;TAKE RECIPROCAL OF ANS.
FDVRM LPSA,A
JRST POWRET ;AND RETURN IT.
EXZERO: SKIPN USER ;0↑0
ZRET: TDZA A,A ;RETURN 0
MOVSI A,(1.0) ;RETURN FLOATING 1
JRST POWRET
FPOWOV: SKIPN TEMP,OVPCWD ;IF TRAPS ENABLED, USE EM
JSP TEMP,.+1 ;ELSE GET FLAGS THIS WAY
TLNE TEMP,100 ;SKIP IF NOT UNDERFLOW
FPDOV: MOVNS -2(P) ;UNDERFLOW -- CHANGE EXPONENT SIGN.
MOVE A,[XWD 400000,1] ;LARGE NEGATIVE NUMBER
SKIPG TEMP,-2(P) ;CHECK SIGN OF EXPONENT.
MOVEI A,0 ;NEGATIVE ==> RESULT 0.
SKIPGE -1(P) ;CHECK SIGN OF BASE.
TRNN TEMP,1 ;XOR SIGN OF EXPONENT.
MOVNS A ;MAKE +- LARGE NUMBER
ERR <Exponentiation under or overflow>,1
JRST POWRET ;RETURN.
HERE(FLOGS)
.FLOGS: SKIPA USER,-1(P) ;FLOATING BASE
HERE(LOGS)
.LOGS: FLOAT USER,-1(P) ;FLOAT THE BASE
SKIPN -2(P) ;IF ZERO EXPONENT,
JRST EXZERO ;GO TO COMMON CODE.
MOVM TEMP,-2(P) ;CHECK TO SEE IF 'FIX' WILL
CAMLE TEMP,C1 ;OVERFLOW
JRST USLGEP ;YES -- GO TO LOG-EXP
FIX TEMP,-2(P) ;CHECK TO SEE IF EXPONENT
FLOAT LPSA,TEMP ;HAPPENS TO BE AN INTEGER
CAMN LPSA,-2(P) ;IF SO, USE LOOPS TO
JRST [MOVEM TEMP,-2(P) ;BE SURE OF CORRECT SIGN
JRST FPX]
USLGEP: JUMPE USER,[SKIPGE -2(P) ;IF BASE ZERO, AND EXPT NEG.
JRST FPDOV ;RETURN LARGE NUMBER
JRST ZRET] ;ELSE RETURN ZERO.
PUSH P,USER ;ARGUMENT TO 'ALOG'
PUSHJ P,.LOG ;CALL IT.
FMPR A,-2(P) ;MULTIPLY BY EXPONENT
PUSH P,A ;ARGUMENT TO 'EXP'
PUSHJ P,.EXP ;CALCULATE
JRST POWRET ;AND RETURN.
C1: 243777777777 ;2↑35 - EPSILON
DSCR EXP,ALOG -- FOR USE BY EXPONENTIATION ROUTINES & WORLD
SID CLOBBERS LPSA,TEMP,USER
CAL SAIL
⊗
;FLOATING POINT SINGLE PRECISION EXPONENTIAL FUNCTION
;THE ARGUMENT IS RESTRICTED TO THE FOLLOWING RANGE
; -88.028<X<88.028
;IF X<-88.028, THE PROGRAM RETURNS ZERO AS THE ANSWER
;IF X<88.028, THE PROGRAM RETURNS X AS THE ANSWER
;THE RANGE OF THE ARGUMENT IS REDUCED AS FOLLOWS:
;EXP(X) = 2**(X*LOG(E)BASE2) = 2**(M+F)
;WHERE M IS AN INTEGER AND F IS A FRACTION
;2**M IS CALCULATED BY ALGEBRAICALLY ADDING M TO THE EXPONENT
;OF THE RESULT OF 2**F. 2**F IS CALCULATED AS
;2**F = 2(0.5+F(A+B*F↑2 - F-C(F↑2 + D)**-1)**-1
;THE ROUTINE HAS THE FOLLOWING CALLING SEQUENCE:
; PUSH P,ARG
; PUSHJ P,EXP
;THE ANSWER IS RETURNED IN ACCUMULATOR A
HERE(EXP$)
.EXP: PUSH P,[0] ;ONE WORKING CELL
PUSH P,B ;AND ONE SAVED AC
MOVE LPSA,-3(P) ;GET ARGUMENT
MOVM A,LPSA ;GET ABSF(X)
CAMG A, E7 ;IS ARGUMENT IN PROPER RANGE?
JRST EXP1 ;YES, GO TO ALGORITHM
ERR <EXP: under or overflow>,1
HRLOI A, 377777 ;GET LARGEST FLOATING NUMBER
SKIPG LPSA ;WAS THE ARGUMENT POSITIVE?
MOVEI A, 0 ;NO, RETURN 0
JRST EXPXIT ;AND RETURN
EXP1: MULI LPSA,400 ;SEPARATE FRACTION AND EXPONENT
TSC LPSA,LPSA ;GET A POSITIVE EXPONENT
MUL TEMP,E5 ;FIXED POINT MULTIPLY BY LOG2(E)
ASHC TEMP,-242(LPSA) ;SEPARATE FRACTION AND INTEGER
AOSG TEMP ;ALGORITHM CALLS FOR MULT. BY 2
AOS TEMP ;ADJUST IF FRACTION WAS NEGATIVE
HRRM TEMP,B ;SAVE FOR FUTURE SCALING
JUMPG USER,ASHH ;GO AHEAD IF ARG GREATER THAN 0
TRNN USER,377 ;ALL THESE BITS 0?
JRST ASHH ;YES -- GO AHEAD
ADDI USER,200 ;NO -- FIX UP
ASHH: ASH USER, -10 ;MAKE ROOM FOR EXPONENT
TLC USER, 200000 ;PUT 200 IN EXPONENT BITS
FADB USER, -1(P) ;NORMALIZE, RESULTS TO USER AND E
FMP USER,USER ;FORM X↑2
MOVE A, E2 ;GET FIRST CONSTANT
FMP A, USER ;E2*X↑2 IN A
FAD USER, E4 ;ADD E4 TO RESULTS IN USER
MOVE LPSA, E3 ;PICK UP E3
FDV LPSA,USER ;CALCULATE E3/(F↑2 + E4)
FSB A,LPSA ;E2*F↑2-E3(F↑2 + E4)**-1
MOVE TEMP,-1(P) ;GET F AGAIN
FSB A, TEMP ;SUBTRACT FROM PARTIAL SUM
FAD A, E1 ;ADD IN E1
FDVM TEMP, A ;DIVIDE BY F
FAD A, E6 ;ADD 0.5
FSC A, (B) ;SCALE THE RESULTS
EXPXIT: POP P,B ;RESTORE AC
SUB P,X33 ;ADJUST STACK
JRST @2(P) ;RETURN.
E1: 204476430062 ;9.95459578
E2: 174433723400 ;0.03465735903
E3: 212464770715 ;617.97226953
E4: 207535527022 ;87.417497202
E5: 270524354513 ;LOG(E), BASE 2
E6: 0.5
E7: 207540071260 ;88.028
;FLOATING POINT SINGLE PRECISION LOGARITHM FUNCTION
;LOG(ABSF(X)) IS CALCULATED BY THE SUBROUTINE, AND AN
;ARGUMENT OF ZERO IS RETURNED AS MINUS INFINITY. THE ALGORITHM IS
;LOGE(X) = (I + LOG2(F))*LOGE(2)
;WHERE X = (F/2)*2↑(I+1), AND LOG2(F) IS GIVEN BY
;LOG2(F) = C1*Z + C3*Z↑3 + C5*Z↑5 - 1/2
;AND Z = (F-SQRT(2))/(F+SQRT(2))
;THE CALLING SEQUENCE FOR THE ROUTINE IS AS FOLLOWS:
; PUSH P,ARG
; PUSHJ P, LOG
;THE ANSWER IS RETURNED IN ACCUMULATOR A
HERE(LOG$)
.LOG:
SKIPGE -1(P) ;CHECK SIGN OF ARGUMENT.
ERR <LOG: Negative argument -- real part returned>,1
MOVM LPSA,-1(P) ;GET ABSF(A)
JUMPE LPSA, LZERO ;CHECK FOR ZERO ARGUMENT
CAMN LPSA, ONE ;CHECK FOR 1.0 ARGUMENT
JRST ZERANS ;IT IS 1.0 RETURN ZERO ANS.
ASHC LPSA, -33 ;SEPARATE FRACTION FROM EXPONENT
ADDI LPSA, 211000 ;FLOAT THE EXPONENT AND MULT. BY 2
MOVSM LPSA,USER ;NUMBER NOW IN CORRECT FL. FORMAT
MOVSI LPSA, 567377 ;SET UP -401.0 IN LPSA
FADM LPSA,USER ;SUBTRACT 401 FROM EXP.*2
ASH TEMP, -10 ;SHIFT FRACTION FOR FLOATING
TLC TEMP, 200000 ;FLOAT THE FRACTION PART
FAD TEMP, L1 ;TEMP = TEMP-SQRT(2.0)/2.0
MOVE LPSA,TEMP ;PUT RESULTS IN LPSA
FAD LPSA, L2 ;LPSA = LPSA+SQRT(2.0)
FDV TEMP,LPSA ;TEMP = TEMP/LPSA
MOVEM TEMP,A ;STORE NEW VARIABLE IN A
FMP TEMP,TEMP ;CALCULATE Z↑2
MOVE LPSA, L3 ;PICK UP FIRST CONSTANT
FMP LPSA,TEMP ;MULTIPLY BY Z↑2
FAD LPSA, L4 ;ADD IN NEXT CONSTANT
FMP LPSA,TEMP ;MULTIPLY BY Z↑2
FAD LPSA, L5 ;ADD IN NEXT CONSTANT
FMP A,LPSA ;MULTIPLY BY Z
FAD A,USER ;ADD IN EXPONENT TO FORM LOG2(X)
FMP A, L7 ;MULTIPLY TO FORM LOGE(X)
LOGXIT: SUB P,X22
JRST @2(P)
LZERO: ERR <LOG: Argument 0; minus infinity returned>,1
SKIPA A, MIFI ;PICK UP MINUS INFINITY
ZERANS: MOVEI A,0 ;MARG ANS ZERO
JRST LOGXIT ;AND RETURN
;CONSTANTS
ONE: 201400000000
L1: 577225754146 ;-0.707106781187
L2: 201552023632 ;1.414213562374
L3: 200462532521 ;0.5989786496
L4: 200754213604 ;0.9614706323
L5: 202561251002 ;2.8853912903
L7: 200542710300 ;0.69314718056
MIFI: 400000000001 ;LARGEST NEGATIVE FLOATING NUMBER
ENDCOM (POW)
COMPIL(COD,<CODE,CALL>,<.SKIP.,CVSIX,X22,GOGTAB,X33>,<CODE, CALL>)
DSCR VAL←CODE(OCTAL COMMAND, REFERENCE ARG);
⊗
Comment ⊗CODE
Reference arg is added to octal command. CODAC(USER)
is placed in AC 1. The constructed word is executed, and AC 1 resaved.
Isn't that clever? (AC1 is also returned as the value of the call)
⊗
HERE (CODE) MOVE USER,GOGTAB
SETOM .SKIP. ;ASSUME IT SKIPS
PUSH P,0
MOVE 1,CODAC(USER) ;GET USER'S AC
MOVE 0,-3(P)
ADDI 0,@-2(P) ;CALCULATE THE INSTR DO BE EXECUTED
XCT 0 ;DO IT
SETZM .SKIP. ;DIDN'T SKIP
MOVEM 1,CODAC(USER)
POP P,0
SUB P,X33
JRST @3(P)
DSCR VALUE←CALL(VAL,"FUNCTION");
CAL SAIL
⊗
↑↑.CALL:
HERE (CALL)
SETOM .SKIP. ;ASSUME A SKIP
PUSHJ P,CVSIX ;PARSE SIXBIT
MOVE TEMP,A ;SIXBIT FOR WHAT'S WANTED
MOVE A,-1(P) ;INPUT VALUE
CALL A,TEMP
SETZM .SKIP. ;NO SKIP, RECORD IT
SUB P,X22 ;RETURN VALUE IN 1, WANT IT OR NOT
JRST @2(P)
ENDCOM (COD)
IFN ALWAYS,<BEND UTILS>
SUBTTL STRING HANDLING ROUTINES