The hand-written parts of the manual still described how the retired xenia-rs interpreter behaved: its snapshots, Rust casts and helpers. Each of those 490 statements is now either restated as what Canary's emitters and x64 backend actually do (at the pinned canary_experimental commit), or dropped where it only made sense for xenia-rs. Checking them turned up claims that were wrong, not just outdated: - VSCR[SAT] is never modelled in Canary (DID_SATURATE is a stub and mfvscr cannot see it); the pages said saturating ops set it stickily. - Canary does not implement lswi/lswx/stswi/stswx, dcbi, mtfsb0/mtfsb1, vmsum*, vmhaddshs, vupkhpx/vupklpx, and most SPRs; pages described them as working. - Traps evaluate TO in Canary; stvebx/stvehx/stvewx store one element, not 16 bytes; mtmsrd writes only EE; fres/frsqrte/vrsqrtefp precision claims and the stfs "rounds under RN / sets FPSCR" claim contradicted the spec. - Reservations are a 64 KiB block bitmap plus a value compare, not per-address tracking. Claims that neither Canary's source nor a public spec settles are marked unverified (NI at boot, vmaddcfp128 operand order, estimate bit-exactness). Generated regions are untouched; re-running the generator changes nothing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
8.7 KiB
8.7 KiB
vpkd3d128 — Vector128 Pack D3Dtype, Rotate Left Immediate and Mask Insert
Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
|---|---|---|---|
vpkd3d128 |
vpkd3d128 |
— | Vector128 Pack D3Dtype, Rotate Left Immediate and Mask Insert |
Syntax
(no disassembly template)
Encoding
vpkd3d128 — form VX128_4
- Opcode word:
0x18000610 - Primary opcode (bits 0–5):
6 - Extended opcode:
1552 - Synchronising: no
| Bits | Field | Meaning |
|---|---|---|
| 0–5 | OPCD |
primary opcode (6) |
| 6–10 | VD128l |
destination low 5 bits |
| 11–15 | IMM |
5-bit immediate |
| 16–20 | VB128l |
source B low 5 bits |
| 21–23 | XO |
extended opcode |
| 24–25 | z |
sub-operation selector |
| 28–29 | VD128h |
destination high 2 bits |
| 30–31 | VB128h |
source B high 2 bits |
Operands
| Field | Role | Description |
|---|---|---|
VB |
vpkd3d128: read | Source B vector register. |
VD |
vpkd3d128: write | Destination vector register. |
Register Effects
vpkd3d128
- Reads (always):
VB - Reads (conditional): none
- Writes (always):
VD - Writes (conditional): none
Status-Register Effects
No condition-register or status-register effects.
Operation (pseudocode)
; No hand-written pseudocode for this instruction yet.
; The authoritative semantics are the Canary emitter snapshot under
; Implementation References; about half of Canary's emitters open
; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`).
; Every side effect is also enumerated in the Register Effects and
; Status-Register Effects tables above.
C Translation Example
/* No hand-written C yet. Translate the Canary emitter snapshot */
/* under Implementation References; its HIR maps directly: */
/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */
/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */
/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */
/* wrap them in f.ByteSwap for the big-endian guest value */
/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */
/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */
/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */
/* The Register Effects and Status-Register Effects tables above */
/* enumerate every side effect a faithful translation must emit. */
Implementation References
vpkd3d128
- Canary XML:
tools/ppc-instructions.xml— search formnem="vpkd3d128" - Canary emitter:
src/xenia/cpu/ppc/ppc_emit_altivec.cc:2074 - Sylpheed opcode:
crates/sylpheed-ppc/src/opcode.rs:403 - Sylpheed decoder:
crates/sylpheed-ppc/src/decoder.rs:763
Canary emitter (frozen snapshot @ f21ebd49e9)
int InstrEmit_vpkd3d128(PPCHIRBuilder& f, const InstrData& i) {
const uint32_t vd = i.VX128_4.VD128l | (i.VX128_4.VD128h << 5);
const uint32_t vb = i.VX128_4.VB128l | (i.VX128_4.VB128h << 5);
uint32_t type = i.VX128_4.IMM >> 2;
uint32_t pack = i.VX128_4.IMM & 0x3;
uint32_t shift = i.VX128_4.z;
Value* v = f.LoadVR(vb);
switch (type) {
case 0: // VPACK_D3DCOLOR
v = f.Pack(v, PACK_TYPE_D3DCOLOR);
break;
case 1: // VPACK_NORMSHORT2
v = f.Pack(v, PACK_TYPE_SHORT_2);
break;
case 2: // VPACK_NORMPACKED32 2_10_10_10 w_z_y_x
v = f.Pack(v, PACK_TYPE_UINT_2101010);
break;
case 3: // VPACK_FLOAT16_2 DXGI_FORMAT_R16G16_FLOAT
v = f.Pack(v, PACK_TYPE_FLOAT16_2);
break;
case 4: // VPACK_NORMSHORT4
v = f.Pack(v, PACK_TYPE_SHORT_4);
break;
case 5: // VPACK_FLOAT16_4 DXGI_FORMAT_R16G16B16A16_FLOAT
v = f.Pack(v, PACK_TYPE_FLOAT16_4);
break;
case 6: // VPACK_NORMPACKED64 4_20_20_20 w_z_y_x
// Used in 54540829 and other installments in the series, pretty rarely in
// general.
v = f.Pack(v, PACK_TYPE_ULONG_4202020);
break;
default:
assert_unhandled_case(type);
return 1;
}
// https://hlssmod.net/he_code/public/pixelwriter.h
// control = prev:0123 | new:4567
uint32_t control = kIdentityPermuteMask; // original
switch (pack) {
case 1: // VPACK_32
// VPACK_32 & shift = 3 puts lower 32 bits in x (leftmost slot).
switch (shift) {
case 0:
control = MakePermuteMask(0, 0, 0, 1, 0, 2, 1, 3);
break;
case 1:
control = MakePermuteMask(0, 0, 0, 1, 1, 3, 0, 3);
break;
case 2:
control = MakePermuteMask(0, 0, 1, 3, 0, 2, 0, 3);
break;
case 3:
control = MakePermuteMask(1, 3, 0, 1, 0, 2, 0, 3);
break;
default:
assert_unhandled_case(shift);
return 1;
}
break;
case 2: // 64bit
switch (shift) {
case 0:
control = MakePermuteMask(0, 0, 0, 1, 1, 2, 1, 3);
break;
case 1:
control = MakePermuteMask(0, 0, 1, 2, 1, 3, 0, 3);
break;
case 2:
control = MakePermuteMask(1, 2, 1, 3, 0, 2, 0, 3);
break;
case 3:
control = MakePermuteMask(1, 3, 0, 1, 0, 2, 0, 3);
break;
default:
assert_unhandled_case(shift);
return 1;
}
break;
case 3: // 64bit
switch (shift) {
case 0:
control = MakePermuteMask(0, 0, 0, 1, 1, 2, 1, 3);
break;
case 1:
control = MakePermuteMask(0, 0, 1, 2, 1, 3, 0, 3);
break;
case 2:
control = MakePermuteMask(1, 2, 1, 3, 0, 2, 0, 3);
break;
case 3:
control = MakePermuteMask(0, 0, 0, 1, 0, 2, 1, 2);
break;
default:
assert_unhandled_case(shift);
return 1;
}
break;
default:
assert_unhandled_case(pack);
return 1;
}
v = f.Permute(f.LoadConstantUint32(control), f.LoadVR(vd), v, INT32_TYPE);
f.StoreVR(vd, v);
return 0;
}
Special Cases & Edge Conditions
- Pack four float lanes into a single D3D-format 32-bit word. In Canary's decoding (
VX128_4form),IMM >> 2chooses which D3D format to emit,IMM & 3how wide a slot it goes into, andzthe lane shift:D3dColor— pack 4×float[0.0, 1.0]lanes into a 32-bit RGBA8 (A in high byte, B in low byte) — the canonical Direct3D 9D3DCOLORformat. Canary emitsPack(PACK_TYPE_D3DCOLOR).- Canary also packs
NORMSHORT2,NORMPACKED32(2:10:10:10),FLOAT16_2,NORMSHORT4,FLOAT16_4andNORMPACKED64(4:20:20:20); format 7 is unhandled and reported as an unimplemented instruction.
- Also merges into the existing
VD. The mnemonic is "Pack D3Dtype, Rotate Left Immediate and Mask Insert": the result of the pack step is placed into an existingVDrather than overwriting it. Canary does this with a permute whose control depends onIMM & 3andz, keeping the other lanes ofVD. - Sub-operation via the
zfield (2 bits) +IMM(5 bits) gives 7 bits of format selection; the practical set used by Xenon games is small (D3DCOLOR is the dominant one). - No saturation signal. The packer saturates floats beyond
[0.0, 1.0]silently;VSCR[SAT]is not touched. - VMX128 register-fusion on
VDandVB. - No IBM AIX entry — Xenon-only.
- No
Rc, no XER.
Related Instructions
vupkd3d128— the inverse (unpack a D3D-format word back into 4 floats).vpkpx— the standard Altivec 1-5-5-5 pixel pack.vpkshus,vpkuhus— byte-range saturating packs (an alternative colour-packing path).vcfpsxws128,vcfpuxws128— conversion with explicit scale; software sometimes pre-scales floats to[0, 255]before using these in place ofvpkd3d128.
IBM Reference
- No IBM AIX entry — Xbox 360 VMX128 extension only. The "D3D" in the mnemonic refers directly to Direct3D 9 vertex/pixel formats (the
D3DDECLTYPE_*enumeration). - Xbox 360 XDK, Altivec-128 (VMX128) extensions.
- Microsoft D3D9 documentation:
D3DDECLTYPE_D3DCOLOR,D3DDECLTYPE_UBYTE4N, etc.