1changecom(`;');;; -*-Midas-*-
2;;;
3;;; Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993,
4;;;     1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
5;;;     2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013,
6;;;     2014 Massachusetts Institute of Technology
7;;;
8;;; This file is part of MIT/GNU Scheme.
9;;;
10;;; MIT/GNU Scheme is free software; you can redistribute it and/or
11;;; modify it under the terms of the GNU General Public License as
12;;; published by the Free Software Foundation; either version 2 of the
13;;; License, or (at your option) any later version.
14;;;
15;;; MIT/GNU Scheme is distributed in the hope that it will be useful,
16;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18;;; General Public License for more details.
19;;;
20;;; You should have received a copy of the GNU General Public License
21;;; along with MIT/GNU Scheme; if not, write to the Free Software
22;;; Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23;;; 02110-1301, USA.
24
25;;;; HP Precision Architecture assembly language part of the compiled
26;;;; code interface. See cmpint.txt, cmpint.c, cmpint-hppa.h, and
27;;;; cmpgc.h for more documentation.
28;;;;
29;;;; NOTE:
30;;;;	Assumptions:
31;;;;
32;;;;	1) All registers (except double floating point registers) and
33;;;;	stack locations hold a C long object.
34;;;;
35;;;;	2) The C compiler divides registers into three groups:
36;;;;	- Linkage registers, used for procedure calls and global
37;;;;	references.  On HPPA: gr0 (always 0), gr2 (return address),
38;;;;	gr27 (global data pointer), and gr30 (stack pointer).
39;;;;	- super temporaries, not preserved accross procedure calls and
40;;;;	always usable. On HPPA: gr1, gr19-gr26, gr28-29, gr31.
41;;;;	gr26-23 are argument registers, gr28-29 are return registers.
42;;;;	- preserved registers saved by the callee if they are written.
43;;;;	On HPPA: gr3-gr18
44;;;;
45;;;;	3) Arguments, if passed on a stack, are popped by the caller
46;;;;	or by the procedure return instruction (as on the VAX).  Thus
47;;;;	most "leaf" procedures need not worry about them. On HPPA: All
48;;;;	arguments have slots in the stack, allocated and popped by the
49;;;;	caller, but the first four words are actually passed in gr26,
50;;;;	gr25, gr24, gr23, unless they are floating point arguments, in
51;;;;	which case they are passed in floating point registers.
52;;;;
53;;;;	4) There is a hardware or software maintained stack for
54;;;;	control.  The procedure calling sequence may leave return
55;;;;	addresses in registers, but they must be saved somewhere for
56;;;;	nested calls and recursive procedures.  On HPPA: Passed in a
57;;;;	register, but a slot on the stack exists, allocated by the
58;;;;	caller.  The return link is in gr2 and immediately saved in
59;;;;	-20(0,30) if the procedure makes further calls.  The stack
60;;;;	pointer is in gr30.
61;;;;
62;;;;	5) C procedures return long values in a super temporary
63;;;;    register.  Two word structures are returned in super temporary
64;;;;    registers as well.  On HPPA: gr28 is used for long returns,
65;;;;	gr28/gr29 are used for two word structure returns.
66;;;;	GCC returns two word structures differently: It passes
67;;;;	the address of the structure in gr28!
68;;;;
69;;;;	6) Floating point registers are not preserved by this
70;;;;	interface.  The interface is only called from the Scheme
71;;;;	interpreter, which does not use floating point data.  Thus
72;;;;	although the calling convention would require us to preserve
73;;;;	them, they contain garbage.  On HPPA: fr12-fr15 are
74;;;;	callee-saves registers, fr4-fr7 are parameter registers, and
75;;;;	fr8-fr11 are caller-saves registers.  fr0-fr3 are status
76;;;;	registers.
77;;;;
78;;;; Compiled Scheme code uses the following register convention.
79;;;; Note that scheme_to_interface_ble and the register block are
80;;;; preserved by C calls, but the others are not, since they change
81;;;; dynamically.  scheme_to_interface and trampoline_to_interface can
82;;;; be reached at fixed offsets from scheme_to_interface_ble.
83;;;;	- gr22 contains the Scheme stack pointer.
84;;;;	- gr21 contains the Scheme free pointer.
85;;;;	- gr20 contains a cached version of MemTop.
86;;;;	- gr19 contains the dynamic link when needed.
87;;;;	- gr5 contains the quad mask for machine pointers.
88;;;;	- gr4 contains a pointer to the Scheme interpreter's
89;;;;	"register" block.  This block contains the compiler's copy of
90;;;;	MemTop, the interpreter's registers (val, env, exp, etc),
91;;;;	temporary locations for compiled code.
92;;;;	- gr3 contains the address of scheme_to_interface_ble.
93;;;;
94;;;;	All other registers are available to the compiler.  A
95;;;;	caller-saves convention is used, so the registers need not be
96;;;;	preserved by subprocedures.
97;;;;
98;;;; ADB mnemonics:
99;;;;	arg3 = gr23; arg2 = gr24; arg1 = gr25; arg0 = gr26
100;;;;	dp   = gr27; ret0 = gr28; ret1 = gr29; sp   = gr30; rp   = gr02
101
102changequote(",")
103define(HEX, "0x$1")
104define(ASM_DEBUG, 0)
105define(TC_LENGTH, ifdef("TYPE_CODE_LENGTH", TYPE_CODE_LENGTH, 6))
106define(QUAD_MASK, eval(2 ** (TC_LENGTH - 2)))
107define(LOW_TC_BIT, eval(TC_LENGTH - 1))
108define(DATUM_LENGTH, eval(32 - TC_LENGTH))
109define(FIXNUM_LENGTH, DATUM_LENGTH)
110define(FIXNUM_POS, eval(FIXNUM_LENGTH - 1))
111define(FIXNUM_BIT, eval(TC_LENGTH + 1))
112define(TC_START, eval(TC_LENGTH - 1))
113define(TC_FLONUM, 0x6)
114define(TC_VECTOR, 0xa)
115define(TC_FIXNUM, 0x1a)
116define(TC_STRING, 0x1e)
117define(TC_NMV, 0x27)
118define(TC_CCENTRY, 0x28)
119define(FLONUM_VECTOR_HEADER, eval((TC_NMV * (2 ** DATUM_LENGTH)) + 2))
120define(TC_FALSE, 0)
121define(TC_TRUE, 0x8)
122define(SHARP_F, eval(TC_FALSE * (2 ** DATUM_LENGTH)))
123define(SHARP_T, eval(TC_TRUE * (2 ** DATUM_LENGTH)))
124define(C_FRAME_SIZE,
125       ifdef("HPC", 112,
126	     ifdef("GCC", 120,
127	           `Unknown C compiler: bad frame size')))
128define(INT_BIT_STACK_OVERFLOW, 31)
129
130	.SPACE  $TEXT$
131	.SUBSPA $CODE$,QUAD=0,ALIGN=8,ACCESS=44,CODE_ONLY
132C_to_interface
133	.PROC
134	.CALLINFO CALLER,FRAME=28,SAVE_RP
135	.ENTRY
136	STW	2,-20(0,30)			; Save return address
137	STWM	3,eval(C_FRAME_SIZE)(30)	; Save first reg,
138	STW	4,-108(30)			;  and allocate frame
139	STW	5,-104(30)			; Save the other regs
140	STW	6,-100(30)
141	STW	7,-96(30)
142	STW	8,-92(30)
143	STW	9,-88(30)
144	STW	10,-84(30)
145	STW	11,-80(30)
146	STW	12,-76(30)
147	STW	13,-72(30)
148	STW	14,-68(30)
149	STW	15,-64(30)
150	STW	16,-60(30)
151	STW	17,-56(30)
152	STW	18,-52(30)
153	ADDIL	L'Registers-$global$,27
154	LDO	R'Registers-$global$(1),4	; Setup Regs
155	LDI	QUAD_MASK,5
156
157ep_interface_to_scheme
158	LDW	8(0,4),2			; Move interpreter reg to val
159	COPY	2,19				; Restore dynamic link if any
160	DEP	5,LOW_TC_BIT,TC_LENGTH,19
161	ADDIL	L'sp_register-$global$,27
162	LDW	R'sp_register-$global$(1),22	; Setup stack pointer
163
164ep_interface_to_scheme_2
165	LDW	0(0,4),20			; Setup memtop
166	ADDIL	L'Free-$global$,27
167	LDW	R'Free-$global$(1),21		; Setup free
168	.CALL	RTNVAL=GR			; out=28
169	BLE	0(5,26)				; Invoke entry point
170	COPY	31,3				; Setup scheme_to_interface_ble
171
172scheme_to_interface_ble
173	ADDI	4,31,31				; Skip over format word ...
174trampoline_to_interface
175	COPY	31,26
176	DEP	0,31,2,26
177scheme_to_interface
178	STW	2,8(0,4)			; Move val to interpreter reg
179	ADDIL	L'hppa_utility_table-$global$,27
180	LDW	R'hppa_utility_table-$global$(1),29
181	ADDIL	L'sp_register-$global$,27
182	LDWX,S	28(0,29),29			; Find handler
183	STW	22,R'sp_register-$global$(1)	; Update stack pointer
184	ADDIL	L'Free-$global$,27
185	STW	21,R'Free-$global$(1)		; Update free
186	ifelse(ASM_DEBUG,1,"ADDIL	L'interface_counter-$global$,27
187	LDW	R'interface_counter-$global$(1),21
188	LDO	1(21),21
189	STW	21,R'interface_counter-$global$(1)
190	ADDIL	L'interface_limit-$global$,27
191	LDW	R'interface_limit-$global$(1),22
192	COMB,=,N	21,22,interface_break
193interface_proceed")
194	ifdef("GCC", "LDO	-116(30),28")
195	.CALL	ARGW0=GR,ARGW1=GR,ARGW2=GR,ARGW3=GR,RTNVAL=GR
196	BLE	0(4,29)				; Call handler
197	COPY	31,2				; Setup return address
198	ifdef("GCC", "LDW	-116(30),28
199		      LDW	-112(30),29")
200	BV	0(28)				; Call receiver
201	COPY	29,26				; Setup entry point
202
203;; This sequence of NOPs is provided to allow for modification of
204;; the sequence that appears above without having to recompile the
205;; world.  The compiler "knows" the distance between
206;; scheme_to_interface_ble and hook_jump_table (100 bytes)
207
208	ifelse(ASM_DEBUG,1,"","NOP
209	NOP
210	NOP
211	NOP
212	NOP
213	NOP
214	NOP")
215	ifdef("GCC","","NOP
216	NOP
217	NOP")
218
219;; This label is used by the trap handler
220
221ep_scheme_hooks_low
222hook_jump_table					; scheme_to_interface + 100
223store_closure_code_hook
224	B	store_closure_code+4
225	LDIL	L'0x23400000,20			; LDIL opcode and register
226
227store_closure_entry_hook
228	B	store_closure_entry+4
229	DEP	0,31,2,1			; clear PC protection bits
230
231multiply_fixnum_hook
232	B	multiply_fixnum+4
233	EXTRS	26,FIXNUM_POS,FIXNUM_LENGTH,26	; arg1
234
235fixnum_quotient_hook
236	B	fixnum_quotient+4
237	EXTRS	26,FIXNUM_POS,FIXNUM_LENGTH,26	; arg1
238
239fixnum_remainder_hook
240	B	fixnum_remainder+4
241	EXTRS	26,FIXNUM_POS,FIXNUM_LENGTH,26	; arg1
242
243fixnum_lsh_hook
244	B	fixnum_lsh+4
245	EXTRS	25,FIXNUM_POS,FIXNUM_LENGTH,25	; arg2
246
247generic_plus_hook
248	B	generic_plus+4
249	LDW	0(0,22),6			; arg1
250
251generic_subtract_hook
252	B	generic_subtract+4
253	LDW	0(0,22),6			; arg1
254
255generic_times_hook
256	B	generic_times+4
257	LDW	0(0,22),6			; arg1
258
259generic_divide_hook
260	B	generic_divide+4
261	LDW	0(0,22),6			; arg1
262
263generic_equal_hook
264	B	generic_equal+4
265	LDW	0(0,22),6			; arg1
266
267generic_less_hook
268	B	generic_less+4
269	LDW	0(0,22),6			; arg1
270
271generic_greater_hook
272	B	generic_greater+4
273	LDW	0(0,22),6			; arg1
274
275generic_increment_hook
276	B	generic_increment+4
277	LDW	0(0,22),6			; arg1
278
279generic_decrement_hook
280	B	generic_decrement+4
281	LDW	0(0,22),6			; arg1
282
283generic_zero_hook
284	B	generic_zero+4
285	LDW	0(0,22),6			; arg1
286
287generic_positive_hook
288	B	generic_positive+4
289	LDW	0(0,22),6			; arg1
290
291generic_negative_hook
292	B	generic_negative+4
293	LDW	0(0,22),6			; arg1
294
295shortcircuit_apply_hook
296	B	shortcircuit_apply+4
297	EXTRU	26,5,6,24			; procedure type -> 24
298
299shortcircuit_apply_1_hook
300	B	shortcircuit_apply_1+4
301	EXTRU	26,5,6,24			; procedure type -> 24
302
303shortcircuit_apply_2_hook
304	B	shortcircuit_apply_2+4
305	EXTRU	26,5,6,24			; procedure type -> 24
306
307shortcircuit_apply_3_hook
308	B	shortcircuit_apply_3+4
309	EXTRU	26,5,6,24			; procedure type -> 24
310
311shortcircuit_apply_4_hook
312	B	shortcircuit_apply_4+4
313	EXTRU	26,5,6,24			; procedure type -> 24
314
315shortcircuit_apply_5_hook
316	B	shortcircuit_apply_5+4
317	EXTRU	26,5,6,24			; procedure type -> 24
318
319shortcircuit_apply_6_hook
320	B	shortcircuit_apply_6+4
321	EXTRU	26,5,6,24			; procedure type -> 24
322
323shortcircuit_apply_7_hook
324	B	shortcircuit_apply_7+4
325	EXTRU	26,5,6,24			; procedure type -> 24
326
327shortcircuit_apply_8_hook
328	B	shortcircuit_apply_8+4
329	EXTRU	26,5,6,24			; procedure type -> 24
330
331stack_and_interrupt_check_hook
332	B	stack_and_interrupt_check+4
333	LDW	44(0,4),25			; Stack_Guard -> r25
334
335invoke_primitive_hook
336	B	invoke_primitive+4
337	DEPI	0,31,2,31			; clear privilege bits
338
339vector_cons_hook
340	B	vector_cons+4
341	LDW	0(0,22),26			; length as fixnum
342
343string_allocate_hook
344	B	string_allocate+4
345	LDW	0(0,22),26			; length as fixnum
346
347floating_vector_cons_hook
348	B	floating_vector_cons+4
349	LDW	0(0,22),26			; length as fixnum
350
351flonum_sin_hook
352	B	flonum_sin+4
353	COPY	22,18
354
355flonum_cos_hook
356	B	flonum_cos+4
357	COPY	22,18
358
359flonum_tan_hook
360	B	flonum_tan+4
361	COPY	22,18
362
363flonum_asin_hook
364	B	flonum_asin+4
365	COPY	22,18
366
367flonum_acos_hook
368	B	flonum_acos+4
369	COPY	22,18
370
371flonum_atan_hook
372	B	flonum_atan+4
373	COPY	22,18
374
375flonum_exp_hook
376	B	flonum_exp+4
377	COPY	22,18
378
379flonum_log_hook
380	B	flonum_log+4
381	COPY	22,18
382
383flonum_truncate_hook
384	B	flonum_truncate+4
385	COPY	22,18
386
387flonum_ceiling_hook
388	B	flonum_ceiling+4
389	COPY	22,18
390
391flonum_floor_hook
392	B	flonum_floor+4
393	COPY	22,18
394
395flonum_atan2_hook
396	B	flonum_atan2+4
397	COPY	22,18
398
399compiled_code_bkpt_hook				; hook 44 (offset 451 + 1)
400	B	compiled_code_bkpt+4
401	LDO	-8(31),31
402
403compiled_closure_bkpt_hook			; hook 45 (offset 451 + 9)
404	B	compiled_closure_bkpt+4
405	LDO	-12(31),31
406
407copy_closure_pattern_hook
408	B	copy_closure_pattern+4
409	LDW	-3(0,31),29			; offset
410
411copy_multiclosure_pattern_hook
412	B	copy_multiclosure_pattern+4
413	LDW	-3(0,31),29			; offset
414
415closure_entry_bkpt_hook				; hook 48 (offset 451 + 33)
416	B	closure_entry_bkpt+4
417	LDO	-8(31),31			; bump back to entry point
418
419;;
420;; Provide dummy trapping hooks in case a newer version of compiled
421;; code that expects more hooks is run.
422;;
423
424no_hook
425	BREAK	0,49
426	NOP
427	BREAK	0,50
428	NOP
429	BREAK	0,51
430	NOP
431	BREAK	0,52
432	NOP
433	BREAK	0,53
434	NOP
435	BREAK	0,54
436	NOP
437	BREAK	0,55
438	NOP
439	BREAK	0,56
440	NOP
441	BREAK	0,57
442	NOP
443	BREAK	0,58
444	NOP
445	BREAK	0,59
446	NOP
447	BREAK	0,60
448	NOP
449	BREAK	0,61
450	NOP
451	BREAK	0,62
452	NOP
453	BREAK	0,63
454	NOP
455
456ifelse(ASM_DEBUG,1,"interface_break
457	COMB,=	21,22,interface_break
458	NOP
459	B,N	interface_proceed")
460
461store_closure_entry
462;;
463;; On arrival, 31 has a return address and 1 contains the address to
464;; which the closure should jump with pc protection bits.
465;; 26 contains the format/gc-offset word for this entry.
466;;
467	DEP	0,31,2,1			; clear PC protection bits
468	STWM	26,4(0,21)			; move format long to heap
469;; fall through to store_closure_code
470
471store_closure_code
472;;
473;; On arrival, 31 has a return address and 1 contains the address to
474;; which the closure should jump.  The appropriate instructions (LDIL
475;; and BLE and SUBI) are pushed on the heap.
476;;     Important:
477;; 3 words in memory are modified, but only 2 FDC instructions and one FIC
478;; instruction are issued.  The PDC_CACHE description in the I/O Architecture
479;; manual specifies that each flush will flush a multiple of 16 bytes, thus
480;; a flush of the first data word and a flush of the last data word suffice to
481;; flush all three.  A single FIC of the first instruction word suffices since
482;; the space is newly allocated and the whole I-cache was flushed at
483;; exec and relocation(GC) time.
484;; The SYNC is assumed to be separated by at least 7 instructions from
485;; the first execution of the new instructions.
486;;
487	LDIL	L'0x23400000,20			; LDIL opcode and register
488	EXTRU	1,0,1,5
489	DEP	5,31,1,20
490	EXTRU	1,11,11,5
491	DEP	5,30,11,20
492	EXTRU	1,13,2,5
493	DEP	5,17,2,20
494	EXTRU	1,18,5,5
495	DEP	5,15,5,20
496	STW	20,0(0,21)			; Store LDIL instruction
497	LDIL	L'0xe7406000,20			; BLE opcode, register
498	LDO	R'0xe7406000(20),20		;  and nullify
499	EXTRU	1,19,1,5
500	DEP	5,29,1,20
501	EXTRU	1,29,10,5
502	DEP	5,28,10,20
503	STW	20,4(0,21)			; Store BLE instruction
504	LDIL	L'0xb7ff07e9,20
505	LDO	R'0xb7ff07e9(20),20
506	STW	20,8(0,21)			; Store ADDI instruction
507	LDI	12,20
508	FDC	0(0,21)				; flush 1st inst. from D-cache
509	FDC	20(0,21)			; flush last inst. from D-cache
510	SYNC
511	FIC,M	20(5,21)			; flush 1st inst. from I-cache
512	SYNC
513	LDW	0(0,4),20			; Reload memtop
514	BE	0(5,31)				; Return
515	LDI	QUAD_MASK,5			; Restore register 5
516
517multiply_fixnum
518;;
519;; On arrival, 31 has a return address and 26 and 25 have the fixnum arguments.
520;;
521	EXTRS	26,FIXNUM_POS,FIXNUM_LENGTH,26	; arg1
522	STW	26,0(0,21)
523	EXTRS	25,FIXNUM_POS,FIXNUM_LENGTH,25	; arg2
524	STW	25,4(0,21)
525	ZDEPI	1,TC_LENGTH,1,26		; FIXNUM_LIMIT
526	FLDWS	0(0,21),4
527	FLDWS	4(0,21),5
528	STW	26,8(0,21)			; FIXNUM_LIMIT
529        FCNVXF,SGL,DBL  4,4			; arg1
530        FCNVXF,SGL,DBL  5,5			; arg2
531	FMPY,DBL	4,5,4
532	FLDWS	8(0,21),5			; FIXNUM_LIMIT
533        FCNVXF,SGL,DBL  5,5			; FIXNUM_LIMIT
534	COPY	0,25				; signal no overflow
535	FCMP,DBL,!>=	4,5			; result too large?
536	FTEST
537	B,N	multiply_fixnum_ovflw
538	FSUB,DBL	0,5,5
539	FCMP,DBL,!<	4,5			; result too small?
540	FTEST
541	B,N	multiply_fixnum_ovflw
542	FCNVFXT,DBL,SGL	4,5
543	FSTWS	5,0(0,21)			; result
544	LDW	0(0,21),26
545	BE	0(5,31)				; return
546	ZDEP    26,FIXNUM_POS,FIXNUM_LENGTH,26	; make into fixnum
547;;
548multiply_fixnum_ovflw
549	COPY	0,26
550	LDO	1(0),25				; signal overflow
551	BE	0(5,31)				; return
552	ZDEP    26,FIXNUM_POS,FIXNUM_LENGTH,26	; make into fixnum
553
554fixnum_quotient
555;;
556;; On arrival, 31 has a return address and 26 and 25 have the fixnum arguments.
557;; Note that quotient only overflows when dividing by 0 and when the
558;; divisor is -1 and the dividend is the most negative fixnum,
559;; producing the most positive fixnum plus 1.
560;;
561	EXTRS	26,FIXNUM_POS,FIXNUM_LENGTH,26	; arg1
562	COMB,=	0,25,fixnum_quotient_ovflw
563	STW	26,0(0,21)
564	EXTRS	25,FIXNUM_POS,FIXNUM_LENGTH,25	; arg2
565	STW	25,4(0,21)
566	ZDEPI	1,TC_LENGTH,1,26		; FIXNUM_LIMIT
567	FLDWS	0(0,21),4
568	FLDWS	4(0,21),5
569        FCNVXF,SGL,DBL  4,4			; arg1
570        FCNVXF,SGL,DBL  5,5			; arg2
571	FDIV,DBL	4,5,4
572	STW	26,0(0,21)			; FIXNUM_LIMIT
573	FCNVFXT,DBL,SGL	4,5
574	FSTWS	5,4(0,21)			; result
575	FLDWS	0(0,21),5			; FIXNUM_LIMIT
576	FCNVXF,SGL,DBL	5,5
577	FCMP,DBL,!>=	4,5			; result too large?
578	LDW	4(0,21),26
579	COPY	0,25				; signal no overflow
580	FTEST
581;;
582fixnum_quotient_ovflw
583	LDO	1(0),25				; signal overflow
584	BE	0(5,31)				; return
585	ZDEP    26,FIXNUM_POS,FIXNUM_LENGTH,26	; make into fixnum
586
587;; fixnum_remainder
588;;
589;; NOTE: The following code is disabled because the FREM instruction
590;;	 has been dropped from the architecture and has never been
591;;	 implemented in hardware.
592;;
593;; On arrival, 31 has a return address and 26 and 25 have the fixnum arguments.
594;; Note that remainder only overflows when dividing by 0.
595;; Note also that the FREM instruction does not compute the same as
596;; the Scheme remainder operation.  The sign of the result must
597;; sometimes be adjusted.
598;;
599;;	EXTRS	26,FIXNUM_POS,FIXNUM_LENGTH,26	; arg1
600;;	COMB,=,N	0,25,fixnum_remainder_ovflw
601;;	STW	26,0(0,21)
602;;	EXTRS	25,FIXNUM_POS,FIXNUM_LENGTH,25	; arg2
603;;	STW	25,4(0,21)
604;;	FLDWS	0(0,21),4
605;;	FLDWS	4(0,21),5
606;;	FCNVXF,SGL,DBL  4,4			; arg1
607;;	FCNVXF,SGL,DBL  5,5			; arg2
608;;	FREM,DBL	4,5,4
609;;	FCNVFXT,DBL,SGL	4,5
610;;	FSTWS	5,4(0,21)			; result
611;;	LDW	4(0,21),1
612;;	XOR,<	26,1,0				; skip if signs !=
613;;	B,N	fixnum_remainder_done
614;;	COMB,=,N	0,1,fixnum_remainder_done
615;;	XOR,<	26,25,0				; skip if signs !=
616;;	ADD,TR	1,25,1				; result += arg2
617;;	SUB	1,25,1				; result -= arg2
618;;;;
619;;fixnum_remainder_done
620;;	ZDEP    1,FIXNUM_POS,FIXNUM_LENGTH,26	; make into fixnum
621;;	BE	0(5,31)				; return
622;;	COPY	0,25				; signal no overflow
623;;;;
624;;fixnum_remainder_ovflw
625;;	BE	0(5,31)				; return
626;;	LDO	1(0),25				; signal overflow
627
628fixnum_remainder
629;;
630;; On arrival, 31 has a return address and 26 and 25 have the fixnum
631;; arguments.
632;; Remainder can overflow only if arg2 = 0.
633;;
634	EXTRS	26,FIXNUM_POS,FIXNUM_LENGTH,26	; arg1
635	STWM	29,-4(0,22)			; Preserve gr29
636	COMB,=,N	0,25,fixnum_remainder_ovflw
637	STWM	31,-4(0,22)			; Preserve ret. add.
638	EXTRS	25,FIXNUM_POS,FIXNUM_LENGTH,25	; arg2
639	STWM	26,-4(0,22)			; Preserve arg1
640        .CALL   				;in=25,26;out=29; (MILLICALL)
641	BL	$$remI,31
642	STWM	25,-4(0,22)			; Preserve arg2
643;;
644	LDWM	4(0,22),25			; Restore arg2
645	LDWM	4(0,22),26			; Restore arg1
646	XOR,<	26,29,0				; Skip if signs !=
647	B,N	fixnum_remainder_done
648	COMB,=,N	0,29,fixnum_remainder_done
649	XOR,<	26,25,0
650	ADD,TR	29,25,29			; setup result
651	SUB	29,25,29
652;;
653fixnum_remainder_done
654	ZDEP	29,FIXNUM_POS,FIXNUM_LENGTH,26	; make into fixnum
655	LDWM	4(0,22),31			; Restore ret. add.
656	COPY	0,25				; signal no overflow
657	BE	0(5,31)				; return
658	LDWM	4(0,22),29			; Restore gr29
659;;
660fixnum_remainder_ovflw
661	LDO	1(0),25				; signal overflow
662	COPY	0,26				; bogus return value
663	BE	0(5,31)				; return
664	LDWM	4(0,22),29			; Restore gr29
665
666fixnum_lsh
667;;
668;; On arrival, 31 has a return address and 26 and 25 have the fixnum arguments.
669;; If arg2 is negative, it is a right shift, otherwise a left shift.
670;;
671	EXTRS	25,FIXNUM_POS,FIXNUM_LENGTH,25	; arg2
672	COMB,<,N	0,25,fixnum_lsh_positive
673	SUB	0,25,25				; negate, for right shift
674	COMICLR,>	FIXNUM_LENGTH,25,0
675	LDI	31,25				; shift right completely
676	MTSAR	25
677	VSHD	0,26,26				; shift right
678	DEP	0,31,TC_LENGTH,26		; normalize fixnum
679	BE	0(5,31)				; return
680	COPY	0,25				; signal no overflow
681;;
682fixnum_lsh_positive
683	SUBI,>	32,25,25			; shift amount for right shift
684	COPY	0,25				; shift left completely
685	MTSAR	25
686	VSHD	26,0,26				; shift right (32 - arg2)
687	BE	0(5,31)				; return
688	COPY	0,25				; signal no overflow
689
690;;;; Generic arithmetic utilities.
691;;;  On entry the arguments are on the Scheme stack, and the return
692;;;  address immediately above them.
693
694define(define_generic_binary,
695"generic_$1
696	LDW	0(0,22),6			; arg1
697	LDW	4(0,22),8			; arg2
698	EXTRU	6,TC_START,TC_LENGTH,7		; type of arg1
699	EXTRU	8,TC_START,TC_LENGTH,9		; type of arg2
700	COMIB,<>,N	TC_FLONUM,7,generic_$1_fail
701	COMIB,<>,N	TC_FLONUM,9,generic_$1_fail
702	DEP	5,TC_START,TC_LENGTH,6		; data segment quadrant bits
703	FLDDS	4(0,6),4			; arg1 -> fr4
704	DEP	5,TC_START,TC_LENGTH,8		; data segment quadrant bits
705	FLDDS	4(0,8),5			; arg2 -> fr5
706	B	binary_flonum_result		; cons flonum and return
707	$3,DBL	4,5,4				; operate
708
709generic_$1_fail					; ?? * ??, out of line
710	B	scheme_to_interface
711	LDI	HEX($2),28			; operation code")
712
713flonum_result
714unary_flonum_result
715	ADDI,TR	4,22,6				; ret. add. location
716
717binary_flonum_result				; expects data in fr4.
718	LDO	8(22),6				; ret. add. location
719	DEPI	4,31,3,21			; align free
720	COPY	21,2				; result (untagged)
721	LDW	0(0,6),8			; return address
722	LDIL	L'FLONUM_VECTOR_HEADER,7
723	;	LDO	R'FLONUM_VECTOR_HEADER(7),7 ; Assembler bug!
724	ADDI	R'FLONUM_VECTOR_HEADER,7,7
725	STWM	7,4(0,21)			; vector header
726	DEPI	TC_FLONUM,TC_START,TC_LENGTH,2 ; tag flonum
727	DEP	5,TC_START,TC_LENGTH,8		; data segment quadrant bits
728	FSTDS,MA	4,8(0,21)		; store floating data
729	BLE	0(5,8)				; return!
730	LDO	4(6),22				; pop frame
731
732define(define_generic_binary_predicate,
733"generic_$1
734	LDW	0(0,22),6			; arg1
735	LDW	4(0,22),8			; arg2
736	EXTRU	6,TC_START,TC_LENGTH,7		; type of arg1
737	EXTRU	8,TC_START,TC_LENGTH,9		; type of arg2
738	COMIB,<>,N	TC_FLONUM,7,generic_$1_one_unk
739	COMIB,<>,N	TC_FLONUM,9,generic_$1_two_unk
740	DEP	5,TC_START,TC_LENGTH,6		; data segment quadrant bits
741	FLDDS	4(0,6),4			; arg1 -> fr4
742	DEP	5,TC_START,TC_LENGTH,8		; data segment quadrant bits
743	FLDDS	4(0,8),5			; arg2 -> fr5
744	LDO	8(22),22			; pop args from stack
745	B	generic_boolean_result		; cons answer and return
746	FCMP,DBL,$3	4,5			; compare
747
748generic_$1_one_unk				; ~FLO * ??
749	COMIB,<>,N	TC_FLONUM,9,generic_$1_fail
750	COMICLR,=	TC_FIXNUM,7,0
751	B,N	generic_$1_fail
752	EXTRS	6,31,FIXNUM_LENGTH,6		; sign extend arg1
753	STW	6,0(0,21)			; through memory into fpcp
754	LDO	8(22),22			; pop args from stack
755	DEP	5,TC_START,TC_LENGTH,8		; data segment quadrant bits
756	FLDWS	0(0,21),4			; single int arg1 -> fr4
757	FLDDS	4(0,8),5			; arg2 -> fr5
758        FCNVXF,SGL,DBL  4,4			; convert to double float
759	B	generic_boolean_result		; cons answer and return
760	FCMP,DBL,$3	4,5			; compare
761
762generic_$1_two_unk				; FLO * ~FLO
763	COMICLR,=	TC_FIXNUM,9,0
764	B,N	generic_$1_fail
765	EXTRS	8,31,FIXNUM_LENGTH,8		; sign extend arg2
766	STW	8,0(0,21)			; through memory into fpcp
767	LDO	8(22),22			; pop args from stack
768	DEP	5,TC_START,TC_LENGTH,6		; data segment quadrant bits
769	FLDWS	0(0,21),5			; single int arg2 -> fr5
770	FLDDS	4(0,6),4			; arg1 -> fr4
771        FCNVXF,SGL,DBL  5,5			; convert to double float
772	B	generic_boolean_result		; cons answer and return
773	FCMP,DBL,$3	4,5			; compare
774
775generic_$1_fail					; ?? * ??, out of line
776	B	scheme_to_interface
777	LDI	HEX($2),28			; operation code")
778
779generic_boolean_result
780	LDWM	4(0,22),8			; return address
781	LDIL	L'SHARP_T,2
782	FTEST
783	LDIL	L'SHARP_F,2
784	DEP	5,TC_START,TC_LENGTH,8		; data segment quadrant bits
785	BLE,N	0(5,8)				; return!
786
787define(define_generic_unary,
788"generic_$1
789	LDW	0(0,22),6			; arg
790	EXTRU	6,TC_START,TC_LENGTH,7		; type of arg
791	COMIB,<>,N	TC_FLONUM,7,generic_$1_fail
792	LDI	1,7				; constant 1
793	STW	7,0(0,21)			; into memory
794	DEP	5,TC_START,TC_LENGTH,6		; data segment quadrant bits
795	FLDWS	0(0,21),5			; 1 -> fr5
796	FLDDS	4(0,6),4			; arg -> fr4
797	FCNVXF,SGL,DBL	5,5			; convert to double float
798	B	unary_flonum_result		; cons flonum and return
799	$3,DBL	4,5,4				; operate
800
801generic_$1_fail
802	B	scheme_to_interface
803	LDI	HEX($2),28			; operation code")
804
805define(define_generic_unary_predicate,
806"generic_$1
807	LDW	0(0,22),6			; arg
808	EXTRU	6,TC_START,TC_LENGTH,7		; type of arg
809	COMIB,<>,N	TC_FLONUM,7,generic_$1_fail
810	DEP	5,TC_START,TC_LENGTH,6		; data segment quadrant bits
811	FLDDS	4(0,6),4			; arg -> fr4
812	LDO	4(22),22			; pop arg from stack
813	B	generic_boolean_result		; cons answer and return
814	FCMP,DBL,$3	4,0			; compare
815
816generic_$1_fail
817	B	scheme_to_interface
818	LDI	HEX($2),28			; operation code")
819
820define_generic_unary(decrement,22,FSUB)
821define_generic_binary(divide,23,FDIV)
822define_generic_binary_predicate(equal,24,=)
823define_generic_binary_predicate(greater,25,>)
824define_generic_unary(increment,26,FADD)
825define_generic_binary_predicate(less,27,<)
826define_generic_binary(subtract,28,FSUB)
827define_generic_binary(times,29,FMPY)
828define_generic_unary_predicate(negative,2a,<)
829define_generic_binary(plus,2b,FADD)
830define_generic_unary_predicate(positive,2c,>)
831define_generic_unary_predicate(zero,2d,=)
832
833;;;; Optimized procedure application for unknown procedures.
834;;;  Procedure in r26, arity (for shortcircuit-apply) in r25.
835
836shortcircuit_apply
837	EXTRU	26,5,6,24			; procedure type -> 24
838	COMICLR,=	TC_CCENTRY,24,0
839	B,N	shortcircuit_apply_lose
840	DEP	5,5,6,26			; procedure -> address
841	LDB	-3(0,26),23			; procedure's frame-size
842	COMB,<>,N	25,23,shortcircuit_apply_lose
843	BLE,N	0(5,26)				; invoke procedure
844
845define(define_shortcircuit_fixed,
846"shortcircuit_apply_$1
847	EXTRU	26,5,6,24			; procedure type -> 24
848	COMICLR,=	TC_CCENTRY,24,0
849	B	shortcircuit_apply_lose
850	LDI	$1,25
851	DEP	5,5,6,26			; procedure -> address
852	LDB	-3(0,26),23			; procedure's frame-size
853	COMB,<>,N	25,23,shortcircuit_apply_lose
854	BLE,N	0(5,26)				; invoke procedure")
855
856define_shortcircuit_fixed(1)
857define_shortcircuit_fixed(2)
858define_shortcircuit_fixed(3)
859define_shortcircuit_fixed(4)
860define_shortcircuit_fixed(5)
861define_shortcircuit_fixed(6)
862define_shortcircuit_fixed(7)
863define_shortcircuit_fixed(8)
864
865shortcircuit_apply_lose
866	DEP	24,5,6,26			; insert type back
867	B	scheme_to_interface
868	LDI	0x14,28
869
870;;; Return address in r31.  r26 contains the offset from the return
871;;; address to the interrupt invocation label.
872
873stack_and_interrupt_check
874	LDW	44(0,4),25			; Stack_Guard -> r25
875	LDW	0(0,4),20			; MemTop -> r20
876;;;
877;;; If the Scheme stack pointer is <= Stack_Guard, then the stack has
878;;; overflowed -- in which case we must signal a stack-overflow interrupt.
879	COMB,<=,N 22,25,stack_and_interrupt_check_stack_overflow
880;;;
881;;; If (Free >= MemTop), signal an interrupt.
882	COMB,>=,N 21,20,stack_and_interrupt_check_signal_interrupt
883;;;
884;;; Otherwise, return normally -- there's nothing to do.
885	BE	0(5,31)
886	NOP
887
888stack_and_interrupt_check_stack_overflow
889	LDW	48(0,4),25			; IntCode -> r25
890	LDW	4(0,4),24			; IntEnb -> r24
891;;;
892;;; Set the stack-overflow interrupt bit and write the interrupt word
893;;; back out to memory.  If the stack-overflow interrupt is disabled,
894;;; skip forward to gc test.  Otherwise, set MemTop to -1 and signal
895;;; the interrupt.
896	DEPI	1,INT_BIT_STACK_OVERFLOW,1,25
897	BB,>=	24,INT_BIT_STACK_OVERFLOW,stack_and_interrupt_check_no_overflow
898	STW	25,48(0,4)			; r25 -> IntCode
899	ADDI	-1,0,20				; -1 -> r20
900	STW	20,0(0,4)			; r20 -> MemTop
901;;;
902;;; If (Free >= MemTop), signal an interrupt.
903stack_and_interrupt_check_no_overflow
904	SUB,<	21,20,0				; skip next inst.
905						;  if (Free < MemTop)
906;;;
907;;; To signal the interrupt, add the interrupt invocation offset to
908;;; the return address, then return normally.
909stack_and_interrupt_check_signal_interrupt
910	ADD	26,31,31
911	BE	0(5,31)				; return
912	NOP
913
914;;; invoke_primitive and *cons all have the same interface:
915;;; The "return address" in r31 points to a word containing
916;;; the distance between itself and the word in memory containing
917;;; the primitive object.
918;;; All arguments are passed on the stack, ready for the primitive.
919
920invoke_primitive
921	DEPI	0,31,2,31			; clear privilege bits
922	LDW	0(0,31),26			; get offset
923	ADDIL	L'hppa_primitive_table-$global$,27
924	LDWX	26(0,31),26			; get primitive
925	LDW	R'hppa_primitive_table-$global$(1),25
926	EXTRU	26,31,DATUM_LENGTH,24		; get primitive index
927	STW	26,32(0,4)			; store primitive
928	ADDIL	L'Primitive_Arity_Table-$global$,27
929	LDW	R'Primitive_Arity_Table-$global$(1),18
930	LDWX,S	24(0,25),25			; find primitive entry point
931	ADDIL	L'sp_register-$global$,27
932	STW	22,R'sp_register-$global$(1)	; Update stack pointer
933	ADDIL	L'Free-$global$,27
934	LDWX,S	24(0,18),18			; primitive arity
935	STW	21,R'Free-$global$(1)		; Update free
936	.CALL	RTNVAL=GR			; out=28
937	BLE	0(4,25)				; Call primitive
938	COPY	31,2				; Setup return address
939
940	ADDIL	L'sp_register-$global$,27
941	LDW	R'sp_register-$global$(1),22	; Setup stack pointer
942	COPY	28,2				; Move result to val
943	SH2ADD	18,22,22			; pop frame
944	LDWM	4(0,22),26			; return address as object
945	STW	0,32(0,4)			; clear primitive
946	B	ep_interface_to_scheme_2
947	DEP	5,TC_START,TC_LENGTH,26		; return address as address
948
949;;; The BLE in invoke_primitive can jump here.
950;;; The primitive index is in gr24
951
952cross_segment_call
953	ADDIL	L'Primitive_Procedure_Table-$global$,27
954	LDW	R'Primitive_Procedure_Table-$global$(1),22
955	LDWX,S	24(0,22),22
956	B,N	$$dyncall			; ignore the return address
957
958vector_cons
959	LDW	0(0,22),26			; length as fixnum
960	COPY	21,2
961	ZDEP	26,31,DATUM_LENGTH,26		; length as machine word
962	SH2ADD	26,21,25			; end of data (-1)
963	COMBF,<	25,20,invoke_primitive		; no space, use primitive
964	LDW	4(0,22),24			; fill value
965	LDO	4(25),21			; allocate!
966	STW	26,0(0,2)			; vector length (0-tagged)
967	LDO	4(2),23				; start location
968
969vector_cons_loop
970	COMBT,<,N	23,21,vector_cons_loop
971	STWM	24,4(0,23)			; initialize
972
973	LDW	8(0,22),25			; return address as object
974	DEPI	TC_VECTOR,TC_START,TC_LENGTH,2	; tag result
975	DEP	5,TC_START,TC_LENGTH,25		; return address as address
976	BLE	0(5,25)				; return!
977	LDO	12(22),22			; pop stack frame
978
979string_allocate
980	LDW	0(0,22),26			; length as fixnum
981	COPY	21,2				; return value
982	ZDEP	26,31,DATUM_LENGTH,26		; length as machine word
983	ADD	26,21,25			; end of data (-(9+round))
984	COMBF,<	25,20,invoke_primitive		; no space, use primitive
985	SHD	0,26,2,24			; scale down to word
986	STB	0,8(0,25)			; end-of-string #\NUL
987	LDO	2(24),24			; total word size (-1)
988	STWS,MB	26,4(0,21)			; store string length
989	LDI	TC_NMV,1
990	SH2ADD	24,21,21			; allocate!
991	DEP	1,TC_START,TC_LENGTH,24		; tag header
992	LDW	4(0,22),25			; return address as object
993	STW	24,0(0,2)			; store nmv header
994	LDI	TC_STRING,1
995	DEP	5,TC_START,TC_LENGTH,25		; return address as address
996	DEP	1,TC_START,TC_LENGTH,2		; tag result
997	BLE	0(5,25)				; return!
998	LDO	8(22),22			; pop stack frame
999
1000floating_vector_cons
1001	LDW	0(0,22),26			; length as fixnum
1002	; STW	0,0(0,21)			; make heap parseable
1003	DEPI	4,31,3,21			; bump free past header
1004	COPY	21,2				; return value
1005	ZDEP	26,31,DATUM_LENGTH,26		; length as machine word
1006	SH3ADD	26,21,25			; end of data (-1)
1007	COMBF,<	25,20,invoke_primitive		; no space, use primitive
1008	SHD	26,0,31,26			; scale, harmless in delay slot
1009	LDO	4(25),21			; allocate!
1010	LDI	TC_NMV,1
1011	DEP	1,TC_START,TC_LENGTH,26		; tag header
1012	LDW	4(0,22),25			; return address as object
1013	STW	26,0(0,2)			; store nmv header
1014	DEPI	TC_FLONUM,TC_START,TC_LENGTH,2	; tag result
1015	DEP	5,TC_START,TC_LENGTH,25		; return address as address
1016	BLE	0(5,25)				; return!
1017	LDO	8(22),22			; pop stack frame
1018
1019define(define_floating_point_util,
1020"flonum_$1
1021	STW	2,8(0,4)			; preserve val
1022	COPY	22,18				; preserve regs
1023	COPY	21,17
1024	COPY	19,16
1025        .CALL   ARGW0=FR,ARGW1=FU,RTNVAL=FU     ;fpin=105;fpout=104;
1026	BL	$2,2
1027	COPY	31,15
1028	COPY	16,19
1029	COPY	17,21
1030	COPY	18,22
1031	LDW	8(0,4),2			; restore val
1032	BE	0(5,15)
1033	LDW	0(0,4),20")
1034
1035define_floating_point_util(sin,sin)
1036define_floating_point_util(cos,cos)
1037define_floating_point_util(tan,tan)
1038define_floating_point_util(asin,asin)
1039define_floating_point_util(acos,acos)
1040define_floating_point_util(atan,atan)
1041define_floating_point_util(exp,exp)
1042define_floating_point_util(log,log)
1043define_floating_point_util(truncate,double_truncate)
1044define_floating_point_util(ceiling,ceil)
1045define_floating_point_util(floor,floor)
1046
1047flonum_atan2
1048	STW	2,8(0,4)			; preserve val
1049	COPY	22,18				; preserve regs
1050	COPY	21,17
1051	COPY	19,16
1052        .CALL   ARGW0=FR,ARGW1=FU,ARGW2=FR,ARGW3=FU,RTNVAL=FU   ;fpin=105,107;fpout=104;
1053	BL	atan2,2
1054	COPY	31,15
1055	COPY	16,19
1056	COPY	17,21
1057	COPY	18,22
1058	LDW	8(0,4),2			; restore val
1059	BE	0(5,15)
1060	LDW	0(0,4),20
1061
1062compiled_code_bkpt
1063	LDO	-4(31),31			; bump back to entry point
1064	COPY	19,25				; Preserve Dynamic link
1065	B	trampoline_to_interface
1066	LDI	0x3c,28
1067
1068compiled_closure_bkpt
1069	LDO	-12(31),31			; bump back to entry point
1070	B	trampoline_to_interface
1071	LDI	0x3d,28
1072
1073closure_entry_bkpt
1074	LDO	-4(31),31			; bump back to entry point
1075	B	trampoline_to_interface
1076	LDI	0x3c,28
1077
1078;; On arrival, 31 has a return address.  The word at the return
1079;; address has the offset between the return address and the
1080;; closure pattern.
1081;; Returns the address of the entry point in 25
1082;; Used: 29, 28, 26, 25, fp11, fp10 [31]
1083
1084copy_closure_pattern
1085	LDW	-3(0,31),29			; offset
1086	DEPI	4,31,3,21			; quad align
1087	ADD	29,31,29			; addr of pattern
1088	LDWS,MA	4(0,29),28			; load pattern header
1089	LDO	8(21),25			; preserve for FDC & FIC
1090	STWS,MA	28,4(0,21)			; store pattern header
1091	FLDDS,MA	8(0,29),10		; load entry
1092	FLDDS,MA	8(0,29),11
1093	FSTDS,MA	10,8(0,21)		; store entry
1094	FSTDS,MA	11,8(0,21)
1095	FDC	0(0,25)
1096	FDC	0(0,21)
1097	SYNC
1098	FIC	0(5,25)
1099	BE	4(5,31)
1100	SYNC
1101
1102;; On arrival, 31 has a return address and 1 contains the number of
1103;; entries in the closure.  The word at the return address has the
1104;; offset between the return address and the closure pattern.
1105;; Returns the address of the entry point in 25
1106;; Used: 29, 28, 26, 25, fp11, fp10 [31, 1]
1107
1108copy_multiclosure_pattern
1109	LDW	-3(0,31),29			; offset
1110	DEPI	4,31,3,21			; quad align
1111	ADD	29,31,29			; addr of pattern
1112	LDWS,MA	4(0,29),28			; load pattern header
1113	LDO	12(21),25			; preserve for FIC
1114	STWS,MA	28,4(0,21)			; store pattern header
1115	LDI	-16,26				; FDC index
1116
1117copy_multiclosure_pattern_loop
1118	FLDDS,MA	8(0,29),10		; load entry
1119	FLDDS,MA	8(0,29),11
1120	FSTDS,MA	10,8(0,21)		; store entry
1121	FSTDS,MA	11,8(0,21)
1122	ADDIB,>	-1,1,copy_multiclosure_pattern_loop
1123	FDC	26(0,21)
1124
1125	LDWS,MA	4(0,29),28			; load pattern tail
1126	COPY	21,26
1127	STWS,MA 28,4(0,21)			; store pattern tail
1128	FDC	0(0,26)
1129	SYNC
1130	FIC	0(5,25)
1131	BE	4(5,31)				; return
1132	SYNC
1133
1134;; This label is used by the trap handler
1135
1136ep_scheme_hooks_high
1137
1138;;;; Assembly language entry point used by utilities in cmpint.c
1139;;;  to return to the interpreter.
1140;;;  It returns from C_to_interface.
1141
1142ep_interface_to_C
1143	COPY	29,28				; Setup C value
1144        LDW     -eval(C_FRAME_SIZE+20)(0,30),2	; Restore return address
1145        LDW     -52(0,30),18			; Restore saved registers
1146        LDW     -56(0,30),17
1147        LDW     -60(0,30),16
1148        LDW     -64(0,30),15
1149        LDW     -68(0,30),14
1150        LDW     -72(0,30),13
1151        LDW     -76(0,30),12
1152        LDW     -80(0,30),11
1153        LDW     -84(0,30),10
1154        LDW     -88(0,30),9
1155        LDW     -92(0,30),8
1156        LDW     -96(0,30),7
1157        LDW     -100(0,30),6
1158        LDW     -104(0,30),5
1159        LDW     -108(0,30),4
1160        BV      0(2)				; Return
1161        .EXIT
1162        LDWM    -eval(C_FRAME_SIZE)(0,30),3	; Restore last reg, pop frame
1163        .PROCEND				;in=26;out=28;
1164
1165;;;; Procedure to initialize this interface.
1166;;;
1167;;; C signature:
1168;;;
1169;;; void initialize_interface (void);
1170
1171interface_initialize
1172	.PROC
1173	.CALLINFO CALLER,FRAME=4,SAVE_RP
1174	.ENTRY
1175	STW	2,-20(0,30)			; Preserve return address
1176	LDO	64(30),30			; Allocate stack frame
1177	STW	3,-64(30)			; Preserve gr3
1178	FSTWS	0,-4(30)
1179	LDW	-4(30),22
1180	LDI	30,21				; enable V, Z, O, U traps
1181	OR	21,22,22
1182	STW	22,-4(30)
1183	FLDWS	-4(30),0
1184						; Prepare entry points
1185	BL	known_pc,3			; get pc
1186	NOP
1187known_pc
1188
1189define(store_entry_point,"ADDIL	L'ep_$1-known_pc,3
1190	LDO	R'ep_$1-known_pc(1),29
1191	ADDIL	L'$1-$global$,27
1192	STW	29,R'$1-$global$(1)")
1193
1194	store_entry_point(interface_to_scheme)
1195	store_entry_point(interface_to_C)
1196
1197changequote([,])
1198define(builtin,[ADDIL	L'$1-known_pc,3
1199	LDO	R'$1-known_pc(1),26
1200	ADDIL	L'$1_string-$global$,27
1201	.CALL	ARGW0=GR
1202	BL	declare_builtin,2
1203	LDO	R'$1_string-$global$(1),25 divert(1)
1204$1_string
1205	.ALIGN	8
1206	.STRINGZ "$1" divert(0)])
1207
1208	builtin(scheme_to_interface_ble)
1209	builtin(ep_scheme_hooks_low)
1210	builtin(store_closure_entry)
1211	builtin(store_closure_code)
1212	builtin(multiply_fixnum)
1213	builtin(fixnum_quotient)
1214	builtin(fixnum_remainder)
1215	builtin(fixnum_lsh)
1216	builtin(flonum_result)
1217	builtin(generic_boolean_result)
1218	builtin(generic_decrement)
1219	builtin(generic_divide)
1220	builtin(generic_equal)
1221	builtin(generic_greater)
1222	builtin(generic_increment)
1223	builtin(generic_less)
1224	builtin(generic_subtract)
1225	builtin(generic_times)
1226	builtin(generic_negative)
1227	builtin(generic_plus)
1228	builtin(generic_positive)
1229	builtin(generic_zero)
1230	builtin(shortcircuit_apply)
1231	builtin(shortcircuit_apply_1)
1232	builtin(shortcircuit_apply_2)
1233	builtin(shortcircuit_apply_3)
1234	builtin(shortcircuit_apply_4)
1235	builtin(shortcircuit_apply_5)
1236	builtin(shortcircuit_apply_6)
1237	builtin(shortcircuit_apply_7)
1238	builtin(shortcircuit_apply_8)
1239	builtin(stack_and_interrupt_check)
1240	builtin(invoke_primitive)
1241	builtin(cross_segment_call)
1242	builtin(vector_cons)
1243	builtin(string_allocate)
1244	builtin(floating_vector_cons)
1245	builtin(flonum_sin)
1246	builtin(flonum_cos)
1247	builtin(flonum_tan)
1248	builtin(flonum_asin)
1249	builtin(flonum_acos)
1250	builtin(flonum_atan)
1251	builtin(flonum_exp)
1252	builtin(flonum_log)
1253	builtin(flonum_truncate)
1254	builtin(flonum_ceiling)
1255	builtin(flonum_floor)
1256	builtin(flonum_atan2)
1257	builtin(compiled_code_bkpt)
1258	builtin(compiled_closure_bkpt)
1259	builtin(copy_closure_pattern)
1260	builtin(copy_multiclosure_pattern)
1261	builtin(ep_scheme_hooks_high)
1262changequote(",")
1263						; Return
1264	LDW	-84(30),2			; Restore return address
1265	LDW	-64(30),3			; Restore gr3
1266	BV	0(2)
1267	.EXIT
1268	LDO	-64(30),30			; De-allocate stack frame
1269	.PROCEND
1270
1271;;;; Routine to flush some locations from the processor cache.
1272;;;
1273;;; Its C signature is
1274;;;
1275;;; void
1276;;; cache_flush_region (address, count, cache_set)
1277;;;     void *address;
1278;;;     long count;		/* in long words */
1279;;;	unsigned int cache_set;
1280;;;
1281;;; cache_set is a bit mask of the flags I_CACHE (1) and D_CACHE (2).
1282;;; the requested cache (or both) is flushed.
1283;;;
1284;;; We only need to flush every 16 bytes, since cache lines are
1285;;; architecturally required to have cache line sizes that are
1286;;; multiples of 16 bytes.  This is wasteful on processors with cache
1287;;; line sizes greater than 16 bytes, but this routine is typically
1288;;; called to flush very small ranges.
1289;;; We flush an additional time after flushing every 16 bytes since
1290;;; the start address may not be aligned with a cache line, and thus
1291;;; the end address may fall in a different cache line from the
1292;;; expected one.  The extra flush is harmless when not necessary.
1293
1294cache_flush_region
1295	.PROC
1296        .CALLINFO CALLER,FRAME=0
1297	.ENTRY
1298	LDO	3(25),25			; add 3 to round up
1299	SHD	0,25,2,25			; divide count (in longs) by 4
1300	COPY	25,28				; save for FIC loop
1301	COPY	26,29				; save for FIC loop
1302	LDI	16,1				; increment
1303	BB,>=,N	24,30,process_i_cache		; if D_CACHE is not set,
1304						;  skip d-cache
1305;;;
1306flush_cache_fdc_loop
1307	ADDIB,>=	-1,25,flush_cache_fdc_loop
1308	FDC,M	1(0,26)
1309	SYNC
1310;;;
1311process_i_cache
1312	BB,>=,N	24,31,L$exit2			; if I_CACHE is not set, return
1313;;;
1314flush_cache_fic_loop
1315	ADDIB,>=	-1,28,flush_cache_fic_loop
1316	FIC,M	1(5,29)
1317;;;
1318L$exit2
1319	BV	0(2)
1320	.EXIT
1321	SYNC
1322	.PROCEND				;in=25,26;
1323
1324;;;; Routine to flush the processor cache.
1325;;;
1326;;; Its C signature is
1327;;;
1328;;; void
1329;;; cache_flush_all (cache_set, cache_info)
1330;;;      unsigned int cache_set;
1331;;;      struct pdc_cache_rtn_block *cache_info;
1332;;;
1333;;; cache_set is a bit mask of the flags I_CACHE (1) and D_CACHE (2).
1334;;; the requested cache (or both) is flushed.
1335;;;
1336;;; struct pdc_cache_rtn_block is defined in <machine/pdc_rqsts.h> and
1337;;; is the structure returned by the PDC_CACHE
1338;;; processor-dependent-code call, and stored in the kernel variable
1339;;; (HP-UX) "cache_tlb_parms".  Only the cache parameters (and not the
1340;;; TLB parameters) are used.
1341
1342cache_flush_all
1343	.PROC
1344	.CALLINFO CALLER,FRAME=24
1345	.ENTRY
1346
1347do_d_cache
1348	BB,>=,N	26,30,do_i_cache		; if D_CACHE is not set,
1349						;  skip d-cache
1350
1351	LDW	32(0,25),31			; 31 <- address (init. base)
1352	LDW	44(0,25),29			; 29 <- loop
1353	LDW	36(0,25),23			; 23 <- stride
1354	LDW	40(0,25),19			; 19 <- count
1355
1356	LDO	-1(19),19			; decrement count
1357	COMIB,>,N	0,19,d_sync		; if (count < 0), no flush
1358	COMIB,=,N	1,29,d_direct_l
1359	COMIB,=,N	2,29,d_assoc2_l
1360	COMIB,=,N	4,29,d_assoc4_l
1361
1362d_assoc_l					; set-associative flush-loop
1363	COPY	29,20				; 20 (lcount) <- loop
1364
1365d_set_l						; set flush-loop
1366	LDO	-1(20),20			; decrement lcount
1367	COMIB,<=,N	0,20,d_set_l		; if (lcount >= 0), set loop
1368	FDCE	0(0,31)				; flush entry at (address)
1369
1370	LDO	-1(19),19			; decrement count
1371	COMIB,<=	0,19,d_assoc_l		; if (count >= 0), loop
1372	ADD	31,23,31			; address++
1373
1374	B	do_i_cache			; next
1375	SYNC					; synchronize after flush
1376
1377d_assoc4_l					; 4-way set-associative loop
1378	FDCE	0(0,31)				; flush entry at (*address)
1379	FDCE	0(0,31)				; flush entry at (*address)
1380	FDCE	0(0,31)				; flush entry at (*address)
1381	FDCE,M	23(0,31)			; flush entry at (*address++)
1382	COMIB,<		0,19,d_assoc4_l		; if (count > 0), loop
1383	LDO	-1(19),19			; decrement count
1384
1385	B	do_i_cache			; next
1386	SYNC					; synchronize after flush
1387
1388d_assoc2_l					; 2-way set-associative loop
1389	FDCE	0(0,31)				; flush entry at (*address)
1390	FDCE,M	23(0,31)			; flush entry at (*address++)
1391	COMIB,<		0,19,d_assoc2_l		; if (count > 0), loop
1392	LDO	-1(19),19			; decrement count
1393
1394	B	do_i_cache			; next
1395	SYNC					; synchronize after flush
1396
1397d_direct_l					; direct-mapped flush loop
1398	FDCE,M	23(0,31)			; flush entry at (*address++)
1399	COMIB,<		0,19,d_direct_l		; if (count > 0), loop
1400	LDO	-1(19),19			; decrement count
1401
1402d_sync
1403	SYNC					; synchronize after flush
1404
1405do_i_cache
1406	BB,>=,N	26,31,L$exit1			; if I_CACHE is not set, return
1407
1408	LDW	8(0,25),31			; 31 <- address (init. base)
1409	LDW	20(0,25),29			; 29 <- loop
1410	LDW	12(0,25),23			; 23 <- stride
1411	LDW	16(0,25),19			; 19 <- count
1412
1413	LDO	-1(19),19			; decrement count
1414	COMIB,>,N	0,19,i_sync		; if (count < 0), no flush
1415	COMIB,=,N	1,29,i_direct_l
1416	COMIB,=,N	2,29,i_assoc2_l
1417	COMIB,=,N	4,29,i_assoc4_l
1418
1419i_assoc_l					; set-associative flush-loop
1420	COPY	29,20				; 20 (lcount) <- loop
1421
1422i_set_l						; set flush-loop
1423	LDO	-1(20),20			; decrement lcount
1424	COMIB,<=,N	0,20,i_set_l		; if (lcount >= 0), set loop
1425	FICE	0(5,31)				; flush entry at (address)
1426
1427	LDO	-1(19),19			; decrement count
1428	COMIB,<=	0,19,i_assoc_l		; if (count >= 0), loop
1429	ADD	31,23,31			; address++
1430
1431	B	i_skips				; next
1432	SYNC					; synchronize after flush
1433
1434i_assoc4_l					; 4-way set-associative loop
1435	FICE	0(5,31)				; flush entry at (*address)
1436	FICE	0(5,31)				; flush entry at (*address)
1437	FICE	0(5,31)				; flush entry at (*address)
1438	FICE,M	23(5,31)			; flush entry at (*address++)
1439	COMIB,<		0,19,i_assoc4_l		; if (count > 0), loop
1440	LDO	-1(19),19			; decrement count
1441
1442	B	i_skips				; next
1443	SYNC					; synchronize after flush
1444
1445i_assoc2_l					; 2-way set-associative loop
1446	FICE	0(5,31)				; flush entry at (*address)
1447	FICE,M	23(5,31)			; flush entry at (*address++)
1448	COMIB,<		0,19,i_assoc2_l		; if (count > 0), loop
1449	LDO	-1(19),19			; decrement count
1450
1451	B	i_skips				; next
1452	SYNC					; synchronize after flush
1453
1454i_direct_l					; direct-mapped flush loop
1455	FICE,M	23(5,31)			; flush entry at (*address++)
1456	COMIB,<		0,19,i_direct_l		; if (count > 0), loop
1457	LDO	-1(19),19			; decrement count
1458
1459i_sync
1460	SYNC					; synchronize after flush
1461
1462i_skips
1463	NOP					; 7 instructionss as prescribed
1464	NOP					; by the programming note in
1465	NOP					; the description for SYNC.
1466	NOP
1467	NOP
1468
1469L$exit1
1470	BV	0(2)
1471	.EXIT
1472	NOP
1473	.PROCEND ;in=25,26;
1474
1475bkpt_normal_proceed
1476	BL	bkpt_normal_cont,1		; Get PC
1477	DEP	0,31,2,1
1478bkpt_normal_cont
1479	LDW	bkpt_normal_ep-bkpt_normal_cont(0,1),1		; entry point
1480	BV	0(1)				; Invoke
1481	NOP					; Slot for first instruction
1482bkpt_normal_ep
1483	NOP					; Slot for fall through
1484
1485bkpt_plus_proceed
1486	COMB,=	1,1,bkpt_plus_t			; Slot for first instruction
1487	NOP					; Slot for second instruction
1488	STWM	1,-4(0,22)			; Preserve 1
1489	BL	bkpt_plus_cont_f,1		; Get PC
1490	DEP	0,31,2,1
1491bkpt_plus_cont_f
1492	LDW	bkpt_plus_ep-bkpt_plus_cont_f(0,1),1		; entry point
1493	BV	0(1)				; Invoke
1494	LDWM	4(0,22),1
1495bkpt_plus_t
1496	STWM	1,-4(0,22)			; Preserve 1
1497	BL	bkpt_plus_cont_t,1		; Get PC
1498	DEP	0,31,2,1
1499bkpt_plus_cont_t
1500	LDW	bkpt_plus_bt-bkpt_plus_cont_t(0,1),1		; entry point
1501	BV	0(1)				; Invoke
1502	LDWM	4(0,22),1
1503bkpt_plus_ep
1504	NOP					; Slot for fall through
1505bkpt_plus_bt
1506	NOP					; Slot for branch target
1507
1508bkpt_minus_proceed_start
1509bkpt_minus_t
1510	STWM	1,-4(0,22)			; Preserve 1
1511	BL	bkpt_minus_cont_t,1		; Get PC
1512	DEP	0,31,2,1
1513bkpt_minus_cont_t
1514	LDW	bkpt_minus_bt-bkpt_minus_cont_t(0,1),1 ; entry point
1515	BV	0(1)				; Invoke
1516	LDWM	4(0,22),1
1517bkpt_minus_proceed
1518	COMB,=	1,1,bkpt_minus_t		; Slot for first instruction
1519	NOP					; Slot for second instruction
1520	STWM	1,-4(0,22)			; Preserve 1
1521	BL	bkpt_minus_cont_f,1		; Get PC
1522	DEP	0,31,2,1
1523bkpt_minus_cont_f
1524	LDW	bkpt_minus_ep-bkpt_minus_cont_f(0,1),1 ; entry point
1525	BV	0(1)				; Invoke
1526	LDWM	4(0,22),1
1527bkpt_minus_ep
1528	NOP					; Slot for fall through
1529bkpt_minus_bt
1530	NOP					; Slot for branch target
1531
1532bkpt_closure_proceed
1533	BL	bkpt_closure_cont,1
1534	DEP	0,31,2,1
1535bkpt_closure_cont
1536	LDW	bkpt_closure_entry-bkpt_closure_cont(0,1),25
1537	LDW	bkpt_closure_closure-bkpt_closure_cont(0,1),31
1538	BV	0(25)
1539	COPY	31,25
1540bkpt_closure_closure
1541	NOP					; Closure object pointer
1542bkpt_closure_entry
1543	NOP					; Eventual entry point
1544bkpt_closure_proceed_end
1545	NOP
1546
1547	.SPACE	$TEXT$
1548	.SUBSPA $LIT$,QUAD=0,ALIGN=8,ACCESS=44
1549;	.SUBSPA $CODE$,QUAD=0,ALIGN=8,ACCESS=44,CODE_ONLY
1550	.SUBSPA $UNWIND$,QUAD=0,ALIGN=8,ACCESS=44
1551	.SUBSPA $CODE$
1552	.SPACE	$PRIVATE$
1553	.SUBSPA $SHORTBSS$
1554interface_to_scheme .COMM 4
1555interface_to_C .COMM 4
1556scheme_hooks_low .COMM 4
1557scheme_hooks_high .COMM 4
1558	.SUBSPA $DATA$,QUAD=1,ALIGN=8,ACCESS=31
1559$THISMODULE$
1560ifelse(ASM_DEBUG,1,"interface_counter
1561	.ALIGN	8
1562	.WORD	0
1563interface_limit
1564	.WORD	0")
1565undivert(1)
1566	.SUBSPA $BSS$,QUAD=1,ALIGN=8,ACCESS=31,ZERO
1567	.IMPORT $global$,DATA
1568	.IMPORT	Registers,DATA
1569	.IMPORT	sp_register,DATA
1570	.IMPORT	Free,DATA
1571	.IMPORT	hppa_utility_table,DATA
1572	.IMPORT	hppa_primitive_table,DATA
1573	.IMPORT	Primitive_Arity_Table,DATA
1574	.IMPORT	Primitive_Procedure_Table,DATA
1575	.SPACE	$TEXT$
1576	.SUBSPA $CODE$
1577        .IMPORT $$dyncall,MILLICODE
1578        .IMPORT $$remI,MILLICODE
1579	.IMPORT declare_builtin,CODE
1580	.IMPORT	sin,CODE
1581	.IMPORT	cos,CODE
1582	.IMPORT	tan,CODE
1583	.IMPORT	asin,CODE
1584	.IMPORT	acos,CODE
1585	.IMPORT	atan,CODE
1586	.IMPORT	exp,CODE
1587	.IMPORT	log,CODE
1588	.IMPORT	double_truncate,CODE
1589	.IMPORT	ceil,CODE
1590	.IMPORT	floor,CODE
1591	.IMPORT	atan2,CODE
1592	.EXPORT C_to_interface,PRIV_LEV=3,ARGW0=GR,RTNVAL=GR
1593	.EXPORT ep_interface_to_scheme,PRIV_LEV=3
1594	.EXPORT scheme_to_interface_ble,PRIV_LEV=3
1595	.EXPORT trampoline_to_interface,PRIV_LEV=3
1596	.EXPORT scheme_to_interface,PRIV_LEV=3
1597	.EXPORT hook_jump_table,PRIV_LEV=3
1598	.EXPORT cross_segment_call,PRIV_LEV=3
1599	.EXPORT	flonum_atan2,PRIV_LEV=3
1600	.EXPORT ep_interface_to_C,PRIV_LEV=3
1601	.EXPORT interface_initialize,PRIV_LEV=3
1602	.EXPORT cache_flush_region,PRIV_LEV=3
1603	.EXPORT cache_flush_all,PRIV_LEV=3
1604	.EXPORT bkpt_normal_proceed,PRIV_LEV=3
1605	.EXPORT bkpt_plus_proceed,PRIV_LEV=3
1606	.EXPORT bkpt_minus_proceed_start,PRIV_LEV=3
1607	.EXPORT bkpt_minus_proceed,PRIV_LEV=3
1608	.EXPORT bkpt_closure_proceed,PRIV_LEV=3
1609	.EXPORT bkpt_closure_proceed_end,PRIV_LEV=3
1610	.END
1611