code:
/*	$OpenBSD: emulate.s,v 1.5 2013/07/05 21:11:57 miod Exp $ */
/*	$NetBSD: emulate.s,v 1.2 1997/03/15 16:14:25 ragge Exp $ */
/*
 * Copyright (c) 1986, 1987 The Regents of the University of California.
 * All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * Mt. Xinu.
 *
 * 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.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
 *
 *	@(#)emulate.s	7.5 (Berkeley) 6/28/90
 */

#include <machine/asm.h>

/*
 * String instruction emulation - MicroVAX only.  These routines are called
 * from locore.s when an "emulate" fault occurs on the MicroVAX.  They are
 * called with the stack set up as follows:
 *
 *	  (sp):	Return address of trap handler
 *	 4(sp):	Instruction Opcode	(also holds PSL result from emulator)
 *	 8(sp):	Instruction PC
 *	12(sp):	Operand 1
 *	16(sp):	Operand 2
 *	20(sp):	Operand 3
 *	24(sp):	Operand 4
 *	28(sp):	Operand 5
 *	32(sp):	Operand 6
 *	36(sp):	old Register 11
 *	40(sp):	old Register 10
 *	44(sp):	Return PC
 *	48(sp):	Return PSL
 *	52(sp): TOS before instruction
 *
 * R11 and r10 are available for use.  If any routine needs to use r9-r1
 * they need to save them first (unless those registers are SUPPOSED to be
 * messed with by the "instruction").  These routines leave their results
 * in registers 0-5 explicitly, as needed, and use the macros defined below
 * to link up with calling routine.
 */

#define return		rsb
#define savepsl		movpsl	4(%sp)
#define setpsl(reg)	movl	reg,4(%sp)
#define overflowpsl	movl	$2,4(%sp)
#define arg1		12(%sp)
#define arg2		16(%sp)
#define arg3		20(%sp)
#define arg4		24(%sp)
#define arg5		28(%sp)
#define arg6		32(%sp)
#define argub(num,reg)	movzbl	8+4*num(%sp),reg
#define arguw(num,reg)	movzwl	8+4*num(%sp),reg
#define argul(num,reg)	movl	8+4*num(%sp),reg
#define argb(num,reg)	cvtbl	8+4*num(%sp),reg
#define argw(num,reg)	cvtwl	8+4*num(%sp),reg
#define argl(num,reg)	movl	8+4*num(%sp),reg
#define toarg(reg,num)	movl	reg,8+4*num(%sp)

	.text
	_ALIGN_TEXT
ALTENTRY(EMcrc)
	argl(1,%r11)		# (1) table address == r11
	argl(2,%r0)		# (2) initial crc == r0
	argl(4,%r3)		# (4) source address == r3
	arguw(3,%r2)		# (3) source length == r2
	jeql	Lcrc_out
Lcrc_loop:
	xorb2	(%r3)+,%r0
	extzv	$0,$4,%r0,%r10
	extzv	$4,$28,%r0,%r1
	xorl3	%r1,(%r11)[%r10],%r0
	extzv	$0,$4,%r0,%r10
	extzv	$4,$28,%r0,%r1
	xorl3	%r1,(%r11)[%r10],%r0
	sobgtr	%r2,Lcrc_loop
	tstl	%r0
Lcrc_out:
	savepsl
	clrl	%r1
	return

	_ALIGN_TEXT
ALTENTRY(EMmovtc)
	arguw(1,%r0)		# (1) source length == r0
	argl(2,%r1)		# (2) source address == r1
	argub(3,%r11)		# (3) fill character == r11
	argl(4,%r3)		# (4) table address == r3
	argl(6,%r5)		# (6) destination address == r5
	arguw(5,%r4)		# (5) destination length == r4
	jeql	Lmovtc_out
Lmovtc_loop:
	tstl	%r0
	jeql	Lmovtc_2loop
	movzbl	(%r1)+,%r2
	movb	(%r3)[%r2],(%r5)+
	decl	%r0
	sobgtr	%r4,Lmovtc_loop
	jbr	Lmovtc_out
Lmovtc_2loop:
	movb	%r11,(%r5)+
	sobgtr	%r4,Lmovtc_2loop
Lmovtc_out:
	cmpl	%r4,%r0
	savepsl
	clrl	%r2
	return

	_ALIGN_TEXT
ALTENTRY(EMmovtuc)
	arguw(1,%r0)		# (1) source length == r0
	argl(2,%r1)		# (2) source address == r1
	argub(3,%r11)		# (3) escape character == r11
	argl(4,%r3)		# (4) table address == r3
	argl(6,%r5)		# (6) destination address == r5
	arguw(5,%r4)		# (5) destination length == r4
	jeql	Lmovtuc_out
Lmovtuc_loop:
	tstl	%r0
	jeql	Lmovtuc_out
	movzbl	(%r1),%r2
	movzbl	(%r3)[%r2],%r2
	cmpl	%r2,%r11
	jeql	Lmovtuc_out
	movzbl	(%r1)+,%r2
	movb	(%r3)[%r2],(%r5)+
	decl	%r0
	sobgtr	%r4,Lmovtuc_loop
Lmovtuc_out:
	cmpl	%r4,%r0
	savepsl
	clrl	%r2
	return

	_ALIGN_TEXT
ALTENTRY(EMmatchc)
	argl(2,%r10)		# (2) substring address == r10
	arguw(3,%r2)		# (3) source length == r2
	argl(4,%r3)		# (4) source address == r3
	arguw(1,%r11)		# (1) substring length == r11
	jeql	Lmatchc_out	# temp source address == r1
	addl2	%r10,%r11	# temp substring address == r0
	tstl	%r2
	jeql	Lmatchc_out
Lmatchc_loop:
	cmpb	(%r10),(%r3)
	jneq	Lmatchc_fail
	movl	%r3,%r1
	movl	%r10,%r0
Lmatchc_2loop:
	cmpl	%r0,%r11
	jeql	Lmatchc_succ
	cmpb	(%r0)+,(%r1)+
	jeql	Lmatchc_2loop
Lmatchc_fail:
	incl	%r3
	sobgtr	%r2,Lmatchc_loop
	movl	%r10,%r1
	subl3	%r10,%r11,%r0
	jbr	Lmatchc_out
Lmatchc_succ:
	movl	%r1,%r3
	movl	%r11,%r1
	clrl	%r0
Lmatchc_out:
	savepsl
	return

	_ALIGN_TEXT
ALTENTRY(EMspanc)
	argl(2,%r1)		# (2) string address == r1
	argub(4,%r2)		# (4) character-mask == r2
	argl(3,%r3)		# (3) table address == r3
	arguw(1,%r0)		# (1) string length == r0
	jeql	Lspanc_out
Lspanc_loop:
	movzbl	(%r1),%r11
	mcomb	(%r3)[%r11],%r11
	bicb3	%r11,%r2,%r11
	jeql	Lspanc_out
	incl	%r1
	sobgtr	%r0,Lspanc_loop
Lspanc_out:
	savepsl
	clrl	%r2
	return

	_ALIGN_TEXT
ALTENTRY(EMscanc)
	argl(2,%r1)		# (2) string address == r1
	argub(4,%r2)		# (4) character-mask == r2
	argl(3,%r3)		# (3) table address == r3
	arguw(1,%r0)		# (1) string length == r0
	jeql	Lscanc_out
Lscanc_loop:
	movzbl	(%r1),%r11
	mcomb	(%r3)[%r11],%r11
	bicb3	%r11,%r2,%r11
	jneq	Lscanc_out
	incl	%r1
	sobgtr	%r0,Lscanc_loop
Lscanc_out:
	savepsl
	clrl	%r2
	return

	_ALIGN_TEXT
ALTENTRY(EMskpc)
	argub(1,%r11)		# (1) character == r11
	argl(3,%r1)		# (3) string address == r1
	arguw(2,%r0)		# (2) string length == r0
	jeql	Lskpc_out	# forget zero length strings
Lskpc_loop:
	cmpb	(%r1),%r11
	jneq	Lskpc_out
	incl	%r1
	sobgtr	%r0,Lskpc_loop
Lskpc_out:
	tstl	%r0		# be sure of condition codes
	savepsl
	return

	_ALIGN_TEXT
ALTENTRY(EMlocc)
	argub(1,%r11)		# (1) character == r11
	argl(3,%r1)		# (3) string address == r1
	arguw(2,%r0)		# (2) string length == r0
	jeql	Lskpc_out	# forget zero length strings
Llocc_loop:
	cmpb	(%r1),%r11
	jeql	Llocc_out
	incl	%r1
	sobgtr  %r0,Llocc_loop
Llocc_out:
	tstl	%r0		# be sure of condition codes
	savepsl
	return

	_ALIGN_TEXT
ALTENTRY(EMcmpc3)
	argl(2,%r1)		# (2) string1 address == r1
	argl(3,%r3)		# (3) string2 address == r3
	arguw(1,%r0)		# (1) strings length == r0
	jeql	Lcmpc3_out
Lcmpc3_loop:
	cmpb	(%r1),(%r3)
	jneq	Lcmpc3_out
	incl	%r1
	incl	%r3
	sobgtr	%r0,Lcmpc3_loop
Lcmpc3_out:
	savepsl
	movl	%r0,%r2
	return

	_ALIGN_TEXT
ALTENTRY(EMcmpc5)
	argl(2,%r1)		# (2) string1 address == r1
	argub(3,%r11)		# (1) fill character == r11
	arguw(4,%r2)		# (1) string2 length == r2
	argl(5,%r3)		# (3) string2 address == r3
	arguw(1,%r0)		# (1) string1 length == r0
	jeql	Lcmpc5_str2
Lcmpc5_loop:
	tstl	%r2
	jeql	Lcmpc5_str1loop
	cmpb	(%r1),(%r3)
	jneq	Lcmpc5_out
	incl	%r1
	incl	%r3
	decl	%r2
	sobgtr	%r0,Lcmpc5_loop
Lcmpc5_str2:
	tstl	%r2
	jeql	Lcmpc5_out
Lcmpc5_str2loop:
	cmpb	%r11,(%r3)
	jneq	Lcmpc5_out
	incl	%r3
	sobgtr	%r2,Lcmpc5_str2loop
	jbr	Lcmpc5_out
Lcmpc5_str1loop:
	cmpb	(%r1),%r11
	jneq	Lcmpc5_out
	incl	%r1
	sobgtr	%r0,Lcmpc5_str1loop
Lcmpc5_out:
	savepsl
	return

/*
 * Packed Decimal string operations
 */

#define POSITIVE	$12
#define NEGATIVE	$13
#define NEGATIVEalt	$11

	_ALIGN_TEXT
ALTENTRY(EMaddp4)
	toarg(%r9,6)		# save register r9 in arg6 spot
	arguw(1,%r11)		# (1) source length == r11
	argl(2,%r10)		# (2) source address == r10
	arguw(3,%r9)		# (3) destination length == r9
	argl(4,%r3)		# (4) destination address == r3
	ashl	$-1,%r11,%r11
	addl2	%r11,%r10	# source address of LSNibble
	incl	%r11		# source length is in bytes
	ashl	$-1,%r9,%r9
	addl2	%r9,%r3		# r3 = destination address of LSNibble
	incl	%r9		# destination length is in bytes
	toarg(%r3,5)
	extzv	$0,$4,(%r3),%r2	# set standard +/- indicators in destination
	cmpl	%r2,NEGATIVE
	jeql	L112
	cmpl	%r2,NEGATIVEalt
	jeql	L111
	insv	POSITIVE,$0,$4,(%r3)
	jbr	L112
L111:
	insv	NEGATIVE,$0,$4,(%r3)
L112:
	extzv	$0,$4,(%r10),%r2 # r2 = standard +/- of source
	cmpl	%r2,NEGATIVE
	jeql	L114
	cmpl	%r2,NEGATIVEalt
	jeql	L113
	movl	POSITIVE,%r2
	jbr	L114
L113:
	movl	NEGATIVE,%r2
L114:
	cmpl	%r11,%r9	# if source is longer than destination
	jleq	L115
	movl	%r9,%r11	#	set source length == destination length
L115:
	extzv	$4,$4,(%r3),%r9	# r9 = LSDigit of destination
	extzv	$4,$4,(%r10),%r1 # r1 = LSDigit of source
	extzv	$0,$4,(%r3),%r0
	cmpl	%r0,%r2		# if signs of operands are not equal
	jeql	Laddp4_same	#	do a subtraction
	clrl	%r2		# r2 is non-zero if result is non-zero
	subl2	%r1,%r9		# r9 = "addition" of operands high nibble
	jbr	L119		# jump into addition loop
Laddp4_diff_loop:
	decl	%r3
	extzv	$0,$4,(%r3),%r0
	addl2	%r0,%r1		# r1 = carry + next (low) nibble of source
	decl	%r10
	extzv	$0,$4,(%r10),%r0
	subl2	%r0,%r1		# r1 -= next (low) nibble of destination
	jgeq	L121		# if negative result
	mnegl	$1,%r9		#	r9 == carry = -1
	addl2	$10,%r1		#	r1 == result += 10
	jbr	L122		# else
L121:
	clrl	%r9		#	r9 == carry = 0
