/* vax-hc.s
 * 
 * Assembly language assist and startup for DDT.  Gets a stack for
 * DDT, initializes interrupt vectors, and calls the main DDT interpreter.
 * Also contains trap handling routines and return to inerrupted program.
 */

.set	KSP,0		/* Kernel Stack Pointer */
.set	SCBB,0x11	/* System Control Block Base */
.set	IPLR,0x12	/* Interrupt Priority Level Register */
.set	MCESR,0x26	/* Machine Check Error Summary */
.set	SID,62		/* System ID register */
.set	SIDmask,0x00ffffff /* Only the high byte has the processor type */
.set	uVAX2,0x08000000 /* SID for the uVAX-II */


	.globl	_DDT
	.globl	_ddthc
	.globl	_mkioptab

/* Main DDT entry point */
_DDT:
	mtpr	$ddtstack,$KSP		/* Get our own stack */
	calls	$0,inivec		/* Initialize interrupt vectors */
	calls	$0,_mkioptab		/* Initialize disassembler */
	calls	$0,_ddthc		/* Goto debugger */
	jmp	rtn			/* Return to user program */


.set	MAXVEC,0x100
.set	ISTK,0x1			/* Take trap on interrupt stack */
.set	XFC, 0xfc			/* `XFC' instruction */

.set	MCHECK, 0x4			/* Machine Check */
.set	PRIVINST, 0x10			/* Priviledged Instruction */
.set	CRESINST, 0x14			/* Customer Reserved Instruction */
.set	RESOP,0x18			/* Reserved Operand */
.set	RESADD,0x1c			/* Reserved Addressing Mode */
.set	TP, 0x28			/* Trace Pending */
.set	BRK, 0x2c			/* Breakpoint */
.set	ARITH, 0x34			/* Arithmetic Trap */
.set	MWT, 0x60			/* Memory Write Timeout */

/* Initialize interrupt and trap vectors */
inivec:
	.word	0
	mfpr	$SCBB,r0		/* Get base of interrupt vectors */
	clrl	r1			/* Index register */
1:	moval	0[r1],(r0)[r1]		/* set vector to bad_int table */
	movl	$XFC, 0[r1]		/* fill in bad_int table with 'xfc' */
					/* bad_int table starts on page 0 */
	aoblss	$MAXVEC,r1,1b

	/* Set up right machine check handler */
	mfpr	$SID,r1
	bicl2	$SIDmask,r1
	cmpl	r1,$uVAX2
	bneq	2f
	movl	$mcheck2, MCHECK(r0)
	brb	3f
2:	movl	$mcheck1, MCHECK(r0)
3:
	movl	$ill_inst, PRIVINST(r0)
	movl	$uninit_int, CRESINST(r0)
	movl	$res_op, RESOP(r0)
	movl	$res_add, RESADD(r0)
	movl	$trc_trap, TP(r0)
	movl	$brk_trap, BRK(r0)
	movl	$arith_trap, ARITH(r0)
	movl	$mrt, MWT(r0)
	ret

	.globl	_ddtbpt
	.globl	brk_trap
/* Breakpoint Trap handler */
.align	2
brk_trap:
	movl	(sp)+,_ddtpc		/* get pc and ps off stack */
	movl	(sp)+,_ddtps

	mtpr	$0x1f,$IPLR		/* Disable interrupts */
	movl	r0,_ddtregs		/* save registers */
	movl	r1,_ddtregs+0x4
	movl	r2,_ddtregs+0x8
	movl	r3,_ddtregs+0xc
	movl	r4,_ddtregs+0x10
	movl	r5,_ddtregs+0x14
	movl	r6,_ddtregs+0x18
	movl	r7,_ddtregs+0x1c
	movl	r8,_ddtregs+0x20
	movl	r9,_ddtregs+0x24
	movl	r10,_ddtregs+0x28
	movl	r11,_ddtregs+0x2c
	movl	r12,_ddtregs+0x30
	movl	r13,_ddtregs+0x34
	movl	r14,_ddtregs+0x38

	movl	$ddtstack,sp		/* get our own stack */
	calls	$0,_ddtbpt		/* go process breakpoint */
	jmp	rtn			/* return to user program */


	.globl	_ddttrc
	.globl	trc_trap
/* Trace Trap handler */
.align	2
trc_trap:
	movl	(sp)+,_ddtpc		/* get pc and ps off stack */
	movl	(sp)+,_ddtps

	mtpr	$0x1f,$IPLR		/* Disable interrupts */
	movl	r0,_ddtregs		/* save registers */
	movl	r1,_ddtregs+0x4
	movl	r2,_ddtregs+0x8
	movl	r3,_ddtregs+0xc
	movl	r4,_ddtregs+0x10
	movl	r5,_ddtregs+0x14
	movl	r6,_ddtregs+0x18
	movl	r7,_ddtregs+0x1c
	movl	r8,_ddtregs+0x20
	movl	r9,_ddtregs+0x24
	movl	r10,_ddtregs+0x28
	movl	r11,_ddtregs+0x2c
	movl	r12,_ddtregs+0x30
	movl	r13,_ddtregs+0x34
	movl	r14,_ddtregs+0x38

	movl	$ddtstack,sp		/* get our own stack */
	calls	$0,_ddttrc		/* go process trace trap */
	jmp	rtn			/* return to user program */

	.globl	_ddtrte
	.globl	trap_handler
	.globl	_noddt
