Overhaul the emulation facility. We do this by:
- accumulating all emulation code (including floating-point) in one place - steal MachFPInterrupt() back from SOFTFLOAT for use only with interrupts and traps from *real* FPUs - introducing MachEmulateInst() as a common dispatch point for all emulated instructions - cleaning up emulation dispatch in trap() Also, while we're here, implement MIPS2 LL/SC/SYNC emulation for MIPS1. Tested on r3k with and without SOFTFLOAT enabled.
This commit is contained in:
parent
de0c9630a1
commit
cc4037a913
@ -1,4 +1,4 @@
|
||||
# $NetBSD: files.mips,v 1.41 2002/06/01 11:41:33 simonb Exp $
|
||||
# $NetBSD: files.mips,v 1.42 2002/07/06 23:59:18 gmcgarry Exp $
|
||||
#
|
||||
|
||||
defflag opt_cputype.h NOFPU # and the rest...
|
||||
@ -47,7 +47,7 @@ file arch/mips/mips/cache_mipsNN.c mips32 | mips64
|
||||
file arch/mips/mips/in_cksum.c inet
|
||||
file netns/ns_cksum.c ns
|
||||
|
||||
file arch/mips/mips/fpemu.c softfloat
|
||||
file arch/mips/mips/mips_emul.c
|
||||
file arch/mips/mips/fp.S softfloat | !nofpu
|
||||
|
||||
file arch/mips/mips/procfs_machdep.c procfs
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: cpuregs.h,v 1.53 2002/06/27 03:43:45 simonb Exp $ */
|
||||
/* $NetBSD: cpuregs.h,v 1.54 2002/07/06 23:59:19 gmcgarry Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
@ -557,10 +557,6 @@
|
||||
*/
|
||||
#define MIPS_OPCODE_SHIFT 26
|
||||
#define MIPS_OPCODE_C1 0x11
|
||||
#define MIPS_OPCODE_LWC1 0x31
|
||||
#define MIPS_OPCODE_LDC1 0x35
|
||||
#define MIPS_OPCODE_SWC1 0x39
|
||||
#define MIPS_OPCODE_SDC1 0x3d
|
||||
|
||||
|
||||
/*
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: mips_opcode.h,v 1.8 2001/08/13 18:48:48 soda Exp $ */
|
||||
/* $NetBSD: mips_opcode.h,v 1.9 2002/07/06 23:59:19 gmcgarry Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1992, 1993
|
||||
@ -126,6 +126,7 @@ typedef union {
|
||||
#define OP_BNE 005
|
||||
#define OP_BLEZ 006
|
||||
#define OP_BGTZ 007
|
||||
#define OP_SYNC 017
|
||||
|
||||
#define OP_ADDI 010
|
||||
#define OP_ADDIU 011
|
||||
@ -178,6 +179,7 @@ typedef union {
|
||||
#define OP_LWC2 062
|
||||
#define OP_LWC3 063
|
||||
#define OP_LLD 064 /* MIPS-II, for r4000 port */
|
||||
#define OP_LDC1 065
|
||||
#define OP_LD 067 /* MIPS-II, for r4000 port */
|
||||
|
||||
#define OP_SC 070
|
||||
@ -186,6 +188,7 @@ typedef union {
|
||||
#define OP_SWC2 072
|
||||
#define OP_SWC3 073
|
||||
#define OP_SCD 074 /* MIPS-II, for r4000 port */
|
||||
#define OP_SDC1 075
|
||||
#define OP_SD 077 /* MIPS-II, for r4000 port */
|
||||
|
||||
/*
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: locore.S,v 1.141 2002/07/04 19:20:01 thorpej Exp $ */
|
||||
/* $NetBSD: locore.S,v 1.142 2002/07/06 23:59:20 gmcgarry Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
@ -1194,7 +1194,7 @@ LEAF(mips_cp0_status_write)
|
||||
END(mips_cp0_status_write)
|
||||
|
||||
|
||||
#if !defined(NOFPU) || defined(SOFTFLOAT)
|
||||
#if !defined(NOFPU) && !defined(SOFTFLOAT)
|
||||
/*----------------------------------------------------------------------------
|
||||
*
|
||||
* MachFPInterrupt --
|
||||
@ -1227,11 +1227,8 @@ NESTED(MachFPInterrupt, CALLFRAME_SIZ, ra)
|
||||
XNESTED(MachFPTrap)
|
||||
.mask 0x80000000, -4
|
||||
subu sp, sp, CALLFRAME_SIZ
|
||||
#ifndef SOFTFLOAT
|
||||
mfc0 t0, MIPS_COP_0_STATUS
|
||||
#endif
|
||||
sw ra, CALLFRAME_RA(sp)
|
||||
#ifndef SOFTFLOAT
|
||||
or t0, t0, MIPS_SR_COP_1_BIT
|
||||
mtc0 t0, MIPS_COP_0_STATUS
|
||||
COP0_SYNC
|
||||
@ -1246,9 +1243,13 @@ XNESTED(MachFPTrap)
|
||||
sll t2, t0, (31 - 17) # unimplemented operation?
|
||||
bgez t2, 3f # no, normal trap
|
||||
nop
|
||||
#endif
|
||||
/*
|
||||
* We got an unimplemented operation trap so
|
||||
* We received an unimplemented operation trap.
|
||||
*
|
||||
* We check whether it's an unimplemented FP instruction here rather
|
||||
* than invoking MachEmulateInst(), since it is faster.
|
||||
*
|
||||
* fetch the instruction and emulate the instruction.
|
||||
*/
|
||||
bgez a1, 1f # Check the branch delay bit.
|
||||
@ -1275,21 +1276,6 @@ XNESTED(MachFPTrap)
|
||||
beq t0, MIPS_OPCODE_C1, 4f
|
||||
nop
|
||||
|
||||
#ifdef SOFTFLOAT
|
||||
REG_PROLOGUE
|
||||
REG_S zero, FRAME_ZERO(a3) # ensure zero has value 0
|
||||
REG_EPILOGUE
|
||||
|
||||
beq t0, MIPS_OPCODE_LWC1, 5f
|
||||
nop
|
||||
beq t0, MIPS_OPCODE_LDC1, 6f
|
||||
nop
|
||||
beq t0, MIPS_OPCODE_SWC1, 7f
|
||||
nop
|
||||
beq t0, MIPS_OPCODE_SDC1, 8f
|
||||
nop
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Send a floating point exception signal to the current process.
|
||||
*/
|
||||
@ -1336,48 +1322,15 @@ XNESTED(MachFPTrap)
|
||||
* Turn off the floating point coprocessor and return.
|
||||
*/
|
||||
FPReturn:
|
||||
#ifndef SOFTFLOAT
|
||||
mfc0 t0, MIPS_COP_0_STATUS
|
||||
#endif
|
||||
lw ra, CALLFRAME_RA(sp)
|
||||
#ifndef SOFTFLOAT
|
||||
and t0, t0, ~MIPS_SR_COP_1_BIT
|
||||
mtc0 t0, MIPS_COP_0_STATUS
|
||||
COP0_SYNC
|
||||
#else
|
||||
nop
|
||||
#endif
|
||||
j ra
|
||||
addu sp, sp, CALLFRAME_SIZ
|
||||
|
||||
#ifdef SOFTFLOAT
|
||||
5: # lwc1
|
||||
jal _C_LABEL(MachEmulateLWC1)
|
||||
move a1, a3
|
||||
b FPReturn
|
||||
nop
|
||||
|
||||
6: # ldc1
|
||||
jal _C_LABEL(MachEmulateLDC1)
|
||||
move a1, a3
|
||||
b FPReturn
|
||||
nop
|
||||
|
||||
7: # swc1
|
||||
jal _C_LABEL(MachEmulateSWC1)
|
||||
move a1, a3
|
||||
b FPReturn
|
||||
nop
|
||||
|
||||
8: # sdc1
|
||||
jal _C_LABEL(MachEmulateSDC1)
|
||||
move a1, a3
|
||||
b FPReturn
|
||||
nop
|
||||
|
||||
#endif
|
||||
END(MachFPInterrupt)
|
||||
#endif /* !defined(NOFPU) || defined(SOFTFLOAT) */
|
||||
#endif /* !defined(NOFPU) && !defined(SOFTFLOAT) */
|
||||
|
||||
LEAF(mips_pagecopy)
|
||||
#if !defined(_MIPS_BSD_API) || _MIPS_BSD_API == _MIPS_BSD_API_LP32
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: fpemu.c,v 1.10 2002/03/05 15:46:51 simonb Exp $ */
|
||||
/* $NetBSD: mips_emul.c,v 1.1 2002/07/06 23:59:21 gmcgarry Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1999 Shuichiro URATA. All rights reserved.
|
||||
@ -40,14 +40,23 @@
|
||||
#include <mips/vmparam.h> /* for VM_MAX_ADDRESS */
|
||||
#include <mips/trap.h>
|
||||
|
||||
extern void MachEmulateFP(u_int32_t, struct frame *, u_int32_t);
|
||||
|
||||
static __inline void send_sigsegv(u_int32_t, u_int32_t, struct frame *,
|
||||
u_int32_t);
|
||||
static __inline void update_pc(struct frame *, u_int32_t);
|
||||
|
||||
vaddr_t MachEmulateBranch(struct frame *, vaddr_t, unsigned, int);
|
||||
void MachEmulateInst(u_int32_t, u_int32_t, u_int32_t, struct frame *);
|
||||
|
||||
void MachEmulateLWC0(u_int32_t inst, struct frame *, u_int32_t);
|
||||
void MachEmulateSWC0(u_int32_t inst, struct frame *, u_int32_t);
|
||||
void MachEmulateSpecial(u_int32_t inst, struct frame *, u_int32_t);
|
||||
void MachEmulateLWC1(u_int32_t inst, struct frame *, u_int32_t);
|
||||
void MachEmulateLDC1(u_int32_t inst, struct frame *, u_int32_t);
|
||||
void MachEmulateSWC1(u_int32_t inst, struct frame *, u_int32_t);
|
||||
void MachEmulateSDC1(u_int32_t inst, struct frame *, u_int32_t);
|
||||
|
||||
void bcemul_lb(u_int32_t inst, struct frame *, u_int32_t);
|
||||
void bcemul_lbu(u_int32_t inst, struct frame *, u_int32_t);
|
||||
void bcemul_lh(u_int32_t inst, struct frame *, u_int32_t);
|
||||
@ -61,7 +70,180 @@ void bcemul_sw(u_int32_t inst, struct frame *, u_int32_t);
|
||||
void bcemul_swl(u_int32_t inst, struct frame *, u_int32_t);
|
||||
void bcemul_swr(u_int32_t inst, struct frame *f, u_int32_t);
|
||||
|
||||
vaddr_t MachEmulateBranch(struct frame *, vaddr_t, unsigned, int);
|
||||
/*
|
||||
* Analyse 'next' PC address taking account of branch/jump instructions
|
||||
*/
|
||||
vaddr_t
|
||||
MachEmulateBranch(f, instpc, fpuCSR, allowNonBranch)
|
||||
struct frame *f;
|
||||
vaddr_t instpc;
|
||||
unsigned fpuCSR;
|
||||
int allowNonBranch;
|
||||
{
|
||||
#define BRANCHTARGET(p) (4 + (p) + ((short)((InstFmt *)(p))->IType.imm << 2))
|
||||
InstFmt inst;
|
||||
vaddr_t nextpc;
|
||||
|
||||
if (instpc < MIPS_KSEG0_START)
|
||||
inst.word = fuiword((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) |
|
||||
((unsigned)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
|
||||
}
|
||||
|
||||
/*
|
||||
* Emulate instructions (including floating-point instructions)
|
||||
*/
|
||||
void
|
||||
MachEmulateInst(status, cause, opc, frame)
|
||||
u_int32_t status;
|
||||
u_int32_t cause;
|
||||
u_int32_t opc;
|
||||
struct frame *frame;
|
||||
{
|
||||
u_int32_t inst;
|
||||
|
||||
/*
|
||||
* Fetch the instruction.
|
||||
*/
|
||||
if (cause & MIPS_CR_BR_DELAY)
|
||||
inst = fuword((u_int32_t *)opc+1);
|
||||
else
|
||||
inst = fuword((u_int32_t *)opc);
|
||||
|
||||
switch (((InstFmt)inst).FRType.op) {
|
||||
#if defined(MIPS1)
|
||||
case OP_LWC0:
|
||||
MachEmulateLWC0(inst, frame, cause);
|
||||
break;
|
||||
case OP_SWC0:
|
||||
MachEmulateSWC0(inst, frame, cause);
|
||||
break;
|
||||
case OP_SPECIAL:
|
||||
MachEmulateSpecial(inst, frame, cause);
|
||||
break;
|
||||
#endif
|
||||
case OP_COP1:
|
||||
MachEmulateFP(inst, frame, cause);
|
||||
break;
|
||||
#if defined(SOFTFLOAT)
|
||||
case OP_LWC1:
|
||||
MachEmulateLWC1(inst, frame, cause);
|
||||
break;
|
||||
case OP_LDC1:
|
||||
MachEmulateLDC1(inst, frame, cause);
|
||||
break;
|
||||
case OP_SWC1:
|
||||
MachEmulateSWC1(inst, frame, cause);
|
||||
break;
|
||||
case OP_SDC1:
|
||||
MachEmulateSDC1(inst, frame, cause);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
frame->f_regs[CAUSE] = cause;
|
||||
frame->f_regs[BADVADDR] = opc;
|
||||
trapsignal(curproc, SIGSEGV, opc);
|
||||
}
|
||||
}
|
||||
|
||||
static __inline void
|
||||
send_sigsegv(u_int32_t vaddr, u_int32_t exccode, struct frame *frame,
|
||||
@ -86,6 +268,162 @@ update_pc(struct frame *frame, u_int32_t cause)
|
||||
frame->f_regs[PC] += 4;
|
||||
}
|
||||
|
||||
#if defined(MIPS1)
|
||||
|
||||
#define LWLWC0_MAXLOOP 12
|
||||
|
||||
/*
|
||||
* XXX only on uniprocessor machines
|
||||
*/
|
||||
void
|
||||
MachEmulateLWC0(u_int32_t inst, struct frame *frame, u_int32_t cause)
|
||||
{
|
||||
u_int32_t vaddr;
|
||||
int16_t offset;
|
||||
void *t;
|
||||
mips_reg_t pc;
|
||||
int i;
|
||||
|
||||
offset = inst & 0xFFFF;
|
||||
vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
|
||||
|
||||
/* segment and alignment check */
|
||||
if (vaddr > VM_MAX_ADDRESS || vaddr & 0x3) {
|
||||
send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause);
|
||||
return;
|
||||
}
|
||||
|
||||
t = &(frame->f_regs[(inst>>16)&0x1F]);
|
||||
|
||||
if (copyin((void *)vaddr, t, 4) != 0) {
|
||||
send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause);
|
||||
return;
|
||||
}
|
||||
|
||||
pc = frame->f_regs[PC];
|
||||
update_pc(frame, cause);
|
||||
|
||||
if (cause & MIPS_CR_BR_DELAY)
|
||||
return;
|
||||
|
||||
for (i = 1; i < LWLWC0_MAXLOOP; i++) {
|
||||
if (mips_btop(frame->f_regs[PC]) != mips_btop(pc))
|
||||
return;
|
||||
|
||||
vaddr = frame->f_regs[PC]; /* XXX truncates to 32 bits */
|
||||
inst = fuiword((u_int32_t *)vaddr);
|
||||
if (((InstFmt)inst).FRType.op != OP_LWC0)
|
||||
return;
|
||||
|
||||
offset = inst & 0xFFFF;
|
||||
vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
|
||||
|
||||
/* segment and alignment check */
|
||||
if (vaddr > VM_MAX_ADDRESS || vaddr & 0x3) {
|
||||
send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause);
|
||||
return;
|
||||
}
|
||||
|
||||
t = &(frame->f_regs[(inst>>16)&0x1F]);
|
||||
|
||||
if (copyin((void *)vaddr, t, 4) != 0) {
|
||||
send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause);
|
||||
return;
|
||||
}
|
||||
|
||||
pc = frame->f_regs[PC];
|
||||
update_pc(frame, cause);
|
||||
}
|
||||
}
|
||||
|
||||
#define LWSWC0_MAXLOOP 12
|
||||
|
||||
/*
|
||||
* XXX only on uniprocessor machines
|
||||
*/
|
||||
void
|
||||
MachEmulateSWC0(u_int32_t inst, struct frame *frame, u_int32_t cause)
|
||||
{
|
||||
|
||||
u_int32_t vaddr;
|
||||
int16_t offset;
|
||||
void *t;
|
||||
mips_reg_t pc;
|
||||
int i;
|
||||
|
||||
offset = inst & 0xFFFF;
|
||||
vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
|
||||
|
||||
/* segment and alignment check */
|
||||
if (vaddr > VM_MAX_ADDRESS || vaddr & 0x3) {
|
||||
send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause);
|
||||
return;
|
||||
}
|
||||
|
||||
t = &(frame->f_regs[(inst>>16)&0x1F]);
|
||||
|
||||
if (copyout(t, (void *)vaddr, 4) != 0) {
|
||||
send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause);
|
||||
return;
|
||||
}
|
||||
|
||||
pc = frame->f_regs[PC];
|
||||
update_pc(frame, cause);
|
||||
|
||||
if (cause & MIPS_CR_BR_DELAY)
|
||||
return;
|
||||
|
||||
for (i = 1; i < LWSWC0_MAXLOOP; i++) {
|
||||
if (mips_btop(frame->f_regs[PC]) != mips_btop(pc))
|
||||
return;
|
||||
|
||||
vaddr = frame->f_regs[PC]; /* XXX truncates to 32 bits */
|
||||
inst = fuiword((u_int32_t *)vaddr);
|
||||
if (((InstFmt)inst).FRType.op != OP_SWC0)
|
||||
return;
|
||||
|
||||
offset = inst & 0xFFFF;
|
||||
vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
|
||||
|
||||
/* segment and alignment check */
|
||||
if (vaddr > VM_MAX_ADDRESS || vaddr & 0x3) {
|
||||
send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause);
|
||||
return;
|
||||
}
|
||||
|
||||
t = &(frame->f_regs[(inst>>16)&0x1F]);
|
||||
|
||||
if (copyout(t, (void *)vaddr, 4) != 0) {
|
||||
send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause);
|
||||
return;
|
||||
}
|
||||
|
||||
pc = frame->f_regs[PC];
|
||||
update_pc(frame, cause);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MachEmulateSpecial(u_int32_t inst, struct frame *frame, u_int32_t cause)
|
||||
{
|
||||
switch (((InstFmt)inst).RType.func) {
|
||||
case OP_SYNC:
|
||||
/* nothing */
|
||||
break;
|
||||
default:
|
||||
frame->f_regs[CAUSE] = cause;
|
||||
frame->f_regs[BADVADDR] = frame->f_regs[PC];
|
||||
trapsignal(curproc, SIGSEGV, frame->f_regs[PC]);
|
||||
}
|
||||
|
||||
update_pc(frame, cause);
|
||||
}
|
||||
|
||||
#endif /* defined(MIPS1) */
|
||||
|
||||
|
||||
#if defined(SOFTFLOAT)
|
||||
|
||||
#define LWSWC1_MAXLOOP 12
|
||||
|
||||
void
|
||||
@ -591,3 +929,4 @@ bcemul_swr(u_int32_t inst, struct frame *frame, u_int32_t cause)
|
||||
|
||||
update_pc(frame, cause);
|
||||
}
|
||||
#endif /* defined(SOFTFLOAT) */
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: trap.c,v 1.169 2002/03/11 16:39:40 uch Exp $ */
|
||||
/* $NetBSD: trap.c,v 1.170 2002/07/06 23:59:21 gmcgarry Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1988 University of Utah.
|
||||
@ -44,7 +44,7 @@
|
||||
|
||||
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
|
||||
|
||||
__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.169 2002/03/11 16:39:40 uch Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.170 2002/07/06 23:59:21 gmcgarry Exp $");
|
||||
|
||||
#include "opt_cputype.h" /* which mips CPU levels do we support? */
|
||||
#include "opt_ktrace.h"
|
||||
@ -128,9 +128,9 @@ const char *trap_type[] = {
|
||||
void trap(unsigned, unsigned, unsigned, unsigned, struct trapframe *);
|
||||
void ast(unsigned);
|
||||
|
||||
vaddr_t MachEmulateBranch(struct frame *, vaddr_t, unsigned, int);
|
||||
extern void MachEmulateFP(unsigned);
|
||||
extern void MachFPInterrupt(unsigned, unsigned, unsigned, struct frame *);
|
||||
extern vaddr_t MachEmulateBranch(struct frame *, vaddr_t, unsigned, int);
|
||||
extern void MachEmulateInst(u_int32_t, u_int32_t, u_int32_t, struct frame *);
|
||||
extern void MachFPTrap(u_int32_t, u_int32_t, u_int32_t, struct frame *);
|
||||
|
||||
#define DELAYBRANCH(x) ((int)(x)<0)
|
||||
|
||||
@ -481,43 +481,29 @@ trap(status, cause, vaddr, opc, frame)
|
||||
break; /* SIGNAL */
|
||||
}
|
||||
case T_RES_INST+T_USER:
|
||||
#if defined(MIPS3_5900) && defined(SOFTFLOAT)
|
||||
MachFPInterrupt(status, cause, opc, p->p_md.md_regs);
|
||||
userret(p);
|
||||
return; /* GEN */
|
||||
#else
|
||||
sig = SIGILL;
|
||||
break; /* SIGNAL */
|
||||
#endif
|
||||
break; /* SIGNAL */
|
||||
case T_COP_UNUSABLE+T_USER:
|
||||
#if defined(NOFPU) && !defined(SOFTFLOAT)
|
||||
sig = SIGILL;
|
||||
break; /* SIGNAL */
|
||||
#endif
|
||||
if ((cause & MIPS_CR_COP_ERR) != 0x10000000) {
|
||||
sig = SIGILL; /* only FPU instructions allowed */
|
||||
break; /* SIGNAL */
|
||||
}
|
||||
#ifndef SOFTFLOAT
|
||||
{
|
||||
struct frame *f;
|
||||
#if !defined(SOFTFLOAT) && !defined(NOFPU)
|
||||
if ((cause & MIPS_CR_COP_ERR) == 0x10000000) {
|
||||
struct frame *f;
|
||||
|
||||
f = (struct frame *)p->p_md.md_regs;
|
||||
savefpregs(fpcurproc); /* yield FPA */
|
||||
loadfpregs(p); /* load FPA */
|
||||
fpcurproc = p;
|
||||
p->p_md.md_flags |= MDP_FPUSED;
|
||||
f->f_regs[SR] |= MIPS_SR_COP_1_BIT;
|
||||
}
|
||||
#else
|
||||
MachFPInterrupt(status, cause, opc, p->p_md.md_regs);
|
||||
f = (struct frame *)p->p_md.md_regs;
|
||||
savefpregs(fpcurproc); /* yield FPA */
|
||||
loadfpregs(p); /* load FPA */
|
||||
fpcurproc = p;
|
||||
p->p_md.md_flags |= MDP_FPUSED;
|
||||
f->f_regs[SR] |= MIPS_SR_COP_1_BIT;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
MachEmulateInst(status, cause, opc, p->p_md.md_regs);
|
||||
}
|
||||
userret(p);
|
||||
return; /* GEN */
|
||||
case T_FPE+T_USER:
|
||||
#if !defined(NOFPU) || defined(SOFTFLOAT)
|
||||
MachFPInterrupt(status, cause, opc, p->p_md.md_regs);
|
||||
#if defined(SOFTFLOAT)
|
||||
MachEmulateInst(status, cause, opc, p->p_md.md_regs);
|
||||
#elif !defined(NOFPU)
|
||||
MachFPTrap(status, cause, opc, p->p_md.md_regs);
|
||||
#endif
|
||||
userret(p);
|
||||
return; /* GEN */
|
||||
@ -595,124 +581,6 @@ ast(pc)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Analyse 'next' PC address taking account of branch/jump instructions
|
||||
*/
|
||||
vaddr_t
|
||||
MachEmulateBranch(f, instpc, fpuCSR, allowNonBranch)
|
||||
struct frame *f;
|
||||
vaddr_t instpc;
|
||||
unsigned fpuCSR;
|
||||
int allowNonBranch;
|
||||
{
|
||||
#define BRANCHTARGET(p) (4 + (p) + ((short)((InstFmt *)(p))->IType.imm << 2))
|
||||
InstFmt inst;
|
||||
vaddr_t nextpc;
|
||||
|
||||
if (instpc < MIPS_KSEG0_START)
|
||||
inst.word = fuiword((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) |
|
||||
((unsigned)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
|
||||
}
|
||||
|
||||
/* XXX need to rewrite acient comment XXX
|
||||
* This routine is called by procxmt() to single step one instruction.
|
||||
|
Loading…
Reference in New Issue
Block a user