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