code:
/*	$OpenBSD: db_disasm.c,v 1.7 2004/01/15 17:22:28 miod Exp $	*/
/*	$NetBSD: db_disasm.c,v 1.9 1996/03/31 23:45:07 pk Exp $ */

/*
 * Copyright (c) 1994 David S. Miller, davem@nadzieja.rutgers.edu
 * Copyright (c) 1995 Paul Kranenburg
 * 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 by David Miller.
 * 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 <machine/db_machdep.h>
#include <machine/instr.h>
#include <ddb/db_sym.h>
#include <ddb/db_interface.h>
#include <ddb/db_extern.h>
#include <ddb/db_output.h>
#include <ddb/db_access.h>

/*
 * All Sparc instructions are 32-bits, with the one exception being
 * the set instruction which is actually a macro which expands into
 * two instructions...
 *
 * There are 5 different fields that can be used to identify which
 * operation is encoded into a particular 32-bit insn. There are 3
 * formats for instructions, which one being used is determined by
 * bits 30-31 of the insn. Here are the bit fields and their names:
 *
 * 1100 0000 0000 0000 0000 0000 0000 0000 op field, determines format
 * 0000 0001 1100 0000 0000 0000 0000 0000 op2 field, format 2 only
 * 0000 0001 1111 1000 0000 0000 0000 0000 op3 field, format 3 only
 * 0000 0000 0000 0000 0010 0000 0000 0000 f3i bit, format 3 only
 */

#define OP(x)	(((x) & 0x3) << 30)
#define OP2(x)	(((x) & 0x7) << 22)
#define OP3(x)	(((x) & 0x3f) << 19)
#define OPF(x)	(((x) & 0x1ff) << 5)
#define F3I(x)	(((x) & 0x1) << 13)

/* various other fields */

#define A(x)		(((x) & 0x1) << 29)
#define P(x)		(((x) & 0x1) << 19)
#define X(x)		(((x) & 0x1) << 12)
#define FCN(x)		(((x) & 0x1f) << 25)
#define RCOND2(x)	(((x) & 0x7) << 25)
#define RCOND34(x)	(((x) & 0x7) << 10)
#define COND(x)		(((x) & 0xf) << 25)
#define SW_TRAP(x)	((x) & 0x7f)
#define SHCNT32(x)	((x) & 0x1f)
#define SHCNT64(x)	((x) & 0x3f)
#define IMM11(x)	((x) & 0x7ff)
#define IMM22(x)	((x) & 0x3fffff)
#define DISP19(x)	((x) & 0x7ffff)
#define DISP22(x)	((x) & 0x3fffff)
#define DISP30(x)	((x) & 0x3fffffff)

/* Register Operand Fields */
#define RS1(x)		(((x) & 0x1f) << 14)
#define RS2(x)		((x) & 0x1f)
#define RD(x)		(((x) & 0x1f) << 25)

/* FORMAT macros used in sparc_i table to decode each opcode */
#define FORMAT1(a)	(OP(a))
#define FORMAT2(a,b)	(OP(a) | OP2(b))
#define FORMAT3(a,b,c)	(OP(a) | OP3(b) | F3I(c))
#define FORMAT3F(a,b,c)	(OP(a) | OP3(b) | OPF(c))

/* Helper macros to construct OP3 & OPF */
#define OP3_X(x,y)	((((x) & 3) << 4) | ((y) & 0xf))
#define OPF_X(x,y)	((((x) & 0x1f) << 4) | ((y) & 0xf))

/* COND condition codes field... */
#define COND2(x)	(((x) & 0xf) << 14)

struct sparc_insn {
	  unsigned long int match;
	  char *name;
	  char *format;
};

char *regs[] = {
	"g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
	"o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
	"l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
	"i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7"
};

char *priv_regs[] = {
	"tpc", "tnpc", "tstate", "tt", "tick", "tba", "pstate", "tl",
	"pil", "cwp", "cansave", "canrestore", "cleanwin", "otherwin",
	"wstate", "fq",
	"", "", "", "", "", "", "", "",
	"", "", "", "", "", "", "", ""
};

char *state_regs[] = {
	"y", "", "ccr", "asi", "tick", "pc", "fprs", "asr",
	"", "", "", "", "", "", "", "",
	"illegal", "", "", "", "", "", "", "", "",
	"", "", "", "", "", "", "", ""
};

char *ccodes[] = {
	"fcc0", "fcc1", "fcc2", "fcc3", "icc", "", "xcc", ""
};

char *prefetch[] = {
	"n_reads", "one_read", "n_writes", "one_write", "page"
};

/* The sparc instruction table has a format field which tells what
   the operand structure for this instruction is. Here are the codes:

Modifiers (nust be first):
	a -- opcode has annul bit
	p -- opcode has branch prediction bit

Codes:
        1 -- source register operand stored in rs1
	2 -- source register operand stored in rs2
	d -- destination register operand stored in rd
	3 -- floating source register in rs1
	4 -- floating source register in rs2
	e -- floating destination register in rd
	i -- 13-bit immediate value stored in simm13
	j -- 11-bit immediate value stored in simm11
	l -- displacement using d16lo and d16hi
	m -- 22-bit fcc displacement value
	n -- 30-bit displacement used in call insns
	o -- %fcc number specified in cc1 and cc0 fields
	p -- address computed by the contents of rs1+rs2
	q -- address computed by the contents of rs1+simm13
	r -- prefetch
	s -- %asi is implicit in the insn, rs1 value not used
	t -- immediate 8-bit asi value
	u -- 19-bit fcc displacement value
	5 -- hard register, %fsr lower-half
	6 -- hard register, %fsr all
	7 -- [reg_addr rs1+rs2] imm_asi
	8 -- [reg_addr rs1+simm13] %asi
	9 -- logical or of the cmask and mmask fields (membar insn)
	0 -- icc or xcc condition codes register
	r -- prefection function stored in fcn field
	A -- privileged register encoded in rs1
	B -- state register encoded in rs1
	C -- %hi(value) where value is stored in imm22 field
	D -- 32-bit shift count in shcnt32
	E -- 64-bit shift count in shcnt64
	F -- software trap number stored in sw_trap
	G -- privileged register encoded in rd
	H -- state register encoded in rd

V8 only:
	Y -- write y register
	P -- write psr register
	T -- write tbr register
	W -- write wim register
*/

struct sparc_insn sparc_i[] = {

	/*
	 * Format 1: Call
	 */
	{(FORMAT1(1)), "call", "n"},

	/*
	 * Format 0: Sethi & Branches
	 */
	/* Illegal Instruction Trap */
	{(FORMAT2(0, 0)), "illtrap", "m"},

	/* Note: if imm22 is zero then this is actually a "nop" grrr... */
	{(FORMAT2(0, 0x4)), "sethi", "Cd"},

	/* Branch on Integer Condition Codes "Bicc" */
	{(FORMAT2(0, 2) | COND(8)), "ba", "a,m"},
	{(FORMAT2(0, 2) | COND(0)), "bn", "a,m"},
	{(FORMAT2(0, 2) | COND(9)), "bne", "a,m"},
	{(FORMAT2(0, 2) | COND(1)), "be", "a,m"},
	{(FORMAT2(0, 2) | COND(10)), "bg", "a,m"},
	{(FORMAT2(0, 2) | COND(2)), "ble", "a,m"},
	{(FORMAT2(0, 2) | COND(11)), "bge", "a,m"},
	{(FORMAT2(0, 2) | COND(3)), "bl", "a,m"},
	{(FORMAT2(0, 2) | COND(12)), "bgu", "a,m"},
	{(FORMAT2(0, 2) | COND(4)), "bleu", "a,m"},
	{(FORMAT2(0, 2) | COND(13)), "bcc", "a,m"},
	{(FORMAT2(0, 2) | COND(5)), "bcs", "a,m"},
	{(FORMAT2(0, 2) | COND(14)), "bpos", "a,m"},
	{(FORMAT2(0, 2) | COND(6)), "bneg", "a,m"},
	{(FORMAT2(0, 2) | COND(15)), "bvc", "a,m"},
	{(FORMAT2(0, 2) | COND(7)), "bvs", "a,m"},

	/* Branch on Integer Condition Codes with Prediction "BPcc" */
	{(FORMAT2(0, 1) | COND(8)), "ba", "ap,u"},
	{(FORMAT2(0, 1) | COND(0)), "bn", "ap,u"},
	{(FORMAT2(0, 1) | COND(9)), "bne", "ap,u"},
	{(FORMAT2(0, 1) | COND(1)), "be", "ap,u"},
	{(FORMAT2(0, 1) | COND(10)), "bg", "ap,u"},
	{(FORMAT2(0, 1) | COND(2)), "ble", "ap,u"},
	{(FORMAT2(0, 1) | COND(11)), "bge", "ap,u"},
	{(FORMAT2(0, 1) | COND(3)), "bl", "ap,u"},
	{(FORMAT2(0, 1) | COND(12)), "bgu", "ap,u"},
	{(FORMAT2(0, 1) | COND(4)), "bleu", "ap,u"},
	{(FORMAT2(0, 1) | COND(13)), "bcc", "ap,u"},
	{(FORMAT2(0, 1) | COND(5)), "bcs", "ap,u"},
	{(FORMAT2(0, 1) | COND(14)), "bpos", "ap,u"},
	{(FORMAT2(0, 1) | COND(6)), "bneg", "ap,u"},
	{(FORMAT2(0, 1) | COND(15)), "bvc", "ap,u"},
	{(FORMAT2(0, 1) | COND(7)), "bvs", "ap,u"},

	/* Branch on Integer Register with Prediction "BPr" */
	{(FORMAT2(0, 3) | RCOND2(1)), "brz", "ap,1l"},
	{(FORMAT2(0, 3) | A(1) | P(1) | RCOND2(2)), "brlex", "ap,1l"},
	{(FORMAT2(0, 3) | RCOND2(3)), "brlz", "ap,1l"},
	{(FORMAT2(0, 3) | RCOND2(5)), "brnz", "ap,1l"},
	{(FORMAT2(0, 3) | RCOND2(6)), "brgz", "ap,1l"},
	{(FORMAT2(0, 3) | RCOND2(7)), "brgez", "ap,1l"},

	/* Branch on Floating-Point Condition Codes with Prediction "FBPfcc" */
	{(FORMAT2(0, 5) | COND(8)), "fba", "ap,m"},
	{(FORMAT2(0, 5) | COND(0)), "fbn", "ap,m"},
	{(FORMAT2(0, 5) | COND(7)), "fbu", "ap,m"},
	{(FORMAT2(0, 5) | COND(6)), "fbg", "ap,m"},
	{(FORMAT2(0, 5) | COND(5)), "fbug", "ap,m"},
	{(FORMAT2(0, 5) | COND(4)), "fbl", "ap,m"},
	{(FORMAT2(0, 5) | COND(3)), "fbul", "ap,m"},
	{(FORMAT2(0, 5) | COND(2)), "fblg", "ap,m"},
	{(FORMAT2(0, 5) | COND(1)), "fbne", "ap,m"},
	{(FORMAT2(0, 5) | COND(9)), "fbe", "ap,m"},
	{(FORMAT2(0, 5) | COND(10)), "fbue", "ap,m"},
	{(FORMAT2(0, 5) | COND(11)), "fbge", "ap,m"},
	{(FORMAT2(0, 5) | COND(12)), "fbuge", "ap,m"},
	{(FORMAT2(0, 5) | COND(13)), "fble", "ap,m"},
	{(FORMAT2(0, 5) | COND(14)), "fbule", "ap,m"},
	{(FORMAT2(0, 5) | COND(15)), "fbo", "ap,m"},

	/* Branch on Floating-Point Condition Codes "FBfcc" */
	{(FORMAT2(0, 6) | COND(8)), "fba", "a,m"},
	{(FORMAT2(0, 6) | COND(0)), "fbn", "a,m"},
	{(FORMAT2(0, 6) | COND(7)), "fbu", "a,m"},
	{(FORMAT2(0, 6) | COND(6)), "fbg", "a,m"},
	{(FORMAT2(0, 6) | COND(5)), "fbug", "a,m"},
	{(FORMAT2(0, 6) | COND(4)), "fbl", "a,m"},
	{(FORMAT2(0, 6) | COND(3)), "fbul", "a,m"},
	{(FORMAT2(0, 6) | COND(2)), "fblg", "a,m"},
	{(FORMAT2(0, 6) | COND(1)), "fbne", "a,m"},
	{(FORMAT2(0, 6) | COND(9)), "fbe", "a,m"},
	{(FORMAT2(0, 6) | COND(10)), "fbue", "a,m"},
	{(FORMAT2(0, 6) | COND(11)), "fbge", "a,m"},
	{(FORMAT2(0, 6) | COND(12)), "fbuge", "a,m"},
	{(FORMAT2(0, 6) | COND(13)), "fble", "a,m"},
	{(FORMAT2(0, 6) | COND(14)), "fbule", "a,m"},
	{(FORMAT2(0, 6) | COND(15)), "fbo", "a,m"},

	/*
	 * Format 3/2: Arithmetic & misc (table 32, appendix E)
	 */
	{FORMAT3(2, OP3_X(0,0), 0), "add", "12d"},
	{FORMAT3(2, OP3_X(0,0), 1), "add", "1id"},
	{FORMAT3(2, OP3_X(1,0), 0), "addcc", "12d"},
	{FORMAT3(2, OP3_X(1,0), 1), "addcc", "1id"},
	{FORMAT3(2, OP3_X(2,0), 0), "taddcc", "12d"},
	{FORMAT3(2, OP3_X(2,0), 1), "taddcc", "1id"},
#ifdef V9
	{(FORMAT3(2, 0x30, 1) | RD(0xf)), "sir", "i"},
	{FORMAT3(2, OP3_X(3,0), 0), "wr", "12H"},
	{FORMAT3(2, OP3_X(3,0), 1), "wr", "1iH"},
#else
	{FORMAT3(2, OP3_X(3,0), 0), "wr", "12Y"}, /* wr 1, 2, %y  */
	{FORMAT3(2, OP3_X(3,0), 1), "wr", "1iY"}, /* wr 1, i, %y */
#endif

	{FORMAT3(2, OP3_X(0,1), 0), "and", "12d"},
	{FORMAT3(2, OP3_X(0,1), 1), "and", "1id"},
	{FORMAT3(2, OP3_X(1,1), 0), "andcc", "12d"},
	{FORMAT3(2, OP3_X(1,1), 1), "andcc", "1id"},
	{FORMAT3(2, OP3_X(2,1), 0), "tsubcc", "12d"},
	{FORMAT3(2, OP3_X(2,1), 1), "tsubcc", "1id"},
#ifdef V9
	{FORMAT3(2, OP3_X(3,1), 0), "saved", ""},
	{FORMAT3(2, OP3_X(3,1), 0)|FCN(1), "restored", ""},
#else
	{FORMAT3(2, OP3_X(3,1), 0), "wr", "12P"}, /* wr 1, 2, %psr  */
	{FORMAT3(2, OP3_X(3,1), 1), "wr", "1iP"}, /* wr 1, i, %psr */
#endif

