Skip to content

Instantly share code, notes, and snippets.

@bisqwit
Created March 5, 2014 18:45
Show Gist options
  • Save bisqwit/9373842 to your computer and use it in GitHub Desktop.
Save bisqwit/9373842 to your computer and use it in GitHub Desktop.
Sparc64 emulator WIP (from 2011)
#include <stdint.h>
#include <stdio.h>
#include <cstring>
#include <string>
#include <map>
#include <vector>
#include <cmath>
#include <list>
#include <functional>
/* Declare integer datatypes for each number of bits */
typedef uint_least8_t u8; typedef int_least8_t s8;
typedef uint_least16_t u16; typedef int_least16_t s16;
typedef uint_least32_t u32; typedef int_least32_t s32;
typedef uint_least64_t u64; typedef int_least64_t s64;
/* Declare facilities for detecting and dealing with different byteorder */
#include <endian.h>
#define LITTLE_ENDIAN_HOST (__BYTE_ORDER == __LITTLE_ENDIAN)
#define LITTLE_ENDIAN_SLAVE 0 /* 0=big endian */
#define CROSS_ENDIAN (LITTLE_ENDIAN_HOST != LITTLE_ENDIAN_SLAVE)
static u64 SwapBytes(u64 value, unsigned size)
{
if(size >= 2) value = ((value & 0xFF00FF00FF00FF00ull) >> 8ull)
| ((value & 0x00FF00FF00FF00FFull) << 8ull);
if(size >= 4) value = ((value & 0xFFFF0000FFFF0000ull) >> 16ull)
| ((value & 0x0000FFFF0000FFFFull) << 16ull);
if(size >= 8) value = (value >> 32ull) | (value << 32ull);
return value;
}
class SPARC64CPU // SPARC V9
{
enum { NWINDOWS=32, MAXTL=4,
VER = 0x0000000000000000ull,
RSTVaddr = 0x0000000000000000ull,
power_on_reset =0x01,
software_initiated_reset=0x04,
data_access_exception =0x30,
data_access_MMU_miss =0x31,
data_access_error =0x32,
data_access_protected =0x33,
mem_address_not_aligned=0x34,
privileged_action =0x37,
instruction_access_exception=0x08,
instruction_access_MMU_miss =0x09,
instruction_access_error =0x0A,
illegal_instruction = 0x10,
unimplemented_LDD = 0x12,
unimplemented_STD = 0x13,
fp_disabled = 0x20,
tag_overflow = 0x23,
clear_window = 0x24, // ..27
division_by_zero = 0x28,
interrupt_level = 0x41, // ..4F
spill_fill = 0x80, // .. FF
trap_instruction = 0x100 // .. 17F
};
struct reg // SPARC V9 register file
{
// r0..r7 or g0..g7 = one of these sets
u64 g[8][2];
// register windows.
// out registers (r8..r15 or o0..o7) = r[(window+n)%M]. o6=stack pointer
// local registers (r16..r23 or l0..l7) = r[(window+n+8)%M]
// in registers (r24..r31 or i0..i7) = r[(window+n+16)%M]. i6=frame pointer
// where window = 0..NWINDOWS-1, M = 16*NWINDOWS
u64 r[16*NWINDOWS];
u64 Y, TT[MAXTL], TBA, TICK, PIL, TL;
u64 CANSAVE, CANRESTORE, OTHERWIN, CLEANWIN;
u64 ASR[25];
// These are a bit more complex.
union { u16 w; struct { u8 NORMAL:3, OTHER:3; }; } WSTATE;
union
{
// as 32-bit word (TSTATE)
u32 w;
// as register components
struct {
u32 CWP:8;
u32 PSTATE:16;
u32 ASI:8;
u32 CCR:8;
u32 PC :32; // PC and TPC[]
u32 nPC:32; // nPC and TNPC[]
};
// as individual bits
struct {
u32 cwp_bits:8;
// pstate:
u32 AG:1, IE:1, PRIV:1, AM:1, PEF:1, RED:1, MM:2, TLE:1, CLE:1, PID0:1, PID1:1;
u32 unused_pstate_bits:4;
u32 asi_bits:8;
// CCR bits 7..4: XCC; bits 3..0: ICC
u32 ic:1, iv:1, iz:1, in:1;
u32 xc:1, xv:1, xz:1, xn:1;
};
} t, TSTATE[MAXTL]; // Also encapsulates TPC,TnPC
} regs;
u64& R(unsigned rno) // Return a reference to the given register
{
if(rno < 8) return regs.g[rno][ regs.t.AG ];
return regs.r[ (rno-8 + 16*regs.t.CWP) % (16*NWINDOWS) ];
}
std::pair<unsigned,bool> condition(unsigned condtype, unsigned condno)
{
unsigned condmask = (0x2815AE40 >> ((condno&7)*4));
bool c = condmask&1, v=condmask&2, z=condmask&4, n=condmask&8;
bool cond = false, want = (condno & 8) ^ !!(condno & 7);
switch(condtype)
{
case 0: case 1: case 2: case 3: return {fp_disabled,false}; break;
case 0x80: cond = (c&regs.t.ic) | (z&regs.t.iz) | ((n&regs.t.in) ^ (v&regs.t.iv)); break;
case 0x82: cond = (c&regs.t.xc) | (z&regs.t.xz) | ((n&regs.t.xn) ^ (v&regs.t.xv)); break;
default: return {illegal_instruction,false};
}
return {0, cond == want};
}
std::pair<unsigned,bool> icondition(s64 val, unsigned rcond)
{
bool cond = false, want = rcond&4;
switch(rcond & 3)
{
case 1: cond = val != 0; break;
case 2: cond = val > 0; break;
case 3: cond = val >= 0; break;
default: return {illegal_instruction,false};
}
return {0, cond == want};
}
template<typename T>
T Load(u64 address)
{
return address; // TODO
}
template<typename T>
void Store(u64 address, T value)
{
address=address; value=value; // TODO
}
void DoTrap(unsigned trapno)
{
unsigned traplo = trapno & 0x1FF;
if(regs.TL > 0) trapno |= 0x200;
unsigned oldtl = regs.TL;
if(regs.TL < MAXTL) ++regs.TL;
regs.TT[regs.TL-1] = trapno;
regs.TSTATE[regs.TL-1] = regs.t;
regs.t.RED = oldtl == (MAXTL-1);
if(traplo == software_initiated_reset
|| traplo == power_on_reset)
{
regs.t.RED = 1;
regs.t.MM = 0; // TSO
if(traplo == power_on_reset)
regs.t.TLE = 0; // big-endian for traps
}
regs.t.PEF = 0; // no fpu
regs.t.AM = 0; // address masking off
regs.t.PRIV = 1; // privileged mode
regs.t.IE = 0; // interrupts disabled
regs.t.AG = 1; // global registers are replaced with alternate globals
regs.t.CLE = regs.t.TLE; // Set endian mode for traps
if( (traplo) == clear_window)
regs.t.CWP += 1;
else if( (traplo & 0x1C0) == 0x080) // spill trap
regs.t.CWP += regs.CANSAVE+2;
else if( (traplo & 0x1C0) == 0x0C0) // fill trap
regs.t.CWP -= 1;
if(regs.t.RED)
{
regs.t.PC = (RSTVaddr & ~0xFFull);
if(traplo == software_initiated_reset)
regs.t.PC += 0x80ull;
else if(traplo == power_on_reset)
regs.t.PC += 0x20ull;
else
regs.t.PC += 0xC0ull;
}
else
{
regs.t.PC = regs.TBA & ~(0x7FFFull);
regs.t.PC += u64(trapno << 5);
if(oldtl) regs.t.PC += 0x4000ul;
}
regs.t.nPC = regs.t.PC + 4;
}
void ExecuteOne(const u32 i)
{
#define rs1 ((i >> 14) & 0x1F)
#define rs2 ((i >> 0) & 0x1F)
unsigned rd = (i >> 25) & 0x1F;
#define simm13 (s64)(((s32)((i & 0x1FFF) << 19)) >> 19)
#define simm11 (s64)(((s32)((i & 0x07FF) << 21)) >> 21)
#define simm10 (s64)(((s32)((i & 0x03FF) << 22)) >> 22)
#define arg2_13 ((i&0x2000) ? simm13 : (s64)R(rs2))
#define arg2_11 ((i&0x2000) ? simm11 : (s64)R(rs2))
#define arg2_10 ((i&0x2000) ? simm10 : (s64)R(rs2))
#define Sab { u64 a = R(rs1), v = arg2_13, b =
#define Sd { if(rd) R(rd) = b; } break; }
#define Sc(c,v) do { regs.t.ic = regs.t.xc = (c); \
regs.t.iv = (v>>31)&1; \
regs.t.xv = (v>>63)&1; } while(0)
#define Sccr(v) do { regs.t.ic = regs.t.xc = regs.t.iv = regs.t.xv = 0; \
regs.t.iz=!((u32)(v)); regs.t.in=((v)>>31)&1; \
regs.t.xz=!((u64)(v)); regs.t.xn=((v)>>63)&1; } while(0)
#define RetTrap(trapno) \
do { DoTrap(trapno); return; } while(0)
#define RetSpillTrap(spill) \
RetTrap(spill_fill + 0x40*(spill) \
+ 0x4*(regs.OTHERWIN \
? 0x8|regs.WSTATE.OTHER \
: regs.WSTATE.NORMAL))
#define getcondition(condtype, condno) \
std::pair<unsigned,bool> tmp = condition(condtype, condno); \
if(tmp.first) RetTrap(tmp.first); \
bool act = tmp.second
#define geticondition(val, rcond) \
std::pair<unsigned,bool> tmp = icondition(val, rcond); \
if(tmp.first) RetTrap(tmp.first); \
bool act = tmp.second
u64 Next = regs.t.nPC, Next2 = Next+4;
auto Jump = [&] (unsigned linkreg, bool skip_delayslot, bool condition, u64 target_address)
{
if(linkreg) R(linkreg) = regs.t.PC;
if(condition && (target_address & 3)) RetTrap(mem_address_not_aligned); // FIXME
switch( skip_delayslot*2 + condition )
{
case 0: // Do delay, don't jump */
break;
case 1: /* Do delay, do jump */
Next2 = target_address;
break;
case 2: /* Skip delay-slot, don't jump */
Next = Next2;
Next2 = Next+4;
break;
case 3: /* Skip delay-slot, do jump */
Next = target_address;
Next2 = Next+4;
}
};
#define nTL if(!regs.TL) RetTrap(illegal_instruction);
#define nPR if(!regs.t.PRIV) RetTrap(privileged_action);
#define tr(op,op3) (((op) << 6) | ((op3)&0x3F))
switch(tr(i>>30, i>>19))
{
case tr(0,0x20) ... tr(0,0x27): { u32 b = (u32)(i << 10); Sd // SETHI/NOP (note: ranged case is a GCC extension)
case tr(2,0x09): Sab a * v; Sd // MULX
case tr(2,0x00): Sab a + v; Sd // ADD
case tr(2,0x10): Sab a + v; Sc(b<a, (a^b)&~(a^v)); Sd // ADDcc
case tr(2,0x04): Sab a - v; Sd // SUB
case tr(2,0x14): Sab a - v; Sc(b>a, (a^b)& (a^v)); Sd // SUBcc
case tr(2,0x01): Sab a & v; Sd // AND
case tr(2,0x11): Sab a & v; Sccr(b); Sd // ANDcc
case tr(2,0x02): Sab a | v; Sd // OR
case tr(2,0x12): Sab a | v; Sccr(b); Sd // ORcc
case tr(2,0x03): Sab a ^ v; Sd // XOR
case tr(2,0x13): Sab a ^ v; Sccr(b); Sd // XORcc
case tr(2,0x05): Sab a & ~v; Sd // ANDN
case tr(2,0x15): Sab a & ~v; Sccr(b); Sd // ANDNcc
case tr(2,0x06): Sab a | ~v; Sd // ORN
case tr(2,0x16): Sab a | ~v; Sccr(b); Sd // ORNcc
case tr(2,0x07): Sab ~(a ^ v); Sd // XNOR
case tr(2,0x17): Sab ~(a ^ v); Sccr(b); Sd // XNORcc
case tr(2,0x08): Sab a + regs.t.ic + v; Sd // ADDC
case tr(2,0x18): Sab a + regs.t.ic + v; Sc(b<a, (a^b)&~(a^v)); Sd // ADDCcc
case tr(2,0x0C): Sab a - regs.t.ic - v; Sd // SUBC
case tr(2,0x1C): Sab a - regs.t.ic - v; Sc(b>a, (a^b)& (a^v)); Sd // SUBCcc
case tr(2,0x0A): Sab (u32)a * (u32)v; regs.Y = u32(b >> 32); Sd // UMUL
case tr(2,0x1A): Sab (u32)a * (u32)v; regs.Y = u32(b >> 32); Sccr(b); Sd // UMULcc
case tr(2,0x0B): Sab (s32)a * (s32)v; regs.Y = s32(b >> 32); Sd // SMUL
case tr(2,0x1B): Sab (s32)a * (s32)v; regs.Y = s32(b >> 32); Sccr(b); Sd // SMULcc
case tr(2,0x0D): Sab v; if(v) b = (u64)a / (u64)v; else RetTrap(division_by_zero); Sd // UDIVX
case tr(2,0x2D): Sab v; if(v) b = (s64)a / (s64)v; else RetTrap(division_by_zero); Sd // SDIVX
case tr(2,0x0E): Sab (u64)((regs.Y<<32)|u32(a)) / (u32)v; Sd // UDIV
case tr(2,0x1E): Sab (u64)((regs.Y<<32)|u32(a)) / (u32)v; Sccr(b); regs.t.iv=!!(u64(v) >> 32); Sd // UDIVcc
case tr(2,0x0F): Sab (s64)((regs.Y<<32)|u32(a)) / (s32)v; Sd // SDIV
case tr(2,0x1F): Sab (s64)((regs.Y<<32)|u32(a)) / (s32)v; Sccr(b); regs.t.iv=!!(u64(v) >> 32); Sd // SDIVcc
case tr(2,0x20): Sab a + v; Sccr(b); Sc(b<a, (a^b)&~(a^v)); Sd // TADDcc (TODO: tag handling)
case tr(2,0x21): Sab a - v; Sccr(b); Sc(b>a, (a^b)& (a^v)); Sd // TSUBcc (TODO: tag handling)
case tr(2,0x22): Sab a + v; Sccr(b); Sc(b<a, (a^b)&~(a^v)); Sd // TADDccTV (TODO: Tag handling, tag exceptions)
case tr(2,0x23): Sab a - v; Sccr(b); Sc(b>a, (a^b)& (a^v)); Sd // TSUBccTV (TODO: Tag handling, tag exceptions)
case tr(2,0x24): Sab (a>>1) + ((regs.t.in ^ regs.t.iv)<<31), y=regs.Y;
if(y&1) b += v;
regs.Y = (y>>1) + ((a&1) << 31);
Sc(b<(a>>1), 0ull); Sd // MULScc
case tr(2,0x25): Sab (i&0x1000) ? ((u64)a << (v&63)) : ((u64)a << (v&31)); Sd // SLL,SLLX
case tr(2,0x26): Sab (i&0x1000) ? ((u64)a >> (v&63)) : ((u32)a >> (v&31)); Sd // SRL,SRLX
case tr(2,0x27): Sab (i&0x1000) ? ((s64)a >> (v&63)) : ((s32)a >> (v&31)); Sd // SRA,SRAX
case tr(2,0x2E): if(rd) R(rd) = __builtin_popcountl(arg2_13); break; // POPC (note: uses GCC extension)
case tr(2,0x2C): { u64 b = arg2_11; getcondition((i>>11)&0x83, i>>14); if(act) Sd // MOVcc
case tr(2,0x2F): { u64 b = arg2_10; geticondition(R(rs1), i>>10); if(act) Sd // MOVr
// Register window manipulation operations are a bit hairy:
case tr(2,0x3C):
Sab a + v; // Take these values from current window
if(!regs.CANSAVE) RetSpillTrap(true);
if(regs.CLEANWIN == regs.CANRESTORE) RetTrap(clear_window);
--regs.CANSAVE; ++regs.CANRESTORE; ++regs.t.CWP;
Sd // Put the result in new window // SAVE
case tr(2,0x3D):
Sab a + v; // Take these values from current window
if(!regs.CANRESTORE) RetSpillTrap(false);
++regs.CANSAVE; --regs.CANRESTORE; --regs.t.CWP;
Sd // Put the result in new window // RESTORE
case tr(2,0x31): nPR switch(rd) {
case 0: ++regs.CANSAVE;
if(regs.OTHERWIN) --regs.OTHERWIN; else --regs.CANRESTORE;
break; // SAVED
case 1: ++regs.CANRESTORE;
if(regs.OTHERWIN) --regs.OTHERWIN; else --regs.CANSAVE;
if(regs.CLEANWIN+1 < NWINDOWS) ++regs.CLEANWIN;
break; // RESTORED
default: RetTrap(illegal_instruction);
} break;
case tr(2,0x2B): if(NWINDOWS - 2 - regs.CANSAVE) RetSpillTrap(true); break; // FLUSHW
case tr(2,0x28): // MEMBAR, RD<asr>
{ u32 b = 0;
switch(rs1)
{
case 15: break; // MEMBAR
case 0: b = regs.Y; break;
case 2: b = regs.t.CCR; break;
case 3: b = regs.t.ASI; break;
case 4: b = regs.TICK; break;
case 5: b = regs.t.PC; break;
//case 6: b = regs.Y; break; // Floating point registers status register
case 7 ... 14: nPR b = regs.ASR[rs1-7]; break;
case 16 ... 31: nPR b = regs.ASR[rs1-8]; break;
}
Sd
case tr(2,0x2A): // RDPR
nPR { u32 b = 0;
switch(rs1)
{
case 0: nTL b = regs.TSTATE[regs.TL-1].PC; break;
case 1: nTL b = regs.TSTATE[regs.TL-1].nPC; break;
case 2: nTL b = regs.TSTATE[regs.TL-1].w; break;
case 3: nTL b = regs.TT[regs.TL-1]; break;
case 4: b = regs.TICK; break;
case 5: b = regs.TBA; break;
case 6: b = regs.t.PSTATE; break;
case 7: b = regs.TL; break;
case 8: b = regs.PIL; break;
case 9: b = regs.t.CWP % NWINDOWS; break;
case 10: b = regs.CANSAVE % NWINDOWS; break;
case 11: b = regs.CANRESTORE % NWINDOWS; break;
case 12: b = regs.CLEANWIN % NWINDOWS; break;
case 13: b = regs.OTHERWIN % NWINDOWS; break;
case 14: b = regs.WSTATE.w; break;
case 31: b = VER; break;
default: RetTrap(illegal_instruction);
}
Sd
case tr(2,0x30): // SIR, WR<asr>
{ u32 a = R(rs1) ^ arg2_13; // xor
switch(rd)
{
case 15: RetTrap(software_initiated_reset); break; // SIR
case 0: regs.Y = a; break;
case 2: regs.t.CCR = a; break;
case 3: regs.t.ASI = a; break;
case 4:case 5: ; break; // ASR #?
case 7 ... 14: nPR regs.ASR[rd-7] = a; break;
case 16 ... 31: nPR regs.ASR[rd-8] = a; break;
}
break; }
case tr(2,0x32): // WRPR
nPR { u32 a = R(rs1) ^ arg2_13; // xor
switch(rs1)
{
case 0: nTL regs.TSTATE[regs.TL-1].PC = a; break;
case 1: nTL regs.TSTATE[regs.TL-1].nPC = a; break;
case 2: nTL regs.TSTATE[regs.TL-1].w = a; break;
case 3: nTL regs.TT[regs.TL-1] = a; break;
case 4: regs.TICK = a; break;
case 5: regs.TBA = a; break;
case 6: regs.t.PSTATE = a; break;
case 7: regs.TL = a; break;
case 8: regs.PIL = a; break;
case 9: regs.t.CWP = a % NWINDOWS; break;
case 10: regs.CANSAVE = a % NWINDOWS; break;
case 11: regs.CANRESTORE = a % NWINDOWS; break;
case 12: regs.CLEANWIN = a % NWINDOWS; break;
case 13: regs.OTHERWIN = a % NWINDOWS; break;
case 14: regs.WSTATE.w = a; break;
default: RetTrap(illegal_instruction);
}
} break;
case tr(2,0x3A): // Tcc
{ getcondition(0x80 | ((i>>11)&3), i>>25);
if(act) RetTrap( trap_instruction + ((R(rs1) + arg2_13) & 0x7F) );
break;
} // Tcc
case tr(2,0x3E): // DONE/RETRY
if(rd >= 2) { RetTrap(illegal_instruction); break; }
nPR nTL regs.t = regs.TSTATE[--regs.TL]; // restore CWP,ASI,CCR,PSTATE,PC,nPC
if(!rd) { regs.t.PC = regs.t.nPC; regs.t.nPC += 4; } // DONE(rd=0)/RETRY(rd=1)
return; // Note that PC,nPC changed
// Load/Store operations:
case tr(3,0x00): case tr(3,0x10): Sab Load<u32> (a+v); Sd // LDUW/LDUWA (TODO: alternate space)
case tr(3,0x01): case tr(3,0x11): Sab Load<u8 > (a+v); Sd // LDUB/LDUBA (TODO: alternate space)
case tr(3,0x02): case tr(3,0x12): Sab Load<u16> (a+v); Sd // LDUH/LDUHA (TODO: alternate space)
case tr(3,0x04): case tr(3,0x14): Store<u32> (R(rs1)+arg2_13, R(rd)); break; // STW/STWA (TODO: alternate space)
case tr(3,0x05): case tr(3,0x15): Store<u8> (R(rs1)+arg2_13, R(rd)); break; // STB/STBA (TODO: alternate space)
case tr(3,0x06): case tr(3,0x16): Store<u16> (R(rs1)+arg2_13, R(rd)); break; // STH/STHA (TODO: alternate space)
case tr(3,0x08): case tr(3,0x18): Sab Load<s32> (a+v); Sd // LDSW/LDSWA (TODO: alternate space)
case tr(3,0x09): case tr(3,0x19): Sab Load<s8 > (a+v); Sd // LDSB/LDSBA (TODO: alternate space)
case tr(3,0x0A): case tr(3,0x1A): Sab Load<s16> (a+v); Sd // LDSH/LDSHA (TODO: alternate space)
case tr(3,0x0B): case tr(3,0x1B): Sab Load<u64> (a+v); Sd // LDX/LDXA (TODO: alternate space)
case tr(3,0x0D): case tr(3,0x1D): Sab Load<u8> (a+v); Store<u8> (a+v, 0xFF); Sd // LDSTUB/LDSTUBA (TODO: alternate space)
case tr(3,0x0E): case tr(3,0x1E): Store<u64> (R(rs1)+arg2_13, R(rd)); break; // STX/STXA (TODO: alternate space)
case tr(3,0x0F): case tr(3,0x1F): Sab Load<u32> (a+v); Store<u32> (a+v, R(rd)); Sd // SWAP/SWAPA (TODO: alternate space)
case tr(3,0x2C): case tr(3,0x3C): Sab Load<u32> (a); if(b==(u32)R(rs2)) Store<u32>(a, R(rd)); Sd // ---/CASA (TODO: alternate space)
case tr(3,0x2E): case tr(3,0x3E): Sab Load<u64> (a); if(b==(u64)R(rs2)) Store<u64>(a, R(rd)); Sd // ---/CASXA (TODO: alternate space)
// Branch/jump operations:
case tr(0,0x08) ... tr(0,0x0F):
{ bool annull = i>>29, cond = (i>>25)&7; getcondition(0x80 | ((i>>20)&3), i>>25);
Jump(0, annull && !(act && cond), act, regs.t.PC + (s32(i<<13) >> 11)); break;
} // Bpcc
case tr(0,0x10) ... tr(0,0x17):
{ bool annull = i>>29, cond = (i>>25)&7; getcondition(0x80, i>>25);
Jump(0, annull && !(act && cond), act, regs.t.PC + (s32(i<<10) >> 8)); break;
} // Bicc
case tr(0,0x18) ... tr(0,0x1F):
{ bool annull = i>>2; geticondition(R(rs1), i>>25);
Jump(0, annull && !act, act, regs.t.PC + s32(s16((i&0x3FFF) | ((i >> 6) & 0xC000)) << 2)); break;
} // BPr
case tr(1,0x00) ... tr(1,0x3F): { Jump(15, false, true, regs.t.PC + s32(i<<2) ); break; } // CALL
case tr(2,0x38): { Jump(rd, false, true, R(rs1) + arg2_13); break; } // JMPL
case tr(2,0x39): nPR { Jump(0, false, true, R(rs1) + arg2_13);
if(!regs.CANRESTORE) RetSpillTrap(false);
++regs.CANSAVE; --regs.CANRESTORE; --regs.t.CWP; break; } // RETURN (JMPL+RESTORE)
// Cache operations (nop):
case tr(3,0x2D): case tr(3,0x3D): break; // PREFETCH/PREFETCHA (NOP)
case tr(2,0x3B): break; // FLUSH (It might be unimplemented, but Linux requires it)
// Floating point mathematics operations (not supported):
case tr(0,0x28) ... tr(0,0x2F): // FBPfcc
case tr(0,0x30) ... tr(0,0x37): // FBfcc
case tr(2,0x34): // FPop1
case tr(2,0x35): // FPop2
case tr(3,0x20): case tr(3,0x30): // LDF/LDFA
case tr(3,0x21): case tr(3,0x31): // LDFSR or LDXFSR
case tr(3,0x22): case tr(3,0x32): // LDQF/LDQFA
case tr(3,0x23): case tr(3,0x33): // LDDF/LDDFA
case tr(3,0x24): case tr(3,0x34): // STF/STFA
case tr(3,0x25): case tr(3,0x35): // STFSR or STXFSR
case tr(3,0x26): case tr(3,0x36): // STQF/STQFA
case tr(3,0x27): case tr(3,0x37): // STDF/STDFA
RetTrap(fp_disabled);
// Deliberately unimplemented operations:
default:
case tr(0,0x00) ... tr(0,0x07): // ILLTRAP/UNIMP
case tr(2,0x36): // IMPDEP1
case tr(2,0x37): // IMPDEP2
RetTrap(illegal_instruction);
case tr(3,0x03): case tr(3,0x13): // LDD/LDDA (FIXME: Linux requires LDD)
RetTrap(unimplemented_LDD);
case tr(3,0x07): case tr(3,0x17): // STD/STDA (FIXME: Linux requires STD)
RetTrap(unimplemented_STD);
#undef tr
#undef nTL
#undef nPR
}
regs.t.PC = Next;
regs.t.nPC = Next2;
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment