### -*-Midas-*-
###
### $Id: vax.m4,v 1.4 2000/12/05 21:23:50 cph Exp $
###
### Copyright (c) 1991-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.
###

#### Vax assembly language (BSD as Syntax) part of the compiled code
#### interface.  See cmpint.txt, cmpaux.txt, cmpint.c, cmpint-vax.h,
#### and cmpgc.h for more documentation.
####
#### NOTE:
####	Assumptions:
####
####	1) C uses CALLS and RET for linkage.
####
####	2) The C compiler divides registers into three groups:
####	- Linkage registers, used for procedure calls and global
####	references.  On Vax: ap, fp, sp, pc.
####	- Super temporaries, not preserved accross procedure calls and
####	always usable.  On the Vax this depends on the compiler:
####	GCC and BSD PCC use r0-r5 as super temporaries.
####	The (VMS) Vax C compiler uses r0-r1 as super temporaries.
####	- Preserved registers saved by the callee if they are written.
####	On the Vax: all others.
####
####	3) C procedures return long values in r0.
####	Two word structures are returned in different ways:
####	o GCC returns them in r0/r1.  Define flag GCC.
####	o PCC returns the address of the structure (in static storage)
####	in r0.  This is the default.
####	o (VMS) Vax C passes the address of the destination structure
####	as the first argument.  The other arguments are shifted right.
####
#### Compiled Scheme code uses the following register convention:
####	- sp (r14) contains the Scheme stack pointer, not the C stack
####	pointer.
####	- fp (r13) contains the dynamic link when needed.
####	- ap (r12) contains the Scheme free pointer.
####	- r11 contains the Scheme datum mask.
####	- r10 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.
####	- r9 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.
####
#### MAJOR NOTE: $ signifies immediate values to AS on the Vax.
#### However, M4 also uses $ to signify macro constants,
#### thus we use @ here to signify immediate values and a sed script
#### is run on the output of M4 to change them to $.

####	Utility macros and definitions

ifdef(`VMS', `', `ifdef(`GCC',`',`define(PCC,1)')')

ifdef(`VMS',
      `define(HEX,`^X$1')',
      `define(HEX,`0x$1')')


ifdef(`VMS',
      `define(ASMSET,
	      `
	$1=$2')',

      `define(ASMSET,
	      `
	.set $1,$2')')


ifdef(`VMS',
      `define(extern_c_variable,
	      `$1')',
      `define(extern_c_variable,
	      `_$1')')

define(extern_c_label,
       `extern_c_variable($1)')


ifdef(`VMS',
      `define(reference_c_variable,
	      `
	.save_psect
	.psect $1,pic,usr,ovr,rel,gbl,shr,noexe,rd,wrt,novec
$1:
	.restore_psect')',

      `define(reference_c_variable,
	      `')')


ifdef(`VMS',
      `define(define_c_label,
	      `
$1::')',

      `define(define_c_label,
	      `
	.globl	extern_c_label($1)
extern_c_label($1):')')


ifdef(`VMS',
      `define(define_c_procedure,
	      `
	.align	word
define_c_label($1)
	.word	^M<r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>')', # save r2-r11

      `define(define_c_procedure,
	      `
	.align	1
define_c_label($1)
	.word	0x0fc0')')		# save r6-r11

# This must match the compiler (machines/vax/machin.scm)

define(TC_LENGTH, ifdef(`TYPE_CODE_LENGTH', TYPE_CODE_LENGTH, 6))
define(ADDRESS_MASK, eval((0 - (2 ** (32 - TC_LENGTH))), 10))

define(rval,r9)
define(regs,r10)
define(rmask,r11)
define(rfree,ap)
define(dlink,fp)

ASMSET(regblock_val,8)
ASMSET(address_mask,ADDRESS_MASK)

reference_c_variable(Ext_Stack_Pointer)
reference_c_variable(Free)
reference_c_variable(Registers)
reference_c_variable(utility_table)

###
### Global data
###

ifdef(`VMS',
      `
	.psect	code,nowrt,exe,long
	.psect	data,wrt,noexe,quad

	.psect	data
	.align	long
c_save_stack:
	.long	0

	.psect	code',
      `
	.data
	.align	2
	.comm	c_save_stack,4

	.text')

### Callable by C conventions.  Swaps to Scheme register set and jumps
### to the entry point specified by its only argument.

define_c_procedure(C_to_interface)
	movl	4(ap),r1		# Argument: entry point
	subl2	@8,sp			# Allocate space for return struct.
	pushl	ap			# Save while in Scheme
	pushl	fp
	movl	@address_mask,rmask
	moval	extern_c_variable(Registers),regs

### The data in r1 is the address of an entry point to invoke.

define_c_label(interface_to_scheme)
					# Swap to C registers
	movl	sp,c_save_stack
	movl	extern_c_variable(Ext_Stack_Pointer),sp
	movl	extern_c_variable(Free),rfree
					# Scheme return value
	movl	regblock_val(regs),rval
	bicl3	rmask,rval,dlink
	jmp	(r1)			# invoke entry point

### The data in r1 is a return code to the interpreter

define_c_label(interface_to_C)
	movl	r1,r0			# C return location
	ret

### Called by Scheme through a jump instruction in the register block.
### It expects an index in r0, a return address on the stack, and 3
### longword arguments in r2-r4.
### The return address needs to be bumped over the format longword.

define_c_label(asm_scheme_to_interface_jsb)
	addl3	@4,(sp)+,r1
#	brb	asm_scheme_to_interface

### Transfer procedure from Scheme to C.
### Called by Scheme through a jump instruction in the register block.
### It expects an index in r0, and 4 longword arguments in r1-r4

define_c_label(asm_scheme_to_interface)
					# Swap to C registers
	movl	rval,regblock_val(regs)
	movl	rfree,extern_c_variable(Free)
	movl	sp,extern_c_variable(Ext_Stack_Pointer)
	movl	c_save_stack,sp
	movl	(sp),fp
	movl	4(sp),ap
					# extract the C utility
	moval	extern_c_variable(utility_table),r6
	movl	(r6)[r0],r6
					# push arguments to utility
	pushl	r4
	pushl	r3
	pushl	r2
	pushl	r1
					# call C procedure
	ifdef(`VMS',
	      `pushab	24(sp)
	       calls	@5,(r6)',
	      `calls	@4,(r6)')
					# return struct -> r0/r1
	ifdef(`VMS',
	      `movl	28(sp),r1
	       movl	24(sp),r0')
	ifdef(`PCC',
	      `movl	4(r0),r1
	       movl	(r0),r0')

	jmp	(r0)			# invoke return handler

### Called by Scheme trampolines through a jump instruction in the
### register block.
### It expects an index in r0, and a return address on the stack.
### The return address needs to be bumped over the padding in the
### trampoline.

define_c_label(asm_trampoline_to_interface)
	addl3	@2,(sp)+,r1
	brb	extern_c_label(asm_scheme_to_interface)

ifdef(`VMS',
      `.end',
      `')


syntax highlighted by Code2HTML, v. 0.9.1