Use existing helpers for more instructions instructions (twi, mtsr,
mtmsr, etc.). Prompted by the recent fix for tw - these were all correct
already, but might as well make things more uniform.
The manual decode swapped rA and rB. Fix thix by using the standard
`ppc_grab_regsab` decode helper.
Fixes Macintosh Common Lisp 4.2 hanging at startup (with 7.5.5 booting
using the 7500 ROM).
Log a warning whenever an illegal opcode exception is being raised,
since it's usually a clue that we have a correctness bug.
Just a warning (as opposed to an error) because the guest OS may handle
the exception and continue execution.
Normally rA (where the effective address is stored) cannot be 0, but the
MPC601 user manual explicitly says that it's allowed for POWER
compatibility (the update is skipped in that case).
Fixes mouse movement in Barrack under on the 6100, which would previously
stop executing because of an illegal opcode exeception being raised
(and unhandled).
With the shared `TimerInfo` structs refactor from 529fff7d, it's easier
to accidentally enqueue the same timer multiple twice. Help the the
programmer out by logging an error if the timer is already `active` when
adding it. To also reduce the boilerplate, one-shot timers and and
cancellation automatically clear the flag.
The error could be upgraded to a CHECK_F once we're more confident that
we've fixed all of the callsites.
This fixes booting Mac OS 8.6 hanging at the Happy Mac on the iMac G3.
During boot, as part of installing the nanokernel, the OS attempts to do
a full TLB flush via a series of `tlbie` instructions. We were trying to
respect the effective address that's specified in the instruction, but
the semantics of how it should be interpreted are different on the 750
CPU - the [user manual](https://www.nxp.com/docs/en/reference-manual/MPC750UM.pdf)
says:
> The `tlbie` instruction invalidates all TLB entries indexed by the EA,
> and operates on both the instruction and data TLBs simultaneously
> invalidating four TLB entries. The index corresponds to bits 14-19 of the EA.
We were not respecting the bits 14-19 part (`TLB_VPS_MASK` matched bits
4-19), and thus not matching all expected entries. The stale entries
would remain, leading to unexpected behavior.
Rather than trying to more precisely model the 750 behavior, we instead
flush all PAT-derived TLB entries. This matches QEMU's approach (see
qemu/qemu@3dcfb74fd4) and is allowed by
[the PowerPC specification](http://refspecs.linux-foundation.org/PPC_hrm.2005mar31.pdf):
> For example, the tlbie instruction may be implemented to purge all TLB
> entries in a congruence class (that is, all TLB entries indexed by the
> specified effective address which can include corresponding entries in
> data and instruction TLBs) **or the entire TLB**.
As of #219 a full flush is not that expensive, thus this does not
materially affect performance. The goal of the guest OS is a full TLB
flush anyway (hence the sweep of `tlbie` instructions), so we don't end
up doing too many extra lookups after they're done.
For #184
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.