L122:
	insv	%r1,$0,$4,(%r3)	# store result low nibble
	bisl2	%r1,%r2
	extzv	$4,$4,(%r3),%r0
	addl2	%r0,%r9		# r9 = carry + next (high) nibble of source
	extzv	$4,$4,(%r10),%r0
	subl2	%r0,%r9		# r9 -= next (high) nibble of destination
L119:
	jgeq	L117		# if negative result
	mnegl	$1,%r1		#	r1 == carry = -1
	addl2	$10,%r9		#	r9 == result += 10
	jbr	L118		# else
L117:
	clrl	%r1		#	r1 == carry = 0
L118:
	insv	%r9,$4,$4,(%r3)	# store result high nibble
	bisl2	%r9,%r2		# r2 is non-zero if result is non-zero
	decl	%r11		# while (--source length)
	jneq	Laddp4_diff_loop
	argl(4,%r10)		# r10 = address of destination MSNibble
	jbr	Laddp4_diff_carry
Laddp4_diff_carlop:
	decl	%r3
	extzv	$0,$4,(%r3),%r0
	addl2	%r0,%r1		# r1 == carry += next (low) nibble
	jgeq	L127		# if less than zero
	movl	%r1,%r9		#	r9 == carry (must be -1)
	movl	$9,%r1		#	r1 == result = 9
	jbr	L128
L127:				# else
	clrl	%r9		#	r9 == carry = 0
L128:
	insv	%r1,$0,$4,(%r3)	# store result
	bisl2	%r1,%r2
	extzv	$4,$4,(%r3),%r0
	addl2	%r0,%r9		# r9 == carry += next (high) nibble
	jgeq	L129		# if less than zero
	movl	%r9,%r1		# r1 == carry (must be -1)
	movl	$9,%r9		# r9 == result = 9
	jbr	L130
L129:
	clrl	%r1
L130:
	insv	%r9,$4,$4,(%r3)	# store result
	bisl2	%r9,%r2
Laddp4_diff_carry:
	cmpl	%r3,%r10
	jneq	Laddp4_diff_carlop
	tstl	%r1		#	if carry out of MSN then fix up result
	jeql	Laddp4_add_done
	argl(5,%r3)		# r3 == address of LSN of destination
	extzv	$0,$4,(%r3),%r0
	cmpl	%r0,NEGATIVE	# switch sign of result
	jneq	L132
	insv	POSITIVE,$0,$4,(%r3)
	jbr	L133
L132:
	insv	NEGATIVE,$0,$4,(%r3)
L133:
	extzv	$4,$4,(%r3),%r0	# normalize result (carry out of MSN into LSN)
	subl3	%r0,$10,%r9	# r9 = 10 - destination LSNibble
	jbr	L134
L137:
	movl	$9,%r1
Laddp4_diff_norm:
	insv	%r9,$4,$4,(%r3)
	cmpl	%r3,%r10	# while (not at MSNibble)
	jeql	Laddp4_add_done
	decl	%r3
	extzv	$0,$4,(%r3),%r0	# low nibble = (9 + carry) - low nibble
	subl2	%r0,%r1
	cmpl	%r1,$9
	jleq	L135
	clrl	%r1
	movl	$10,%r9
	jbr	L136
L135:
	movl	$9,%r9
L136:
	insv	%r1,$0,$4,(%r3)
	extzv	$4,$4,(%r3),%r0	# high nibble = (9 + carry) - high nibble
	subl2	%r0,%r9
L134:
	cmpl	%r9,$9
	jleq	L137
	clrl	%r9
	movl	$10,%r1
	jbr	Laddp4_diff_norm

Laddp4_same:			# operands are of the same sign
	clrl	%r2
	addl2	%r1,%r9
	jbr	L139
Laddp4_same_loop:
	decl	%r3
	extzv	$0,$4,(%r3),%r0
	addl2	%r0,%r1		# r1 == carry += next (low) nibble of dest
	decl	%r10
	extzv	$0,$4,(%r10),%r0
	addl2	%r0,%r1		# r1 += next (low) nibble of source
	cmpl	%r1,$9		# if result > 9
	jleq	L141
	movl	$1,%r9		#	r9 == carry = 1
	subl2	$10,%r1		#	r1 == result -= 10
	jbr	L142
L141:				# else
	clrl	%r9		#	r9 == carry = 0
L142:
	insv	%r1,$0,$4,(%r3)	# store result
	bisl2	%r1,%r2
	extzv	$4,$4,(%r10),%r0
	addl2	%r0,%r9		# ditto for high nibble
	extzv	$4,$4,(%r3),%r0
	addl2	%r0,%r9
L139:
	cmpl	%r9,$9
	jleq	L143
	movl	$1,%r1
	subl2	$10,%r9
	jbr	L144
L143:
	clrl	%r1
L144:
	insv	%r9,$4,$4,(%r3)
	bisl2	%r9,%r2
	sobgtr	%r11,Laddp4_same_loop	# while (--source length)
	argl(4,%r10)		# r10 = destination address of MSNibble
	jbr	Laddp4_same_carry
Laddp4_same_cloop:
	decl	%r3
	extzv	$0,$4,(%r3),%r0	# propagate carry up to MSNibble of destination
	addl2	%r0,%r1
	cmpl	%r1,$10
	jneq	L147
	movl	$1,%r9
	clrl	%r1
	jbr	L148
L147:
	clrl	%r9
L148:
	insv	%r1,$0,$4,(%r3)
	bisl2	%r1,%r2
	extzv	$4,$4,(%r3),%r0
	addl2	%r0,%r9
	cmpl	%r9,$10
	jneq	L149
	movl	$1,%r1
	clrl	%r9
	jbr	L150
L149:
	clrl	%r1
L150:
	insv	%r9,$4,$4,(%r3)
	bisl2	%r9,%r2
Laddp4_same_carry:
	cmpl	%r3,%r10
	jneq	Laddp4_same_cloop

Laddp4_add_done:
	argl(5,%r3)		# r3 = destination address of LSNibble
	tstl	%r2		# if zero result
	jneq	L151
	savepsl			#	remember that for condition codes
	insv	POSITIVE,$0,$4,(%r3) #	make sure sign of result is positive
	jbr	Laddp4_out
L151:				# else
	extzv	$0,$4,(%r3),%r0
	cmpl	%r0,NEGATIVE	#	if result is negative
	jneq	Laddp4_out
	mnegl	%r2,%r2		#		remember THAT in Cond Codes
	savepsl
Laddp4_out:
	argl(4,%r3)
	argl(2,%r1)
	clrl	%r0
	clrl	%r2
	argl(6,%r9)		# restore r9 from stack
	return

	_ALIGN_TEXT
ALTENTRY(EMmovp)
	arguw(1,%r11)		# (1) string length == r11
	argl(2,%r10)		# (1) source address == r10
	argl(3,%r3)		# (1) destination address == r3
			# we will need arg2 and arg3 later
	clrl	%r2		# r2 == non-zero if source is non-zero
	ashl	$-1,%r11,%r11	# length is number of bytes, not nibbles
	jeql	Lmovp_zlen
Lmovp_copy:
	bisb2	(%r10),%r2	# keep track of non-zero source
	movb	(%r10)+,(%r3)+	# move two nibbles
	sobgtr	%r11,Lmovp_copy	# loop for length of source
Lmovp_zlen:
	extzv	$4,$4,(%r10),%r0 # look at least significant nibble
	bisl2	%r0,%r2
	extzv	$0,$4,(%r10),%r0 # check sign nibble
	cmpl	%r0,NEGATIVEalt
	jeql	Lmovp_neg
	cmpl	%r0,NEGATIVE
	jneq	Lmovp_pos
Lmovp_neg:			# source was negative
	mnegl	%r2,%r2
Lmovp_pos:
	tstl	%r2		# set condition codes
	savepsl
	jeql	Lmovp_zero
	movb	(%r10),(%r3)	# move last byte if non-zero result
	jbr	Lmovp_out
Lmovp_zero:
	movb	POSITIVE,(%r3)	#	otherwise, make result zero and positive
Lmovp_out:
	clrl	%r0
	argl(2,%r1)
	clrl	%r2
	argl(3,%r3)
	return

/*
 *	Definitions for Editpc instruction
 *
 *  Here are the commands and their corresponding hex values:
 *
 *	EPend		0x00
 *	EPend_float	0x01
 *	EPclear_signif	0x02
 *	EPset_signif	0x03
 *	EPstore_sign	0x04
 *	EPload_fill	0x40
 *	EPload_sign	0x41
 *	EPload_plus	0x42
 *	EPload_minus	0x43
 *	EPinsert	0x44
 *	EPblank_zero	0x45
 *	EPreplace_sign	0x46
 *	EPadjust_input	0x47
 *	EPfill		0x80
 *	EPmove		0x90
 *	EPfloat		0xa0
 *
 *
 *  r4 is carved up as follows:
 *
 *	-------------------------------------------
 *     |                                   N Z V C |
 *	-------------------------------------------
 *
 *	fill character is stuffed into arg5 space
 *	sign character is stuffed into arg6 space
 */

#define SIGNIFBIT	$0
#define setsignif	bisl2	$1,%r4
#define clsignif	bicl2	$1,%r4
#define OVERFLOWBIT	$1
#define setoverflow	bisl2	$2,%r4
#define cloverflow	bicl2	$2,%r4
#define ZEROBIT		$2
#define setzero		bisl2	$4,%r4
#define clzero		bicl2	$4,%r4
#define NEGATIVEBIT	$3
#define setnegative	bisl2	$8,%r4
#define clnegative	bicl2	$8,%r4
#define putfill		movb	arg5,(%r5)+
#define setfill(reg)	movb	reg,arg5
#define putsign		movb	arg6,(%r5)+
#define setsign(reg)	movb	reg,arg6

	_ALIGN_TEXT
ALTENTRY(EMeditpc)
	arguw(1,%r11)		# (1) source length == r11
	argl(2,%r10)		# (2) source address == r10
	argl(3,%r3)		# (3) pattern address == r3
	argl(4,%r5)		# (4) destination address == r5
/*		# we will need arg1 and arg2 later */
/*		# arg5 and arg6 are used for fill and sign - r0 is free */
	setfill($32)		# fill character is ' '
	setsign($32)		# sign character is ' '
	clrl	%r4		# clear flags
	ashl	$-1,%r11,%r11	# source length / 2
	addl3	%r11,%r10,%r2
	extzv	$4,$4,(%r2),%r1	# r1 == least significant nibble of source
L169:
	cmpl	%r2,%r10
	jeql	L170
	tstb	-(%r2)		# loop over source packed decimal number
	jeql	L169
	incl	%r1		# r1 is non-zero if source is non-zero
L170:
	addl3	%r11,%r10,%r2
	tstl	%r1
	jeql	L172		# source is zero - set flags
	extzv	$0,$4,(%r2),%r11
	cmpl	%r11,NEGATIVEalt
	jeql	L9998		# source is negative - set sign and flags
	cmpl	%r11,NEGATIVE
	jneq	L175
L9998:
	setnegative
	setsign($45)		# sign character is '-'
	jbr	L175
L172:
	setzero
L175:
	arguw(1,%r2)		# (1) source length == r2
Ledit_case:
	movzbl	(%r3)+,%r11	# get next edit command (pattern)
	cmpl	%r11,$128
	jlss	L180
	extzv	$0,$4,%r11,%r1	# command has a "count" arg - into r1
	ashl	$-4,%r11,%r11	# and shift over
L180:
	jbc	$6,%r11,L181	# "shift" those commands > 64 to 16 and up
	subl2	$48,%r11
L181:
	caseb	%r11,$0,$0x18	# "do" the command
				# r11 is available for use, r1 has "count" in it
Lcaseb_label:
	.word	Le_end - Lcaseb_label		# 00
	.word	Le_end_float - Lcaseb_label	# 01
	.word	Le_clear_signif - Lcaseb_label	# 02
	.word	Le_set_signif - Lcaseb_label	# 03
	.word	Le_store_sign - Lcaseb_label	# 04
	.word	Le_end - Lcaseb_label		# 05
	.word	Le_end - Lcaseb_label		# 06
	.word	Le_end - Lcaseb_label		# 07
	.word	Le_fill - Lcaseb_label		# 80
	.word	Le_move - Lcaseb_label		# 90
	.word	Le_float - Lcaseb_label		# a0
	.word	Le_end - Lcaseb_label		# b0
	.word	Le_end - Lcaseb_label		# c0
	.word	Le_end - Lcaseb_label		# d0
	.word	Le_end - Lcaseb_label		# e0
	.word	Le_end - Lcaseb_label		# f0
	.word	Le_load_fill - Lcaseb_label	# 40
	.word	Le_load_sign - Lcaseb_label	# 41
	.word	Le_load_plus - Lcaseb_label	# 42
	.word	Le_load_minus - Lcaseb_label	# 43
	.word	Le_insert - Lcaseb_label	# 44
	.word	Le_blank_zero - Lcaseb_label	# 45
	.word	Le_replace_sign - Lcaseb_label	# 46
	.word	Le_adjust_input - Lcaseb_label	# 47
Le_end:
	arguw(1,%r0)
	argl(2,%r1)
	clrl	%r2
	decl	%r3
	setpsl(%r4)
	clrl	%r4
	return

Le_end_float:
	jbs	SIGNIFBIT,%r4,Ledit_case # if significance not set
	putsign				# drop in the sign
					# fall into...