	{FORMAT3(2, OP3_X(0,2), 0), "or", "12d"},
	{FORMAT3(2, OP3_X(0,2), 1), "or", "1id"},
	{FORMAT3(2, OP3_X(1,2), 0), "orcc", "12d"},
	{FORMAT3(2, OP3_X(1,2), 1), "orcc", "1id"},
	{FORMAT3(2, OP3_X(2,2), 0), "taddcctv", "12d"},
	{FORMAT3(2, OP3_X(2,2), 1), "taddcctv", "1id"},
#ifdef V9
	{FORMAT3(2, OP3_X(3,2), 0), "wrpr", "12G"},
	{FORMAT3(2, OP3_X(3,2), 1), "wrpr", "1iG"},
#else
	{FORMAT3(2, OP3_X(3,2), 0), "wr", "12W"}, /* wr 1, 2, %wim */
	{FORMAT3(2, OP3_X(3,2), 1), "wr", "1iW"}, /* wr 1, i, %wim */
#endif

	{FORMAT3(2, OP3_X(0,3), 0), "xor", "12d"},
	{FORMAT3(2, OP3_X(0,3), 1), "xor", "1id"},
	{FORMAT3(2, OP3_X(1,3), 0), "xorcc", "12d"},
	{FORMAT3(2, OP3_X(1,3), 1), "xorcc", "1id"},
	{FORMAT3(2, OP3_X(2,3), 0), "tsubcctv", "12d"},
	{FORMAT3(2, OP3_X(2,3), 1), "tsubcctv", "1id"},
#ifdef V9
	{FORMAT3(2, OP3_X(3,3), 0), "UNDEFINED", ""},
#else
	{FORMAT3(2, OP3_X(3,3), 0), "wr", "12T"}, /* wr 1, 2, %tbr */
	{FORMAT3(2, OP3_X(3,3), 1), "wr", "1iT"}, /* wr 1, i, %tbr */
#endif

	{FORMAT3(2, OP3_X(0,4), 0), "sub", "12d"},
	{FORMAT3(2, OP3_X(0,4), 1), "sub", "1id"},
	{FORMAT3(2, OP3_X(1,4), 0), "subcc", "12d"},
	{FORMAT3(2, OP3_X(1,4), 1), "subcc", "1id"},
	{FORMAT3(2, OP3_X(2,4), 0), "mulscc", "12d"},
	{FORMAT3(2, OP3_X(2,4), 1), "mulscc", "1id"},
	{FORMAT3(2, OP3_X(3,4), 1), "FPop1", ""},	/* see below */

	{FORMAT3(2, OP3_X(0,5), 0), "andn", "12d"},
	{FORMAT3(2, OP3_X(0,5), 1), "andn", "1id"},
	{FORMAT3(2, OP3_X(1,5), 0), "andncc", "12d"},
	{FORMAT3(2, OP3_X(1,5), 1), "andncc", "1id"},
	{FORMAT3(2, OP3_X(2,5), 0), "sll", "12d"},
	{FORMAT3(2, OP3_X(2,5), 1), "sll", "1Dd"},
	{FORMAT3(2, OP3_X(2,5)|X(1), 0), "sllx", "12d"},
	{FORMAT3(2, OP3_X(2,5)|X(1), 1), "sllx", "1Ed"},
	{FORMAT3(2, OP3_X(3,5), 1), "FPop2", ""},	/* see below */

	{FORMAT3(2, OP3_X(0,6), 0), "orn", "12d"},
	{FORMAT3(2, OP3_X(0,6), 1), "orn", "1id"},
	{FORMAT3(2, OP3_X(1,6), 0), "orncc", "12d"},
	{FORMAT3(2, OP3_X(1,6), 1), "orncc", "1id"},
	{FORMAT3(2, OP3_X(2,6), 0), "srl", "12d"},
	{FORMAT3(2, OP3_X(2,6), 1), "srl", "1Dd"},
	{FORMAT3(2, OP3_X(2,6)|X(1), 0), "srlx", "12d"},
	{FORMAT3(2, OP3_X(2,6)|X(1), 1), "srlx", "1Ed"},
	{FORMAT3(2, OP3_X(3,6), 1), "impdep1", ""},

	{FORMAT3(2, OP3_X(0,7), 0), "xorn", "12d"},
	{FORMAT3(2, OP3_X(0,7), 1), "xorn", "1id"},
	{FORMAT3(2, OP3_X(1,7), 0), "xorncc", "12d"},
	{FORMAT3(2, OP3_X(1,7), 1), "xorncc", "1id"},
	{FORMAT3(2, OP3_X(2,7), 0), "sra", "12d"},
	{FORMAT3(2, OP3_X(2,7), 1), "sra", "1Dd"},
	{FORMAT3(2, OP3_X(2,7)|X(1), 0), "srax", "12d"},
	{FORMAT3(2, OP3_X(2,7)|X(1), 1), "srax", "1Ed"},
	{FORMAT3(2, OP3_X(3,7), 1), "impdep2", ""},

	{FORMAT3(2, OP3_X(0,8), 0), "addc", "12d"},
	{FORMAT3(2, OP3_X(0,8), 1), "addc", "1id"},
	{FORMAT3(2, OP3_X(1,8), 0), "addccc", "12d"},
	{FORMAT3(2, OP3_X(1,8), 1), "addccc", "1id"},
#ifdef V9
	{(FORMAT3(2, 0x28, 1) | RS1(15)), "membar", "9"},
	{(FORMAT3(2, 0x28, 0) | RS1(15)), "stbar", ""},
	{FORMAT3(2, OP3_X(2,8), 0), "rd", "Bd"},
#else
	{FORMAT3(2, OP3_X(2,8), 0), "rd", "Yd"},
#endif

	{FORMAT3(2, OP3_X(3,8), 0), "jmpl", "pd"},
	{FORMAT3(2, OP3_X(3,8), 1), "jmpl", "qd"},

	{FORMAT3(2, OP3_X(0,9), 0), "mulx", "12d"},
	{FORMAT3(2, OP3_X(0,9), 1), "mulx", "1id"},
	{FORMAT3(2, OP3_X(1,9), 0), "UNDEFINED", ""},
#ifdef V9
	{FORMAT3(2, OP3_X(2,9), 0), "UNDEFINED", ""},
#else
	{FORMAT3(2, OP3_X(2,9), 0), "rd", "Pd"},
#endif
	{FORMAT3(2, OP3_X(3,9), 0), "return", "p"},
	{FORMAT3(2, OP3_X(3,9), 1), "return", "q"},

	{FORMAT3(2, OP3_X(0,10), 0), "umul", "12d"},
	{FORMAT3(2, OP3_X(0,10), 1), "umul", "1id"},
	{FORMAT3(2, OP3_X(1,10), 0), "umulcc", "12d"},
	{FORMAT3(2, OP3_X(1,10), 1), "umulcc", "1id"},
#ifdef V9
	{FORMAT3(2, OP3_X(2,10), 0), "rdpr", "Ad"},
#else
	{FORMAT3(2, OP3_X(2,10), 0), "rd", "Wd"},
#endif
		/*
		 * OP3 = (3,10): TCC: Trap on Integer Condition Codes
		 */
		{(FORMAT3(2, OP3_X(3,10), 0) | COND(0x8)), "ta", "12F"},
		{(FORMAT3(2, OP3_X(3,10), 1) | COND(0x8)), "ta", "0F"},
		{(FORMAT3(2, OP3_X(3,10), 0) | COND(0x0)), "tn", "12F"},
		{(FORMAT3(2, OP3_X(3,10), 1) | COND(0x0)), "tn", "0F"},
		{(FORMAT3(2, OP3_X(3,10), 0) | COND(0x9)), "tne", "12F"},
		{(FORMAT3(2, OP3_X(3,10), 1) | COND(0x9)), "tne", "0F"},
		{(FORMAT3(2, OP3_X(3,10), 0) | COND(0x1)), "te", "12F"},
		{(FORMAT3(2, OP3_X(3,10), 1) | COND(0x1)), "te", "0F"},
		{(FORMAT3(2, OP3_X(3,10), 0) | COND(0xa)), "tg", "12F"},
		{(FORMAT3(2, OP3_X(3,10), 1) | COND(0xa)), "tg", "0F"},
		{(FORMAT3(2, OP3_X(3,10), 0) | COND(0x2)), "tle", "12F"},
		{(FORMAT3(2, OP3_X(3,10), 1) | COND(0x2)), "tle", "0F"},
		{(FORMAT3(2, OP3_X(3,10), 0) | COND(0xb)), "tge", "12F"},
		{(FORMAT3(2, OP3_X(3,10), 1) | COND(0xb)), "tge", "0F"},
		{(FORMAT3(2, OP3_X(3,10), 0) | COND(0x3)), "tl", "12F"},
		{(FORMAT3(2, OP3_X(3,10), 1) | COND(0x3)), "tl", "0F"},
		{(FORMAT3(2, OP3_X(3,10), 0) | COND(0xc)), "tgu", "12F"},
		{(FORMAT3(2, OP3_X(3,10), 1) | COND(0xc)), "tgu", "0F"},
		{(FORMAT3(2, OP3_X(3,10), 0) | COND(0x4)), "tleu", "12F"},
		{(FORMAT3(2, OP3_X(3,10), 1) | COND(0x4)), "tleu", "0F"},
		{(FORMAT3(2, OP3_X(3,10), 0) | COND(0xd)), "tcc", "12F"},
		{(FORMAT3(2, OP3_X(3,10), 1) | COND(0xd)), "tcc", "0F"},
		{(FORMAT3(2, OP3_X(3,10), 0) | COND(0x5)), "tcs", "12F"},
		{(FORMAT3(2, OP3_X(3,10), 1) | COND(0x5)), "tcs", "0F"},
		{(FORMAT3(2, OP3_X(3,10), 0) | COND(0xe)), "tpos", "12F"},
		{(FORMAT3(2, OP3_X(3,10), 1) | COND(0xe)), "tpos", "0F"},
		{(FORMAT3(2, OP3_X(3,10), 0) | COND(0x6)), "tneg", "12F"},
		{(FORMAT3(2, OP3_X(3,10), 1) | COND(0x6)), "tneg", "0F"},
		{(FORMAT3(2, OP3_X(3,10), 0) | COND(0xf)), "tvc", "12F"},
		{(FORMAT3(2, OP3_X(3,10), 1) | COND(0xf)), "tvc", "0F"},
		{(FORMAT3(2, OP3_X(3,10), 0) | COND(0x7)), "tvs", "12F"},
		{(FORMAT3(2, OP3_X(3,10), 1) | COND(0x7)), "tvs", "0F"},

	{FORMAT3(2, OP3_X(0,11), 0), "smul", "12d"},
	{FORMAT3(2, OP3_X(0,11), 1), "smul", "1id"},
	{FORMAT3(2, OP3_X(1,11), 0), "smulcc", "12d"},
	{FORMAT3(2, OP3_X(1,11), 1), "smulcc", "1id"},
#ifdef V9
	{FORMAT3(2, OP3_X(2,11), 0), "flushw", ""},
#else
	{FORMAT3(2, OP3_X(2,11), 0), "rd", "Td"},
#endif
	{FORMAT3(2, OP3_X(3,11), 0), "flush", "p"},
	{FORMAT3(2, OP3_X(3,11), 1), "flush", "q"},

