/* montrap.S -- RAM-Monitor initialization and trap handling
 * copyright (c) 1984  American Information Systems Corporation
 *	Daniel Steinberg
 *	November, 1984
 *
 *	AIS/UNIX-System V.2  code format
 *
 *	Trap dispatching for AIS/RAM-Monitor.
 */
	.file	"montrap.S"
	
#include "promhdr.h"
#include "3200config.h"
#include "vmdispatch.h"
#include "cflags.h"
#include "RAMmonaddr.m"

.set	LF,0x0A

	.text


/* mon_init() -- Initialize the RAM-Monitor
 *	return:	r0	address of RAM-Monitor intbase
 */
	.globl	_mon_init
_mon_init:

	/* push fake psr, mod, and pc for RAM-Monitor initialization */

	sprw	psr,tos			/* set a fake psr */
	sprw	mod,tos			/* set current module */
	addr	initdone,tos		/* return to this address */
	addr	@MON_INIT,tos		/* id for initial entry */
	br	realtrap		/* enter the RAM-Monitor */

initdone:
	ret	$0			/* initialization done */

	.globl	_mon_start
_mon_start:
	movd	0(sp),tos		/* re-push return address */
	sprw	psr,6(sp)		/* convert 'jsr' into trap */
	sprw	mod,4(sp)		/* psr & mod on stack above ret addr */
	bicpsrw	$PSR_I			/* disable interrupts */
	addr	@MON_START,tos		/* set trapless entry code */
					/* and fall thru to realtrap */

/*  */

/* Traps always switch to the debugger stack with no address translation.
 * The following code processes traps as follows:
 *	0) (interrupt entry disables interrupts and pushes the trap id)
 *	1) save a few working registers (enter [r0,r1,r2],4)
 *	2) disable user address translation (to get to physical memory)
 *	3) get the pointer to the Monitor stack and adjust for saved info
 *	4) using movsud (move supervisor to user), copy saved registers
 *	   and trap information to the Monitor stack
 *	5) restore old user translation state and disable kernel translation
 *	6) save the old stack pointer on the Monitor stack
 *	7) switch the sp to the Monitor stack
 *	8) save the intbase on the stack
 *	9) save the rest of the registers, copy fp and id from saved locations
 *	10)save the original msr, and all mmu and fpu registers on the stack
 *	11)push the pointer to the saved environment and call the debugger
 *	12)on return, reset all breakpoints, restore most of the saved
 *	   environment (old sp included), disable user address translation
 *	   and enable supervisor translation and copy relevant information
 *	   back to the original stack (saved regs, pc, psr, etc.) using
 *	   movusd (move user to supervisor)
 *	13)restore saved registers and return from trap
 *
 * The stacks at 'saverest' & 'restorerest' are as follows:
 *
 *	Target task stack		Monitor stack (currently selected)
 *				40(sp)	saved fp (copied down later)
 *				36(sp)	trap id (replaced by processing state)
 *	(...stack...)		32(sp)	saved sp (points to r2 on old stack)
 * 28()	psr // mod at trap	28(sp)	saved MMU msr at trap
 * 24()	pc at trap		24(sp)	psr // mod at trap
 * 20()	(trap id)		20(sp)	pc at trap
 * 16()	saved fp		16(sp)	sp at trap
 * 12()	(saved msr)		12(sp)	intbase at trap
 *  8()	saved r0		 8(sp)	r0 at trap
 *  4()	saved r1		 4(sp)	r1 at trap
 *  0()	saved r2		 0(sp)	r2 at trap
 */

realtrap:				/* trap id already pushed on stack */
	enter	[r0,r1,r2],$4		/* get some working registers */

#ifdef MMU /********************** MMU Available ***********************/
	smr	msr,r2			/* save current mapping state */
	movd	r2,12(sp)		/* save msr on interrupt stack */
	bicd	$(MSR_FT | MSR_NT | MSR_BEN),r2	/* turn off tracing */
	movd	r2,r1			/* copy msr */
	bicd	$MSR_TS,r2		/* turn off supervisor translation */
	lmr	msr,r2
#endif /************************** MMU Available ***********************/

	/* Disable PICK byte-swapping */
	movb	$PICK_ENABLE,@(UART_PARENABLE + U_CLROUT)