Le_set_signif:
	setsignif
	jbr	Ledit_case

Le_clear_signif:
	clsignif
	jbr	Ledit_case

Le_store_sign:
	putsign
	jbr	Ledit_case

Le_load_fill:
	setfill((%r3)+)
	jbr	Ledit_case

Le_load_plus:
	jbs	NEGATIVEBIT,%r4,Lpattern_inc	# if non-negative
					# fall into...
Le_load_sign:
	setsign((%r3)+)
	jbr	Ledit_case

Le_load_minus:
	jbs	NEGATIVEBIT,%r4,Le_load_sign	# if negative load the sign
	incl	%r3			# else increment pattern
	jbr	Ledit_case

Le_insert:
	jbc	SIGNIFBIT,%r4,L196	# if significance set, put next byte
	movb	(%r3)+,(%r5)+
	jbr	Ledit_case
L196:					# else put in fill character
	putfill
					# and throw away character in pattern
Le_replace_sign:			# we dont do anything with
Lpattern_inc:				# replace sign cause we dont
	incl	%r3			# get negative zero
	jbr	Ledit_case

Le_blank_zero:
	jbc	ZEROBIT,%r4,Lpattern_inc # if zero
	movzbl	(%r3)+,%r11		# next byte is a count
	jeql	Ledit_case
	subl2	%r11,%r5		# to back up over output and replace
L200:
	putfill				# with fill character
	sobgtr	%r11,L200
	jbr	Ledit_case

Le_adjust_input:
	movzbl	(%r3)+,%r0		# get count of nibbles from pattern
	subl3	%r2,%r0,%r11
	jgeq	Ledit_case		# if length of source is > this number
L204:					# discard digits in source
	jlbc	%r2,L206		# use low bit of length to choose nibble
	bitb	$0xf0,(%r10)		# high nibble
	jeql	L208
	setsignif			# set significance and overflow if
	setoverflow			#    wasted digit is non-zero
	jbr	L208
L206:
	bitb	$0xf,(%r10)		# low nibble
	jeql	L209
	setsignif
	setoverflow
L209:
	incl	%r10			# increment to next byte
L208:
	decl	%r2			# decrement source length
	incl	%r11			# continue till were out of excess
	jlss	L204
	jbr	Ledit_case

Le_fill:
	tstl	%r1			# put (count in r1) fill characters
	jeql	Ledit_case
Le_fill_loop:
	putfill
	sobgtr	%r1,Le_fill_loop
	jbr	Ledit_case

Le_move:
	tstl	%r1			# move (count in r1) characters
	jeql	Ledit_case		# from source to destination
L214:
	jlbc	%r2,L215		# read a nibble
	extzv	$4,$4,(%r10),%r11
	jbr	L216
L215:
	extzv	$0,$4,(%r10),%r11
	incl	%r10
L216:
	decl	%r2			# source length CAN go negative here...
	tstl	%r11
	jeql	L218			# if non-zero
	setsignif			# set significance
L218:
	jbc	SIGNIFBIT,%r4,L219	# if significance set
	addb3	$48,%r11,(%r5)+		# put 0 + digit into destination
	jbr	L220
L219:					# else put fill character
	putfill
L220:
	sobgtr	%r1,L214
	jbr	Ledit_case

Le_float:				# move with floating sign character
	tstl	%r1
	jeql	Ledit_case
L221:
	jlbc	%r2,L222
	extzv	$4,$4,(%r10),%r11
	jbr	L223
L222:
	extzv	$0,$4,(%r10),%r11
	incl	%r10
L223:
	decl	%r2			# source length CAN go negative here...
	tstl	%r11
	jeql	L225
	jbs	SIGNIFBIT,%r4,L226
	putsign
L226:
	setsignif
L225:
	jbc	SIGNIFBIT,%r4,L227
	addb3	$48,%r11,(%r5)+
	jbr	L228
L227:
	putfill
L228:
	sobgtr	%r1,L221
	jbr	Ledit_case

	_ALIGN_TEXT
ALTENTRY(EMashp)
	argb(1,%r11)		# (1) scale (number to shift) == r11
	arguw(2,%r10)		# (2) source length == r10
	argl(3,%r1)		# (3) source address == r1
	argub(4,%r2)		# (4) rounding factor == r2
	arguw(5,%r3)		# (5) destination length == r3
	toarg(%r6,3)/* 	# arg3 holds register 6 from caller */
	argl(6,%r6)		# (6) destination address == r6
/*
			# we need arg6 for later
			# arg1 is used for temporary storage
			# arg2 holds "even or odd" destination length
			# arg4 is used as general storage
			# arg5 is used as general storage
*/
	ashl	$-1,%r3,%r0	# destination length is number of bytes
	addl2	%r0,%r6		# destination address == least sig nibble
	toarg(%r6,1)		# save in arg1 spot for later
	ashl	$-1,%r10,%r0
	addl2	%r0,%r1		# source address == least sig nibble
	extzv	$0,$4,(%r1),%r0	# determine sign of source
	cmpl	%r0,NEGATIVEalt
	jeql	Lashp_neg
	cmpl	%r0,NEGATIVE
	jeql	Lashp_neg
	movb	POSITIVE,(%r6)
	jbr	L245
Lashp_neg:
	movb	NEGATIVE,(%r6)
L245:
	clrl	arg2		# arg2 is 1 if dstlen is even, 0 if odd
	blbs	%r3,L246
	incl	arg2
	bisl2	$1,%r3		# r3<0> counts digits going into destination
L246:				#	and is flip-flop for which nibble to
	tstl	%r11		#	write in destination (1 = high, 0 = low)
	jgeq	Lashp_left	#	(it must start out odd)
	addl2	%r11,%r10	# scale is negative (right shift)
	jgeq	Lashp_right
	clrl	%r10		# test for shifting whole number out
	jbr	Lashp_setround
Lashp_right:
	divl3	$2,%r11,%r0
	addl2	%r0,%r1		# source address == MSNibble to be shifted off
	jlbc	%r11,L249
	extzv	$4,$4,(%r1),%r0
	addl2	%r0,%r2		# round = last nibble to be shifted off + round
	jbr	Lashp_setround
L249:
	extzv	$0,$4,(%r1),%r0
	addl2	%r0,%r2		# round = last nibble to be shifted off + round
Lashp_setround:			# r11<0> now is flip-flop for which nibble to
	incl	%r11		#    read from source (1 == high, 0 == low)
	cmpl	%r2,$9		# set rounding factor to one if nibble shifted
	jleq	Lashp_noround	#    off + round argument was 10 or greater
	movl	$1,%r2
	jbr	Lashp_shift
Lashp_zloop:
	jlbs	%r3,L257	# dont need to clear high nibble twice
	clrb	-(%r6)		# clear low (and high) nib of next byte in dest
L257:
	sobgtr	%r3,L258		# move to next nibble in destination, but
	incl	%r3		#	dont go beyond the end.
L258:
	decl	%r11
Lashp_left:			# while scale is positive
	jneq	Lashp_zloop
	incl	%r11		# r11<0> is flip-plop ... (incl sets it to one)
Lashp_noround:
	clrl	%r2		# no more rounding
Lashp_shift:
	clrl	arg4		# arg4 will be used for result condition codes
	tstl	%r10
	jeql	Lashp_round
Lashp_shloop:
	jlbc	%r11,L260
	extzv	$4,$4,(%r1),%r0
	jbr	L261
L260:
	decl	%r1
	extzv	$0,$4,(%r1),%r0
L261:
	incl	%r11		# flip the source nibble flip/flop
	addl2	%r0,%r2		# round += next nibble
	cmpl	%r2,$10		# if round == 10
	jneq	L262
	clrl	arg5		#	then result = 0 and round = 1
	movl	$1,%r2
	jbr	L263
L262:				# else
	movl	%r2,arg5	#	store result and round = 0
	clrl	%r2
L263:
	bisl2	arg5,arg4	# remember if result was nonzero in arg4
	decl	%r3		# move to next nibble early to check
	cmpl	%r3,arg2	# if weve moved passed destination limits
	jgeq	Lashp_noovfl	#	test the result for possible overflow
	movl	arg2,%r3	#	ignore zero nibbles
	tstl	arg5		#	if the nibble was non-zero, overflow
	jeql	L265
	jbr	Lashp_overfl
Lashp_noovfl:			# else
	jlbs	%r3,L264
	insv	arg5,$4,$4,(%r6) # put the result into destination (high or low)
	jbr	L265
L264:
	movb	arg5,-(%r6)
L265:
	sobgtr	%r10,Lashp_shloop	# loop for length of source

Lashp_round:
	tstl	%r2		# take care of round out of high nibble
	jeql	Lashp_zeroround
	decl	%r3
	cmpl	%r3,arg2	# if weve moved passed destination limits
	jlss	Lashp_overfl	#	then overflow
	jlbs	%r3,L266
	insv	arg5,$4,$4,(%r6) # put the round into destination (high or low)
	jbr	Lashp_zeroround
L266:
	movb	arg5,-(%r6)

Lashp_zeroround:
	argl(1,%r10)		# r10 = address of destination LSNibble
	argl(6,%r3)		# r3 = address of destination MSNibble
	movl	arg4,%r11	# r11 = non-zero if destination == non-zero
	savepsl
	jbr	L267
Lashp_zerofill:
	clrb	-(%r6)		# fill up MSNs of destination with zeros
L267:
	cmpl	%r3,%r6
	jneq	Lashp_zerofill
	extzv	$0,$4,(%r10),%r0 # test for negative result
	cmpl	%r0,NEGATIVE
	jneq	Lashp_out
	mnegl	%r11,%r11
	savepsl
	jneq	Lashp_out	# turn -0 into 0
	insv	POSITIVE,$0,$4,(%r10)
Lashp_out:
	clrl	%r0
	argl(3,%r6)		# restore r6 from stack
	return
Lashp_overfl:			#    do overflow
	clrl	%r2
	overflowpsl
	jbr	Lashp_out

	_ALIGN_TEXT
ALTENTRY(EMcvtlp)
	arguw(2,%r10)		# (2) destination length == r10
	argl(3,%r3)		# (3) destination address == r3
	ashl	$-1,%r10,%r10
	addl2	%r10,%r3	# destination address points to Least Sig byte
	incl	%r10		# length is # of bytes, not nibbles
	argl(1,%r11)		# (1) source == r11
	savepsl
	jgeq	Lcvtlp_pos
	movb	NEGATIVE,(%r3)	# source is negative
	divl3	$10,%r11,%r0
	mull3	$10,%r0,%r1
	subl3	%r11,%r1,%r2	# r2 = source mod 10
	mnegl	%r0,%r11	# source = -(source / 10)
	jbr	Lcvtlp_cvt
Lcvtlp_pos:
	movb	POSITIVE,(%r3)	# source is non-negative
	divl3	$10,%r11,%r0
	mull3	$10,%r0,%r1
	subl3	%r1,%r11,%r2	# r2 = source mod 10
	movl	%r0,%r11	# source = source / 10
Lcvtlp_cvt:
	insv	%r2,$4,$4,(%r3)	# store least significant digit
	tstl	%r11
	jeql	Lcvtlp_zloop
Lcvtlp_loop:			# while source is non-zero
	decl	%r10		#   and for length of destination ...
	jeql	Lcvtlp_over
	divl3	$10,%r11,%r1	# r1 = source / 10
	mull3	$10,%r1,%r0
	subl2	%r0,%r11	# source = source mod 10
	movb	%r11,-(%r3)	# store low "nibble" in next significant byte
	divl3	$10,%r1,%r11	# source = r1 / 10
	mull3	$10,%r11,%r0
	subl2	%r0,%r1		# r1 = source mod 10
	insv	%r1,$4,$4,(%r3)	# store high nibble
	tstl	%r11
	jneq	Lcvtlp_loop	# quit if source becomes zero
Lcvtlp_zloop:			# fill any remaining bytes with zeros
	decl	%r10
	jeql	Lcvtlp_out
	clrb	-(%r3)
	jbr	Lcvtlp_zloop
Lcvtlp_over:
	overflowpsl
Lcvtlp_out:
	clrl	%r1		# r0 is already zero
	clrl	%r2
	return

	_ALIGN_TEXT
ALTENTRY(EMcvtpl)
	arguw(1,%r11)		# (1) source length == r11
	argl(2,%r10)		# (2) source address == r10
	clrl	%r3		# r3 == destination
	movl	%r10,%r1	# r1 set up now for return
	ashl	$-1,%r11,%r11	# source length is number of bytes
	jeql	Lcvtpl_zero
Lcvtpl_loop:			# for source length
	mull2	$10,%r3		# destination *= 10
	extzv	$4,$4,(%r10),%r0
	addl2	%r0,%r3		# destination += high nibble
	mull2	$10,%r3		# destination *= 10
	extzv	$0,$4,(%r10),%r0
	addl2	%r0,%r3		# destination += low nibble
	incl	%r10
	sobgtr	%r11,Lcvtpl_loop
Lcvtpl_zero:			# least significant byte
	mull2	$10,%r3
	extzv	$4,$4,(%r10),%r0
	addl2	%r0,%r3		# dest = 10 * dest + high nibble
	savepsl
	extzv	$0,$4,(%r10),%r2 # test sign nibble
	cmpl	%r2,NEGATIVE
	jeql	Lcvtpl_neg
	cmpl	%r2,NEGATIVEalt
	jneq	Lcvtpl_out