	{FORMAT3(2, OP3_X(0,12), 0), "subc", "12d"},
	{FORMAT3(2, OP3_X(0,12), 1), "subc", "1id"},
	{FORMAT3(2, OP3_X(1,12), 0), "subccc", "12d"},
	{FORMAT3(2, OP3_X(1,12), 1), "subccc", "1id"},
		/*
		 * OP3 = (2,12): MOVcc, Move Integer Register on Condition
		 */
		/* For Integer Condition Codes */
		{(FORMAT3(2, OP3_X(2,12), 1) | COND(8)), "mova", "0jd"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND(0)), "movn", "0jd"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND(9)), "movne", "0jd"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND(1)), "move", "0jd"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND(10)), "movg", "0jd"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND(2)), "movle", "0jd"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND(11)), "movge", "0jd"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND(3)), "movl", "0jd"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND(12)), "movgu", "0jd"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND(4)), "movleu", "0jd"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND(13)), "movcc", "0jd"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND(5)), "movcs", "0jd"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND(14)), "movpos", "0jd"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND(6)), "movneg", "0jd"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND(15)), "movvc", "0jd"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND(7)), "movvs", "0jd"},

		/* For Floating-Point Condition Codes */
		{(FORMAT3(2, OP3_X(2,12), 1) | COND(8)), "mova", "ojd"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND(0)), "movn", "ojd"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND(7)), "movu", "ojd"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND(6)), "movg", "ojd"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND(5)), "movug", "ojd"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND(4)), "movl", "ojd"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND(3)), "movul", "ojd"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND(2)), "movlg", "ojd"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND(1)), "movne", "ojd"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND(9)), "move", "ojd"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND(10)), "movue", "ojd"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND(11)), "movge", "ojd"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND(12)), "movuge", "ojd"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND(13)), "movle", "ojd"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND(14)), "movule", "ojd"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND(15)), "movo", "ojd"},

	{FORMAT3(2, OP3_X(3,12), 0), "save", "12d"},
	{FORMAT3(2, OP3_X(3,12), 1), "save", "1id"},

	{FORMAT3(2, OP3_X(0,13), 0), "udivx", "12d"},
	{FORMAT3(2, OP3_X(0,13), 1), "udivx", "1id"},
	{FORMAT3(2, OP3_X(1,13), 0), "UNDEFINED", ""},
	{FORMAT3(2, OP3_X(2,13), 0), "sdivx", "12d"},
	{FORMAT3(2, OP3_X(2,13), 1), "sdivx", "1id"},
	{FORMAT3(2, OP3_X(3,13), 0), "restore", "12d"},
	{FORMAT3(2, OP3_X(3,13), 1), "restore", "1id"},

	{FORMAT3(2, OP3_X(0,14), 0), "udiv", "12d"},
	{FORMAT3(2, OP3_X(0,14), 1), "udiv", "1id"},
	{FORMAT3(2, OP3_X(1,14), 0), "udivcc", "12d"},
	{FORMAT3(2, OP3_X(1,14), 1), "udivcc", "1id"},
	{FORMAT3(2, OP3_X(2,14), 0), "popc", "2d"},
	{FORMAT3(2, OP3_X(2,14), 1), "popc", "id"},

	{FORMAT3(2, OP3_X(3,14), 0), "done", ""},
	{FORMAT3(2, OP3_X(3,14)|FCN(1), 1), "retry", ""},

	{FORMAT3(2, OP3_X(0,15), 0), "sdiv", "12d"},
	{FORMAT3(2, OP3_X(0,15), 1), "sdiv", "1id"},
	{FORMAT3(2, OP3_X(1,15), 0), "sdivcc", "12d"},
	{FORMAT3(2, OP3_X(1,15), 1), "sdivcc", "1id"},
		/*
		 * OP3 = (2,15): MOVr:
		 * 	Move Integer Register on Register Condition
		 */
		{(FORMAT3(2, OP3_X(2,15), 1) | RCOND34(1)), "movrz", "1jd"},
		{(FORMAT3(2, OP3_X(2,15), 0) | RCOND34(1)), "movrz", "12d"},
		{(FORMAT3(2, OP3_X(2,15), 1) | RCOND34(2)), "movrlez", "1jd"},
		{(FORMAT3(2, OP3_X(2,15), 0) | RCOND34(2)), "movrlez", "12d"},
		{(FORMAT3(2, OP3_X(2,15), 1) | RCOND34(3)), "movrlz", "1jd"},
		{(FORMAT3(2, OP3_X(2,15), 0) | RCOND34(3)), "movrlz", "12d"},
		{(FORMAT3(2, OP3_X(2,15), 1) | RCOND34(5)), "movrnz", "1jd"},
		{(FORMAT3(2, OP3_X(2,15), 0) | RCOND34(5)), "movrnz", "12d"},
		{(FORMAT3(2, OP3_X(2,15), 1) | RCOND34(6)), "movrgz", "1jd"},
		{(FORMAT3(2, OP3_X(2,15), 0) | RCOND34(6)), "movrgz", "12d"},
		{(FORMAT3(2, OP3_X(2,15), 1) | RCOND34(7)), "movrgez", "1jd"},
		{(FORMAT3(2, OP3_X(2,15), 0) | RCOND34(7)), "movrgez", "12d"},

	{FORMAT3(2, OP3_X(3,15), 0), "UNDEFINED", ""},

	/*
	 * Format 3/3: Load and store (appendix E, table 33)
	 */

	/* Loads */
	{(FORMAT3(3, OP3_X(0,0), 0)), "ld", "pd"},	/* officially: lduw */
	{(FORMAT3(3, OP3_X(0,0), 1)), "ld", "qd"},
	{(FORMAT3(3, OP3_X(1,0), 0)), "lda", "7d"},	/* officially: lduwa */
	{(FORMAT3(3, OP3_X(1,0), 1)), "lda", "8d"},
	{(FORMAT3(3, OP3_X(2,0), 0)), "ldf", "pe"},
	{(FORMAT3(3, OP3_X(2,0), 1)), "ldf", "qe"},
	{(FORMAT3(3, OP3_X(3,0), 0)), "ldfa", "7e"},
	{(FORMAT3(3, OP3_X(3,0), 1)), "ldfa", "8e"},

	{(FORMAT3(3, OP3_X(0,1), 0)), "ldub", "pd"},
	{(FORMAT3(3, OP3_X(0,1), 1)), "ldub", "qd"},
	{(FORMAT3(3, OP3_X(1,1), 0)), "lduba", "7d"},
	{(FORMAT3(3, OP3_X(1,1), 1)), "lduba", "8d"},
	{(FORMAT3(3, OP3_X(2,1), 0) | RD(0)), "ld", "p5"},
	{(FORMAT3(3, OP3_X(2,1), 1) | RD(0)), "ld", "q5"},
	{(FORMAT3(3, OP3_X(2,1), 0) | RD(1)), "ldx", "p6"},
	{(FORMAT3(3, OP3_X(2,1), 1) | RD(1)), "ldx", "q6"},

	{(FORMAT3(3, OP3_X(0,2), 0)), "lduh", "pd"},
	{(FORMAT3(3, OP3_X(0,2), 1)), "lduh", "qd"},
	{(FORMAT3(3, OP3_X(1,2), 0)), "lduha", "7d"},
	{(FORMAT3(3, OP3_X(1,2), 1)), "lduha", "8d"},
	{(FORMAT3(3, OP3_X(2,2), 0)), "ldq", "pe"},
	{(FORMAT3(3, OP3_X(2,2), 1)), "ldq", "qe"},
	{(FORMAT3(3, OP3_X(3,2), 0)), "ldqa", "7e"},
	{(FORMAT3(3, OP3_X(3,2), 1)), "ldqa", "8e"},

	{(FORMAT3(3, OP3_X(0,3), 0)), "ldd", "pd"},
	{(FORMAT3(3, OP3_X(0,3), 1)), "ldd", "qd"},
	{(FORMAT3(3, OP3_X(1,3), 0)), "ldda", "7d"},
	{(FORMAT3(3, OP3_X(1,3), 1)), "ldda", "8d"},
	{(FORMAT3(3, OP3_X(2,3), 0)), "ldd", "pe"},
	{(FORMAT3(3, OP3_X(2,3), 1)), "ldd", "qe"},
	{(FORMAT3(3, OP3_X(3,3), 0)), "ldda", "7e"},
	{(FORMAT3(3, OP3_X(3,3), 1)), "ldda", "8e"},

	{(FORMAT3(3, OP3_X(0,4), 0)), "st", "dp"},	/* officially: stw */
	{(FORMAT3(3, OP3_X(0,4), 1)), "st", "dq"},
	{(FORMAT3(3, OP3_X(1,4), 0)), "sta", "d7"},	/* officially: stwa */
	{(FORMAT3(3, OP3_X(1,4), 1)), "sta", "d8"},
	{(FORMAT3(3, OP3_X(2,4), 0)), "st", "ep"},
	{(FORMAT3(3, OP3_X(2,4), 1)), "st", "eq"},
	{(FORMAT3(3, OP3_X(3,4), 0)), "sta", "e7"},
	{(FORMAT3(3, OP3_X(3,4), 1)), "sta", "e8"},

	{(FORMAT3(3, OP3_X(0,5), 0)), "stb", "dp"},
	{(FORMAT3(3, OP3_X(0,5), 1)), "stb", "dq"},
	{(FORMAT3(3, OP3_X(1,5), 0)), "stba", "d7"},
	{(FORMAT3(3, OP3_X(1,5), 1)), "stba", "d8"},
	{(FORMAT3(3, OP3_X(2,5), 0)), "st", "5p"},
	{(FORMAT3(3, OP3_X(2,5), 1)), "st", "5q"},
	{(FORMAT3(3, OP3_X(2,5), 0)|RD(1)), "stx", "6p"},
	{(FORMAT3(3, OP3_X(2,5), 1)|RD(1)), "stx", "6q"},

	{(FORMAT3(3, OP3_X(0,6), 0)), "sth", "dp"},
	{(FORMAT3(3, OP3_X(0,6), 1)), "sth", "dq"},
	{(FORMAT3(3, OP3_X(1,6), 0)), "stha", "d7"},
	{(FORMAT3(3, OP3_X(1,6), 1)), "stha", "d8"},
	{(FORMAT3(3, OP3_X(2,6), 0)), "stq", "ep"},
	{(FORMAT3(3, OP3_X(2,6), 1)), "stq", "eq"},
	{(FORMAT3(3, OP3_X(3,6), 0)), "stqa", "e7"},
	{(FORMAT3(3, OP3_X(3,6), 1)), "stqa", "e8"},

	{(FORMAT3(3, OP3_X(0,7), 0)), "std", "dp"},
	{(FORMAT3(3, OP3_X(0,7), 1)), "std", "dq"},
	{(FORMAT3(3, OP3_X(1,7), 0)), "stda", "d7"},
	{(FORMAT3(3, OP3_X(1,7), 1)), "stda", "d8"},
	{(FORMAT3(3, OP3_X(2,7), 0)), "std", "ep"},
	{(FORMAT3(3, OP3_X(2,7), 1)), "std", "eq"},
	{(FORMAT3(3, OP3_X(3,7), 0)), "stda", "e7"},
	{(FORMAT3(3, OP3_X(3,7), 1)), "stda", "e8"},

	{(FORMAT3(3, OP3_X(0,8), 0)), "ldsw", "pd"},
	{(FORMAT3(3, OP3_X(0,8), 1)), "ldsw", "qd"},
	{(FORMAT3(3, OP3_X(1,8), 0)), "ldswa", "7d"},
	{(FORMAT3(3, OP3_X(1,8), 1)), "ldswa", "8d"},

	{(FORMAT3(3, OP3_X(0,9), 0)), "ldsb", "pd"},
	{(FORMAT3(3, OP3_X(0,9), 1)), "ldsb", "qd"},
	{(FORMAT3(3, OP3_X(1,9), 0)), "ldsba", "7d"},
	{(FORMAT3(3, OP3_X(1,9), 1)), "ldsba", "8d"},

	{(FORMAT3(3, OP3_X(0,10), 0)), "ldsh", "pd"},
	{(FORMAT3(3, OP3_X(0,10), 1)), "ldsh", "qd"},
	{(FORMAT3(3, OP3_X(1,10), 0)), "ldsha", "7d"},
	{(FORMAT3(3, OP3_X(1,10), 1)), "ldsha", "8d"},

	{(FORMAT3(3, OP3_X(0,11), 0)), "ldx", "pd"},
	{(FORMAT3(3, OP3_X(0,11), 1)), "ldx", "qd"},
	{(FORMAT3(3, OP3_X(1,11), 0)), "ldxa", "7d"},
	{(FORMAT3(3, OP3_X(1,11), 1)), "ldxa", "8d"},

	{(FORMAT3(3, OP3_X(3,12), 1)), "casa", "s2d"},
	{(FORMAT3(3, OP3_X(3,12), 0)), "casa", "t2d"},

	{(FORMAT3(3, OP3_X(0,13), 0)), "ldstub", "7d"},
	{(FORMAT3(3, OP3_X(0,13), 1)), "ldstub", "8d"},
	{(FORMAT3(3, OP3_X(1,13), 0)), "ldstuba", "pd"},
	{(FORMAT3(3, OP3_X(1,13), 1)), "ldstuba", "qd"},
	{(FORMAT3(3, OP3_X(2,13), 0)), "prefetch", "pr"},
	{(FORMAT3(3, OP3_X(2,13), 1)), "prefetch", "qr"},
	{(FORMAT3(3, OP3_X(3,13), 0)), "prefetcha", "7r"},
	{(FORMAT3(3, OP3_X(3,13), 1)), "prefetcha", "8r"},

	{(FORMAT3(3, OP3_X(0,14), 0)), "stx", "dp"},
	{(FORMAT3(3, OP3_X(0,14), 1)), "stx", "dq"},
	{(FORMAT3(3, OP3_X(1,14), 0)), "stwa", "d7"},
	{(FORMAT3(3, OP3_X(1,14), 1)), "stwa", "d8"},
	{(FORMAT3(3, OP3_X(3,14), 0)), "casxa", "t2d"},
	{(FORMAT3(3, OP3_X(3,14), 1)), "casxa", "s2d"},

	/* Swap Register */
	{(FORMAT3(3, OP3_X(0,15), 0)), "swap", "pd"},
	{(FORMAT3(3, OP3_X(0,15), 1)), "swap", "qd"},
	{(FORMAT3(3, OP3_X(1,15), 0)), "swapa", "7d"},
	{(FORMAT3(3, OP3_X(1,15), 1)), "swapa", "8d"},

	/*
	 * OP3 = (3,4): FPop1 (table 34)
	 */
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(0,1))), "fmovs", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(0,2))), "fmovd", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(0,3))), "fmovq", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(0,5))), "fnegs", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(0,6))), "fnegd", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(0,7))), "fnegq", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(0,9))), "fabss", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(0,10))), "fabsd", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(0,11))), "fabsq", "4e"},

	{(FORMAT3F(2, OP3_X(3,4), OPF_X(2,9))), "fsqrts", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(2,10))), "fsqrtd", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(2,11))), "fsqrtq", "4e"},

	{(FORMAT3F(2, OP3_X(3,4), OPF_X(4,1))), "fadds", "34e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(4,2))), "faddd", "34e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(4,3))), "faddq", "34e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(4,5))), "fsubs", "34e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(4,6))), "fsubd", "34e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(4,7))), "fsubq", "34e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(4,9))), "fmuls", "34e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(4,10))), "fmuld", "34e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(4,11))), "fmulq", "34e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(4,13))), "fdivs", "34e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(4,14))), "fdivd", "34e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(4,15))), "fdivq", "34e"},

	{(FORMAT3F(2, OP3_X(3,4), OPF_X(6,9))), "fsmuld", "34e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(6,14))), "fdmulq", "34e"},

	{(FORMAT3F(2, OP3_X(3,4), OPF_X(8,1))), "fstox", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(8,2))), "fdtox", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(8,3))), "fqtox", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(8,4))), "fxtos", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(8,8))), "fxtod", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(8,12))), "fxtoq", "4e"},

	{(FORMAT3F(2, OP3_X(3,4), OPF_X(12,4))), "fitos", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(12,6))), "fdtos", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(12,7))), "fqtos", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(12,8))), "fitod", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(12,9))), "fstod", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(12,11))), "fqtod", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(12,12))), "fitoq", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(12,13))), "fstoq", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(12,14))), "fdtoq", "4e"},

	{(FORMAT3F(2, OP3_X(3,4), OPF_X(13,1))), "fstoi", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(13,2))), "fdtoi", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(13,3))), "fqtoi", "4e"},

#ifdef xxx
	/*
	 * OP3 =(3,5): FPop2 (table 35)
	 */
	{(FORMAT3F(2, OP3_X(3,5), 81)), "fcmps", "o34"},
	{(FORMAT3F(2, OP3_X(3,5), 82)), "fcmpd", "o34"},
	{(FORMAT3F(2, OP3_X(3,5), 83)), "fcmpq", "o34"},
	{(FORMAT3F(2, OP3_X(3,5), 85)), "fcmpes", "o34"},
	{(FORMAT3F(2, OP3_X(3,5), 86)), "fcmped", "o34"},
	{(FORMAT3F(2, OP3_X(3,5), 87)), "fcmpeq", "o34"},

	/* Move Floating-Point Register on Condition "FMOVcc" */
	/* FIXME should check for single, double, and quad movements */
	/* Integer Condition Codes */
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(8)), "fmova", "04e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(0)), "fmovn", "04e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(9)), "fmovne", "04e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(1)), "fmove", "04e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(10)), "fmovg", "04e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(2)), "fmovle", "04e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(11)), "fmovge", "04e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(3)), "fmovl", "04e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(12)), "fmovgu", "04e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(4)), "fmovleu", "04e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(13)), "fmovcc", "04e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(5)), "fmovcs", "04e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(14)), "fmovpos", "04e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(6)), "fmovneg", "04e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(15)), "fmovvc", "04e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(7)), "fmovvs", "04e"},

	/* Floating-Point Condition Codes */
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(8)), "fmova", "o4e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(0)), "fmovn", "o4e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(7)), "fmovu", "o4e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(6)), "fmovg", "o4e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(5)), "fmovug", "o4e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(4)), "fmovk", "o4e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(3)), "fmovul", "o4e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(2)), "fmovlg", "o4e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(1)), "fmovne", "o4e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(9)), "fmove", "o4e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(10)), "fmovue", "o4e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(11)), "fmovge", "o4e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(12)), "fmovuge", "o4e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(13)), "fmovle", "o4e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(14)), "fmovule", "o4e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(15)), "fmovo", "o4e"},

	/* Move F-P Register on Integer Register Condition "FMOVr" */
	/* FIXME: check for short, double, and quad's */
	{(FORMAT3(2, OP3_X(3,5), 0) | RCOND34(1)), "fmovre", "14e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | RCOND34(2)), "fmovrlez", "14e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | RCOND34(3)), "fmovrlz", "14e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | RCOND34(5)), "fmovrne", "14e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | RCOND34(6)), "fmovrgz", "14e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | RCOND34(7)), "fmovrgez", "14e"},
