#ifndef lint
static char rcsid[] = "$Header: /slow/cvs_repository/clu/PCLU/code/gc/sony-news-1850/mach_dep.c,v 1.1.1.1 1991/09/18 16:20:40 howard Exp $";
#endif
/* $Log: mach_dep.c,v $
 * Revision 1.1.1.1  1991/09/18  16:20:40  howard
 * PCLU system from MIT
 *
 * Revision 1.1  1991/09/18  16:20:39  howard
 * Initial revision
 *
 * Revision 1.2  91/05/06  12:25:49  dcurtis
 * *** empty log message ***
 * 
 * Revision 1.1  91/02/04  16:21:29  mtv
 * Initial revision
 * 
 */

# include "gc.h"
# include <setjmp.h>


/* If no assembly calls are anticipated, it is only necessary to port     */
/* the mark_regs routine near the end of the file to your machine.        */
/* The allocobj and allocaobj routines are designed only as an assembly   */
/* language interface.  The definitions of objfreelist and aobjfreelist   */
/* are useful only if in-line allocation code is generated.               */

/* Definitions similar to the following make it easier to access the free */
/* lists from an assembly lnguage, or in-line C interface.                */
/* They should be added for other architectures.                          */


struct __gc_arrays _gc_arrays = { 0 }; 
	/* The purpose of the initialization is to force _gc_arrays */
	/* into the data segment.  The Fortran-based object file    */
	/* format used by many versions of UNIX otherwise makes the */
	/* following impossible.  (Note that some assemblers and    */
	/* linkers, notably those for Sun-3s, don't realize that    */
	/* this is impossible, and simply generate garbage.)        */

# ifdef M68K_NEWS
    asm(".globl _aobjfreelist");
    asm(".globl _objfreelist");
    asm("_aobjfreelist = __gc_arrays");
    asm("_objfreelist = __gc_arrays+0x804");
# endif
# ifdef M68K_SUN
    asm(".globl _aobjfreelist");
    asm(".globl _objfreelist");
    asm("_aobjfreelist = __gc_arrays");
    asm("_objfreelist = __gc_arrays+0x804");
# endif
# ifdef SPARC
    asm(".global _aobjfreelist");
    asm(".global _objfreelist");
    asm("_aobjfreelist = _gc_arrays");
    asm("_objfreelist = _gc_arrays+0x804");
# endif
# ifdef VAX
    asm(".globl _aobjfreelist");
    asm(".globl _objfreelist");
    asm(".set _aobjfreelist,__gc_arrays");
    asm(".set _objfreelist,__gc_arrays+0x804");
# endif
# ifdef RT
    asm(".globl _aobjfreelist");
    asm(".globl _objfreelist");
    asm(".set _aobjfreelist,__gc_arrays");
    asm(".set _objfreelist,__gc_arrays+0x804");
# endif

/* Call allocobj or allocaobj after first saving at least those registers */
/* not preserved by the C compiler. The register used for return values   */
/* is not saved, since it will be clobbered anyway.                       */
# ifdef RT
    /* This is done in rt_allocobj.s */
# else
#   ifdef M68K_HP
    /* Optimizer is not safe, we want these suckers stored. */
/* #   pragma OPTIMIZE OFF - we claim this is unnecessary if -O flag */
/*                           is not used.  It breaks the collector   */
/*                           on other machines.                      */
    asm("    text");		/* HP/Motorola assembler syntax */
    asm("    global  __allocobj");
    asm("    global  __allocaobj");
    asm("    global  _allocobj");
    asm("    global  _allocaobj");
/* The following clause was removed for HP_PA version
#   else
    asm("    .text");		/ * Default (PDP-11 Unix syntax) * /
    asm("	.globl  __allocobj");
    asm("	.globl  __allocaobj");
    asm("	.globl  _allocobj");
    asm("	.globl  _allocaobj");
*/
#   endif

# ifdef M68K_NEWS
    asm("_allocobj:");
    asm("   link    a6,#0");
    asm("	movl    d1,sp@-");
    asm("	movl    a0,sp@-");
    asm("	movl    a1,sp@-");
    asm("	movl    sp@(20),sp@-");
    asm("	jbsr    __allocobj");
    asm("	addl    #4,sp");
    asm("	movl    sp@+,a1");
    asm("	movl    sp@+,a0");
    asm("	movl    sp@+,d1");
    asm("	unlk    a6");
    asm("	rts");
    
    asm("_allocaobj:");
    asm("	link    a6,#0");
    asm("	movl    d1,sp@-");
    asm("	movl    a0,sp@-");
    asm("	movl    a1,sp@-");
    asm("	movl    sp@(20),sp@-");
    asm("	jbsr    __allocaobj");
    asm("	addl    #4,sp");
    asm("	movl    sp@+,a1");
    asm("	movl    sp@+,a0");
    asm("	movl    sp@+,d1");
    asm("	unlk    a6");
    asm("	rts");