Lcvtpl_neg:			# source was negative - negate destination
	mnegl	%r3,%r3
	savepsl
Lcvtpl_out:
	toarg(%r3,3)
	clrl	%r0
	clrl	%r2
	clrl	%r3
	return

	_ALIGN_TEXT
ALTENTRY(EMcvtps)
	return

	_ALIGN_TEXT
ALTENTRY(EMcvtsp)
	return

	_ALIGN_TEXT
ALTENTRY(EMaddp6)
	return

	_ALIGN_TEXT
ALTENTRY(EMsubp4)
	return

	_ALIGN_TEXT
ALTENTRY(EMsubp6)
	return

	_ALIGN_TEXT
ALTENTRY(EMcvtpt)
	return

	_ALIGN_TEXT
ALTENTRY(EMmulp)
	return

	_ALIGN_TEXT
ALTENTRY(EMcvttp)
	return

	_ALIGN_TEXT
ALTENTRY(EMdivp)
	return

	_ALIGN_TEXT
ALTENTRY(EMcmpp3)
	return

	_ALIGN_TEXT
ALTENTRY(EMcmpp4)
	return

#ifdef notdef
/*
 * Emulation OpCode jump table:
 *	ONLY GOES FROM 0xf8 (-8) TO 0x3B (59)
 */
#define EMUTABLE	0x43
#define NOEMULATE	.long noemulate
#define	EMULATE(a)	.long _C_LABEL(__CONCAT(EM,a))
	.globl	_C_LABEL(emJUMPtable)
_C_LABEL(emJUMPtable):
/* f8 */	EMULATE(ashp);	EMULATE(cvtlp);	NOEMULATE;	NOEMULATE
/* fc */	NOEMULATE;	NOEMULATE;	NOEMULATE;	NOEMULATE
/* 00 */	NOEMULATE;	NOEMULATE;	NOEMULATE;	NOEMULATE
/* 04 */	NOEMULATE;	NOEMULATE;	NOEMULATE;	NOEMULATE
/* 08 */	EMULATE(cvtps);	EMULATE(cvtsp);	NOEMULATE;	EMULATE(crc)
/* 0c */	NOEMULATE;	NOEMULATE;	NOEMULATE;	NOEMULATE
/* 10 */	NOEMULATE;	NOEMULATE;	NOEMULATE;	NOEMULATE
/* 14 */	NOEMULATE;	NOEMULATE;	NOEMULATE;	NOEMULATE
/* 18 */	NOEMULATE;	NOEMULATE;	NOEMULATE;	NOEMULATE
/* 1c */	NOEMULATE;	NOEMULATE;	NOEMULATE;	NOEMULATE
/* 20 */	EMULATE(addp4);	EMULATE(addp6);	EMULATE(subp4);	EMULATE(subp6)
/* 24 */	EMULATE(cvtpt);	EMULATE(mulp);	EMULATE(cvttp);	EMULATE(divp)
/* 28 */	NOEMULATE;	EMULATE(cmpc3);	EMULATE(scanc);	EMULATE(spanc)
/* 2c */	NOEMULATE;	EMULATE(cmpc5);	EMULATE(movtc);	EMULATE(movtuc)
/* 30 */	NOEMULATE;	NOEMULATE;	NOEMULATE;	NOEMULATE
/* 34 */	EMULATE(movp);	EMULATE(cmpp3);	EMULATE(cvtpl);	EMULATE(cmpp4)
/* 38 */	EMULATE(editpc); EMULATE(matchc); EMULATE(locc); EMULATE(skpc)

/*
 * The following is called with the stack set up as follows:
 *
 *	  (sp):	Opcode
 *	 4(sp):	Instruction PC
 *	 8(sp):	Operand 1
 *	12(sp):	Operand 2
 *	16(sp):	Operand 3
 *	20(sp):	Operand 4
 *	24(sp):	Operand 5
 *	28(sp):	Operand 6
 *	32(sp):	Operand 7 (unused)
 *	36(sp):	Operand 8 (unused)
 *	40(sp):	Return PC
 *	44(sp):	Return PSL
 *	48(sp): TOS before instruction
 *
 * Each individual routine is called with the stack set up as follows:
 *
 *	  (sp):	Return address of trap handler
 *	 4(sp):	Opcode (will get return PSL)
 *	 8(sp):	Instruction PC
 *	12(sp):	Operand 1
 *	16(sp):	Operand 2
 *	20(sp):	Operand 3
 *	24(sp):	Operand 4
 *	28(sp):	Operand 5
 *	32(sp):	Operand 6
 *	36(sp):	saved register 11
 *	40(sp):	saved register 10
 *	44(sp):	Return PC
 *	48(sp):	Return PSL
 *	52(sp): TOS before instruction
 */

SCBVEC(emulate):
	movl	%r11,32(%sp)		# save register r11 in unused operand
	movl	%r10,36(%sp)		# save register r10 in unused operand
	cvtbl	(%sp),%r10		# get opcode
	addl2	$8,%r10			# shift negative opcodes
	subl3	%r10,$EMUTABLE,%r11	# forget it if opcode is out of range
	bcs	noemulate
	movl	_C_LABEL(emJUMPtable)[%r10],%r10
					# call appropriate emulation routine
	jsb	(%r10)		# routines put return values into regs 0-5
	movl	32(%sp),%r11		# restore register r11
	movl	36(%sp),%r10		# restore register r10
	insv	(%sp),$0,$4,44(%sp)	# and condition codes in Opcode spot
	addl2	$40,%sp			# adjust stack for return
	rei
noemulate:
	addl2	$48,%sp			# adjust stack for
	.word	0xffff			# "reserved instruction fault"
SCBVEC(emulateFPD):
	.word	0xffff			# "reserved instruction fault"
#endif


code:
/*	$OpenBSD: findcpu.c,v 1.16 2011/09/19 21:53:02 miod Exp $	*/
/*	$NetBSD: findcpu.c,v 1.5 1999/08/23 19:10:43 ragge Exp $	*/
/*
 * Copyright (c) 1994, 1998 Ludd, University of Lule}, Sweden.
 * 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.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *     This product includes software developed at Ludd, University of Lule}.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * 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.
 */

#include <sys/param.h>
#include <sys/device.h>

#include <machine/sid.h>
#include <machine/nexus.h>
#include <machine/mtpr.h>
#include <machine/cpu.h>
#include <machine/cvax.h>

/*
 * We set up some information about the machine we're
 * running on and thus initializes/uses vax_cputype and vax_boardtype.
 * There should be no need to change/reinitialize these variables
 * outside of this routine, they should be read only!
 */
int vax_cputype;	/* highest byte of SID register */
int vax_cpustype;	/* second byte of SIE register */
int vax_bustype;	/* holds/defines the main bus type on this machine */
int vax_boardtype;	/* machine dependent, combination of SID and SIE */

int vax_cpudata = 0;	/* contents of the SID register */
int vax_siedata = 0;	/* contents of the SIE register */
int vax_confdata;	/* machine dependent, configuration/setup data */

void	findcpu(void);

/*
 * Try to figure out which type of system this is.
 */
void
findcpu(void)
{
	vax_cpudata = mfpr(PR_SID);
	vax_cputype = vax_cpudata >> 24;
	vax_boardtype = vax_cputype << 24;

	switch (vax_cputype) {
	case VAX_TYP_UV2:
	case VAX_TYP_CVAX:
	case VAX_TYP_RIGEL:
	case VAX_TYP_MARIAH:
	case VAX_TYP_NVAX:
	case VAX_TYP_SOC:
		vax_siedata = *(int *)(0x20040004);	/* SIE address */
		vax_cpustype = (vax_siedata >> 8) & 0xff;
		vax_boardtype |= vax_siedata >> 24;

		switch (vax_boardtype) {
		case VAX_BTYP_420: /* They are very similar */
		case VAX_BTYP_410:
		case VAX_BTYP_43:
		case VAX_BTYP_46:
		case VAX_BTYP_48:
		case VAX_BTYP_IS1:
			vax_confdata = *(int *)(0x20020000);
			vax_bustype = VAX_VSBUS;
			break;
		case VAX_BTYP_49:
			vax_confdata = *(int *)(0x25800000);
			vax_bustype = VAX_VSBUS;
			break;
		case VAX_BTYP_VXT:
			vax_confdata = *(int *)(0x200c0000);
			vax_bustype = VAX_VXTBUS;
			break;

		case VAX_BTYP_60:
			vax_confdata =
			    ((struct cvax_ssc *)CVAX_SSC)->ssc_terminfo;
			vax_bustype = VAX_MBUS;
			break;

		case VAX_BTYP_630:
		case VAX_BTYP_650:
		case VAX_BTYP_660:
		case VAX_BTYP_670:
		case VAX_BTYP_1301:
		case VAX_BTYP_1303:
		case VAX_BTYP_1305:
			vax_bustype = VAX_IBUS;
			break;

		default:
			/* CPU not supported, just give up */
			asm("halt");
		}
		break;

	default:
		/* CPU not supported, just give up */
		asm("halt");
	}
}

license: unknown


code:
#	$OpenBSD: genassym.cf,v 1.12 2013/11/24 22:08:25 miod Exp $
#	$NetBSD: genassym.cf,v 1.10 1999/11/19 22:09:55 ragge Exp $
#
# Copyright (c) 1997 Ludd, University of Lule}, Sweden.
# 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.
# 3. All advertising materials mentioning features or use of this software
#    must display the following acknowledgement:
#      This product includes software developed at Ludd, University of
#      Lule}, Sweden and its contributors.
# 4. The name of the author may not be used to endorse or promote products
#    derived from this software without specific prior written permission
#
# 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.
#

include	<sys/param.h>
include	<sys/proc.h>
include	<sys/errno.h>
include	<sys/syscall.h>
include	<sys/evcount.h>

include	<machine/mtpr.h>
include	<machine/pcb.h>
include	<machine/sid.h>
include	<machine/trap.h>
include	<machine/cpu.h>

struct	proc
member	p_priority
member	p_addr
member	p_vmspace
member	p_stat

export	SONPROC

struct	pcb
member	P0BR
member	P0LR
member	P1BR
member	P1LR
member	iftrap
member	pcb_paddr

struct	cpu_dep
member	MCHK		cpu_mchk
member	MEMERR		cpu_memerr
member	HARDCLOCK	cpu_hardclock

struct	cpu_info
member	ci_curproc

export	KERNBASE

# mtpr register numbers
export	PR_KSP
export	PR_USP
export	PR_ICCS
export	PR_PCBB
export	PR_IPL
export	PR_SBIFS
export	PR_EHSR
export	PR_MCESR
export	PR_P0BR
export	PR_P1BR
export	PR_P0LR
export	PR_P1LR
export	PR_SCBB

# trap numbering
export	T_KSPNOTVAL
export	T_PRIVINFLT
export	T_XFCFLT
export	T_RESOPFLT
export	T_RESADFLT
export	T_TRANSFLT
export	T_PTEFETCH
export	T_WRITE
export	T_ACCFLT
export	T_PTELEN
export	T_TRCTRAP
export	T_BPTFLT
export	T_ARITHFLT
export	T_SYSCALL
export	T_ASTFLT
export	T_KDBTRAP

export	USPACE

export	EFAULT
export	ENAMETOOLONG

struct	evcount
member	ec_count

export	SYS_sigreturn
export	SYS_exit

export	VAX_TYP_SOC
export	VAX_TYP_UV2


code:
/*	$OpenBSD: gencons.c,v 1.24 2011/07/06 18:32:59 miod Exp $	*/
/*	$NetBSD: gencons.c,v 1.22 2000/01/24 02:40:33 matt Exp $	*/

/*
 * Copyright (c) 1994 Gordon W. Ross
 * Copyright (c) 1994 Ludd, University of Lule}, Sweden.
 * 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.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *     This product includes software developed at Ludd, University of Lule}.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * 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.
 *
 *	kd.c,v 1.2 1994/05/05 04:46:51 gwr Exp $
 */

 /* All bugs are subject to removal without further notice */

#include <sys/param.h>
#include <sys/proc.h>
#include <sys/systm.h>
#include <sys/ioctl.h>
#include <sys/tty.h>
#include <sys/file.h>
#include <sys/conf.h>
#include <sys/device.h>
#include <sys/reboot.h>

#include <dev/cons.h>

#include <machine/mtpr.h>
#include <machine/sid.h>
#include <machine/cpu.h>
#include <machine/scb.h>
#include <machine/../vax/gencons.h>

struct tty *gencn_tty[4];

int consopened = 0;
int maxttys = 1;

int pr_txcs[4] = {PR_TXCS, PR_TXCS1, PR_TXCS2, PR_TXCS3};
int pr_rxcs[4] = {PR_RXCS, PR_RXCS1, PR_RXCS2, PR_RXCS3};
int pr_txdb[4] = {PR_TXDB, PR_TXDB1, PR_TXDB2, PR_TXDB3};
int pr_rxdb[4] = {PR_RXDB, PR_RXDB1, PR_RXDB2, PR_RXDB3};

cons_decl(gen);
cdev_decl(gencn);

int gencnparam(struct tty *, struct termios *);
void gencnstart(struct tty *);
void gencnrint(void *);
void gencntint(void *);