#endif

	/* grrrr.... */
	{0, 0, 0}

};

db_addr_t
db_disasm(loc, altfmt)
	vaddr_t loc;
	boolean_t altfmt;
{
	struct sparc_insn*	i_ptr = (struct sparc_insn *)&sparc_i;

	unsigned long int insn, you_lose, bitmask;
	int matchp;
	char *f_ptr, *cp;

	you_lose = 0;
	matchp = 0;
	insn = db_get_value(loc, 4, 0);

	if (insn == 0x01000000) {
		db_printf("nop\n");
		return loc + 4;
	}

	while (i_ptr->name) {
		/* calculate YOU_LOSE value */
		bitmask= (i_ptr->match);
		you_lose = (~bitmask);

		if (((bitmask>>30) & 0x3) == 0x1) {
			/* Call */
			you_lose = ((~0x1)<<30);
		} else if (((bitmask>>30) & 0x3) == 0x0) {
			if (((bitmask>>22) & 0x7) == 0x4) {
				/* Sethi */
				you_lose &= (FORMAT2(0x3,0x7));
			} else {
				/* Branches */
				you_lose &= (FORMAT2(0x3,0x7)|COND(0xf));
			}
		} else if (((bitmask>>30) & 0x3) == 0x2 &&
			   ((bitmask>>19) & 0x3f) == 0x34) /* XXX */ {
			/* FPop1 */
			you_lose &= (FORMAT3(0x3,0x3f,0x1) | OPF(0x1ff));
		} else {
			you_lose &= (FORMAT3(0x3,0x3f,0x1));
		}

		if (((bitmask & insn) == bitmask) && ((you_lose & insn) == 0)) {
			matchp = 1;
			break;
		}
		i_ptr++;
	};

	if (!matchp) {
		db_printf("undefined\n");
		return loc + 4;
	}

	db_printf("%s", i_ptr->name);

	f_ptr = i_ptr->format;

	for (cp = f_ptr; *cp; cp++) {
		if (*cp == ',') {
			for (;f_ptr < cp; f_ptr++)
				switch (*f_ptr) {
				case 'a':
					if (insn & A(1))
						db_printf(",a");
					break;
				case 'p':
					if (insn & P(1))
						db_printf(",pt");
					else
						db_printf(",pn");
					break;
				}
			f_ptr++;
			break;
		}
	}
	db_printf("      \t");

	while (*f_ptr) {
		switch (*f_ptr) {
		case '1':
			db_printf("%%%s", regs[((insn >> 14) & 0x1f)]);
			break;
		case '2':
			db_printf("%%%s", regs[(insn & 0x1f)]);
			break;
		case 'd':
			db_printf("%%%s", regs[((insn >> 25) & 0x1f)]);
			break;
		case '3':
			db_printf("%%f%ld", ((insn >> 14) & 0x1f));
			break;
		case '4':
			db_printf("%%f%ld", (insn & 0x1f));
			break;
		case 'e':
			db_printf("%%f%ld", ((insn >> 25) & 0x1f));
			break;
		case 'i':
			db_printf("0x%lx", (insn & 0x1fff));
			break;
		case 'j':
			db_printf("0x%lx", (insn & 0x7ff));
			break;
		case 'l':
			db_printf("0x%lx", ((insn & 0x1fff) |
				((insn >> 20) & 0x3)));
			break;
		case 'm':
			db_printsym(
				(db_addr_t)(loc + (4 * (insn & 0x3fffff))),
				DB_STGY_ANY, db_printf);
			break;
		case 'u':
			db_printsym(
				(db_addr_t)(loc + (4 * (insn & 0x7ffff))),
				DB_STGY_ANY, db_printf);
			break;
		case 'n':
			db_printsym(
				(db_addr_t)(loc + (4 * (insn & 0x3fffffff))),
				DB_STGY_PROC, db_printf);
			break;
		case 's':
			db_printf("%%asi");
			break;
		case 't':
			db_printf("0x%-2.2lx", ((insn >> 5) & 0xff));
			break;
		case 'o':
			db_printf("%%fcc%ld", ((insn >> 25) & 0x3));
			break;
		case 'p':
		case '7':
			db_printf("[%%%s + %%%s]",
				  regs[((insn >> 14) & 0x1f)],
				  regs[(insn & 0x1f)]);
			if (*f_ptr == '7')
				db_printf(" %ld", ((insn >> 5) & 0xff));
			break;
		case 'q':
		case '8':
			db_printf("[%%%s + 0x%lx]",
				  regs[((insn >> 14) & 0x1f)],
				  (insn & 0x1fff));
			if (*f_ptr == '8')
				db_printf(" %%asi");
			break;
		case '5':
			db_printf("%%fsr");
			break;
		case '6':
			db_printf("%%fsr");
			break;
		case '9':
			db_printf("0x%lxl",
				  ((insn & 0xf) | ((insn >> 4) & 0x7)));
			break;
		case '0':
			db_printf("%%%s", ccodes[((insn >> 11) & 0x7)]);
			break;
		case 'r':
			db_printf("#%s", prefetch[((insn >> 25) & 0x1f)]);
			break;
		case 'A':
			db_printf("%%%s", priv_regs[((insn >> 14) & 0x1f)]);
			break;
		case 'B':
			db_printf("%%%s", state_regs[((insn >> 14) & 0x1f)]);
			break;
		case 'C':
			db_printf("%%hi(0x%lx)", ((insn & 0x3fffff) << 10));
			break;
		case 'D':
			db_printf("0x%lx", (insn & 0x1f));
			break;
		case 'E':
			db_printf("0x%lx", (insn & 0x3f));
			break;
		case 'F':
			db_printf("0x%lx", (insn & 0x3f));
			break;
		case 'G':
			db_printf("%%%s", priv_regs[((insn >> 25) & 0x1f)]);
			break;
		case 'H':
			db_printf("%%%s", state_regs[((insn >> 25) & 0x1f)]);
			break;
#ifndef V9
		case 'P':
			db_printf("%%psr");
			break;
		case 'T':
			db_printf("%%tbr");
			break;
		case 'W':
			db_printf("%%wim");
			break;
		case 'Y':
			db_printf("%%y");
			break;
#endif
		default:
			db_printf("(UNKNOWN)");
			break;
		}
		if (*(++f_ptr))
			db_printf(", ");
	};

	db_printf("\n");

	return (loc + 4);
}


code:
/*	$OpenBSD: db_interface.c,v 1.15 2015/03/18 20:49:10 miod Exp $	*/
/*	$NetBSD: db_interface.c,v 1.18 1997/09/01 00:16:31 pk Exp $ */

/*
 * Mach Operating System
 * Copyright (c) 1991,1990 Carnegie Mellon University
 * All Rights Reserved.
 *
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 *
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 *
 * Carnegie Mellon requests users of this software to return to
 *
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 *
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 *
 *	From: db_interface.c,v 2.4 1991/02/05 17:11:13 mrt (CMU)
 */

/*
 * Interface to new debugger.
 */
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/reboot.h>
#include <sys/systm.h>

#include <uvm/uvm_extern.h>

#include <dev/cons.h>

#include <machine/autoconf.h>
#include <machine/db_machdep.h>

#include <ddb/db_access.h>
#include <ddb/db_var.h>

#if defined(DDB)
#include <ddb/db_command.h>
#include <ddb/db_sym.h>
#include <ddb/db_variables.h>
#include <ddb/db_extern.h>
#include <ddb/db_output.h>
#endif

#include <machine/bsd_openprom.h>
#include <machine/ctlreg.h>
#include <sparc/sparc/asm.h>

/*
 * Read bytes from kernel address space for debugger.
 */
void
db_read_bytes(addr, size, data)
	vaddr_t	addr;
	size_t	size;
	char	*data;
{
	char	*src;

	src = (char *)addr;
	while (size-- > 0)
		*data++ = *src++;
}

/*
 * Write bytes to kernel address space for debugger.
 */
void
db_write_bytes(addr, size, data)
	vaddr_t	addr;
	size_t	size;
	char	*data;
{
	extern char	__data_start[];
	char	*dst;

	dst = (char *)addr;
	while (size-- > 0) {
		if (dst >= (char *)KERNBASE && dst < __data_start)
			pmap_writetext(dst, *data);
		else
			*dst = *data;
		dst++, data++;
	}

}

#if defined(DDB)

/*
 * Data and functions used by DDB only.
 */
void
Debugger()
{
	asm("ta 0x81");
}

static int nil;

struct db_variable db_regs[] = {
	{ "psr", (long *)&DDB_TF->tf_psr, FCN_NULL, },
	{ "pc", (long *)&DDB_TF->tf_pc, FCN_NULL, },
	{ "npc", (long *)&DDB_TF->tf_npc, FCN_NULL, },
	{ "y", (long *)&DDB_TF->tf_y, FCN_NULL, },
	{ "wim", (long *)&DDB_TF->tf_global[0], FCN_NULL, }, /* see reg.h */
	{ "g0", (long *)&nil, FCN_NULL, },
	{ "g1", (long *)&DDB_TF->tf_global[1], FCN_NULL, },
	{ "g2", (long *)&DDB_TF->tf_global[2], FCN_NULL, },
	{ "g3", (long *)&DDB_TF->tf_global[3], FCN_NULL, },
	{ "g4", (long *)&DDB_TF->tf_global[4], FCN_NULL, },
	{ "g5", (long *)&DDB_TF->tf_global[5], FCN_NULL, },
	{ "g6", (long *)&DDB_TF->tf_global[6], FCN_NULL, },
	{ "g7", (long *)&DDB_TF->tf_global[7], FCN_NULL, },
	{ "o0", (long *)&DDB_TF->tf_out[0], FCN_NULL, },
	{ "o1", (long *)&DDB_TF->tf_out[1], FCN_NULL, },
	{ "o2", (long *)&DDB_TF->tf_out[2], FCN_NULL, },
	{ "o3", (long *)&DDB_TF->tf_out[3], FCN_NULL, },
	{ "o4", (long *)&DDB_TF->tf_out[4], FCN_NULL, },
	{ "o5", (long *)&DDB_TF->tf_out[5], FCN_NULL, },
	{ "o6", (long *)&DDB_TF->tf_out[6], FCN_NULL, },
	{ "o7", (long *)&DDB_TF->tf_out[7], FCN_NULL, },
	{ "l0", (long *)&DDB_FR->fr_local[0], FCN_NULL, },
	{ "l1", (long *)&DDB_FR->fr_local[1], FCN_NULL, },
	{ "l2", (long *)&DDB_FR->fr_local[2], FCN_NULL, },
	{ "l3", (long *)&DDB_FR->fr_local[3], FCN_NULL, },
	{ "l4", (long *)&DDB_FR->fr_local[4], FCN_NULL, },
	{ "l5", (long *)&DDB_FR->fr_local[5], FCN_NULL, },
	{ "l6", (long *)&DDB_FR->fr_local[6], FCN_NULL, },
	{ "l7", (long *)&DDB_FR->fr_local[7], FCN_NULL, },
	{ "i0", (long *)&DDB_FR->fr_arg[0], FCN_NULL, },
	{ "i1", (long *)&DDB_FR->fr_arg[1], FCN_NULL, },
	{ "i2", (long *)&DDB_FR->fr_arg[2], FCN_NULL, },
	{ "i3", (long *)&DDB_FR->fr_arg[3], FCN_NULL, },
	{ "i4", (long *)&DDB_FR->fr_arg[4], FCN_NULL, },
	{ "i5", (long *)&DDB_FR->fr_arg[5], FCN_NULL, },
	{ "i6", (long *)&DDB_FR->fr_arg[6], FCN_NULL, },
	{ "i7", (long *)&DDB_FR->fr_arg[7], FCN_NULL, },
};
struct db_variable *db_eregs = db_regs + nitems(db_regs);

extern label_t	*db_recover;

db_regs_t	ddb_regs;	/* register state */

int	db_active = 0;

extern char *trap_type[];

void kdb_kbd_trap(struct trapframe *);
void db_prom_cmd(db_expr_t, int, db_expr_t, char *);

/*
 * Received keyboard interrupt sequence.
 */
void
kdb_kbd_trap(tf)
	struct trapframe *tf;
{
	if (db_active == 0 && (boothowto & RB_KDB)) {
		printf("\n\nkernel: keyboard interrupt\n");
		kdb_trap(-1, tf);
	}
}

/*
 *  kdb_trap - field a TRACE or BPT trap
 */
int
kdb_trap(type, tf)
	int	type;
	struct trapframe *tf;
{

	fb_unblank();

	switch (type) {
	case T_BREAKPOINT:	/* breakpoint */
	case -1:		/* keyboard interrupt */
		break;
	default:
		if (!db_panic)
			return (0);

		printf("kernel: %s trap", trap_type[type & 0xff]);
		if (db_recover != 0) {
			db_error("Faulted in DDB; continuing...\n");
			/*NOTREACHED*/
		}
	}

	/* Should switch to kdb`s own stack here. */

	ddb_regs.db_tf = *tf;
	ddb_regs.db_fr = *(struct frame *)tf->tf_out[6];

	db_active++;
	cnpollc(TRUE);
	db_trap(type, 0/*code*/);
	cnpollc(FALSE);
	db_active--;

	*(struct frame *)tf->tf_out[6] = ddb_regs.db_fr;
	*tf = ddb_regs.db_tf;

	return (1);
}

void
db_prom_cmd(addr, have_addr, count, modif)
	db_expr_t addr;
	int have_addr;
	db_expr_t count;
	char *modif;
{
	callrom();
}