/* Common trap handler.  Individual trap handlers should save r0 in ddtregs,
 * put a pointer to their message in r0, and jump to here.
 */
trap_handler:
	movl	(sp)+,_ddtpc		/* get pc and ps off stack */
	movl	(sp)+,_ddtps

	tstl	_noddt			/* If noddt then halt */
	beql	1f
	halt

1:	mtpr	$0x1f,$IPLR		/* Disable interrupts */
	movl	r1,_ddtregs+0x4		/* save registers (R0 already saved) */
	movl	r2,_ddtregs+0x8
	movl	r3,_ddtregs+0xc
	movl	r4,_ddtregs+0x10
	movl	r5,_ddtregs+0x14
	movl	r6,_ddtregs+0x18
	movl	r7,_ddtregs+0x1c
	movl	r8,_ddtregs+0x20
	movl	r9,_ddtregs+0x24
	movl	r10,_ddtregs+0x28
	movl	r11,_ddtregs+0x2c
	movl	r12,_ddtregs+0x30
	movl	r13,_ddtregs+0x34
	movl	r14,_ddtregs+0x38

	movl	$ddtstack,sp		/* get our own stack */
	pushl	r0			/* push message */
	calls	$1,_ddtrte		/* go process trap */
	jmp	rtn			/* continue program */

	.globl	uninit_int
/* Random interrupt handler.  These are handled through the XFC trap.
 * This routine could do a lot more, like print out the address trapped
 * through and set the saved PC to what it should be. */
.align 2
uninit_int:
	movl	r0,_ddtregs
	movl	$uninitm,r0
	jmp	trap_handler

	.data
uninitm:
	.asciz	"Unexpected interrupt"
	.text

	.globl	ill_inst
/* Illegal instruction trap */
.align	2
ill_inst:
	movl	r0,_ddtregs
	movl	$illm,r0
	jmp	trap_handler

	.data
illm:	.asciz	"Illegal instruction"
	.text

	.globl	mrt
/* Memory write timeout handler */
.align	2
mrt:
	movl	r0,_ddtregs
	movl	$mrtm,r0
	jmp	trap_handler

	.data
mrtm:	.asciz	"Memory write timeout"
	.text

	.globl	arith_trap
/* Handles arithmetic traps and faults */
.align	2
arith_trap:
	movl	r0,_ddtregs
	movl	(sp)+,r0		/* Get exception type code */
	movl	arith_msg(r0),r0
	jmp	trap_handler

	.data
arith1:	.asciz	"Integer overflow"
arith2:	.asciz	"Integer divide by zero"
arith3:	.asciz	"Floating overflow (trap)"
arith4:	.asciz	"Floating/decimal divide by zero (trap)"
arith5:	.asciz	"Floating underflow (trap)"
arith6:	.asciz	"Decimal overflow"
arith7:	.asciz	"Subscript range"
arith8:	.asciz	"Floating overflow (fault)"
arith9:	.asciz	"Floating divide by zero (fault)"
arithA:	.asciz	"Floating underflow (fault)"

.align	2
arith_msg:
	.long	arith1
	.long	arith2
	.long	arith3
	.long	arith4
	.long	arith5
	.long	arith6
	.long	arith7
	.long	arith8
	.long	arith9
	.long	arithA
	.text

	.globl	mcheck1
/* Machine check handler for uVAX-I.
 */
.align	2
mcheck1:
	movl	r0,_ddtregs
	movl	(sp)+,r0		/* Gets number of mcheck args (which is ignored for now) */
	movl	(sp)+,r0		/* Get mcheck code */
	movl	r0, mc_code
	movl	(sp)+, mc_p1
	movl	(sp)+, mc_p2
	cmpl	r0, $9
	blss	1f
	movl	$mchm,r0		/* Use generic mcheck message */
	brb	2f
1:	movl	mcheck1_msg[r0],r0	/* Get approprite mcheck message */
2:	mtpr	$0,$MCESR		/* clear machine check flag */
	jmp	trap_handler

	.globl	mcheck2
/* Machine check handler for uVAX-II.
 */
.align	2
mcheck2:
	movl	r0,_ddtregs
	movl	(sp)+,r0		/* Get number of mcheck args (which is ignored for now) */
	movl	(sp)+,r0		/* Get mcheck code */
	movl	r0, mc_code
	movl	(sp)+, mc_p1
	movl	(sp)+, mc_p2

	cmpl	r0,$9			/* if less than 9 then is good mcode */
	bgtru	1f
	movl	mcheck2_msg[r0],r0
	brb	5f

1:	cmpl	r0,$0x80		/* if between 0x80 and 0x83 (incl) then is good */
	blssu	4f
	cmpl	r0,$0x83
	bgtru	4f
	subl2	$0x80,r0
	movl	mcheck2_80_msg[r0],r0
	brb	5f

