From owner-p4-projects@FreeBSD.ORG Fri Jul 7 12:20:10 2006 Return-Path: X-Original-To: p4-projects@freebsd.org Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 358A716A4E7; Fri, 7 Jul 2006 12:20:10 +0000 (UTC) X-Original-To: perforce@FreeBSD.org Delivered-To: perforce@FreeBSD.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id D1FE716A4E1 for ; Fri, 7 Jul 2006 12:20:09 +0000 (UTC) (envelope-from wkoszek@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [216.136.204.115]) by mx1.FreeBSD.org (Postfix) with ESMTP id D60D143D79 for ; Fri, 7 Jul 2006 12:20:08 +0000 (GMT) (envelope-from wkoszek@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.6/8.13.6) with ESMTP id k67CK8n2004489 for ; Fri, 7 Jul 2006 12:20:08 GMT (envelope-from wkoszek@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.6/8.13.4/Submit) id k67CK8de004486 for perforce@freebsd.org; Fri, 7 Jul 2006 12:20:08 GMT (envelope-from wkoszek@FreeBSD.org) Date: Fri, 7 Jul 2006 12:20:08 GMT Message-Id: <200607071220.k67CK8de004486@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to wkoszek@FreeBSD.org using -f From: "Wojciech A. Koszek" To: Perforce Change Reviews Cc: Subject: PERFORCE change 100869 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 07 Jul 2006 12:20:10 -0000 http://perforce.freebsd.org/chv.cgi?CH=100869 Change 100869 by wkoszek@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@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 @@ -53,21 +54,727 @@ #include #include +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