/*	$NetBSD: macromasm.s,v 1.21 2007/03/04 06:00:08 christos Exp $	*/

/*-
 * Copyright (C) 1994	Bradley A. Grantham
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * Mac ROM Glue assembly
 */


#include "opt_adb.h"
#include "assym.h"
#include <machine/asm.h>
#include <machine/trap.h>


	/* Define this symbol as global with (v) value */
#define loglob(g, v)	\
	.global _C_LABEL(g) ;\
	.set	_C_LABEL(g), v

	/* Return from a pascal function; pop (pbytes) number of bytes */
	/*  passed as parameters.  Should have picked up "pascal" extension */
	/*  to GCC... */
#ifdef __STDC__
#define	IMMEDIATE	#
#define pascalret(pbytes)	\
	movl	%sp@+,%a1		/* get PC (I hate Pascal) */ ; \
	addl	IMMEDIATE pbytes,%sp	/* pop params (I hate Pascal) */ ; \
	jra	%a1@			/* return (I hate Pascal) */
#else
#define pascalret(pbytes)	\
	movl	%sp@+,%a1		/* get PC (I hate Pascal) */ ; \
	addl	#pbytes,%sp		/* pop params (I hate Pascal) */ ; \
	jra	%a1@			/* return (I hate Pascal) */
#endif


/*
 * MacOS low-memory global variables.
 */
	loglob(ADBBase, 0xcf8)		/* ptr to ADB driver variables */
	loglob(ADBYMM, 0xd18)		/* Yet more memory used by ADB/PM */
	loglob(ADBDelay, 0xcea) 	/* 8s of dbras per ADB delay */
	loglob(ROMBase, 0x2ae)		/* ptr to ROM Base */
	loglob(Lvl1DT, 0x192)		/* VIA 1 interrupt table */
	loglob(Lvl2DT, 0x1b2)		/* VIA 2 interrupt table? */
	loglob(JADBProc, 0x6b8) 	/* ADBReinit pre/post-processing */
	loglob(jADBOp, 0x5f0)		/* pointer to ADBOp */
	loglob(DeviceList, 0x8a8)	/* ptr to first device entry */
	loglob(KbdLast, 0x218)		/* ptr to first device entry */
	loglob(KbdType, 0x21E)		/* ptr to first device entry */
	loglob(JKybdTask, 0x21A)	/* keyboard task jump ptr? */
	loglob(Lo3Bytes, 0x31a) 	/* contains 0x00ffffff */
	loglob(MinusOne, 0xa06) 	/* contains 0xffffffff */
	loglob(MMU32Bit, 0xcb2) 	/* MMU mode (uh-oh) 1 = 32 bit? */
	loglob(CPUFlag, 0x12f)		/* CPU type */
	loglob(MacJmp, 0x120)		/* ?? */
	loglob(Scratch8, 0x9fa) 	/* 8-byte scratch area */
	loglob(Scratch20, 0x1e4)	/* 20-byte scratch area */
	loglob(Ticks, 0x16a)		/* ticks since system startup */
	loglob(Time, 0x20c)		/* Sec since midnight, 1-1-1904 */
	loglob(TimeDBRA, 0xd00) 	/* dbra's per millisecond (short) */
	loglob(ToolScratch, 0x9ce)	/* another 8-byte scratch area */
	loglob(VIA, 0x1d4)		/* VIA1 base address */
	loglob(mrg_VIA2, 0xcec) 	/* VIA2 base address */
	loglob(SCCRd, 0x1d8)		/* SCC read base address */
	loglob(FinderName, 0x2e0)	/* Name of finder */
	loglob(jSwapMMU, 0xdbc) 	/* ptr to MMU swap routine */
	loglob(ADBState, 0xde0) 	/* ptr to ADB state information? */
	loglob(jUnimplTrap, 0x61c)	/* ptr to UnimplTrap routine */
	loglob(jEgret, 0x648)		/* ptr to Egret trap routine */
	loglob(HwCfgFlags, 0xb22)	/* 2 bytes, h/w config flags */
	loglob(HwCfgFlags2, 0xdd0)	/* 4 bytes, more h/w config flags */
	loglob(HwCfgFlags3, 0xdd4)	/* 4 bytes, more h/w config flags */
	loglob(ADBReInit_JTBL, 0xdd8)	/* 4 bytes, pointer to patch table */
	loglob(jClkNoMem, 0x54c)	/* Pointer to ClkNoMem function */
	loglob(PramTransfer, 0x1e4)	/* Transfer buffer used with PRam */
	loglob(SysParam, 0x1f8) 	/* Place where PRam data gets stored */
	loglob(ExpandMem, 0x2b6)	/* pointer to Expanded Memory used by */
					/*   newer ADB routines */
	loglob(VBLQueue, 0x160)		/* Vertical blanking Queue, unused ? */
	loglob(VBLQueue_head, 0x162)	/* Vertical blanking Queue, head */
	loglob(VBLQueue_tail, 0x166)	/* Vertical blanking Queue, tail */
	loglob(jDTInstall, 0xd9c)	/* Deferred task mgr trap handler */

	loglob(InitEgretJTVec, 0x2010)	/* pointer to a jump table for */
					/* InitEgret on AV machines */

