|
|
BSD 4.2
.asciz "$Header: /var/lib/cvsd/repos/CSRG/42BSD/ucb/lisp/franz/vax/qfuncl.c,v 1.1.1.1 2018/04/24 16:12:54 root Exp $"
/* -[Mon Mar 21 17:04:58 1983 by jkf]-
* qfuncl.c $Locker: $
* lisp to C interface
*
* (c) copyright 1982, Regents of the University of California
*/
/*
* This is written in assembler but must be passed through the C preprocessor
* before being assembled.
*/
#include "ltypes.h"
#include "config.h"
/* important offsets within data types for atoms */
#define Atomfnbnd 8
/* for arrays */
#define Arrayaccfun 0
#ifdef PROF
.set indx,0
#define Profile \
movab prbuf+indx,r0 \
.set indx,indx+4 \
jsb mcount
#define Profile2 \
movl r0,r5 \
Profile \
movl r5,r0
#else
#define Profile
#define Profile2
#endif
#ifdef PORTABLE
#define NIL _nilatom
#define NP _np
#define LBOT _lbot
#else
#define NIL 0
#define NP r6
#define LBOT r7
#endif
/* transfer table linkage routine */
.globl _qlinker
_qlinker:
.word 0xfc0 # save all possible registers
Profile
tstl _exception # any pending exceptions
jeql noexc
tstl _sigintcnt # is it because of SIGINT
jeql noexc # if not, just leave
pushl $2 # else push SIGINT
calls $1,_sigcall
noexc:
movl 16(fp),r0 # get return pc
addl2 -4(r0),r0 # get pointer to table
movl 4(r0),r1 # get atom pointer
retry: # come here after undef func error
movl Atomfnbnd(r1),r2 # get function binding
jleq nonex # if none, leave
tstl _stattab+2*4 # see if linking possible (Strans)
jeql nolink # no, it isn't
ashl $-9,r2,r3 # check type of function
cmpb $/**/BCD,_typetable+1[r3]
jeql linkin # bcd, link it in!
cmpb $/**/ARRAY,_typetable+1[r3] # how about array?
jeql doarray # yep
nolink:
pushl r1 # non, bcd, call interpreter
calls $1,_Ifuncal
ret
/*
* handle arrays by pushing the array descriptor on the table and checking
* for a bcd array handler
*/
doarray:
ashl $-9,Arrayaccfun(r2),r3 # get access function addr shifted
cmpb $/**/BCD,_typetable+1[r3] # bcd??
jneq nolink # no, let funcal handle it
#ifdef PORTABLE
movl NP,r4
movl r2,(r4)+ # store array header on stack
movl r4,NP
#else
movl r2,(r6)+ # store array header on stack
#endif
movl *(r2),r2 # get in func addr
jmp 2(r2) # jump in beyond calls header
linkin:
ashl $-9,4(r2),r3 # check type of function discipline
cmpb $0,_typetable+1[r3] # is it string?
jeql nolink # yes, it is a c call, so dont link in
movl (r2),r2 # get function addr
movl r2,(r0) # put fcn addr in table
jmp 2(r2) # enter fcn after mask
nonex: pushl r0 # preserve table address
pushl r1 # non existant fcn
calls $1,_Undeff # call processor
movl r0,r1 # back in r1
movl (sp)+,r0 # restore table address
jbr retry # for the retry.
.globl __erthrow # errmessage for uncaught throws
__erthrow:
.asciz "Uncaught throw from compiled code"
.globl _tynames
_tynames:
.long NIL # nothing here
.long _lispsys+20*4 # str_name
.long _lispsys+21*4 # atom_name
.long _lispsys+19*4 # int_name
.long _lispsys+23*4 # dtpr_name
.long _lispsys+22*4 # doub_name
.long _lispsys+58*4 # funct_name
.long _lispsys+103*4 # port_name
.long _lispsys+47*4 # array_name
.long NIL # nothing here
.long _lispsys+50*4 # sdot_name
.long _lispsys+53*4 # val_nam
.long NIL # hunk2_nam
.long NIL # hunk4_nam
.long NIL # hunk8_nam
.long NIL # hunk16_nam
.long NIL # hunk32_nam
.long NIL # hunk64_nam
.long NIL # hunk128_nam
.long _lispsys+124*4 # vector_nam
.long _lispsys+125*4 # vectori_nam
/* Quickly allocate small fixnums */
.globl _qnewint
_qnewint:
Profile
cmpl r5,$1024
jgeq alloc
cmpl r5,$-1024
jlss alloc
moval _Fixzero[r5],r0
rsb
alloc:
movl _int_str,r0 # move next cell addr to r0
jlss callnewi # if no space, allocate
incl *_lispsys+24*4 # inc count of ints
movl (r0),_int_str # advance free list
movl r5,(r0) # put baby to bed.
rsb
callnewi:
pushl r5
calls $0,_newint
movl (sp)+,(r0)
rsb
/* _qoneplus adds one to the boxed fixnum in r0
* and returns a boxed fixnum.
*/
.globl _qoneplus
_qoneplus:
Profile2
addl3 (r0),$1,r5
#ifdef PORTABLE
movl r6,NP
movl r6,LBOT
#endif
jmp _qnewint
/* _qoneminus subtracts one from the boxes fixnum in r0 and returns a
* boxed fixnum
*/
.globl _qoneminus
_qoneminus:
Profile2
subl3 $1,(r0),r5
#ifdef PORTABLE
movl r6,NP
movl r6,LBOT
#endif
jmp _qnewint
/*
* _qnewdoub quick allocation of a initialized double (float) cell.
* This entry point is required by the compiler for symmetry reasons.
* Passed to _qnewdoub in r4,r5 is a double precision floating point
* number. This routine allocates a new cell, initializes it with
* the given value and then returns the cell.
*/
.globl _qnewdoub
_qnewdoub:
Profile
movl _doub_str,r0 # move next cell addr to r0
jlss callnewd # if no space, allocate
incl *_lispsys+30*4 # inc count of doubs
movl (r0),_doub_str # advance free list
movq r4,(r0) # put baby to bed.
rsb
callnewd:
movq r4,-(sp) # stack initial value
calls $0,_newdoub
movq (sp)+,(r0) # restore initial value
rsb
.globl _qcons
/*
* quick cons call, the car and cdr are stacked on the namestack
* and this function is jsb'ed to.
*/
_qcons:
Profile
movl _dtpr_str,r0 # move next cell addr to r0
jlss getnew # if ran out of space jump
incl *_lispsys+28*4 # inc count of dtprs
movl (r0),_dtpr_str # advance free list
storit:
movl -(r6),(r0) # store in cdr
movl -(r6),4(r0) # store in car
rsb
getnew:
#ifdef PORTABLE
movl r6,NP
movab -8(r6),LBOT
#endif
calls $0,_newdot # must gc to get one
jbr storit # now initialize it.
/*
* Fast equivalent of newdot, entered by jsb
*/
.globl _qnewdot
_qnewdot:
Profile
movl _dtpr_str,r0 # mov next cell addr t0 r0
jlss mustallo # if ran out of space
incl *_lispsys+28*4 # inc count of dtprs
movl (r0),_dtpr_str # advance free list
clrq (r0)
rsb
mustallo:
calls $0,_newdot
rsb
/* prunel - return a list of dtpr cells to the free list
* this is called by the pruneb after it has discarded the top bignum
* the dtpr cells are linked through their cars not their cdrs.
* this returns with an rsb
*
* method of operation: the dtpr list we get is linked by car's so we
* go through the list and link it by cdr's, then have the last dtpr
* point to the free list and then make the free list begin at the
* first dtpr.
*/
qprunel:
movl r0,r2 # remember first dtpr location
rep: decl *_lispsys+28*4 # decrement used dtpr count
movl 4(r0),r1 # put link value into r1
jeql endoflist # if nil, then end of list
movl r1,(r0) # repl cdr w/ save val as car
movl r1,r0 # advance to next dtpr
jbr rep # and loop around
endoflist:
movl _dtpr_str,(r0) # make last 1 pnt to free list
movl r2,_dtpr_str # & free list begin at 1st 1
rsb
/*
* qpruneb - called by the arithmetic routines to free an sdot and the dtprs
* which hang on it.
* called by
* pushl sdotaddr
* jsb _qpruneb
*/
.globl _qpruneb
_qpruneb:
Profile
movl 4(sp),r0 # get address
decl *_lispsys+48*4 # decr count of used sdots
movl _sdot_str,(r0) # have new sdot point to free list
movl r0,_sdot_str # start free list at new sdot
movl 4(r0),r0 # get address of first dtpr
jneq qprunel # if exists, prune it
rsb # else return.
/*
* _qprunei
* called by the arithmetic routines to free a fixnum cell
* calling sequence
* pushl fixnumaddr
* jsb _qprunei
*/
.globl _qprunei
_qprunei:
Profile
movl 4(sp),r0 # get address of fixnum
cmpl r0,$_Lastfix # is it a small fixnum
jleq skipit # if so, leave
decl *_lispsys+24*4 # decr count of used ints
movl _int_str,(r0) # link the fixnum into the free list
movl r0,_int_str
skipit:
rsb
.globl _qpopnames
_qpopnames: # equivalent of C-code popnames, entered by jsb.
movl (sp)+,r0 # return address
movl (sp)+,r1 # Lower limit
movl _bnp,r2 # pointer to bind stack entry
qploop:
subl2 $8,r2 # for(; (--r2) > r1;) {
cmpl r2,r1 # test for done
jlss qpdone
movl (r2),*4(r2) # r2->atm->a.clb = r2 -> val;
brb qploop # }
qpdone:
movl r1,_bnp # restore bnp
jmp (r0) # return
/*
* _qget : fast get subroutine
* (get 'atom 'ind)
* called with -8(r6) equal to the atom
* -4(r6) equal to the indicator
* no assumption is made about LBOT
* unfortunately, the atom may not in fact be an atom, it may
* be a list or nil, which are special cases.
* For nil, we grab the nil property list (stored in a special place)
* and for lists we punt and call the C routine since it is most likely
* and error and we havent put in error checks yet.
*/
.globl _qget
_qget:
Profile
movl -4(r6),r1 # put indicator in r1
movl -8(r6),r0 # and atom into r0
jeql nilpli # jump if atom is nil
ashl $-9,r0,r2 # check type
cmpb _typetable+1[r2],$1 # is it a symbol??
jneq notsymb # nope
movl 4(r0),r0 # yes, put prop list in r1 to begin scan
jeql fail # if no prop list, we lose right away
lp: cmpl r1,4(r0) # is car of list eq to indicator?
jeql good # jump if so
movl *(r0),r0 # else cddr down list
jneq lp # and jump if more list to go.
fail: subl2 $8,NP # unstack args
rsb # return with r0 eq to nil
good: movl (r0),r0 # return cadr of list
movl 4(r0),r0
subl2 $8,NP #unstack args
rsb
nilpli: movl _lispsys+64*4,r0 # want nil prop list, get it specially
jneq lp # and process if anything there
subl2 $8,NP #unstack args
rsb # else fail
notsymb:
#ifdef PORTABLE
movl r6,NP
movab -8(r6),LBOT # must set up LBOT before calling
#else
movab -8(r6),LBOT # must set up LBOT before calling
#endif
calls $0,_Lget # not a symbol, call C routine to error check
subl2 $8,NP #unstack args
rsb # and return what it returned.
/*
* _qexarith exact arithmetic
* calculates x=a*b+c where a,b and c are 32 bit 2's complement integers
* whose top two bits must be the same (i.e. the are members of the set
* of valid fixnum values for Franz Lisp). The result, x, will be 64 bits
* long but since each of a, b and c had only 31 bits of precision, the
* result x only has 62 bits of precision. The lower 30 bits are returned
* in *plo and the high 32 bits are returned in *phi. If *phi is 0 or -1 then
* x doesn't need any more than 31 bits plus sign to describe, so we
* place the sign in the high two bits of *plo and return 0 from this
* routine. A non zero return indicates that x requires more than 31 bits
* to describe.
*/
.globl _qexarith
/* qexarith(a,b,c,phi,plo)
* int *phi, *plo;
*/
_qexarith:
emul 4(sp),8(sp),12(sp),r2 #r2 = a*b + c to 64 bits
extzv $0,$30,r2,*20(sp) #get new lo
extv $30,$32,r2,r0 #get new carry
beql out # hi = 0, no work necessary
movl r0,*16(sp) # save hi
mcoml r0,r0 # Is hi = -1 (it'll fit in one word)
bneq out # it doesn't
bisl2 $0xc0000000,*20(sp) # alter low so that it is ok.
out: rsb
/*
* pushframe : stack a frame
* When this is called, the optional arguments and class have already been
* pushed on the stack as well as the return address (by virtue of the jsb)
* , we push on the rest of the stuff (see h/frame.h)
* for a picture of the save frame
*/
.globl _qpushframe
_qpushframe:
Profile
movl _errp,-(sp)
movl _bnp,-(sp)
movl NP,-(sp)
movl LBOT,-(sp)
pushr $0x3f00 # save r13(fp), r12(ap),r11,r10,r9,r8
movab 6*4(sp),r0 # return addr of lbot on stack
clrl _retval # set retval to C_INITIAL
#ifndef SPISFP
jmp *40(sp) # return through return address
#else
movab -4(sp),sp
movl sp,(sp)
movl _xsp,-(sp)
jmp *48(sp)
#endif
/*
* Ipushf : stack a frame, where space is preallocated on the stack.
* this is like pushframe, except that it doesn't alter the stack pointer
* and will save more registers.
* This might be written a little more quickly by having a bigger register
* save mask, but this is only supposed to be an example for the
* IBM and RIDGE people.
*/
#ifdef SPISFP
.globl _Ipushf
_Ipushf:
.word 0
addl3 $96,16(ap),r1
movl 12(ap),-(r1)
movl 8(ap),-(r1)
movl 4(ap),-(r1)
movl 16(fp),-(r1)
movl _errp,-(r1)
movl _bnp,-(r1)
movl NP,-(r1)
movl LBOT,-(r1)
movl r1,r0
movq 8(fp),-(r1) /* save stuff in the same order unix saves them
(r13,r12,r11,r10,r9,r8) and then add extra
for vms (sp,r7,r6,r5,r4,r3,r2) */
movq r10,-(r1)
movq r8,-(r1)
movab 20(ap),-(r1) /* assumes Ipushf allways called by calls, with
the stack alligned */
movl _xsp,-(r1)
movq r6,-(r1)
movq r4,-(r1)
movq r2,-(r1)
clrl _retval
ret
#endif
/*
* qretfromfr
* called with frame to ret to in r11. The popnames has already been done.
* we must restore all registers, and jump to the ret addr. the popping
* must be done without reducing the stack pointer since an interrupt
* could come in at any time and this frame must remain on the stack.
* thus we can't use popr.
*/
.globl _qretfromfr
_qretfromfr:
Profile
movl r11,r0 # return error frame location
subl3 $24,r11,sp # set up sp at bottom of frame
movl sp,r1 # prepare to pop off
movq (r1)+,r8 # r8,r9
movq (r1)+,r10 # r10,r11
movq (r1)+,r12 # r12,r13
movl (r1)+,LBOT # LBOT (lbot)
movl (r1)+,NP # NP (np)
jmp *40(sp) # jump out of frame
#ifdef SPISFP
/*
* this is equivalent to qretfro for a native VMS system
*
*/
.globl _Iretfrm
_Iretfrm:
.word 0
movl 4(ap),r0 # return error frame location
movl r0,r1
movq -(r1),ap
movq -(r1),r10
movq -(r1),r8
movl -(r1),sp
movl -(r1),_xsp
movq -(r1),r6
movq -(r1),r4
movq -(r1),r2
movl r0,r1
movl (r1)+,LBOT
movl (r1)+,NP
jmp *16(r0)
#endif
/*
* This routine gets the name of the inital entry point
* It is here so it can be under ifdef control.
*/
.globl _gstart
_gstart:
.word 0
#if os_vms
moval _$$$start,r0
#else
moval start,r0
#endif
ret
.globl _proflush
_proflush:
.word 0
ret
/*
* The definition of mcount must be present even when the C code
* isn't being profiled, since lisp code may reference it.
*/
#ifndef os_vms
.globl mcount
mcount:
#endif
.globl _mcount
_mcount:
#ifdef PROF
movl (r0),r1
bneq incr
movl _countbase,r1
beql return
addl2 $8,_countbase
movl (sp),(r1)+
movl r1,(r0)
incr:
incl (r1)
return:
#endif
rsb
/* This must be at the end of the file. If we are profiling, allocate
* space for the profile buffer
*/
#ifdef PROF
.data
.comm _countbase,4
.lcomm prbuf,indx+4
.text
#endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.