Created
March 5, 2014 18:45
-
-
Save bisqwit/9373842 to your computer and use it in GitHub Desktop.
Sparc64 emulator WIP (from 2011)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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®s.t.ic) | (z®s.t.iz) | ((n®s.t.in) ^ (v®s.t.iv)); break; | |
case 0x82: cond = (c®s.t.xc) | (z®s.t.xz) | ((n®s.t.xn) ^ (v®s.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