#ifdef MMU /********************** MMU Available ***********************/
	bicd	$MSR_TU,r1		/* turn off user translation */
	lmr	msr,r1
#endif /************************** MMU Available ***********************/

	addr	@A_mondispatch,r0	/* get addr of RAM-Monitor disp table */
	cmpd	@A_state,r0		/* already in monitor? */
	beq	recursive_trap		/* yes....error */

	addr	@A_monstack,r1		/* get saved Monitor stack pointer */
copystack:
	subd	$44,r1			/* adjust for the crap that goes on */
	movsud	0(sp),0(r1)		/* copy saved r2 */
	movsud	4(sp),4(r1)		/* copy saved r1 */
	movsud	8(sp),8(r1)		/* copy saved r0 */
	movsud	12(sp),28(r1)		/* copy msr at trap */
	movsud	16(sp),40(r1)		/* copy saved fp */
	movsud	20(sp),36(r1)		/* copy trap id */
	movsud	24(sp),20(r1)		/* copy pc at trap */
	movsud	28(sp),24(r1)		/* copy trap psr/mod */

#ifdef MMU /********************** MMU Available ***********************/
	lmr	msr,r2			/* and reset user translation bit */
#endif /************************** MMU Available ***********************/

	sprd	sp,32(r1)		/* save interrupt stack pointer */
	sprd	sp,16(r1)		/* & set sp at trap by adjusting for */
	addd	$32,16(r1)		/* saved registers and trap addr */
	lprd	sp,r1			/* set stack pointer in VIOS space */
	sprd	intbase,12(r1)		/* save interrupt intbase */

saverest:
	save	[r3,r4,r5,r6,r7]	/* save registers */
	movzwd	24(r1),r2		/* get old mod register value */
	movd	MOD_SB(r2),tos		/* save static base on stack */
	movd	40(r1),tos		/* copy saved frame pointer */

	bispsrw $PSR_S			/* select usr stack */
	sprd	sp,r2			/* get usr stack (usp) */
	bicpsrw $PSR_S			/* select Monitor stack */
	movd	r2,tos			/* store usp on interrupt stack */
	movd	36(r1),tos		/* copy saved trap id */
	movd	@A_state,36(r1)		/* save interrupted processing state */
	movd	r0,@A_state		/* set processing state */

readmmu:
#ifdef MMU /********************** MMU Available ***********************/
	smr	ptb0,tos	/* read in the mmu registers */
	smr	ptb1,tos
	smr	eia,tos
	smr	bcnt,tos
	smr	bpr0,tos
	smr	bpr1,tos
	smr	sc,tos
	smr	pf0,tos
	smr	pf1,tos
#else  /************************** MMU Available ***********************/
	adjspb	$(9*4)		/* skip space for mmu registers */
#endif /************************** MMU Available ***********************/

readfpu:
#ifdef FPU /********************** FPU Available ***********************/
	sfsr	tos		/* read in the fpu registers */
	movf	f0,tos
	movf	f1,tos
	movf	f2,tos
	movf	f3,tos
	movf	f4,tos
	movf	f5,tos
	movf	f6,tos
	movf	f7,tos
#else  /************************** FPU Available ***********************/
	adjspb	$(9*4)		/* skip space for fpu registers */
#endif /************************** FPU Available ***********************/

	addr	tos,tos			/* push pointer to environment */
	jsr	_rammonitor		/* Start RAM-Monitor */

dbret:
	jsr	_exec_init		/* set breakpoints */

	adjspb	$-4			/* pop env */

restorefpu:
#ifdef FPU /********************** FPU Available ***********************/
	movf	tos,f7		/* restore fpu registers */
	movf	tos,f6
	movf	tos,f5
	movf	tos,f4
	movf	tos,f3
	movf	tos,f2
	movf	tos,f1
	movf	tos,f0
	lfsr	0(sp)		/* BUG: 'lfsr tos'  doesn't work! */
	adjspb	$-4
#else  /************************** FPU Available ***********************/
	adjspb	$-(9*4)		/* pop space for fpu registers */
#endif /************************** FPU Available ***********************/

restoremmu:
#ifdef MMU /********************** MMU Available ***********************/
	adjspb	$-(9*4)		/* throw away saved mmu registers */
#else  /************************** MMU Available ***********************/
	adjspb	$-(9*4)		/* pop space for mmu registers */
#endif /************************** MMU Available ***********************/

	/* restore fp and pop off excess stack */
	adjspb	$-4			/* skip id */
	movd	tos,r2			/* restore usp from interrupt stack */
	bispsrw $PSR_S			/* select usr stack */
	lprd	sp,r2			/* get usr stack (usp) */
	bicpsrw $PSR_S			/* select Monitor stack */

	adjspb	$-8			/* skip sb and fp on stack */
	restore [r3,r4,r5,r6,r7]	/* restore registers */
					/*  (r0,r1,r2 are on int stack) */

restorerest:
	movd	@A_cflags,r0		/* cflags sets MMU configuration */
	addr	tos,r1			/* point to current stack location */

#ifdef MMU /********************** MMU Available ***********************/
	movd	28(r1),r2		/* get saved msr */
					/* cflags in r0 */
	tbitd	$CF_TRACE,r0		/* test for program flow tracing */
	bfc	nflow
	sbitd	$MSR_B_FT,r2		/* flow tracing on, set FT bit in msr */
	sbitd	$MSR_B_NT,r2		/* set NT bit */
	br	mmt
nflow:
	cbitd	$MSR_B_FT,r2		/* flow tracing off, clr FT bit */
	cbitd	$MSR_B_NT,r2		/* disable non-sequential trace trap */
mmt:
	tbitd	$CF_MMUBRK,r0	/* test for mmu breakpointing */
	bfc	nbrk
	sbitd	$MSR_B_BEN,r2	/* set breakpoint enable bit BEN in msr */
	br	landr
nbrk:
	cbitd	$MSR_B_BEN,r2	/* disable breakpointing, clear BEN bit */
landr:
	movd	r2,28(r1)		/* save msr on stack */
#endif /************************** MMU Available ***********************/

#ifdef DEBUG_MONITOR /************ Monitor Debugging *************************/
	movqb	$0,@A_recursive		/* Reset recursive trap count */
#endif /* DEBUG_MONITOR ********** Monitor Debugging *************************/

	movd	36(r1),@A_state		/* restore saved processing state */
	lprd	sp,32(r1)		/* restore interrupt stack pointer */
					/* (intbase not touched) */

#ifdef MMU /********************** MMU Available ***********************/
	bicd	$(MSR_TU | MSR_FT | MSR_NT | MSR_BEN),r2
	lmr	msr,r2		/* restore interrupt supervisor mapping */
				/* but turn user mapping off */
#endif /************************** MMU Available ***********************/

	movusd	0(r1),0(sp)		/* copy saved r2 */
	movusd	4(r1),4(sp)		/* copy saved r1 */
	movusd	8(r1),8(sp)		/* copy saved r0 */
	movusd	28(r1),12(sp)		/* copy new msr to program */
					/* leave saved fp & skip trap id */
	movusd	20(r1),24(sp)		/* copy Monitor's copy of return addr */
	movusd	24(r1),28(sp)		/* and psr/mod */

#ifdef MMU /********************** MMU Available ***********************/
	lmr	msr,12(sp)		/* restore saved mapping state */
#endif /************************** MMU Available ***********************/

	restore	[r0,r1,r2]	/* restore regs copied from Monitor stack */
	adjspb	$-4		/* skip saved msr */
	lprd	fp,tos		/* restore fp */
	adjspb	$-4		/* skip trap id */
	rett	$0		/* return from real trap (finally) */

recursive_trap:		/* get here if MONITOR_STATE at trap */
	movd	20(sp),r2		/* get trap number */

#ifdef DEBUG_MONITOR /************ Monitor Debugging *************************/
	cmpqb	$0,@A_recursive		/* First recursive trap? */
	bne	recng			/* no....disallow */
mdebug:
	addqb	$1,@A_recursive		/* count recursive traps */
	addr	@A_debug_monstack,r1	/* set Monitor debug stack */
	br	copystack		/* and merge with normal trap code */

recng:
#endif /* DEBUG_MONITOR ********** Monitor Debugging *************************/

	movd	24(sp),tos		/* push address of fault */
	movd	_trapname[r2:d],tos	/* push address of trap name string */
	addr	_rectrapmsg,tos 	/* and msg address */
	jsr	_printf			/* print a msg */
	adjspb	$-(3*4)			/* pop arguments */

	cmpqb	$T_NMI,r2		/* can return from NMI & TRC */
	beq	recret
	cmpb	$T_TRC,r2
	beq	recret

					/* can't rett since pc is unchanged */
	cmpd	@A_reset_addr,$ROMSTART		/* running in PROM? */
	bne	ramon				/* no...leave RAM turned on */
	movb	$(ROM_MAP),@(UART_MAPENABLE + U_CLROUT)	/* disable RAM */
ramon:	jump	_ramless_monitor

recret:
#ifdef MMU /********************** MMU Available ***********************/
	lmr	msr,12(sp)		/* restore msr to pre-trap state */
#endif /************************** MMU Available ***********************/

	exit	[r0,r1,r2]		/* restore stack */
	adjspb	$-4			/* pop trap id */
	rett	$0		/* return to interrupted Monitor, hopefully */


#ifdef MMUBRK
/* program break point register 0 */
	.globl	_prgb0
_prgb0:
#ifdef MMU /********************** MMU Available ***********************/
	lmr	bpr0,8(sp)	/* load breakpoint register 0 */
	lmr	bcnt,12(sp)	/* load breakpoint count register */
#endif /************************** MMU Available ***********************/
	ret	$0

/* program break point register 1 */
	.globl	_prgb1
_prgb1:
#ifdef MMU /********************** MMU Available ***********************/
	lmr	bpr1,8(sp)	/* load breakpoint register 1 */
#endif /************************** MMU Available ***********************/
	ret	$0
#endif MMUBRK


#ifdef MONJSR

/* 
 * xcall (addr, arg1, arg2, arg3) - call external procedure with three arguments
 */
	.globl	_xcall
_xcall:
	movd	16(sp),tos		/* push three arguments */
	movd	12(sp),tos		/* for an external procedure call */
	movd	8(sp),tos
	jsr	0(4(sp))		/* do the jsr to the supplied address */
	adjspb	$-12			/* get rid of arguments on stack */
	ret	$0			/* return to RAM-Monitor */

#endif


/*  */

/* trap routines - disable interrupts, set trap id on stack, and merge above */
_NVI_monitor:
	movqd	$0,tos		/* trap number 0 */
	br	realtrap
_NMI_monitor:
	movqd	$1,tos		/* trap number 1 */
	br	realtrap
_ABT_monitor:
	movqd	$2,tos		/* trap number 2 */
	br	realtrap
_FPU_monitor:
	movqd	$3,tos		/* trap number 3 */
	br	realtrap
_ILL_monitor:
	movqd	$4,tos		/* trap number 4 */
	br	realtrap
_SVC_monitor:
	movqd	$5,tos		/* trap number 5 */
	br	realtrap
_DVZ_monitor:
	movqd	$6,tos		/* trap number 6 */
	br	realtrap
_FLG_monitor:
	movqd	$7,tos		/* trap number 7 */
	br	realtrap
_BPT_monitor:
	addr	@8,tos		/* trap number 8 */
	br	realtrap
_TRC_monitor:
	addr	@9,tos		/* trap number 9 */
	br	realtrap
_UND_monitor:
	addr	@10,tos		/* trap number 10 */
	br	realtrap
_RSV11_monitor:
_RSV12_monitor:
_RSV13_monitor:
_RSV14_monitor:
_RSV15_monitor:
	addr	@11,tos		/* trap number 11 */
	br	realtrap

_VEC0_monitor:
	addr	@(16 + 0),tos		/* vectored interrupt */
	br	realtrap
_VEC1_monitor:
	addr	@(16 + 1),tos		/* vectored interrupt */
	br	realtrap
_VEC2_monitor:
	addr	@(16 + 2),tos		/* vectored interrupt */
	br	realtrap
_VEC3_monitor:
	addr	@(16 + 3),tos		/* vectored interrupt */
	br	realtrap