#if 0
	/* I wish I knew what these things were */
	loglob(MMUFlags, 0xcb0)
	loglob(MMUFluff, 0xcb3)
	loglob(MMUTbl, 0xcb4)
	loglob(MMUTblSize, 0xcb8)
	loglob(MMUType, 0xcb1)
#endif

	.text
	.even
	.global _C_LABEL(panic)
	.global _C_LABEL(printf)

#ifdef MRG_ADB
/*
 * These functions are defined in adb_direct.c if we are not using
 * the MRG method of accessing the ADB/PRAM/RTC.
 */
/*
 * Most of the following glue just takes C function calls, converts
 * the parameters to the MacOS Trap parameters, and then tries to
 * return the result correctly.  About the only thing our C functions
 * and MacOS' traps have in common is returning numerical results in
 * %d0.
 *
 * If some code actually pulls down the a-trap line, we jump right
 * to the ROMs; none of this is called. 
 */

/* Initialize Utils, mainly XPRam */
	/*
	 * void
	 */
ENTRY(InitUtil)
	.word 0xa03f
	rts


/* Initialize the ADB ------------------------------------------------------*/
	/*
	 * void
	 */
ENTRY(ADBReInit)
	.word	0xa07b
	rts


/* Set the ADB device info for a device; routine handler and so on ---------*/
	/*
	 * %sp@(4)	ADBSetInfoBlock *info
	 * %sp@(8)	int		adbAddr
	 */
ENTRY(SetADBInfo)
	movl	%sp@(4),%a0
	movl	%sp@(8),%d0
	.word	0xa07a
	rts


/* Find the number of ADB devices in the device table ----------------------*/
	/*
	 * void
	 */
ENTRY(CountADBs)
	.word 0xa077
	rts


/* Get ADB entry from index in table ---------------------------------------*/
	/*
	 * sp@(4)	ADBDataBlock	*info
	 * sp@(8)	u_short 	devTableIndex
	 */
ENTRY(GetIndADB)
	movl	%sp@(4),%a0
	movl	%sp@(8),%d0
	.word 0xa078
	rts


/* Get ADB device information ----------------------------------------------*/
	/*
	 * sp@(4)	ADBSetInfoBlock *info
	 * sp@(8)	int		adbAddr
	 */
ENTRY(GetADBInfo)
	movl	%sp@(4),%a0
	movl	%sp@(8),%d0
	.word 0xa079
	rts


/* Perform an ADB transaction ----------------------------------------------*/
	/*
	 * sp@(4)	Ptr	buffer
	 * sp@(8)	Ptr	compRout
	 * sp@(12)	Ptr	data
	 * sp@(16)	short	commandNum
	 */
ENTRY(ADBOp)
	lea	%sp@(4),%a0
	movl	%sp@(16),%d0
	.word 0xa07c
	rts
#endif /* MRG_ADB */


#if 0
/* My Own Trap (for testing.  returns 50.) ---------------------------------*/
	.global _MyOwnTrap
_MyOwnTrap:
	.word	0xa000
	rts


/* Known RTS (for testing) -------------------------------------------------*/
	.global _KnownRTS
_KnownRTS:
	.word	0xa001
	rts
#endif


/* Allocate memory ---------------------------------------------------------*/
ENTRY(NewPtr)
	/*
	 * int size
	 */
	movl	%sp@(4),%d0
	.word	0xa71e		/* clear and sys */
	rts


/* Free memory -------------------------------------------------------------*/
ENTRY(DisposPtr)
	/*
	 * Ptr ptr
	 */
	movl	%sp@(4),%a0
	.word	0xa01f
	rts