# endif

# ifdef M68K_SUN
    asm("_allocobj:");
    asm("   link    a6,#0");
    asm("	movl    d1,sp@-");
    asm("	movl    a0,sp@-");
    asm("	movl    a1,sp@-");
    asm("	movl    sp@(20),sp@-");
    asm("	jbsr    __allocobj");
    asm("	addl    #4,sp");
    asm("	movl    sp@+,a1");
    asm("	movl    sp@+,a0");
    asm("	movl    sp@+,d1");
    asm("	unlk    a6");
    asm("	rts");
    
    asm("_allocaobj:");
    asm("	link    a6,#0");
    asm("	movl    d1,sp@-");
    asm("	movl    a0,sp@-");
    asm("	movl    a1,sp@-");
    asm("	movl    sp@(20),sp@-");
    asm("	jbsr    __allocaobj");
    asm("	addl    #4,sp");
    asm("	movl    sp@+,a1");
    asm("	movl    sp@+,a0");
    asm("	movl    sp@+,d1");
    asm("	unlk    a6");
    asm("	rts");
# endif

# ifdef M68K_HP
    asm("_allocobj:");
    asm("	link     %a6,&0");
    asm("	mov.l    %d1,-(%sp)");
    asm("	mov.l    %a0,-(%sp)");
    asm("	mov.l    %a1,-(%sp)");
    asm("	mov.l    20(%sp),-(%sp)");
    asm("	jsr      __allocobj");
    asm("	add.l    &4,%sp");
    asm("	mov.l    (%sp)+,%a1");
    asm("	mov.l    (%sp)+,%a0");
    asm("	mov.l    (%sp)+,%d1");
    asm("	unlk     %a6");
    asm("	rts");
    
    asm("_allocaobj:");
    asm("	link     %a6,&0");
    asm("	mov.l    %d1,-(%sp)");
    asm("	mov.l    %a0,-(%sp)");
    asm("	mov.l    %a1,-(%sp)");
    asm("	mov.l    20(%sp),-(%sp)");
    asm("	jsr      __allocaobj");
    asm("	add.l    &4,%sp");
    asm("	mov.l    (%sp)+,%a1");
    asm("	mov.l    (%sp)+,%a0");
    asm("	mov.l    (%sp)+,%d1");
    asm("	unlk     %a6");
    asm("	rts");
# endif

# ifdef I386
    asm(".data");
    asm("gc_ret_value: .word 0");
    asm(".word 0");
    asm(".text");

    asm("_allocaobj:");
    asm("pushl %ebp");
    asm("movl %esp,%ebp");
    asm("pushal");
    asm("pushl 8(%ebp)");          /* Push orignal argument */
    asm("call __allocaobj");
    asm("popl %ecx");
    asm("movl %eax,gc_ret_value");  /* Save return value */
    asm("popal");
    asm("movl gc_ret_value,%eax");
    asm("leave");
    asm("ret");

    asm("_allocobj:");
    asm("pushl %ebp");
    asm("movl %esp,%ebp");
    asm("pushal");
    asm("pushl 8(%ebp)");          /* Push orignal argument */
    asm("call __allocobj");
    asm("popl %ecx");
    asm("movl %eax,gc_ret_value");  /* Save return value */
    asm("popal");
    asm("movl gc_ret_value,%eax");
    asm("leave");
    asm("ret");
# endif

# ifdef SPARC
    asm(".global _allocaobj");
    asm("_allocaobj:");
    asm("	ba	allocaobj");
    asm("	nop");
    asm(".global _allocobj");
    asm("_allocobj:");
    asm("	ba	allocobj");
    asm("	nop");
    
#   include <sys/trap.h>
    asm("	.globl	save_regs_in_stack");
    asm("save_regs_in_stack:");
    asm("	t	0x3   ! ST_FLUSH_WINDOWS");
    asm("	mov	%sp,%o0");
    asm("	retl");
    asm("	nop");
# endif

# ifdef VAX
    asm("_allocobj:");
    asm(".word    0x3e");
    asm("pushl   4(ap)");
    asm("calls   $1,__allocobj");
    asm("ret");
    asm("_allocaobj:");
    asm(".word   0x3e");
    asm("pushl   4(ap)");
    asm("calls   $1,__allocaobj");
    asm("ret");
