|
|
1.1 root 1: .asciz "$Header: qfuncl.c,v 1.9 83/09/12 14:05:29 sklower Exp $"
2:
3: /* -[Mon Mar 21 17:04:58 1983 by jkf]-
4: * qfuncl.c $Locker: $
5: * lisp to C interface
6: *
7: * (c) copyright 1982, Regents of the University of California
8: */
9:
10: /*
11: * This is written in assembler but must be passed through the C preprocessor
12: * before being assembled.
13: */
14:
15: #include "ltypes.h"
16: #include "config.h"
17:
18: /* important offsets within data types for atoms */
19: #define Atomfnbnd 8
20:
21: /* for arrays */
22: #define Arrayaccfun 0
23:
24: #ifdef PROF
25: .set indx,0
26: #define Profile \
27: movab prbuf+indx,r0 \
28: .set indx,indx+4 \
29: jsb mcount
30: #define Profile2 \
31: movl r0,r5 \
32: Profile \
33: movl r5,r0
34: #else
35: #define Profile
36: #define Profile2
37: #endif
38:
39: #ifdef PORTABLE
40: #define NIL _nilatom
41: #define NP _np
42: #define LBOT _lbot
43: #else
44: #define NIL 0
45: #define NP r6
46: #define LBOT r7
47: #endif
48:
49:
50: /* transfer table linkage routine */
51:
52: .globl _qlinker
53: _qlinker:
54: .word 0xfc0 # save all possible registers
55: Profile
56: tstl _exception # any pending exceptions
57: jeql noexc
58: tstl _sigintcnt # is it because of SIGINT
59: jeql noexc # if not, just leave
60: pushl $2 # else push SIGINT
61: calls $1,_sigcall
62: noexc:
63: movl 16(fp),r0 # get return pc
64: addl2 -4(r0),r0 # get pointer to table
65: movl 4(r0),r1 # get atom pointer
66: retry: # come here after undef func error
67: movl Atomfnbnd(r1),r2 # get function binding
68: jleq nonex # if none, leave
69: tstl _stattab+2*4 # see if linking possible (Strans)
70: jeql nolink # no, it isn't
71: ashl $-9,r2,r3 # check type of function
72: cmpb $/**/BCD,_typetable+1[r3]
73: jeql linkin # bcd, link it in!
74: cmpb $/**/ARRAY,_typetable+1[r3] # how about array?
75: jeql doarray # yep
76:
77:
78: nolink:
79: pushl r1 # non, bcd, call interpreter
80: calls $1,_Ifuncal
81: ret
82:
83: /*
84: * handle arrays by pushing the array descriptor on the table and checking
85: * for a bcd array handler
86: */
87: doarray:
88: ashl $-9,Arrayaccfun(r2),r3 # get access function addr shifted
89: cmpb $/**/BCD,_typetable+1[r3] # bcd??
90: jneq nolink # no, let funcal handle it
91: #ifdef PORTABLE
92: movl NP,r4
93: movl r2,(r4)+ # store array header on stack
94: movl r4,NP
95: #else
96: movl r2,(r6)+ # store array header on stack
97: #endif
98: movl *(r2),r2 # get in func addr
99: jmp 2(r2) # jump in beyond calls header
100:
101:
102: linkin:
103: ashl $-9,4(r2),r3 # check type of function discipline
104: cmpb $0,_typetable+1[r3] # is it string?
105: jeql nolink # yes, it is a c call, so dont link in
106: movl (r2),r2 # get function addr
107: movl r2,(r0) # put fcn addr in table
108: jmp 2(r2) # enter fcn after mask
109:
110: nonex: pushl r0 # preserve table address
111: pushl r1 # non existant fcn
112: calls $1,_Undeff # call processor
113: movl r0,r1 # back in r1
114: movl (sp)+,r0 # restore table address
115: jbr retry # for the retry.
116:
117:
118: .globl __erthrow # errmessage for uncaught throws
119: __erthrow:
120: .asciz "Uncaught throw from compiled code"
121:
122: .globl _tynames
123: _tynames:
124: .long NIL # nothing here
125: .long _lispsys+20*4 # str_name
126: .long _lispsys+21*4 # atom_name
127: .long _lispsys+19*4 # int_name
128: .long _lispsys+23*4 # dtpr_name
129: .long _lispsys+22*4 # doub_name
130: .long _lispsys+58*4 # funct_name
131: .long _lispsys+103*4 # port_name
132: .long _lispsys+47*4 # array_name
133: .long NIL # nothing here
134: .long _lispsys+50*4 # sdot_name
135: .long _lispsys+53*4 # val_nam
136: .long NIL # hunk2_nam
137: .long NIL # hunk4_nam
138: .long NIL # hunk8_nam
139: .long NIL # hunk16_nam
140: .long NIL # hunk32_nam
141: .long NIL # hunk64_nam
142: .long NIL # hunk128_nam
143: .long _lispsys+124*4 # vector_nam
144: .long _lispsys+125*4 # vectori_nam
145:
146: /* Quickly allocate small fixnums */
147:
148: .globl _qnewint
149: _qnewint:
150: Profile
151: cmpl r5,$1024
152: jgeq alloc
153: cmpl r5,$-1024
154: jlss alloc
155: moval _Fixzero[r5],r0
156: rsb
157: alloc:
158: movl _int_str,r0 # move next cell addr to r0
159: jlss callnewi # if no space, allocate
160: incl *_lispsys+24*4 # inc count of ints
161: movl (r0),_int_str # advance free list
162: movl r5,(r0) # put baby to bed.
163: rsb
164: callnewi:
165: pushl r5
166: calls $0,_newint
167: movl (sp)+,(r0)
168: rsb
169:
170:
171: /* _qoneplus adds one to the boxed fixnum in r0
172: * and returns a boxed fixnum.
173: */
174:
175: .globl _qoneplus
176: _qoneplus:
177: Profile2
178: addl3 (r0),$1,r5
179: #ifdef PORTABLE
180: movl r6,NP
181: movl r6,LBOT
182: #endif
183: jmp _qnewint
184:
185: /* _qoneminus subtracts one from the boxes fixnum in r0 and returns a
186: * boxed fixnum
187: */
188: .globl _qoneminus
189: _qoneminus:
190: Profile2
191: subl3 $1,(r0),r5
192: #ifdef PORTABLE
193: movl r6,NP
194: movl r6,LBOT
195: #endif
196: jmp _qnewint
197:
198: /*
199: * _qnewdoub quick allocation of a initialized double (float) cell.
200: * This entry point is required by the compiler for symmetry reasons.
201: * Passed to _qnewdoub in r4,r5 is a double precision floating point
202: * number. This routine allocates a new cell, initializes it with
203: * the given value and then returns the cell.
204: */
205:
206: .globl _qnewdoub
207: _qnewdoub:
208: Profile
209: movl _doub_str,r0 # move next cell addr to r0
210: jlss callnewd # if no space, allocate
211: incl *_lispsys+30*4 # inc count of doubs
212: movl (r0),_doub_str # advance free list
213: movq r4,(r0) # put baby to bed.
214: rsb
215:
216: callnewd:
217: movq r4,-(sp) # stack initial value
218: calls $0,_newdoub
219: movq (sp)+,(r0) # restore initial value
220: rsb
221:
222: .globl _qcons
223:
224: /*
225: * quick cons call, the car and cdr are stacked on the namestack
226: * and this function is jsb'ed to.
227: */
228:
229: _qcons:
230: Profile
231: movl _dtpr_str,r0 # move next cell addr to r0
232: jlss getnew # if ran out of space jump
233: incl *_lispsys+28*4 # inc count of dtprs
234: movl (r0),_dtpr_str # advance free list
235: storit:
236: movl -(r6),(r0) # store in cdr
237: movl -(r6),4(r0) # store in car
238: rsb
239:
240: getnew:
241: #ifdef PORTABLE
242: movl r6,NP
243: movab -8(r6),LBOT
244: #endif
245: calls $0,_newdot # must gc to get one
246: jbr storit # now initialize it.
247:
248: /*
249: * Fast equivalent of newdot, entered by jsb
250: */
251:
252: .globl _qnewdot
253: _qnewdot:
254: Profile
255: movl _dtpr_str,r0 # mov next cell addr t0 r0
256: jlss mustallo # if ran out of space
257: incl *_lispsys+28*4 # inc count of dtprs
258: movl (r0),_dtpr_str # advance free list
259: clrq (r0)
260: rsb
261: mustallo:
262: calls $0,_newdot
263: rsb
264:
265: /* prunel - return a list of dtpr cells to the free list
266: * this is called by the pruneb after it has discarded the top bignum
267: * the dtpr cells are linked through their cars not their cdrs.
268: * this returns with an rsb
269: *
270: * method of operation: the dtpr list we get is linked by car's so we
271: * go through the list and link it by cdr's, then have the last dtpr
272: * point to the free list and then make the free list begin at the
273: * first dtpr.
274: */
275: qprunel:
276: movl r0,r2 # remember first dtpr location
277: rep: decl *_lispsys+28*4 # decrement used dtpr count
278: movl 4(r0),r1 # put link value into r1
279: jeql endoflist # if nil, then end of list
280: movl r1,(r0) # repl cdr w/ save val as car
281: movl r1,r0 # advance to next dtpr
282: jbr rep # and loop around
283: endoflist:
284: movl _dtpr_str,(r0) # make last 1 pnt to free list
285: movl r2,_dtpr_str # & free list begin at 1st 1
286: rsb
287:
288: /*
289: * qpruneb - called by the arithmetic routines to free an sdot and the dtprs
290: * which hang on it.
291: * called by
292: * pushl sdotaddr
293: * jsb _qpruneb
294: */
295: .globl _qpruneb
296: _qpruneb:
297: Profile
298: movl 4(sp),r0 # get address
299: decl *_lispsys+48*4 # decr count of used sdots
300: movl _sdot_str,(r0) # have new sdot point to free list
301: movl r0,_sdot_str # start free list at new sdot
302: movl 4(r0),r0 # get address of first dtpr
303: jneq qprunel # if exists, prune it
304: rsb # else return.
305:
306:
307: /*
308: * _qprunei
309: * called by the arithmetic routines to free a fixnum cell
310: * calling sequence
311: * pushl fixnumaddr
312: * jsb _qprunei
313: */
314:
315: .globl _qprunei
316: _qprunei:
317: Profile
318: movl 4(sp),r0 # get address of fixnum
319: cmpl r0,$_Lastfix # is it a small fixnum
320: jleq skipit # if so, leave
321: decl *_lispsys+24*4 # decr count of used ints
322: movl _int_str,(r0) # link the fixnum into the free list
323: movl r0,_int_str
324: skipit:
325: rsb
326:
327:
328: .globl _qpopnames
329: _qpopnames: # equivalent of C-code popnames, entered by jsb.
330: movl (sp)+,r0 # return address
331: movl (sp)+,r1 # Lower limit
332: movl _bnp,r2 # pointer to bind stack entry
333: qploop:
334: subl2 $8,r2 # for(; (--r2) > r1;) {
335: cmpl r2,r1 # test for done
336: jlss qpdone
337: movl (r2),*4(r2) # r2->atm->a.clb = r2 -> val;
338: brb qploop # }
339: qpdone:
340: movl r1,_bnp # restore bnp
341: jmp (r0) # return
342:
343: /*
344: * _qget : fast get subroutine
345: * (get 'atom 'ind)
346: * called with -8(r6) equal to the atom
347: * -4(r6) equal to the indicator
348: * no assumption is made about LBOT
349: * unfortunately, the atom may not in fact be an atom, it may
350: * be a list or nil, which are special cases.
351: * For nil, we grab the nil property list (stored in a special place)
352: * and for lists we punt and call the C routine since it is most likely
353: * and error and we havent put in error checks yet.
354: */
355:
356: .globl _qget
357: _qget:
358: Profile
359: movl -4(r6),r1 # put indicator in r1
360: movl -8(r6),r0 # and atom into r0
361: jeql nilpli # jump if atom is nil
362: ashl $-9,r0,r2 # check type
363: cmpb _typetable+1[r2],$1 # is it a symbol??
364: jneq notsymb # nope
365: movl 4(r0),r0 # yes, put prop list in r1 to begin scan
366: jeql fail # if no prop list, we lose right away
367: lp: cmpl r1,4(r0) # is car of list eq to indicator?
368: jeql good # jump if so
369: movl *(r0),r0 # else cddr down list
370: jneq lp # and jump if more list to go.
371:
372: fail: subl2 $8,NP # unstack args
373: rsb # return with r0 eq to nil
374:
375: good: movl (r0),r0 # return cadr of list
376: movl 4(r0),r0
377: subl2 $8,NP #unstack args
378: rsb
379:
380: nilpli: movl _lispsys+64*4,r0 # want nil prop list, get it specially
381: jneq lp # and process if anything there
382: subl2 $8,NP #unstack args
383: rsb # else fail
384:
385: notsymb:
386: #ifdef PORTABLE
387: movl r6,NP
388: movab -8(r6),LBOT # must set up LBOT before calling
389: #else
390: movab -8(r6),LBOT # must set up LBOT before calling
391: #endif
392: calls $0,_Lget # not a symbol, call C routine to error check
393: subl2 $8,NP #unstack args
394: rsb # and return what it returned.
395:
396: /*
397: * _qexarith exact arithmetic
398: * calculates x=a*b+c where a,b and c are 32 bit 2's complement integers
399: * whose top two bits must be the same (i.e. the are members of the set
400: * of valid fixnum values for Franz Lisp). The result, x, will be 64 bits
401: * long but since each of a, b and c had only 31 bits of precision, the
402: * result x only has 62 bits of precision. The lower 30 bits are returned
403: * in *plo and the high 32 bits are returned in *phi. If *phi is 0 or -1 then
404: * x doesn't need any more than 31 bits plus sign to describe, so we
405: * place the sign in the high two bits of *plo and return 0 from this
406: * routine. A non zero return indicates that x requires more than 31 bits
407: * to describe.
408: */
409:
410: .globl _qexarith
411: /* qexarith(a,b,c,phi,plo)
412: * int *phi, *plo;
413: */
414: _qexarith:
415: emul 4(sp),8(sp),12(sp),r2 #r2 = a*b + c to 64 bits
416: extzv $0,$30,r2,*20(sp) #get new lo
417: extv $30,$32,r2,r0 #get new carry
418: beql out # hi = 0, no work necessary
419: movl r0,*16(sp) # save hi
420: mcoml r0,r0 # Is hi = -1 (it'll fit in one word)
421: bneq out # it doesn't
422: bisl2 $0xc0000000,*20(sp) # alter low so that it is ok.
423: out: rsb
424:
425:
426:
427: /*
428: * pushframe : stack a frame
429: * When this is called, the optional arguments and class have already been
430: * pushed on the stack as well as the return address (by virtue of the jsb)
431: * , we push on the rest of the stuff (see h/frame.h)
432: * for a picture of the save frame
433: */
434: .globl _qpushframe
435:
436: _qpushframe:
437: Profile
438: movl _errp,-(sp)
439: movl _bnp,-(sp)
440: movl NP,-(sp)
441: movl LBOT,-(sp)
442: pushr $0x3f00 # save r13(fp), r12(ap),r11,r10,r9,r8
443: movab 6*4(sp),r0 # return addr of lbot on stack
444: clrl _retval # set retval to C_INITIAL
445: #ifndef SPISFP
446: jmp *40(sp) # return through return address
447: #else
448: movab -4(sp),sp
449: movl sp,(sp)
450: movl _xsp,-(sp)
451: jmp *48(sp)
452: #endif
453:
454: /*
455: * Ipushf : stack a frame, where space is preallocated on the stack.
456: * this is like pushframe, except that it doesn't alter the stack pointer
457: * and will save more registers.
458: * This might be written a little more quickly by having a bigger register
459: * save mask, but this is only supposed to be an example for the
460: * IBM and RIDGE people.
461: */
462:
463: #ifdef SPISFP
464: .globl _Ipushf
465: _Ipushf:
466: .word 0
467: addl3 $96,16(ap),r1
468: movl 12(ap),-(r1)
469: movl 8(ap),-(r1)
470: movl 4(ap),-(r1)
471: movl 16(fp),-(r1)
472: movl _errp,-(r1)
473: movl _bnp,-(r1)
474: movl NP,-(r1)
475: movl LBOT,-(r1)
476: movl r1,r0
477: movq 8(fp),-(r1) /* save stuff in the same order unix saves them
478: (r13,r12,r11,r10,r9,r8) and then add extra
479: for vms (sp,r7,r6,r5,r4,r3,r2) */
480: movq r10,-(r1)
481: movq r8,-(r1)
482: movab 20(ap),-(r1) /* assumes Ipushf allways called by calls, with
483: the stack alligned */
484: movl _xsp,-(r1)
485: movq r6,-(r1)
486: movq r4,-(r1)
487: movq r2,-(r1)
488: clrl _retval
489: ret
490: #endif
491: /*
492: * qretfromfr
493: * called with frame to ret to in r11. The popnames has already been done.
494: * we must restore all registers, and jump to the ret addr. the popping
495: * must be done without reducing the stack pointer since an interrupt
496: * could come in at any time and this frame must remain on the stack.
497: * thus we can't use popr.
498: */
499:
500: .globl _qretfromfr
501:
502: _qretfromfr:
503: Profile
504: movl r11,r0 # return error frame location
505: subl3 $24,r11,sp # set up sp at bottom of frame
506: movl sp,r1 # prepare to pop off
507: movq (r1)+,r8 # r8,r9
508: movq (r1)+,r10 # r10,r11
509: movq (r1)+,r12 # r12,r13
510: movl (r1)+,LBOT # LBOT (lbot)
511: movl (r1)+,NP # NP (np)
512: jmp *40(sp) # jump out of frame
513:
514: #ifdef SPISFP
515:
516: /*
517: * this is equivalent to qretfro for a native VMS system
518: *
519: */
520: .globl _Iretfrm
521: _Iretfrm:
522: .word 0
523: movl 4(ap),r0 # return error frame location
524: movl r0,r1
525: movq -(r1),ap
526: movq -(r1),r10
527: movq -(r1),r8
528: movl -(r1),sp
529: movl -(r1),_xsp
530: movq -(r1),r6
531: movq -(r1),r4
532: movq -(r1),r2
533: movl r0,r1
534: movl (r1)+,LBOT
535: movl (r1)+,NP
536: jmp *16(r0)
537: #endif
538: /*
539: * This routine gets the name of the inital entry point
540: * It is here so it can be under ifdef control.
541: */
542: .globl _gstart
543: _gstart:
544: .word 0
545: #if os_vms
546: moval _$$$start,r0
547: #else
548: moval start,r0
549: #endif
550: ret
551: .globl _proflush
552: _proflush:
553: .word 0
554: ret
555:
556: /*
557: * The definition of mcount must be present even when the C code
558: * isn't being profiled, since lisp code may reference it.
559: */
560:
561: #ifndef os_vms
562: .globl mcount
563: mcount:
564: #endif
565:
566: .globl _mcount
567: _mcount:
568:
569: #ifdef PROF
570: movl (r0),r1
571: bneq incr
572: movl _countbase,r1
573: beql return
574: addl2 $8,_countbase
575: movl (sp),(r1)+
576: movl r1,(r0)
577: incr:
578: incl (r1)
579: return:
580: #endif
581: rsb
582:
583:
584: /* This must be at the end of the file. If we are profiling, allocate
585: * space for the profile buffer
586: */
587: #ifdef PROF
588: .data
589: .comm _countbase,4
590: .lcomm prbuf,indx+4
591: .text
592: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.