Trailing-Edge
-
PDP-10 Archives
-
BB-4157F-BM_1983
-
fortran/tools/extend.mac
There are 2 other files named extend.mac in the archive. Click here to see a list.
SEARCH FORPRM
TV EXTEND Calls routines with large arrays as arguments,7(0)
SUBTTL Alan H. Martin/AHM 1-Nov-82
;COPYRIGHT (C) DIGITAL EQUIPMENT CORPORATION 1982,1983
;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED
;ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE AND WITH THE
;INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE OR ANY OTHER
;COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
;OTHER PERSON. NO TITLE TO AND OWNERSHIP OF THE SOFTWARE IS HEREBY
;TRANSFERRED.
;THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE
;AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT
;CORPORATION.
;DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ITS
;SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL.
;This software is provided for informational purposes only, and is not
;supported by Digital. Furthermore, Digital makes no claim that this
;software will ever be supported in the future.
; ***** WARNING *****
;You must be running a KL microcode later than version 275 (which is
;the current field image version for Tops-20 releases 5 and 5.1) in
;order to use these routines; many instructions used by FOROTS rely on
;changes to the microcode which will only be available in the next
;release. Unpredictable results will occur if FOROTS is run in a
;non-zero section with microcode version 275. Various routines in
;FORLIB will exhibit similar problems. Some features that may have
;problems include formatted I/O, character data operations, ENCODE,
;DECODE and internal files.
;Also, note that EXTEND will only work on an Extended KL10 running
;TOPS-20, and that certain things (particularly FORDDT, DBMS and the
;DUMP subroutine) do not work with it.
SALL ;Suppress nasty macro expansions
.DIRECTIVE SFCOND ;Suppress listing of failing conditionals
.DIRECTIVE FLBLST ;List first line of binary data only
COMMENT \
***** Begin Revision History *****
***** Begin Version 7 *****
0 AHM 1-Nov-82
Create EXTEND
***** End Revision History *****
\
COMMENT |
EXTEND.HLP -- Help file for EXTEND Version 7 February 1983
Routines for using large arrays from Fortran programs
Fortran programs can manipulate arrays containing more than 256K words
of data. Such arrays (called "large" arrays) cannot be declared local
to program units, or declared in COMMON blocks. They must be created
by a system subroutine named EXTEND and passed as arguments to all of
the subprograms that must manipulate them. To call a subroutine which
requires large arrays, you must call EXTEND with an argument list
which includes the name of your subroutine that you want to be invoked
with large arrays as arguments. EXTEND will create the arrays and
then call the subroutine. When that routine returns to EXTEND, the
arrays are discarded and control returns to the caller of EXTEND.
Before you can use large arrays, you have to initialize the subroutine
package. Do this by:
CALL EXTINI
Also, if SORT is going to be called after the call to EXTINI, there
must be a CALL SORT(' ') before the call to EXTINI. This makes SORT
allocate a non-zero section for itself.
If your subroutine requires arguments in addition to the large arrays,
append them to the argument list for the call to EXTEND. They will be
passed to the subroutine. This is what a call to EXTEND looks like:
CALL EXTEND(SUBRTN,N, SCALAR1,SIZE1,...,SCALARN,SIZEN, ARG1,...,ARGm)
is a call to the EXTEND routine with m+2N+2 arguments, where:
SUBRTN Is the name of a Fortran subroutine to call using the N
large arrays, N array sizes and m extra values (ARG1...ARGm)
as arguments. SUBRTN should be declared to be EXTERNAL.
N Is the number of large arrays to generate.
SCALAR1, . . . Are N scalar variables of the same type as the array elements
SCALARN, in large array arguments to SUBRTN. Note that a CHARACTER
variable must be of the desired length for the elements of the
corresponding array.
SIZE1, . . . Are N scalars of type INTEGER which give the number of elements
SIZEN in the large arrays. These arguments are passed on to SUBRTN
for use in adjustable array dimension declarations.
ARG1, . . . Are "m" arguments of any type which are passed on to SUBRTN
ARGm following the N large array arguments.
The EXTEND subroutine performs a call to SUBRTN that looks like this:
CALL SUBRTN(ARRAY1,SIZE1,...,ARRAYN,SIZEN, ARG1,...,ARGm)
Consider the following program for example:
PROGRAM BIG
REAL A,XVEC(10)
DOUBLE PRECISION B,EPS
CHARACTER C*132,CARD*80
EXTERNAL FOO
CALL EXTINI
CALL EXTEND(FOO,3, A,1000000,B,1000000,C,100000, XVEC,EPS,CARD)
END
It will allocate an array of 1000000 real numbers (call it ARRAYA), an
array of 1000000 double precision numbers (ARRAYB) and an array of
100000 132 character long strings (ARRAYC). It will appear as if a
Fortran subroutine named EXTEND was called which looks like this:
SUBROUTINE EXTEND(XVEC,EPS,CARD)
REAL ARRAYA(1000000),XVEC
DOUBLE PRECISION ARRAYB(1000000),EPS
CHARACTER ARRAYC(100000)*132,CARD*80
CALL FOO(ARRAYA,1000000,ARRAYB,1000000,ARRAYC,100000,
1 XVEC,EPS,CARD)
END
Note that if the program is not started in a non-zero section, FOROTS
may fail in an unpredictable manner. EXTEND will abort the program
rather than let execution continue. One way to make the program start
in a non-zero section is to:
@LOAD FOO.FOR,EXTEND.REL ; Get a core image with code in section 0
@SAVE FOO.EXE ; Create .EXE file with code in section 0
@GET FOO.EXE/USE-SECTION:1 ; Get a core image with code in section 1
@SAVE FOO.EXE ; Create .EXE file with code in section 1
If EXTEND is on a system area (say, SYS:), then the first command is:
@LOAD FOO.FOR,SYS:EXTEND.REL
See your system administrator to find out where EXTEND.REL is.
You must be running a KL microcode later than version 275 (which is
the current field image version for Tops-20 releases 5 and 5.1) in
order to use EXTEND.
|
SUBTTL Definitions
; Argument block offsets
; Offsets from the beginning of the arg block
SUBRTN==0 ;Address of routine to call
N==1 ;Number of generated arrays
ARRAYS==2 ;Beginning of 2N arguments that give the
; types of the generated array elements
; Relative position of generated array types and sizes
TYPE==0 ;First item is the scalar for the type
SIZE==1 ;Second item is the integer size
; Private ACs
I==U ;Pointer to indirect words
LL==D ;Copy of incoming arg block pointer
A==F ;Address of arg block being created
; Random symbols
EXTERN FUNCT. ;OTS core manager entry point
EXTERN ABORT. ;Subroutine to return control to
; the operating system on errors
SM%RWX==SM%RD!SM%WR!SM%EX ;Read, write and execute access to a whole
; section - MONSYM should get this some day
NSEC==40 ;Number of sections to search.
SUBTTL Tops-10 error message code
IF10,<
HELLO (EXTINI)
JRST EXTFEH
HELLO (EXTEND)
EXTFEH: PUSHJ P,F.EN1 ;We can't do anything on TOPS-10 - complain
JRST ABORT. ; and die
$FERR (?,EN1,21,0,<EXTEND is not implemented on TOPS-10>)
> ; End of IF10
IF20,<
SUBTTL Variables
SEGMENT DATA ;Down to the low segment
; Note that starred (;*;) variables are stored on the stack around the
; call to the user's routine in case EXTEND is called recursively.
; Two tables describing chunks of free core
CHUNKS: BLOCK 1 ;Holds -# of chunks,,0
FREADR: BLOCK NSEC ;The number of words available in each chunk
FRESIZ: BLOCK NSEC ;Address of first free location in each chunk
; A table describing what sections were created and must be discarded
; upon exit from EXTEND.
RETPTR: BLOCK 1 ;Pointer to first free entry in RETARG
RETORG: BLOCK 1 ;*; ;Contents of RETPTR at routine entry
RETARG: BLOCK NSEC ;SMAP% args to discard sections we create
;(number of sections,,first section)
; Random scalars
ARGN: BLOCK 1 ;*; ;Number of pass along arguments
ARGLST: BLOCK 1 ;*; ;Holds the address of the argument list
; being constructed
ROUTIN: BLOCK 1 ;Holds address of user's routine to call
; FUNCT. arguments
FNOPC: BLOCK 1 ;Holds opcode for FUNCT. calls
FNSTS: BLOCK 1 ;Holds status upon return fron FUNCT. calls
FNARG1: BLOCK 1 ;First argument for FUNCT.
FNARG2: BLOCK 1 ;Second argument for FUNCT.
SEGMENT CODE ;Up to the high segment
SUBTTL EXTINI - Global initialization entry point
; EXTINI - subroutine to initialize some global OWN variables
; Call:
; XMOVEI L,ZERARG
; PUSHJ P,EXTINI
; Return: always
; RETPTR/ Address of first free location in SMAP% argument save area
; FREADR through FREADR+NSEC-1/ Address of first free word in each chunk
; FRESIZ through FRESIZ+NSEC-1/ Number of free words in each chunk
HELLO (EXTINI)
XMOVEI T1,0 ;Get the section local address of AC 0
JUMPN T1,EXTI.1 ;Is it 1,,0 ? If not, we are in section 0
; Note that CALL EXTEND will not work if FOROTS was initialized in
; section 0 because FOROTS stores addresses of some section local data
; structures as 30 bit numbers and so can get very confused if an
; address is stored with a section number of 0 and fetched when we are
; no longer running in section 0.
PUSHJ P,F.ES0 ;No, complain
JRST ABORT. ; and die
$FERR (?,ES0,21,0,<EXTINI called in section 0 - RUN /USE-SECTION:1>)
EXTI.1: XMOVEI T1,RETARG ;Point to the SMAP% return section arg table
MOVEM T1,RETPTR ;Save it for later use
; Set up the chunk tables. First we look for a free section.
MOVSI T3,-NSEC ;Set up an AOBJN counter for the sections
SETZ T4, ;Point to the first chunk
EXTI.2: MOVEI T1,0(T3) ;Look at the next section
HRLI T1,.FHSLF ; in our fork
RSMAP% ;Ask the monitor for info
$FJCAL IJE,ABORT. ;Shouldn't happen
AOJN T1,EXTI.5 ;Is this section free ?
HRLZM T3,FREADR(T4) ;Yes, save chunk origin
MOVEI T0,1 ;At least one free section, look for more
EXTI.3: AOBJP T3,EXTI.4 ;Is there a section after this one?
MOVEI T1,0(T3) ;Yes, look at it
HRLI T1,.FHSLF ; in our fork
RSMAP% ;Ask the monitor for info
$FJCAL IJE,ABORT. ;Shouldn't happen
AOSN T1 ;Is it free ?
AOJA T0,EXTI.3 ;Yes, tally it and look at the next section
EXTI.4: HRLZM T0,FRESIZ(T4) ;No, save away the size of this chunk in words
ADDI T4,1 ;Move chunk pointer
EXTI.5: AOBJN T3,EXTI.2 ;No, go check the next section
MOVN T4,T4 ;Get the negative number of chunks
HRLZM T4,CHUNKS ;Save away as an AOBJN pointer
; If section 1 is a data section, then we must ask for 20 locations to
; avoid using the ACs as part of a large array. Note that this will
; prevent us from ever returning section 1 to the monitor.
MOVEI T1,20 ;We may have to steal the non-zero section ACs
MOVS T2,FREADR+0 ;Look at the first chunk
CAIN T2,1 ;Does it start at 1,,0 ?
PUSHJ P,GETWRD ;Yes, steal some core
GOODBYE ;Done initializing things
SUBTTL Top level routine for EXTEND
HELLO (EXTEND)
PUSHJ P,INIT ;Set up ARGN, ARGLST, etc.
PUSHJ P,ALCARG ;Get SUBRTN's argument list from the heap
PUSHJ P,GENARY ;Generate all of the necessary large arrays
PUSHJ P,COPARG ;Copy over all of the pass along arguments
PUSHJ P,CALLEM ;Call the user's routine
PUSHJ P,RETCOR ;Free arg list, EFIWs and extra sections
GOODBYE
SUBTTL INIT - subroutine to initialize ROUTIN, ARGN and RETORG
; INIT - subroutine to initialize ROUTIN, ARGN and RETORG
; Call:
; PUSHJ P,INIT
; Return: always
; ROUTIN/ Address of user routine to call with large array arguments
; ARGN/ Number of pass along arrays
INIT: SKIPN T1,RETPTR ;Get the first available location in RETARG
JRST INIWRN ;CALL EXTINI sets RETPTR, too bad user didn't
MOVEM T1,RETORG ;Remember it for later
XMOVEI T1,@SUBRTN(L) ;Get the address of the user's routine
MOVEM T1,ROUTIN ;Save it for later use
SKIPN (T1) ;Is the first word of the routine non-zero ?
JRST RERR ;No, user forgot his EXTERNAL declaration
SKIPGE T1,@N(L) ;Get the number of pass along args
JRST NERR ;Negative number - yell at user
MOVEM T1,ARGN ;Save it away
POPJ P,
INIWRN: PUSHJ P,F.CEN ;Complain,
FUNCT (EXTINI,<>) ; initialize
JRST INIT ; and try again
$FERR (%,CEN,21,0,<CALL EXTINI was not done before CALL EXTEND>)
NERR: PUSHJ P,F.NNA ;Complain,
JRST ABORT. ; and die
$FERR (?,NNA,21,0,<Negative number of large arrays in CALL EXTEND>)
RERR: PUSHJ P,F.MED ;Complain,
JRST ABORT. ; and die
$FERR (?,MED,21,0,<Missing EXTERNAL declaration in CALL to EXTEND>)
SUBTTL ALCARG - Get new arg list from the heap
; ALCARG - subroutine to allocate the argument list
; Call:
; PUSHJ P,ALCARG
; Return: always
; A, ARGLST/ Pointer to new argument list, complete with count word set up
ALCARG:
; First we compute M+2N so that we know how much core to allocate for
; the arg list.
HLRE T1,-1(L) ;Get the negative of the total
; number of our arguments
MOVN T1,T1 ;Convert total to positive number
SUBI T1,2 ;Exclude SUBRTN and N from the count
; Now figure out how big an argument list to dynamically allocate. If
; there are any arguments for SUBRTN, we need a word for each pass
; along argument (M), a word for each generated argument (N), a word
; for each large array size (N) and a word for the count, or M+2N+1.
; If there are no arguments, then we need two words - one for the
; count, and one for the empty arg block which allows people to
; reference 0(L) without an ill mem ref.
SKIPE T3,T1 ;Is M+2N equal to 0 ? (Stash it away for later)
AOSA T1 ;No, T1 gets M+2N+1
MOVEI T1,2 ;Yes, get room for count and idiot phantom arg
MOVEM T1,FNARG2 ;Save the size for the call
PUSHJ P,ALLOC ;Go get some core
AOS A,FNARG1 ;Fetch address+1
MOVEM A,ARGLST ;Save it away
MOVN T3,T3 ;Negate the arg list's count word
HRLZM T3,-1(A) ; and save it away (-size,,0)
POPJ P, ;Done allocating the arg block
SUBTTL GENARY - Generate large arrays in the free sections
; GENARY - subroutine to generate large arrays in the free sections
; Call:
; A/ Address of first word in new argument list for generated arguments
; ARGN/ Number of large arrays to generate
; PUSHJ P,GENARY
; Return: always
; A/ Address of word in new arg list after generated arrays
; LL/ Address of word in old arg list after generated arrays
; Destroys I
GENARY: MOVN LL,ARGN ;Get the negative number of large arrays
HRLZ LL,LL ;Make an AOBJN pointer into the old arg block
HRRI LL,ARRAYS(L) ;Point to the beginning of the scalars
JUMPGE LL,GENXIT ;Are there any arrays to generate ?
;Yes, allocate them
ARYLUP: LDB T2,[POINTR(TYPE(LL),ARGTYP)] ;Get this scalar's type
MOVEI T1,1 ;Assume it is numeric - we need 1 indirect word
CAIN T2,TP%CHR ;Is it character?
MOVEI T1,2 ;Yes, need 2 word character descriptor
MOVEM T1,FNARG2 ;Save the size for the call
PUSHJ P,ALLOC ;Go get some core
HRRZ I,FNARG1 ;Fetch its address
TXO I,<IFIW> ;Make a local indirect and index word (heh heh)
DPB T2,[POINTR(I,ARGTYP)] ;Drop off the arg type
CAIE T2,TP%CHR ;Are we playing with characters?
JRST NOTCHR ;No, go hack numerics
XMOVEI T2,@TYPE(LL) ;Get the address of the character descriptor
SKIPG T1,1(T2) ;Get the element length
JRST BCAERR ;Not positive - bad character argument
MOVEM T1,1(I) ;Save it away
SKIPG T2,@SIZE(LL) ;Fetch the number of elements desired
JRST INEERR ;Tell ninny he has illegal number of elements
IMUL T1,T2 ;Multiply by number of elements
ADDI T1,4 ;Round up ahead of time
IDIVI T1,5 ;Convert from characters to words
PUSHJ P,GETWRD ;Find a place for the array
TXO T1,IFOWG ;Make the address into a OWGBP
JRST ARYFIN ;Go store it and set up the arg block word
NOTCHR: SKIPG T1,@SIZE(LL) ;Get the array size
JRST INEERR ;Illegal number of elements
TRNE T2,10 ;High order bit set in arg type ?
LSH T1,1 ;Yes, DP data type, multiply size by 2
PUSHJ P,GETWRD ;Find a place for the array
TXO I,<@> ;Numeric args use indirection
ARYFIN: MOVEM T1,0(I) ;Save the address away
MOVEM I,TYPE(A) ;Store the "array" argument word
MOVE T1,SIZE(LL) ;Get the arg block word for the size
MOVEM T1,SIZE(A) ;Copy it over
ADDI LL,1 ;Allow for the fact that each large array
ADDI A,2 ; takes two arguments to describe
AOBJN LL,ARYLUP ;Go back for more arguments
GENXIT: POPJ P, ;Done with the large arrays
BCAERR: PUSHJ P,F.BCA ;Complain,
JRST ABORT. ; and die
$FERR (?,BCA,21,0,<Bad character argument in CALL EXTEND>)
INEERR: PUSHJ P,F.INE ;Complain,
JRST ABORT. ; and die
$FERR (?,INE,21,0,<Illegal number of array elements in CALL EXTEND>)
SUBTTL COPARG - Copy over the pass along arguments to the new arg list
; COPARG - subroutine to copy over the pass along arguments to the new arg list
; Call:
; ARGN/ Number of generated arrays
; A/ Address of place to put first pass along argument in new list
; LL/ Address of first pass along argument in user's list
; PUSHJ P,COPARG
; Return: always
COPARG: HLRE T1,-1(L) ;Get the negative of our argument count
MOVN T1,T1 ;Positivize it
MOVE T2,ARGN ;Get the number of generated arrays
LSH T2,1 ;Generated arrays use two argumants each
SUBI T1,2(T2) ;Don't count generated arrays, "SUBRTN" and "N"
JUMPE T1,COPA.1 ;Are there any generated arguments ?
;Yes, set up for BLT
HRRZ T2,A ;Destination is our arg list
ADD T1,T2 ;Compute end of args to copy
HRL T2,LL ;Source is the user's arg list
BLT T2,-1(T1) ;Move things around
COPA.1: POPJ P, ;Done with the pass along arguments
SUBTTL CALLEM - Call the user's routine
; CALLEM - subroutine to call the user's routine
; Call:
; ARGN/ Number of generated arrays
; ARGLST/ Address of first word in generated argument list
; ROUTIN/ Address of routine to call
; PUSHJ P,CALLEM
; Return: always, save the following variables in case of a recursive call:
; ARGN/ Number of generated arrays
; ARGLST/ Address of first word in generated argument list
CALLEM: PUSH P,ARGN ;Save the number of generated arrays
PUSH P,ARGLST ;Save the address of the user's arg list
PUSH P,RETORG ;Save the first location we used
XMOVEI L,@ARGLST ;Point to the arg list
PUSHJ P,@ROUTIN ;Call the user's routine
POP P,RETORG ;Restore our old RETARG origin
POP P,ARGLST ;Restore the address of the user's arg list
POP P,ARGN ;Restore the number of generated arrays
POPJ P, ;Return to the main line code
SUBTTL RETCOR - Return our arg list, indirect words and extra sections
; RETCOR - subroutine to return our arg list, indirect words and extra sections
; Call:
; ARGN/ Number of generated arrays
; ARGLST/ Address of first word in generated argument list
; RETPTR/ Address of first unused word in SMAP% argument save area
; PUSHJ P,RETCOR
; Return: always
; Destroys A
RETCOR: MOVN A,ARGN ;Get the negative number of generated arrays
JUMPGE A,RETC.2 ;Any arrays? If so, free up indirect words
HRLZ A,A ;No, put count in left half
HRR A,ARGLST ;Yes, there are, point to the arg list
RETC.1: HRRZ T1,0(A) ;Point to the indirect word
MOVEM T1,FNARG1 ;Save it away for the call
LDB T2,[POINTR (TYPE(A),ARGTYP)] ;Get the data type
MOVEI T1,1 ;Assume array is numeric and has an EFIW
CAIN T2,TP%CHR ;Is it type character ?
MOVEI T1,2 ;Yes, two word descriptor to return
MOVEM T1,FNARG2 ;Save away the size
PUSHJ P,FREE ;Go return some core
ADDI A,1 ;Account for the size arg
AOBJN A,RETC.1 ;Loop back for the rest of the args
RETC.2: SOS T1,ARGLST ;Point to the start of the arg list
HRRZM T1,FNARG1 ;Save it away for the call
HLRE T1,0(T1) ;Get the size word
SKIPE T1 ;Is it zero length ?
SOSA T1 ;No, allow for the count word itself
MOVNI T1,2 ;Yes, it is actually two words long
MOVNM T1,FNARG2 ;Save size for call
PUSHJ P,FREE ;Free up the arg list
MOVE T4,RETORG ;Point to start of table
MOVE T1,T4 ;Make copy for storing
SUB T4,RETPTR ;Subtract first free to get negative count
MOVEM T1,RETPTR ;Restore our old limit
JUMPE T4,RETC.4 ;Are there any sections to return ?
HRLZ T4,T4 ;Yes, put AOBJN count in left half of AC
HRR T4,RETORG ;Point to the start of our arguments
SETO T1, ;Tell Tops-20 we want to destroy sections
RETC.3: MOVE T2,0(T4) ;Get count,,section number
HLRZ T3,T2 ;Put count in right place
HRLI T2,.FHSLF ;Say we mean our fork
SMAP% ;Return the sections
$FJCAL IJE,ABORT. ;Should never happen
AOBJN T4,RETC.3 ;Loop back for other sections
RETC.4: POPJ P, ;All done - return to main line code
SUBTTL GETWRD - Get n words of core, where n is large
; GETWRD - subroutine to search for free core
; Call:
; T1/ Number of words needed (can be bigger than a section)
; PUSHJ P,GETWRD
; Return: always
; T1/ Address of allocated core
; To allocate core, we first have to find the core in the chunk table.
; Just look for the first chunk with enough free words.
GETWRD: MOVE T4,CHUNKS ;Create AOBJN pointer for chunk table
GETW.1: CAMG T1,FRESIZ(T4) ;Does this chunk have enough free ?
JRST GETW.2 ;Yes, go take it
AOBJN T4,GETW.1 ;No, try again
PUSHJ P,F.NFS ;No core left
JRST ABORT.
$FERR (?,NFS,21,0,<Not enough free sections for CALL EXTEND>)
; T1/ Number of words needed
; T4/ -# chunks not ruled out,,# of chunk with enough space in it
; Now that we have found a chunk with enough words available, we may
; need to create some sections with an SMAP%.
GETW.2: MOVS T2,FREADR(T4) ;Get the section number of the first address
; to be used into T2 (= lowest new section)
TLZE T2,-1 ;Does it start on a section boundary ?
ADDI T2,1 ;No, round up
MOVE T3,T1 ;Get amount needed in T3
ADD T3,FREADR(T4) ;Compute the last address used+1
MOVS T3,T3 ;Get the section number in the right half of T3
TLZE T3,-1 ;Ending on a section boundary ?
ADDI T3,1 ;No, round up
SUB T3,T2 ;Get number of new sections (last-first)
MOVN T0,T1 ;Save number of words needed, negate for later
JUMPE T3,GETW.3 ;Don't SMAP% if there are no new sections
MOVEM T2,@RETPTR ;Save away the section number
HRLM T3,@RETPTR ; and the count
AOS RETPTR ;Point to the next location
SETZ T1, ;Say we have to create some sections
HRLI T2,.FHSLF ;Say that it is our process
TXO T3,SM%RWX ;Set our access attributes
SMAP% ;Create some sections
$FJCAL IJE,ABORT. ;Should never happen
MOVN T1,T0 ;Restore the number of words needed
GETW.3: ADDM T0,FRESIZ(T4) ;Shrink the chunk
EXCH T1,FREADR(T4) ;Get chunk origin, save amount used
ADDM T1,FREADR(T4) ;Account for what was used
POPJ P, ;Return to the caller with address in T1
SUBTTL ALLOC - Hide the uglyness of calling FUNCT. to get core
; ALLOC - subroutine to get section local heap space from FOROTS
; Call:
; FNARG2/ Number of words needed
; PUSHJ P,ALLOC
; Return: core is available
; FNARG1/ Address of allocated core
ALLOC: PUSH P,L ;Save our arg pointer
PUSH P,[FN%GOT] ;Get opcode for getting OTS heap space
POP P,FNOPC ;Save it in the arg block
XMOVEI L,FNARGL ;Point to the FUNCT. arg list
PUSHJ P,FUNCT. ; and call it
POP P,L ;Restore the old arg pointer
SKIPN FNSTS ;Did the FUNCT. win ?
POPJ P, ;Yes, return to caller
PUSHJ P,F.NEC ;No, complain
JRST ABORT. ; and die
$FERR (?,NEC,21,0,<Not enough OTS core for CALL EXTEND>)
-FNARGN,,0
FNARGL: IFIW TP%INT,FNOPC ;Address of opcode
IFIW TP%LIT,[ASCII |EXT|] ; ?EXTxxx should be printed for errors
IFIW TP%INT,FNSTS ;Address of status variable
IFIW TP%INT,FNARG1 ;First real argument
IFIW TP%INT,FNARG2 ;Second real argument
FNARGN==.-FNARGL
SUBTTL FREE - Hide the uglyness of calling FUNCT. to return core
; FREE - subroutine to return section local heap space to FOROTS
; Call:
; FNARG1/ Address of core being returned
; FNARG2/ Number of words being returned
; PUSHJ P,FREE
; Return: core has been deallocated
FREE: PUSH P,L ;Save our arg pointer
PUSH P,[FN%ROT] ;Get opcode for returning OTS heap space
POP P,FNOPC ;Save it in the arg block
XMOVEI L,FNARGL ;Point to the FUNCT. arg list
PUSHJ P,FUNCT. ; and call it
POP P,L ;Restore the old arg pointer
SKIPN FNSTS ;Did the FUNCT. win ?
POPJ P, ;Yes, return to caller
PUSHJ P,F.CRC ;No, complain
JRST ABORT. ; and die
$FERR (?,CRC,21,0,<Can't return OTS core after CALL EXTEND>)
> ; End of IF20
END