int
gencnopen(dev, flag, mode, p)
	dev_t	dev;
	int	flag, mode;
	struct proc *p;
{
	int unit;
	struct tty *tp;

	unit = minor(dev);
	if (unit >= maxttys)
		return ENXIO;

	if (gencn_tty[unit] == NULL)
		gencn_tty[unit] = ttymalloc(0);

	tp = gencn_tty[unit];

	tp->t_oproc = gencnstart;
	tp->t_param = gencnparam;
	tp->t_dev = dev;
	if ((tp->t_state & TS_ISOPEN) == 0) {
		ttychars(tp);
		tp->t_iflag = TTYDEF_IFLAG;
		tp->t_oflag = TTYDEF_OFLAG;
		tp->t_cflag = TTYDEF_CFLAG;
		tp->t_lflag = TTYDEF_LFLAG;
		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
		gencnparam(tp, &tp->t_termios);
		ttsetwater(tp);
	} else if (tp->t_state & TS_XCLUDE && suser(p, 0) != 0)
		return EBUSY;
	tp->t_state |= TS_CARR_ON;
	if (unit == 0)
		consopened = 1;
	mtpr(GC_RIE, pr_rxcs[unit]); /* Turn on interrupts */
	mtpr(GC_TIE, pr_txcs[unit]);

        return ((*linesw[tp->t_line].l_open)(dev, tp, p));
}

int
gencnclose(dev, flag, mode, p)
        dev_t dev;
        int flag, mode;
        struct proc *p;
{
	struct tty *tp = gencn_tty[minor(dev)];

	if (minor(dev) == 0)
		consopened = 0;
	(*linesw[tp->t_line].l_close)(tp, flag, p);
	ttyclose(tp);
	return (0);
}

struct tty *
gencntty(dev_t dev)
{
	return gencn_tty[minor(dev)];
}

int
gencnread(dev_t dev, struct uio *uio, int flag)
{
	struct tty *tp = gencn_tty[minor(dev)];

	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
}

int
gencnwrite(dev_t dev, struct uio *uio, int flag)
{
	struct tty *tp = gencn_tty[minor(dev)];

	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
}

int
gencnioctl(dev, cmd, data, flag, p)
        dev_t dev;
        u_long cmd;
        caddr_t data;
        int flag;
        struct proc *p;
{
	struct tty *tp = gencn_tty[minor(dev)];
	int error;

	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
	if (error >= 0)
		return error;
	error = ttioctl(tp, cmd, data, flag, p);
	if (error >= 0)
		return error;

	return ENOTTY;
}

void
gencnstart(struct tty *tp)
{
	struct clist *cl;
	int s, ch;

	s = spltty();
	if (tp->t_state & (TS_BUSY|TS_TTSTOP|TS_TIMEOUT))
		goto out;
	cl = &tp->t_outq;

	if(cl->c_cc){
		tp->t_state |= TS_BUSY;
		ch = getc(cl);
		mtpr(ch, pr_txdb[minor(tp->t_dev)]);
	} else {
		if (tp->t_state & TS_ASLEEP) {
			tp->t_state &= ~TS_ASLEEP;
			wakeup((caddr_t)cl);
		}
		selwakeup(&tp->t_wsel);
	}

out:	splx(s);
}

void
gencnrint(void *arg)
{
	struct tty *tp = *(struct tty **) arg;
	int unit = (struct tty **) arg - gencn_tty;
	int i;

	i = mfpr(pr_rxdb[unit]) & 0377; /* Mask status flags etc... */

#ifdef DDB
	if (tp->t_dev == cn_tab->cn_dev) {
		int j = kdbrint(i);

		if (j == 1)	/* Escape received, just return */
			return;

		if (j == 2)	/* Second char wasn't 'D' */
			(*linesw[tp->t_line].l_rint)(27, tp);
	}
#endif

	(*linesw[tp->t_line].l_rint)(i, tp);
	return;
}

int
gencnstop(struct tty *tp, int flag)
{
	return 0;
}

void
gencntint(void *arg)
{
	struct tty *tp = *(struct tty **) arg;

	tp->t_state &= ~TS_BUSY;

	gencnstart(tp);
}

int
gencnparam(struct tty *tp, struct termios *t)
{
	/* XXX - These are ignored... */
	tp->t_ispeed = t->c_ispeed;
	tp->t_ospeed = t->c_ospeed;
	tp->t_cflag = t->c_cflag;
	return 0;
}

void
gencnprobe(struct consdev *cndev)
{
	if ((vax_cputype < VAX_TYP_UV2) || /* All older has MTPR console */
	    (vax_boardtype == VAX_BTYP_9RR) ||
	    (vax_boardtype == VAX_BTYP_630) ||
	    (vax_boardtype == VAX_BTYP_650) ||
	    (vax_boardtype == VAX_BTYP_660) ||
	    (vax_boardtype == VAX_BTYP_670) ||
	    (vax_boardtype == VAX_BTYP_1301) ||
	    (vax_boardtype == VAX_BTYP_1305)) {
		cndev->cn_dev = makedev(25, 0);
		cndev->cn_pri = CN_LOWPRI;
	}
}

void
gencninit(struct consdev *cndev)
{

	/* Allocate interrupt vectors */
	scb_vecalloc(SCB_G0R, gencnrint, &gencn_tty[0], SCB_ISTACK, NULL);
	scb_vecalloc(SCB_G0T, gencntint, &gencn_tty[0], SCB_ISTACK, NULL);

	if (vax_cputype == VAX_TYP_8SS) {
		maxttys = 4;
		scb_vecalloc(SCB_G1R, gencnrint, &gencn_tty[1], SCB_ISTACK, NULL);
		scb_vecalloc(SCB_G1T, gencntint, &gencn_tty[1], SCB_ISTACK, NULL);

		scb_vecalloc(SCB_G2R, gencnrint, &gencn_tty[2], SCB_ISTACK, NULL);
		scb_vecalloc(SCB_G2T, gencntint, &gencn_tty[2], SCB_ISTACK, NULL);

		scb_vecalloc(SCB_G3R, gencnrint, &gencn_tty[3], SCB_ISTACK, NULL);
		scb_vecalloc(SCB_G3T, gencntint, &gencn_tty[3], SCB_ISTACK, NULL);
	}
	mtpr(0, PR_RXCS);
	mtpr(0, PR_TXCS);
	mtpr(0, PR_TBIA); /* ??? */
}

void
gencnputc(dev_t dev, int ch)
{
	while ((mfpr(PR_TXCS) & GC_RDY) == 0) /* Wait until xmit ready */
		;
	mtpr(ch, PR_TXDB);	/* xmit character */
	if(ch == 10)
		gencnputc(dev, 13); /* CR/LF */

}

int
gencngetc(dev_t dev)
{
	int i;

	while ((mfpr(PR_RXCS) & GC_DON) == 0) /* Receive chr */
		;
	i = mfpr(PR_RXDB) & 0x7f;
	if (i == 13)
		i = 10;
	return i;
}

void
gencnpollc(dev_t dev, int pollflag)
{
	if (pollflag)  {
		mtpr(0, PR_RXCS);
		mtpr(0, PR_TXCS);
	} else if (consopened) {
		mtpr(GC_RIE, PR_RXCS);
		mtpr(GC_TIE, PR_TXCS);
	}
}


code:
/*	$OpenBSD: gencons.h,v 1.6 2011/07/06 18:32:59 miod Exp $ */
/*	$NetBSD: gencons.h,v 1.9 2000/01/20 00:07:49 matt Exp $ */

/*
 * Copyright (c) 1994 Ludd, University of Lule}, Sweden.
 * 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.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *     This product includes software developed at Ludd, University of Lule}.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * 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.
 *
 */

 /* All bugs are subject to removal without further notice */

/*
 * Some definitions for generic console interface (PR 32-35)
 */

/* PR_TXCS */
#define	GC_RDY	0x80	/* Console ready to xmit chr */
#define	GC_TIE	0x40	/* xmit interrupt enable */

/* PR_RXCS */
#define	GC_DON	0x80	/* character received */
#define	GC_RIE	0x40	/* recv interrupt enable */

/* PR_RXDB */
#define	GC_ERR	0x8000	/* received character error */
#define	GC_CON	0xf00	/* mfpr($PR_RXDB)&GC_CON==0 then console chr */

/* PR_TXDB */
#define	GC_CONS	0xf00	/* Console software !8600 */
#define	GC_BTFL	0x2	/* boot machine */
#define	GC_CWFL	0x3	/* clear warm start flag */
#define	GC_CCFL	0x4	/* clear cold start flag */

/* Interrupt vectors used */
#define	SCB_G0R	0xf8
#define	SCB_G0T	0xfc
#define	SCB_G1R	0xc8
#define	SCB_G1T	0xcc
#define	SCB_G2R	0xd0
#define	SCB_G2T	0xd4
#define	SCB_G3R	0xd8
#define	SCB_G3T	0xdc

/* Prototypes */
void	gencnputc(dev_t, int);


code:
/*	$OpenBSD: ibus.c,v 1.9 2011/09/19 21:53:02 miod Exp $	*/
/*	$NetBSD: ibus.c,v 1.7 2001/02/04 20:36:32 ragge Exp $ */
/*
 * Copyright (c) 1999 Ludd, University of Lule}, Sweden.
 * 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.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed at Ludd, University of
 *	Lule}, Sweden and its contributors.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * 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.
 */

#include <sys/param.h>
#include <sys/device.h>
#include <sys/systm.h>

#include <machine/nexus.h>
#include <machine/cpu.h>
#include <machine/sid.h>

static	int ibus_print(void *, const char *);
static	int ibus_match(struct device *, struct cfdata *, void *);
static	void ibus_attach(struct device *, struct device *, void *);

struct	cfdriver ibus_cd = {
	NULL, "ibus", DV_DULL
};

struct	cfattach ibus_ca = {
	sizeof(struct device), (cfmatch_t)ibus_match, ibus_attach
};

int
ibus_print(void *aux, const char *name)
{
	struct bp_conf *bp = aux;

	if (name)
		printf("%s at %s", bp->type, name);

	return (UNCONF);
}

int
ibus_match(struct device *parent, struct cfdata *cf, void *aux)
{
	struct mainbus_attach_args *maa = aux;

	if (maa->maa_bustype == VAX_IBUS)
		return 1;
	return 0;
}

#define	MVNIADDR	0x20084400
#define	SGECADDR	0x20008000
#define	SHACADDR	0x20004200
#define	SHAC1303ADDR	0x20008200

void
ibus_attach(parent, self, aux)
	struct	device	*parent, *self;
	void	*aux;
{
	struct bp_conf bp;
	vaddr_t va;

	printf("\n");

	/*
	 * There may be a SGEC. Is badaddr() enough here?
	 */
	bp.type = "sgec";
	va = vax_map_physmem(SGECADDR, 1);
	if (badaddr((caddr_t)va, 4) == 0)
		config_found(self, &bp, ibus_print);
	vax_unmap_physmem(va, 1);

	/*
	 * There may be a LANCE.
	 */
	bp.type = "lance";
	va = vax_map_physmem(MVNIADDR, 1);
	if (badaddr((caddr_t)va, 2) == 0)
		config_found(self, &bp, ibus_print);
	vax_unmap_physmem(va, 1);

	/*
	 * The same procedure for SHAC.
	 */
	bp.type = "shac";
	/*
	 * XXX Clearly the address on Cheetah machines varies between models,
	 * XXX but I could only check the address on a 4000 106 so far. -- miod
	 */
	if (vax_boardtype == VAX_BTYP_1303 && vax_cpustype != VAX_STYP_53)
		va = vax_map_physmem(SHAC1303ADDR, 1);
	else
		va = vax_map_physmem(SHACADDR, 1);
	if (badaddr((caddr_t)va + 0x48, 4) == 0)
		config_found(self, &bp, ibus_print);
	vax_unmap_physmem(va, 1);

	/*
	 * All MV's have a Qbus.
	 */
	bp.type = "uba";
	config_found(self, &bp, ibus_print);

}


code:
/*	$OpenBSD: in4_cksum.c,v 1.6 2014/08/21 14:24:08 mpi Exp $	*/
/*	$NetBSD: in4_cksum.c,v 1.8 2003/09/29 22:54:28 matt Exp $	*/

/*
 * Copyright (C) 1999 WIDE Project.
 * 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.
 * 3. Neither the name of the project nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``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 PROJECT OR CONTRIBUTORS 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.
 */

/*
 * Copyright (c) 1988, 1992, 1993
 *	The Regents of the University of California.  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.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
 *
 *	@(#)in_cksum.c	8.1 (Berkeley) 6/10/93
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
#include <sys/socketvar.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_var.h>

#ifdef CKSUMDEBUG
int in4_cksum_md_debug(struct mbuf *m, u_int8_t nxt, int off, int len);
#define	in4_cksum in4_cksum_md_debug
#include <netinet/in4_cksum.c>
#undef in4_cksum
#undef ADDCARRY
#undef REDUCE
#endif

/*
 * Checksum routine for Internet Protocol family headers.
 * This is only for IPv4 pseudo header checksum.
 * No need to clear non-pseudo-header fields in IPv4 header.
 * len is for actual payload size, and does not include IPv4 header and
 * skipped header chain (off + len should be equal to the whole packet).
 *
 * This implementation is VAX version.
 */