struct db_command sparc_db_command_table[] = {
	{ "prom",	db_prom_cmd,	0,	0 },
	{ (char *)0, }
};

void
db_machine_init()
{
	db_machine_commands_install(sparc_db_command_table);
}
#endif /* DDB */

license: unknown


code:
/*	$OpenBSD: db_trace.c,v 1.9 2015/03/18 20:49:40 miod Exp $	*/
/*	$NetBSD: db_trace.c,v 1.9 1997/07/29 09:42:00 fair Exp $ */

/*
 * Mach Operating System
 * Copyright (c) 1991,1990 Carnegie Mellon University
 * All Rights Reserved.
 *
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 *
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 *
 * Carnegie Mellon requests users of this software to return to
 *
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 *
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 */

#include <sys/param.h>
#include <sys/proc.h>
#include <machine/db_machdep.h>

#include <ddb/db_access.h>
#include <ddb/db_sym.h>
#include <ddb/db_interface.h>
#include <ddb/db_output.h>

#define INKERNEL(va)		(((vaddr_t)(va)) >= vm_min_kernel_address)
#define INKERNELTEXT(va)	(((vaddr_t)(va)) >= KERNBASE)

void
db_stack_trace_print(addr, have_addr, count, modif, pr)
	db_expr_t       addr;
	int             have_addr;
	db_expr_t       count;
	char            *modif;
	int		(*pr)(const char *, ...);
{
	struct frame	*frame;
	boolean_t	kernel_only = TRUE;

	{
		char c, *cp = modif;
		while ((c = *cp++) != 0)
			if (c == 'u')
				kernel_only = FALSE;
	}

	if (count == -1)
		count = 65535;

	if (!have_addr)
		frame = (struct frame *)DDB_TF->tf_out[6];
	else
		frame = (struct frame *)addr;

	while (count--) {
		int		i;
		db_expr_t	offset;
		char		*name;
		db_addr_t	pc;

		pc = frame->fr_pc;
		if (!INKERNELTEXT(pc))
			break;

		/*
		 * Switch to frame that contains arguments
		 */
		frame = frame->fr_fp;
		if (!INKERNEL(frame))
			break;

		db_find_sym_and_offset(pc, &name, &offset);
		if (name == NULL)
			name = "?";

		(*pr)("%s(", name);

		/*
		 * Print %i0..%i5, hope these still reflect the
		 * actual arguments somewhat...
		 */
		for (i=0; i < 5; i++)
			(*pr)("0x%x, ", frame->fr_arg[i]);
		(*pr)("0x%x) at ", frame->fr_arg[i]);
		db_printsym(pc, DB_STGY_PROC, pr);
		(*pr)("\n");

	}
}


code:
/*	$OpenBSD: disksubr.c,v 1.93 2015/01/16 20:17:05 miod Exp $	*/
/*	$NetBSD: disksubr.c,v 1.16 1996/04/28 20:25:59 thorpej Exp $ */

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

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/ioccom.h>
#include <sys/device.h>
#include <sys/disklabel.h>
#include <sys/disk.h>
#include <sys/dkbad.h>

#include <machine/cpu.h>
#include <machine/autoconf.h>
#include <dev/sun/disklabel.h>

#if defined(SUN4)
#include <machine/oldmon.h>
#endif

#include "cd.h"

static	int disklabel_sun_to_bsd(struct sun_disklabel *, struct disklabel *);
static	int disklabel_bsd_to_sun(struct disklabel *, struct sun_disklabel *);
static __inline u_int sun_extended_sum(struct sun_disklabel *, void *);

#if NCD > 0
extern void cdstrategy(struct buf *);
#endif

/*
 * Attempt to read a disk label from a device
 * using the indicated strategy routine.
 * The label must be partly set up before this:
 * secpercyl, secsize and anything required for a block i/o read
 * operation in the driver's strategy/start routines
 * must be filled in before calling us.
 */
int
readdisklabel(dev_t dev, void (*strat)(struct buf *),
    struct disklabel *lp, int spoofonly)
{
	struct sun_disklabel *slp;
	struct buf *bp = NULL;
	int error;

	if ((error = initdisklabel(lp)))
		goto done;
	lp->d_flags |= D_VENDOR;

	/*
	 * On sparc64 we check for a CD label first, because our
	 * CD install media contains both sparc & sparc64 labels.
	 * We want the sparc64 machine to find the "CD label", not
	 * the SunOS label, for loading its kernel.
	 */
#if NCD > 0
	if (strat == cdstrategy) {
#if defined(CD9660)
		if ((error = iso_disklabelspoof(dev, strat, lp)) == 0)
			goto done;
#endif
#if defined(UDF)
		if ((error = udf_disklabelspoof(dev, strat, lp)) == 0)
			goto done;
#endif
	}
#endif /* NCD > 0 */

	/* get buffer and initialize it */
	bp = geteblk((int)lp->d_secsize);
	bp->b_dev = dev;

	if (spoofonly)
		goto doslabel;

	bp->b_blkno = LABELSECTOR;
	bp->b_bcount = lp->d_secsize;
	CLR(bp->b_flags, B_READ | B_WRITE | B_DONE);
	SET(bp->b_flags, B_BUSY | B_READ | B_RAW);
	(*strat)(bp);
	if (biowait(bp)) {
		error = bp->b_error;
		goto done;
	}

	slp = (struct sun_disklabel *)bp->b_data;
	if (slp->sl_magic == SUN_DKMAGIC) {
		error = disklabel_sun_to_bsd(slp, lp);
		goto done;
	}

	error = checkdisklabel(bp->b_data + LABELOFFSET, lp, 0, DL_GETDSIZE(lp));
	if (error == 0)
		goto done;

doslabel:
	error = readdoslabel(bp, strat, lp, NULL, spoofonly);
	if (error == 0)
		goto done;

	/* A CD9660/UDF label may be on a non-CD drive, so recheck */
#if defined(CD9660)
	error = iso_disklabelspoof(dev, strat, lp);
	if (error == 0)
		goto done;
#endif
#if defined(UDF)
	error = udf_disklabelspoof(dev, strat, lp);
	if (error == 0)
		goto done;
#endif

done:
	if (bp) {
		bp->b_flags |= B_INVAL;
		brelse(bp);
	}
	disk_change = 1;
	return (error);
}

/*
 * Write disk label back to device after modification.
 */
int
writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp)
{
	struct buf *bp = NULL;
	int error;

	/* get buffer and initialize it */
	bp = geteblk((int)lp->d_secsize);
	bp->b_dev = dev;

	error = disklabel_bsd_to_sun(lp, (struct sun_disklabel *)bp->b_data);
	if (error)
		goto done;

	/* Write out the updated label. */
	bp->b_blkno = LABELSECTOR;
	bp->b_bcount = lp->d_secsize;
	CLR(bp->b_flags, B_READ | B_WRITE | B_DONE);
	SET(bp->b_flags, B_BUSY | B_WRITE | B_RAW);
	(*strat)(bp);
	error = biowait(bp);

done:
	if (bp) {
		bp->b_flags |= B_INVAL;
		brelse(bp);
	}
	disk_change = 1;
	return (error);
}

/************************************************************************
 *
 * The rest of this was taken from arch/sparc/scsi/sun_disklabel.c
 * and then substantially rewritten by Gordon W. Ross
 *
 ************************************************************************/

/* What partition types to assume for Sun disklabels: */
static u_char
sun_fstypes[16] = {
	FS_BSDFFS,	/* a */
	FS_SWAP,	/* b */
	FS_UNUSED,	/* c - whole disk */
	FS_BSDFFS,	/* d */
	FS_BSDFFS,	/* e */
	FS_BSDFFS,	/* f */
	FS_BSDFFS,	/* g */
	FS_BSDFFS,	/* h */
	FS_BSDFFS,	/* i */
	FS_BSDFFS,	/* j */
	FS_BSDFFS,	/* k */
	FS_BSDFFS,	/* l */
	FS_BSDFFS,	/* m */
	FS_BSDFFS,	/* n */
	FS_BSDFFS,	/* o */
	FS_BSDFFS	/* p */
};

/*
 * Given a struct sun_disklabel, assume it has an extended partition
 * table and compute the correct value for sl_xpsum.
 */
static __inline u_int
sun_extended_sum(struct sun_disklabel *sl, void *end)
{
	u_int sum, *xp, *ep;

	xp = (u_int *)&sl->sl_xpmag;
	ep = (u_int *)end;

	sum = 0;
	for (; xp < ep; xp++)
		sum += *xp;
	return (sum);
}

/*
 * Given a SunOS disk label, set lp to a BSD disk label.
 *
 * The BSD label is cleared out before this is called.
 */
static int
disklabel_sun_to_bsd(struct sun_disklabel *sl, struct disklabel *lp)
{
	struct sun_preamble *preamble = (struct sun_preamble *)sl;
	struct sun_partinfo *ppp;
	struct sun_dkpart *spp;
	struct partition *npp;
	u_short cksum = 0, *sp1, *sp2;
	int i, secpercyl;

	/* Verify the XOR check. */
	sp1 = (u_short *)sl;
	sp2 = (u_short *)(sl + 1);
	while (sp1 < sp2)
		cksum ^= *sp1++;
	if (cksum != 0)
		return (EINVAL); /* SunOS disk label, bad checksum */

	/* Format conversion. */
	lp->d_magic = DISKMAGIC;
	lp->d_magic2 = DISKMAGIC;
	lp->d_flags = D_VENDOR;
	memcpy(lp->d_packname, sl->sl_text, sizeof(lp->d_packname));

	lp->d_secsize = DEV_BSIZE;
	lp->d_nsectors = sl->sl_nsectors;
	lp->d_ntracks = sl->sl_ntracks;
	lp->d_ncylinders = sl->sl_ncylinders;

	secpercyl = sl->sl_nsectors * sl->sl_ntracks;
	lp->d_secpercyl = secpercyl;
	/* If unset or initialized as full disk, permit refinement */
	if (DL_GETDSIZE(lp) == 0 || DL_GETDSIZE(lp) == MAXDISKSIZE)
		DL_SETDSIZE(lp, (u_int64_t)secpercyl * sl->sl_ncylinders);
	lp->d_version = 1;

	memcpy(&lp->d_uid, &sl->sl_uid, sizeof(sl->sl_uid));

	lp->d_acylinders = sl->sl_acylinders;

	lp->d_npartitions = MAXPARTITIONS;
	/* These are as defined in <ufs/ffs/fs.h> */
	lp->d_bbsize = 8192;	/* XXX */
	lp->d_sbsize = 8192;	/* XXX */

	for (i = 0; i < 8; i++) {
		spp = &sl->sl_part[i];
		npp = &lp->d_partitions[i];
		DL_SETPOFFSET(npp, spp->sdkp_cyloffset * secpercyl);
		DL_SETPSIZE(npp, spp->sdkp_nsectors);
		if (DL_GETPSIZE(npp) == 0) {
			npp->p_fstype = FS_UNUSED;
		} else {
			npp->p_fstype = sun_fstypes[i];
			if (npp->p_fstype == FS_BSDFFS) {
				/*
				 * The sun label does not store the FFS fields,
				 * so just set them with default values here.
				 */
				npp->p_fragblock =
				    DISKLABELV1_FFS_FRAGBLOCK(2048, 8);
				npp->p_cpg = 16;
			}
		}
	}

	/* Clear "extended" partition info, tentatively */
	for (i = 0; i < SUNXPART; i++) {
		npp = &lp->d_partitions[i+8];
		DL_SETPOFFSET(npp, 0);
		DL_SETPSIZE(npp, 0);
		npp->p_fstype = FS_UNUSED;
	}

	/* Check to see if there's an "extended" partition table
	 * SL_XPMAG partitions had checksums up to just before the
	 * (new) sl_types variable, while SL_XPMAGTYP partitions have
	 * checksums up to the just before the (new) sl_xxx1 variable.
	 */
	if ((sl->sl_xpmag == SL_XPMAG &&
	    sun_extended_sum(sl, &sl->sl_types) == sl->sl_xpsum) ||
	    (sl->sl_xpmag == SL_XPMAGTYP &&
	    sun_extended_sum(sl, &sl->sl_xxx1) == sl->sl_xpsum)) {
		/*
		 * There is.  Copy over the "extended" partitions.
		 * This code parallels the loop for partitions a-h.
		 */
		for (i = 0; i < SUNXPART; i++) {
			spp = &sl->sl_xpart[i];
			npp = &lp->d_partitions[i+8];
			DL_SETPOFFSET(npp, spp->sdkp_cyloffset * secpercyl);
			DL_SETPSIZE(npp, spp->sdkp_nsectors);
			if (DL_GETPSIZE(npp) == 0) {
				npp->p_fstype = FS_UNUSED;
				continue;
			}
			npp->p_fstype = sun_fstypes[i+8];
			if (npp->p_fstype == FS_BSDFFS) {
				npp->p_fragblock =
				    DISKLABELV1_FFS_FRAGBLOCK(2048, 8);
				npp->p_cpg = 16;
			}
		}
		if (sl->sl_xpmag == SL_XPMAGTYP) {
			for (i = 0; i < MAXPARTITIONS; i++) {
				npp = &lp->d_partitions[i];
				npp->p_fstype = sl->sl_types[i];
				npp->p_fragblock = sl->sl_fragblock[i];
				npp->p_cpg = sl->sl_cpg[i];
			}
		}
	} else if (preamble->sl_nparts <= 8) {
		/*
		 * A more traditional Sun label.  Recognise certain filesystem
		 * types from it, if they are available.
		 */
		i = preamble->sl_nparts;
		if (i == 0)
			i = 8;

		npp = &lp->d_partitions[i-1];
		ppp = &preamble->sl_part[i-1];
		for (; i > 0; i--, npp--, ppp--) {
			if (npp->p_size == 0)
				continue;
			if ((ppp->spi_tag == 0) && (ppp->spi_flag == 0))
				continue;

			switch (ppp->spi_tag) {
			case SPTAG_SUNOS_ROOT:
			case SPTAG_SUNOS_USR:
			case SPTAG_SUNOS_VAR:
			case SPTAG_SUNOS_HOME:
				npp->p_fstype = FS_BSDFFS;
				npp->p_fragblock =
				    DISKLABELV1_FFS_FRAGBLOCK(2048, 8);
				npp->p_cpg = 16;
				break;
			case SPTAG_LINUX_EXT2:
				npp->p_fstype = FS_EXT2FS;
				break;
			default:
				/* FS_SWAP for _SUNOS_SWAP and _LINUX_SWAP? */
				npp->p_fstype = FS_UNUSED;
				break;
			}
		}
	}

	lp->d_checksum = 0;
	lp->d_checksum = dkcksum(lp);
	return (checkdisklabel(lp, lp, 0, DL_GETDSIZE(lp)));
}

/*
 * Given a BSD disk label, update the Sun disklabel
 * pointed to by cp with the new info.  Note that the
 * Sun disklabel may have other info we need to keep.
 */
