perm filename GOGOL[S,AIL]7 blob
sn#026181 filedate 1973-02-23 generic text, type T, neo UTF8
COMMENT ⊗ VALID 00054 PAGES VERSION 16-2(60)
RECORD PAGE DESCRIPTION
00001 00001
00005 00002 HISTORY
00010 00003 Command File Descriptions
00012 00004 Conditional Assembly Switches, Macros
00016 00005 Titles, Versions
00017 00006 AC Definitions
00018 00007 CDB, SIMIO Indices For IOSER, OTHER INDICES
00022 00008 Base (Low Segment) Data Descriptions -- Macros, Compil spec
00024 00009 Base (Low Segment) Data Descriptions - Params, Links, Size specs
00032 00010 Initialization Routines, Data
00034 00011 Sailor, Reent -- Allocation, Main Program Control
00037 00012 .SEG2. -- Get a second segment
00040 00013
00043 00014
00046 00015
00047 00016 Segment-Fetching Data
00050 00017
00051 00018 %ALLOC -- Main Allocation Routine
00057 00019
00064 00020
00068 00021
00071 00022 Utility Subroutines for allocation
00073 00023 %UUOLNK -- UUO Handler (Dispatch Vector Just Below)
00075 00024 ILLUUO, PDLOV, ERR UUO Handlers
00080 00025
00083 00026 Special Printing Routines For Error Handler
00086 00027 Code to Handle Linkage to Editors
00089 00028
00093 00029 DECPNT, OCTPNT, FIX, FLOAT UUOs
00095 00030 DSPLIN, etc.for Disp. Text Line on Error (Compiler)
00096 00031 SAVE, RESTR, INSET -- General Utility Routines
00100 00032 Core Service Routines -- General Description
00104 00033 Special AC Declarations
00105 00034 Utility Routines
00110 00035
00114 00036 CORGET
00118 00037
00120 00038 CORINC, CANINC
00125 00039 CORREL
00130 00040 CORPRT, CORBIG
00133 00041 String Garbage Collector Routines
00138 00042
00141 00043
00146 00044
00150 00045
00154 00046
00156 00047
00158 00048
00160 00049 Some Runtime Routines Which Could Go Nowhere Else
00161 00050 Kounter Routines
00163 00051
00169 00052
00171 00053
00172 00054
00174 ENDMK
⊗;
COMMENT ⊗HISTORY
AUTHOR,FAIL,REASON
031 202000000074 ⊗;
DEFINE .VERSION <202000000074>
COMMENT ⊗
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=CALLIS(LR)+HEAD+ORDER+GOGOL+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=CALLIS+HEAD+LOW+FILSPC+GOGOL/NOLO
TAILOR.REL,UPPER=CALLIS+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
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)
;;#HE# (1-2)
RELOC
LOC 124 ;SET UP REENTER ADDRESS
REENT
RELOC
>;NOUP
>;ALWAYS≠0
EXTERNAL JOBHRL
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 ↓Q←10
↓T←11 ↓CDB←11 ;CHANNEL DATA BLOCK PTR
↓T1←12 ↓CHNL←12 ;CHNL # FOR IOSER
↓LPSA←13 ;TEMP, PARAM AC
↓TEMP←14 ;TEMP ONLY
↓USER←15 ;→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 FORMAT OF CDBs
DMODE ←← 0 ↔↓IOSTATUS ←← 0 ;DATA MODE ;RETURN STATUS
DNAME ←← 1 ↔↓IOIN ←← 1 ;DEVICE ;BUFFERED INPUT
BFHED ←← 2 ↔↓IODIN ←← 2 ;HEADER POINTERS ;DUMP INPUT
↓IOOUT ←← 3 ;BUFMODE OUT.
OBPNT ←← 3 ↔↓IODOUT ←← 4 ;OUTPUT BUF. PTR ;DUMP OUTPUT
OBP ←← 4 ↔↓IOCLOSE ←← 5 ;OUTPUT BYTE PTR ;CLOSE FILE
OCOWNT ←← 5 ↔↓IORELEASE←← 6 ;OUTPUT BYTE CNT ;RELEASE FILE
ONAME ←← 6 ↔↓IOINBUF ←← 7 ;OUTPUT FILE NAM ;INBUF
OBUF ←← 7 ↔↓IOOUTBUF ←←10 ;OUTPUT BUFFER LOC. ;OUTBUF
↔↓IOSETI ←←11 ;USETI
IBPNT ←←10 ↔↓IOSETO ←←12 ;SAME FOR INPUT ;USETO
IBP ←←11 ↔ ; 13 UNUSED
ICOWNT ←←12 ↔↓IOOPEN ←←14 ;OPEN CHANNEL
INAME ←←13 ↔↓IOLOOKUP ←←15 ;LOOKUP FILE
IBUF ←←14 ↔↓IOENTER ←←16 ;ENTER FILE
↔↓IORENAME ←←17 ;RENAME FILE
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
PGNNO ←←20 ;PAGE NUMBER FOR DISPLAY FEATURE (IF FEATURE NOT INCLUDED)
NOEXPO <
PGNNO ←←21 ;SAME THING IF IT IS INCLUDED
>;NOEXPO
↑IOTLEN ←←PGNNO+1 ;LENGTH OF TABLE ENTRY
↓LUPDL←30 ;LENGTH OF UUO PDL
↓MINPDS←←=64 ;SMALLEST ALLOWABLE SYSTEM PDL SIZE
↓DEFPDS←←=192 ;DEFAULT PDL SIZE
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,K.ZERO>
,<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) ;→USER TABLE
XX (DATM,0,INTERNAL) ;XWD 3,→DATUM TABLE
XX (LKSTAT,0,INTERNAL) ;STATUS OF GLOBAL LEAP MODEL INTERLOCK (SHOULD BE IN GOGTAB
XX (INFTB,0,INTERNAL) ;XWD 2,→INFOTAB TABLE
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 REENTERS TO SPECIFY ALLOC
XX (CONFIG,0,INTERNAL) ;0 FOR RUNTIME, <0 FOR COMPILER
XX (ERRSPC,0,INTERNAL) ;ADDR OF COMPILER'S ERROR AUGMENTOR
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) ;≠0 →→ 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 (S1PARE,0) ;SPARE LOWER LOCATIONS
XX (S2PARE,0) ;SPARE LOWER LOCATIONS
XX (S3PARE,0)
XX (S4PARE,0)
XX (S5PARE,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)
SYSPHS←←2 ;TWO SYSTEM PHASES
USRPHS←←1 ;TWO USER PHASES (FOR 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)
XX (ALLPDP,<IOWD 20,ALLPDL>,INTERNAL);USED FOR A WHILE DURING ALLOC
XX (ALLPDL,<BLOCK 20>,INTERNAL,20) ;AND IN PROCESS TERMINATION
XX (%ALLCHR,0,INTERNAL)
XX (%OCTRET,0,INTERNAL)
XX (%ERGO,0,INTERNAL) ;ON IF LF TYPED TO ERR. GUY
XX (%RECOV,0,INTERNAL) ;ON IF RECOVERY FROM ERR. IS POSSIBLE
XX (DPYSW,0,INTERNAL) ;ON IF CONSOLE IS DPY
XX (%UACS,<BLOCK 20>,INTERNAL,20) ;UUOCON ACS
XX (%UPDL,<BLOCK LUPDL+1>,INTERNAL,LUPDL+1) ;UUOCON PDL
NOEXPO <
XX (PGDS,<PGDS0>,INTERNAL) ;PIECE OF GLASS FOR LINE BREAK ON INPUT
XX (,7,)
XX (PGDS0,0,)
XX (,<AIVECT (300,200)>,)
XX (,<ASCID /PAGE/>,)
XX (,<ASCID / />,)
XX (,<ASCID /LINE />,)
XX (,<ASCID / />,)
XX (,<DPYJMP PGDS0>,)
>;NOEXPO
;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)
;SINCE UUO TRIGGERING IS NON-RE-ENTRANT, THIS IS THE PLACE WHERE IT HAPPENS
XX (UUO0,0,INTERNAL) ;JSR RETURN STORED HERE
↓UUCOR←UUO0
NOUP <
JRST %UUOLNK ;GO HANDLE UUO
>;NOUP
LOW <
EXTERNAL LPINI
LPLK: 0
LPINI
0
LINK %INLNK,LPLK
>;LOW
EXPO <
XX (PPMAX,<BLOCK 3>,INTERNAL,3) ;FOR SCREWY EDITOR LINKAGE
>;EXPO
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
↑REENT: SETOM %RENSW ;RE-ENTER -- ASK FOR NEW ALLOC
;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
STRT: CALLI
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
MOVEI A,REENT ;"REE" ASKS QUESTIONS AGAIN
MOVEM A,JOBREN
PUSHJ P,K.ZERO ;ZERO OUT THE COUNTERS
PUSHJ P,INILST ;GO DO ALL OTHER INITIALIZATIONS
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
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, ;
INTERNAL .UINIT
.UINIT: MOVE A,[XWD -USRPHS,400000] ;DO USER PHASES
;; #KV# MAKE SURE LINK NON-NULL
SKIPN INILNK
POPJ P,
;; #KV#
JRST DOPHS
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⊂(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: TERPRI <SEGMENT LOGICAL NAME?>
JSR GGNAM ;GET A SEGMENT NAME.
GOTEM: MOVEM A,NMSAV
>;GLOB
NOGLOB <
MOVE A,[FILXXX] ;TRY TO FIND IT.
>;NOGLOB
CALLI A,400016 ;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
CALLI A,400016 ;ATTSEG.
JSP A,ERSEG
JRST (P) ;OK, GOT IT
>;NOEXPO
EXPO <
ASKEM: ;MISPLACED LABEL
>;EXPO
GETSE: CALLI
GLOB <
SKIPE A,SEGFIL ;WAS ONE "REQUIRE"D?
JRST THSFL ; YES, USE IT
TERPRI <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
TERPRI <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
TERPRI <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.
CALLI A,11 ;CORE UUO ----
JSP A,ERSEG
LOP22: INPUT 1,[LIOD: IOWD 200,%UPDL
0]
GLOB <
TLZ D,-1 ;NO, MAKE IT WRITEABLE IF GLOBAL MODEL.
>;GLOB
IFN NOPROT,<
TLZ D,-1 ;MAKE WRITEABLE IF REQUESTED TO
>;NOPROT≠0
CALL D,[SIXBIT/REMAP/] ;
JSP A,ERSEG
NOGLOB <
MOVE A,[FILXXX]
>;NOGLOB
GLOB <
MOVE A,NMSAV
>;GLOB
CALLI A,400036 ;SETNM2
JRST [MOVEI A,0
CALLI A,400015 ;CORE2
JSP A,ERSEG
GLOB <
SETOM %RENSW ;FORCE TTY RITUAL
>;GLOB
JRST SEGTR] ;TRY AGAIN.
CALLI
>;NOEXPO
EXPO <
SETZM SEGNAM+4 ;CLEAR LAST TWO WORDS OF GETSEG BLOCK
SETZM SEGNAM+5
MOVEI A,DEVSEG ;GET READY
MOVEM P,SAVPP
CALL A,[SIXBIT /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
>;LOW
EXPO <
NOUP <
INTERNAL TYPER.,OVPCWD,ERRMSG
;THESE ARE BECUSE OF LIB40 CHANGES
; MADE CAPRICIOUSLY BY DEC
TYPER.:
ERRMSG:
OVPCWD: 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: TERPRI <SAIL SEGMENT LOADING ERROR>
GLOB<
SETOM %RENSW ;FORCE TTY RITUAL
>;GLOB
CALLI 12
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 ; → SIXBIT
IDPB C,B ;SAVE IT.
JRST GGGO
>;GLOB
>;LOW
ENDCOM(LOR)
LOW <
END
>;LOW
COMPIL(LUP,<%UUOLNK,%ALLOC,SAVE,RESTR,STACSV,STACRS,INSET>
,<CORGET,STCLER,%RECOV,%UACS,GOGTAB,%UPDL,CONFIG,%ALLCHR>
,<INITIALIZATION ROUTINES, UUO HANDLER, UTILITY ROUTINES>)
IFE ALWAYS,<
INTERNAL %ALLOC
; MORE EXTERNALS
EXTERNAL ALLPDP,ERRSPC,SETLET,DPYSW,INILNK
EXTERNAL %ERGO,SPLNEK,UUO0,%OCTRET
EXTERNAL X11,X22,X44,CORINC,%STDLS,%RENSW,%SPL,KTLNK
>;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 =200 ;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 →next allocation block.
; T1 is →next entry specification
; Q1 is modified T1 -- accounts for STDSPC specifications
; Q2 is incoming OP-size word
; A is →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) ;→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 → 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≠0, OSIZ etc. -- then
NMIN∧¬OSIZ ⊃⊃ OSIZ←NSIZ, OMIN←TRUE
NMIN∧ OSIZ ⊃⊃ no change
¬NMIN∧NSIZ∧OMIN ⊃⊃ OSIZ←NSIZ, OMIN←FALSE
¬NMIN∧¬NSIZ∧OMIN ⊃⊃ no change
¬NMIN∧¬OMIN ⊃⊃ OSIZ←NSIZ+OSIZ, OMIN←FALSE
In the sequel,
A→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 ;¬NMIN∧¬OMIN, ADD
JUMPN Q2,%AL6 ;¬NMIN∧ OMIN, NSIZ?
TLOA Q3,MINSZ ;¬NMIN∧ OMIN∧¬NSIZ, NMIN←TRUE, NSIZ+OSIZ=OSIZ
%AL6: HLLZS TEMP ;¬NMIN∧OMIN∧NSIZ, OSIZ←FALSE,NSIZ+OSIZ=NSIZ,NMIN←FALSE
JRST ADDIT ;¬NMIN∧ OMIN, EITHER NSIZ OR OSIZ
; NMIN
INMIN: TRNE TEMP,-1 ;OSIZ?
TLZA Q3,MINSZ ;NMIN∧OSIZ, OSIZ unchg, NMIN←FALSE
TLZA LPSA,MINSZ ;NMIN∧¬OSIZ, OSIZ←NSIZ, NMIN←TRUE
MOVEI Q2,0 ;NMIN∧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 <
SKIPL $ITNO(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? >
TTCALL 0,B ;ASK LEADING QUESTION AND GET ANSWER
TERPRI
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
OUTSTR (A) ;PRINT IT
PRINT <= >
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: SKIPN %ALLCHR ;ARE WE BLABBING?
JRST SUBJMP ;NOPE
OUTSTR (A)
PRINT <: >
HLRZ C,A ;SIZE AGAIN
DECPNT C ;TOTAL ALLOC FOR THIS ONE
TERPRI
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 ;→RETURN ADDRESS (DUMMY AND SYSPDL ENTRIES)
; FINAL BOOKKEEPING
SETZM %RENSW ;DON'T ASK EACH TIME
MOVE SP,SPDL(USER) ;STRING STACK POINTER
MOVE B,ST(USER) ;STRING SPACE BEGINNING
MOVN C,-1(B) ;SIZE
SUBI C,3 ;MINUS OVERHEAD
MOVEM C,STMAX(USER) ;SIZE OF STRING SPACE DATA
HRLI B,(<POINT 7,0>)
MOVEM B,TOPBYTE(USER) ;NEXT FREE BYTE
IMUL C,[-5] ;NUMBER OF FREE CHARS
;;#GI# DCS 2-2-72 (1-3) MAKE CAT BETTER -- THIS LEAVES SOME ROOM
ADDI C,=15 ;LEAVE SOME SLOP FOR INSET, ETC.
;;#GI# (1-3)
MOVEM C,REMCHR(USER)
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 %ERGO ;NO AUTOMATIC CONTINUE FROM ERR.
NOEXPO <
MOVNI TEMP,1 ;FIND OUT IF ON A DPY
TTCALL 6,TEMP
MOVEM TEMP,DPYSW ;NEG IF DPY
>;NOEXPO
;;#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
POPJ P, ; 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)
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
OCTIN1: TTCALL 0,B
CAIN B,177 ;RUBOUT?
JRST RUB ;AYE, THERE'S THE RUB
CAIN B,"U"-100 ;↑U?
JRST CTRLU ;INDEED
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,
RUB:
CTRLU: TTCALL 3,[BYTE (7) "↑","U",15,12] ;WON'T THE USER BE
JRST OCTIN ;START OVER
SUBTTL %UUOLNK -- UUO Handler (Dispatch Vector Just Below)
NOLOW < ;INCLUDE IN UPPER SEGMENT.....
↑%UUOLNK:
↑UUOCON:MOVEM 17,%UACS+17 ;NOTICE UUO0 IS ABOVE HERE
MOVEI 17,%UACS
BLT 17,%UACS+16
MOVE P,[XWD -LUPDL,%UPDL] ;SET UP SPECIAL UUO PDL
MOVE A,JOBUUO ;GET THE INSTRUCTION
LDB B,[POINT 9,A,8] ;GET UUO NUMBER.
TRNE B,-1≠17 ;CHECK IN RANGE
JRST UUOTBL ;ILLUUO
XCT UUOTBL(B) ;GO DO RIGHT THING.
MOVSI 17,%UACS
BLT 17,17 ;RELOAD ACCUMULATORS.
JRST 2,@UUO0
; UUO TABLE
↑↑UUOTBL:PUSHJ P,ILLUUO ;0
PUSHJ P,PDLOQ ;1
PUSHJ P,FLOAQ ;2
PUSHJ P,FIXQ ;3
PUSHJ P,IOERRR ;4
PUSHJ P,ERRR ;5
PUSHJ P,PSIX ;6 -- SIXBIT PRINT.
PUSHJ P,ARERRR ;7 -- ARRAY ERROR
PUSHJ P,ILLUUO ;10
PUSHJ P,DECPNQ ;11
PUSHJ P,OCTPNQ ;12
PUSHJ P,FLTPNQ ;13
PUSHJ P,ILLUUO ;14
PUSHJ P,ILLUUO ;15
FLTPNQ: TERPRI (<WELL ONE FLOATING PT NUMBER IS 1.0>)
JRST GODD
SUBTTL ILLUUO, PDLOV, ERR UUO Handlers
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: SKIPA A,[10B12+[ASCIZ /ILLEGAL UUO /]]
PDLOQ: MOVEI A,[ASCIZ /PDL OVERFLOW/]
ERRR: ERSEEN←←10000
;##LN##KVL - MAKE SEMANTIC ERRORS VISIBLE AFTER SYNTAX ERRORS (THERE
; USED TO BE SOME 9 LINES OF JUNK HERE.
NOCOM:
NOEXPO <
PUSHJ P,PPRESET ;TURN ON PP 0, RESET POSITION
>;NOEXPO
TTCALL 3,(A) ;PRINT MESSAGE
LDB B,[POINT 4,A,12] ;DISPATCH INDEX
ROT B,-1 ;LOW ORDER BIT TO SIGN BIT
MOVEM B,%RECOV ;MARK %RECOVERABLE (OR NOT)
PUSHJ P,@URTBL(B) ;CALL ERROR ROUTINE
MOVEI A,0 ;INFO FOR MYERR
SKIPE ERRSPC ;SPECIAL ERROR ROUTINE??
PUSHJ P,@ERRSPC ;YES -- GO DO IT.
LINDUN: TERPRI
PRINT <CALLED FROM >
HRRZ A,UUO0
SUBI A,1
PUSHJ P,OCTPNQ+1
SKIPGE CONFIG ;RUNTIMES OR GAG
JRST NOLSCL
PRINT < LAST SAIL CALL AT >
MOVE A,GOGTAB
HRRZ A,UUO1(A)
SOS A
PUSHJ P,OCTPNQ+1
NOLSCL: TERPRI
MOVE A,GOGTAB
HRRZ B,TOPBYTE(A)
CAML B,STTOP(A);HAVE WE GONE OFF THE DEEP END?
JRST [PRINT <ALL BETS ARE OFF, FOLKS!
STRING SPACE EXHAUSTED UNEXPECTEDLY. WILL RESTART NOW>
JRST @JOBREN]
SKIPE %ERGO
JRST GOTRY ;AUTOMATIC CONTINUE SET
WATNOW: MOVEI A,"?" ;PRINT ? FOR IRRECOVERABLE ERRORS,
SKIPGE %RECOV ; → FOR %RECOVERABLE ONES.
EXPO <
MOVEI A,"↑" ;SOMETHING PRINTABLE
>;EXPO
NOEXPO <
MOVEI A,"→" ;FOR %RECOVERABLE ONES
>;NOEXPO
TTCALL 1,A ;PRINT IT
NOEXPO <
SKIPGE DPYSW ;ON A DPY?
DPYOUT 7,DPYMBK ; FLASHING INSTRUCTIONS
>;NOEXPO
TTCALL 0,B ;GET RESPONSE CHAR
CAIL B,"a" ;lower case?
SUBI B,40 ;YES, CONVERT TO UPPER
NOEXPO <
SKIPGE DPYSW
DPYOUT 7,[0↔0] ;TURN OFF ALL THAT FLASHING
>;NOEXPO
CAIN B,"E" ;RE-EDIT?
JRST EDIT ; YES
CAIN B,"T" ;USE TV?
JRST TVEDIT ; YES
TTCALL 11, ;CLEAR INPUT BUFFER
CAIN B,12 ;CONTINUE AUTOMATISCH?
SETOM %ERGO ;YES
CAILE B,15 ;TRY TO CONTINUE?
JRST NOCR
CAIE B,"α" ;CONTINUE ANYWAY OR
GOTRY: SKIPGE %RECOV ;CAN WE CONTINUE?
POPJ P, ;YES
TERPRI <CAN'T CONTINUE>
JRST WATNOW
NOCR: CAIN B,"S"
JRST STRTIT ;RESTART
CAIN B,"X" ;EXIT?
JRST [
MOVSI 17,%UACS
BLT 17,17
CALL6 EXIT]
NOXIT: CAIE B,"D"
JRST BADRSP ;DOESN'T KNOW WHAT HE WANTS
GODD: SKIPN JOBDDT ;IS DDT IN CORE
JRST NODDT ;NOPE
MOVSI 17,%UACS
BLT 17,17
JRST @JOBDDT
NODDT: TERPRI <NO DDT>
JRST WATNOW
BADRSP: SKIPE A,ERRSPC ;IS THERE A COMPILER ROUTINE?
SKIPN A,-1(A) ;YES, IS THERE AN FTDEBUGGER?
JRST RELYBD ;NO OR NO
CAIE B,"L" ;WANT TO LOOK AT STACK?
JRST RELYBD ;NO, ALL THAT WORK FOR LITTLE
TERPRI <YOU ARE IN THE COMPILER DEBUGGER>
PUSHJ P,(A) ;GO DEBUG
JRST WATNOW
RELYBD: PRINT <REPLY [CR] TO CONTINUE,
[LF] TO CONTINUE AUTOMATICALLY,
"D" FOR DDT, "E" TO EDIT,
"X" TO EXIT, "S" TO RESTART>
JUMPE A,CRL
PRINT <,
"L" TO LOOK AT THE STACK>
CRL: TERPRI
JRST WATNOW
IOERRR: TERPRI
TTCALL 3,(A)
TLNE A,740 ;ANY AC AT ALL?
PUSHJ P,SIXPRT ;YES, ASSUME 14-15, SIXBIT IN LPSA
TERPRI
CALLI ;AVOID CLOSING FILES
CALL [SIXBIT/EXIT/] ;FAIL WON'T LET ME USE CALL6
STRTIT: HRRZ A,JOBSA
JRST (A)
DSCR ARRAY ERROR UUO
PAR ARRAY NAME STRING DESCRIPTOR ADDRESS IS EFFECTIVE ADDR
INDEX NUMBER IS AC FIELD.
DES ARRAY NAME, INDEX NUMBER ARE PRINTED. THEN ERROR UUO CODE
IS ENTERED AS ABOVE.
⊗
ARERRR:
NOEXPO <
PUSH P,PPRETR ;IN LINE CALL
PPRESET:
SKIPL DPYSW ;ON A DPY?
POPJ P, ;NO, DON'T BOTHER
OPDEF PPIOT [702B8]
PPIOT 1,400000
DPYPOS (-200) ;RESET X POS
DPYSIZ (3,5) ;RESET GLITCHES
PPRETR: POPJ P,.+1
>;NOEXPO
PRINT <INVALID INDEX NO. >
LDB A,[POINT 4,JOBUUO,12]
PUSHJ P,DECPNQ+1
PRINT < FOR ARRAY >
SETZM %RECOV ;NON-RECOVERABLE ERROR!
PUSHJ P,PRASC
JRST LINDUN
SUBTTL Special Printing Routines For Error Handler
DSCR UUO ERROR MESSAGE ROUTINES AND THEIR INDICES (AC FIELD OF UUO)
⊗
↑↑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
UUOPRT: HLRZ A,40 ;LH
PUSHJ P,OCTPNQ+1 ;TYPE IT
HRRZ A,40 ;RH
JRST OCTPNQ+1 ;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
PRASC: SKIPA A,JOBUUO ;→STRING DESCRITPOR
.PRSM: HRRI A,$PNAME(LPSA) ;→STRING DESCRIPTOR
HRRZ B,(A) ;#CHARACTERS
MOVE A,1(A) ;STRING BP
MOVEI D,0 ;NO ADJUSTMENT
JRST PRSL1 ;WON'T WORK FOR ZERO LENGTH STRINS
PRSL: ILDB C,A ;CHARACTER
ADDI C,(D) ;ADJUSTMENT
TTCALL 1,C ;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,UUO0
LDB A,[POINT 4,-2(A),12] ;AC # FROM PREV INSTR
ADDI A,%UACS
JRST DECPNQ ;PRINT IT IN DECIMAL
SIXPRT: SKIPA A,[POINT 6,LPSA];GET FROM HERE
PSIX: HRLI A,(<POINT 6,0>) ;UUO ADDR IS ADDR OF SIXBIT
MOVEI D,40 ;ADJUSTMENT
MOVEI B,6 ;PRINT 6 CHARS
JRST PRSL1
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 #
TTCALL 0,B ;SEE IF FILE NAME SPECIFIED
CAIE B,15 ;CR?
JRST GTNAM ; NO, NAME SPECIFIED
AUTO: TTCALL 0,B ;SNARF UP LINE FEED AFTER CR
MOVEI A,1
SKIPE ERRSPC
PUSHJ P,@ERRSPC ;SPECIAL FOR COMPILER....
JRST GTIT ;GET QQSVED.RPG
GTNAM: CAIE B," " ;DELETE LEADING BLANKS
JRST MKNAMM
TTCALL 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
TTCALL 0,B
JRST MKNLP
GTIT1: CAIN B,15
TTCALL 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,<TV>) ;NO, TV
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
⊗
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,OCTO ;OUTPUT OCTAL
MOVEI 1,","
PUSHJ P,OUT1
HRRZ 1,11
PUSHJ P,OCTO
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,
OCTO: IDIVI 1,10
HRLM 2,(P)
SKIPE 1
PUSHJ P,OCTO
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 DECPNT, OCTPNT, FIX, FLOAT UUOs
DSCR OCTPNT, DECPNT UUO'S
PAR ADDR OF WORD TO BE PROCESSED IS EFFECTIVE ADDR
RES DECPNT -- WORD TYPED IN DECIMAL
OCTPNT -- OCTAL
⊗
OCTPNQ: HRRZ A,(A)
MOVEI C,10 ;KEEP RADIX IN C.
JRST PNT
DECPNQ: MOVE A,(A)
MOVEI C,=10
JUMPGE A,PNT ; GREATER 0.
PRINT <->
MOVMS A ; FOO1 ← ABS(FOO1);
PNT: IDIV A,C ;FAMOUS DEC RECURSIVE NUMBER PRINTER.
IORI B,"0"
HRLM B,(P)
SKIPE A
PUSHJ P,PNT
HLRZ B,(P)
TTCALL 1,B
POPJ P,
DSCR FIX UUO (FIXQ)
PAR EFFECTIVE ADDR → WORD TO BE CONVERTED
RES FIXED POINT EQUIVALENT IN AC SPECIFIED IN AC FIELD OF UUO
⊗
FIXQ: TRNN A,777760 ;IN AC?
ADDI A,%UACS ;YES
MOVE B,(A) ;GET ARGUMENT
MULI B,400 ;THIS ALGORITHM STOLEN FROM F4.
TSC B,B
EXCH B,C
ASH B,-243(C)
JRST FXFLT ;STORE IN RIGHT PLACE.
POPJ P,
DSCR FLOAT UUO (FLOAQ)
RES LIKE FIX, BUT RETURNS FLOATING POINT EQUIVALENT OF ITS ARGUMENT
⊗
FLOAQ: TRNN A,777760 ;IN AC?
ADDI A,%UACS ;YES
MOVE B,(A) ;GET ARGUMENT
IDIVI B,1B18
SKIPE B
TLC B,254000
TLC C,233000
FAD B,C
FXFLT:
LDB A,[POINT 4,A,12] ;RESULT REGISTER
MOVEM B,%UACS(A) ;STORE RESULT
POPJ P,
SUBTTL DSPLIN, etc.for Disp. Text Line on Error (Compiler)
DSCR DPYCLR
CAL PUSHJ
RES RESETS III DPY STATE IF A III DPY IS AROUND
⊗
NOEXPO <
↑DSPCLR:
SKIPGE DPYSW
DPYCLR
POPJ P,
>;NOEXPO
NOEXPO <
↑↑DPYMBK: DPYMSG
DPYSVV-DPYMSG+1 ;DPYOUT HEADER BLOCK
DPYMSG: 0
AIVECT (=100,=400) ;MOVE TO RIGHTOF RAID SCREEN
ASCID /REPLY [CR] TO CONTINUE,
/
RIVECT (=612,0) ;GET OUT THERE AGAIN
ASCID ([LF] TO CONTINUE AUTOMATICALLY,
(
RIVECT (=612,0)
ASCID ("D" FOR DDT, "E" TO EDIT, "T" TO TVEDIT,
(
RIVECT (=612,0)
ASCID ("X" TO EXIT, "S" TO RESTART,
(
DPYSVV: DPYJMP DPYMSG
>;NOEXPO
SUBTTL SAVE, RESTR, INSET -- General Utility Routines
DSCR SAVE
CAL PUSHJ
DES This routine saves registers 0-CHNL (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 ;→USER RE-ENTRANT TABLE
HRRZI TEMP,RACS(USER) ;XWD FF,SAVEADDR
BLT TEMP,RACS+CHNL(USER) ;SAVE FF THRU CHNL
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
BLT TEMP,CHNL ;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→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>
,<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: →PREV,,→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,,→HEAD ;x=1 if in use, 0 if free
→PREV is zero if this block is first on free storage list. →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) → 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) ≠ 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) ≠ 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 →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) ;→NEXT BLOCK
HLRZ PREV,(THIS) ;→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 → core block to be placed on free storage list
AC LAST → 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 ⊃ 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>
CALLI 12]
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
ERR <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: CALLI LAST,SEGSIZUUO ;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.
⊗
↑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) ;→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 ⊃ 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→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
GLOB <
CAIN USER,GLUSER ;THIS IS HOW WE TELL
JRST [CALLI TEMP,CORE2UUO ;GET SOME CORE
JRST GETRST ;HE SPAT UPON OUR HUMBLE REQUEST.
PUSHJ P,NEWB2 ;LINK IT UP
JRST .+4]
>;GLOB
CALL6 (TEMP,CORE) ;ASK FOR MORE
JRST GETRST ;CAN'T GET IT
PUSHJ P,NEWBLK ;MAKE TOP LOOK LIKE FREE BLOCK
CAMLE SIZ,1(THIS) ;NOW SHOULD FIT
ERR <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
⊗
↑↑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
⊗
↑↑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
ERR <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
ERR <DRYROT> ;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
ERR <DRYROT> ; 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
⊗
↑↑CORREL:
IFN DEBCOR,<
SKIPE PRTCOR
TERPRI <CORREL: >
>
SKIPN USER,GOGTAB ;MUST BE SET UP HERE
ERR <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?
ERR <DRYROT -- BAD ADDRESS TO CORREL>
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) ;→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)
ERR <YOU ARE ABOUT TO GET AN ILL MEM-REF>,1
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 → 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
;;#IC# (1-1)
CALL6 (TEMP,CORE)
ERR <DRYROT --CORSER&LNKRET>
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
⊗
↑↑CORBIG: SKIPN USER,GOGTAB
ERR <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>
,<GOGTAB,X11,CORGET,CORREL,CORINC,X22,CORBIG,SPRPDA>
,<STRING GARBAGE COLLECTOR ROUTINES>
,<%SPGC,%STRMRK,%ARRSRT>)
;String Garbage Collector Routines
NOLOW < ;INCLUDE IN UPPER SEGMENT.
BKSZ←←=25 BKOFF←←=23 MLT←←5
↑.CORERR:
↑CORERR:
ERR <NO CORE FOR ALLOCATION>
DSCR STRGC(# chars desired);
CAL SAIL
RES calls string garbage collector with #chars in -1(p)..i.e.a formal param.
⊗
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
DSCR STRNGC
CAL PUSHJ
PAR A -- number of new characters needed
REMCHR(USER) -- has been updated by that number of chars
RES String space is compacted, new REMCHR is updated by C(A).
Restarts if not enough room left
SID none
DES STRNGC is a two-pass process. In the first, all string descriptors
are found and sorted into ascending sequence with respect to the locations
of their respective texts. String descriptors are found via the generating
routines, described in CALSG.
In the second pass, all string texts are moved down to fill any
unused space. All descriptors are adjusted to reflect the new locations.
⊗
↑STRNGC: MOVE USER,GOGTAB ;GET USER TABLE POINTER
MOVEM 12,SGACS+12(USER)
MOVEI 12,SGACS(USER)
BLT 12,SGACS+11(USER)
; →→→→→→ OBTAIN SPACE, INITIALIZE GARBAGE COLLECTOR ←←←←←←
HRRZ TEMP,TOPBYTE(USER) ;MAKE SURE DIDN'T OVERFLOW
; **** BUG TRAP
CAMG TEMP,STTOP(USER)
CAMGE TEMP,ST(USER)
ERR <DRYROT AT STRNGC>
; **** EBT
SUB TEMP,ST(USER) ;CREATE A DIVISOR FOR DISTRIBUTION
ADDI TEMP,5 ; OF DESCRIPTORS DURING SGSORT
MOVEM TEMP,INKY(USER)
SKIPE XPAND(USER) ;ALLOWED TO EXPAND?
JRST INSIDE ; NO
SETOM ATTOP(USER) ;WANT BLOCK OFF THE TOP FOR SAFETY
MOVEI C,=400 ;REASONABLE SIZE
PUSHJ P,CORGET ;IF CAN'T GET IT, TROUBLE
SKIPA ;TRY TO GET WHAT YOU CAN
JRST CORROK ;GOT IT
INSIDE: SETZM ATTOP(USER) ;CAN'T EXPAND
PUSHJ P,CORBIG ;HOW MUCH CAN WE HAVE?
PUSHJ P,CORGET ;GET THAT AMOUNT
ERR <DRYROT - STRNGC CAN'T GET CORE>
CORROK: SETZM ATTOP(USER) ;NOW CAN GET ANYWHERE
MOVEM B,STBUCK(USER) ;SAVE → TO BLOCK
SETZM (B)
HRLS B
ADDI B,1
MOVEI TEMP,BKOFF(B)
BLT B,(TEMP)
MOVE B,STBUCK(USER)
ADDI B,BKSZ ;FIRST BKSZ WORDS IS "BUCKET" LIST
MOVNI C,-BKSZ(C)
JUMPGE C,CORERR ;BAD THING
HRL B,C
SUB B,X11 ;IOWD FOR WORD ALLOC IN STRNGC
MOVEM B,SGFRE(USER) ;FREE SPACE POINTER
HRRZ A,ST(USER)
HRLI A,(<POINT 7,0>)
MOVEM A,TOPBYTE(USER) ;FIRST(USER) NEW OK POSITION
SETZM NUMCHR(USER) ;TOTAL # CHARS PREVIOUSLY MOVED
; →→→→→→ SORT THE STRINGS ←←←←←←←←←
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 sorting routine, SGSORT.
SID SGSORT uses B,C,D,E,TEMP, accepts input in A. Generating
routines may use A-T1 (12) and TEMP for their own devices.
Q1 through T1 will not be changed by calls on SGSORT.
DES Each generating routine should do the following:
1) Place a string descriptor 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 return
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 compiller
These routines should provide sufficient examples.
⊗
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
JRST CALSGL ;DO MORE THAN ONCE
; →→→→→→ 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:
; SKIPN -2(T) ;PROCEDURE ACTIVE?
; SETZM (A) ; NO, MAKE NULL STRINGS
Comment ⊗ Due to certain social pressures (WFW LIVES ON)
strings in inactive blocks remain over garbage collection ⊗
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
↑%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 T1,ARYLS(USER) ;LEAPING LISTS
POPJ P, ;NONE
LAR1:
HLRZ Q2,(T1) ;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 <LEAPING DRYROT AT ARRSRT>
PUSHJ P,ARPUTX ;GO SORT IT
LAR2: HRRZ T1,(T1) ;MERRILY WE LINK ALONG
JUMPN T1,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.
; SUBROUTINE ENTERED WITH A → A STRING DESCRIPTOR. CONVERTS
; IT TO GARBAGE COLLECTOR FORMAT. USES B, C.D,E,TEMP
; START CONTAINS FIRST #CHARS FOR BEGINNING OF STRING SPACE.
; WARNING ***** CLOBBERS B,C,D,E,TEMX **********
SGSORT:
HLLZ B,(A) ;GET STRING NUMBER
JUMPE B,SGSRT ; DON'T COLLECT CONSTANTS OR NULL STRINGS
HRRZ D,1(A) ;MAKE SURE STRING IN RANGE
HRRE C,(A) ;CHECK LENGTH CONSISTENCY
; *** BUG TRAP
JUMPE C,DONBUG ;DON'T WORRY MUCH ABOUT NULL STRINGS
JUMPL C,BUGG
CAMG D,STTOP(USER)
CAMGE D,ST(USER)
BUGG: ERR <DRYROT AT SGSORT>,1
DONBUG:
; *** EBT
HLLZ B,1(A) ;GET POINTER AND SIZE FIELDS OF BP
HRRI B,[BYTE (7) 0,1,2,3,4,5]
ILDB B,B ;#CHARS REPRESENTED BY POINTER
;C HAS ADDR FILED OF BP (SEE ABOVE)
SUB D,ST(USER) ; - STRING SPACE BASE
IMULI D,5 ;#CHARS
ADD B,D ; + CHARS IN POINTER
MOVEM B,1(A) ; TO BP WORD
ADD C,B ; + #CHARS FIELD (D LOADED ABOVE)
HRRZM C,(A) ;TO #CHARS WORD
MOVE D,B ;NOW DISTRIBUTE STRING TO PROPER
IMULI D,MLT ; LIST TO SPEED SORT
IDIV D,INKY(USER) ; SEE ABOVE FOR INKY CALC
ADD D,STBUCK(USER) ;D→PROPER "BUCKET" ENTRY
; *** BUG TRAP
MOVE TEMP,STBUCK(USER)
CAML D,TEMP
CAIL D,BKSZ(TEMP)
ERR <DRYROT AT SGSLUP>,1
; *** EBT
; A→ STRING DESCRIPTOR (MARKED) -- D→BUCKET LIST THIS STRING
; B IS START COUNT [=1(A)] -- C IS END COUNT [=(A)]
SGSLUP: MOVE E,D ;E←CDR(E), IN FACT
HRRZ D,(E) ;D←CDR(E)
SKIPN D ;DONE?
JRST INSERT ; YES, INSERT AT END
HLRZ TEMP,(D) ;TEMP←CAR(D)
CAMGE B,1(TEMP) ;NEW START LESS?
JRST INSERT ;YES, INSERT THIS ONE IN FRONT OF IT
CAME B,1(TEMP) ;NEW START SAME?
JRST SGSLUP ;NO, GREATER
; EQUAL START COUNTS, ARRANGE BY END COUNT, DESCENDING SEQUENCE
CAMG C,(TEMP) ;NEW END GT OLD?
JRST SGSLUP ;NO, CONTINUE
; (JRST INSERT) ;YES
INSERT:
MOVE TEMP,SGFRE(USER)
AOBJN TEMP,STILMOR ;EXPAND LINK SPACE
SGXPND:
PUSH P,TEMP
MOVE B,STBUCK(USER) ;→CURRENT FWS BLOCK
MOVEI C,=100 ;GET 100 MORE
PUSHJ P,CORINC ;EXPAND THE BLOCK
ERR <NO CORE FOR ALLOCATION>
POP P,TEMP
SUB TEMP,[(100)] ;THERE IS MORE
STILMOR:
MOVEM TEMP,SGFRE(USER)
HRLM A,(TEMP)
HRRM D,(TEMP)
HRRM TEMP,(E)
SGSRT: ADDI A,2 ;AUTO-INDEXING
POPJ P,
; FIND A DISJOINT STRING GROUP, MOVE IT BACK.
; MARK POINTERS APPROPRIATELY.
ALLCOL: SUB P,X22 ;REMOVE JUNK PUT ON BY CALSG
SGSWEP:
SETZB T,T1 ;IN CASE NO STRINGS AT ALL
MOVEI Q2,1 ;INIT STRING NO.
MOVE Q3,STBUCK(USER) ;WORK UP BUCKET LIST, HANDLING
MOVEI FF,BKSZ(Q3) ;EVERYTHING IN THE PATH
SUBI Q3,1
PUSHJ P,FSTSTR ;A→FIRST LIST
HLRZ Q1,(A) ;Q1 → FIRST MARKED DESCRIPTOR
JRST SGFX1 ;JUMP INTO THINGS
SGFIX: PUSHJ P,NXTSTR ;A→NEXT LIST ELEMENT
HLRZ Q1,(A) ;Q1 → NEXT DESCRIPTOR
CAMG T1,1(Q1) ;INCLUDED IN OR OVERLAPPING THIS STRING
JRST SGBLT ; NO, MOVE OLD BEFORE HANDLING NEW
PUSHJ P,FIXPTR ;FIX UP DESCRIPTOR
CAMGE T1,TEMP ;OVERLAPPING STRING
MOVE T1,TEMP ; YES, USE BIGGER END POINT
JRST SGFIX ;CONTINUE
SGBLT: ADDI Q2,1 ;INCREMENT STRING NUMBER
MOVN B,T
ADD B,T1 ;TOTAL STRING SIZE
SKIPN SGLIGN(USER) ;HAVE TO ALIGN TO FW BDRY?
JRST NOLIGN ; NO
ADDI B,4 ;YES, DO IT
IDIVI B,5
IMULI B,5 ;NOW MULT OF 5 CHARS, BIG ENOUGH
NOLIGN:
ADDM B,NUMCHR(USER) ;NUMBER USED SO FAR
MOVE C,T ;STARTING COUNT FOR STRING
PUSHJ P,MKBPT ;PICK UP FROM HERE
MOVE T,TOPBYTE(USER) ;PUT DOWN HERE
JUMPE B,SGBLT1 ;DON'T DO IT IF NOT NECESSARY
BLTLUP: ILDB D,C
IDPB D,T ;WHEEE!
SOJG B,BLTLUP ;MOVE 'EM ON OUT
MOVEM T,TOPBYTE(USER) ;RESTORE IT
SGBLT1: JUMPE A,STSTAT ;LAST ONE
SGFX1: MOVE T,1(Q1) ;INITIALIZE START OF STRING,
MOVE T1,(Q1) ; END OF STRING,
MOVE E,T ; OFFSET FOR BP FIXUPS
SUB E,NUMCHR(USER) ; (THIS IS THE OFFSET)
PUSHJ P,FIXPTR ;FIX UP THIS DESCRIPTOR
JRST SGFIX ;CONTINUE
NXTSTR: HRRZ A,(A) ;A←CDR(A)
JUMPN A,APOPJ ; GOT ONE, DONE
FSTSTR: AOS A,Q3 ;END OF THAT LIST, LOOK AT NEXT
CAMGE A,FF ;OOOPS, THERE ARE NO MORE!
JRST NXTSTR ; YES THERE ARE
SUB P,X11 ;DON'T RETURN, BUT MARK DONE,
MOVEI A,0 ; AND GO OFF FOR LAST
JRST SGBLT ; NOSTALGIC MOVE
FIXPTR: MOVE TEMP,(Q1)
SUB TEMP,1(Q1) ;SIZE OF STRING FOR THIS DESCRIPTOR
HRL TEMP,Q2 ;ADD STRING NUMBER
EXCH TEMP,(Q1) ;PUT FIRST WORD AWAY
MOVE C,1(Q1) ;START COUNT
SUB C,E ;ADJUST TO NEW LOCATION
PUSHJ P,MKBPT ;MAKE A BYTE POINTER
MOVEM C,1(Q1) ;THIS BABY IS READY TO FLY!
APOPJ: POPJ P, ;ALL DONE
; MKBPT TAKES A #CHARS IN C, MAKES A BYTE POINTER RELATIVE TO ST
; OUT OF IT, LEAVES IT IN C -- DESTROYS D
MKBPT: IDIVI C,5 ;WORD # IN C, CHAR OFLOW IN D
ADD C,ST(USER) ;REAL WORD #
HLL C,[POINT 7,0
POINT 7,0,6
POINT 7,0,13
POINT 7,0,20
POINT 7,0,27](D) ;POINTER PART
POPJ P,
; FINISH UP
STSTAT:
SKIPN SGLIGN(USER) ;HAVE TO LINE UP TOPBYTE?
JRST NORCLR ;NO
MOVE C,T1 ;END CHAR # OF LAST STRING
SUB C,E ;ADJUST BY THE WINNING OFFSET
PUSHJ P,MKBPT ;MAKE A BP FOR TO BE TOPBYTE
MOVEM C,TOPBYTE(USER) ;FOR THE RIDICULOUS, DEMANDING SAIL
PUSHJ P,RESCLR ;CLEAR REST OF STRING SPACE
;;#GI# DCS 2-5-72 REMOVE TOPSTR
NORCLR: AOS SGCCNT(USER)
MOVN B,STMAX(USER)
IMULI B,5
ADD B,NUMCHR(USER)
;;#GI# DCS 2-2-72 (2-3) LEAVE SOME SLOP SO ONE NEEDN'T FEAR INSET
ADDI B,=15 ;SOME SLOP
ADD B,SGACS+A(USER) ;#CHARS WHICH CAUSED THIS MESS IN FIRST PLACE
MOVEM B,REMCHR(USER)
;;#GI (2-3)
JUMPGE B,[ERR (<STRING SPACE EXHAUSTED, WILL RESTART>,1)
JRST @JOBREN] ;RE-ALLOCATE
MOVE B,STBUCK(USER) ;RELEASE IT
PUSHJ P,CORREL
HRLZI 12,SGACS(USER)
BLT 12,12
POPJ P,
COMMENT ⊗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
⊗
↑↑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
⊗
↑↑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)
DSCR STCLER
CAL PUSHJ
RES Clears all string variables on STRLNK(USER) to null strings
DES compiler only
⊗
↑STCLER:
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: ;SETZM -2(T) ;***** CAN'T DO THIS UNLESS PATSW IS
; *** ON IN COMPILER!!!!!
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>,<SAVE,RESTR,X33>,<POW, FPOW -- EXPON. ROUTINES>)
DSCR BEGIN UTILS
⊗
IFN ALWAYS,< BEGIN UTILS>
COMMENT % EXPONENTIATION CODE
POW(EXP,ARGUMENT) OR
FPOW(EXP,ARGUMENT) DEPENDING %
DSCR POW, FPOW, LOGS, FLOGS(EXPONENT,ARGUMENT);
CAL SAIL
DES CALLS GENERATED BY COMPILER FOR ↑ OPERATOR
⊗
↑↑FPOW: PUSHJ P,SAVE
JSP B,SETEXP ;SET∧ UP, SAVE ACS
MOVSI B,(1.0) ;SET FOR FLOATING
JUMPE A,EXZERO ;0 EXPONENT
FEXLUP: TRNE A,1 ;COLLECT PRODUCT?
FMPR B,C ;YES
ASH A,-1 ;PREPARE TO LOOK AT NEXT BIT
JUMPE A,EXDUN ;ALL DONE IF ZERO
FMPR C,C ;SQUARE BASE
JRST FEXLUP
↑↑POW: PUSHJ P,SAVE
JSP B,SETEXP
MOVEI B,1
JUMPE A,EXZERO
EXPLUP: TRNE A,1
IMUL B,C
ASH A,-1
JUMPE A,EXDUN
IMUL C,C
JRST EXPLUP
EXZERO: SKIPN C ;0↑0
ERR <0↑0 NOT DEFINED>
EXDUN: MOVEM B,RACS+1(USER)
MOVEI LPSA,0
JRST RESTR
; SET UP FOR POWER ROUTINES
SETEXP: POP P,UUO1(USER) ;RETURN FROM (F)EXP
POP P,C ;OPERAND
POP P,A ;EXPONENT
SKIPGE A ;EXP ≥0?
ERR <NEGATIVE EXPONENT NOT IN -- YOU LOSE>
JRST (B) ;RETURN
ENDCOM (POW)
NOLOW <
NOUP <
COMPIL(LOG,<LOGS,FLOGS>,<SAVE,RESTR,X33>,<LOGS & FLOGS FOR F4 LINKAGE>)
EXTERNAL EXP3.0 ;FORTRAN MAGIC FOR REAL↑REAL
↑↑LOGS: PUSHJ P,SAVE
FLOAT 0,-1(P)
MOVE 1,-2(P) ;EXPONENT
PUSHJ P,EXP3.0
FIX
FORGO: MOVEM RACS+1(USER)
MOVE LPSA,X33
JRST RESTR
↑↑FLOGS: PUSHJ P,SAVE
MOVE 0,-1(P)
MOVE 1,-2(P)
PUSHJ P,EXP3.0
JRST FORGO
ENDCOM (LOG)
>;NOUP
>;NOLOW ;...
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