_VEC4_monitor:
	addr	@(16 + 4),tos		/* vectored interrupt */
	br	realtrap
_VEC5_monitor:
	addr	@(16 + 5),tos		/* vectored interrupt */
	br	realtrap
_VEC6_monitor:
	addr	@(16 + 6),tos		/* vectored interrupt */
	br	realtrap
_VEC7_monitor:
	addr	@(16 + 7),tos		/* vectored interrupt */
	br	realtrap
_VEC8_monitor:
	addr	@(16 + 8),tos		/* vectored interrupt */
	br	realtrap
_VEC9_monitor:
	addr	@(16 + 9),tos		/* vectored interrupt */
	br	realtrap
_VEC10_monitor:
	addr	@(16 + 10),tos		/* vectored interrupt */
	br	realtrap
_VEC11_monitor:
	addr	@(16 + 11),tos		/* vectored interrupt */
	br	realtrap
_VEC12_monitor:
	addr	@(16 + 12),tos		/* vectored interrupt */
	br	realtrap
_VEC13_monitor:
	addr	@(16 + 13),tos		/* vectored interrupt */
	br	realtrap
_VEC14_monitor:
	addr	@(16 + 14),tos		/* vectored interrupt */
	br	realtrap
_VEC15_monitor:
	addr	@(16 + 15),tos		/* vectored interrupt */
	br	realtrap

	.globl	illegal_int
illegal_int:		/* illegal int code (jump to with vector on stack) */
	bicpsrw	$PSR_I		/* make sure that interrupts are disabled */
	br	realtrap	/* (stack has vector and interrupt addr) */


	.globl	_jump_after_break
	.globl	_jump_to
	.globl	_jump_reset
_jump_reset:
	movqd	$0,r0
	lmr	msr,r0		/* turn off mapping */
	lprw	psr,r0		/* turn off interrupts, etc. */
	br	_jump_to

_jump_after_break:
	bpt			/* LAST CHANCE FOR SALVATION!!! */
_jump_to:
	movd	4(sp),r0	/* get address to jump to */
	jump	r0		/* jump to address specified as argument */


	.globl	emergency
emergency:
	movd	r0,@A_emergency+0
	movd	r1,@A_emergency+4
	movd	r2,@A_emergency+8
	movd	r3,@A_emergency+12
	movd	r4,@A_emergency+16
	movd	r5,@A_emergency+20
	movd	r6,@A_emergency+24
	movd	r7,@A_emergency+28
	sprd	sp,@A_emergency+32
	sprd	fp,@A_emergency+36
	sprd	sb,@A_emergency+40
	sprd	mod,@A_emergency+44
	sprd	intbase,@A_emergency+48
	jump	_ramless_monitor	/* jump to rom monitor */


	/* construct dispatch table entries */
#define Setdispatch(x)	addr	_/**/x/**/_monitor,I_/**/x/**/(r1)
#define Setvector(x)	addr	_VEC/**/x/**/_monitor,(I_VEC + ( x * 4))(r1)

	.globl	init_mondispatch
init_mondispatch:	/* RAM-Monitor Trap/Interrupt Dispatch Table */

	addr	@A_mondispatch,r1	/* Get address of dispatch table */

	Setdispatch(NVI)	/* Trap handlers */
	Setdispatch(NMI)
	Setdispatch(ABT)
	Setdispatch(FPU)
	Setdispatch(ILL)
	Setdispatch(SVC)
	Setdispatch(DVZ)
	Setdispatch(FLG)
	Setdispatch(BPT)
	Setdispatch(TRC)
	Setdispatch(UND)
	Setdispatch(RSV11)
	Setdispatch(RSV12)
	Setdispatch(RSV13)
	Setdispatch(RSV14)
	Setdispatch(RSV15)
			/* initialize Interrupt handlers */
	Setvector(0)
	Setvector(1)
	Setvector(2)
	Setvector(3)
	Setvector(4)
	Setvector(5)
	Setvector(6)
	Setvector(7)
	Setvector(8)
	Setvector(9)
	Setvector(10)
	Setvector(11)
	Setvector(12)
	Setvector(13)
	Setvector(14)
	Setvector(15)

	ret	$0