/* Get size of allocated memory --------------------------------------------*/
ENTRY(GetPtrSize)
	/*
	 * Ptr ptr
	 */
	movl	%sp@(4),%a0
	.word	0xa021
	rts


/* Extend allocated memory -------------------------------------------------*/
ENTRY(SetPtrSize)
	/*
	 * Ptr ptr
	 * int bytesdiff
	 */
	movl	%sp@(4),%a0
	movl	%sp@(8),%d0
	.word	0xa020
	rts


/* Resource manager */
	.data
GLOBAL(mrg_ResErr)
	.word	0

	.text
/* Return the current Resource Manager Error -------------------------------*/
ENTRY(ResError)
	/*
	 * void
	 */
	movl	%d2,%sp@-		| Toolbox trap may alter %d0-%d2,%a0,%a1
					| but C caller would save %d1,%a0,%a1
	clrw	%sp@-			| space for return arg (ugh)
	.word	0xa9af			| ResError
	movw	%sp@+,%d0
	movl	%sp@+,%d2		| restore %d2
	rts     

ENTRY(mrg_ResError)
	/*
	 * %sp@(4)	:short
	 */
#if defined(MRG_SHOWTRAPS)
		movml	#0xc0c0,%sp@-
		pea	LRE_enter
		jbsr	_C_LABEL(printf)
		addql	#4,%sp
		movml	%sp@+,#0x0303
#endif
	movw	_C_LABEL(mrg_ResErr),%sp@(4)
	| movw	%d0,%sp@(4)
	pascalret(0)

LRE_enter:
	.asciz	"mrg: ResError()\n"
	.even

/* Find a resource in open resource files ----------------------------------*/
ENTRY(GetResource)
	/*
	 * sp@(4)	u_int theType
	 * sp@(8)	short theID
	 */
	movl	%sp@(8),%a1
	movl	%sp@(4),%a0
	movl	%d2,%sp@-		| Toolbox trap may alter %d0-%d2,%a0,%a1
					| but C caller would save %d1,%a0,%a1
	clrl	%sp@-			| space for :Handle
	movl	%a0,%sp@-
	movw	%a1,%sp@-		| pascal parameters upside down
	.word	0xa9a0			| GetResource
	movl	%sp@+,%d0		| return Handle
	movl	%sp@+,%d2		| restore registers
	rts

ENTRY(mrg_GetResource)
	/*
	 * sp@(10)	:Handle
	 * sp@(6)	u_int	theType
	 * sp@(4)	short	theID
	 */
	/* For now, we return NIL, because, well, we have no resources. */
#if defined(MRG_SHOWTRAPS)
		movml	#0xc0c0,%sp@-
		movw	%sp@(20),%d0
		movl	%sp@(22),%d1
		movl	%d0,%sp@-
		movl	%d1,%sp@-
		pea	LGR_enter
		jbsr	_C_LABEL(printf)
		addl	#12,%sp
		movml	%sp@+,#0x0303
#endif
	clrl	%d0			| okay to change %d0 ?
	movl	%d0,%sp@(10)		| return value is NIL
	movl	#-192,%d0		| resNotFound; that's pretty accurate.
	movw	%d0,_C_LABEL(mrg_ResErr)| set current ResMan error
	pascalret(6)			| I hate Pascal.



ENTRY(mrg_CountResources)
/* Original from WRU: 960120
 * sp@(4)	u_int32_t  rsrc_type
 * sp@(8)	u_int16_t  nr_of_rsrcs
 */
	movl 	%sp@(4),%d0
  	movl	%d0,%sp@-
	jbsr	_C_LABEL(Count_Resources)
	addl	#4,%sp			| pop C params
	movw	%d0,%sp@(8)		| store result
	pascalret(4)

ENTRY(mrg_GetIndResource)
/* Original from WRU: 960120
 * sp@(4)	u_int16_t  rsrc_index
 * sp@(6)	u_int32_t  rsrc_type
 * sp@(10)	void *  *rsrc_handle
 */
	movl	%sp@(6),%a0
	clrl	%d0
	movw	%sp@(4),%d0
  	movl	%d0,%sp@-
	movl	%a0,%sp@-
	jbsr	_C_LABEL(Get_Ind_Resource)
	addl	#8,%sp		| pop C params
	movl	%d0,%sp@(10)	| store result
	pascalret(6)