static int
disklabel_bsd_to_sun(struct disklabel *lp, struct sun_disklabel *sl)
{
	struct partition *npp;
	struct sun_dkpart *spp;
	int i, secpercyl;
	u_short cksum, *sp1, *sp2;

	/* Enforce preconditions */
	if (lp->d_secsize != DEV_BSIZE || lp->d_nsectors == 0 ||
	    lp->d_ntracks == 0)
		return (EINVAL);

	/* Format conversion. */
	bzero(sl, sizeof(*sl));
	memcpy(sl->sl_text, lp->d_packname, sizeof(lp->d_packname));
	sl->sl_pcylinders = lp->d_ncylinders + lp->d_acylinders; /* XXX */
	sl->sl_ncylinders = lp->d_ncylinders;
	sl->sl_acylinders = lp->d_acylinders;
	sl->sl_ntracks = lp->d_ntracks;
	sl->sl_nsectors = lp->d_nsectors;

	memcpy(&sl->sl_uid, &lp->d_uid, sizeof(lp->d_uid));

	secpercyl = sl->sl_nsectors * sl->sl_ntracks;
	for (i = 0; i < 8; i++) {
		spp = &sl->sl_part[i];
		npp = &lp->d_partitions[i];
		spp->sdkp_cyloffset = 0;
		spp->sdkp_nsectors = 0;
		if (DL_GETPSIZE(npp)) {
			if (DL_GETPOFFSET(npp) % secpercyl)
				return (EINVAL);
			spp->sdkp_cyloffset = DL_GETPOFFSET(npp) / secpercyl;
			spp->sdkp_nsectors = DL_GETPSIZE(npp);
		}
	}
	sl->sl_magic = SUN_DKMAGIC;

	for (i = 0; i < SUNXPART; i++) {
		spp = &sl->sl_xpart[i];
		npp = &lp->d_partitions[i+8];
		spp->sdkp_cyloffset = 0;
		spp->sdkp_nsectors = 0;
		if (DL_GETPSIZE(npp)) {
			if (DL_GETPOFFSET(npp) % secpercyl)
				return (EINVAL);
			spp->sdkp_cyloffset = DL_GETPOFFSET(npp) / secpercyl;
			spp->sdkp_nsectors = DL_GETPSIZE(npp);
		}
	}
	for (i = 0; i < MAXPARTITIONS; i++) {
		npp = &lp->d_partitions[i];
		sl->sl_types[i] = npp->p_fstype;
		sl->sl_fragblock[i] = npp->p_fragblock;
		sl->sl_cpg[i] = npp->p_cpg;
	}
	sl->sl_xpmag = SL_XPMAGTYP;
	sl->sl_xpsum = sun_extended_sum(sl, &sl->sl_xxx1);

	/* Correct the XOR check. */
	sp1 = (u_short *)sl;
	sp2 = (u_short *)(sl + 1);
	sl->sl_cksum = cksum = 0;
	while (sp1 < sp2)
		cksum ^= *sp1++;
	sl->sl_cksum = cksum;
	return (0);
}

/*
 * Search the bad sector table looking for the specified sector.
 * Return index if found.
 * Return -1 if not found.
 */
int
isbad(struct dkbad *bt, int cyl, int trk, int sec)
{
	int i;
	long blk, bblk;

	blk = ((long)cyl << 16) + (trk << 8) + sec;
	for (i = 0; i < NBT_BAD; i++) {
		bblk = ((long)bt->bt_bad[i].bt_cyl << 16) +
			bt->bt_bad[i].bt_trksec;
		if (blk == bblk)
			return (i);
		if (blk < bblk || bblk < 0)
			break;
	}
	return (-1);
}


code:
/*	$OpenBSD: dvma.c,v 1.2 2015/05/19 20:42:11 miod Exp $	*/

/*
 * Copyright (c) 1996
 *	The President and Fellows of Harvard College. All rights reserved.
 * Copyright (c) 1992, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This software was developed by the Computer Systems Engineering group
 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
 * contributed to Berkeley.
 *
 * All advertising materials mentioning features or use of this software
 * must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Lawrence Berkeley Laboratory.
 *	This product includes software developed by Harvard University.
 *
 * 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 by Harvard University.
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. 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.
 *
 *	@(#)vm_machdep.c	8.2 (Berkeley) 9/23/93
 */

#include <sys/param.h>
#include <sys/extent.h>
#include <sys/mbuf.h>
#include <sys/proc.h>

#include <uvm/uvm_extern.h>

#include <machine/bus.h>
#include <machine/cpu.h>

/*
 * dvmamap_extent is used to manage DVMA memory.
 */
vaddr_t dvma_base, dvma_end;
struct extent *dvmamap_extent;

vaddr_t	dvma_mapin_space(struct vm_map *, vaddr_t, int, int, int);

void
dvma_init(void)
{
	dvma_base = CPU_ISSUN4M ? DVMA4M_BASE : DVMA_BASE;
	dvma_end = CPU_ISSUN4M ? DVMA4M_END : DVMA_END;
	dvmamap_extent = extent_create("dvmamap", dvma_base, dvma_end,
				       M_DEVBUF, NULL, 0, EX_NOWAIT);
	if (dvmamap_extent == NULL)
		panic("unable to allocate extent for dvma");
}

/*
 * Wrapper for dvma_mapin_space() in kernel space,
 * so drivers need not include VM goo to get at kernel_map.
 */
caddr_t
kdvma_mapin(caddr_t va, int len, int canwait)
{
	return (caddr_t)dvma_mapin_space(kernel_map, (vaddr_t)va, len, canwait,
	    0);
}

#if defined(SUN4M)	/* XXX iommu.c */
extern int has_iocache;
#endif

caddr_t
dvma_malloc_space(size_t len, void *kaddr, int flags, int space)
{
	int waitok = (flags & M_NOWAIT) == 0;
	vsize_t maplen, tmplen;
	vaddr_t	kva;
	vaddr_t	dva;
	int s;

	len = round_page(len);
	/* XXX - verify if maybe uvm_km_valloc from kernel_map would be ok. */
	s = splvm();
	kva = uvm_km_valloc(kmem_map, len);
	splx(s);
	if (kva == 0)
		return (NULL);

	for (maplen = 0; maplen < len; maplen += PAGE_SIZE) {
		struct vm_page *pg;
		paddr_t pa;

again:
		pg = uvm_pagealloc(NULL, 0, NULL, 0);
		if (pg == NULL) {
			if (waitok) {
				uvm_wait("dvmapg");
				goto again;
			}
			goto dropit;
		}
		pa = VM_PAGE_TO_PHYS(pg);
#if defined(SUN4M)
		if (!has_iocache)
#endif
			pa |= PMAP_NC;
		pmap_kenter_pa(kva + maplen, pa, PROT_READ | PROT_WRITE);
	}

	*(vaddr_t *)kaddr = kva;
	dva = dvma_mapin_space(kernel_map, kva, len, waitok ? 1 : 0, space);
	if (dva == 0) {
		goto dropit;
	}
	return (caddr_t)dva;
dropit:
	for (tmplen = 0; tmplen < maplen; tmplen += PAGE_SIZE) {
		paddr_t pa;

		if (pmap_extract(pmap_kernel(), kva + tmplen, &pa) == FALSE)
			panic("dvma_malloc_space: pmap_extract");

		pmap_kremove(kva + tmplen, PAGE_SIZE);
		uvm_pagefree(PHYS_TO_VM_PAGE(pa));
	}

	uvm_km_free(kmem_map, kva, len);

	return NULL;
}

void
dvma_free(caddr_t dva, size_t len, void	*kaddr)
{
	size_t tmplen;
	vaddr_t	kva = *(vaddr_t *)kaddr;

	len = round_page(len);

	dvma_mapout((vaddr_t)dva, kva, len);
	for (tmplen = 0; tmplen < len; tmplen += PAGE_SIZE) {
		paddr_t pa;

		if (pmap_extract(pmap_kernel(), kva + tmplen, &pa) == FALSE)
			panic("dvma_free: pmap_extract");

		pmap_kremove(kva + tmplen, PAGE_SIZE);
		uvm_pagefree(PHYS_TO_VM_PAGE(pa));
	}

	uvm_km_free(kmem_map, kva, len);
}

u_long dvma_cachealign = 0;

/*
 * Map a range [va, va+len] of wired virtual addresses in the given map
 * to a valid DVMA address. On non-SRMMU systems, this establish a
 * second mapping of that range.
 */
vaddr_t
dvma_mapin_space(struct vm_map *map, vaddr_t va, int len, int canwait,
    int space)
{
	vaddr_t	kva, tva;
	int npf, s;
	paddr_t pa;
	vaddr_t off;
	vaddr_t ova;
	int olen;
	int error;

	if (dvma_cachealign == 0)
	        dvma_cachealign = PAGE_SIZE;

	ova = va;
	olen = len;

	off = va & PAGE_MASK;
	va &= ~PAGE_MASK;
	len = round_page(len + off);
	npf = atop(len);

	s = splhigh();
	if (space & M_SPACE_D24)
		error = extent_alloc_subregion(dvmamap_extent,
		    DVMA_D24_BASE, DVMA_D24_END, len, dvma_cachealign,
		    va & (dvma_cachealign - 1), 0,
		    canwait ? EX_WAITSPACE : EX_NOWAIT, &tva);
	else
		error = extent_alloc(dvmamap_extent, len, dvma_cachealign,
		    va & (dvma_cachealign - 1), 0,
		    canwait ? EX_WAITSPACE : EX_NOWAIT, &tva);
	splx(s);
	if (error)
		return 0;
	kva = tva;

	while (npf--) {
		if (pmap_extract(vm_map_pmap(map), va, &pa) == FALSE)
			panic("dvma_mapin: null page frame");
		pa = trunc_page(pa);

#if defined(SUN4M)
		if (CPU_ISSUN4M) {
			iommu_enter(tva, pa);
		} else
#endif
		{
			/*
			 * pmap_enter distributes this mapping to all
			 * contexts... maybe we should avoid this extra work
			 */
#ifdef notyet
#if defined(SUN4)
			if (have_iocache)
				pa |= PG_IOC;
#endif
#endif
			pmap_kenter_pa(tva, pa | PMAP_NC,
			    PROT_READ | PROT_WRITE);
		}

		tva += PAGE_SIZE;
		va += PAGE_SIZE;
	}
	pmap_update(pmap_kernel());

	/*
	 * XXX Only have to do this on write.
	 */
	if (CACHEINFO.c_vactype == VAC_WRITEBACK)		/* XXX */
		cpuinfo.cache_flush((caddr_t)ova, olen);	/* XXX */

	return kva + off;
}

/*
 * Remove DVMA mapping of `va' in DVMA space at `dva'.
 */
void
dvma_mapout(vaddr_t dva, vaddr_t va, int len)
{
	int s, off;
	int error;
	int dlen;

	off = (int)dva & PGOFSET;
	dva -= off;
	dlen = round_page(len + off);

#if defined(SUN4M)
	if (CPU_ISSUN4M)
		iommu_remove(dva, dlen);
	else
#endif
	{
		pmap_kremove(dva, dlen);
		pmap_update(pmap_kernel());
	}

	s = splhigh();
	error = extent_free(dvmamap_extent, dva, dlen, EX_NOWAIT);
	if (error)
		printf("dvma_mapout: extent_free failed\n");
	splx(s);

	if (CACHEINFO.c_vactype != VAC_NONE)
		cpuinfo.cache_flush((caddr_t)va, len);
}

int	dvma_dmamap_create(bus_dma_tag_t, bus_size_t, int, bus_size_t,
	    bus_size_t, int, bus_dmamap_t *);
int	dvma_dmamap_load(bus_dma_tag_t, bus_dmamap_t, void *, bus_size_t,
	    struct proc *, int);
int	dvma_dmamap_load_mbuf(bus_dma_tag_t, bus_dmamap_t, struct mbuf *, int);
int	dvma_dmamap_load_raw(bus_dma_tag_t, bus_dmamap_t, bus_dma_segment_t *,
	    int, bus_size_t, int);
void	dvma_dmamap_unload(bus_dma_tag_t, bus_dmamap_t);
void	dvma_dmamap_sync(bus_dma_tag_t, bus_dmamap_t, bus_addr_t, bus_size_t,
	    int);

int	dvma_dmamem_map(bus_dma_tag_t, bus_dma_segment_t *, int, size_t,
	    caddr_t *, int);
void	dvma_dmamem_unmap(bus_dma_tag_t, void *, size_t);

int	dvma_dmamap_load_buffer(bus_dma_tag_t, bus_dmamap_t, void *, bus_size_t,
	    struct proc *, int);

int	dvma_alloc(bus_dmamap_t, vaddr_t, bus_size_t, int, bus_addr_t *,
	    bus_size_t *);

struct sparc_bus_dma_tag dvma_dmatag = {
	._cookie = NULL,
	._dmamap_create = dvma_dmamap_create,
	._dmamap_destroy = _bus_dmamap_destroy,
	._dmamap_load = dvma_dmamap_load,
	._dmamap_load_mbuf = dvma_dmamap_load_mbuf,
	._dmamap_load_uio = _bus_dmamap_load_uio,
	._dmamap_load_raw = dvma_dmamap_load_raw,
	._dmamap_unload = dvma_dmamap_unload,
	._dmamap_sync = dvma_dmamap_sync,

	._dmamem_alloc = _bus_dmamem_alloc,
	._dmamem_free = _bus_dmamem_free,
	._dmamem_map = dvma_dmamem_map,
	._dmamem_unmap = _bus_dmamem_unmap,
	._dmamem_mmap = _bus_dmamem_mmap,
};

/*
 * DVMA DMA map functions.
 */
int
dvma_dmamap_create(bus_dma_tag_t t, bus_size_t size, int nsegments,
    bus_size_t maxsegsz, bus_size_t boundary, int flags, bus_dmamap_t *dmamp)
{
	bus_dmamap_t map;
	int error;

	if ((error = _bus_dmamap_create(t, size, nsegments, maxsegsz, boundary,
	    flags, &map)) != 0)
		return (error);

	/* Enable allocations from the entire map */
	map->_dm_ex_start = DVMA_BASE;
	map->_dm_ex_end = DVMA_END;

	*dmamp = map;
	return (0);
}

/*
 * Internal routine to allocate space in the DVMA extent.
 */
int
dvma_alloc(bus_dmamap_t map, vaddr_t va, bus_size_t len, int flags,
    bus_addr_t *dvap, bus_size_t *sgsizep)
{
	bus_size_t sgsize;
	u_long align, voff, dvaddr;
	int s, error;
	int pagesz = PAGE_SIZE;

	/*
	 * Remember page offset, then truncate the buffer address to
	 * a page boundary.
	 */
	voff = va & (pagesz - 1);
	va &= -pagesz;

	if (len > map->_dm_size)
		return (EINVAL);

	sgsize = (len + voff + pagesz - 1) & -pagesz;
	align = dvma_cachealign ? dvma_cachealign : map->_dm_align;

	s = splhigh();
	error = extent_alloc_subregion(dvmamap_extent, map->_dm_ex_start,
	    map->_dm_ex_end, sgsize, align, va & (align-1), map->_dm_boundary,
	    (flags & BUS_DMA_NOWAIT) == 0 ? EX_WAITOK : EX_NOWAIT, &dvaddr);
	splx(s);
	*dvap = (bus_addr_t)dvaddr;
	*sgsizep = sgsize;
	return (error);
}

int
dvma_dmamap_load_buffer(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
    bus_size_t buflen, struct proc *p, int flags)
{
	bus_size_t sgsize;
	bus_addr_t dva;
	vaddr_t va = (vaddr_t)buf;
	int pagesz = PAGE_SIZE;
	pmap_t pmap;
	int error;

	if (map->dm_nsegs >= map->_dm_segcnt)
		return (EFBIG);

	/* Allocate DVMA resources */
	if ((error = dvma_alloc(map, va, buflen, flags, &dva, &sgsize)) != 0)
		return (error);

	if ((CACHEINFO.ec_totalsize == 0))
		cpuinfo.cache_flush(buf, buflen); /* XXX - move to bus_dma_sync? */

	/*
	 * We always use just one segment.
	 */
	map->dm_segs[map->dm_nsegs].ds_addr = dva + (va & (pagesz - 1));
	map->dm_segs[map->dm_nsegs].ds_len = buflen;
	map->dm_segs[map->dm_nsegs]._ds_sgsize = sgsize;
	map->dm_nsegs++;

	if (p != NULL)
		pmap = p->p_vmspace->vm_map.pmap;
	else
		pmap = pmap_kernel();

	for (; buflen != 0; ) {
		paddr_t pa;
		/*
		 * Get the physical address for this page.
		 */
		if (!pmap_extract(pmap, va, &pa)) {
			pmap_update(pmap_kernel());
			return (EFAULT);
		}

		/*
		 * Compute the segment size, and adjust counts.
		 */
		sgsize = pagesz - (va & (pagesz - 1));
		if (buflen < sgsize)
			sgsize = buflen;

#ifdef notyet
#if defined(SUN4)
		if (have_iocache)
			pa |= PG_IOC;
#endif
#endif
		pmap_kenter_pa(dva, (pa & -pagesz) | PMAP_NC,
		    PROT_READ | PROT_WRITE);

		dva += pagesz;
		va += sgsize;
		buflen -= sgsize;
	}
	pmap_update(pmap_kernel());

	return (0);
}

/*
 * Prepare buffer for DMA transfer.
 */
int
dvma_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
    bus_size_t buflen, struct proc *p, int flags)
{
	int error;

	/*
	 * Make sure that on error condition we return "no valid mappings".
	 */
	map->dm_mapsize = buflen;
	map->dm_nsegs = 0;

	error = dvma_dmamap_load_buffer(t, map, buf, buflen, p, flags);
	if (error)
		dvma_dmamap_unload(t, map);

	return (error);
}

/*
 * Like _bus_dmamap_load(), but for mbufs.
 */
int
dvma_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map, struct mbuf *m0,
    int flags)
{
	struct mbuf *m;
	int error = 0;

	/*
	 * Make sure that on error condition we return "no valid mappings".
	 */
	map->dm_mapsize = m0->m_pkthdr.len;
	map->dm_nsegs = 0;

	for (m = m0; m != NULL && error == 0; m = m->m_next) {
		if (m->m_len == 0)
			continue;
		error = dvma_dmamap_load_buffer(t, map, m->m_data, m->m_len,
		    NULL, flags);
	}

	if (error)
		dvma_dmamap_unload(t, map);

	return (error);
}

/*
 * Like _bus_dmamap_load(), but for raw memory allocated with
 * bus_dmamem_alloc().
 */
int
dvma_dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map, bus_dma_segment_t *segs,
    int nsegs, bus_size_t size, int flags)
{
	struct vm_page *m;
	paddr_t pa;
	bus_addr_t dva;
	bus_size_t sgsize;
	struct pglist *mlist;
	int pagesz = PAGE_SIZE;
	int error;

	map->dm_nsegs = 0;

	/* Allocate DVMA resources */
	if ((error = dvma_alloc(map, segs[0]._ds_va, size, flags, &dva,
	    &sgsize)) != 0)
		return (error);

	/*
	 * Note DVMA address in case bus_dmamem_map() is called later.
	 * It can then insure cache coherency by choosing a KVA that
	 * is aligned to `ds_addr'.
	 */
	segs[0].ds_addr = dva;
	segs[0].ds_len = size;

	map->dm_segs[0].ds_addr = dva;
	map->dm_segs[0].ds_len = size;
	map->dm_segs[0]._ds_sgsize = sgsize;

	/* Map physical pages into the DVMA address space */
	mlist = segs[0]._ds_mlist;
	for (m = TAILQ_FIRST(mlist); m != NULL; m = TAILQ_NEXT(m,pageq)) {
		if (sgsize == 0)
			panic("dvma_dmamap_load_raw: size botch");
		pa = VM_PAGE_TO_PHYS(m);

#ifdef notyet
#if defined(SUN4)
		if (have_iocache)
			pa |= PG_IOC;
#endif
#endif
		pmap_kenter_pa(dva, (pa & -pagesz) | PMAP_NC,
		    PROT_READ | PROT_WRITE);

		dva += pagesz;
		sgsize -= pagesz;
	}
	pmap_update(pmap_kernel());

	map->dm_nsegs = 1;
	map->dm_mapsize = size;

	return (0);
}

/*
 * Unload a DVMA DMA map.
 */
void
dvma_dmamap_unload(bus_dma_tag_t t, bus_dmamap_t map)
{
	bus_dma_segment_t *segs = map->dm_segs;
	int nsegs = map->dm_nsegs;
	bus_addr_t dva;
	bus_size_t len;
	int i, s, error;

	for (i = 0; i < nsegs; i++) {
		dva = segs[i].ds_addr & -PAGE_SIZE;
		len = segs[i]._ds_sgsize;

		pmap_kremove(dva, len);
		s = splhigh();
		error = extent_free(dvmamap_extent, dva, len, EX_NOWAIT);
		splx(s);
		if (error != 0)
			printf("warning: %ld of DVMA space lost\n", (long)len);
	}
	pmap_update(pmap_kernel());

	/* Mark the mappings as invalid. */
	map->dm_mapsize = 0;
	map->dm_nsegs = 0;
}

/*
 * DMA map synchronization.
 */
void
dvma_dmamap_sync(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset,
    bus_size_t len, int ops)
{

	/*
	 * XXX Should flush CPU write buffers.
	 */
}

/*
 * Map DMA-safe memory.
 */
int
dvma_dmamem_map(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs,
    size_t size, caddr_t *kvap, int flags)
{
	struct vm_page *m;
	vaddr_t va;
	bus_addr_t addr;
	struct pglist *mlist;
	u_long align;
	int pagesz = PAGE_SIZE;
	const struct kmem_dyn_mode *kd;

	if (nsegs != 1)
		panic("dvma_dmamem_map: nsegs = %d", nsegs);

	align = dvma_cachealign ? dvma_cachealign : pagesz;

	size = round_page(size);

	kd = flags & BUS_DMA_NOWAIT ? &kd_trylock : &kd_waitok;
	va = (vaddr_t)km_alloc(size, &kv_any, &kp_none, kd);
	if (va == 0)
		return (ENOMEM);

	segs[0]._ds_va = va;
	*kvap = (void *)va;

	/*
	 * Map the pages allocated in _bus_dmamem_alloc() to the
	 * kernel virtual address space.
	 */
	mlist = segs[0]._ds_mlist;
	for (m = TAILQ_FIRST(mlist); m != NULL; m = TAILQ_NEXT(m,pageq)) {

		if (size == 0)
			panic("dvma_dmamem_map: size botch");

		addr = VM_PAGE_TO_PHYS(m);
		pmap_kenter_pa(va, addr | PMAP_NC, PROT_READ | PROT_WRITE);

		va += pagesz;
		size -= pagesz;
	}
	pmap_update(pmap_kernel());

	return (0);
}

void
dvma_dmamem_unmap(bus_dma_tag_t t, void *kva, size_t size)
{

#ifdef DIAGNOSTIC
	if ((u_long)kva & PAGE_MASK)
		panic("dvma_dmamem_unmap");
#endif

	km_free(kva, round_page(size), &kv_any, &kp_none);
}


code:
/*	$OpenBSD: emul.c,v 1.5 2010/11/27 19:41:48 miod Exp $	*/
/*	$NetBSD: emul.c,v 1.3 1997/07/29 09:42:01 fair Exp $	*/

/*
 * Copyright (c) 1997 Christos Zoulas.  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 by Christos Zoulas.
 * 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/systm.h>
#include <sys/proc.h>
#include <machine/reg.h>
#include <machine/instr.h>
#include <machine/cpu.h>
#include <machine/psl.h>
#include <sparc/sparc/cpuvar.h>

#ifdef DEBUG_EMUL
# define DPRINTF(a) uprintf a
#else
# define DPRINTF(a)
#endif

#define GPR(tf, i)	((int32_t *) &tf->tf_global)[i]
#define IPR(tf, i)	((int32_t *) tf->tf_out[6])[i - 16]
#define FPR(p, i)	((int32_t) p->p_md.md_fpstate->fs_regs[i])
#define FPRSET(p, i, v)	p->p_md.md_fpstate->fs_regs[i] = (v)

static __inline int readgpreg(struct trapframe *, int, void *);
static __inline int readfpreg(struct proc *, int, void *);
static __inline int writegpreg(struct trapframe *, int, const void *);
static __inline int writefpreg(struct proc *, int, const void *);
static __inline int decodeaddr(struct trapframe *, union instr *, void *);
static int muldiv(struct trapframe *, union instr *, int32_t *, int32_t *,
    int32_t *);

#define	REGNAME(i)	"goli"[i >> 3], i & 7

static __inline int
readgpreg(tf, i, val)
	struct trapframe *tf;
	int i;
	void *val;
{
	int error = 0;
	if (i == 0)
		*(int32_t *) val = 0;
	else if (i < 16)
		*(int32_t *) val = GPR(tf, i);
	else
		error = copyin(&IPR(tf, i), val, sizeof(int32_t));

	return error;
}

static __inline int
writegpreg(tf, i, val)
	struct trapframe *tf;
	int i;
	const void *val;
{
	int error = 0;

	if (i == 0)
		return error;
	else if (i < 16)
		GPR(tf, i) = *(int32_t *) val;
	else
		/* XXX: Fix copyout prototype */
		error = copyout((caddr_t) val, &IPR(tf, i), sizeof(int32_t));

	return error;
}

static __inline int
readfpreg(p, i, val)
	struct proc *p;
	int i;
	void *val;
{
	*(int32_t *) val = FPR(p, i);
	return 0;
}

static __inline int
writefpreg(p, i, val)
	struct proc *p;
	int i;
	const void *val;
{
	FPRSET(p, i, *(const int32_t *) val);
	return 0;
}

static __inline int
decodeaddr(tf, code, val)
	struct trapframe *tf;
	union instr *code;
	void *val;
{
	if (code->i_simm13.i_i)
		*((int32_t *) val) = code->i_simm13.i_simm13;
	else {
		int error;

		if (code->i_asi.i_asi)
			return EINVAL;
		if ((error = readgpreg(tf, code->i_asi.i_rs2, val)) != 0)
			return error;
	}
	return 0;
}

static int
muldiv(tf, code, rd, rs1, rs2)
	struct trapframe *tf;
	union instr *code;
	int32_t *rd, *rs1, *rs2;
{
	/*
	 * We check for {S,U}{MUL,DIV}{,cc}
	 *
	 * [c = condition code, s = sign]
	 * Mul = 0c101s
	 * Div = 0c111s
	 */
	union {
		struct {
			unsigned unused:26;	/* padding */
			unsigned zero:1;	/* zero by opcode */
			unsigned cc:1;		/* one to send condition code */
			unsigned one1:1;	/* one by opcode */
			unsigned div:1;		/* one if divide */
			unsigned one2:1;	/* one by opcode */
			unsigned sgn:1;		/* sign bit */
		} bits;
		int num;
	} op;

	op.num = code->i_op3.i_op3;

#ifdef DEBUG_EMUL
	uprintf("muldiv 0x%x: %c%s%s %c%d, %c%d, ", code->i_int,
	    "us"[op.bits.sgn], op.bits.div ? "div" : "mul",
	    op.bits.cc ? "cc" : "", REGNAME(code->i_op3.i_rd),
	    REGNAME(code->i_op3.i_rs1));
	if (code->i_loadstore.i_i)
		uprintf("0x%x\n", *rs2);
	else
		uprintf("%c%d\n", REGNAME(code->i_asi.i_rs2));
#endif

	if (op.bits.div) {
		if (*rs2 == 0) {
			/*
			 * XXX: to be 100% correct here, on sunos we need to
			 *	ignore the error and return *rd = *rs1.
			 *	It should be easy to fix by passing struct
			 *	proc in here.
			 */
			DPRINTF(("emulinstr: avoid zerodivide\n"));
			return EINVAL;
		}
		*rd = *rs1 / *rs2;
		DPRINTF(("muldiv: %d / %d = %d\n", *rs1, *rs2, *rd));
	}
	else {
		*rd = *rs1 * *rs2;
		DPRINTF(("muldiv: %d * %d = %d\n", *rs1, *rs2, *rd));
	}

	if (op.bits.cc) {
		/* Set condition codes */
		tf->tf_psr &= ~PSR_ICC;

		if (*rd == 0)
			tf->tf_psr |= PSR_Z << 20;
		else {
			if (op.bits.sgn && *rd < 0)
				tf->tf_psr |= PSR_N << 20;
			if (op.bits.div) {
				if (*rd * *rs2 != *rs1)
					tf->tf_psr |= PSR_O << 20;
			}
			else {
				if (*rd / *rs2 != *rs1)
					tf->tf_psr |= PSR_O << 20;
			}
		}
	}

	return 0;
}

/*
 * Emulate unimplemented instructions on earlier sparc chips.
 */
int
emulinstr(pc, tf)
	int pc;
	struct trapframe *tf;
{
	union instr code;
	int32_t rs1, rs2, rd;
	int error;

	/* fetch and check the instruction that caused the fault */
	error = copyin((caddr_t) pc, &code.i_int, sizeof(code.i_int));
	if (error != 0) {
		DPRINTF(("emulinstr: Bad instruction fetch\n"));
		return SIGILL;
	}