#define REDUCE		{sum = (sum & 0xffff) + (sum >> 16);}
#define ADDCARRY	{if (sum > 0xffff) sum -= 0xffff;}
#define ADVANCE(n)	{w += n; mlen -= n;}
#define SWAP		{sum <<= 8;}		/* depends on recent REDUCE */

#define Asm     __asm volatile
#define ADDL    Asm("addl2 (%2)+,%0" : "=r" (sum) : "0" (sum), "r" (w))
#define ADWC    Asm("adwc  (%2)+,%0" : "=r" (sum) : "0" (sum), "r" (w))
#define ADDC    Asm("adwc     $0,%0" : "=r" (sum) : "0" (sum))
#define UNSWAP  Asm("rotl  $8,%0,%0" : "=r" (sum) : "0" (sum))
#define ADDBYTE	{sum += *w; SWAP; byte_swapped ^= 1;}
#define ADDWORD	{sum += *(u_short *)w;}

int
in4_cksum(struct mbuf *m, u_int8_t nxt, int off, int len)
{
	u_int8_t *w;
	u_int32_t sum = 0;
	int mlen = 0;
	int byte_swapped = 0;
#ifdef CKSUMDEBUG
	int debugrv = in4_cksum_md_debug(m, nxt, off, len);
#endif

	if (nxt != 0) {
#ifdef DEBUG
		if (off < sizeof(struct ipovly))
			panic("in4_cksum: offset too short");
		if (m->m_len < sizeof(struct ip))
			panic("in4_cksum: bad mbuf chain");
#endif

		__asm volatile(
			"movzwl	%3,%0;"	/* mov len to sum */
			"addb2	%4,%0;"	/* add proto to sum */
			"rotl	$8,%0,%0;"	/* htons, carry is preserved */
			"adwc	12(%2),%0;"	/* add src ip */
			"adwc	16(%2),%0;"	/* add dst ip */
			"adwc	$0,%0;"		/* clean up carry */
			: "=r" (sum)
			: "0" (sum), "r" (mtod(m, void *)), "r" (len), "r"(nxt));
	}

	/* skip unnecessary part */
	while (m && off > 0) {
		if (m->m_len > off)
			break;
		off -= m->m_len;
		m = m->m_next;
	}

	for (;m && len; m = m->m_next) {
		if ((mlen = m->m_len) == 0)
			continue;
		w = mtod(m, u_int8_t *);
		if (off) {
			w += off;
			mlen -= off;
			off = 0;
		}
		if (len < mlen)
			mlen = len;
		len -= mlen;
		if (mlen < 16)
			goto short_mbuf;
		/*
		 * Ensure that we're aligned on a word boundary here so
		 * that we can do 32 bit operations below.
		 */
		if ((3 & (u_long) w) != 0) {
			REDUCE;
			if ((1 & (u_long) w) != 0) {
				ADDBYTE;
				ADVANCE(1);
			}
			if ((2 & (u_long) w) != 0) {
				ADDWORD;
				ADVANCE(2);
			}
		}
		/*
		 * Do as much of the checksum as possible 32 bits at at time.
		 * In fact, this loop is unrolled to make overhead from
		 * branches &c small.
		 */
		while ((mlen -= 32) >= 0) {
			/*
			 * Add with carry 16 words and fold in the last carry
			 * by adding a 0 with carry.
			 */
			ADDL;	ADWC;	ADWC;	ADWC;
			ADWC;	ADWC;	ADWC;	ADWC;
			ADDC;
		}
		mlen += 32;
		if (mlen >= 16) {
			ADDL;	ADWC;	ADWC;	ADWC;
			ADDC;
			mlen -= 16;
		}
	short_mbuf:
		if (mlen >= 8) {
			ADDL;	ADWC;
			ADDC;
			mlen -= 8;
		}
		if (mlen >= 4) {
			ADDL;
			ADDC;
			mlen -= 4;
		}
		if (mlen > 0) {
			REDUCE;
			if (mlen >= 2) {
				ADDWORD;
				ADVANCE(2);
			}
			if (mlen >= 1) {
				ADDBYTE;
			}
		}
	}

	if (len)
		printf("cksum4: out of data\n");
	if (byte_swapped) {
		UNSWAP;
	}
	REDUCE;
	ADDCARRY;
#ifdef CKSUMDEBUG
	if ((sum ^ 0xffff) != debugrv)
		printf("in4_cksum: rv != debugrv (rv %x debugrv %x)\n",
		    (sum ^ 0xffff), debugrv);
#endif
	return (sum ^ 0xffff);
}


code:
/*	$OpenBSD: in_cksum.c,v 1.6 2014/03/29 18:09:30 guenther Exp $	*/
/*	$NetBSD: in_cksum.c,v 1.7 2003/08/07 16:30:19 agc Exp $	*/

/*
 * Copyright (c) 1988, 1992, 1993
 *	The Regents of the University of California.  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.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
 *
 *	@(#)in_cksum.c	8.1 (Berkeley) 6/10/93
 */

#include <sys/param.h>
#include <sys/mbuf.h>
#include <sys/systm.h>

#include <netinet/in.h>

/*
 * Checksum routine for Internet Protocol family headers.
 *
 * This routine is very heavily used in the network
 * code and should be modified for each CPU to be as fast as possible.
 *
 * This implementation is VAX version.
 */

#define REDUCE		{sum = (sum & 0xffff) + (sum >> 16);}
#define ADDCARRY	{if (sum > 0xffff) sum -= 0xffff;}
#define ADVANCE(n)	{w += n; mlen -= n;}
#define SWAP		{sum <<= 8;}		/* depends on recent REDUCE */

#define Asm     __asm volatile
#define ADDL    Asm("addl2 (%2)+,%0" : "=r" (sum) : "0" (sum), "r" (w))
#define ADWC    Asm("adwc  (%2)+,%0" : "=r" (sum) : "0" (sum), "r" (w))
#define ADDC    Asm("adwc     $0,%0" : "=r" (sum) : "0" (sum))
#define UNSWAP  Asm("rotl  $8,%0,%0" : "=r" (sum) : "0" (sum))
#define ADDBYTE	{sum += *w; SWAP; byte_swapped ^= 1;}
#define ADDWORD	{sum += *(u_short *)w;}

int
in_cksum(struct mbuf *m, int len)
{
	u_int8_t *w;
	u_int32_t sum = 0;
	int mlen = 0;
	int byte_swapped = 0;

	for (;m && len; m = m->m_next) {
		if ((mlen = m->m_len) == 0)
			continue;
		w = mtod(m, u_int8_t *);
		if (len < mlen)
			mlen = len;
		len -= mlen;
		if (mlen < 16)
			goto short_mbuf;
		/*
		 * Ensure that we're aligned on a word boundary here so
		 * that we can do 32 bit operations below.
		 */
		if ((3 & (u_long) w) != 0) {
			REDUCE;
			if ((1 & (u_long) w) != 0) {
				ADDBYTE;
				ADVANCE(1);
			}
			if ((2 & (u_long) w) != 0) {
				ADDWORD;
				ADVANCE(2);
			}
		}
		/*
		 * Do as much of the checksum as possible 32 bits at at time.
		 * In fact, this loop is unrolled to make overhead from
		 * branches &c small.
		 */
		while ((mlen -= 32) >= 0) {
			/*
			 * Add with carry 16 words and fold in the last carry
			 * by adding a 0 with carry.
			 */
			ADDL;	ADWC;	ADWC;	ADWC;
			ADWC;	ADWC;	ADWC;	ADWC;
			ADDC;
		}
		mlen += 32;
		if (mlen >= 16) {
			ADDL;	ADWC;	ADWC;	ADWC;
			ADDC;
			mlen -= 16;
		}
	short_mbuf:
		if (mlen >= 8) {
			ADDL;	ADWC;
			ADDC;
			mlen -= 8;
		}
		if (mlen >= 4) {
			ADDL;
			ADDC;
			mlen -= 4;
		}
		if (mlen > 0) {
			REDUCE;
			if (mlen >= 2) {
				ADDWORD;
				ADVANCE(2);
			}
			if (mlen >= 1) {
				ADDBYTE;
			}
		}
	}

	if (len)
		printf("cksum: out of data\n");
	if (byte_swapped) {
		UNSWAP;
	}
	REDUCE;
	ADDCARRY;
	return (sum ^ 0xffff);
}


code:
/*	$OpenBSD: ka410.c,v 1.13 2011/09/15 00:48:24 miod Exp $ */
/*	$NetBSD: ka410.c,v 1.21 1999/09/06 19:52:53 ragge Exp $ */
/*
 * Copyright (c) 1996 Ludd, University of Lule}, Sweden.
 * All rights reserved.
 *
 * This code is derived from software contributed to Ludd by Bertram Barth.
 *
 * 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.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed at Ludd, University of
 *	Lule}, Sweden and its contributors.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * 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.
 */

#include <sys/param.h>
#include <sys/types.h>
#include <sys/device.h>
#include <sys/kernel.h>
#include <sys/systm.h>

#include <uvm/uvm_extern.h>

#include <machine/pte.h>
#include <machine/cpu.h>
#include <machine/mtpr.h>
#include <machine/sid.h>
#include <machine/pmap.h>
#include <machine/uvax.h>
#include <machine/ka410.h>
#include <machine/ka420.h>
#include <machine/cvax.h>
#include <machine/clock.h>
#include <machine/vsbus.h>

static	void	ka410_conf(void);
static	void	ka410_memerr(void);
static	int	ka410_mchk(caddr_t);
static	void	ka410_halt(void);
static	void	ka410_reboot(int);
static	void	ka41_cache_enable(void);
static	void	ka410_clrf(void);

static	caddr_t	l2cache;	/* mapped in address */
static	long 	*cacr;		/* l2csche ctlr reg */

/*
 * Declaration of 410-specific calls.
 */
struct	cpu_dep ka410_calls = {
	0,
	ka410_mchk,
	ka410_memerr,
	ka410_conf,
	chip_clkread,
	chip_clkwrite,
	1,      /* ~VUPS */
	2,	/* SCB pages */
	ka410_halt,
	ka410_reboot,
	ka410_clrf,
	icr_hardclock
};

void
ka410_conf()
{
	struct vs_cpu *ka410_cpu;

	ka410_cpu = (struct vs_cpu *)vax_map_physmem(VS_REGS, 1);

	switch (vax_cputype) {
	case VAX_TYP_UV2:
		ka410_cpu->vc_410mser = 1;
		printf("cpu: KA410\n");
		break;

	case VAX_TYP_CVAX:
		printf("cpu: KA41/42\n");
		ka410_cpu->vc_vdcorg = 0; /* XXX */
		ka410_cpu->vc_parctl = PARCTL_CPEN | PARCTL_DPEN ;
		printf("cpu: Enabling primary cache, ");
		mtpr(CADR_SEN2 | CADR_SEN1 | CADR_CENI | CADR_CEND, PR_CADR);
		if (vax_confdata & KA420_CFG_CACHPR) {
			l2cache = (void *)vax_map_physmem(KA420_CH2_BASE,
			    (KA420_CH2_SIZE / VAX_NBPG));
			cacr = (void *)vax_map_physmem(KA420_CACR, 1);
			printf("secondary cache\n");
			ka41_cache_enable();
		} else
			printf("no secondary cache present\n");
	}
	/* Done with ka410_cpu - release it */
	vax_unmap_physmem((vaddr_t)ka410_cpu, 1);
	/*
	 * Setup parameters necessary to read time from clock chip.
	 */
	clk_adrshift = 1;       /* Addressed at long's... */
	clk_tweak = 2;          /* ...and shift two */
	clk_page = (short *)vax_map_physmem(KA420_WAT_BASE, 1);
}

void
ka41_cache_enable()
{
	*cacr = KA420_CACR_TPE; 	/* Clear any error, disable cache */
	bzero(l2cache, KA420_CH2_SIZE); /* Clear whole cache */
	*cacr = KA420_CACR_CEN;		/* Enable cache */
}

void
ka410_memerr()
{
	printf("Memory err!\n");
}

int
ka410_mchk(addr)
	caddr_t addr;
{
	panic("Machine check");
	return 0;
}

static void
ka410_halt()
{
	asm("movl $0xc, (%0)"::"r"((int)clk_page + 0x38)); /* Don't ask */
	asm("halt");
}

static void
ka410_reboot(arg)
	int arg;
{
	asm("movl $0xc, (%0)"::"r"((int)clk_page + 0x38)); /* Don't ask */
	asm("halt");
}

static void
ka410_clrf()
{
	struct ka410_clock *clk = (void *)clk_page;

	/*
	 * Clear restart and boot in progress flags
	 * in the CPMBX. (ie. clear bits 4 and 5)
	 */
	clk->cpmbx = (clk->cpmbx & ~0x30);
}


code:
/*	$OpenBSD: ka43.c,v 1.16 2014/05/08 19:06:07 miod Exp $ */
/*	$NetBSD: ka43.c,v 1.19 1999/09/06 19:52:53 ragge Exp $ */
/*
 * Copyright (c) 1996 Ludd, University of Lule}, Sweden.
 * All rights reserved.
 *
 * This code is derived from software contributed to Ludd by Bertram Barth.
 *
 * 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.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed at Ludd, University of
 *	Lule}, Sweden and its contributors.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * 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.
 */