/*
 * I'd like to take a moment here to talk about the calling convention
 * for ToolBox routines.  Inside Mac "Operating System Utilities,"
 * page 8-16, "About the Trap Manager," states that ToolBox routines
 * may alter %D0-%D2 and %A0-%A1.  However, a crucial bit of code in
 * ADBReInit on the Mac II, 0x40807834, does not save its own %D1 or %A1
 * before calling GetResource.	Therefore, it is imperative that our
 * MacBSD ToolBox trap handler save at least %D1, %D2, %A0, and %A1.  I
 * believe that the system uses %D0 in most places to hold the function's
 * return value, as in "movl	%sp@+,%d0", and so I don't think it's
 * that necessary to save %d0 unless we find a specific case of ugliness.
 *
 * It surprises me during every moment that I deal with the Macintosh
 * architecture how wonderful and ugly it really is.  I continue to find
 * pieces of beautiful, elegant code, reduced to crap by another following
 * piece of code which uses global offsets, doesn't save registers, and
 * makes assumptions.  If only it was consistent, Mac ROMs would be a
 * true example to programmers everywhere.  As it stands, it is an example
 * of a different kind. 	-Brad Grantham, September 5th, 1994
 */

LGR_enter:
	.asciz	"GetResource('0x%x', %d)\n"
	.even


/*
 * 1010 line emulator; A-line trap
 * (we fake MacOS traps from here)
 */
	.global _C_LABEL(mrg_aline_super)
	.global _C_LABEL(mrg_ToolBoxtraps)
ENTRY_NOPROFILE(alinetrap)
	clrl	%sp@-		| pad %SR to longword (I still don't know
				| why we do this.)
	moveml	#0xffff,%sp@-	| save registers
	movl	%sp,%sp@-	| save pointer to frame
	movw	%sp@(FR_HW + 4),%d0	| retrieve status register
	andw	#PSL_S,%d0	| supervisor state?
	bne	Lalnosup	| branch if supervisor
	addql	#4,%sp		| pop frame ptr
	movql	#T_ILLINST,%d0	| user-mode fault
	jra	_ASM_LABEL(fault)
Lalnosup:
#define FR_PC (FR_HW+2)
	movl	%sp@(FR_PC + 4),%a0	| retrieve PC
	movw	%a0@,%d0 	| retrieve trap word
	btst	#11,%d0 	| ToolBox trap?
	bne	Laltoolbox	| branch if ToolBox
	jbsr	_C_LABEL(mrg_aline_super) | supervisor a-line trap
Lalrts:
	addql	#4,%sp		| pop frame ptr
	movw	%sp@(FR_HW),%sr	| restore status register (I hate MacOS traps)
	movl	%sp@(FR_PC),%a0	| move PC to correct location
	movl	%a0,%sp@(FR_PC+2)
	moveml	%sp@+,#0xffff	| restore registers (some of which may have
				| been magically changed)
	addql	#8,%sp		| pop alignment long, make stack look like
				| ordinary jbsr
	tstw	%d0		| Gotta do this because call might depend on it
	rts			| Go home (God, this is ugly.)
Laltoolbox:
	addql	#4,%sp		| pop frame ptr
#if defined(MRG_DEBUG)
		movml	#0xC0C0,%sp@-	| better save
		pea	LalP1	        
		jbsr	_C_LABEL(printf)
			| printf ("Toolbox trap\n"); 
		lea	%sp@(4),%sp	| pop
		movml	%sp@+,#0x0303	| restore
#endif
	movl	%a0,%a1		| save PC
	movw	%sp@(FR_HW),%sr	| restore status register
#if defined(MRG_DEBUG)
		movml	#0xC0C0,%sp@-	| better save
		movw	%sr,%sp@-
		clrw	%sp@-		| coerce to int
		pea	LalP2
		jbsr	_C_LABEL(printf)
			| printf ("Status register 0x%x\n", sr);
		lea	%sp@(8),%sp	| pop
		movml	%sp@+,#0x0303	| restore
#endif
	btst	#10,%d0 	| auto-pop the jump address?
	beq	Lalnoauto	| branch if no auto-pop
	pea	Lalautopanic	| I really don't know how to handle this
	jbsr	_C_LABEL(panic)
Lalnoauto:
	addl	#2,%a1		| add 2 to PC
#if defined(MRG_DEBUG)
		movml	#0xC0C0,%sp@-	| better save
		movl	%a1,%sp@-
		pea	LalP4
		jbsr	_C_LABEL(printf)
			| printf ("return address is 0x%x\n", new pc);
		lea	%sp@(8),%sp	| pop
		movml	%sp@+,#0x0303	| restore
