Files
Sylpheed/tools/ppc-manual/control/mtcrf.md
sim f3c512f2ab docs(ppc-manual): check every xenia-rs claim against Canary's source
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>
2026-09-16 21:52:38 +02:00

6.3 KiB
Raw Blame History

mtcrf — Move to Condition Register Fields

Category: Control / CR / SPR · Form: XFX · Opcode: 0x7c000120

Assembler Mnemonics

Mnemonic XML entry Flags Description
mtcrf mtcrf Move to Condition Register Fields

Syntax

mtcrf [CRM], [RS]

Encoding

mtcrf — form XFX

  • Opcode word: 0x7c000120
  • Primary opcode (bits 05): 31
  • Extended opcode: 144
  • Synchronising: no
Bits Field Meaning
05 OPCD primary opcode (31)
610 RT destination / source GPR
1120 spr/tbr/FXM SPR/TBR number (byte-swapped halves) or CR field mask
2130 XO extended opcode
31 reserved

Operands

Field Role Description
RS mtcrf: read Source GPR (alias for RD in some stores).
CRM mtcrf: write 8-bit CR field mask used by mtcrf — one bit per CR field.

Register Effects

mtcrf

  • Reads (always): RS
  • Reads (conditional): none
  • Writes (always): CRM
  • Writes (conditional): none

Status-Register Effects

No condition-register or status-register effects.

Operation (pseudocode)

for i in 0..7:
    if CRM[i] then CR[i] <- (RS)[32+i*4 : 35+i*4]

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

mtcrf

Canary emitter (frozen snapshot @ f21ebd49e9)
int InstrEmit_mtcrf(PPCHIRBuilder& f, const InstrData& i) {
  // mtocrf FXM,RS
  // count <- 0
  // do i = 0 to 7
  //   if FXMi = 1 then
  //     n <- i
  //     count <- count + 1
  // if count = 1 then
  //   CR4un + 32 : 4un + 35 <- RS4un + 32:4un + 35

  Value* v = f.LoadGPR(i.XFX.RT);
  if (i.XFX.spr & (1 << 9)) {
    uint32_t bits = (i.XFX.spr & 0x1FF) >> 1;
    int count = 0;
    int cri = 0;
    for (int b = 0; b <= 7; ++b) {
      if (bits & (1 << b)) {
        cri = 7 - b;
        ++count;
      }
    }
    if (count == 1) {
      f.StoreCR(cri, v);
    } else {
      // Invalid; store zero to CR.
      f.StoreCR(f.LoadZeroInt64());
    }
  } else {
    uint32_t bits = (i.XFX.spr & 0x1FF) >> 1;
    for (int b = 0; b <= 7; ++b) {
      if (bits & (1 << b)) {
        int cri = 7 - b;
        f.StoreCR(cri, v);
      }
    }
  }
  return 0;
}

Special Cases & Edge Conditions

  • CRM is an 8-bit field-mask, MSB-first. Each bit of CRM corresponds to one CR field: CRM[0] (mask bit 0x80) selects CR0, CRM[1] (0x40) selects CR1, …, CRM[7] (0x01) selects CR7. Each set mask bit causes the corresponding 4-bit slice of RS[32:63] to overwrite that CR field; clear mask bits leave the field untouched.
  • Slice positions inside RS. Big-endian: bits 32..35 of RS map to CR0, bits 36..39 to CR1, …, bits 60..63 to CR7. The high 32 bits of RS are ignored.
  • mtcr RS simplified mnemonic. When CRM = 0xFF, all eight CR fields are written; assemblers fold this into mtcr RS. This is the dominant form (function epilogue restoring the saved CR).
  • mtocrf variant. PowerISA defines mtocrf as the single-field variant — encoded with the high bit of FXM set and exactly one CRM bit set. Canary distinguishes it: with exactly one bit set it writes that field, with any other count it zeroes the whole CR (the spec calls that case undefined).
  • Use case in ABI. Save/restore non-volatile CR fields (CR2, CR3, CR4 on the Xbox 360 ABI). The standard restore is lwz r12, 8(r1); mtcrf 0x38, r120x38 = bits for CR2|CR3|CR4 — preserving the volatile fields the callee may have already updated.
  • No CR0 / XER side effects. mtcrf does not record into CR0; XER is untouched.
  • Canary exact match. For plain mtcrf, Canary walks the 8-bit CRM mask and writes each selected field from RS (StoreCR(field, RS)), matching the spec exactly.
  • Not synchronising. Reorderable.
  • mfcr — read the entire CR into a GPR.
  • mcrf — copy one CR field to another (no GPR involved).
  • mcrxr, mcrfs — narrower CR-field moves from XER / FPSCR.
  • crand, cror, … — bit-level CR manipulation.

Simplified Mnemonics

Simplified Expansion Notes
mtcr RS mtcrf 0xFF, RS write all eight CR fields from low half of RS

mtocrf RS, FXM is a related encoding handled by the same Canary emitter (InstrEmit_mtcrf).

IBM Reference