Hacking on some instructions.
This commit is contained in:
parent
2e6db831a5
commit
ffdc1e5d4b
14
TODO.md
14
TODO.md
|
@ -1,8 +1,11 @@
|
|||
## Instructions
|
||||
|
||||
```
|
||||
stbu
|
||||
lwzu
|
||||
need cr0:
|
||||
andix
|
||||
orx
|
||||
mullwx
|
||||
divwux
|
||||
|
||||
addx
|
||||
addix
|
||||
|
@ -12,13 +15,6 @@ subfx
|
|||
subfex
|
||||
subficx
|
||||
|
||||
mulli
|
||||
mullwx
|
||||
divwux
|
||||
|
||||
andix
|
||||
orx
|
||||
|
||||
rlwinmx
|
||||
rlwimix
|
||||
rldiclx
|
||||
|
|
|
@ -73,6 +73,7 @@ typedef struct {
|
|||
|
||||
// kXEPPCInstrFormatI
|
||||
struct {
|
||||
// TODO(benvanik): doc format update
|
||||
uint32_t LK : 1;
|
||||
uint32_t AA : 1;
|
||||
uint32_t LI : 24;
|
||||
|
@ -80,6 +81,7 @@ typedef struct {
|
|||
} I;
|
||||
// kXEPPCInstrFormatB
|
||||
struct {
|
||||
// TODO(benvanik): doc format update
|
||||
uint32_t LK : 1;
|
||||
uint32_t AA : 1;
|
||||
uint32_t BD : 14;
|
||||
|
@ -89,7 +91,9 @@ typedef struct {
|
|||
} B;
|
||||
|
||||
// kXEPPCInstrFormatSC
|
||||
// kXEPPCInstrFormatD
|
||||
struct {
|
||||
// TODO(benvanik): doc format update
|
||||
uint32_t SIMM : 16;
|
||||
uint32_t A : 5;
|
||||
uint32_t D : 5;
|
||||
|
@ -97,6 +101,7 @@ typedef struct {
|
|||
} D;
|
||||
// kXEPPCInstrFormatDS
|
||||
struct {
|
||||
// TODO(benvanik): doc format update
|
||||
uint32_t : 2;
|
||||
uint32_t ds : 14;
|
||||
uint32_t A : 5;
|
||||
|
@ -105,6 +110,7 @@ typedef struct {
|
|||
} DS;
|
||||
// kXEPPCInstrFormatX
|
||||
struct {
|
||||
// TODO(benvanik): doc format update
|
||||
uint32_t Rc : 1;
|
||||
uint32_t : 10;
|
||||
uint32_t B : 5;
|
||||
|
@ -114,6 +120,7 @@ typedef struct {
|
|||
} X;
|
||||
// kXEPPCInstrFormatXL
|
||||
struct {
|
||||
// TODO(benvanik): doc format update
|
||||
uint32_t LK : 1;
|
||||
uint32_t : 10;
|
||||
uint32_t BB : 5;
|
||||
|
@ -121,7 +128,9 @@ typedef struct {
|
|||
uint32_t BO : 5;
|
||||
uint32_t OPCD : 6;
|
||||
} XL;
|
||||
// kXEPPCInstrFormatXFX
|
||||
struct {
|
||||
// TODO(benvanik): doc format update
|
||||
uint32_t : 1;
|
||||
uint32_t : 10;
|
||||
uint32_t spr : 10;
|
||||
|
@ -132,6 +141,7 @@ typedef struct {
|
|||
// kXEPPCInstrFormatXS
|
||||
// kXEPPCInstrFormatXO
|
||||
struct {
|
||||
// TODO(benvanik): doc format update
|
||||
uint32_t Rc : 1;
|
||||
uint32_t : 8;
|
||||
uint32_t OE : 1;
|
||||
|
@ -142,6 +152,15 @@ typedef struct {
|
|||
} XO;
|
||||
// kXEPPCInstrFormatA
|
||||
// kXEPPCInstrFormatM
|
||||
struct {
|
||||
uint32_t Rc : 1;
|
||||
uint32_t ME : 5;
|
||||
uint32_t MB : 5;
|
||||
uint32_t SH : 5;
|
||||
uint32_t RA : 5;
|
||||
uint32_t RS : 5;
|
||||
uint32_t OPCD : 6;
|
||||
} M;
|
||||
// kXEPPCInstrFormatMD
|
||||
// kXEPPCInstrFormatMDS
|
||||
// kXEPPCInstrFormatVA
|
||||
|
|
|
@ -118,8 +118,28 @@ XEEMITTER(divwx, 0x7C0003D6, XO )(FunctionGenerator& g, IRBuilder<>& b, I
|
|||
}
|
||||
|
||||
XEEMITTER(divwux, 0x7C000396, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
// dividend[0:31] <- (RA)[32:63]
|
||||
// divisor[0:31] <- (RB)[32:63]
|
||||
// RT[32:63] <- dividend ÷ divisor
|
||||
// RT[0:31] <- undefined
|
||||
|
||||
if (i.XO.Rc) {
|
||||
// With cr0 update.
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
if (i.XO.OE) {
|
||||
// With XER update.
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
Value* dividend = b.CreateTrunc(g.gpr_value(i.XO.A), b.getInt32Ty());
|
||||
Value* divisor = b.CreateTrunc(g.gpr_value(i.XO.B), b.getInt32Ty());
|
||||
Value* v = b.CreateUDiv(dividend, divisor);
|
||||
v = b.CreateZExt(v, b.getInt64Ty());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(mulhdx, 0x7C000092, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
|
||||
|
@ -148,13 +168,38 @@ XEEMITTER(mulldx, 0x7C0001D2, XO )(FunctionGenerator& g, IRBuilder<>& b, I
|
|||
}
|
||||
|
||||
XEEMITTER(mulli, 0x1C000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
// prod[0:127] <- (RA) × EXTS(SI)
|
||||
// RT <- prod[64:127]
|
||||
|
||||
// TODO(benvanik): ensure this has the right behavior when the value
|
||||
// overflows. It should be truncating the result, but I'm not sure what LLVM
|
||||
// does.
|
||||
|
||||
Value* v = b.CreateMul(g.gpr_value(i.D.A), b.getInt64(XEEXTS16(i.D.SIMM)));
|
||||
g.update_gpr_value(i.D.D, b.CreateTrunc(v, b.getInt64Ty()));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(mullwx, 0x7C0001D6, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
// RT <- (RA)[32:63] × (RB)[32:63]
|
||||
|
||||
if (i.XO.Rc) {
|
||||
// With cr0 update.
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
if (i.XO.OE) {
|
||||
// With XER update.
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
Value* v = b.CreateMul(b.CreateSExt(g.gpr_value(i.XO.A), b.getInt64Ty()),
|
||||
b.CreateSExt(g.gpr_value(i.XO.B), b.getInt64Ty()));
|
||||
g.update_gpr_value(i.XO.D, v);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(negx, 0x7C0000D0, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
|
||||
|
@ -594,6 +639,42 @@ XEEMITTER(rlwimix, 0x50000000, M )(FunctionGenerator& g, IRBuilder<>& b, I
|
|||
}
|
||||
|
||||
XEEMITTER(rlwinmx, 0x54000000, M )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
|
||||
// n <- SH
|
||||
// r <- ROTL32((RS)[32:63], n)
|
||||
// m <- MASK(MB+32, ME+32)
|
||||
// RA <- r & m
|
||||
|
||||
if (i.M.Rc) {
|
||||
// With cr0 update.
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// The compiler will generate a bunch of these for the special case of
|
||||
// SH=0, MB=ME
|
||||
// Which seems to just select a single bit and set cr0 for use with a branch.
|
||||
// We can detect this and do less work.
|
||||
if (!i.M.SH && i.M.MB == i.M.ME) {
|
||||
Value* v = b.CreateAnd(g.gpr_value(i.M.RS), 1 << i.M.MB);
|
||||
g.update_gpr_value(i.M.RS, v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// if mstart ≤ mstop then
|
||||
// mask[mstart:mstop] = ones
|
||||
// mask[all other bits] = zeros
|
||||
// else
|
||||
// mask[mstart:63] = ones
|
||||
// mask[0:mstop] = ones
|
||||
// mask[all other bits] = zeros
|
||||
|
||||
// // ROTL32(x, y) = rotl(i64.(x||x), y)
|
||||
// Value* v = b.CreateZExt(b.CreateTrunc(g.gpr_value(i.M.RS)), b.getInt64Ty());
|
||||
// v = b.CreateOr(b.CreateLShr(v, 32), v);
|
||||
// // (v << shift) | (v >> (64 - shift));
|
||||
// v = b.CreateOr(b.CreateShl(v, i.M.SH), b.CreateLShr(v, 32 - i.M.SH));
|
||||
// v = b.CreateAnd(v, XEMASK(i.M.MB + 32, i.M.ME + 32));
|
||||
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -215,8 +215,16 @@ XEEMITTER(lwz, 0x80000000, D )(FunctionGenerator& g, IRBuilder<>& b, I
|
|||
}
|
||||
|
||||
XEEMITTER(lwzu, 0x84000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
// EA <- (RA) + EXTS(D)
|
||||
// RT <- i32.0 || MEM(EA, 4)
|
||||
// RA <- EA
|
||||
|
||||
Value* ea = b.CreateAdd(g.gpr_value(i.D.A), b.getInt64(XEEXTS16(i.D.SIMM)));
|
||||
Value* v = g.ReadMemory(ea, 4, false);
|
||||
g.update_gpr_value(i.D.D, v);
|
||||
g.update_gpr_value(i.D.A, ea);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(lwzux, 0x7C00006E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
|
||||
|
@ -264,8 +272,16 @@ XEEMITTER(stb, 0x98000000, D )(FunctionGenerator& g, IRBuilder<>& b, I
|
|||
}
|
||||
|
||||
XEEMITTER(stbu, 0x9C000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
|
||||
XEINSTRNOTIMPLEMENTED();
|
||||
return 1;
|
||||
// EA <- (RA) + EXTS(D)
|
||||
// MEM(EA, 1) <- (RS)[56:63]
|
||||
// RA <- EA
|
||||
|
||||
Value* ea = b.CreateAdd(g.gpr_value(i.D.A), b.getInt64(XEEXTS16(i.D.SIMM)));
|
||||
Value* v = g.gpr_value(i.D.D);
|
||||
g.WriteMemory(ea, 1, v);
|
||||
g.update_gpr_value(i.D.A, ea);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(stbux, 0x7C0001EE, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
|
||||
|
|
Loading…
Reference in New Issue