#endif
	movl	%a1,%sp@(FR_PC+2)	| push new return address
	movl	%d0,%d1		| just in case of panic
	andl	#0x3ff,%d0	| %d0 = trap number
#if defined(MRG_DEBUG)
		movml	#0xC0C0,%sp@-	| better save
		movl	%d0,%sp@-
		pea	LalP5
		jbsr	_C_LABEL(printf)
			| printf ("trap number is 0x%x\n", trapnum);
		lea	%sp@(8),%sp	| pop
		movml	%sp@+,#0x0303	| restore
#endif
	lsll	#2,%d0		| ptr = 4 bytes
	lea	_C_LABEL(mrg_ToolBoxtraps),%a0
	addl	%d0,%a0		| get trap address
	movl	%a0@,%a0
	bne	Laltbok 	| branch on trap addr non-zero
	movl	%d1,%sp@+	| trap word
	pea	Laltbnotrap
	jbsr	_C_LABEL(printf)
	pea	Laltbnogo
	jbsr	_C_LABEL(panic)
Laltbok:
#if defined(MRG_DEBUG)
		movml	#0xC0C0,%sp@-	| better save
		movl	%a0,%sp@-
		pea	LalP6
		jbsr	_C_LABEL(printf)
			| printf ("trap address is 0x%x\n", trapaddr);
		lea	%sp@(8),%sp	| pop
		movml	%sp@+,#0x0303	| restore
#endif
	movl	%a0,%sp@(FR_HW)	| we will RTS to trap routine (ick)
	moveml	%sp@+,#0xffff	| restore registers
	addql	#4,%sp		| pop alignment long
	rts			| go for it

Lalautopanic:
	.asciz	"mrg: A-line ToolBox trap wanted auto-pop; I don't know how"
Laltbnotrap:
	.asciz	"mrg: Don't know how to handle this trap: 0x%x\n"
Laltbnogo:
	.asciz	"mrg: can't go on"
LalP1:
	.asciz	"mrg: TB!"
LalP2:
	.asciz	" sr 0x%x"
LalP4:
	.asciz	" ret 0x%x"
LalP5:
	.asciz	" #%d"
LalP6:
	.asciz	" addr 0x%x\n"
	.even


	.data

GLOBAL(traceloopstart)
	.space	20 * 4		| save last 20 program counters on trace trap
GLOBAL(traceloopend)
GLOBAL(traceloopptr)
	.long	_C_LABEL(traceloopstart)

	.text
ENTRY_NOPROFILE(mrg_tracetrap)
	movl	%d0,%sp@-		| save %d0
	movl	%a0,%sp@-		| save %a0
	movl	%sp@(0x10),%d0		| address of instruction
		|%sp@	 old %a0
		|%sp@(4) old %d0
		|%sp@(8) old %sr
		|%sp@(10) old %PC
		|%sp@(14) exception vector
		|%sp@(16) address of instruction
#if defined(MRG_FOLLOW)
		movml	#0xc0c0,%sp@-
		movl	%d0,%sp@-
		pea	Ltraceprint
		jbsr	_C_LABEL(printf) | printf("PC is %x\n", pc);
		addql	#8,%sp
		movml	%sp@+,#0x0303
		tstl	%d0
#endif
	beq	LPCiszero		| if PC goes to zero, freak!
	movl	_C_LABEL(traceloopptr),%a0	| ptr = traceloopptr;
	movl	%d0,%a0@+		| *ptr++ = PC;
	cmpl	#_C_LABEL(traceloopend),%a0	| if(ptr == traceloopend)
	bne	Lnotpast		|  {
	movl	#_C_LABEL(traceloopstart),%a0	|   ptr = traceloopstart;
Lnotpast:				|  }
	movl	%a0,_C_LABEL(traceloopptr)	| traceloopptr = ptr;
	movl	%sp@+,%a0		| restore %a0
	movl	%sp@+,%d0		| restore %d0
	rte				| everything cool, return.
LPCiszero:
	movl	%sp@+,%a0		| restore %a0
	movl	%sp@+,%d0		| restore %d0
	movml	#0xc0c0,%sp@-
	pea	LtracePCzero
	jbsr	_C_LABEL(panic)		| panic("PC is zero!", pc);
	addql	#4,%sp
	movml	%sp@+,#0x0303

Ltraceprint:
	.asciz	"tracing, pc at 0x%08x\n"
LtracePCzero:
	.asciz	"PC went to zero!\n"
	.even
