The ATI drivers uses dcbz to simulate a write-combining buffer when
sending HOST_DATA payloads.
The intent is something like this (on real hardware):
```
dcbz:
cache line = [0, 0, 0, 0, 0, 0, 0, 0]
ATI sees nothing
following stores:
cache line = [A, B, C, D, E, F, G, H]
ATI still sees nothing
dcbf or eviction:
write back [A, B, C, D, E, F, G, H]
ATI receives one completed cache line
```
With our previous cacheless implementation, the behavior was more like this:
```
dcbz:
ATI immediately receives [0, 0, 0, 0, 0, 0, 0, 0]
following stores:
ATI then receives [A, B, C, D, E, F, G, H]
dcbf:
no-op
```
The zero-ed out values have side effects (32 pixels of black being
written), so the intermediate state was visible.
The truly correct fix is to fully model the data cache, and do an
eventual write back of the modified cache lines with their final values,
but that is very invasive (and likely to be slow).
We instead just make `dcbz` a no-op for MMIO regions, which lets us
avoid that intermediate state and unintended side effects.
Followup to #186 - select `MSR[POW]` handling mode once during CPU
initialization instead of treating every processor as `HID0`-gated.
We match documented (and QEMU) behavior:
- 603/7xx CPUs require `HID0` doze, nap, or sleep bits before we enter
the emulator sleep loop
- 604-family CPUs use just for `POW` directly
- 601 does not support `POW` at all
xnu-123.5 and similar vintage kernls enter the PowerPC 750 powersave mode
when the scheduler has no runnable work. `machine_idle_ppc` selects HID0
doze or nap, records a nap timestamp, then executes mtmsr with MSR[POW]
set. It stays in a loop there (in case the power saving had no effect
immediately) - it expects execution to resume at the `machine_idle_ret`
label (when an interrupt occurs), which ends up returning from the
function.
We model this state explicitly:
- When mtmsr sets MSR[POW] with the HID0 doze/nap/sleep flags, set a new
EXEF_SLEEP flag.
- When EXEF_SLEEP is set, keep processing host events without advancing
the guest PC.
Towards getting the 10.0 public beta to boot (#154) - before this we
would enter the DPPC debugger shortly after this instruction (due to a
bogus MSR LE flag eventually being set). Now we make more progress and
end up in a "Still waiting for root device" loop (presumably something
at the ATA layer)
===============
Rairii changes:
memctrlbase: The memory controller may have an endian swap mode.
mpc106: Only mmio regions need endian swap and only if PCIR_LE_MODE is
set.
videoctrl: Add framebuffer_in_main_memory flag. Use needs_swap_endian.
debugger: Fix disasm for little endian mode.
ppcmmu: little endian mode requires munging of the data and instruction
addresses, affecting the 3 least significant bits.
ppcexec: pc_real is always recalculated during little endian mode
because instructions are swapped every 8 bytes (due to the address
munging).
==============
joevt changes:
Add SUPPORTS_MEMORY_CTRL_ENDIAN_MODE for memory controller.
Use cmake -DDPPC_SUPPORT_PPC_LE=ON to enable.
Add SUPPORTS_PPC_LITTLE_ENDIAN_MODE for CPU.
Use cmake -DDPPC_SUPPORT_MEM_LE=ON to enable.
Add ppc_change_endian to handle endian switch for MPC601 (uses HID0
instead of MSR) and later PPC CPUs.
Add is_LE flag to ppc_state to indicate little endian mode for all
processor versions.
Create separate ppc_exec_inner template functions for little and big
endian.
Switch endian mode in the ppc_exec outer functions when power_off_reason
is po_endian_switch.
Since MPC601 doesn't have ILE and LE bits, remove that code for that
CPU.
videoctrl: Uses templated methods. See next commit for a fix that this
change introduces.
- Always add a tick to the timeout calculation.
- Make sure value of decrementer is < 0 for timed decrementer exception.
- Don't recalculate decrementer write time stamp in the case of an
immediate decrementer exception.
Added a third full screen mode which removes letterbox or pillarbox black bars.
Added Control-- and control-+ to decrease or increase the scale by a factor of 2^(1/8). This means the scale doubles or halves after pressing the same key 8 times.
drawable_w and drawable_h are floating point so that scaling is reversible (i.e. scaling from 100% to 800% and back to 100% gives 100% instead of 99 or 101%).
default_scale_x
Handle switching host resolution between Retina (HiDPI) and Low resolution modes. This involves updating the window scale factor.
Add window scale factor to window title.
Note: all timings are relative to virtual time which is 16 ns per instruction. 8 ns per instruction is too fast for the PDM 'mach' gestalt calculation in firmware.
- For MPC601, bit 7 of RTC and DEC changes at 7.8336 MHz so bit 0 would change at 1.0027008 GHz. Therefore multiply time base frequency by 128. For MPC601, DEC now changes at 1.0027008 GHz instead of 7.8336 MHz.
- Add tbr_freq_shift for cases where time base frequency exceeds 1GHz.
- Change calc_rtcl_value to use time base frequency. For MPC601, RTC now changes at 1.0027008 GHz instead 1GHz.
- For MPC601, the 7 least significant bits of DEC are not implemented so make them not getable or setable.
In #135 we switched from a static OpcodeGrabber table to a
curOpcodeGrabber pointer in ppc_main_opcode. This results in an extra
indirection (as far as generated assembly having an additional load),
which reduces execution speed.
Switch to making the opcode grabber into a parameter to
ppc_main_opcode, and make ppc_exec_inner keep it up to date (via an
EXEF_OPCODE exception flag).
Also fixes FPU instructions in ppctests - we now need to set the FP
MSR bit when initializing the CPU.
Rather than running them normally, they should trigger a "no FPU"
exception. This appears to be required to allow correct graphical
rendering under Mac OS X - the FP bit cleared via mtmsr and rfi
instructions and something else appears to be relying on the exception
to be thrown.
Implemented by maintaining a parallel version of the OpcodeGrabber
table (OpcodeGrabberNoFPU) which contains alternate implementations
for all the floating point instructions. We switch the table whenever
the MSR value changes. This should minimize the overhead of doing
these checks.
Replace it wth an explicit opcode parameter that is passed around. That
is both slightly easier to reason about (to trace where it comes from)
and slightly faster, since it can be read from a register.
On my machine takes booting to "Welcome to Macintosh" being output in
a verbose boot of Mac OS X 10.2.8 from 31.8s to 30.6s (average of 5
runs, measured using deterministic mode and looking at when execution
reaches PC 0x90004a88).