4:	movl	$mchm,r0		/* Unknown machine check */
5:	mtpr	$0,$MCESR		/* clear machine check flag */
	jmp	trap_handler

	.data
mchm:	.asciz	"Unknown Machine check"
mchm0:	.asciz	"Memory controller bug check"
mchm1:	.asciz	"Unrecoverable read error"
mchm2:	.asciz	"NXM"
mchm3:	.asciz	"Illegal operation"
mchm4:	.asciz	"Unrecoverable page table read error"
mchm5:	.asciz	"Unrecoverable page table write error"
mchm6:	.asciz	"Control store parity error"
mchm7:	.asciz	"Micromachine bug check"
mchm8:	.asciz	"Q22 bus vector read error"
mchm9:	.asciz	"Write parameter error"
mch2m1:	.asciz	"Impossible ucode state (FSD)"
mch2m2:	.asciz	"Impossible ucode state (SSD)"
mch2m3:	.asciz	"Undefined FPU error 0"
mch2m4:	.asciz	"Undefined FPU error 7"
mch2m5:	.asciz	"Undefined memory management status (TB miss)"
mch2m6:	.asciz	"Undefined memory management status (M=0)"
mch2m7:	.asciz	"Process PTE address in P0 space"
mch2m8:	.asciz	"Process PTE address in P1 space"
mch2m9:	.asciz	"Undefined interrupt ID code"
mch2m80: .asciz	"read bus error (mc_p1 is virtual address)"
mch2m81: .asciz	"read bus error (mc_p1 is physical address)"
mch2m82: .asciz	"write bus error (mc_p1 is virtual address)"
mch2m83: .asciz	"write bus error (mc_p1 is physical address)"

.align 2
mcheck1_msg:
	.long	mchm0
	.long	mchm1
	.long	mchm2
	.long	mchm3
	.long	mchm4
	.long	mchm5
	.long	mchm6
	.long	mchm7
	.long	mchm8
	.long	mchm9
mcheck2_msg:
	.long	mchm
	.long	mch2m1
	.long	mch2m2
	.long	mch2m3
	.long	mch2m4
	.long	mch2m5
	.long	mch2m6
	.long	mch2m7
	.long	mch2m8
	.long	mch2m9
mcheck2_80_msg:
	.long	mch2m80
	.long	mch2m81
	.long	mch2m82
	.long	mch2m83

	.globl	mc_code
	.globl	mc_p1
	.globl	mc_p2
mc_code: .long	0		/* Machine check code */
mc_p1:	.long	0		/* Parameter 1 */
mc_p2:	.long	0		/* Parameter 2 */

	.text
	.globl	res_op
/* Reserved Operand Trap */
.align 2
res_op:
	movl	r0,_ddtregs
	movl	$ropm,r0
	jmp	trap_handler

	.data
ropm:	.asciz	"Reserved Operand"
	.text

	.globl	res_add
/* Reserved Addressing Mode Trap */
.align 2
res_add:
	movl	r0,_ddtregs
	movl	$radm,r0
	jmp	trap_handler

	.data
radm:	.asciz	"Reserved addressing mode"
	.text

	.globl	rtn
/* Return to Interrupted Program */
rtn:
	movl	_ddtregs+0x0,r0	/* Restore registers */
	movl	_ddtregs+0x4,r1
	movl	_ddtregs+0x8,r2
	movl	_ddtregs+0xc,r3
	movl	_ddtregs+0x10,r4
	movl	_ddtregs+0x14,r5
	movl	_ddtregs+0x18,r6
	movl	_ddtregs+0x1c,r7
	movl	_ddtregs+0x20,r8
	movl	_ddtregs+0x24,r9
	movl	_ddtregs+0x28,r10
	movl	_ddtregs+0x2c,r11
	movl	_ddtregs+0x30,r12
	movl	_ddtregs+0x34,r13
	movl	_ddtregs+0x38,r14
	pushl	_ddtps
	pushl	_ddtpc
	rei

	.globl	_ddtexec
/* Code to reset machine for $G. */
_ddtexec:
	.word	0
	movl	$ddtstack,_ddtsp
	ret


.data

/* The stack used by DDT. */
.align 2
	.space	1024
ddtstack:

	.globl	_ddtregs
	.globl	_ddtpc
	.globl	_ddtps
/* register save locations */
.align 2
_ddtregs:
	.long	0	/* r0 */
	.long	0	/* r1 */
	.long	0	/* r2 */
	.long	0	/* r3 */
	.long	0	/* r4 */
	.long	0	/* r5 */
	.long	0	/* r6 */
	.long	0	/* r7 */
	.long	0	/* r8 */
	.long	0	/* r9 */
	.long	0	/* r10 */
	.long	0	/* r11 */
_ddtap:	.long	0	/* r12 */
_ddtfp:	.long	0	/* r13 */
_ddtsp:	.long	0	/* r14 */
_ddtpc:	.long	0	/* r15 */
_ddtps:	.long	0	/* psl */