#include <sys/param.h>
#include <sys/types.h>
#include <sys/device.h>
#include <sys/kernel.h>
#include <sys/systm.h>

#include <uvm/uvm_extern.h>

#include <machine/pte.h>
#include <machine/cpu.h>
#include <machine/mtpr.h>
#include <machine/sid.h>
#include <machine/pmap.h>
#include <machine/uvax.h>
#include <machine/vsbus.h>
#include <machine/ka43.h>
#include <machine/clock.h>

static	void ka43_conf(void);
static	void ka43_init(void);

static	int ka43_mchk(caddr_t);
static	void ka43_memerr(void);
#if 0
static	void ka43_clear_errors(void);
#endif
static	int ka43_cache_init(void);	/* "int mapen" as argument? */
static	int ka43_cache_reset(int);
static	int ka43_cache_enable(void);
static	int ka43_cache_disable(void);
static	int ka43_cache_invalidate(void);
static  void ka43_halt(void);
static  void ka43_reboot(int);
static  void ka43_clrf(void);

struct	cpu_dep ka43_calls = {
	ka43_init,
	ka43_mchk,
	ka43_memerr,
	ka43_conf,
	chip_clkread,
	chip_clkwrite,
	7,	/* 7.6 VUP */
	2,	/* SCB pages */
	ka43_halt,
	ka43_reboot,
	ka43_clrf,
	icr_hardclock
};

static	volatile struct	ka43_cpu   *ka43_cpu	= (void *)KA43_CPU_BASE;
static	volatile u_int	*ka43_creg = (void *)KA43_CH2_CREG;
static	volatile u_int	*ka43_ctag = (void *)KA43_CT2_BASE;

#define KA43_MC_RESTART	0x00008000	/* Restart possible*/
#define KA43_PSL_FPDONE	0x00010000	/* First Part Done */

struct ka43_mcframe {		/* Format of RigelMAX machine check frame: */
	int	mc43_bcnt;	/* byte count, always 24 (0x18) */
	int	mc43_code;	/* machine check type code and restart bit */
	int	mc43_addr;	/* most recent (faulting?) virtual address */
	int	mc43_viba;	/* contents of VIBA register */
	int	mc43_sisr;	/* ICCS bit 6 and SISR bits 15:0 */
	int	mc43_istate;	/* internal state */
	int	mc43_sc;	/* shift count register */
	int	mc43_pc;	/* trapped PC */
	int	mc43_psl;	/* trapped PSL */
};

static char *ka43_mctype[] = {
	"no error (0)",			/* Code 0: No error */
	"FPA: protocol error",		/* Code 1-5: FPA errors */
	"FPA: illegal opcode",
	"FPA: operand parity error",
	"FPA: unknown status",
	"FPA: result parity error",
	"unused (6)",			/* Code 6-7: Unused */
	"unused (7)",
	"MMU error (TLB miss)",		/* Code 8-9: MMU errors */
	"MMU error (TLB hit)",
	"HW interrupt at unused IPL",	/* Code 10: Interrupt error */
	"MOVCx impossible state",	/* Code 11-13: Microcode errors */
	"undefined trap code (i-box)",
	"undefined control store address",
	"unused (14)",			/* Code 14-15: Unused */
	"unused (15)",
	"PC tag or data parity error",	/* Code 16: Cache error */
	"data bus parity error",	/* Code 17: Read error */
	"data bus error (NXM)",		/* Code 18: Write error */
	"undefined data bus state",	/* Code 19: Bus error */
};
#define MC43_MAX	19

static int ka43_error_count = 0;

int
ka43_mchk(addr)
	caddr_t addr;
{
	register struct ka43_mcframe *mcf = (void *)addr;

	mtpr(0x00, PR_MCESR);	/* Acknowledge the machine check */
	printf("machine check %d (0x%x)\n", mcf->mc43_code, mcf->mc43_code);
	printf("reason: %s\n", ka43_mctype[mcf->mc43_code & 0xff]);
	if (++ka43_error_count > 10) {
		printf("error_count exceeded: %d\n", ka43_error_count);
		return (-1);
	}

	/*
	 * If either the Restart flag is set or the First-Part-Done flag
	 * is set, and the TRAP2 (double error) bit is not set, then the
	 * error is recoverable.
	 */
	if (mfpr(PR_PCSTS) & KA43_PCS_TRAP2) {
		printf("TRAP2 (double error) in ka43_mchk.\n");
		panic("unrecoverable state in ka43_mchk.");
		return (-1);
	}
	if ((mcf->mc43_code & KA43_MC_RESTART) ||
	    (mcf->mc43_psl & KA43_PSL_FPDONE)) {
		printf("ka43_mchk: recovering from machine-check.\n");
		ka43_cache_reset(0);	/* reset caches */
		return (0);		/* go on; */
	}

	/*
	 * Unknown error state, panic/halt the machine!
	 */
	printf("ka43_mchk: unknown error state!\n");
	return (-1);
}

void
ka43_memerr()
{
	/*
	 * Don\'t know what to do here. So just print some messages
	 * and try to go on...
	 */
	printf("memory error!\n");
	printf("primary cache status: %lb\n", mfpr(PR_PCSTS), KA43_PCSTS_BITS);
	printf("secondary cache status: %b\n", *ka43_creg, KA43_SESR_BITS);
}

int
ka43_cache_init()
{
	return (ka43_cache_reset(1));
}

#if 0
void
ka43_clear_errors()
{
	int val = *ka43_creg;
	val |= KA43_SESR_SERR | KA43_SESR_LERR | KA43_SESR_CERR;
	*ka43_creg = val;
}
#endif

int
ka43_cache_reset(int silent)
{
	/*
	 * resetting primary and secondary caches is done in three steps:
	 *	1. disable both caches
	 *	2. manually clear secondary cache
	 *	3. enable both caches
	 */
	ka43_cache_disable();
	ka43_cache_invalidate();
	ka43_cache_enable();

	if (silent == 0) {
		printf("primary cache status: %lb\n", mfpr(PR_PCSTS),
		    KA43_PCSTS_BITS);
		printf("secondary cache status: %b\n", *ka43_creg,
		    KA43_SESR_BITS);
	}

	return (0);
}

int
ka43_cache_disable()
{
	int val;

	/*
	 * first disable primary cache and clear error flags
	 */
	mtpr(KA43_PCS_REFRESH, PR_PCSTS);	/* disable primary cache */
	val = mfpr(PR_PCSTS);
	mtpr(val, PR_PCSTS);			/* clear error flags */

	/*
	 * now disable secondary cache and clear error flags
	 */
	val = *ka43_creg & ~KA43_SESR_CENB;	/* BICL !!! */
	*ka43_creg = val;			/* disable secondary cache */
	val = KA43_SESR_SERR | KA43_SESR_LERR | KA43_SESR_CERR;
	*ka43_creg = val;			/* clear error flags */

	return (0);
}

int
ka43_cache_invalidate()
{
	int i, val;

	val = KA43_PCTAG_PARITY;	/* clear valid flag, set parity bit */
	for (i = 0; i < 256; i++) {	/* 256 Quadword entries */
		mtpr(i*8, PR_PCIDX);	/* write index of tag */
		mtpr(val, PR_PCTAG);	/* write value into tag */
	}
	val = KA43_PCS_FLUSH | KA43_PCS_REFRESH;
	mtpr(val, PR_PCSTS);		/* flush primary cache */

	/*
	 * Rigel\'s secondary cache doesn\'t implement a valid-flag.
	 * Thus we initialize all entries with out-of-range/dummy
	 * addresses which will never be referenced (ie. never hit).
	 * After enabling cache we also access 128K of memory starting
	 * at 0x00 so that secondary cache will be filled with these
	 * valid addresses...
	 */
	val = 0xff;
	/* if (memory > 28 MB) val = 0x55; */
	for (i = 0; i < KA43_CT2_SIZE; i+= 4) {	/* Quadword entries ?? */
		ka43_ctag[i/4] = val;		/* reset upper and lower */
	}

	return (0);
}

int
ka43_cache_enable()
{
	volatile char *membase = (void *)0x80000000;	/* physical 0x00 */
	int i, val;

	val = KA43_PCS_FLUSH | KA43_PCS_REFRESH;
	mtpr(val, PR_PCSTS);		/* flush primary cache */

	/*
	 * now we enable secondary cache and access first 128K of memory
	 * so that secondary cache gets really initialized and holds
	 * valid addresses/data...
	 */
	*ka43_creg = KA43_SESR_CENB;	/* enable secondary cache */
	for (i=0; i<128*1024; i++) {
		val += membase[i];	/* some dummy operation... */
	}

	val = KA43_PCS_ENABLE | KA43_PCS_REFRESH;
	mtpr(val, PR_PCSTS);		/* enable primary cache */

	return (0);
}

void
ka43_conf()
{
	printf("cpu: KA43\n");
	ka43_cpu = (void *)vax_map_physmem(VS_REGS, 1);

	ka43_creg = (void *)vax_map_physmem(KA43_CH2_CREG, 1);
	ka43_ctag = (void *)vax_map_physmem(KA43_CT2_BASE,
	    (KA43_CT2_SIZE/VAX_NBPG));

	/*
	 * ka43_conf() gets called with MMU enabled, now it's safe to
	 * init/reset the caches.
	 */
	ka43_cache_init();

	clk_adrshift = 1;       /* Addressed at long's... */
	clk_tweak = 2;		/* ...and shift two */
	clk_page = (short *)vax_map_physmem(VS_CLOCK, 1);
}

void
ka43_init()
{
	int	val;

	/*
	 * if LANCE\'s io-buffer is above 16 MB, then the appropriate flag
	 * in the parity control register has to be set (it works as an
	 * additional address bit). In any case, don\'t enable CPEN and
	 * DPEN in the PARCTL register, somewhow they are internally managed
	 * by the RIGEL chip itself!?!
	 */
	val = ka43_cpu->parctl & 0x03;	/* read the old value */
	ka43_cpu->parctl = val;		/* and write new value */
}

static void
ka43_clrf()
{
	volatile struct ka43_clock *clk = (void *)clk_page;

	/*
	 * Clear restart and boot in progress flags in the CPMBX.
	 * The cpmbx is split into two 4-bit fields.
	 * One for the current restart/boot in progress flags, and
	 * one for the permanent halt flag.
	 * The restart/boot in progress flag is also used as the action request
	 * for the CPU at a halt. /BQT
	 */
	clk->req = 0;
}

static void
ka43_halt()
{
	volatile struct ka43_clock *clk = (void *)clk_page;

	clk->req = 3;		/* 3 is halt. */
	asm("halt");
}

static void
ka43_reboot(arg)
	int arg;
{
	volatile struct ka43_clock *clk = (void *)clk_page;

	clk->req = 2;		/* 2 is reboot. */
	asm("halt");
}


code:
/*	$OpenBSD: ka46.c,v 1.12 2014/05/17 12:13:44 miod Exp $	*/
/*	$NetBSD: ka46.c,v 1.12 2000/03/04 07:27:49 matt Exp $ */
/*
 * Copyright (c) 1998 Ludd, University of Lule}, Sweden.
 * All rights reserved.
 *
 * This code is derived from software contributed to Ludd by Bertram Barth.
 *
 * 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.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed at Ludd, University of
 *	Lule}, Sweden and its contributors.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * 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.
 */

#include <sys/param.h>
#include <sys/types.h>
#include <sys/device.h>
#include <sys/kernel.h>
#include <sys/systm.h>

#include <uvm/uvm_extern.h>

#include <machine/pte.h>
#include <machine/cpu.h>
#include <machine/mtpr.h>
#include <machine/sid.h>
#include <machine/pmap.h>
#include <machine/uvax.h>
#include <machine/ka410.h>
#include <machine/ka420.h>
#include <machine/ka46.h>
#include <machine/clock.h>
#include <machine/vsbus.h>

static	void	ka46_conf(void);
static	void	ka46_init(void);
static	void	ka46_memerr(void);
static	int	ka46_mchk(caddr_t);
static	void	ka46_halt(void);
static	void	ka46_reboot(int);
static	void	ka46_cache_enable(void);
static	void	ka46_hardclock(struct clockframe *);

struct	vs_cpu *ka46_cpu;

/*
 * Declaration of 46-specific calls.
 */
struct	cpu_dep ka46_calls = {
	ka46_init,
	ka46_mchk,
	ka46_memerr,
	ka46_conf,
	chip_clkread,
	chip_clkwrite,
	8,      /* ~VUPS */
	2,	/* SCB pages */
	ka46_halt,
	ka46_reboot,
	NULL,
	ka46_hardclock
};

void
ka46_conf()
{
        switch (vax_siedata & 0xFF) {
	case VAX_VTYP_47:
		printf("cpu: KA47\n");
		break;
	case VAX_VTYP_46:
		printf("cpu: KA46\n");
		break;
	default:
		printf("cpu: Unknown Mariah\n");
	}

	ka46_cpu = (void *)vax_map_physmem(VS_REGS, 1);
	printf("cpu: turning on floating point chip\n");
	mtpr(2, PR_ACCS); /* Enable floating points */
	/*
	 * Setup parameters necessary to read time from clock chip.
	 */
	clk_adrshift = 1;       /* Addressed at long's... */
	clk_tweak = 2;          /* ...and shift two */
	clk_page = (short *)vax_map_physmem(VS_CLOCK, 1);
}