# endif

# ifdef NS32K
    asm("_allocobj:");
    asm("enter [],$0");
    asm("movd r1,tos");
    asm("movd r2,tos");
    asm("movd 8(fp),tos");
    asm("bsr ?__allocobj");
    asm("adjspb $-4");
    asm("movd tos,r2");
    asm("movd tos,r1");
    asm("exit []");
    asm("ret $0");
    asm("_allocaobj:");
    asm("enter [],$0");
    asm("movd r1,tos");
    asm("movd r2,tos");
    asm("movd 8(fp),tos");
    asm("bsr ?__allocaobj");
    asm("adjspb $-4");
    asm("movd tos,r2");
    asm("movd tos,r1");
    asm("exit []");
    asm("ret $0");
# endif


# if !defined(VAX) && !defined(M68K_SUN) && !defined(M68K_HP)&& !defined(SPARC) && !defined(I386) && !defined(NS32K) && !defined(M68K_NEWS)
    /* Assembly language interface routines undefined */
# endif

# endif

/* Routine to mark from registers that are preserved by the C compiler. */
/* This must be ported to every new architecture.  There is a generic   */
/* version at the end, that is likely, but not guaranteed to work       */
/* on your architecture.  Run the test_setjmp program to see whether    */
/* there is any chance it will work.                                    */
mark_regs()
{
#       ifdef RT
	  register long TMP_SP; /* must be bound to r11 */
#       endif
#       ifdef VAX
	/* VAX - generic code below does not work under 4.2 */
	  /* r1 through r5 are caller save, and therefore     */
	  /* on the stack or dead.                            */
	  asm("pushl r11");     asm("calls $1,_tl_mark");
	  asm("pushl r10"); 	asm("calls $1,_tl_mark");
	  asm("pushl r9");	asm("calls $1,_tl_mark");
	  asm("pushl r8");	asm("calls $1,_tl_mark");
	  asm("pushl r7");	asm("calls $1,_tl_mark");
	  asm("pushl r6");	asm("calls $1,_tl_mark");
#       endif
#       ifdef M68K_NEWS
	/*  M68K_NEWS - could be replaced by generic code */
	  /* a0, a1 and d1 are caller save          */
	  /*  and therefore are on stack or dead.   */
	
	  asm("subqw #0x4,sp");		/* allocate word on top of stack */

	  asm("movl a2,sp@");	asm("jbsr _tl_mark");
	  asm("movl a3,sp@");	asm("jbsr _tl_mark");
	  asm("movl a4,sp@");	asm("jbsr _tl_mark");
	  asm("movl a5,sp@");	asm("jbsr _tl_mark");
	  /* Skip frame pointer and stack pointer */
	  asm("movl d1,sp@");	asm("jbsr _tl_mark");
	  asm("movl d2,sp@");	asm("jbsr _tl_mark");
	  asm("movl d3,sp@");	asm("jbsr _tl_mark");
	  asm("movl d4,sp@");	asm("jbsr _tl_mark");
	  asm("movl d5,sp@");	asm("jbsr _tl_mark");
	  asm("movl d6,sp@");	asm("jbsr _tl_mark");
	  asm("movl d7,sp@");	asm("jbsr _tl_mark");

	  asm("addqw #0x4,sp");		/* put stack back where it was	*/
#       endif

#       ifdef M68K_SUN
	/*  M68K_SUN - could be replaced by generic code */
	  /* a0, a1 and d1 are caller save          */
	  /*  and therefore are on stack or dead.   */
	
	  asm("subqw #0x4,sp");		/* allocate word on top of stack */

	  asm("movl a2,sp@");	asm("jbsr _tl_mark");
	  asm("movl a3,sp@");	asm("jbsr _tl_mark");
	  asm("movl a4,sp@");	asm("jbsr _tl_mark");
	  asm("movl a5,sp@");	asm("jbsr _tl_mark");
	  /* Skip frame pointer and stack pointer */
	  asm("movl d1,sp@");	asm("jbsr _tl_mark");
	  asm("movl d2,sp@");	asm("jbsr _tl_mark");
	  asm("movl d3,sp@");	asm("jbsr _tl_mark");
	  asm("movl d4,sp@");	asm("jbsr _tl_mark");
	  asm("movl d5,sp@");	asm("jbsr _tl_mark");
	  asm("movl d6,sp@");	asm("jbsr _tl_mark");
	  asm("movl d7,sp@");	asm("jbsr _tl_mark");

	  asm("addqw #0x4,sp");		/* put stack back where it was	*/
#       endif

#       ifdef M68K_HP
	/*  M68K_HP - could be replaced by generic code */
	  /* a0, a1 and d1 are caller save.  */
	
	  asm("subq.w &0x4,%sp");	/* allocate word on top of stack */

	  asm("mov.l %a2,(%sp)"); asm("jsr _tl_mark");
	  asm("mov.l %a3,(%sp)"); asm("jsr _tl_mark");
	  asm("mov.l %a4,(%sp)"); asm("jsr _tl_mark");
	  asm("mov.l %a5,(%sp)"); asm("jsr _tl_mark");
	  /* Skip frame pointer and stack pointer */
	  asm("mov.l %d1,(%sp)"); asm("jsr _tl_mark");
	  asm("mov.l %d2,(%sp)"); asm("jsr _tl_mark");
	  asm("mov.l %d3,(%sp)"); asm("jsr _tl_mark");
	  asm("mov.l %d4,(%sp)"); asm("jsr _tl_mark");
	  asm("mov.l %d5,(%sp)"); asm("jsr _tl_mark");
	  asm("mov.l %d6,(%sp)"); asm("jsr _tl_mark");
	  asm("mov.l %d7,(%sp)"); asm("jsr _tl_mark");

	  asm("addq.w &0x4,%sp");	/* put stack back where it was	*/
#       endif

#       ifdef I386
	/* I386 code, generic code does not appear to work */
	  asm("pushl %eax");  asm("call _tl_mark"); asm("addl $4,%esp");
	  asm("pushl %ecx");  asm("call _tl_mark"); asm("addl $4,%esp");
	  asm("pushl %edx");  asm("call _tl_mark"); asm("addl $4,%esp");
	  asm("pushl %esi");  asm("call _tl_mark"); asm("addl $4,%esp");
	  asm("pushl %edi");  asm("call _tl_mark"); asm("addl $4,%esp");
	  asm("pushl %ebx");  asm("call _tl_mark"); asm("addl $4,%esp");
#       endif

#       ifdef NS32K
	  asm ("movd r3, tos"); asm ("bsr ?_tl_mark"); asm ("adjspb $-4");
	  asm ("movd r4, tos"); asm ("bsr ?_tl_mark"); asm ("adjspb $-4");
	  asm ("movd r5, tos"); asm ("bsr ?_tl_mark"); asm ("adjspb $-4");
	  asm ("movd r6, tos"); asm ("bsr ?_tl_mark"); asm ("adjspb $-4");
	  asm ("movd r7, tos"); asm ("bsr ?_tl_mark"); asm ("adjspb $-4");
#       endif

#       ifdef SPARC
	  /* generic code will not work */
	  save_regs_in_stack();
#       endif

#	ifdef RT
	    tl_mark(TMP_SP);    /* tl_mark from r11 */

	    asm("cas r11, r6, r0"); tl_mark(TMP_SP);	/* r6 */
	    asm("cas r11, r7, r0"); tl_mark(TMP_SP);	/* through */
	    asm("cas r11, r8, r0"); tl_mark(TMP_SP);	/* r10 */
	    asm("cas r11, r9, r0"); tl_mark(TMP_SP);
	    asm("cas r11, r10, r0"); tl_mark(TMP_SP);

	    asm("cas r11, r12, r0"); tl_mark(TMP_SP); /* r12 */
	    asm("cas r11, r13, r0"); tl_mark(TMP_SP); /* through */
	    asm("cas r11, r14, r0"); tl_mark(TMP_SP); /* r15 */
	    asm("cas r11, r15, r0"); tl_mark(TMP_SP);
#       endif

#     if defined(HP_PA)
	/* Generic code                          */
	/* The idea is due to Parag Patel at HP. */
	/* We're not sure whether he would like  */
	/* to be he acknowledged for it or not.  */
	{
	    jmp_buf regs;
	    register word * i = (word *) regs;
	    register word * lim = (word *) (((char *)(regs)) + (sizeof regs));

	    /* Setjmp on Sun 3s doesn't clear all of the buffer.  */
	    /* That tends to preserve garbage.  Clear it.         */
		for (; i < lim; i++) {
		    *i = 0;
		}
	    (void) _setjmp(regs);
	    tl_mark_all(regs, lim);
	}
#     endif

      /* other machines... */
#       if !(defined M68K_SUN) && !defined(M68K_HP) && !(defined VAX) && !(defined RT) && !(defined SPARC) && !(defined I386) &&!(defined NS32K) && !defined(M68K_NEWS) && !(defined HP_PA)
	    --> bad news <--
#       endif
}
