Trailing-Edge
-
PDP-10 Archives
-
SRI_NIC_PERM_FS_1_19910112
-
c/old/lib/crt.c
There are 9 other files named crt.c in the archive. Click here to see a list.
/* <KCC.LIB>CRT.C.14, 26-Jul-85 14:35:26, Edit by KRONJ */
/* Fix $MAPSC to work for pre-release-5 TOPS-20 */
/*
** CRT - C Run Time machine-language support routines
** Split out and rewritten from TOPS20.FAI by KLH@SRI-NIC, June 1985
*/
#include "c-env.h"
entry $start, _exit; /* System-dependent routines */
entry etext; /* 1st addr above program text (code) region */
entry edata; /* 1st addr above initialized data region */
entry end; /* 1st addr above uninitialized data */
/* == 1st addr of dynamically allocated stuff.*/
entry $byte,$adjbp,$subbp,$bpcnt; /* Byte pointer support */
entry $dfix,$dflot; /* int <-> double conversion */
entry $spush,$spop; /* Structure args & retvals */
entry $ret; /* Handy return points. Simple return. */
entry $retp,$rett; /* Returns +1 Positive (True) */
entry $retz,$retf; /* Returns 0 Zero (False) */
entry $retn; /* Returns -1 Negative */
entry $zero; /* Double zero for floating constant ref */
#if SYS_T20+SYS_10X
entry $mapsc; /* Hack, so fork() can get at it. */
#endif
extern _runtm(); /* C Unix-environment runtime */
/**************************************************************/
#asm /* Start of moby assembler code stuff */
A=1
B=2
C=3
R=15 ; for dfix, spush.
S=16 ; for dfix, spush, byte.
P=17
OPDEF RET [POPJ 17,]
; System-dependent runtime code should contain the following:
; (1) A $START label. The process will be started at this point,
; and the code should:
; - Set up the stack and point P at it.
; - Arrange for whatever memory shuffling is desired,
; including extended addressing.
; - Set the global vars END, ETEXT, EDATA.
; - Finally, jump back to SREADY.
; (2) A .EXIT label, for a function that should halt the process
; normally with the exit status provided by arg 1.
; Link to runtime initializations
INITS: BLOCK 1 ;Make space for LINK to fill in with init chain
.LNKEND 1,INITS ;Tell it to head the chain here
SREADY: SETZ 0, ; Make sure any refs to 0 just get 0.
SKIPE R,INITS ; Are there any inits set up by loader?
PUSHJ P,1(R) ; Yeah, go hack them (obscure feature)
PUSHJ P,.RUNTM ; Invoke higher level setup. This will call MAIN.
; This should exit by itself, but just in case
PUSH P,1 ; we return, pass on the return value
PUSHJ P,.EXIT ; and exit forcibly, without any cleanup.
JRST .-1 ; Insist.
#if SYS_T20+SYS_10X
; ************************************************************
; C low-level Runtime Support Routines
; TOPS-20/TENEX Operating System
; ************************************************************
SEARCH MONSYM
.JBHSP==75 ;Contains page number of start of high seg
.JBHRL==115 ;high seg first free addr,,highest addr
.JBSA==120 ;Contains first free loc low seg,,start addr
; Start of program
$START: RESET% ;Initialize the world.
MOVE P,.JBSA ;Get top of low core (bottom of stack)
HLR P,P ; in both halves.
HRRZ 15,P ;Save ptr to end of data in words
IOR 15,$BYTE ;Make a byte ptr
MOVEM 15,EDATA ;Save the ptr to the end of data
SETCM 16,.JBHSP ;Get neg page no of high core start, minus one.
ROT 16,^D27 ;Make negation of (address,,1).
ADD P,16 ;Add to make stack pointer.
#if SYS_T20
XMOVEI 15,0 ;Get section number in left half
JUMPN 15,ESTART ;If non-zero, jump to extended start
#endif
MOVE 16,.JBHSP ;Get first high seg. page
ROT 16,^D9 ;Make it an address
HLRZ 15,.JBHRL ;Get first free high seg. relative address
ADD 15,16 ;Make it absolute
IOR 15,$BYTE ;Make a byte pointer
MOVEM 15,END ;Save it as the END
MOVEM 15,ETEXT ;Same as END
;; MOVEM 15,CURBRK ;Save it as the current break
#if SYS_T20
SKIPE $EXADF ;Want extended addressing?
JRST DOEXTA ; Yeah, must do hairy setup
#endif
JRST SREADY ; All ready to go, jump to start the rest.
.EXIT: HALTF% ;Exit to monitor.
HRROI 1,[ASCIZ/Cannot continue/]
ESOUT% ;Complain if continued
JRST .EXIT ; and stop again.
#if SYS_T20
DOEXTA: SETZ 11, ;From section zero
DOMOVE: MOVEI 10,1 ;Destination section is 1
DMOVE 6,[ .FHSLF
.FHSLF ] ;From and to ourself
PUSHJ P,$mapsc ;Map section
SETO 1, ;1 Unmapping
MOVSI 2,.FHSLF ;2 Starting on page zero of ourself
MOVE 3,[PM%CNT!PM%EPN!1000] ;3 All pages of section zero
SETZ 4, ;4 No PC flags
MOVSI 5,1 ;5 Section number 1
HRRI 5,ESTART ; To make extended address
DMOVE 6,[ PMAP% ;6 Unmap current section
XJRSTF 4 ] ;7 Jump into section 1
JRST 6 ;Go do it
ESTART: XMOVEI 11,. ;Get section number we are in
HLRZS 11 ;Isolate it
CAIE 11,1 ;Are we in section 1?
JRST DOMOVE ;No, so go there
MOVEI 1,1 ;Get section number for code
MOVEM 1,$EXADF ;Remember where code lives
;; Make a stack in section 2
SETZ 1, ;Creating
HRRZI 2,2 ;In section 2
HRLI 2,.FHSLF ;On ourself
MOVEI 3,1 ;One section
SMAP% ;Make it
MOVEI P,1000 ;Make stack starting at first page
HRLI P,2 ;Of section 2
SETZM -1(P) ;Clear out word before
SETZM @[170000,,776000] ;And word after (EFIW)
MOVEI 1,2000 ;Make page number of start
HRLI 1,.FHSLF ;On self
SETZ 2, ;No access privileges
SPACS% ;Write-protect page zero
ADDI 1,777 ;Now last page
SPACS% ;Similarly write-protect to bracket stack
;; Set up the EDATA, ETEXT, and END for memory allocation
HRLZI 1,2 ;In section 1
IOR 1,XBYTE ;Make it a byte pointer
MOVEM 1,EDATA ;Both initialized data and code
MOVEM 1,ETEXT ;are in section 1
SETZ 1, ;Make a new section
HRRZI 2,3 ;In section 3
HRLI 2,.FHSLF ;For us
MOVEI 3,1 ;One section
SMAP%
HRLZI 1,3 ;In section 3
IOR 1,XBYTE ;Make it a byte pointer
MOVEM 1,END ;First location past end of program
;; MOVEM 1,CURBRK ;Setup the current break
;; Set up OWGBPs in byte-pointer table
MOVE 1,[XBYTE,,$BYTE] ;From OWG table into byte constructor table
BLT 1,$BYTE+^D8 ;Move OWGs over so contructed BPs are OWGs
JRST SREADY ; Done, return to main startup.
#endif /* T20 */
/*
** $MAPSC - Check map for one section and copy across to new fork.
** This auxiliary subroutine is also used by FORK().
** Call with
** 5/unchangeable by $mapsc
** 6/destination fork handle
** 7/source fork handle
** 10/destination section
** 11/source section
**
** We use the stack for scratch space, so have to be careful.
*/
$mapsc: MOVE 16,P /* Copy stack pointer */
ADJSP P,10000 /* Give us some stack space */
/*
** Normal TOPS-20 (releases 5 and beyond) code.
** Read in the map all at once, and then do individual copies.
**
** Note that no SMAP% is needed to create the destination section;
** it will be done implicitly by the PMAP%s.
*/
#if SYS_T20
MOVE 1,11 /* Copy source section number */
HRL 1,7 /* and source handle */
RSMAP% /* Read section map */
ERJMP mapsc3 /* lost, go try it the old way */
AOJE 1,mapsc2 /* If unmapped, dont copy */
/* Have section, read page maps */
MOVEI 1,4 /* Length of argument block is 4 */
MOVEI 2,1000 /* Want a full section of pages */
DMOVEM 1,1(16) /* Save as first two words of argument block */
MOVE 1,11 /* Get source section number */
LSH 1,^D9 /* into page number */
XMOVEI 2,5(16) /* and a pointer to some scratch space */
DMOVEM 1,3(16) /* as third and fourth words of block */
HRLZ 1,7 /* On source handle */
XMOVEI 2,1(16) /* with argument block */
XRMAP% /* read in a bunch of paging info at once */
/* Now set up for individual page loop */
XMOVEI 13,4000(16) /* Get a place above the top of XRMAP% info */
LSH 13,-^D9 /* as page number */
HRLI 13,.FHSLF /* of self (not source) */
MOVE 14,10 /* Get destination section this time */
LSH 14,^D9 /* as page number */
HRLI 14,-1000 /* make AOBJN pointer */
XMOVEI 12,5(16) /* point to start of XRMAP% block */
mapse0: DMOVE 1,0(12) /* Get # of page in 1, page access wd in 2 */
PUSHJ 17,mappag /* Map that page */
ADDI 12,2 /* Move over XRMAP% info to next page */
AOBJN 14,mapse0 /* Loop over all pages in section */
JRST mapsc4 /* Go on to cleanup and return */
#endif /* T20 */
/*
** Fall into here when not T20 (i.e. TENEX).
** Also come here if RSMAP% fails (pre-rel-5 TOPS20 or out of range section).
** Do it the old way, with a RPACS% per page.
*/
mapsc3: CAIN 10,0 /* Make sure destination */
CAIE 11,0 /* and source sections are both zero */
JRST mapsc2 /* Can't handle non-zero, just return */
MOVEI 13,777(16)
LSH 13,-^D9 /* Get page # of a scratch page */
HRLI 13,.FHSLF /* Make page handle */
MOVSI 14,-1000 /* Set up AOBJN pointer */
mapsc5: MOVSI 1,(7) /* Get source fork handle in LH */
HRRI 1,(14) /* Source page # */
RPACS% /* Get access of page */
PUSHJ P,MAPPAG /* Map the page over */
AOBJN 14,mapsc5
/*
** Here after either sequence of code.
** Unmap the scratch page and return.
*/
mapsc4: SETO 1, /* Unmapping */
MOVE 2,13 /* Into temporary page */
MOVE 3,[PM%EPN] /* One page, extended addressing */
PMAP% /* Do the unmap */
/*
** Here after scratch space unmapped or if error occurred.
** Give our space back to the stack and return.
*/
mapsc2: ADJSP 17,-10000 /* Get space back */
POPJ 17, /* Done with mapping section */
; Map one page of fork into another (can be same) fork
; 1/ page handle (fork/file,,#) of source
; 2/ page access bits for above
; 6 / fork handle of destination
; 12 / <don't touch>
; 13 / page handle of temporary page on stack for our own use
; 14 / AOBJN pointer to page number of dest, including section
mappag: TDNN 2,[RM%PEX] ; Check page access bits - page exists?
RET ;No, dont map across
CAMN 1,13 ; Page handle same as our temporary page?
RET ;Yes, dont copy
MOVE 4,2 ; Save access bits.
MOVEI 2,(14) ; OK, copy to this dest page number
HRLI 2,(6) ; In new inferior fork
MOVE 3,[PM%RD!PM%EX!PM%CPY!PM%EPN] ;Copy-on-write, one page
PMAP% ;Copy across, creating section if empty
#if SYS_T20
JUMPGE 1,MAPPG9 ;If directly from file, done with mapping
#endif
#if SYS_10X
TDNN 4,[1B10] ; See if "Private" access bit is set.
JRST MAPPG9 ; Nope.
#endif
;; Here when page is private, break copy-on-write link
MOVE 1,2 ;Now get page again as source this time
MOVE 2,13 ;Get PMAP pointer to temporary page
MOVE 3,[PM%RD!PM%WR!PM%EPN] ;Write not copy-on-write to self from fork
PMAP% ;Copy the page
ERJMP .+1 ;Dont die if tried to make circular
HRRZ 1,13 ;Get pointer again
LSH 1,^D9 ;As address
MOVES (1) ;Break copy-on-write link in subfork to us
MAPPG9: RET ;All done
#endif /* T20+10X */
#if SYS_WAITS
; ************************************************************
; C low-level Runtime Support Routines
; WAITS Operating System
; ************************************************************
JOBREL==44 ; highest core usage
JOBFF==121 ; first free location from monitor tables
JOBHRL==115 ; Highest addr in high segment
$START: RESET
MOVE P,JOBFF
HRL P,P ; Set up stack pointer
MOVE R,JOBREL ; get max core usage
ADD R,$STKSZ ; get some stack space
CORE R, ; ask for more core
JRST .+1 ; no space, tough
MOVE R,JOBREL ; get highest usage
MOVEM R,JOBFF ; Update JOBFF past allocated stack
IOR R,$BYTE ; Make byte ptr
MOVEM R,END ; This is where to allocate new memory.
MOVEI R,(P) ; Get 1st free data loc (same as PDL start)
IOR R,$BYTE ; Make it a byte ptr
MOVEM R,EDATA ; This is where data ended.
HRRZ R,JOBHRL ; Get highest addr in upper segment
IOR R,$BYTE
MOVEM R,ETEXT ; This is end of code.
JRST SREADY ; All set, jump to start the rest.
.EXIT: EXIT 0, ; exit to monitor
JRST .EXIT ; no reentry
#endif /* WAITS */
#if SYS_ITS
; ************************************************************
; C low-level Runtime Support Routines
; ITS Operating System
; ************************************************************
SSEGLO==20 ; STINK sets this to <loseg org>,,<loseg top> ; org always 0
SSEGHI==21 ; STINK sets this to <hiseg org>,,<hiseg top>
PG$BTS==12 ; log 2 of ITS page size
PG$SIZ==2000 ; # words in ITS page
PG$MSK==<PG$SIZ-1>
; For the time being, we duplicate the TOPS-20 arrangement of having
; the stack at the end of the low segment, and new allocated memory
; at the end of the high segment. If we want to use all of the address
; space, we can always make malloc smarter.
$START:
HRRZ P,SSEGLO ; Set up stack pointer
ADDI P,1
MOVN R,$STKSZ
HRL P,R ; Now have -<count> in LH
MOVEI 1,PG$SIZ-1(P)
LSH 1,-PG$BTS ; Find 1st page # we dont have
MOVE 2,$STKSZ
ADDI 2,PG$SIZ-1
LSH 2,-PG$BTS ; Find # pages we need for stack
IMUL 2,[-1,,0]
HRRI 2,(1) ; Now have page AOBJN
.CALL [ SETZ ; Allocate pages for the stack.
SIXBIT /CORBLK/
MOVEI %CBNDR+%CBNDW
MOVEI %JSELF
2
SETZI %JSNEW]
.LOSE ; Shouldnt fail.
MOVEI R,(P) ; Now set end of loaded data
IOR R,$BYTE
MOVEM R,EDATA
HRRZ R,SSEGHI
ADDI R,1
IOR R,$BYTE ; Must make into char ptrs.
MOVEM R,ETEXT ; End of code
ADDI R,PG$SIZ-1
ANDCMI R,PG$MSK
MOVEM R,END ; This is where to allocate new mem.
JRST SREADY ; All set, jump to start the rest.
.EXIT: MOVE 1,ARG1(P) ; Just in case, leave "exit status" in AC 1.
.LOGOUT 1, ; Return to superior (log out if disowned)
JRST .EXIT ; Never continue.
#endif /* ITS */
$$DATA
$EXADF: 0 ; Patch non-zero to run extended.
$STKSZ: 10000 ; Minimum stack size to allocate at startup.
END: 0 ; End of the address space (where to alloc new stuff)
ETEXT: 0 ; End of text segment
EDATA: 0 ; End of data segment
$$CODE
$RETF:
$RETZ: SETZ 1, ; Return Zero (also False)
$RET: RET
$RETT:
$RETP: MOVEI 1,1 ; Return Positive (also True)
RET
$RETN: SETO 1, ; Return Negative
RET
$ZERO: 0 ; Double zero, for floating constant reference.
0
$$DATA
$BYTE: 331100,,0 ;Bits to drop onto pointers to make them bytes
221100,,0 ;(Changed to OWGBPs if we go extended)
111100,,0
001100,,0
350700,,0 ;And the same for 7-bit bytes
260700,,0
170700,,0
100700,,0
010700,,0
$$CODE
XBYTE: 700000,,0 ;OWGBPs to replace $BYTE in extended sections
710000,,0
720000,,0
730000,,0
620000,,0
630000,,0
640000,,0
650000,,0
660000,,0
; What this code section used to be:
;<KCC.LIB>BYTE.FAI.14, 24-Mar-85 11:35:42, Edit by KRONJ
; Fix calls to $BPCNT in $SUBBP
;<KCC.LIB>BYTE.FAI.13, 15-Mar-85 12:26:44, Edit by KRONJ
; New fixed register calling convention
;
; TITLE BYTE - Byte manipulation subroutines for C
; SUBTTL David Eppstein / Stanford University / 22-May-1984
;
; Routines for pseudo-op expansion: $ADJBP $SUBBP $BPCNT
; calling convention is:
; MOVE 15,R
; MOVE 16,ADDR
; PUSHJ P,$FOO
;
; A return value if any is left in S.
;
; These routines should be as general as possible so that I can decide to
; use other byte pointers than are currently in KCC and make it still work.
;
; First the jacket routines:
; Here at start of simulation, set up registers and stack
BYTENT: EXCH A,0(P) ;Save register, get return
PUSH P,B ;Save another register
PUSH P,A ;Save return address again
DMOVE A,15 ;Put registers where caller expects them
RET ;Go run main routine
; Here when simulation complete, return value in R
BYTRET: MOVE 15,A ;Get return value
POP P,B ;Restore registers
POP P,A
RET ;Return from opcode simulation
; PTRSIZ - return bytes/word of pointer
; Call with B/pointer, returns S/size
PTRSIZ: CAML B,[444500,,0] ;OWGBP?
JUMPL B,PTRSZ0 ;Yes, handle differently
PUSH P,A ;Save registers
PUSH P,B
LDB S,[POINT 6,B,11] ;No, just get S field
MOVEI A,^D36 ;Get number of bits per word
IDIV A,S ;Make number of bytes per word
MOVE S,A ;Put where caller expects it
POP P,B
POP P,A
RET ;And return with it
PTRSZ0: LDB S,[POINT 6,B,5] ;OWG, get P field
HLRZ S,OWGSIZ-45(S) ;Find size for that one
RET ;Return with it
; For each OWG P field we have an entry in the following with
; LH/bytes per word, RH/offset in word
OWGSIZ: 6,,-1 ;45 = (POINT 6,)
6,,0 ;46
6,,1 ;47
6,,2 ;50
6,,3 ;51
6,,4 ;52
6,,5 ;53
4,,-1 ;54 = (POINT 8,)
4,,0 ;55
4,,1 ;56
4,,2 ;57
4,,3 ;60
5,,-1 ;61 = (POINT 7,)
5,,0 ;62
5,,1 ;63
5,,2 ;64
5,,3 ;65
5,,4 ;66
4,,-1 ;67 = (POINT 9,)
4,,0 ;70
4,,1 ;71
4,,2 ;72
4,,3 ;73
2,,-1 ;74 = (POINT 18,)
2,,0 ;75
2,,1 ;76
; $ADBJP - simulate ADJBP instruction for losing CPUs
$ADJBP: PUSHJ P,BYTENT ;Get count and pointer
PUSH P,B ;Put pointer in a safe place
PUSHJ P,PTRSIZ ;Get byte size of pointer
IDIV A,S ;Get num words in A, num bytes in B
JUMPGE B,ADJBP0 ;If non-negative, ok
ADD B,S ;Negative, make positive
SUBI A,1 ;And fix up word count
ADJBP0: POP P,S ;Get byte pointer back
ADD A,S ;Offset by word count
ADJBP1: JUMPE B,BYTRET ;If no byte offset, done
IBP A ;Offset by one
SOJA B,ADJBP1 ;Back for another
; $SUBBP - subtract one byte pointer from another
; PUSHJ P,$SUBBP
; IFIW R,ADDR
; ADJBP R,ADDR
; should leave R as it was originally.
$SUBBP: PUSHJ P,BYTENT ;Copy pointers in A and B
PUSHJ P,$BPCNT ;Convert copy of B still in S into count in 15
MOVE 16,A ;Now get other pointer
MOVN A,15 ;And save count negated
PUSHJ P,$BPCNT ;Convert first pointer to count to count
ADD A,15 ;Combine results
JRST BYTRET ;Thats all!
; $BPCNT - turn byte pointer into pure number
; suitable for comparison, subtraction, etc.
; Even works with indirect and indexed pointers.
$BPCNT: PUSHJ P,BYTENT ;Get byte pointer
PUSHJ P,PTRSIZ ;Find number of bytes per word
MOVE A,B ;Get pointer
CAML B,[444500,,0] ;OWGBP?
JUMPL B,BPCNT0 ;Yes, handle differently
TLZ A,777700 ;Not, clear out P and S
TLO A,400000 ;Make IFIW
XMOVEI A,(A) ;Canonicalize
IMUL A,S ;Make number of bytes
PUSH P,A ;Save
LDB S,[POINT 6,B,11] ;Get S field
MOVEI A,^D36 ;Get bits per word
LSH B,-^D30 ;Get P field
SUB A,B ;Negate mod 36 to number of bits from start
IDIV A,S ;Make number of bytes that fit in that
SUBI A,1 ;And a pinch to grow an inch
POP P,S ;Get count back
ADD A,S ;Add in
JRST BYTRET ;All done
; Here to count OWGBP
BPCNT0: TLZ A,770000 ;Get just address part, make absolute
IMUL A,S ;Turn into number of bytes
LSH B,-^D30 ;Get PS field again
HRRE B,OWGSIZ-45(B) ;Byte offset
ADD A,B ;Add it up
JRST BYTRET ;All done
; This is where the code came from:
;<KCC.LIB>DFIX.FAI.6, 15-Mar-85 12:38:40, Edit by KRONJ
; New reentrant fixed register calling conventions
;
; TITLE DFIX - Double precision conversions for C
; SUBTTL David Eppstein / Stanford University / 31-May-1984
; Convert double precision to integer
;
; PUSHJ 17,$DFIX
;
; takes double from registers 15 and 16, leaves int in 15.
; Mostly stolen from Footran.
$DFIX:
#if CENV_DFL_H+CENV_DFL_S /* Hardware or software fmt */
PUSH P,A ;Save a register
HLRE A,R ;This mattered when shifts were bit-at-a-time
ASH A,-^D9 ;Get just exponent
JUMPGE R,DFIX0 ;Positive?
#if CENV_DFL_H
DMOVN R,R ;No, negate, orig sign still in 1B0[A]
#endif
#if CENV_DFL_S
DFN R,R+1
#endif
TRC A,777777 ;Watch for diff between twos and ones comp
DFIX0: TLZ R,777000 ;Bash exponent and sign ... now positive
#if CENV_DFL_S
LSH S,^D8 ; Flush exponent from low order word.
#endif
ASHC R,-233(A) ;Make an integer (may overflow)
TLNE A,(1B0) ;Original negative?
MOVN R,R ;Yup, negate first
POP P,A ;Restore registers
#endif /* H+S */
#if CENV_DFL_G
GFIXR==<026000,,0>
EXTEND R,[GFIXR R]
#endif
RET
; Convert integer to double precision
;
; PUSHJ 17,$DFLOT
;
; takes int from register 16, leaves double in 15 and 16.
; Again, stolen from Footran.
$DFLOT:
#if CENV_DFL_H
; Hardware format
LSHC R,^D36 ;Shift integer into R, zero 16
ASHC R,-10 ;Shift out to make room for exponent
TLC R,243000 ;Put exponent in place
DFAD R,[ 0
0 ] ;Normalize by adding zero
#endif
#if CENV_DFL_S
PUSH P,14
MOVE 14,R
SETZ 15, ; Get integer in 14, zero low order wd
ASHC 14,-10 ; Shift out to make room for exponent
TLC 14,243000 ; Put exponent in place
ASH 15,-10 ; Shift low order wd for more exponent room
TLZ 15,777000 ; Clear all bits of low wd sign+exp
TLO 15,<243000>-<033000> ; Low exp is 27. less than high exp
; Normalize by adding zero
UFA 15,[0] ; Sum of low parts to A+2
FADL 14,[0] ; Sum of high parts to A,A+1
UFA 15,16 ; Add low part of high sum to A+2
FADL 14,16 ; Add low sum to high sum
; Now return the double
MOVE 16,15
MOVE 15,14
POP P,14
#endif
#if CENV_DFL_G
GFLTR==<030000,,0>
EXTEND R,[GFLTR 16]
#endif
POPJ P, ;All done
; Where this code came from:
;<KCC.LIB>SPUSH.FAI.12, 15-Mar-85 13:12:39, Edit by KRONJ
; New reentrant calling conventions
;
; TITLE SPUSH - Push structure as function argument for KCC
; SUBTTL David Eppstein / Stanford University / 3-Jan-85
;
; PUSHJ 17,$SPUSH
;
; Pushes the number of words held in AC15 onto the stack.
; AC16 holds the address of the struct to push.
; AC15 should be the same on return.
; The count must be at least two for this to work correctly.
; KLH: the non-ADJSP version ought to be made better.
$SPUSH: PUSH P,S ;Save address
MOVE S,P ;To get another stack pointer
#if CENV_ADJSP
ADJSP P,-2(R) ;Make enough room for struct
#else
MOVEI R,-2(R)
HRLI R,(R)
ADD P,R
MOVEI R,2(R)
#endif /* No ADJSP */
PUSH P,A ;Then save a register
PUSH P,R ;Save count
POP S,A ;To get address back
POP S,R ;And return address
EXCH R,-1(P) ;Save ret addr where saved A was
PUSH P,R ;And save old A again
MOVE R,-1(P) ;Then get back count
; Stack now contains space for struct, then ret addr, then R, then A
; R contains count, A contains addr, S points to bottom of space - 1
SMOVE: PUSH S,(A) ;Move a word to stack
ADDI A,1 ;Prepare to move on
SOJG R,SMOVE ;Loop until done
POP P,A ;Restore saved register
POP P,R ;And count
POPJ 17, ;And return to caller
; PUSHJ 17,$SPOP
;
; Pops a stacked structure into the given address.
; Same calling conventions as $SPUSH.
; The stack pointer is left unchanged.
; Note that we go from bottom to top, so it is safe for
; the source and destination to overlap.
$SPOP: PUSH 17,R ;Save count
PUSH 17,A ;Get another register
XMOVEI A,-2(17) ;Point just above end of structure
SUB A,R ;Point to begining of source
SUBI S,1 ;Point one before beginning of dest
JRST SMOVE ;Go do move loop
#endasm /* Finally end moby assembler section! */