### -*-Midas-*-
###
### $Id: mc68k.m4,v 1.27 2000/12/05 21:23:50 cph Exp $
###
### Copyright (c) 1989-2000 Massachusetts Institute of Technology
###
### This program is free software; you can redistribute it and/or
### modify it under the terms of the GNU General Public License as
### published by the Free Software Foundation; either version 2 of the
### License, or (at your option) any later version.
###
### This program is distributed in the hope that it will be useful,
### but WITHOUT ANY WARRANTY; without even the implied warranty of
### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
### General Public License for more details.
###
### You should have received a copy of the GNU General Public License
### along with this program; if not, write to the Free Software
### Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
###
#### 68K assembly language (HP/Motorola Syntax) part of the compiled
#### code interface. See cmpint.txt, cmpint.c, cmpint-mc68k.h, and
#### cmpgc.h for more documentation.
####
#### NOTE:
#### Assumptions:
####
#### 1) All registers (except double floating point registers) and
#### stack locations hold a C long object.
####
#### 2) The C compiler divides registers into three groups:
#### - Linkage registers, used for procedure calls and global
#### references. On MC68K: a6, sp.
#### - super temporaries, not preserved accross procedure calls and
#### always usable. On MC68K: a0, a1, d0, d1
#### - preserved registers saved by the callee if they are written.
#### On MC68K: all others.
####
#### 3) Arguments, if passed on a stack, are popped by the caller
#### or by the procedure return instruction (as on the VAX). Thus
#### most "leaf" procedures need not worry about them.
####
#### 4) There is a hardware or software maintained stack for
#### control. The procedure calling sequence may leave return
#### addresses in registers, but they must be saved somewhere for
#### nested calls and recursive procedures. On MC68K: saved on
#### the stack.
####
#### 5) C procedures return long values in a super temporary
#### register. Two word structures are returned in super temporary
#### registers as well. On MC68K: d0 is used for long returns.
#### Since there are two methods for returning structures on MC68K,
#### there is a flag to choose a mechanism:
#### o GCC returns two word structures in d0/d1 (set flag GCC in
#### M4_MACHINE_SWITCHES in m.h)
#### o Other compilers return the address of the structure in d0
#### o The HP compiler requires that the address of this structure
#### be in a1 before the procedure is called (set flag HP in
#### M4_MACHINE_SWITCHES in m.h)
####
#### 6) Floating point registers are not preserved by this
#### interface. The interface is only called from the Scheme
#### interpreter, which does not use floating point data. Thus
#### although the calling convention would require us to preserve
#### them, they contain garbage.
####
#### Compiled Scheme code uses the following register convention:
#### - a7 (sp) contains the Scheme stack pointer, not the C stack
#### pointer.
#### - a6 (fp) contains a pointer to the Scheme interpreter's
#### "register" block. This block contains the compiler's copy of
#### MemTop, the interpreter's registers (val, env, exp, etc),
#### temporary locations for compiled code, and the mechanism used
#### to invoke the hooks in this file.
#### - a5 contains the Scheme free pointer.
#### - a4 contains the dynamic link when needed.
#### - d7 contains the Scheme datum mask.
#### - d6 is where Scheme compiled code returns values.
####
#### All other registers are available to the compiler. A
#### caller-saves convention is used, so the registers need not be
#### preserved by subprocedures.
#### Utility macros and definitions
define(KEEP_HISTORY,0) # Debugging switch
define(reference_external,`') # Declare desire to use an external
define(extern_c_label,`_$1') # The actual reference
define(define_c_label,
` global extern_c_label($1)
extern_c_label($1):')
define(define_debugging_label,
` global $1
$1:')
# Call a SCHEME_UTILITY (see cmpint.c) and then dispatch to the
# interface procedure requested with the data to be passed to the
# procedure in d1.
#
# NOTE: Read introductory note about GCC and HP switches
define(allocate_utility_result,
`ifdef(`HP',
`subq.l &8,%sp
mov.l %sp,%a1',
`')')
define(utility_call,
`jsr (%a0) # call C procedure
ifdef(`HP',
`lea eval(($1+2)*4)(%sp),%sp',
`lea eval($1*4)(%sp),%sp')
mov.l %d0,%a0
ifdef(`GCC',
`',
`mov.l 4(%a0),%d1
mov.l 0(%a0),%a0')
jmp (%a0)')
# Scheme object representation. Must match object.h
define(HEX, `0x$1')
define(TC_LENGTH, ifdef(`TYPE_CODE_LENGTH', TYPE_CODE_LENGTH, 6))
define(ADDRESS_MASK, eval(((2 ** (32 - TC_LENGTH)) - 1), 16))
define(TYPE_CODE_FACTOR, eval(2 ** (8 - TC_LENGTH)))
define(TYPE_CODE_MASK, eval((256 - TYPE_CODE_FACTOR), 16))
define(CLEAR_TYPE_MASK, eval((TYPE_CODE_FACTOR - 1), 16))
define(TYPE_CODE_TO_BYTE, `$1*TYPE_CODE_FACTOR')
define(TYPE_CODE_TO_OBJECT, `TYPE_CODE_TO_BYTE($1)*0x1000000')
define(EXTRACT_TYPE_CODE,
`ifelse(TC_LENGTH, 8,
`mov.b $1,$2',
`mov.b $1,$2
and.b &HEX(TYPE_CODE_MASK), $2')')
define(COMPARE_TYPE_CODE,
`cmp.b $1,&TYPE_CODE_TO_BYTE($2)')
### External conventions
set regblock_memtop,0 # from const.h (* 4)
set regblock_int_mask,4
set regblock_val,8
set regblock_stack_guard,44
set regblock_int_code,48
set address_mask,HEX(ADDRESS_MASK)
# This must match the compiler (machin.scm)
define(dlink, %a4) # Dynamic link register (contains a
# pointer to a return address)
define(rfree, %a5) # Free pointer
define(regs, %a6) # Pointer to Registers[0]
define(rmask, %d7) # Mask to clear type code
define(rval,%d6) # Procedure value
reference_external(Ext_Stack_Pointer)
reference_external(Free)
reference_external(Registers)
# These must match the C compiler
define(switch_to_scheme_registers,
`mov.l %a6,(%sp)
mov.l %sp,c_save_stack
mov.l extern_c_label(Ext_Stack_Pointer),%sp
mov.l extern_c_label(Free),rfree
lea extern_c_label(Registers),regs
mov.l &address_mask,rmask')
define(switch_to_C_registers,
`mov.l rfree,extern_c_label(Free)
mov.l %sp,extern_c_label(Ext_Stack_Pointer)
mov.l c_save_stack,%sp
mov.l (%sp),%a6')
###
### Global data
###
data
define_debugging_label(c_save_stack)
space 4
ifelse(KEEP_HISTORY, 1,
`define_debugging_label(ring_pointer)
long ring_block_1
define_debugging_label(ring_block_1)
long ring_block_2
space 28
define_debugging_label(ring_block_2)
long ring_block_3
space 28
define_debugging_label(ring_block_3)
long ring_block_4
space 28
define_debugging_label(ring_block_4)
long ring_block_5
space 28
define_debugging_label(ring_block_5)
long ring_block_1
space 28')
text
### Initialize the 68881 if present.
define_c_label(interface_initialize)
link %a6,&0
ifdef(`MC68881', `fmov.l &0x3480,%fpcr')
unlk %a6
rts
### Callable by C conventions. Swaps to Scheme register set and jumps
### to the entry point specified by its only argument.
define_c_label(C_to_interface)
link %a6,&-44
movm.l %d2-%d7/%a2-%a5,4(%sp)
mov.l 8(%a6),%a0 # Argument: entry point
bra.b interface_to_scheme_internal
### Called by Scheme through a jump instruction in the register block.
### It expects an index in %d0, and 4 longword arguments in %d1-%d4
reference_external(utility_table)
define_c_label(asm_scheme_to_interface)
define_debugging_label(scheme_to_interface)
ifelse(KEEP_HISTORY, 1,
`lea ring_pointer,%a1
mov.l (%a1),%a0
mov.l (%a0),(%a1)
mov.l %sp,4(%a0)
mov.l %a5,8(%a0)
mov.l %d0,12(%a0)
mov.l %d1,16(%a0)
mov.l %d2,20(%a0)
mov.l %d3,24(%a0)
mov.l %d4,28(%a0)
cmp.l %sp,%a5
bgt.b scheme_to_interface_proceed
nop
define_debugging_label(scheme_to_interface_proceed)')
mov.l rval,regblock_val(regs)
switch_to_C_registers()
allocate_utility_result()
mov.l %d4,-(%sp) # Push arguments to scheme utility
mov.l %d3,-(%sp)
mov.l %d2,-(%sp)
mov.l %d1,-(%sp)
lea extern_c_label(utility_table),%a0
mov.l (0,%a0,%d0.w*4),%a0 # C-written Scheme utility
utility_call(4) # 4 arguments
### The data in %d1 is the address of an entry point to invoke.
define_c_label(interface_to_scheme)
mov.l %d1,%a0
###
### Enter the scheme compiled world.
### The value register is copied to %d0 because some utilities are
### expected to return their value there (this should be fixed),
### and it is stripped and placed in the dlink register since
### we may be returning after interrupting a procedure which
### needs this register. This should also be separated or handled
### inline.
###
define_debugging_label(interface_to_scheme_internal)
switch_to_scheme_registers()
mov.l regblock_val(regs),rval
mov.l rval,%d0
mov.l %d0,%d1
and.l rmask,%d1
mov.l %d1,dlink
jmp (%a0)
### The data in %d1 is a return code (integer) to the interpreter.
define_c_label(interface_to_C)
mov.l %d1,%d0 # C return value location
movm.l 4(%sp),%d2-%d7/%a2-%a5
unlk %a6
rts
#### Optimized entry points
### Additional entry points that take care of common cases and are used to
### shorten code sequences.
### These are not strictly necessary, since the code sequences emitted by
### the compiler could use scheme_to_interface instead, but a few instructions
### are saved this way.
### Called by linker-generated trampolines to invoke the appropriate
### C-written handler. The return address on the stack is the address
### of the trampoline storage area, passed to the C handler as the
### first argument.
### IMPORTANT:
### All the asm_* routines are declared in cmpint-mc68k.h.
### New ones need to be declared there as well!
define_c_label(asm_trampoline_to_interface)
define_debugging_label(trampoline_to_interface)
mov.l (%sp)+,%d1
bra scheme_to_interface
### Called by Scheme through a jump instruction in the register block.
### It is a special version of scheme_to_interface below, used when
### a return address is stored in the Scheme stack.
define_c_label(asm_scheme_to_interface_jsr)
define_debugging_label(scheme_to_interface_jsr)
mov.l (%sp)+,%d1 # Return addr -> d1
addq.l &4,%d1 # Skip format info.
bra scheme_to_interface
define(define_interface_indirection,
`define_c_label(asm_$1)
movq &HEX($2),%d0
bra scheme_to_interface')
define(define_interface_jsr_indirection,
`define_c_label(asm_$1)
movq &HEX($2),%d0
bra scheme_to_interface_jsr')
define_interface_indirection(primitive_lexpr_apply,13)
define_interface_indirection(error,15)
define_interface_jsr_indirection(link,17)
define_interface_indirection(interrupt_closure,18)
define_interface_jsr_indirection(interrupt_procedure,1a)
define_interface_jsr_indirection(interrupt_continuation,1b)
define_interface_jsr_indirection(assignment_trap,1d)
define_interface_jsr_indirection(reference_trap,1f)
define_interface_jsr_indirection(safe_reference_trap,20)
###
### These are handled directly below.
###
### define_interface_indirection(generic_decrement,22)
### define_interface_indirection(generic_divide,23)
### define_interface_indirection(generic_equal,24)
### define_interface_indirection(generic_greater,25)
### define_interface_indirection(generic_increment,26)
### define_interface_indirection(generic_less,27)
### define_interface_indirection(generic_subtract,28)
### define_interface_indirection(generic_multiply,29)
### define_interface_indirection(generic_negative,2a)
### define_interface_indirection(generic_add,2b)
### define_interface_indirection(generic_positive,2c)
### define_interface_indirection(generic_zero,2d)
###
define_interface_jsr_indirection(primitive_error,36)
define_interface_indirection(generic_quotient,37)
define_interface_indirection(generic_remainder,38)
define_interface_indirection(generic_modulo,39)
# Save an additional instruction here to load the dynamic link.
define_c_label(asm_interrupt_dlink)
mov.l dlink,%d2 # Dynamic link -> d2
movq &HEX(19),%d0
bra scheme_to_interface_jsr
# Bum this one for speed.
define_c_label(asm_primitive_apply)
switch_to_C_registers()
allocate_utility_result()
mov.l %d1,-(%sp) # only one argument
ifdef(`SUNASM',
`lea extern_c_label(utility_table),%a0
mov.l HEX(12)*4(%a0),%a0',
`mov.l extern_c_label(utility_table)+HEX(12)*4,%a0')
utility_call(1) # one argument
set tc_compiled_entry,HEX(28)
set tc_flonum,HEX(06)
set tc_fixnum,HEX(1A)
set tc_manifest_nmv,HEX(27)
set tc_false,HEX(0)
set tc_true,HEX(8)
set offset_apply,HEX(14)
define(call_utility,
`movq &offset_$1,%d0
bra scheme_to_interface')
### Called by Scheme when invoking an unknown procedure.
### Having this short sequence in assembly language avoids the C call
### in the common case where the procedure is compiled and the number
### of arguments is correct.
### The number of actual arguments is in d2, the procedure on top
### of the stack.
define_c_label(asm_shortcircuit_apply)
define_debugging_label(shortcircuit_apply)
EXTRACT_TYPE_CODE((%sp),%d0) # Get procedure type
mov.l (%sp)+,%d1 # Get procedure
COMPARE_TYPE_CODE(%d0,tc_compiled_entry)
bne.b shortcircuit_apply_1
mov.l %d1,%d3 # Extract entry point
and.l rmask,%d3
mov.l %d3,%a0
mov.b -3(%a0),%d3 # Extract the frame size
ext.w %d3
cmp.w %d2,%d3 # Is the frame size right?
bne.b shortcircuit_apply_1
jmp (%a0) # Invoke
define_debugging_label(shortcircuit_apply_1)
call_utility(apply)
### Optimized versions of shortcircuit_apply for 0-7 arguments.
define(define_apply_size_n,
`define_c_label(asm_shortcircuit_apply_size_$1)
define_debugging_label(shortcircuit_apply_size_$1)
EXTRACT_TYPE_CODE((%sp),%d0) # Get procedure type
mov.l (%sp)+,%d1 # Get procedure
COMPARE_TYPE_CODE(%d0,tc_compiled_entry)
bne.b shortcircuit_apply_size_$1_1
mov.l %d1,%d3 # Extract entry point
and.l rmask,%d3
mov.l %d3,%a0
cmp.b -3(%a0),&$1 # Is the frame size right?
bne.b shortcircuit_apply_size_$1_1
jmp (%a0) # Invoke
define_debugging_label(shortcircuit_apply_size_$1_1)
movq &$1,%d2 # initialize frame size
call_utility(apply)')
define_apply_size_n(1)
define_apply_size_n(2)
define_apply_size_n(3)
define_apply_size_n(4)
define_apply_size_n(5)
define_apply_size_n(6)
define_apply_size_n(7)
define_apply_size_n(8)
### This utility depends on the C compiler preserving d2-d7 and a2-a7.
### It takes its parameters in d0 and d1, and returns its value in a0.
define_c_label(asm_allocate_closure)
switch_to_C_registers()
mov.l %a1,-(%sp) # Preserve reg.
mov.l %d1,-(%sp) # Preserve reg.
mov.l %d0,-(%sp) # Push arg.
jsr extern_c_label(allocate_closure)
addq.l &4,%sp # Pop arg.
mov.l %d0,%a0 # Return value
mov.l (%sp)+,%d1 # Restore reg.
mov.l (%sp)+,%a1 # Restore reg.
switch_to_scheme_registers()
rts
### These utilities improve the performance of floating point code
### significantly.
### Arguments on top of the stack followed by the return address.
define_debugging_label(asm_generic_flonum_result)
mov.l rfree,rval
mov.l &TYPE_CODE_TO_OBJECT(tc_manifest_nmv)+2,(rfree)+
fmove.d %fp0,(rfree)+
or.l &TYPE_CODE_TO_OBJECT(tc_flonum),rval
and.b &TYPE_CODE_TO_BYTE(1)-1,(%sp)
rts
define_debugging_label(asm_true_result)
mov.l &TYPE_CODE_TO_OBJECT(tc_true),rval
and.b &TYPE_CODE_TO_BYTE(1)-1,(%sp)
rts
define_debugging_label(asm_false_result)
mov.l &TYPE_CODE_TO_OBJECT(tc_false),rval
and.b &TYPE_CODE_TO_BYTE(1)-1,(%sp)
rts
define(define_generic_unary,
`define_c_label(asm_generic_$1)
EXTRACT_TYPE_CODE((%sp),%d0) # Get arg1s type
COMPARE_TYPE_CODE(%d0,tc_flonum)
bne.b asm_generic_$1_hook
mov.l (%sp)+,%d0 # arg1
and.l rmask,%d0
mov.l %d0,%a0
fmove.d 4(%a0),%fp0
$3.b &1,%fp0
bra asm_generic_flonum_result
asm_generic_$1_hook:
movq &HEX($2),%d0
bra scheme_to_interface')
define(define_generic_unary_predicate,
`define_c_label(asm_generic_$1)
EXTRACT_TYPE_CODE((%sp),%d0) # Get arg1s type
COMPARE_TYPE_CODE(%d0,tc_flonum)
bne.b asm_generic_$1_hook
mov.l (%sp)+,%d0 # arg1
and.l rmask,%d0
mov.l %d0,%a0
fmove.d 4(%a0),%fp0
fb$3 asm_true_result
bra asm_false_result
asm_generic_$1_hook:
movq &HEX($2),%d0
bra scheme_to_interface')
define(define_generic_binary,
`define_c_label(asm_generic_$1)
EXTRACT_TYPE_CODE((%sp),%d0) # Get arg1s type
EXTRACT_TYPE_CODE(4(%sp),%d1) # Get arg2s type
mov.l (%sp),%d2 # arg1
mov.l 4(%sp),%d3 # arg2
and.l rmask,%d2
and.l rmask,%d3
mov.l %d2,%a0
mov.l %d3,%a1
COMPARE_TYPE_CODE(%d0,tc_flonum)
bne.b asm_generic_$1_fix_flo
COMPARE_TYPE_CODE(%d1,tc_flonum)
bne.b asm_generic_$1_flo_fix
fmove.d 4(%a0),%fp0
$3.d 4(%a1),%fp0
addq.l &8,%sp
bra asm_generic_flonum_result
asm_generic_$1_fix_flo:
COMPARE_TYPE_CODE(%d0,tc_fixnum)
bne.b asm_generic_$1_hook
COMPARE_TYPE_CODE(%d1,tc_flonum)
bne.b asm_generic_$1_hook
lsl.l &TC_LENGTH,%d2
asr.l &TC_LENGTH,%d2
fmove.l %d2,%fp0
$3.d 4(%a1),%fp0
addq.l &8,%sp
bra asm_generic_flonum_result
asm_generic_$1_flo_fix:
COMPARE_TYPE_CODE(%d1,tc_fixnum)
bne.b asm_generic_$1_hook
lsl.l &TC_LENGTH,%d3
asr.l &TC_LENGTH,%d3
fmove.d 4(%a0),%fp0
$3.l %d3,%fp0
addq.l &8,%sp
bra asm_generic_flonum_result
asm_generic_$1_hook:
movq &HEX($2),%d0
bra scheme_to_interface')
define(define_generic_binary_predicate,
`define_c_label(asm_generic_$1)
EXTRACT_TYPE_CODE((%sp),%d0) # Get arg1s type
EXTRACT_TYPE_CODE(4(%sp),%d1) # Get arg2s type
mov.l (%sp),%d2 # arg1
mov.l 4(%sp),%d3 # arg2
and.l rmask,%d2
and.l rmask,%d3
mov.l %d2,%a0
mov.l %d3,%a1
COMPARE_TYPE_CODE(%d0,tc_flonum)
bne.b asm_generic_$1_fix_flo
COMPARE_TYPE_CODE(%d1,tc_flonum)
bne.b asm_generic_$1_flo_fix
addq.l &8,%sp
fmove.d 4(%a0),%fp0
fcmp.d %fp0,4(%a1)
fb$3 asm_true_result
bra asm_false_result
asm_generic_$1_fix_flo:
COMPARE_TYPE_CODE(%d0,tc_fixnum)
bne.b asm_generic_$1_hook
COMPARE_TYPE_CODE(%d1,tc_flonum)
bne.b asm_generic_$1_hook
addq.l &8,%sp
lsl.l &TC_LENGTH,%d2
asr.l &TC_LENGTH,%d2
fmove.l %d2,%fp0
fcmp.d %fp0,4(%a1)
fb$3 asm_true_result
bra asm_false_result
asm_generic_$1_flo_fix:
COMPARE_TYPE_CODE(%d1,tc_fixnum)
bne.b asm_generic_$1_hook
addq.l &8,%sp
lsl.l &TC_LENGTH,%d3
asr.l &TC_LENGTH,%d3
fmove.d 4(%a0),%fp0
fcmp.l %fp0,%d3
fb$3 asm_true_result
bra asm_false_result
asm_generic_$1_hook:
movq &HEX($2),%d0
bra scheme_to_interface')
define_generic_unary(decrement,22,fsub)
define_generic_binary(divide,23,fdiv)
define_generic_binary_predicate(equal,24,eq)
define_generic_binary_predicate(greater,25,gt)
define_generic_unary(increment,26,fadd)
define_generic_binary_predicate(less,27,lt)
define_generic_binary(subtract,28,fsub)
define_generic_binary(multiply,29,fmul)
define_generic_unary_predicate(negative,2a,lt)
define_generic_binary(add,2b,fadd)
define_generic_unary_predicate(positive,2c,gt)
define_generic_unary_predicate(zero,2d,eq)
### Close-coded stack and interrupt check for use when stack checking
### is enabled.
define_c_label(asm_stack_and_interrupt_check_12)
mov.l &-12,-(%sp)
bra.b stack_and_interrupt_check
define_c_label(asm_stack_and_interrupt_check_14)
mov.l &-14,-(%sp)
bra.b stack_and_interrupt_check
define_c_label(asm_stack_and_interrupt_check_18)
mov.l &-18,-(%sp)
bra.b stack_and_interrupt_check
define_c_label(asm_stack_and_interrupt_check_22)
mov.l &-22,-(%sp)
bra.b stack_and_interrupt_check
define_c_label(asm_stack_and_interrupt_check_24)
mov.l &-24,-(%sp)
# bra.b stack_and_interrupt_check
### On entry, 4(%sp) contains the resumption address, and 0(%sp) is
### the offset between the resumption address and the GC label
### address.
define_debugging_label(stack_and_interrupt_check)
### If the Scheme stack pointer is <= Stack_Guard, then the stack has
### overflowed -- in which case we must signal a stack-overflow interrupt.
cmp.l %sp,regblock_stack_guard(regs)
bgt.b stack_and_interrupt_check_1
### Set the stack-overflow interrupt bit. If the stack-overflow
### interrupt is disabled, skip forward to gc test. Otherwise, set
### MemTop to -1 and signal the interrupt.
bset &0,regblock_int_code+3(regs)
btst &0,regblock_int_mask+3(regs)
beq.b stack_and_interrupt_check_1
mov.l &-1,regblock_memtop(regs)
bra.b stack_and_interrupt_check_2
### If (Free >= MemTop), signal an interrupt.
stack_and_interrupt_check_1:
cmp.l rfree,regblock_memtop(regs)
bge.b stack_and_interrupt_check_2
### No action necessary -- return to resumption address.
addq.l &4,%sp
rts
### Must signal the interrupt -- return to GC label instead.
stack_and_interrupt_check_2:
mov.l %d0,-(%sp)
mov.l 4(%sp),%d0
add.l %d0,8(%sp)
mov.l (%sp),%d0
addq.l &8,%sp
rts
### Assembly-language implementation of SET-INTERRUPT-ENABLES!
### primitive. Argument appears at top of stack, return address below
### that.
define_c_label(asm_set_interrupt_enables)
define_debugging_label(set_interrupt_enables)
# Return value is previous contents of mask register.
mov.l regblock_int_mask(regs),rval
or.l &TYPE_CODE_TO_OBJECT(tc_fixnum),rval
mov.l (%sp)+,%d0 # get new interrupt mask
and.l rmask,%d0 # strip fixnum type
mov.l %d0,regblock_int_mask(regs) # store it in mask register
# Setup compiled memtop register: -1 if pending interrupt,
# Memtop if GC enabled, else Heap_Top.
movq &-1,%d1
mov.l regblock_int_code(regs),%d2
and.l %d0,%d2
bne.b set_interrupt_enables_1
mov.l extern_c_label(MemTop),%d1
btst &2,%d0
bne.b set_interrupt_enables_1
mov.l extern_c_label(Heap_Top),%d1
set_interrupt_enables_1:
mov.l %d1,regblock_memtop(regs)
# Setup compiled stack_guard register: Stack_Guard if
# stack-overflow enabled, else Stack_Bottom
mov.l extern_c_label(Stack_Guard),%d1
btst &0,%d0
bne.b set_interrupt_enables_2
mov.l extern_c_label(Stack_Bottom),%d1
set_interrupt_enables_2:
mov.l %d1,regblock_stack_guard(regs)
mov.l (%sp)+,%d0
and.l rmask,%d0
mov.l %d0,%a0
jmp (%a0)
syntax highlighted by Code2HTML, v. 0.9.1