PERFORCE change 100869 for review
Wojciech A. Koszek
wkoszek at FreeBSD.org
Fri Jul 7 12:20:10 UTC 2006
http://perforce.freebsd.org/chv.cgi?CH=100869
Change 100869 by wkoszek at wkoszek_laptop on 2006/07/07 12:19:12
This is very hackish way of getting db_interface.c work. Some
routines need to be investigated and uncommented to make kernel with
DDB more happy. Leave those #ifdef'ed.
Affected files ...
.. //depot/projects/mips2/src/sys/mips/mips/db_interface.c#3 edit
Differences ...
==== //depot/projects/mips2/src/sys/mips/mips/db_interface.c#3 (text+ko) ====
@@ -1,30 +1,31 @@
-/*-
- * Copyright (c) [year] [your name]
- * All rights reserved.
+/* $NetBSD: db_interface.c,v 1.46 2003/01/17 23:36:11 thorpej 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 "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
- * 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.
+ * Carnegie Mellon requests users of this software to return to
*
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ * Software Distribution Coordinator or Software.Distribution at CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
*
- * $Id$
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
*/
+
#include "opt_ddb.h"
#include <sys/types.h>
@@ -53,21 +54,727 @@
#include <ddb/db_output.h>
#include <ddb/db_sym.h>
+int db_active = 0;
+db_regs_t ddb_regs;
+register_t kdbaux[11]; /* XXX struct switchframe: better inside curpcb? XXX */
+
+static void kdbpoke_4(db_addr_t addr, int newval);
+static void kdbpoke_2(db_addr_t addr, short newval);
+static void kdbpoke_1(db_addr_t addr, char newval);
+/*
+ * XXXMIPS:
+ */
+#if 0
+static short kdbpeek_2(db_addr_t addr);
+static char kdbpeek_1(db_addr_t addr);
+static db_addr_t MachEmulateBranch(struct frame *, db_addr_t, unsigned long, int);
+#endif
+
+/*
+ * XXXMIPS:
+ */
+#if 0
+int
+kdbpeek(db_addr_t addr)
+{
+
+ if (addr == 0 || (addr & 3))
+ return 0;
+ return *(int *)addr;
+}
+
+static short
+kdbpeek_2(db_addr_t addr)
+{
+
+ return *(short *)addr;
+}
+
+static char
+kdbpeek_1(db_addr_t addr)
+{
+
+ return *(char *)addr;
+}
+#endif
+
+/*
+ * kdbpoke -- write a value to a kernel virtual address.
+ * XXX should handle KSEG2 addresses and check for unmapped pages.
+ * XXX user-space addresess?
+ */
+static void
+kdbpoke_4(db_addr_t addr, int newval)
+{
+
+ *(int*) addr = newval;
+ mips_wbflush();
+}
+
+static void
+kdbpoke_2(db_addr_t addr, short newval)
+{
+
+ *(short*) addr = newval;
+ mips_wbflush();
+}
+
+static void
+kdbpoke_1(db_addr_t addr, char newval)
+{
+ *(char*) addr = newval;
+ mips_wbflush();
+}
+
+#if 0 /* UNUSED */
+/*
+ * Received keyboard interrupt sequence.
+ */
+void
+kdb_kbd_trap(int *tf)
+{
+
+ if (db_active == 0 && (boothowto & RB_KDB)) {
+ printf("\n\nkernel: keyboard interrupt\n");
+ ddb_trap(-1, tf);
+ }
+}
+#endif
+
+/*
+ * XXXMIPS: kdb_trap is disabled for now. I probably saw it somewhere in
+ * subr_kdb.c, but not for sure.
+ */
+#if 0
+int
+kdb_trap(int type, struct trapframe *tfp)
+{
+
+ struct frame *f = (struct frame *)&ddb_regs;
+/*
+ * XXXMIPS:
+ */
+#if 0
+#ifdef notyet
+ switch (type) {
+ case T_BREAK: /* breakpoint */
+ case -1: /* keyboard interrupt */
+ break;
+ default:
+ printf("kernel: %s trap", trap_type[type & 0xff]);
+ if (db_recover != 0) {
+ db_error("Faulted in DDB; continuing...\n");
+ /*NOTREACHED*/
+ }
+ break;
+ }
+#endif
+#endif
+ /* Should switch to kdb`s own stack here. */
+ db_set_ddb_regs(type, tfp);
+
+ db_active++;
+ cndbctl(TRUE);
+/*
+ * XXXMIPS:
+ */
+#if 0
+#if notyet
+ db_trap(type & ~T_USER, 0 /*code*/);
+#else
+ db_trap(type, 0 /*code*/);
+#endif
+#endif
+ cndbctl(FALSE);
+ db_active--;
+/*
+ * XXXMIPS:
+ */
+#if 0
+#if notyet
+ if (type & T_USER)
+ *(struct frame *)curthread->td_md.md_regs = *f;
+#else
+ if (0)
+ return (1);
+#endif
+#endif
+ else {
+ /* Synthetic full scale register context when trap happens */
+ kdbaux[0] = f->f_regs[S0];
+ kdbaux[1] = f->f_regs[S1];
+ kdbaux[2] = f->f_regs[S2];
+ kdbaux[3] = f->f_regs[S3];
+ kdbaux[4] = f->f_regs[S4];
+ kdbaux[5] = f->f_regs[S5];
+ kdbaux[6] = f->f_regs[S6];
+ kdbaux[7] = f->f_regs[S7];
+ kdbaux[8] = f->f_regs[SP];
+ kdbaux[9] = f->f_regs[S8];
+ kdbaux[10] = f->f_regs[GP];
+ }
+
+ return (1);
+}
+#endif
void
-db_show_mdpcpu(struct pcpu *pc)
+db_set_ddb_regs(int type, struct trapframe *tfp)
{
+ struct frame *f = (struct frame *)&ddb_regs;
+
+ /* Should switch to kdb`s own stack here. */
+
+/*
+ * XXXMIPS:
+ */
+#if 0
+#if notyet
+ if (type & T_USER)
+ *f = *(struct frame *)curthread->td_md.md_regs;
+#else
+ if (0)
+ return;
+#endif
+#endif
+ /*
+ * XXXMIPS: I also added this one.
+ */
+ if (0)
+ return;
+ else {
+ /* Synthetic full scale register context when trap happens */
+ f->f_regs[AST] = tfp->tf_regs[TF_AST];
+ f->f_regs[V0] = tfp->tf_regs[TF_V0];
+ f->f_regs[V1] = tfp->tf_regs[TF_V1];
+ f->f_regs[A0] = tfp->tf_regs[TF_A0];
+ f->f_regs[A1] = tfp->tf_regs[TF_A1];
+ f->f_regs[A2] = tfp->tf_regs[TF_A2];
+ f->f_regs[A3] = tfp->tf_regs[TF_A3];
+ f->f_regs[T0] = tfp->tf_regs[TF_T0];
+ f->f_regs[T1] = tfp->tf_regs[TF_T1];
+ f->f_regs[T2] = tfp->tf_regs[TF_T2];
+ f->f_regs[T3] = tfp->tf_regs[TF_T3];
+ f->f_regs[TA0] = tfp->tf_regs[TF_TA0];
+ f->f_regs[TA1] = tfp->tf_regs[TF_TA1];
+ f->f_regs[TA2] = tfp->tf_regs[TF_TA2];
+ f->f_regs[TA3] = tfp->tf_regs[TF_TA3];
+ f->f_regs[T8] = tfp->tf_regs[TF_T8];
+ f->f_regs[T9] = tfp->tf_regs[TF_T9];
+ f->f_regs[RA] = tfp->tf_regs[TF_RA];
+ f->f_regs[SR] = tfp->tf_regs[TF_SR];
+ f->f_regs[MULLO] = tfp->tf_regs[TF_MULLO];
+ f->f_regs[MULHI] = tfp->tf_regs[TF_MULHI];
+ f->f_regs[PC] = tfp->tf_regs[TF_EPC];
+ f->f_regs[S0] = kdbaux[0];
+ f->f_regs[S1] = kdbaux[1];
+ f->f_regs[S2] = kdbaux[2];
+ f->f_regs[S3] = kdbaux[3];
+ f->f_regs[S4] = kdbaux[4];
+ f->f_regs[S5] = kdbaux[5];
+ f->f_regs[S6] = kdbaux[6];
+ f->f_regs[S7] = kdbaux[7];
+ f->f_regs[SP] = kdbaux[8];
+ f->f_regs[S8] = kdbaux[9];
+ f->f_regs[GP] = kdbaux[10];
+ }
}
+/*
+ * Read bytes from kernel address space for debugger.
+ */
int
-db_write_bytes(vm_offset_t addr, size_t size, char *data)
+db_read_bytes(vm_offset_t addr, size_t size, char *data)
{
+
+/*
+ * XXXMIPS: warning: use of cast expressions as lvalues is deprecated
+ */
+#if 0
+ while (size >= 4)
+ *((int*)data)++ = kdbpeek(addr), addr += 4, size -= 4;
+ while (size >= 2)
+ *((short*)data)++ = kdbpeek_2(addr), addr += 2, size -= 2;
+ if (size == 1)
+ *((char*)data)++ = kdbpeek_1(addr);
+#endif
return (0);
}
+/*
+ * Write bytes to kernel address space for debugger.
+ */
int
-db_read_bytes(vm_offset_t addr, size_t size, char *data)
+db_write_bytes(vm_offset_t addr, size_t size, char *data)
{
+ db_addr_t p = addr;
+ size_t n = size;
+
+#ifdef DEBUG_DDB
+ printf("db_write_bytes(%lx, %d, %p, val %x)\n", addr, size, data,
+ (addr &3 ) == 0? *(u_int*)addr: -1);
+#endif
+
+ while (n >= 4) {
+ kdbpoke_4(p, *(int*)data);
+ p += 4;
+ data += 4;
+ n -= 4;
+ }
+ if (n >= 2) {
+ kdbpoke_2(p, *(short*)data);
+ p += 2;
+ data += 2;
+ n -= 2;
+ }
+ if (n == 1) {
+ kdbpoke_1(p, *(char*)data);
+ }
+
+ mips_icache_sync_range((db_addr_t) addr, size);
return (0);
}
+DB_COMMAND(tlb, db_tlbdump_cmd)
+{
+ u_long hi;
+ u_long lo[2];
+ u_long pm;
+ int i;
+
+ for (i = 0; i < mips_num_tlb_entries; i++) {
+ mips_wr_index(i);
+ mips_tlbr();
+ hi = mips_rd_entryhi();
+ lo[0] = mips_rd_entrylo0();
+ lo[1] = mips_rd_entrylo1();
+ pm = mips_rd_pagemask();
+
+ printf("=== TLB Entry %02d === ", i);
+ printf("(%svalid) ", (lo[0] | lo[1]) & PG_V ? " " : "in");
+ printf("EntryHi=0x%016lx ", hi);
+ printf("PageMask=%#lx\n", pm);
+ if (*modif != 'a' && (((lo[0] | lo[1]) & PG_V) == 0))
+ continue;
+ printf("\tEntryLo0 = 0x%016lx (%c%c%c)\n", lo[0],
+ (lo[0] & PG_D) ? 'D' : ' ',
+ (lo[0] & PG_G) ? 'G' : ' ',
+ (lo[0] & PG_V) ? 'V' : '!');
+ printf("\tEntryLo1 = 0x%016lx (%c%c%c)\n", lo[1],
+ (lo[1] & PG_D) ? 'D' : ' ',
+ (lo[1] & PG_G) ? 'G' : ' ',
+ (lo[1] & PG_V) ? 'V' : '!');
+ }
+}
+
+DB_COMMAND(kvtop, db_kvtophys_cmd)
+{
+
+ if (!have_addr)
+ return;
+ db_printf("%#lx -> %#lx\n", (u_long)addr,
+ (u_long)pmap_kextract(addr));
+}
+
+#define FLDWIDTH 10
+#define SHOW32(reg, name) \
+do { \
+ uint32_t __val; \
+ \
+ __asm __volatile("mfc0 %0,$" __STRING(reg) : "=r"(__val)); \
+ printf(" %s:%*s %#x\n", name, FLDWIDTH - (int) strlen(name), \
+ "", (u_int)__val); \
+} while (0)
+
+/*
+ * XXXMIPS:
+ */
+#if 0
+/* XXX not 64-bit ABI safe! */
+#define SHOW64(reg, name) \
+do { \
+ uint64_t __val; \
+ \
+ __asm __volatile("dmfc0 %0,$" __STRING(reg):"=r"(__val)); \
+ printf(" %s:%*s %#lx\n", name, FLDWIDTH - (int) strlen(name), \
+ "", (u_long)__val); \
+} while (0)
+#endif
+
+#define SHOW64(reg, name) \
+do { \
+ uint64_t __val; \
+ \
+ __asm __volatile("mfc0 %0,$" __STRING(reg):"=r"(__val)); \
+ printf(" %s:%*s %#lx\n", name, FLDWIDTH - (int) strlen(name), \
+ "", (u_long)__val); \
+} while (0)
+
+DB_COMMAND(cp0, db_cp0dump_cmd)
+{
+ SHOW32(MIPS_COP_0_TLB_INDEX, "index");
+ SHOW32(MIPS_COP_0_TLB_RANDOM, "random");
+
+ SHOW64(MIPS_COP_0_TLB_LO0, "entrylo0");
+ SHOW64(MIPS_COP_0_TLB_LO1, "entrylo1");
+
+ SHOW64(MIPS_COP_0_TLB_CONTEXT, "context");
+
+ SHOW32(MIPS_COP_0_TLB_PG_MASK, "pagemask");
+ SHOW32(MIPS_COP_0_TLB_WIRED, "wired");
+
+ SHOW64(MIPS_COP_0_BAD_VADDR, "badvaddr");
+
+ SHOW32(MIPS_COP_0_COUNT, "count");
+
+ SHOW64(MIPS_COP_0_TLB_HI, "entryhi");
+
+ SHOW32(MIPS_COP_0_COMPARE, "compare");
+
+ SHOW32(MIPS_COP_0_STATUS, "status");
+ SHOW32(MIPS_COP_0_CAUSE, "cause");
+
+ SHOW64(MIPS_COP_0_EXC_PC, "epc");
+
+ SHOW32(MIPS_COP_0_PRID, "prid");
+ SHOW32(MIPS_COP_0_CONFIG, "config");
+
+ SHOW64(MIPS_COP_0_LLADDR, "lladdr");
+ SHOW64(MIPS_COP_0_WATCH_LO, "watchlo");
+
+ SHOW32(MIPS_COP_0_WATCH_HI, "watchhi");
+
+ SHOW64(MIPS_COP_0_TLB_XCONTEXT, "xcontext");
+ SHOW64(MIPS_COP_0_PERFCNT, "perfcnt");
+
+ SHOW32(MIPS_COP_0_ECC, "ecc");
+ SHOW32(MIPS_COP_0_CACHE_ERR, "cacherr");
+ SHOW32(MIPS_COP_0_TAG_LO, "cachelo");
+ SHOW32(MIPS_COP_0_TAG_HI, "cachehi");
+
+ SHOW64(MIPS_COP_0_ERROR_PC, "errorpc");
+}
+
+/*
+ * Determine whether the instruction involves a delay slot.
+ */
+boolean_t
+inst_branch(int inst)
+{
+ InstFmt i;
+ int delay;
+
+ i.word = inst;
+ delay = 0;
+ switch (i.JType.op) {
+ case OP_BCOND:
+ case OP_J:
+ case OP_JAL:
+ case OP_BEQ:
+ case OP_BNE:
+ case OP_BLEZ:
+ case OP_BGTZ:
+ case OP_BEQL:
+ case OP_BNEL:
+ case OP_BLEZL:
+ case OP_BGTZL:
+ delay = 1;
+ break;
+
+ case OP_COP0:
+ case OP_COP1:
+ switch (i.RType.rs) {
+ case OP_BCx:
+ case OP_BCy:
+ delay = 1;
+ }
+ break;
+
+ case OP_SPECIAL:
+ if (i.RType.op == OP_JR || i.RType.op == OP_JALR)
+ delay = 1;
+ break;
+ }
+ return delay;
+}
+
+/*
+ * Determine whether the instruction calls a function.
+ */
+boolean_t
+inst_call(int inst)
+{
+ boolean_t call;
+ InstFmt i;
+
+ i.word = inst;
+ if (i.JType.op == OP_SPECIAL
+ && ((i.RType.func == OP_JR && i.RType.rs != 31) ||
+ i.RType.func == OP_JALR))
+ call = 1;
+ else if (i.JType.op == OP_JAL)
+ call = 1;
+ else
+ call = 0;
+ return call;
+}
+
+/*
+ * Determine whether the instruction returns from a function (j ra). The
+ * compiler can use this construct for other jumps, but usually will not.
+ * This lets the ddb "next" command to work (also need inst_trap_return()).
+ */
+boolean_t
+inst_return(int inst)
+{
+ InstFmt i;
+
+ i.word = inst;
+
+ return (i.JType.op == OP_SPECIAL && i.RType.func == OP_JR &&
+ i.RType.rs == 31);
+}
+
+/*
+ * Determine whether the instruction makes a jump.
+ */
+boolean_t
+inst_unconditional_flow_transfer(int inst)
+{
+ InstFmt i;
+ boolean_t jump;
+
+ i.word = inst;
+ jump = (i.JType.op == OP_J) ||
+ (i.JType.op == OP_SPECIAL && i.RType.func == OP_JR);
+ return jump;
+}
+
+/*
+ * Determine whether the instruction is a load/store as appropriate.
+ */
+boolean_t
+inst_load(int inst)
+{
+ InstFmt i;
+
+ i.word = inst;
+
+ switch (i.JType.op) {
+ case OP_LWC1:
+ case OP_LB:
+ case OP_LH:
+ case OP_LW:
+ case OP_LD:
+ case OP_LBU:
+ case OP_LHU:
+ case OP_LWU:
+ case OP_LDL:
+ case OP_LDR:
+ case OP_LWL:
+ case OP_LWR:
+ case OP_LL:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+boolean_t
+inst_store(int inst)
+{
+ InstFmt i;
+
+ i.word = inst;
+
+ switch (i.JType.op) {
+ case OP_SWC1:
+ case OP_SB:
+ case OP_SH:
+ case OP_SW:
+ case OP_SD:
+ case OP_SDL:
+ case OP_SDR:
+ case OP_SWL:
+ case OP_SWR:
+ case OP_SCD:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/*
+ * Return the next pc if the given branch is taken.
+ * MachEmulateBranch() runs analysis for branch delay slot.
+ */
+#if 0
+db_addr_t
+branch_taken(int inst, db_addr_t pc, db_regs_t *regs)
+{
+ db_addr_t ra;
+ unsigned long fpucsr;
+
+ fpucsr = curthread ? PCB_FSR(curthread->td_pcb) : 0;
+ ra = MachEmulateBranch((struct frame *)regs, pc, fpucsr, 0);
+ return ra;
+}
+#endif
+
+/*
+ * Return the next pc of an arbitrary instruction.
+ */
+db_addr_t
+next_instr_address(db_addr_t pc, boolean_t bd)
+{
+ unsigned ins;
+
+ if (bd == FALSE)
+ return (pc + 4);
+
+ if (pc < MIPS_KSEG0_START)
+ ins = fuword((void *)pc);
+ else
+ ins = *(unsigned *)pc;
+
+ if (inst_branch(ins) || inst_call(ins) || inst_return(ins))
+ return (pc + 4);
+
+ return (pc);
+}
+
+void
+db_show_mdpcpu(struct pcpu *pc)
+{
+}
+
+DB_COMMAND(reboot, db_reboot)
+{
+ cpu_reset();
+}
+
+DB_COMMAND(halt, db_halt)
+{
+ cpu_halt();
+}
+
+#if 0
+/*
+ * Analyse 'next' PC address taking account of branch/jump instructions
+ */
+static db_addr_t
+MachEmulateBranch(f, instpc, fpuCSR, allowNonBranch)
+ struct frame *f;
+ db_addr_t instpc;
+ unsigned long fpuCSR;
+ int allowNonBranch;
+{
+#define BRANCHTARGET(p) (4 + (p) + ((short)((InstFmt *)(p))->IType.imm << 2))
+ InstFmt inst;
+ db_addr_t nextpc;
+
+ if (instpc < MIPS_KSEG0_START)
+ inst.word = fuword((void *)instpc);
+ else
+ inst.word = *(unsigned *)instpc;
+
+ switch ((int)inst.JType.op) {
+ case OP_SPECIAL:
+ if (inst.RType.func == OP_JR || inst.RType.func == OP_JALR)
+ nextpc = f->f_regs[inst.RType.rs];
+ else if (allowNonBranch)
+ nextpc = instpc + 4;
+ else
+ panic("MachEmulateBranch: Non-branch");
+ break;
+
+ case OP_BCOND:
+ switch ((int)inst.IType.rt) {
+ case OP_BLTZ:
+ case OP_BLTZAL:
+ case OP_BLTZL: /* squashed */
+ case OP_BLTZALL: /* squashed */
+ if ((int)(f->f_regs[inst.RType.rs]) < 0)
+ nextpc = BRANCHTARGET(instpc);
+ else
+ nextpc = instpc + 8;
+ break;
+
+ case OP_BGEZ:
+ case OP_BGEZAL:
+ case OP_BGEZL: /* squashed */
+ case OP_BGEZALL: /* squashed */
+ if ((int)(f->f_regs[inst.RType.rs]) >= 0)
+ nextpc = BRANCHTARGET(instpc);
+ else
+ nextpc = instpc + 8;
+ break;
+
+ default:
+ panic("MachEmulateBranch: Bad branch cond");
+ }
+ break;
+
+ case OP_J:
+ case OP_JAL:
+ nextpc = (inst.JType.target << 2) |
+ ((register_t)instpc & 0xF0000000);
+ break;
+
+ case OP_BEQ:
+ case OP_BEQL: /* squashed */
+ if (f->f_regs[inst.RType.rs] == f->f_regs[inst.RType.rt])
+ nextpc = BRANCHTARGET(instpc);
+ else
+ nextpc = instpc + 8;
+ break;
+
+ case OP_BNE:
+ case OP_BNEL: /* squashed */
+ if (f->f_regs[inst.RType.rs] != f->f_regs[inst.RType.rt])
+ nextpc = BRANCHTARGET(instpc);
+ else
+ nextpc = instpc + 8;
+ break;
+
+ case OP_BLEZ:
+ case OP_BLEZL: /* squashed */
+ if ((int)(f->f_regs[inst.RType.rs]) <= 0)
+ nextpc = BRANCHTARGET(instpc);
+ else
+ nextpc = instpc + 8;
+ break;
+
+ case OP_BGTZ:
+ case OP_BGTZL: /* squashed */
+ if ((int)(f->f_regs[inst.RType.rs]) > 0)
+ nextpc = BRANCHTARGET(instpc);
+ else
+ nextpc = instpc + 8;
+ break;
+
+ case OP_COP1:
+ if (inst.RType.rs == OP_BCx || inst.RType.rs == OP_BCy) {
+ int condition = (fpuCSR & MIPS_FPU_COND_BIT) != 0;
+ if ((inst.RType.rt & COPz_BC_TF_MASK) != COPz_BC_TRUE)
+ condition = !condition;
+ if (condition)
+ nextpc = BRANCHTARGET(instpc);
+ else
+ nextpc = instpc + 8;
+ }
+ else if (allowNonBranch)
+ nextpc = instpc + 4;
+ else
+ panic("MachEmulateBranch: Bad COP1 branch instruction");
+ break;
+
+ default:
+ if (!allowNonBranch)
+ panic("MachEmulateBranch: Non-branch instruction");
+ nextpc = instpc + 4;
+ }
+ return nextpc;
+#undef BRANCHTARGET
+}
+#endif
More information about the p4-projects
mailing list