#include <inttypes.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <fenv.h>
#include "sparc.h"
static int fpexec (uint32 op3, uint32 rd, uint32 rs1, uint32 rs2,
struct pstate *sregs);
static uint32
sub_cc (psr, operand1, operand2, result)
uint32 psr;
int32 operand1;
int32 operand2;
int32 result;
{
psr = ((psr & ~PSR_N) | ((result >> 8) & PSR_N));
if (result)
psr &= ~PSR_Z;
else
psr |= PSR_Z;
psr = (psr & ~PSR_V) | ((((operand1 & ~operand2 & ~result) |
(~operand1 & operand2 & result)) >> 10) & PSR_V);
psr = (psr & ~PSR_C) | ((((~operand1 & operand2) |
((~operand1 | operand2) & result)) >> 11) &
PSR_C);
return psr;
}
uint32
add_cc (psr, operand1, operand2, result)
uint32 psr;
int32 operand1;
int32 operand2;
int32 result;
{
psr = ((psr & ~PSR_N) | ((result >> 8) & PSR_N));
if (result)
psr &= ~PSR_Z;
else
psr |= PSR_Z;
psr = (psr & ~PSR_V) | ((((operand1 & operand2 & ~result) |
(~operand1 & ~operand2 & result)) >> 10) & PSR_V);
psr = (psr & ~PSR_C) | ((((operand1 & operand2) |
((operand1 | operand2) & ~result)) >> 11) &
PSR_C);
return psr;
}
static void
log_cc (result, sregs)
int32 result;
struct pstate *sregs;
{
sregs->psr &= ~(PSR_CC); /* Zero CC bits */
sregs->psr = (sregs->psr | ((result >> 8) & PSR_N));
if (result == 0)
sregs->psr |= PSR_Z;
}
static int
chk_asi (sregs, asi, op3)
struct pstate *sregs;
uint32 *asi, op3;
{
if (!(sregs->psr & PSR_S))
{
sregs->trap = TRAP_PRIVI;
return 0;
}
else if (sregs->inst & INST_I)
{
sregs->trap = TRAP_UNIMP;
return 0;
}
else
*asi = (sregs->inst >> 5) & 0x0ff;
return 1;
}
/* Decode watchpoint address mask from opcode. Not correct for LDST,
SWAP and STFSR but watchpoints will work anyway. */
static unsigned char
wpmask (uint32 op3)
{
switch (op3 & 3)
{
case 0:
return (3); /* word */
case 1:
return (0); /* byte */
case 2:
return (1); /* half-word */
default:
return (7); /* double word */
}
}
static int
extract_byte_signed (uint32 data, uint32 address)
{
uint32 tmp = ((data >> ((3 - (address & 3)) * 8)) & 0xff);
if (tmp & 0x80)
tmp |= 0xffffff00;
return tmp;
}
int
extract_short (uint32 data, uint32 address)
{
return ((data >> ((2 - (address & 2)) * 8)) & 0xffff);
}
int
extract_short_signed (uint32 data, uint32 address)
{
uint32 tmp = ((data >> ((2 - (address & 2)) * 8)) & 0xffff);
if (tmp & 0x8000)
tmp |= 0xffff0000;
return tmp;
}
int
extract_byte (uint32 data, uint32 address)
{
return ((data >> ((3 - (address & 3)) * 8)) & 0xff);
}
/* How to map SPARC FSR onto the host */
static void
sparc_set_fsr (fsr)
uint32 fsr;
{
int fround;
fsr >>= 30;
switch (fsr)
{
case 0:
fround = FE_TONEAREST;
break;
case 1:
fround = FE_TOWARDZERO;
break;
case 2:
fround = FE_UPWARD;
break;
case 3:
fround = FE_DOWNWARD;
break;
}
fesetround (fround);
}
static int
sparc_dispatch_instruction (sregs)
struct pstate *sregs;
{
uint32 cwp, op, op2, op3, asi, rd, cond, rs1, rs2;
uint32 ldep, icc, *rdd, data;
int32 operand1, operand2, result, eicc, new_cwp;
int32 pc, npc, address, ws, mexc, fcc, annul;
uint32 ddata[2];
sregs->ninst++;
cwp = ((sregs->psr & PSR_CWP) << 4);
op = sregs->inst >> 30;
pc = sregs->npc;
npc = sregs->npc + 4;
op3 = rd = rs1 = operand2 = eicc = 0;
rdd = 0;
annul = 0;
if (op & 2)
{
op3 = (sregs->inst >> 19) & 0x3f;
rs1 = (sregs->inst >> 14) & 0x1f;
rd = (sregs->inst >> 25) & 0x1f;
#ifdef LOAD_DEL
/* Check if load dependecy is possible */
if (sregs->simtime <= sregs->ildtime)
ldep = (((op3 & 0x38) != 0x28) && ((op3 & 0x3e) != 0x34)
&& (sregs->ildreg != 0));
else
ldep = 0;
if (sregs->inst & INST_I)
{
if (ldep && (sregs->ildreg == rs1))
sregs->hold++;
operand2 = sregs->inst;
operand2 = ((operand2 << 19) >> 19); /* sign extend */
}
else
{
rs2 = sregs->inst & INST_RS2;
if (rs2 > 7)
operand2 = sregs->r[(cwp + rs2) & 0x7f];
else
operand2 = sregs->g[rs2];
if (ldep && ((sregs->ildreg == rs1) || (sregs->ildreg == rs2)))
sregs->hold++;
}
#else
if (sregs->inst & INST_I)
{
operand2 = sregs->inst;
operand2 = ((operand2 << 19) >> 19); /* sign extend */
}
else
{
rs2 = sregs->inst & INST_RS2;
if (rs2 > 7)
operand2 = sregs->r[(cwp + rs2) & 0x7f];
else
operand2 = sregs->g[rs2];
}
#endif
if (rd > 7)
rdd = &(sregs->r[(cwp + rd) & 0x7f]);
else
rdd = &(sregs->g[rd]);
if (rs1 > 7)
rs1 = sregs->r[(cwp + rs1) & 0x7f];
else
rs1 = sregs->g[rs1];
}
switch (op)
{
case 0:
op2 = (sregs->inst >> 22) & 0x7;
switch (op2)
{
case SETHI:
rd = (sregs->inst >> 25) & 0x1f;
if (rd > 7)
rdd = &(sregs->r[(cwp + rd) & 0x7f]);
else
rdd = &(sregs->g[rd]);
*rdd = sregs->inst << 10;
break;
case BICC:
#ifdef STAT
sregs->nbranch++;
#endif
icc = sregs->psr >> 20;
cond = ((sregs->inst >> 25) & 0x0f);
switch (cond)
{
case BICC_BN:
eicc = 0;
break;
case BICC_BE:
eicc = ICC_Z;
break;
case BICC_BLE:
eicc = ICC_Z | (ICC_N ^ ICC_V);
break;
case BICC_BL:
eicc = (ICC_N ^ ICC_V);
break;
case BICC_BLEU:
eicc = ICC_C | ICC_Z;
break;
case BICC_BCS:
eicc = ICC_C;
break;
case BICC_NEG:
eicc = ICC_N;
break;
case BICC_BVS:
eicc = ICC_V;
break;
case BICC_BA:
eicc = 1;
if (sregs->inst & 0x20000000)
annul = 1;
break;
case BICC_BNE:
eicc = ~(ICC_Z);
break;
case BICC_BG:
eicc = ~(ICC_Z | (ICC_N ^ ICC_V));
break;
case BICC_BGE:
eicc = ~(ICC_N ^ ICC_V);
break;
case BICC_BGU:
eicc = ~(ICC_C | ICC_Z);
break;
case BICC_BCC:
eicc = ~(ICC_C);
break;
case BICC_POS:
eicc = ~(ICC_N);
break;
case BICC_BVC:
eicc = ~(ICC_V);
break;
}
if (eicc & 1)
{
operand1 = sregs->inst;
operand1 = ((operand1 << 10) >> 8); /* sign extend */
npc = sregs->pc + operand1;
if (ebase.coven)
{
if (cond == BICC_BA)
cov_jmp (sregs->pc, npc);
else
cov_bt (sregs->pc, npc);
cov_exec (pc); /* delay slot executed */
}
}
else
{
if (sregs->inst & 0x20000000)
{
if (ebase.coven)
{
cov_start (npc); /* jump over delay slot */
}
annul = 1;
}
else
{
if (ebase.coven)
cov_start (sregs->npc); /* delay slot executed */
}
if (ebase.coven)
cov_bnt (sregs->pc);
}
break;
case FPBCC:
#ifdef STAT
sregs->nbranch++;
#endif
if (!((sregs->psr & PSR_EF) && FP_PRES))
{
sregs->trap = TRAP_FPDIS;
break;
}
if (sregs->simtime < sregs->ftime)
{
sregs->ftime = sregs->simtime + sregs->hold;
}
cond = ((sregs->inst >> 25) & 0x0f);
fcc = (sregs->fsr >> 10) & 0x3;
switch (cond)
{
case FBN:
eicc = 0;
break;
case FBNE:
eicc = (fcc != FCC_E);
break;
case FBLG:
eicc = (fcc == FCC_L) || (fcc == FCC_G);
break;
case FBUL:
eicc = (fcc == FCC_L) || (fcc == FCC_U);
break;
case FBL:
eicc = (fcc == FCC_L);
break;
case FBUG:
eicc = (fcc == FCC_G) || (fcc == FCC_U);
break;
case FBG:
eicc = (fcc == FCC_G);
break;
case FBU:
eicc = (fcc == FCC_U);
break;
case FBA:
eicc = 1;
if (sregs->inst & 0x20000000)
annul = 1;
break;
case FBE:
eicc = !(fcc != FCC_E);
break;
case FBUE:
eicc = !((fcc == FCC_L) || (fcc == FCC_G));
break;
case FBGE:
eicc = !((fcc == FCC_L) || (fcc == FCC_U));
break;
case FBUGE:
eicc = !(fcc == FCC_L);
break;
case FBLE:
eicc = !((fcc == FCC_G) || (fcc == FCC_U));
break;
case FBULE:
eicc = !(fcc == FCC_G);
break;
case FBO:
eicc = !(fcc == FCC_U);
break;
}
if (eicc)
{
operand1 = sregs->inst;
operand1 = ((operand1 << 10) >> 8); /* sign extend */
npc = sregs->pc + operand1;
if (ebase.coven)
{
cov_bt (sregs->pc, npc);
cov_exec (pc); /* delay slot executed */
}
}
else
{
if (sregs->inst & 0x20000000)
{
if (ebase.coven)
{
cov_start (npc); /* jump over delay slot */
}
annul = 1;
}
else
{
if (ebase.coven)
cov_start (pc); /* delay slot executed */
}
if (ebase.coven)
cov_bnt (sregs->pc);
}
break;
default:
sregs->trap = TRAP_UNIMP;
break;
}
break;
case 1: /* CALL */
#ifdef STAT
sregs->nbranch++;
#endif
sregs->r[(cwp + 15) & 0x7f] = sregs->pc;
npc = sregs->pc + (sregs->inst << 2);
if (ebase.coven)
{
cov_jmp (sregs->pc, npc);
cov_exec (pc); /* delay slot executed */
}
break;
case 2:
if ((op3 >> 1) == 0x1a)
{
if (!((sregs->psr & PSR_EF) && FP_PRES))
{
sregs->trap = TRAP_FPDIS;
}
else
{
rs1 = (sregs->inst >> 14) & 0x1f;
rs2 = sregs->inst & 0x1f;
sregs->trap = fpexec (op3, rd, rs1, rs2, sregs);
}
}
else
{
switch (op3)
{
case TICC:
icc = sregs->psr >> 20;
cond = ((sregs->inst >> 25) & 0x0f);
switch (cond)
{
case BICC_BN:
eicc = 0;
break;
case BICC_BE:
eicc = ICC_Z;
break;
case BICC_BLE:
eicc = ICC_Z | (ICC_N ^ ICC_V);
break;
case BICC_BL:
eicc = (ICC_N ^ ICC_V);
break;
case BICC_BLEU:
eicc = ICC_C | ICC_Z;
break;
case BICC_BCS:
eicc = ICC_C;
break;
case BICC_NEG:
eicc = ICC_N;
break;
case BICC_BVS:
eicc = ICC_V;
break;
case BICC_BA:
eicc = 1;
break;
case BICC_BNE:
eicc = ~(ICC_Z);
break;
case BICC_BG:
eicc = ~(ICC_Z | (ICC_N ^ ICC_V));
break;
case BICC_BGE:
eicc = ~(ICC_N ^ ICC_V);
break;
case BICC_BGU:
eicc = ~(ICC_C | ICC_Z);
break;
case BICC_BCC:
eicc = ~(ICC_C);
break;
case BICC_POS:
eicc = ~(ICC_N);
break;
case BICC_BVC:
eicc = ~(ICC_V);
break;
}
if (eicc & 1)
{
sregs->trap = (0x80 | ((rs1 + operand2) & 0x7f));
if ((sregs->trap == 129) && (sis_gdb_break) &&
(sregs->inst == 0x91d02001))
{
sregs->trap = WPT_TRAP;
sregs->bphit = 1;
}
}
break;
case MULScc:
operand1 =
(((sregs->psr & PSR_V) ^ ((sregs->psr & PSR_N) >> 2))
<< 10) | (rs1 >> 1);
if ((sregs->y & 1) == 0)
operand2 = 0;
*rdd = operand1 + operand2;
sregs->y = (rs1 << 31) | (sregs->y >> 1);
sregs->psr = add_cc (sregs->psr, operand1, operand2, *rdd);
break;
case SMUL:
{
mul64 (rs1, operand2, &sregs->y, rdd, 1);
sregs->icnt = T_MUL;
}
break;
case SMULCC:
{
uint32 result;
mul64 (rs1, operand2, &sregs->y, &result, 1);
if (result & 0x80000000)
sregs->psr |= PSR_N;
else
sregs->psr &= ~PSR_N;
if (result == 0)
sregs->psr |= PSR_Z;
else
sregs->psr &= ~PSR_Z;
*rdd = result;
sregs->icnt = T_MUL;
}
break;
case UMUL:
{
mul64 (rs1, operand2, &sregs->y, rdd, 0);
sregs->icnt = T_MUL;
}
break;
case UMULCC:
{
uint32 result;
mul64 (rs1, operand2, &sregs->y, &result, 0);
if (result & 0x80000000)
sregs->psr |= PSR_N;
else
sregs->psr &= ~PSR_N;
if (result == 0)
sregs->psr |= PSR_Z;
else
sregs->psr &= ~PSR_Z;
*rdd = result;
sregs->icnt = T_MUL;
}
break;
case SDIV:
{
if (operand2 == 0)
{
sregs->trap = TRAP_DIV0;
break;
}
div64 (sregs->y, rs1, operand2, rdd, 1);
sregs->icnt = T_DIV;
}
break;
case SDIVCC:
{
uint32 result;
if (operand2 == 0)
{
sregs->trap = TRAP_DIV0;
break;
}
div64 (sregs->y, rs1, operand2, &result, 1);
if (result & 0x80000000)
sregs->psr |= PSR_N;
else
sregs->psr &= ~PSR_N;
if (result == 0)
sregs->psr |= PSR_Z;
else
sregs->psr &= ~PSR_Z;
/* FIXME: should set overflow flag correctly. */
sregs->psr &= ~(PSR_C | PSR_V);
*rdd = result;
sregs->icnt = T_DIV;
}
break;
case UDIV:
{
if (operand2 == 0)
{
sregs->trap = TRAP_DIV0;
break;
}
div64 (sregs->y, rs1, operand2, rdd, 0);
sregs->icnt = T_DIV;
}
break;
case UDIVCC:
{
uint32 result;
if (operand2 == 0)
{
sregs->trap = TRAP_DIV0;
break;
}
div64 (sregs->y, rs1, operand2, &result, 0);
if (result & 0x80000000)
sregs->psr |= PSR_N;
else
sregs->psr &= ~PSR_N;
if (result == 0)
sregs->psr |= PSR_Z;
else
sregs->psr &= ~PSR_Z;
/* FIXME: should set overflow flag correctly. */
sregs->psr &= ~(PSR_C | PSR_V);
*rdd = result;
sregs->icnt = T_DIV;
}
break;
case IXNOR:
*rdd = rs1 ^ ~operand2;
break;
case IXNORCC:
*rdd = rs1 ^ ~operand2;
log_cc (*rdd, sregs);
break;
case IXOR:
*rdd = rs1 ^ operand2;
break;
case IXORCC:
*rdd = rs1 ^ operand2;
log_cc (*rdd, sregs);
break;
case IOR:
*rdd = rs1 | operand2;
break;
case IORCC:
*rdd = rs1 | operand2;
log_cc (*rdd, sregs);
break;
case IORN:
*rdd = rs1 | ~operand2;
break;
case IORNCC:
*rdd = rs1 | ~operand2;
log_cc (*rdd, sregs);
break;
case IANDNCC:
*rdd = rs1 & ~operand2;
log_cc (*rdd, sregs);
break;
case IANDN:
*rdd = rs1 & ~operand2;
break;
case IAND:
*rdd = rs1 & operand2;
break;
case IANDCC:
*rdd = rs1 & operand2;
log_cc (*rdd, sregs);
break;
case SUB:
*rdd = rs1 - operand2;
break;
case SUBCC:
*rdd = rs1 - operand2;
sregs->psr = sub_cc (sregs->psr, rs1, operand2, *rdd);
break;
case SUBX:
*rdd = rs1 - operand2 - ((sregs->psr >> 20) & 1);
break;
case SUBXCC:
*rdd = rs1 - operand2 - ((sregs->psr >> 20) & 1);
sregs->psr = sub_cc (sregs->psr, rs1, operand2, *rdd);
break;
case ADD:
*rdd = rs1 + operand2;
break;
case ADDCC:
*rdd = rs1 + operand2;
sregs->psr = add_cc (sregs->psr, rs1, operand2, *rdd);
break;
case ADDX:
*rdd = rs1 + operand2 + ((sregs->psr >> 20) & 1);
break;
case ADDXCC:
*rdd = rs1 + operand2 + ((sregs->psr >> 20) & 1);
sregs->psr = add_cc (sregs->psr, rs1, operand2, *rdd);
break;
case TADDCC:
*rdd = rs1 + operand2;
sregs->psr = add_cc (sregs->psr, rs1, operand2, *rdd);
if ((rs1 | operand2) & 0x3)
sregs->psr |= PSR_V;
break;
case TSUBCC:
*rdd = rs1 - operand2;
sregs->psr = sub_cc (sregs->psr, rs1, operand2, *rdd);
if ((rs1 | operand2) & 0x3)
sregs->psr |= PSR_V;
break;
case TADDCCTV:
*rdd = rs1 + operand2;
result = add_cc (0, rs1, operand2, *rdd);
if ((rs1 | operand2) & 0x3)
result |= PSR_V;
if (result & PSR_V)
{
sregs->trap = TRAP_TAG;
}
else
{
sregs->psr = (sregs->psr & ~PSR_CC) | result;
}
break;
case TSUBCCTV:
*rdd = rs1 - operand2;
result = add_cc (0, rs1, operand2, *rdd);
if ((rs1 | operand2) & 0x3)
result |= PSR_V;
if (result & PSR_V)
{
sregs->trap = TRAP_TAG;
}
else
{
sregs->psr = (sregs->psr & ~PSR_CC) | result;
}
break;
case SLL:
*rdd = rs1 << (operand2 & 0x1f);
break;
case SRL:
*rdd = rs1 >> (operand2 & 0x1f);
break;
case SRA:
*rdd = ((int) rs1) >> (operand2 & 0x1f);
break;
case FLUSH:
if (ift)
sregs->trap = TRAP_UNIMP;
break;
case SAVE:
new_cwp = ((sregs->psr & PSR_CWP) - 1) & PSR_CWP;
if (sregs->wim & (1 << new_cwp))
{
sregs->trap = TRAP_WOFL;
break;
}
if (rd > 7)
rdd = &(sregs->r[((new_cwp << 4) + rd) & 0x7f]);
*rdd = rs1 + operand2;
sregs->psr = (sregs->psr & ~PSR_CWP) | new_cwp;
break;
case RESTORE:
new_cwp = ((sregs->psr & PSR_CWP) + 1) & PSR_CWP;
if (sregs->wim & (1 << new_cwp))
{
sregs->trap = TRAP_WUFL;
break;
}
if (rd > 7)
rdd = &(sregs->r[((new_cwp << 4) + rd) & 0x7f]);
*rdd = rs1 + operand2;
sregs->psr = (sregs->psr & ~PSR_CWP) | new_cwp;
break;
case RDPSR:
if (!(sregs->psr & PSR_S))
{
sregs->trap = TRAP_PRIVI;
break;
}
*rdd = sregs->psr;
break;
case RDY:
if (cputype != CPU_ERC32)
{
rs1 = (sregs->inst >> 14) & 0x1f;
switch (rs1)
{
case 0:
*rdd = sregs->y;
break;
case 17:
*rdd = sregs->asr17;
break;
case 22:
*rdd = (uint32) (sregs->simtime >> 32);
break;
case 23:
*rdd = (uint32) (sregs->simtime & 0xffffffff);
break;
}
}
else
*rdd = sregs->y;
break;
case RDWIM:
if (!(sregs->psr & PSR_S))
{
sregs->trap = TRAP_PRIVI;
break;
}
*rdd = sregs->wim;
break;
case RDTBR:
if (!(sregs->psr & PSR_S))
{
sregs->trap = TRAP_PRIVI;
break;
}
*rdd = sregs->tbr;
break;
case WRPSR:
if ((sregs->psr & 0x1f) > 7)
{
sregs->trap = TRAP_UNIMP;
break;
}
if (!(sregs->psr & PSR_S))
{
sregs->trap = TRAP_PRIVI;
break;
}
sregs->psr = (sregs->psr & 0xff000000) |
((rs1 ^ operand2) & 0x00f03fff);
break;
case WRWIM:
if (!(sregs->psr & PSR_S))
{
sregs->trap = TRAP_PRIVI;
break;
}
sregs->wim = (rs1 ^ operand2) & 0x0ff;
break;
case WRTBR:
if (!(sregs->psr & PSR_S))
{
sregs->trap = TRAP_PRIVI;
break;
}
sregs->tbr = (sregs->tbr & 0x00000ff0) |
((rs1 ^ operand2) & 0xfffff000);
break;
case WRY:
sregs->y = (rs1 ^ operand2);
if (cputype != CPU_ERC32)
{
if (17 == rd)
{
sregs->asr17 &= ~0x0FFFE000;
sregs->asr17 |= 0x0FFFE000 & (rs1 ^ operand2);
}
else if (19 == rd)
{
pwd_enter (sregs);
if (sync_rt)
rt_sync ();
}
}
break;
case JMPL:
#ifdef STAT
sregs->nbranch++;
#endif
sregs->icnt = T_JMPL; /* JMPL takes two cycles */
if (rs1 & 0x3)
{
sregs->trap = TRAP_UNALI;
break;
}
*rdd = sregs->pc;
npc = rs1 + operand2;
if (!npc)
sregs->trap = NULL_TRAP; // halt on null pointer
if (ebase.coven)
{
cov_jmp (sregs->pc, npc);
cov_exec (pc); /* delay slot executed */
}
break;
case RETT:
address = rs1 + operand2;
new_cwp = ((sregs->psr & PSR_CWP) + 1) & PSR_CWP;
sregs->icnt = T_RETT; /* RETT takes two cycles */
if (sregs->psr & PSR_ET)
{
sregs->trap = TRAP_UNIMP;
break;
}
if (!(sregs->psr & PSR_S))
{
sregs->trap = TRAP_PRIVI;
break;
}
if (sregs->wim & (1 << new_cwp))
{
sregs->trap = TRAP_WUFL;
break;
}
if (address & 0x3)
{
sregs->trap = TRAP_UNALI;
break;
}
if (!address)
sregs->trap = NULL_TRAP; // halt on null pointer
sregs->psr = (sregs->psr & ~PSR_CWP) | new_cwp | PSR_ET;
sregs->psr =
(sregs->psr & ~PSR_S) | ((sregs->psr & PSR_PS) << 1);
npc = address;
if (ebase.coven)
{
cov_jmp (sregs->pc, npc);
cov_exec (pc); /* delay slot executed */
}
break;
default:
sregs->trap = TRAP_UNIMP;
break;
}
}
break;
case 3: /* Load/store instructions */
address = rs1 + operand2;
if (op3 & 4)
{
sregs->icnt = T_ST; /* Set store instruction count */
/* skip store if we resume after a write watchpoint */
if (sis_gdb_break && ebase.wphit)
{
ebase.wphit = 0;
break;
}
if (ebase.wpwnum)
{
if ((ebase.wphit = check_wpw (sregs, address, wpmask (op3))))
{
sregs->trap = WPT_TRAP;
/* gdb seems to expect that the write goes trough when the
* watchpoint is hit, but PC stays on the store instruction */
if (!sis_gdb_break)
break;
}
}
#if defined(STAT) || defined(ENABLE_L1CACHE)
sregs->nstore++;
#endif
}
else
{
sregs->icnt = T_LD; /* Set load instruction count */
if (ebase.wprnum)
{
if ((ebase.wphit = check_wpr (sregs, address, wpmask (op3))))
{
sregs->trap = WPT_TRAP;
break;
}
}
#if defined(STAT) || defined(ENABLE_L1CACHE)
sregs->nload++;
#endif
}
/* Decode load/store instructions */
switch (op3)
{
case LDDA:
if (!chk_asi (sregs, &asi, op3))
break;
case LDD:
if (address & 0x7)
{
sregs->trap = TRAP_UNALI;
break;
}
if (rd & 1)
{
rd &= 0x1e;
if (rd > 7)
rdd = &(sregs->r[(cwp + rd) & 0x7f]);
else
rdd = &(sregs->g[rd]);
}
mexc = ms->memory_read (address, ddata, &ws);
sregs->hold += ws;
mexc |= ms->memory_read (address + 4, &ddata[1], &ws);
sregs->hold += ws;
sregs->icnt = T_LDD;
if (mexc)
{
sregs->trap = TRAP_DEXC;
}
else
{
rdd[0] = ddata[0];
rdd[1] = ddata[1];
#if defined(STAT) || defined(ENABLE_L1CACHE)
sregs->nload++; /* Double load counts twice */
#endif
}
break;
case LDA:
if (!chk_asi (sregs, &asi, op3))
break;
if (address & 0x3)
{
sregs->trap = TRAP_UNALI;
break;
}
if ((cputype != CPU_ERC32) && (asi == 2))
{
if (address == 0)
*rdd = sregs->cache_ctrl;
else
*rdd = 1 << 27;
break;
}
case LD:
if (address & 0x3)
{
sregs->trap = TRAP_UNALI;
break;
}
mexc = ms->memory_read (address, &data, &ws);
sregs->hold += ws;
if (mexc)
{
sregs->trap = TRAP_DEXC;
}
else
{
*rdd = data;
}
break;
case LDSTUBA:
if (!chk_asi (sregs, &asi, op3))
break;
/* fall through to LDSTUB */
case LDSTUB:
mexc = ms->memory_read (address & ~3, &data, &ws);
sregs->hold += ws;
sregs->icnt = T_LDST;
if (mexc)
{
sregs->trap = TRAP_DEXC;
break;
}
data = extract_byte (data, address);
*rdd = data;
data = 0x0ff;
mexc = ms->memory_write (address, &data, 0, &ws);
sregs->hold += ws;
if (mexc)
{
sregs->trap = TRAP_DEXC;
}
#if defined(STAT) || defined(ENABLE_L1CACHE)
sregs->nload++;
#endif
break;
case LDSBA:
case LDUBA:
if (!chk_asi (sregs, &asi, op3))
break;
/* fall through to LDSB */
case LDSB:
case LDUB:
mexc = ms->memory_read (address & ~3, &data, &ws);
sregs->hold += ws;
if (mexc)
{
sregs->trap = TRAP_DEXC;
break;
}
if (op3 == LDSB)
data = extract_byte_signed (data, address);
else
data = extract_byte (data, address);
*rdd = data;
break;
case LDSHA:
case LDUHA:
if (!chk_asi (sregs, &asi, op3))
break;
/* fall through to LDSB */
case LDSH:
case LDUH:
if (address & 0x1)
{
sregs->trap = TRAP_UNALI;
break;
}
mexc = ms->memory_read (address & ~3, &data, &ws);
sregs->hold += ws;
if (mexc)
{
sregs->trap = TRAP_DEXC;
break;
}
if (op3 == LDSH)
data = extract_short_signed (data, address);
else
data = extract_short (data, address);
*rdd = data;
break;
case LDF:
if (!((sregs->psr & PSR_EF) && FP_PRES))
{
sregs->trap = TRAP_FPDIS;
break;
}
if (address & 0x3)
{
sregs->trap = TRAP_UNALI;
break;
}
#ifdef HOST_LITTLE_ENDIAN
rd ^= 1;
#endif
if (sregs->simtime < sregs->ftime)
{
if ((sregs->frd == rd) || (sregs->frs1 == rd) ||
(sregs->frs2 == rd))
sregs->fhold += (sregs->ftime - sregs->simtime);
}
mexc = ms->memory_read (address, &data, &ws);
sregs->hold += ws;
sregs->flrd = rd;
sregs->ltime = sregs->simtime + sregs->icnt + FLSTHOLD +
sregs->hold + sregs->fhold;
if (mexc)
{
sregs->trap = TRAP_DEXC;
}
else
{
sregs->fsi[rd] = data;
}
break;
case LDDF:
if (!((sregs->psr & PSR_EF) && FP_PRES))
{
sregs->trap = TRAP_FPDIS;
break;
}
if (address & 0x7)
{
sregs->trap = TRAP_UNALI;
break;
}
if (sregs->simtime < sregs->ftime)
{
if (((sregs->frd >> 1) == (rd >> 1)) ||
((sregs->frs1 >> 1) == (rd >> 1)) ||
((sregs->frs2 >> 1) == (rd >> 1)))
sregs->fhold += (sregs->ftime - sregs->simtime);
}
mexc = ms->memory_read (address, ddata, &ws);
sregs->hold += ws;
mexc |= ms->memory_read (address + 4, &ddata[1], &ws);
sregs->hold += ws;
sregs->icnt = T_LDD;
if (mexc)
{
sregs->trap = TRAP_DEXC;
}
else
{
#ifdef HOST_LITTLE_ENDIAN
rd ^= 1;
#endif
sregs->fsi[rd] = ddata[0];
#if defined(STAT) || defined(ENABLE_L1CACHE)
sregs->nload++; /* Double load counts twice */
#endif
rd ^= 1;
sregs->fsi[rd] = ddata[1];
sregs->ltime = sregs->simtime + sregs->icnt + FLSTHOLD +
sregs->hold + sregs->fhold;
rd &= 0x1E;
sregs->flrd = rd;
}
break;
case LDFSR:
if (sregs->simtime < sregs->ftime)
{
sregs->fhold += (sregs->ftime - sregs->simtime);
}
if (!((sregs->psr & PSR_EF) && FP_PRES))
{
sregs->trap = TRAP_FPDIS;
break;
}
if (address & 0x3)
{
sregs->trap = TRAP_UNALI;
break;
}
mexc = ms->memory_read (address, &data, &ws);
sregs->hold += ws;
if (mexc)
{
sregs->trap = TRAP_DEXC;
}
else
{
sregs->fsr = (sregs->fsr & 0x7FF000) | (data & ~0x7FF000);
sparc_set_fsr (sregs->fsr);
}
break;
case STFSR:
if (!((sregs->psr & PSR_EF) && FP_PRES))
{
sregs->trap = TRAP_FPDIS;
break;
}
if (address & 0x3)
{
sregs->trap = TRAP_UNALI;
break;
}
if (sregs->simtime < sregs->ftime)
{
sregs->fhold += (sregs->ftime - sregs->simtime);
}
mexc = ms->memory_write (address, &sregs->fsr, 2, &ws);
sregs->hold += ws;
if (mexc)
{
sregs->trap = TRAP_DEXC;
}
break;
case STA:
if (!chk_asi (sregs, &asi, op3))
break;
if (address & 0x3)
{
sregs->trap = TRAP_UNALI;
break;
}
if ((cputype != CPU_ERC32) && (asi == 2))
{
sregs->cache_ctrl = *rdd;
break;
}
case ST:
if (address & 0x3)
{
sregs->trap = TRAP_UNALI;
break;
}
mexc = ms->memory_write (address, rdd, 2, &ws);
sregs->hold += ws;
if (mexc)
{
sregs->trap = TRAP_DEXC;
}
break;
case STBA:
if (!chk_asi (sregs, &asi, op3))
break;
/* fall through to STB */
case STB:
mexc = ms->memory_write (address, rdd, 0, &ws);
sregs->hold += ws;
if (mexc)
{
sregs->trap = TRAP_DEXC;
}
break;
case STDA:
if (!chk_asi (sregs, &asi, op3))
break;
case STD:
if (address & 0x7)
{
sregs->trap = TRAP_UNALI;
break;
}
if (rd & 1)
{
rd &= 0x1e;
if (rd > 7)
rdd = &(sregs->r[(cwp + rd) & 0x7f]);
else
rdd = &(sregs->g[rd]);
}
mexc = ms->memory_write (address, rdd, 3, &ws);
sregs->hold += ws;
sregs->icnt = T_STD;
#if defined(STAT) || defined(ENABLE_L1CACHE)
sregs->nstore++; /* Double store counts twice */
#endif
if (mexc)
{
sregs->trap = TRAP_DEXC;
break;
}
break;
case STDFQ:
if ((sregs->psr & 0x1f) > 7)
{
sregs->trap = TRAP_UNIMP;
break;
}
if (!((sregs->psr & PSR_EF) && FP_PRES))
{
sregs->trap = TRAP_FPDIS;
break;
}
if (address & 0x7)
{
sregs->trap = TRAP_UNALI;
break;
}
if (!(sregs->fsr & FSR_QNE))
{
sregs->fsr = (sregs->fsr & ~FSR_TT) | FP_SEQ_ERR;
break;
}
rdd = &(sregs->fpq[0]);
mexc = ms->memory_write (address, rdd, 3, &ws);
sregs->hold += ws;
sregs->icnt = T_STD;
#if defined(STAT) || defined(ENABLE_L1CACHE)
sregs->nstore++; /* Double store counts twice */
#endif
if (mexc)
{
sregs->trap = TRAP_DEXC;
break;
}
else
{
sregs->fsr &= ~FSR_QNE;
sregs->fpstate = FP_EXE_MODE;
}
break;
case STHA:
if (!chk_asi (sregs, &asi, op3))
break;
case STH:
if (address & 0x1)
{
sregs->trap = TRAP_UNALI;
break;
}
mexc = ms->memory_write (address, rdd, 1, &ws);
sregs->hold += ws;
if (mexc)
{
sregs->trap = TRAP_DEXC;
}
break;
case STF:
if (!((sregs->psr & PSR_EF) && FP_PRES))
{
sregs->trap = TRAP_FPDIS;
break;
}
if (address & 0x3)
{
sregs->trap = TRAP_UNALI;
break;
}
if (sregs->simtime < sregs->ftime)
{
if (sregs->frd == rd)
sregs->fhold += (sregs->ftime - sregs->simtime);
}
#ifdef HOST_LITTLE_ENDIAN
rd ^= 1;
#endif
mexc =
ms->memory_write (address, (uint32 *) & sregs->fsi[rd], 2, &ws);
sregs->hold += ws;
if (mexc)
{
sregs->trap = TRAP_DEXC;
}
break;
case STDF:
if (!((sregs->psr & PSR_EF) && FP_PRES))
{
sregs->trap = TRAP_FPDIS;
break;
}
if (address & 0x7)
{
sregs->trap = TRAP_UNALI;
break;
}
rd &= 0x1E;
if (sregs->simtime < sregs->ftime)
{
if ((sregs->frd == rd) || (sregs->frd + 1 == rd))
sregs->fhold += (sregs->ftime - sregs->simtime);
}
#ifdef HOST_LITTLE_ENDIAN
ddata[0] = sregs->fsi[rd ^ 1];
ddata[1] = sregs->fsi[rd];
#else
ddata[0] = sregs->fsi[rd];
ddata[1] = sregs->fsi[rd ^ 1];
#endif
mexc = ms->memory_write (address, ddata, 3, &ws);
sregs->hold += ws;
sregs->icnt = T_STD;
#if defined(STAT) || defined(ENABLE_L1CACHE)
sregs->nstore++; /* Double store counts twice */
#endif
if (mexc)
{
sregs->trap = TRAP_DEXC;
}
break;
case SWAPA:
if (!chk_asi (sregs, &asi, op3))
break;
case SWAP:
if (address & 0x3)
{
sregs->trap = TRAP_UNALI;
break;
}
mexc = ms->memory_read (address, &data, &ws);
sregs->hold += ws;
if (mexc)
{
sregs->trap = TRAP_DEXC;
break;
}
mexc = ms->memory_write (address, rdd, 2, &ws);
sregs->hold += ws;
sregs->icnt = T_LDST;
if (mexc)
{
sregs->trap = TRAP_DEXC;
break;
}
else
*rdd = data;
#if defined(STAT) || defined(ENABLE_L1CACHE)
sregs->nload++;
#endif
break;
case CASA:
asi = (sregs->inst >> 5) & 0x0ff;
address = rs1;
if (!((asi == 10) || (asi == 11)))
if (!chk_asi (sregs, &asi, op3))
break;
if (address & 0x3)
{
sregs->trap = TRAP_UNALI;
break;
}
mexc = ms->memory_read (address, &data, &ws);
sregs->hold += ws;
if (mexc)
{
sregs->trap = TRAP_DEXC;
break;
}
if (data == operand2)
{
mexc = ms->memory_write (address, rdd, 2, &ws);
if (mexc)
{
sregs->trap = TRAP_DEXC;
break;
}
else
*rdd = data;
}
else
*rdd = data;
#if defined(STAT) || defined(ENABLE_L1CACHE)
sregs->nload++;
#endif
break;
default:
sregs->trap = TRAP_UNIMP;
break;
}
#ifdef LOAD_DEL
if (!(op3 & 4))
{
sregs->ildtime = sregs->simtime + sregs->hold + sregs->icnt;
sregs->ildreg = rd;
if ((op3 | 0x10) == 0x13)
sregs->ildreg |= 1; /* Double load, odd register loaded
* last */
}
#endif
#ifdef ENABLE_L1CACHE
if (ncpu > 1)
{
l1data_update (address, sregs->cpu);
if (op3 & 4)
{
l1data_snoop (address, sregs->cpu);
}
}
#endif
break;
default:
sregs->trap = TRAP_UNIMP;
break;
}
sregs->g[0] = 0;
if (!sregs->trap)
{
sregs->pc = pc;
sregs->npc = npc;
if (annul)
{
sregs->pc = sregs->npc;
sregs->npc = sregs->npc + 4;
sregs->icnt += 1;
}
}
return 0;
}
#define FABSs 0x09
#define FADDs 0x41
#define FADDd 0x42
#define FCMPs 0x51
#define FCMPd 0x52
#define FCMPEs 0x55
#define FCMPEd 0x56
#define FDIVs 0x4D
#define FDIVd 0x4E
#define FMOVs 0x01
#define FMULs 0x49
#define FMULd 0x4A
#define FsMULd 0x69
#define FNEGs 0x05
#define FSQRTs 0x29
#define FSQRTd 0x2A
#define FSUBs 0x45
#define FSUBd 0x46
#define FdTOi 0xD2
#define FdTOs 0xC6
#define FiTOs 0xC4
#define FiTOd 0xC8
#define FsTOi 0xD1
#define FsTOd 0xC9
/* This routine should return the accrued exceptions */
static int
sparc_get_accex ()
{
int fexc, accx;
fexc = fetestexcept (FE_ALL_EXCEPT);
accx = 0;
if (fexc & FE_INEXACT)
accx |= 1;
if (fexc & FE_DIVBYZERO)
accx |= 2;
if (fexc & FE_UNDERFLOW)
accx |= 4;
if (fexc & FE_OVERFLOW)
accx |= 8;
if (fexc & FE_INVALID)
accx |= 0x10;
return accx;
}
static int
fpexec (op3, rd, rs1, rs2, sregs)
uint32 op3, rd, rs1, rs2;
struct pstate *sregs;
{
uint32 opf, tem, accex;
int32 fcc;
uint32 ldadj;
if (sregs->fpstate == FP_EXC_MODE)
{
sregs->fsr = (sregs->fsr & ~FSR_TT) | FP_SEQ_ERR;
sregs->fpstate = FP_EXC_PE;
return 0;
}
if (sregs->fpstate == FP_EXC_PE)
{
sregs->fpstate = FP_EXC_MODE;
return TRAP_FPEXC;
}
opf = (sregs->inst >> 5) & 0x1ff;
/* Store float registers in host order and swap reg address */
#ifdef HOST_LITTLE_ENDIAN
rs1 ^= 1;
rs2 ^= 1;
rd ^= 1;
#endif
/*
* Check if we already have an FPop in the pipe. If so, halt until it is
* finished by incrementing fhold with the remaining execution time
*/
if (sregs->simtime < sregs->ftime)
{
sregs->fhold = (sregs->ftime - sregs->simtime);
}
else
{
sregs->fhold = 0;
/* Check load dependencies. */
if (sregs->simtime < sregs->ltime)
{
/* Don't check rs1 if single operand instructions */
if (((opf >> 6) == 0) || ((opf >> 6) == 3))
rs1 = 32;
/* Adjust for double floats */
ldadj = opf & 1;
if (!
(((sregs->flrd - rs1) >> ldadj)
&& ((sregs->flrd - rs2) >> ldadj)))
sregs->fhold++;
}
}
sregs->finst++;
sregs->frs1 = rs1; /* Store src and dst for dependecy check */
sregs->frs2 = rs2;
sregs->frd = rd;
sregs->ftime = sregs->simtime + sregs->hold + sregs->fhold;
clear_accex ();
switch (opf)
{
case FABSs:
sregs->fs[rd] = fabs (sregs->fs[rs2]);
sregs->ftime += T_FABSs;
sregs->frs1 = 32; /* rs1 ignored */
break;
case FADDs:
sregs->fs[rd] = sregs->fs[rs1] + sregs->fs[rs2];
sregs->ftime += T_FADDs;
break;
case FADDd:
sregs->fd[rd >> 1] = sregs->fd[rs1 >> 1] + sregs->fd[rs2 >> 1];
sregs->ftime += T_FADDd;
break;
case FCMPs:
case FCMPEs:
if (sregs->fs[rs1] == sregs->fs[rs2])
fcc = 3;
else if (sregs->fs[rs1] < sregs->fs[rs2])
fcc = 2;
else if (sregs->fs[rs1] > sregs->fs[rs2])
fcc = 1;
else
fcc = 0;
sregs->fsr |= 0x0C00;
sregs->fsr &= ~(fcc << 10);
sregs->ftime += T_FCMPs;
sregs->frd = 32; /* rd ignored */
if ((fcc == 0) && (opf == FCMPEs))
{
sregs->fpstate = FP_EXC_PE;
sregs->fsr = (sregs->fsr & ~0x1C000) | (1 << 14);
}
break;
case FCMPd:
case FCMPEd:
if (sregs->fd[rs1 >> 1] == sregs->fd[rs2 >> 1])
fcc = 3;
else if (sregs->fd[rs1 >> 1] < sregs->fd[rs2 >> 1])
fcc = 2;
else if (sregs->fd[rs1 >> 1] > sregs->fd[rs2 >> 1])
fcc = 1;
else
fcc = 0;
sregs->fsr |= 0x0C00;
sregs->fsr &= ~(fcc << 10);
sregs->ftime += T_FCMPd;
sregs->frd = 32; /* rd ignored */
if ((fcc == 0) && (opf == FCMPEd))
{
sregs->fpstate = FP_EXC_PE;
sregs->fsr = (sregs->fsr & ~FSR_TT) | FP_IEEE;
}
break;
case FDIVs:
sregs->fs[rd] = sregs->fs[rs1] / sregs->fs[rs2];
sregs->ftime += T_FDIVs;
break;
case FDIVd:
sregs->fd[rd >> 1] = sregs->fd[rs1 >> 1] / sregs->fd[rs2 >> 1];
sregs->ftime += T_FDIVd;
break;
case FMOVs:
sregs->fsi[rd] = sregs->fsi[rs2];
sregs->ftime += T_FMOVs;
sregs->frs1 = 32; /* rs1 ignored */
break;
case FMULs:
sregs->fs[rd] = sregs->fs[rs1] * sregs->fs[rs2];
sregs->ftime += T_FMULs;
break;
case FsMULd:
if (cputype != CPU_ERC32)
{ /* FSMULD only supported for LEON3 */
sregs->fd[rd >> 1] =
(double) sregs->fs[rs1] * (double) sregs->fs[rs2];
sregs->ftime += T_FMULd;
}
else
{
sregs->fsr = (sregs->fsr & ~FSR_TT) | FP_UNIMP;
sregs->fpstate = FP_EXC_PE;
}
break;
case FMULd:
sregs->fd[rd >> 1] = sregs->fd[rs1 >> 1] * sregs->fd[rs2 >> 1];
sregs->ftime += T_FMULd;
break;
case FNEGs:
sregs->fs[rd] = -sregs->fs[rs2];
sregs->ftime += T_FNEGs;
sregs->frs1 = 32; /* rs1 ignored */
break;
case FSQRTs:
if (sregs->fs[rs2] < 0.0)
{
sregs->fpstate = FP_EXC_PE;
sregs->fsr = (sregs->fsr & ~FSR_TT) | FP_IEEE;
sregs->fsr = (sregs->fsr & 0x1f) | 0x10;
break;
}
sregs->fs[rd] = sqrtf (sregs->fs[rs2]);
sregs->ftime += T_FSQRTs;
sregs->frs1 = 32; /* rs1 ignored */
break;
case FSQRTd:
if (sregs->fd[rs2 >> 1] < 0.0)
{
sregs->fpstate = FP_EXC_PE;
sregs->fsr = (sregs->fsr & ~FSR_TT) | FP_IEEE;
sregs->fsr = (sregs->fsr & 0x1f) | 0x10;
break;
}
sregs->fd[rd >> 1] = sqrt (sregs->fd[rs2 >> 1]);
sregs->ftime += T_FSQRTd;
sregs->frs1 = 32; /* rs1 ignored */
break;
case FSUBs:
sregs->fs[rd] = sregs->fs[rs1] - sregs->fs[rs2];
sregs->ftime += T_FSUBs;
break;
case FSUBd:
sregs->fd[rd >> 1] = sregs->fd[rs1 >> 1] - sregs->fd[rs2 >> 1];
sregs->ftime += T_FSUBd;
break;
case FdTOi:
sregs->fsi[rd] = (int) sregs->fd[rs2 >> 1];
sregs->ftime += T_FdTOi;
sregs->frs1 = 32; /* rs1 ignored */
break;
case FdTOs:
sregs->fs[rd] = (float32) sregs->fd[rs2 >> 1];
sregs->ftime += T_FdTOs;
sregs->frs1 = 32; /* rs1 ignored */
break;
case FiTOs:
sregs->fs[rd] = (float32) sregs->fsi[rs2];
sregs->ftime += T_FiTOs;
sregs->frs1 = 32; /* rs1 ignored */
break;
case FiTOd:
sregs->fd[rd >> 1] = (float64) sregs->fsi[rs2];
sregs->ftime += T_FiTOd;
sregs->frs1 = 32; /* rs1 ignored */
break;
case FsTOi:
sregs->fsi[rd] = (int) sregs->fs[rs2];
sregs->ftime += T_FsTOi;
sregs->frs1 = 32; /* rs1 ignored */
break;
case FsTOd:
sregs->fd[rd >> 1] = sregs->fs[rs2];
sregs->ftime += T_FsTOd;
sregs->frs1 = 32; /* rs1 ignored */
break;
default:
sregs->fsr = (sregs->fsr & ~FSR_TT) | FP_UNIMP;
sregs->fpstate = FP_EXC_PE;
}
#ifdef ERRINJ
if (errftt)
{
sregs->fsr = (sregs->fsr & ~FSR_TT) | (errftt << 14);
sregs->fpstate = FP_EXC_PE;
if (sis_verbose)
printf ("Inserted fpu error %X\n", errftt);
errftt = 0;
}
#endif
accex = sparc_get_accex ();
if (sregs->fpstate == FP_EXC_PE)
{
sregs->fpq[0] = sregs->pc;
sregs->fpq[1] = sregs->inst;
sregs->fsr |= FSR_QNE;
}
else
{
tem = (sregs->fsr >> 23) & 0x1f;
if (tem & accex)
{
sregs->fpstate = FP_EXC_PE;
sregs->fsr = (sregs->fsr & ~FSR_TT) | FP_IEEE;
sregs->fsr = ((sregs->fsr & ~0x1f) | accex);
}
else
{
sregs->fsr = ((((sregs->fsr >> 5) | accex) << 5) | accex);
}
if (sregs->fpstate == FP_EXC_PE)
{
sregs->fpq[0] = sregs->pc;
sregs->fpq[1] = sregs->inst;
sregs->fsr |= FSR_QNE;
}
}
clear_accex ();
return 0;
}
static int
sparc_execute_trap (sregs)
struct pstate *sregs;
{
int32 cwp;
if (sregs->trap >= 256)
{
switch (sregs->trap)
{
case 256:
sregs->pc = 0;
sregs->npc = 4;
sregs->trap = 0;
break;
case ERROR_TRAP:
return (ERROR_MODE);
case WPT_TRAP:
return (WPT_HIT);
case NULL_TRAP:
return (NULL_HIT);
}
}
else
{
if ((sregs->psr & PSR_ET) == 0)
return ERROR_MODE;
if ((sregs->trap > 16) && (sregs->trap < 32))
sregs->intack (sregs->trap - 16, sregs->cpu);
sregs->tbr = (sregs->tbr & 0xfffff000) | (sregs->trap << 4);
sregs->trap = 0;
sregs->psr &= ~PSR_ET;
sregs->psr |= ((sregs->psr & PSR_S) >> 1);
sregs->psr =
(((sregs->psr & PSR_CWP) - 1) & 0x7) | (sregs->psr & ~PSR_CWP);
cwp = ((sregs->psr & PSR_CWP) << 4);
sregs->r[(cwp + 17) & 0x7f] = sregs->pc;
sregs->r[(cwp + 18) & 0x7f] = sregs->npc;
sregs->psr |= PSR_S;
if (ebase.coven)
cov_jmp (sregs->pc, sregs->tbr);
sregs->pc = sregs->tbr;
sregs->npc = sregs->tbr + 4;
if (0 != (1 & (sregs->asr17 >> 13)))
{
/* single vector trapping! */
sregs->pc = sregs->tbr & 0xfffff000;
sregs->npc = sregs->pc + 4;
}
/* Increase simulator time and add some jitter */
sregs->icnt = TRAP_C + (sregs->ninst ^ sregs->simtime) & 0x7;
}
return 0;
}
static int
sparc_check_interrupts (sregs)
struct pstate *sregs;
{
if ((ext_irl[sregs->cpu]) && (sregs->psr & PSR_ET) &&
((ext_irl[sregs->cpu] == 15)
|| (ext_irl[sregs->cpu] > (int) ((sregs->psr & PSR_PIL) >> 8))))
{
if (sregs->pwd_mode)
{
sregs->pwdtime += sregs->simtime - sregs->pwdstart;
sregs->pwd_mode = 0;
}
if (sregs->trap == 0)
{
return ext_irl[sregs->cpu];
}
}
return 0;
}
static void
sparc_disp_regs (struct pstate *sregs, int cwp)
{
int i;
cwp = ((cwp & 0x7) << 4);
printf ("\n\t INS LOCALS OUTS GLOBALS\n");
for (i = 0; i < 8; i++)
{
printf (" %d: %08X %08X %08X %08X\n", i,
sregs->r[(cwp + i + 24) & 0x7f],
sregs->r[(cwp + i + 16) & 0x7f], sregs->r[(cwp + i + 8) & 0x7f],
sregs->g[i]);
}
}
static void
sparc_display_registers (struct pstate *sregs)
{
sparc_disp_regs (sregs, sregs->psr);
}
static void
sparc_display_ctrl (struct pstate *sregs)
{
uint32 i;
printf ("\n psr: %08X wim: %08X tbr: %08X y: %08X\n",
sregs->psr, sregs->wim, sregs->tbr, sregs->y);
ms->sis_memory_read (sregs->pc, (char *) &i, 4);
printf ("\n pc: %08X = %08X ", sregs->pc, i);
print_insn_sis (sregs->pc);
ms->sis_memory_read (sregs->npc, (char *) &i, 4);
printf ("\n npc: %08X = %08X ", sregs->npc, i);
print_insn_sis (sregs->npc);
if (sregs->err_mode)
printf ("\n IU in error mode");
else if (sregs->pwd_mode)
printf ("\n IU in power-down mode");
printf ("\n\n");
}
static void
sparc_display_special (struct pstate *sregs)
{
printf ("\n cache ctrl : %08X\n asr17 : %08X",
sregs->cache_ctrl, sregs->asr17);
printf ("\n asr22 : %08X\n asr23 : %08X\n\n",
(uint32) (sregs->simtime >> 32),
(uint32) sregs->simtime & 0xffffffff);
}
static void
sparc_set_regi (sregs, reg, rval)
struct pstate *sregs;
int32 reg;
uint32 rval;
{
uint32 cwp;
cwp = ((sregs->psr & 0x7) << 4);
if ((reg > 0) && (reg < 8))
{
sregs->g[reg] = rval;
}
else if ((reg >= 8) && (reg < 32))
{
sregs->r[(cwp + reg) & 0x7f] = rval;
}
else if ((reg >= 32) && (reg < 64))
{
#ifdef HOST_LITTLE_ENDIAN
reg ^= 1;
#endif
sregs->fsi[reg - 32] = rval;
}
else
{
switch (reg)
{
case 64:
sregs->y = rval;
break;
case 65:
sregs->psr = rval;
break;
case 66:
sregs->wim = rval;
break;
case 67:
sregs->tbr = rval;
break;
case 68:
sregs->pc = rval;
last_load_addr = rval;
break;
case 69:
sregs->npc = rval;
break;
case 70:
sregs->fsr = rval;
sparc_set_fsr (rval);
break;
default:
break;
}
}
}
static void
sparc_get_regi (struct pstate *sregs, int32 reg, char *buf, int length)
{
uint32 cwp;
uint32 rval = 0;
cwp = ((sregs->psr & 0x7) << 4);
if ((reg >= 0) && (reg < 8))
{
rval = sregs->g[reg];
}
else if ((reg >= 8) && (reg < 32))
{
rval = sregs->r[(cwp + reg) & 0x7f];
}
else if ((reg >= 32) && (reg < 64))
{
#ifdef HOST_LITTLE_ENDIAN
reg ^= 1;
#endif
rval = sregs->fsi[reg - 32];
}
else
{
switch (reg)
{
case 64:
rval = sregs->y;
break;
case 65:
rval = sregs->psr;
break;
case 66:
rval = sregs->wim;
break;
case 67:
rval = sregs->tbr;
break;
case 68:
rval = sregs->pc;
break;
case 69:
rval = sregs->npc;
break;
case 70:
rval = sregs->fsr;
break;
default:
break;
}
}
buf[0] = (rval >> 24) & 0x0ff;
buf[1] = (rval >> 16) & 0x0ff;
buf[2] = (rval >> 8) & 0x0ff;
buf[3] = rval & 0x0ff;
}
void
sparc_set_rega (struct pstate *sregs, char *reg, uint32 rval)
{
uint32 cwp;
int32 err = 0;
cwp = ((sregs->psr & 0x7) << 4);
if (strcmp (reg, "psr") == 0)
sregs->psr = (rval = (rval & 0x00f03fff));
else if (strcmp (reg, "tbr") == 0)
sregs->tbr = (rval = (rval & 0xfffffff0));
else if (strcmp (reg, "wim") == 0)
sregs->wim = (rval = (rval & 0x0ff));
else if (strcmp (reg, "y") == 0)
sregs->y = rval;
else if (strcmp (reg, "pc") == 0)
sregs->pc = rval;
else if (strcmp (reg, "npc") == 0)
sregs->npc = rval;
else if (strcmp (reg, "fsr") == 0)
{
sregs->fsr = rval;
sparc_set_fsr (rval);
}
else if (strcmp (reg, "g0") == 0)
err = 2;
else if (strcmp (reg, "g1") == 0)
sregs->g[1] = rval;
else if (strcmp (reg, "g2") == 0)
sregs->g[2] = rval;
else if (strcmp (reg, "g3") == 0)
sregs->g[3] = rval;
else if (strcmp (reg, "g4") == 0)
sregs->g[4] = rval;
else if (strcmp (reg, "g5") == 0)
sregs->g[5] = rval;
else if (strcmp (reg, "g6") == 0)
sregs->g[6] = rval;
else if (strcmp (reg, "g7") == 0)
sregs->g[7] = rval;
else if (strcmp (reg, "o0") == 0)
sregs->r[(cwp + 8) & 0x7f] = rval;
else if (strcmp (reg, "o1") == 0)
sregs->r[(cwp + 9) & 0x7f] = rval;
else if (strcmp (reg, "o2") == 0)
sregs->r[(cwp + 10) & 0x7f] = rval;
else if (strcmp (reg, "o3") == 0)
sregs->r[(cwp + 11) & 0x7f] = rval;
else if (strcmp (reg, "o4") == 0)
sregs->r[(cwp + 12) & 0x7f] = rval;
else if (strcmp (reg, "o5") == 0)
sregs->r[(cwp + 13) & 0x7f] = rval;
else if (strcmp (reg, "o6") == 0)
sregs->r[(cwp + 14) & 0x7f] = rval;
else if (strcmp (reg, "o7") == 0)
sregs->r[(cwp + 15) & 0x7f] = rval;
else if (strcmp (reg, "l0") == 0)
sregs->r[(cwp + 16) & 0x7f] = rval;
else if (strcmp (reg, "l1") == 0)
sregs->r[(cwp + 17) & 0x7f] = rval;
else if (strcmp (reg, "l2") == 0)
sregs->r[(cwp + 18) & 0x7f] = rval;
else if (strcmp (reg, "l3") == 0)
sregs->r[(cwp + 19) & 0x7f] = rval;
else if (strcmp (reg, "l4") == 0)
sregs->r[(cwp + 20) & 0x7f] = rval;
else if (strcmp (reg, "l5") == 0)
sregs->r[(cwp + 21) & 0x7f] = rval;
else if (strcmp (reg, "l6") == 0)
sregs->r[(cwp + 22) & 0x7f] = rval;
else if (strcmp (reg, "l7") == 0)
sregs->r[(cwp + 23) & 0x7f] = rval;
else if (strcmp (reg, "i0") == 0)
sregs->r[(cwp + 24) & 0x7f] = rval;
else if (strcmp (reg, "i1") == 0)
sregs->r[(cwp + 25) & 0x7f] = rval;
else if (strcmp (reg, "i2") == 0)
sregs->r[(cwp + 26) & 0x7f] = rval;
else if (strcmp (reg, "i3") == 0)
sregs->r[(cwp + 27) & 0x7f] = rval;
else if (strcmp (reg, "i4") == 0)
sregs->r[(cwp + 28) & 0x7f] = rval;
else if (strcmp (reg, "i5") == 0)
sregs->r[(cwp + 29) & 0x7f] = rval;
else if (strcmp (reg, "i6") == 0)
sregs->r[(cwp + 30) & 0x7f] = rval;
else if (strcmp (reg, "i7") == 0)
sregs->r[(cwp + 31) & 0x7f] = rval;
else
err = 1;
switch (err)
{
case 0:
printf ("%s = %d (0x%08x)\n", reg, rval, rval);
break;
case 1:
printf ("no such regiser: %s\n", reg);
break;
case 2:
printf ("cannot set g0\n");
break;
default:
break;
}
}
static void
sparc_set_register (struct pstate *sregs, char *reg, uint32 rval, uint32 addr)
{
if (reg == NULL)
sparc_set_regi (sregs, addr, rval);
else
sparc_set_rega (sregs, reg, rval);
}
static void
disp_reg (sregs, reg)
struct pstate *sregs;
char *reg;
{
if (strncmp (reg, "w", 1) == 0)
sparc_disp_regs (sregs, VAL (®[1]));
}
/* Save stack pointer in each valid register window. Used to detect if gdb
wants to read a memory location which is cached in a register.
*/
void
save_sp (struct pstate *sregs)
{
int win;
for (win = 0; win < NWIN; win++)
{
if ((sregs->wim >> win) & 1)
sregs->sp[win] = 0;
else
sregs->sp[win] = sregs->r[win * 16 + 14];
}
}
int
gdb_sp_read (uint32 mem, char *buf, int length)
{
int i, j, len;
char *data;
for (i = 0; i < NWIN; i++)
{
if ((mem >= sregs[cpu].sp[i]) && (mem < (sregs[cpu].sp[i] + 64)))
{
data =
(char *)
&sregs[cpu].r[((i + 1) * 16 +
((mem - sregs->sp[i]) >> 2)) % (NWIN * 16)];
for (j = 0; j < length; j++)
#ifdef HOST_LITTLE_ENDIAN
buf[j] = data[j ^ 3];
#else
buf[j] = data[j];
#endif
if (sis_verbose)
printf ("gdb_sp_read: 0x%08x\n", mem);
return length;
}
}
return 0;
}
static void
sparc_display_fpu (struct pstate *sregs)
{
int i, t;
printf ("\n fsr: %08X\n\n", sregs->fsr);
for (i = 0; i < 32; i++)
{
#ifdef HOST_LITTLE_ENDIAN
t = i ^ 1;
#else
t = i;
#endif
printf (" f%02d %08x %14e ", i, sregs->fsi[t], sregs->fs[t]);
if (!(i & 1))
printf ("%14e\n", sregs->fd[i >> 1]);
else
printf ("\n");
}
printf ("\n");
}
static int
sparc_gdb_get_reg (char *buf)
{
int i;
for (i = 0; i < 72; i++)
sparc_get_regi (&sregs[cpu], i, &buf[i * 4], 4);
return (72 * 4);
}
/* op decoding */
#define FMT2 0
#define CALL 1
#define FMT3 2
#define LDST 3
/* -- OP2 codes (INST[31..30]) */
#define UNIMP 0
#define FBFCC 6
#define CBCCC 7
/*-- OP3 codes (INST[24..19]) */
#define IADD 0
#define ISUB 4
#define ANDN 5
#define ORN 6
#define ANDCC 0x11
#define ORCC 0x12
#define XORCC 0x13
#define ANDNCC 0x15
#define ORNCC 0x16
#define XNORCC 0x17
#define MULSCC 0x24
#define FPOP1 0x34
#define FPOP2 0x35
#define CPOP1 0x36
#define CPOP2 0x37
#define UMAC 0x3e
#define SMAC 0x3f
#define STC 0x34
#define STDCQ 0x36
#define STDC 0x37
/* -- BICC codes */
#define BA 8
/* -- FPOP1 */
#define FITOS 0xc4
#define FITOD 0xc8
#define FSTOI 0xd1
#define FDTOI 0xd2
#define FSTOD 0xc9
#define FDTOS 0xc6
#define FMOVS 0x1
#define FNEGS 0x5
#define FABSS 0x9
#define FSQRTS 0x29
#define FSQRTD 0x2a
#define FADDS 0x41
#define FADDD 0x42
#define FSUBS 0x45
#define FSUBD 0x46
#define FMULS 0x49
#define FMULD 0x4a
#define FSMULD 0x69
#define FDIVS 0x4d
#define FDIVD 0x4e
/* -- FPOP2 */
#define FCMPS 0x51
#define FCMPD 0x52
#define FCMPES 0x55
#define FCMPED 0x56
struct insn_type
{
unsigned int op, op2, op3, opf, cond, annul;
int rs1, rs2, rd, i, simm, asi, insn;
};
static void
regdec (char *st, int r)
{
char regst[8], ch;
if (r == 0x1e)
strcat (st, "%fp");
else if (r == 0xe)
strcat (st, "%sp");
else
{
switch ((r >> 3) & 3)
{
case 0:
ch = 'g';
break;
case 1:
ch = 'o';
break;
case 2:
ch = 'l';
break;
case 3:
ch = 'i';
}
sprintf (regst, "%%%c%d", ch, r & 7);
strcat (st, regst);
}
}
static void
simm13dec (char *st, struct insn_type insn, int hex, int merge)
{
char tmp[32];
if (insn.i)
{
if (!hex)
{
if (merge)
{
if (!insn.rs1)
sprintf (tmp, "%d", insn.simm);
else
sprintf (tmp, "%+d", insn.simm);
}
else
{
if (!insn.rs1)
sprintf (tmp, "%d", insn.simm);
else
sprintf (tmp, ", %d", insn.simm);
}
}
else
{
if (merge)
{
if (insn.simm < 0)
{
insn.simm = -insn.simm;
if (!insn.rs1)
sprintf (tmp, "-0x%x", insn.simm);
else
sprintf (tmp, " - 0x%x", insn.simm);
}
else
{
if (!insn.rs1)
sprintf (tmp, "0x%x", insn.simm);
else
sprintf (tmp, " + 0x%x", insn.simm);
}
}
else
{
if (!insn.rs1)
sprintf (tmp, "0x%x", insn.simm);
else
sprintf (tmp, ", 0x%x", insn.simm);
}
}
strcat (st, tmp);
}
}
static void
fregdec (char *st, int reg)
{
char tmp[8];
sprintf (tmp, "%%f%d", reg);
strcat (st, tmp);
}
static void
cregdec (char *st, int reg)
{
char tmp[8];
sprintf (tmp, "%%c%d", reg);
strcat (st, tmp);
}
static void
freg2 (char *st, struct insn_type insn)
{
fregdec (st, insn.rs2);
strcat (st, ", ");
fregdec (st, insn.rd);
}
static void
freg3 (char *st, struct insn_type insn)
{
fregdec (st, insn.rs1);
strcat (st, ", ");
fregdec (st, insn.rs2);
strcat (st, ", ");
fregdec (st, insn.rd);
}
static void
creg3 (char *st, struct insn_type insn)
{
cregdec (st, insn.rs1);
strcat (st, ", ");
cregdec (st, insn.rs2);
strcat (st, ", ");
cregdec (st, insn.rd);
}
static void
fregc (char *st, struct insn_type insn)
{
fregdec (st, insn.rs1);
strcat (st, ", ");
fregdec (st, insn.rs2);
}
static void
regimm (char *st, struct insn_type insn, int hex, int merge)
{
if (!insn.i)
{
if (!insn.rs1)
{
if (!insn.rs2)
{
strcat (st, "0");
}
else
{
regdec (st, insn.rs2);
}
}
else
{
if (!insn.rs2)
{
regdec (st, insn.rs1);
}
else if (merge)
{
regdec (st, insn.rs1);
strcat (st, " + ");
regdec (st, insn.rs2);
}
else
{
regdec (st, insn.rs1);
strcat (st, ", ");
regdec (st, insn.rs2);
}
}
}
else
{
if (!insn.rs1)
{
simm13dec (st, insn, hex, merge);
}
else if (!insn.simm)
{
regdec (st, insn.rs1);
}
else
{
regdec (st, insn.rs1);
simm13dec (st, insn, hex, merge);
}
}
}
static void
regres (char *st, struct insn_type insn, int hex)
{
regimm (st, insn, hex, 0);
strcat (st, ", ");
regdec (st, insn.rd);
}
static char brtbl[16][4] =
{ "n", "e", "le", "l", "lue", "cs", "neg", "vs", "a", "ne", "g", "ge", "gu",
"cc", "pos", "vc"
};
static char fbrtbl[16][4] =
{ "n", "ne", "lg", "ul", "l", "ug", "g", "u", "a", "e", "ue", "ge", "uge",
"le", "ule", "o"
};
char *
branchop (int insn)
{
return brtbl[((insn >> 25) & 0x0f)];
}
char *
fbranchop (int insn)
{
return fbrtbl[((insn >> 25) & 0x0f)];
}
static void
adec (char *st, struct insn_type insn)
{
strcat (st, "[");
regimm (st, insn, 1, 1);
strcat (st, "]");
}
static void
adeca (char *st, struct insn_type insn)
{
char tmp[32];
adec (st, insn);
sprintf (tmp, " 0x%x", insn.asi);
strcat (st, tmp);
}
static void
ldparf (char *st, struct insn_type insn)
{
adec (st, insn);
strcat (st, ", ");
fregdec (st, insn.rd);
}
static void
ldpar (char *st, struct insn_type insn)
{
adec (st, insn);
strcat (st, ", ");
regdec (st, insn.rd);
}
static void
ldpara (char *st, struct insn_type insn)
{
adeca (st, insn);
strcat (st, ", ");
regdec (st, insn.rd);
}
static void
stparx (char *st, struct insn_type insn)
{
if (insn.rd)
{
regdec (st, insn.rd);
strcat (st, ", ");
}
adec (st, insn);
}
static void
stparf (char *st, struct insn_type insn)
{
fregdec (st, insn.rd);
strcat (st, ", ");
adec (st, insn);
}
static void
stparfq (char *st, struct insn_type insn)
{
strcat (st, "fq, ");
adec (st, insn);
}
static void
stparc (char *st, struct insn_type insn)
{
cregdec (st, insn.rd);
strcat (st, ", ");
adec (st, insn);
}
static void
stparcq (char *st, struct insn_type insn)
{
strcat (st, "cq, ");
adec (st, insn);
}
static void
stpar (char *st, struct insn_type insn)
{
regdec (st, insn.rd);
strcat (st, ", ");
adec (st, insn);
}
static void
stpara (char *st, struct insn_type insn)
{
regdec (st, insn.rd);
strcat (st, ", ");
adeca (st, insn);
}
static void
sparc_disas (char *st, unsigned pc, unsigned int inst)
{
struct insn_type insn;
unsigned int addr;
char tmp[32];
insn.insn = inst;
insn.op = (inst >> 30);
insn.op2 = (inst >> 22) & 7;
insn.op3 = (inst >> 19) & 0x3f;
insn.opf = (inst >> 5) & 0x1ff;
insn.cond = (inst >> 25) & 0x0f;
insn.annul = (inst >> 29) & 1;
insn.rs1 = (inst >> 14) & 0x1f;
insn.rs2 = inst & 0x1f;
insn.rd = (inst >> 25) & 0x1f;
insn.i = (inst >> 13) & 1;
insn.simm = (insn.insn << 19) >> 19;
insn.asi = (inst >> 5) & 0xff;
switch (insn.op)
{
case CALL:
addr = pc + (inst << 2);
sprintf (st, "call 0x%08x", addr);
break;
case FMT2:
switch (insn.op2)
{
case UNIMP:
sprintf (st, "unimp");
break;
case SETHI:
if (!insn.rd)
sprintf (st, "nop");
else
{
sprintf (st, "sethi %%hi(0x%x), ", (inst << 10));
regdec (st, insn.rd);
}
break;
case BICC:
case FBFCC:
insn.simm = inst << 10;
insn.simm >>= 8;
addr = pc + insn.simm;
if (insn.op2 == BICC)
{
if ((inst >> 29) & 1)
{
sprintf (st, "b%s,a 0x%08x", branchop (inst), addr);
}
else
{
sprintf (st, "b%s 0x%08x", branchop (inst), addr);
}
}
else
{
if ((inst >> 29) & 1)
{
sprintf (st, "fb%s,a 0x%08x", fbranchop (inst), addr);
}
else
{
sprintf (st, "fb%s 0x%08x", fbranchop (inst), addr);
}
}
break;
default:
sprintf (st, "unknown opcode: 0x%08x", inst);
}
break;
case FMT3:
switch (insn.op3)
{
case IAND:
strcpy (st, "and ");
regres (st, insn, 1);
break;
case IADD:
strcpy (st, "add ");
regres (st, insn, 0);
break;
case IOR:
if ((!insn.i) && (!insn.rs1) && (!insn.rs2))
{
strcpy (st, "clr ");
regdec (st, insn.rd);
}
else if (((insn.i == '1') && (!insn.simm)) || (!insn.rs1))
{
strcpy (st, "mov ");
regres (st, insn, 0);
}
else
{
strcpy (st, "or ");
regres (st, insn, 1);
}
break;
case IXOR:
strcpy (st, "xor ");
regres (st, insn, 1);
break;
case ISUB:
strcpy (st, "sub ");
regres (st, insn, 0);
break;
case ANDN:
strcpy (st, "andn ");
regres (st, insn, 1);
break;
case ORN:
strcpy (st, "orn ");
regres (st, insn, 1);
break;
case IXNOR:
if ((!insn.i) && ((insn.rs1 == insn.rd) || (!insn.rs2)))
{
strcpy (st, "not ");
regdec (st, insn.rd);
}
else
{
strcpy (st, "xnor ");
regdec (st, insn.rd);
}
break;
case ADDX:
strcpy (st, "addx ");
regres (st, insn, 0);
break;
case SUBX:
strcpy (st, "subx ");
regres (st, insn, 0);
break;
case ADDCC:
strcpy (st, "addcc ");
regres (st, insn, 0);
break;
case ANDCC:
strcpy (st, "andcc ");
regres (st, insn, 1);
break;
case ORCC:
if ((insn.rs1) && (!insn.rd) && (!insn.i))
{
strcpy (st, "tst ");
regdec (st, insn.rs2);
}
else
{
strcpy (st, "orcc ");
regres (st, insn, 1);
}
break;
case XORCC:
strcpy (st, "xorcc ");
regres (st, insn, 1);
break;
case SUBCC:
if (insn.rd)
{
strcpy (st, "subcc ");
regres (st, insn, 0);
}
else
{
strcpy (st, "cmp ");
regimm (st, insn, 0, 0);
}
break;
case ANDNCC:
strcpy (st, "andncc ");
regres (st, insn, 1);
break;
case ORNCC:
strcpy (st, "orncc ");
regres (st, insn, 1);
break;
case XNORCC:
strcpy (st, "xnorcc ");
regres (st, insn, 1);
break;
case ADDXCC:
strcpy (st, "addxcc ");
regres (st, insn, 1);
break;
case UMAC:
strcpy (st, "umac ");
regres (st, insn, 0);
break;
case SMAC:
strcpy (st, "smac ");
regres (st, insn, 0);
break;
case UMUL:
strcpy (st, "umul ");
regres (st, insn, 0);
break;
case SMUL:
strcpy (st, "smul ");
regres (st, insn, 0);
break;
case UDIV:
strcpy (st, "udiv ");
regres (st, insn, 0);
break;
case SDIV:
strcpy (st, "sdiv ");
regres (st, insn, 0);
break;
case UMULCC:
strcpy (st, "umulcc ");
regres (st, insn, 0);
break;
case SMULCC:
strcpy (st, "smulcc ");
regres (st, insn, 0);
break;
case SUBXCC:
strcpy (st, "subxcc ");
regres (st, insn, 0);
break;
case UDIVCC:
strcpy (st, "udivcc ");
regres (st, insn, 0);
break;
case SDIVCC:
strcpy (st, "sdivcc ");
regres (st, insn, 0);
break;
case TADDCC:
strcpy (st, "taddcc ");
regres (st, insn, 0);
break;
case TSUBCC:
strcpy (st, "tsubcc ");
regres (st, insn, 0);
break;
case TADDCCTV:
strcpy (st, "taddcctv ");
regres (st, insn, 0);
break;
case TSUBCCTV:
strcpy (st, "tsubcctv ");
regres (st, insn, 0);
break;
case MULSCC:
strcpy (st, "mulscc ");
regres (st, insn, 0);
break;
case SLL:
strcpy (st, "sll ");
regres (st, insn, 0);
break;
case SRL:
strcpy (st, "srl ");
regres (st, insn, 0);
break;
case SRA:
strcpy (st, "sra ");
regres (st, insn, 0);
break;
case RDY:
if (insn.rs1)
{
sprintf (st, "mov %%asr%d, ", insn.rs1);
}
else
{
strcpy (st, "mov %y, ");
}
regdec (st, insn.rd);
break;
case RDPSR:
strcpy (st, "mov %psr, ");
regdec (st, insn.rd);
break;
case RDWIM:
strcpy (st, "mov %wim, ");
regdec (st, insn.rd);
break;
case RDTBR:
strcpy (st, "mov %tbr, ");
regdec (st, insn.rd);
break;
case WRY:
if ((!insn.rs1) || (!insn.rs2))
{
if (insn.rd)
{
strcpy (st, "mov ");
regimm (st, insn, 1, 0);
sprintf (tmp, ", %%asr%d", insn.rd);
strcat (st, tmp);
}
else
{
strcpy (st, "mov ");
regimm (st, insn, 1, 0);
strcat (st, ", %y");
}
}
else
{
if (insn.rd)
{
strcpy (st, "wr ");
regimm (st, insn, 1, 0);
sprintf (tmp, ", %%asr%d", insn.rd);
strcat (st, tmp);
}
else
{
strcpy (st, "wr ");
regimm (st, insn, 1, 0);
strcat (st, ", %y");
}
}
break;
case WRPSR:
if ((!insn.rs1) || (!insn.rs2))
{
strcpy (st, "mov ");
regimm (st, insn, 1, 0);
strcat (st, ", %psr");
}
else
{
strcpy (st, "wr ");
regimm (st, insn, 1, 0);
strcat (st, ", %psr");
}
break;
case WRWIM:
if ((!insn.rs1) || (!insn.rs2))
{
strcpy (st, "mov ");
regimm (st, insn, 1, 0);
strcat (st, ", %wim");
}
else
{
strcpy (st, "wr ");
regimm (st, insn, 1, 0);
strcat (st, ", %wim");
}
break;
case WRTBR:
if ((!insn.rs1) || (!insn.rs2))
{
strcpy (st, "mov ");
regimm (st, insn, 1, 0);
strcat (st, ", %tbr");
}
else
{
strcpy (st, "wr ");
regimm (st, insn, 1, 0);
strcat (st, ", %tbr");
}
break;
case JMPL:
if (!insn.rd)
{
if ((insn.i) && (insn.simm == 8))
{
if (insn.rs1 == 31)
{
strcpy (st, "ret ");
}
else if (insn.rs1 == 15)
{
strcpy (st, "retl ");
}
else
{
strcpy (st, "jmp ");
regimm (st, insn, 1, 1);
}
}
else
{
strcpy (st, "jmp ");
regimm (st, insn, 1, 1);
}
}
else if (insn.rd == 15)
{
strcpy (st, "call ");
regimm (st, insn, 1, 1);
}
else
{
strcpy (st, "jmpl ");
regres (st, insn, 1);
}
break;
case TICC:
sprintf (st, "t%s ", branchop (inst));
regimm (st, insn, 1, 0);
break;
case FLUSH:
strcpy (st, "flush ");
regimm (st, insn, 1, 0);
break;
case RETT:
strcpy (st, "rett ");
regimm (st, insn, 0, 0);
break;
case RESTORE:
if (!insn.rd)
strcpy (st, "restore ");
else
{
strcpy (st, "restore ");
regres (st, insn, 0);
}
break;
case SAVE:
if (!insn.rd)
strcpy (st, "save ");
else
{
strcpy (st, "save ");
regres (st, insn, 0);
}
break;
case FPOP1:
switch (insn.opf)
{
case FITOS:
strcpy (st, "fitos ");
freg2 (st, insn);
break;
case FITOD:
strcpy (st, "fitod ");
freg2 (st, insn);
break;
case FSTOI:
strcpy (st, "fstoi ");
freg2 (st, insn);
break;
case FDTOI:
strcpy (st, "fdtoi ");
freg2 (st, insn);
break;
case FSTOD:
strcpy (st, "fstod ");
freg2 (st, insn);
break;
case FDTOS:
strcpy (st, "fdtos ");
freg2 (st, insn);
break;
case FMOVS:
strcpy (st, "fmovs ");
freg2 (st, insn);
break;
case FNEGS:
strcpy (st, "fnegs ");
freg2 (st, insn);
break;
case FABSS:
strcpy (st, "fabss ");
freg2 (st, insn);
break;
case FSQRTS:
strcpy (st, "fsqrts ");
freg2 (st, insn);
break;
case FSQRTD:
strcpy (st, "fsqrtd ");
freg2 (st, insn);
break;
case FADDS:
strcpy (st, "fadds ");
freg3 (st, insn);
break;
case FADDD:
strcpy (st, "faddd ");
freg3 (st, insn);
break;
case FSUBS:
strcpy (st, "fsubs ");
freg3 (st, insn);
break;
case FSUBD:
strcpy (st, "fsubd ");
freg3 (st, insn);
break;
case FMULS:
strcpy (st, "fmuls ");
freg3 (st, insn);
break;
case FMULD:
strcpy (st, "fmuld ");
freg3 (st, insn);
break;
case FSMULD:
strcpy (st, "fsmuld ");
freg3 (st, insn);
break;
case FDIVS:
strcpy (st, "fdivs ");
freg3 (st, insn);
break;
case FDIVD:
strcpy (st, "fdivd ");
freg3 (st, insn);
break;
default:
sprintf (st, "unknown fpop: %08x", insn.insn);
break;
}
break;
case FPOP2:
switch (insn.opf)
{
case FCMPS:
strcpy (st, "fcmps ");
fregc (st, insn);
break;
case FCMPD:
strcpy (st, "fcmpd ");
fregc (st, insn);
break;
case FCMPES:
strcpy (st, "fcmpes ");
fregc (st, insn);
break;
case FCMPED:
strcpy (st, "fcmped ");
fregc (st, insn);
break;
default:
sprintf (st, "unknown fpop: %08x", inst);
break;
}
break;
default:
sprintf (st, "unknown opcode: 0x%08x", inst);
}
break;
case LDST:
switch (insn.op3)
{
case ST:
if (!insn.rd)
{
strcpy (st, "clr ");
stparx (st, insn);
break;
}
else
{
strcpy (st, "st ");
stpar (st, insn);
break;
}
break;
case STB:
if (!insn.rd)
{
strcpy (st, "clrb ");
stparx (st, insn);
break;
}
else
{
strcpy (st, "stb ");
stpar (st, insn);
break;
}
break;
case STH:
if (!insn.rd)
{
strcpy (st, "clrh ");
stparx (st, insn);
break;
}
else
{
strcpy (st, "sth ");
stpar (st, insn);
break;
}
break;
case STC:
strcpy (st, "st ");
stparc (st, insn);
break;
case STDC:
strcpy (st, "std ");
stparc (st, insn);
break;
case STDCQ:
strcpy (st, "std ");
stparcq (st, insn);
break;
case STF:
strcpy (st, "st ");
stparf (st, insn);
break;
case STDF:
strcpy (st, "std ");
stparf (st, insn);
break;
case STDFQ:
strcpy (st, "std ");
stparfq (st, insn);
break;
case STFSR:
strcpy (st, "st %fsr, ");
adec (st, insn);
break;
case STD:
strcpy (st, "std ");
stpar (st, insn);
break;
case STA:
strcpy (st, "sta ");
stpara (st, insn);
break;
case STBA:
strcpy (st, "stba ");
stpara (st, insn);
break;
case STHA:
strcpy (st, "stha ");
stpara (st, insn);
break;
case STDA:
strcpy (st, "stda ");
stpara (st, insn);
break;
case LDF:
strcpy (st, "ld ");
ldparf (st, insn);
break;
case LDFSR:
strcpy (st, "ld ");
adec (st, insn);
strcat (st, ", %fsr");
break;
case LD:
strcpy (st, "ld ");
ldpar (st, insn);
break;
case LDUB:
strcpy (st, "ldub ");
ldpar (st, insn);
break;
case LDUH:
strcpy (st, "lduh ");
ldpar (st, insn);
break;
case LDDF:
strcpy (st, "ldd ");
ldparf (st, insn);
break;
case LDD:
strcpy (st, "ldd ");
ldpar (st, insn);
break;
case LDSB:
strcpy (st, "ldsb ");
ldpar (st, insn);
break;
case LDSH:
strcpy (st, "ldsh ");
ldpar (st, insn);
break;
case LDSTUB:
strcpy (st, "ldstub ");
ldpar (st, insn);
break;
case SWAP:
strcpy (st, "swap ");
ldpar (st, insn);
break;
case LDA:
strcpy (st, "lda ");
ldpara (st, insn);
break;
case LDUBA:
strcpy (st, "lduba ");
ldpara (st, insn);
break;
case LDUHA:
strcpy (st, "lduha ");
ldpara (st, insn);
break;
case LDDA:
strcpy (st, "ldda ");
ldpara (st, insn);
break;
case LDSBA:
strcpy (st, "ldsba ");
ldpara (st, insn);
break;
case LDSHA:
strcpy (st, "ldsha ");
ldpara (st, insn);
break;
case LDSTUBA:
strcpy (st, "ldstuba ");
ldpara (st, insn);
break;
case SWAPA:
strcpy (st, "swapa ");
ldpara (st, insn);
break;
case CASA:
strcpy (st, "casa ");
ldpara (st, insn);
break;
default:
sprintf (st, "unknown opcode: 0x%08x", inst);
}
break;
default:
sprintf (st, "unknown opcode: 0x%08x", inst);
}
}
static void
sparc_print_insn (uint32 addr)
{
char tmp[128];
uint32 insn;
int32 hold;
ms->memory_iread (addr, &insn, &hold);
sparc_disas (tmp, addr, insn);
printf (" %s", tmp);
}
const struct cpu_arch sparc32 = {
#ifdef HOST_LITTLE_ENDIAN
3,
#else
0,
#endif
sparc_dispatch_instruction,
sparc_execute_trap,
sparc_check_interrupts,
sparc_print_insn,
sparc_gdb_get_reg,
sparc_set_register,
sparc_display_registers,
sparc_display_ctrl,
sparc_display_special,
sparc_display_fpu
};