void
ka46_cache_enable()
{
	int i, *tmp;

	/* Disable caches */
	*(int *)KA46_CCR &= ~CCR_SPECIO;/* secondary */
	mtpr(PCSTS_FLUSH, PR_PCSTS);	/* primary */
	*(int *)KA46_BWF0 &= ~BWF0_FEN; /* invalidate filter */

	/* Clear caches */
	tmp = (void *)KA46_INVFLT;	/* inv filter */
	for (i = 0; i < 32768; i++)
		tmp[i] = 0;

	/* Write valid parity to all primary cache entries */
	for (i = 0; i < 256; i++) {
		mtpr(i << 3, PR_PCIDX);
		mtpr(PCTAG_PARITY, PR_PCTAG);
	}

	/* Secondary cache */
	tmp = (void *)KA46_TAGST;
	for (i = 0; i < KA46_TAGSZ*2; i+=2)
		tmp[i] = 0;

	/* Enable cache */
	*(int *)KA46_BWF0 |= BWF0_FEN; /* invalidate filter */
	mtpr(PCSTS_ENABLE, PR_PCSTS);
	*(int *)KA46_CCR = CCR_SPECIO | CCR_CENA;
}

void
ka46_memerr()
{
	printf("Memory err!\n");
}

int
ka46_mchk(addr)
	caddr_t addr;
{
	panic("Machine check");
	return 0;
}

void
ka46_init()
{

	/* Turn on caches (to speed up execution a bit) */
	ka46_cache_enable();
}

#define	KA46_CPMBX	0x38
#define	KA46_HLT_HALT	0xcf
#define	KA46_HLT_BOOT	0x8b

static void
ka46_halt()
{
	if (((u_int8_t *) clk_page)[KA46_CPMBX] != KA46_HLT_HALT)
		((u_int8_t *) clk_page)[KA46_CPMBX] = KA46_HLT_HALT;
	asm("halt");
}

static void
ka46_reboot(arg)
	int arg;
{
	if (((u_int8_t *) clk_page)[KA46_CPMBX] != KA46_HLT_BOOT)
		((u_int8_t *) clk_page)[KA46_CPMBX] = KA46_HLT_BOOT;
	asm("halt");
}

static void
ka46_hardclock(struct clockframe *cf)
{
	ka46_cpu->vc_diagtimu = 0;
	hardclock(cf);
}


code:
/*	$OpenBSD: ka48.c,v 1.15 2014/05/17 12:13:44 miod Exp $	*/
/*
 * Copyright (c) 1998 Ludd, University of Lule}, Sweden.
 * All rights reserved.
 *
 * This code is derived from software contributed to Ludd by Bertram Barth.
 *
 * 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.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed at Ludd, University of
 *	Lule}, Sweden and its contributors.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * 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.
 */

/*** needs to be completed MK-990306 ***/

#include <sys/param.h>
#include <sys/types.h>
#include <sys/device.h>
#include <sys/kernel.h>
#include <sys/systm.h>

#include <uvm/uvm_extern.h>

#include <machine/pte.h>
#include <machine/cpu.h>
#include <machine/mtpr.h>
#include <machine/sid.h>
#include <machine/pmap.h>
#include <machine/uvax.h>
#include <machine/ka410.h>
#include <machine/ka420.h>
#include <machine/ka48.h>
#include <machine/clock.h>
#include <machine/vsbus.h>

static	void	ka48_conf(void);
static	void	ka48_init(void);
static	void	ka48_memerr(void);
static	int	ka48_mchk(caddr_t);
static	void	ka48_halt(void);
static	void	ka48_reboot(int);
static	void	ka48_cache_enable(void);
static	void	ka48_hardclock(struct clockframe *);

struct	vs_cpu *ka48_cpu;

/*
 * Declaration of 48-specific calls.
 */
struct	cpu_dep ka48_calls = {
	ka48_init,
	ka48_mchk,
	ka48_memerr,
	ka48_conf,
	chip_clkread,
	chip_clkwrite,
	4,      /* ~VUPS */
	2,	/* SCB pages */
	ka48_halt,
	ka48_reboot,
	NULL,
	ka48_hardclock
};

void
ka48_conf()
{
	char *cpuname;
	switch (vax_cpustype) {
	case VAX_STYP_45:
		cpuname = "KA45";
		break;
	case VAX_STYP_48:
		cpuname = "KA48";
		break;
	default:
		cpuname = "Unknown SOC";
	}
	printf("cpu: %s\n", cpuname);
	ka48_cpu = (void *)vax_map_physmem(VS_REGS, 1);
	/*
	 * Setup parameters necessary to read time from clock chip.
	 */
	clk_adrshift = 1;       /* Addressed at long's... */
	clk_tweak = 2;          /* ...and shift two */
	clk_page = (short *)vax_map_physmem(VS_CLOCK, 1);
}

void
ka48_cache_enable()
{
	int i, *tmp;
	long *par_ctl = (long *)KA48_PARCTL;

	/* Disable cache */
	mtpr(0, PR_CADR);		/* disable */
	*par_ctl &= ~KA48_PARCTL_INVENA;	/* clear ? invalid enable */
	mtpr(2, PR_CADR);		/* flush */

	/* Clear caches */
	tmp = (void *)KA48_INVFLT;	/* inv filter */
	for (i = 0; i < KA48_INVFLTSZ / sizeof(int); i++)
		tmp[i] = 0;
	*par_ctl |= KA48_PARCTL_INVENA;	/* Enable ???? */
	mtpr(4, PR_CADR);		/* enable cache */
	*par_ctl |= (KA48_PARCTL_AGS |	/* AGS? */
	    KA48_PARCTL_NPEN |		/* N? Parity Enable */
	    KA48_PARCTL_CPEN);		/* Cpu parity enable */
}

void
ka48_memerr()
{
	printf("Memory err!\n");
}

int
ka48_mchk(addr)
	caddr_t addr;
{
	panic("Machine check");
	return 0;
}

void
ka48_init()
{
	/* Turn on caches (to speed up execution a bit) */
	ka48_cache_enable();
}

#define	KA48_CPMBX	0x38
#define	KA48_HLT_HALT	0xcf	/* 11001111 */
#define	KA48_HLT_BOOT	0x8b	/* 10001011 */

static void
ka48_halt()
{
	if (((u_int8_t *) clk_page)[KA48_CPMBX] != KA48_HLT_HALT)
		((u_int8_t *) clk_page)[KA48_CPMBX] = KA48_HLT_HALT;
	asm("halt");
}

static void
ka48_reboot(arg)
	int arg;
{
	if (((u_int8_t *) clk_page)[KA48_CPMBX] != KA48_HLT_BOOT)
		((u_int8_t *) clk_page)[KA48_CPMBX] = KA48_HLT_BOOT;
	asm("halt");
}

static void
ka48_hardclock(struct clockframe *cf)
{
	ka48_cpu->vc_diagtimu = 0;
	hardclock(cf);
}


code:
/*	$OpenBSD: ka49.c,v 1.12 2013/07/05 21:11:57 miod Exp $	*/
/*
 * Copyright (c) 1999 Ludd, University of Lule}, Sweden.
 * 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.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed at Ludd, University of
 *	Lule}, Sweden and its contributors.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * 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.
 */

#include <sys/param.h>
#include <sys/device.h>
#include <sys/systm.h>
#include <sys/kernel.h>

#include <machine/clock.h>
#include <machine/cpu.h>
#include <machine/scb.h>

static	void	ka49_conf(void);
static	void	ka49_memerr(void);
static	int	ka49_mchk(caddr_t);
static	void	ka49_halt(void);
static	void	ka49_reboot(int);
static	void	ka49_softmem(void *);
static	void	ka49_hardmem(void *);
static	void	ka49_init(void);
static	void	ka49_cache_enable(void);
static	void	ka49_halt(void);

/*
 * Declaration of 49-specific calls.
 */
struct	cpu_dep ka49_calls = {
	ka49_init,
	ka49_mchk,
	ka49_memerr,
	ka49_conf,
	chip_clkread,
	chip_clkwrite,
	32,      /* ~VUPS */
	2,	/* SCB pages */
	ka49_halt,
	ka49_reboot,
	NULL,
	icr_hardclock
};

void
ka49_conf()
{
	printf("cpu0: KA49\n");

/* Why??? */
{ volatile int *hej = (void *)mfpr(PR_ISP); *hej = *hej; hej[-1] = hej[-1];}

	/* This vector shows up during shutdown, ignore it for now. */
	scb_vecalloc(0x0, (void *)nullop, NULL, SCB_ISTACK, NULL);

	/*
	 * Setup parameters necessary to read time from clock chip.
	 */
	clk_adrshift = 1;       /* Addressed at long's... */
	clk_tweak = 2;          /* ...and shift two */
	clk_page = (short *)vax_map_physmem(0x25400000, 1);
}

/*
 * Why may we get memory errors during startup???
 */
void
ka49_hardmem(arg)
	void *arg;
{
	if (cold == 0)
		printf("Hard memory error\n");
	splhigh();
}

void
ka49_softmem(arg)
	void *arg;
{
	if (cold == 0)
		printf("Soft memory error\n");
	splhigh();
}

/*
 * KA49-specific IPRs. KA49 has the funny habit to control all caches
 * via IPRs.
 */
#define	PR_CCTL		0xa0
#define	CCTL_ENABLE	0x00000001
#define	CCTL_SSIZE	0x00000002
#define	CCTL_VSIZE	0x00000004
#define	CCTL_SW_ETM	0x40000000
#define	CCTL_HW_ETM	0x80000000

#define	PR_BCETSTS	0xa3
#define	PR_BCEDSTS	0xa6
#define	PR_NESTS	0xae

#define	PR_VMAR		0xd0
#define	PR_VTAG		0xd1
#define	PR_ICSR		0xd3
#define	ICSR_ENABLE	0x01

#define	PR_PCCTL	0xf8
#define	PCCTL_P_EN	0x10
#define	PCCTL_I_EN	0x02
#define	PCCTL_D_EN	0x01

void
ka49_cache_enable()
{
	int start, slut;

	/*
	 * Turn caches off.
	 */
	mtpr(0, PR_ICSR);
	mtpr(0, PR_PCCTL);
	mtpr(mfpr(PR_CCTL) | CCTL_SW_ETM, PR_CCTL);

	/*
	 * Invalidate caches.
	 */
	mtpr(mfpr(PR_CCTL) | 0x10, PR_CCTL);	/* Set cache size */
	mtpr(mfpr(PR_BCETSTS), PR_BCETSTS);	/* Clear error bits */
	mtpr(mfpr(PR_BCEDSTS), PR_BCEDSTS);	/* Clear error bits */
	mtpr(mfpr(PR_NESTS), PR_NESTS);		/* Clear error bits */

	start = 0x01400000;
	slut  = 0x01440000;

	/* Flush cache lines */
	for (; start < slut; start += 0x20)
		mtpr(0, start);

	mtpr((mfpr(PR_CCTL) & ~(CCTL_SW_ETM|CCTL_ENABLE)) | CCTL_HW_ETM,
	    PR_CCTL);

	start = 0x01000000;
	slut  = 0x01040000;

	/* clear tag and valid */
	for (; start < slut; start += 0x20)
		mtpr(0, start);

	mtpr(mfpr(PR_CCTL) | 0x10 | CCTL_ENABLE, PR_CCTL); /* enab. bcache */

	start = 0x01800000;
	slut  = 0x01802000;

	/* Clear primary cache */
	for (; start < slut; start += 0x20)
		mtpr(0, start);

	/* Flush the pipes (via REI) */
	asm("movpsl -(%sp); movab 1f,-(%sp); rei; 1:;");

	/* Enable primary cache */
	mtpr(PCCTL_P_EN|PCCTL_I_EN|PCCTL_D_EN, PR_PCCTL);

	/* Enable the VIC */
	start = 0;
	slut  = 0x800;
	for (; start < slut; start += 0x20) {
		mtpr(start, PR_VMAR);
		mtpr(0, PR_VTAG);
	}
	mtpr(ICSR_ENABLE, PR_ICSR);
}

void
ka49_memerr()
{
	printf("Memory err!\n");
}

int
ka49_mchk(addr)
	caddr_t addr;
{
	panic("Machine check");
	return 0;
}

void
ka49_init()
{
	/*
	 * Get the soft and hard memory error vectors now.
	 */
	scb_vecalloc(0x54, ka49_softmem, NULL, 0, NULL);
	scb_vecalloc(0x60, ka49_hardmem, NULL, 0, NULL);

	/* Turn on caches (to speed up execution a bit) */
	ka49_cache_enable();
}

#define	KA49_CPMBX	0x38
#define	KA49_HLT_HALT	0xcf
#define	KA49_HLT_BOOT	0x8b

static void
ka49_halt()
{
	if (((u_int8_t *) clk_page)[KA49_CPMBX] != KA49_HLT_HALT)
		((u_int8_t *) clk_page)[KA49_CPMBX] = KA49_HLT_HALT;
	asm("halt");
}

static void
ka49_reboot(arg)
	int arg;
{
	if (((u_int8_t *) clk_page)[KA49_CPMBX] != KA49_HLT_BOOT)
		((u_int8_t *) clk_page)[KA49_CPMBX] = KA49_HLT_BOOT;
	asm("halt");
}