	/* Only support format 2 */
	if (code.i_any.i_op != 2) {
		DPRINTF(("emulinstr: Not a format 2 instruction\n"));
		return SIGILL;
	}

	write_user_windows();

	if ((error = readgpreg(tf, code.i_op3.i_rs1, &rs1)) != 0) {
		DPRINTF(("emulinstr: read rs1 %d\n", error));
		return SIGILL;
	}

	if ((error = decodeaddr(tf, &code, &rs2)) != 0) {
		DPRINTF(("emulinstr: decode addr %d\n", error));
		return SIGILL;
	}

	switch (code.i_op3.i_op3) {
	case IOP3_FLUSH:
		cpuinfo.cache_flush((caddr_t)(rs1 + rs2), 4); /*XXX*/
		return 0;

	default:
		if ((code.i_op3.i_op3 & 0x2a) != 0xa) {
			DPRINTF(("emulinstr: Unsupported op3 0x%x\n",
			    code.i_op3.i_op3));
			return SIGILL;
		}
		else if ((error = muldiv(tf, &code, &rd, &rs1, &rs2)) != 0)
			return SIGFPE;
	}

	if ((error = writegpreg(tf, code.i_op3.i_rd, &rd)) != 0) {
		DPRINTF(("muldiv: write rd %d\n", error));
		return SIGILL;
	}

	return 0;
}


code:
#	$OpenBSD: genassym.cf,v 1.25 2015/03/18 20:49:40 miod Exp $
#	$NetBSD: genassym.cf,v 1.2 1997/06/28 19:59:04 pk Exp $

#
# Copyright (c) 1997 Christos Zoulas.  All rights reserved.
# Copyright (c) 1992, 1993
#	The Regents of the University of California.  All rights reserved.
#
# This software was developed by the Computer Systems Engineering group
# at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
# contributed to Berkeley.
#
# All advertising materials mentioning features or use of this software
# must display the following acknowledgement:
#	This product includes software developed by the University of
#	California, Lawrence Berkeley Laboratory.
#
# 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.
#
#	@(#)genassym.c	8.1 (Berkeley) 6/11/93
#

include <sys/param.h>
include <sys/buf.h>
include <sys/proc.h>
include <sys/mbuf.h>
include <sys/msgbuf.h>
include <sys/syscall.h>
include <sys/user.h>
include <sys/device.h>
include <sys/disklabel.h>
include <sys/disk.h>

include <uvm/uvm_extern.h>

include <machine/pmap.h>
include <machine/cpu.h>
include <machine/intr.h>

include <machine/oldmon.h>
include <machine/bsd_openprom.h>

include <sparc/sparc/cpuvar.h>

include <sparc/dev/audioamdvar.h>

include <sparc/dev/fdreg.h>
include <sparc/dev/fdvar.h>

# general constants
export	SUN4_PGSHIFT
export	SUN4CM_PGSHIFT
export	IOSPACE_BASE
if defined(VM_MIN_KERNEL_ADDRESS)
export	VM_MIN_KERNEL_ADDRESS
endif

# proc fields and values
struct	proc
member	p_addr
member	p_stat
member	p_wchan
member	p_vmspace

export	SRUN
export	SONPROC

# VM structure fields
define	VM_PMAP		offsetof(struct vmspace, vm_map.pmap)
struct	pmap
member	PMAP_CTX	pm_ctx
member	PMAP_CTXNUM	pm_ctxnum

# interrupt/fault metering
struct	uvmexp		V_
member	swtch
member	INTR		intrs
member	faults
member	softs

# CPU info structure
struct	cpu_softc
member  CPUINFO_GETSYNCFLT      get_syncflt
member  CPUINFO_GETASYNCFLT     get_asyncflt
member  CPUINFO_SYNCFLTDUMP     syncfltdump
member	CPUINFO_PURE_VCACHE_FLS	pure_vcache_flush
member	CPUINFO_CURPROC		ci.ci_curproc

# PTE bits and related information
export	PG_W
export	PG_VSHIFT
export	PG_PROTSHIFT
export	PG_PROTUREAD
export	PG_PROTUWRITE
if defined(SUN4M)
export	SRMMU_TETYPE
export	SRMMU_TEPTE
export	SRMMU_PROT_MASK
export	PPROT_R_RW
export	PPROT_RX_RX
export	PPROT_RWX_RWX
export	PPROT_WRITE
endif

# FPU state
struct	fpstate
member	fs_regs
member	fs_fsr
member	fs_qsize
member	fs_queue
export	FSR_QNE

# system calls
export	SYS_sigreturn
export	SYS_execve
export	SYS_exit

# errno
export	EFAULT
export	ENAMETOOLONG

# PCB fields
struct	pcb
member	pcb_nsaved
member	pcb_onfault
member	pcb_psr
member	pcb_rw
member	pcb_sp
member	pcb_pc
member	pcb_uw
member	pcb_wim
member	pcb_wcookie

# interrupt enable register PTE
define	IE_REG_PTE_PG	(PG_V | PG_W | PG_S | PG_NC | PG_OBIO)

# intrhand fields.
struct	intrhand
member	ih_fun
member	ih_arg
member	ih_ipl
member	ih_next
member	IH_COUNT	ih_count.ec_count

# sintrhand fields.
struct	sintrhand
member	sih_pending

ifdef notyet
# ZSCC interrupt fields
struct	zs_softc	Z
member	sc_a
member	sc_b
struct	zs_line
member	zl_wreg
member	zl_tbc
member	zl_tba
member	zl_rbput
member	zl_rbuf
define	ZSRR1_DO_bit	ffs(ZSRR1_DO) - 1
endif

# audio trap handler fields
struct	auio
member	au_amd
member	au_rdata
member	au_rend
member	au_pdata
member	au_pend
member	AU_COUNT	au_ih.ih_count.ec_count
member	au_swih

export	PROM_BASE

struct	promvec
member	pv_nodeops
member	pv_halt
member	PV_EVAL		pv_fortheval.v0_eval
member	pv_romvec_vers

struct	nodeops
member	no_nextnode
member	no_getprop

struct	om_vector	OLDMON_
member	printf
member	HALT		exitToMon

# floppy trap handler fields
struct	fdcio
member	FDC_REG_MSR	fdcio_reg_msr
member	FDC_REG_FIFO	fdcio_reg_fifo
member	FDC_ITASK	fdcio_itask
member	FDC_ISTATUS	fdcio_istatus
member	FDC_STATUS	fdcio_status
member	FDC_NSTAT	fdcio_nstat
member	FDC_DATA	fdcio_data
member	FDC_TC		fdcio_tc
member	FDC_COUNT	fdcio_ih.ih_count.ec_count
member	FDC_SIH		fdcio_sih


code:
/*	$OpenBSD: in_cksum.c,v 1.14 2014/07/22 10:35:35 mpi Exp $	*/
/*	$NetBSD: in_cksum.c,v 1.7 1996/10/05 23:44:34 mrg Exp $ */

/*
 * Copyright (c) 1995 Zubin Dittia.
 * Copyright (c) 1995 Matthew R. Green.
 * Copyright (c) 1994 Charles Hannum.
 * Copyright (c) 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/11/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>

/*
 * 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.
 *
 * SPARC version.
 */

/*
 * The checksum computation code here is significantly faster than its
 * vanilla C counterpart (by significantly, I mean 2-3 times faster if
 * the data is in cache, and 1.5-2 times faster if the data is not in
 * cache).
 * We optimize on three fronts:
 *	1. By using the add-with-carry (addxcc) instruction, we can use
 *	   32-bit operations instead of 16-bit operations.
 *	2. By unrolling the main loop to reduce branch overheads.
 *	3. By doing a sequence of load,load,add,add,load,load,add,add,
 *	   we can avoid the extra stall cycle which is incurred if the
 *	   instruction immediately following a load tries to use the
 *	   target register of the load.
 * Another possible optimization is to replace a pair of 32-bit loads
 * with a single 64-bit load (ldd) instruction, but I found that although
 * this improves performance somewhat on Sun4c machines, it actually
 * reduces performance considerably on Sun4m machines (I don't know why).
 * So I chose to leave it out.
 *
 * Zubin Dittia (zubin@dworkin.wustl.edu)
 */

#define Asm	__asm volatile
#define ADD64		Asm("	ld [%4+ 0],%1;   ld [%4+ 4],%2;		\
				addcc  %0,%1,%0; addxcc %0,%2,%0;	\
				ld [%4+ 8],%1;   ld [%4+12],%2;		\
				addxcc %0,%1,%0; addxcc %0,%2,%0;	\
				ld [%4+16],%1;   ld [%4+20],%2;		\
				addxcc %0,%1,%0; addxcc %0,%2,%0;	\
				ld [%4+24],%1;   ld [%4+28],%2;		\
				addxcc %0,%1,%0; addxcc %0,%2,%0;	\
				ld [%4+32],%1;   ld [%4+36],%2;		\
				addxcc %0,%1,%0; addxcc %0,%2,%0;	\
				ld [%4+40],%1;   ld [%4+44],%2;		\
				addxcc %0,%1,%0; addxcc %0,%2,%0;	\
				ld [%4+48],%1;   ld [%4+52],%2;		\
				addxcc %0,%1,%0; addxcc %0,%2,%0;	\
				ld [%4+56],%1;   ld [%4+60],%2;		\
				addxcc %0,%1,%0; addxcc %0,%2,%0;	\
				addxcc %0,0,%0"				\
				: "=r" (sum), "=&r" (tmp1), "=&r" (tmp2)\
				: "0" (sum), "r" (w))
#define ADD32		Asm("	ld [%4+ 0],%1;   ld [%4+ 4],%2;		\
				addcc  %0,%1,%0; addxcc %0,%2,%0;	\
				ld [%4+ 8],%1;   ld [%4+12],%2;		\
				addxcc %0,%1,%0; addxcc %0,%2,%0;	\
				ld [%4+16],%1;   ld [%4+20],%2;		\
				addxcc %0,%1,%0; addxcc %0,%2,%0;	\
				ld [%4+24],%1;   ld [%4+28],%2;		\
				addxcc %0,%1,%0; addxcc %0,%2,%0;	\
				addxcc %0,0,%0"				\
				: "=r" (sum), "=&r" (tmp1), "=&r" (tmp2)\
				: "0" (sum), "r" (w))
#define ADD16		Asm("	ld [%4+ 0],%1;   ld [%4+ 4],%2;		\
				addcc  %0,%1,%0; addxcc %0,%2,%0;	\
				ld [%4+ 8],%1;   ld [%4+12],%2;		\
				addxcc %0,%1,%0; addxcc %0,%2,%0;	\
				addxcc %0,0,%0"				\
				: "=r" (sum), "=&r" (tmp1), "=&r" (tmp2)\
				: "0" (sum), "r" (w))
#define ADD8		Asm("	ld [%4+ 0],%1;   ld [%4+ 4],%2;		\
				addcc  %0,%1,%0; addxcc %0,%2,%0;	\
				addxcc %0,0,%0"				\
				: "=r" (sum), "=&r" (tmp1), "=&r" (tmp2)\
				: "0" (sum), "r" (w))
#define ADD4		Asm("	ld [%3+ 0],%1; 				\
				addcc  %0,%1,%0;			\
				addxcc %0,0,%0"				\
				: "=r" (sum), "=&r" (tmp1)		\
				: "0" (sum), "r" (w))

#define REDUCE		{sum = (sum & 0xffff) + (sum >> 16);}
#define ROL		{sum = sum << 8;}	/* depends on recent REDUCE */
#define ADDBYTE		{ROL; sum += *w; byte_swapped ^= 1;}
#define ADDSHORT	{sum += *(u_short *)w;}
#define ADVANCE(n)	{w += n; mlen -= n;}

static __inline__ int
in_cksum_internal(struct mbuf *m, int off, int len, u_int sum)
{
	u_char *w;
	int mlen = 0;
	int byte_swapped = 0;

	/*
	 * Declare two temporary registers for use by the asm code.  We
	 * allow the compiler to pick which specific machine registers to
	 * use, instead of hard-coding this in the asm code above.
	 */
	u_int tmp1, tmp2;

	for (; m && len; m = m->m_next) {
		if (m->m_len == 0)
			continue;
		w = mtod(m, u_char *) + off;
		mlen = m->m_len - off;
		off = 0;
		if (len < mlen)
			mlen = len;
		len -= mlen;

		/*
		 * Ensure that we're aligned on a word boundary here so
		 * that we can do 32 bit operations below.
		 */
		if ((3 & (long)w) != 0) {
			REDUCE;
			if ((1 & (long)w) != 0 && mlen >= 1) {
				ADDBYTE;
				ADVANCE(1);
			}
			if ((2 & (long)w) != 0 && mlen >= 2) {
				ADDSHORT;
				ADVANCE(2);
			}
		}

		/*
		 * Do as many 32 bit operations as possible using the
		 * 64/32/16/8/4 macro's above, using as many as possible of
		 * these.
		 */
		while (mlen >= 64) {
			ADD64;
			ADVANCE(64);
		}
		if (mlen >= 32) {
			ADD32;
			ADVANCE(32);
		}
		if (mlen >= 16) {
			ADD16;
			ADVANCE(16);
		}
		if (mlen >= 8) {
			ADD8;
			ADVANCE(8);
		}
		if (mlen >= 4) {
			ADD4;
			ADVANCE(4)
		}
		if (mlen == 0)
			continue;

		REDUCE;
		if (mlen >= 2) {
			ADDSHORT;
			ADVANCE(2);
		}
		if (mlen == 1) {
			ADDBYTE;
		}
	}
	if (byte_swapped) {
		REDUCE;
		ROL;
	}
	/* Two REDUCEs is faster than REDUCE1; if (sum > 65535) sum -= 65535; */
	REDUCE;
	REDUCE;

	return (0xffff ^ sum);
}

int
in_cksum(struct mbuf *m, int len)
{

	return (in_cksum_internal(m, 0, len, 0));
}

int
in4_cksum(struct mbuf *m, u_int8_t nxt, int off, int len)
{
	u_char *w;
	u_int sum = 0;
	struct ipovly ipov;

	/*
	 * Declare two temporary registers for use by the asm code.  We
	 * allow the compiler to pick which specific machine registers to
	 * use, instead of hard-coding this in the asm code above.
	 */
	u_int tmp1, tmp2;

	if (nxt != 0) {
		/* pseudo header */
		memset(&ipov, 0, sizeof(ipov));
		ipov.ih_len = htons(len);
		ipov.ih_pr = nxt;
		ipov.ih_src = mtod(m, struct ip *)->ip_src;
		ipov.ih_dst = mtod(m, struct ip *)->ip_dst;
		w = (u_char *)&ipov;
		/* assumes sizeof(ipov) == 20 */
		ADD16;
		w += 16;
		ADD4;
	}

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

	return (in_cksum_internal(m, off, len, sum));
}