2921 Commits
Author SHA1 Message Date
joevt 7a13951400 psx: Initialize class fields.
Use values from the PSX ERS document instead of leaving them random.
2026-10-21 20:26:27 -07:00
joevt 94e7bbd14a platinum: Update display only if base changes.
Corum III in BeOS sets base address often.
2026-10-20 06:17:31 -07:00
joevt 5ad23f5f88 valkyrie: Add missing display modes. 2026-10-19 07:01:34 -07:00
joevt cd2e0ad7da valkyrie: Fix display mode change detection.
The mode should change even if the display disable flag doesn't change.
2026-10-19 07:01:06 -07:00
joevt 8e03b1c52a ppcexec: Add EAR register for disassembly.
BeOS uses the EAR register. This name map is used when listing the
values of input and output registers in disassembly.
2026-10-19 06:56:12 -07:00
joevt 8cab662f6e ppcexec: Use get_virt_time_ns exclusively. 2026-10-19 06:17:30 -07:00
joevt 8dff8a4238 ppcexec: Add comment for Open Firmware illegal op. 2026-10-19 06:16:44 -07:00
Mihai Parparita 904c1b177e benchmark: Add an FPU-focused benchmark
Complement bench1's integer workload with a replay through the real FPU
opcode dispatcher. The 512 instruction and register snapshots are based
on observed FPU operations while running GLTeapot on BeOS PR1.

Report median host time per instruction and provide a checksum mode for
checking that different implementations produce the same results,
without guest boot, display updates, or timer overhead.
2026-10-16 18:13:30 -07:00
Mihai Parparita a188a15bf6 ppc: Reduce floating-point exception handling overhead
Combine the host exception checks and only clear exceptions when needed.
On Apple ARM64, use ACLE intrinsics to read and update FPSR directly,
preserving unrelated status bits. Skip these checks when FE_ALL_EXCEPT
is zero.

On an M2 Max, the FPU replay benchmark drops from 32.6 ns/instruction to
21.3 ns with combined checks and 17.9 ns with the ARM64 helpers, giving
roughly 1.5x and 1.8x throughput respectively.
2026-10-16 18:13:30 -07:00
joevt 6d8ce06052 macio: Interrupt when event gets set.
First, fix when event gets set. Previously, for emulated mode, event was
always set even if the irq_line_state is unchanged. Now, the event gets
set only when the level transitions.

For native mode, event is set only when level transitions from 0 to 1.
This remains correct behavior.

Second, call signal_cpu_int only if event changed. Previously, it was
always called even if irq_lane_state or int_event are unchanged.
2026-10-15 18:33:00 -07:00
joevt fc0d722df0 macio: Fix MIO_OHARE_ID comments.
Because this is the name of the enum.
2026-10-15 18:27:24 -07:00
joevt b6dbbe2685 macio: Clarify ack_int_common comments. 2026-10-15 07:05:03 -07:00
joevt 3430e108bd videoctrl: VBL deassert relative to assert time.
The de-assert time should be relative to expected assert time to ensure
that it occurs before next assert time.
2026-10-15 06:26:21 -07:00
joevt 5b3e4f6552 videoctrl: Add missing this. 2026-10-15 06:23:04 -07:00
Mihai Parparita 357b838ac7 macio: Keep interrupt events and CPU IRQ state consistent
Apply the Grand Central fixes from dingusdev/dingusppc#240 to O'Hare,
Heathrow, and Paddington; the Heathrow ERS shows that it expects to
have the same behavior:
- Reevaluate the CPU interrupt when either mask changes, releasing it
  if no pending events remain enabled in either bank (section 7.1).
- Keep events latched until software writes InterruptClear, even if a
  device deasserts its interrupt line or repeats an assertion (sections
  7.2.1 and 7.2.5).
- Replace writable InterruptMask2 bits instead of ORing them, allowing
  sources to be disabled while preserving the read-only IntMode bit
  (section 7.2.6).
2026-10-14 17:43:14 -07:00
Mihai Parparita 049f8b68c5 machines: repeat 4 MB ROM in 16 MB mapped space
Per the Hammerhead ERS the ROM region is 0xFF000000-0xFFFFFFFF. We were
only mapping the ROM at the uppermost 4 MB of that (0xFFC00000). The fact
that copies are returned at other addresses in that range is not
explicitly stated in the ERS, but it does appear to be emprically true.
It's also corroborated by the 9600 wiring diagram, which shows only enough
address bits for 4MB being used for the ROM.

Also does the same fix for Platinum/7200, which has the same mapping and
address bits, and adds some notes about this to the documentation.

Fixes SheepShaver in BeOS guests, which was using 0xFF000000 to get at
the hardware ROM (see https://github.com/cebix/macemu/blob/96e512bd6376e78a2869f16dcc8a9028bce5ee72/BasiliskII/src/BeOS/SheepDriver/sheep_driver.c#L454).
2026-10-14 15:46:43 -07:00
Mihai Parparita 45a4965cd5 grandcentral: Keep interrupt events and CPU IRQ state consistent
Two correctness fixes, based on the Grand Central ERS:
- Reevaluate the CPU interrupt when the mask changes, releasing it if
  no pending events remain enabled (section 6.1).
- Keep events latched until software writes InterruptClear, even if a
  device deasserts its interrupt line or repeats an assertion (section
  6.2.1).

This fixes occasional freezes on BeOS (especially in realtime mode).
Previously, the CPU interrupt could remain asserted with no enabled
events, trapping BeOS in its interrupt handler.
2026-10-14 15:32:24 -07:00
4e254fc972 viacuda: Keep timer 2 rollover and interrupt timing in sync
T2 readback wrapped after N+1 clocks, but its interrupt was scheduled
for N+3. Mac OS Microseconds could see a wrapped counter with no pending
interrupt, then clear the newly asserted interrupt by reading T2CL. The
one-shot timer would never be serviced or rearmed.

Abuse paces its intro text by repeatedly calling Microseconds until 150
ms have elapsed. This tight polling loop exposes the race. Once the
interrupt is lost, the OS stops accumulating elapsed timer periods,
while the hardware counter keeps wrapping. Microseconds then cycles
within a roughly 84 ms window instead of advancing monotonically, so the
150 ms wait can no longer complete normally. The guest keeps running,
but the text's pacing loop effectively stalls, accounting for the
reported frozen or extremely slow scrolling.

Use a shared time origin for counter readback and the N+1.5-clock
interrupt, including the initial half-clock delay. Before reading T2 or
IFR, also assert any overdue interrupt and cancel its queued callback,
so realtime reads and acknowledgments don't depend on timer polling.

Verified native Abuse intro and gameplay, native and Emscripten builds,
and 84 timer checks covering rollover, acknowledgment and overdue reads.

Co-Authored-By: joevt <950609+joevt@users.noreply.github.com>
Co-Authored-By: Mihai Parparita <513813+mihaip@users.noreply.github.com>
2026-10-13 21:41:03 -07:00
Mihai Parparita 21c6a80e2c timermanager: Preserve phase when rescheduling overdue timers
We would reschedule timers based on their interval and the current time, which
would cause timers with the same interval to get aligned. This may be not be
desired (if a subsystem has two intentionally out-of-phase timers), so we
instead advance the timer based on its previously scheduled time and multiples
of the interval.

Not strictly necessary for the codebase as it stands today (we no longer use
two cyclic intervals for the VBL interval) but it still seems like a worthwhile
correctness improvement, if we decide to reintroduce that approach.
2026-10-13 19:17:31 -07:00
Mihai Parparita 0ea30ac041 videoctrl: Avoid two cyclic timers for VBL interval
We were relying on two separate cyclic timers for the VBL interval, but
in realtime mode we may end up falling behind in timer execution, and the exact
phase may not be preserved. In the worst case they would end up exactly aligned,
and the VBL interval would be effectively lost (the guest polls for the VBL bit
and would never see it)

Switch to only one cyclic timer, which repeatedly sets a one-shot timer for
the VBL end.
2026-10-13 19:17:31 -07:00
joevt 98421734de viacuda: Remove clock drift from T1 rearm.
Use the expected end time as the start time for the next iteration
rather than using the current time. This removes accumulative lag that
process_events might introduce.
2026-10-13 06:20:32 -07:00
joevt e52317c8b5 ppcopcodes: Reduce rA != 0 checks.
By separating (rA != 0) handling from (rA == 0 && is_601) handling.
2026-10-13 06:20:24 -07:00
Mihai Parparita 2a83f5bddc Create empty CD-ROM drives for SCSI-based machines
We only created SCSI CD-ROM drives when an image was supplied at
startup, so later insertion requests had no drive to go to. The
Beige G3 already worked because its ATAPI drive is always created.

Extend the ATAPI approach (where a `cdr_config` property defines the bus
where a CD-ROM drive should be attached) for SCSI-based machines too.
Use it to define default drive on the appropriate bus for PDM, TNT,
Catalyst, Alchemy, Gazelle, and Pippin. Supplying images at startup still
uses the existing drive allocation behavior.
2026-10-11 15:44:22 -07:00
Mihai Parparita 716254c37c Handle CD-ROM commands when no media is present
The 7300 ROM tries to read from an empty CD-ROM drive during boot.
We would try to transfer data from an unallocated buffer and crash.

Return NOT READY / MEDIUM NOT PRESENT for reads, capacity requests,
and TOC requests. Also covers the separate ATAPI READ CD path. This
matches the behavior described in ATAPI 2.6 section 8.5 and the
per-command error tables:
https://www.grix.it/UserFiles/marco.c/INF-8020.pdf
2026-10-11 15:44:22 -07:00
Mihai Parparita 325cc8ac9f ppcopcodes: Reuse operand decode helpers
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.
2026-10-11 15:32:26 -07:00
Mihai Parparita 5cb6d66f18 ppc: Fix reversed operands in tw opcode implementation
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).
2026-10-11 15:32:26 -07:00
Mihai Parparita 6f87662a1d ppcexec: Avoid excessive timer polling in realtime mode
When the interpreter can run faster than realtime (depends on the
host system's performance), we would end up checking timer more
frequently.

This is because the `max_cycles` value returned by `process_events()`
was based on the absolute timer deadline converted to instruction
counts. Once `g_icycles` got ahead of that value, we would check timers
after every instruction.

Instead, use the time remaining until the next timer to schedule an
instruction batch relative to `g_icycles`, capped using the existing
500us polling interval.
2026-10-09 19:10:36 -07:00
Mihai Parparita 62793bb935 ppc: make illegal instructions more obvious
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.
2026-10-09 19:10:02 -07:00
Mihai Parparita 4ed0282ef3 ppc: allow rA=0 for 601 integer store-update instructions
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).
2026-10-09 19:10:02 -07:00
joevt 47a9ccd73b ppcopcodes: Add parenthesis in conditional.
Makes the statement look nicer - symmetry!
2026-10-08 20:26:42 -07:00
joevt 96393c63d0 ppcopcodes: Don't redefine ppc_result_a.
It is defined by the ppc_grab_* macro.
2026-10-08 20:21:44 -07:00
Mihai Parparita a811ff8aa3 ppcexec: Use recommended Apple API for getting the realtime clock
The documentation for `mach_absolute_time` recommends replacing it with
`clock_gettime_nsec_np(CLOCK_UPTIME_RAW)`. The latter is also slightly
simpler to use (no need for initialization and a conversion step).
2026-10-08 17:57:13 -07:00
Mihai Parparita 8851daadc9 hostevents_sdl: prevent realtime toggle keyboard shortcut from reaching the guest
Matches the behavior of other internal keyboard shortcuts.
2026-10-08 17:56:05 -07:00
Mihai Parparita 90debefc2a main: allow realtime mode to be enabled at startup
Adds a --realtime CLI flag to enable realtime mode immediately at
startup.

Also tweaks documentation to mention the Control-Alt-R realtime toggle
and the relationship between the realtime mode and deterministic mode.
2026-10-08 17:56:05 -07:00
joevt 74c60fcd57 ppcopcodes: Carry calculation conditional cut. 2026-10-07 06:22:28 -07:00
joevt 8652a5b8c4 ppcopcodes: Remove blank line. 2026-10-07 06:22:01 -07:00
joevt 25eac76d26 ppcopcodes: Rename grab_ca or grab_xer to xer_ca. 2026-10-07 06:21:53 -07:00
Mihai Parparita 315e3d9f2a timermanager: Make shared TimerInfo structs safer to use
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.
2026-10-06 19:08:45 -07:00
Mihai Parparita 5f111d0929 soundserver_cubeb: Avoid enqueueing the deterministic poll timer twice
Solarian II repeatedly restarts sound DMA without the stream being
closed, and thus we would end up in `SoundServer::start_out_stream`
without going through `close_out_stream`. The `add_cyclic_timer` did
call did not check if the timer was already active, and we would end up
with a duplicate entry in the timer queue, which slowdowns and other
incorrect behavior.

Fixed by checking the `active` flag, like all of the other callsites.
2026-10-06 19:08:45 -07:00
Mihai Parparita 3f070249f2 control: suppress MON_SENSE logspam during startup
When the Displays Enabler extension would load under Mac OS 7.6.1 and
the 7300 ROM, there would be several hundred ERROR level lines about
MON_SENSE register writes with unexpected values (more than 5 bits set).

These were actually harmless (they had the read-only sense input bits
6-8), tweak the mask so that they remain at level 9.
Alpha104c
2026-10-01 18:10:00 -07:00
Mihai Parparita 13e02f7978 control: skip no-op display updates
Makes both flavors of Control enable the `draw_fb_is_dynamic` optimization,
which lets us skip SDL screen update when the the framebuffer content
has not changed.

Improve BeOS PR1 booting on the 7300 from 15.8-46s to 13.9-14.2. The
variability appears to be due to time spent in `SDL_RenderPresent`,
per https://developer.apple.com/documentation/metal/onscreen-presentation
this may block on macOS (with the Metal backend) until the next display
refresh, and we were generating a lot more frames to present before.

Also improves smoothness of the BeOS GL Teapot demo (the displayed
framerate does not change since the timer is driven by instruction
cycles, which don't change).
2026-10-01 06:25:55 -07:00
joevt 317a34a761 swim3: Add reading of Read Mode register.
This is documented in the SWIM3 ERS as:
2026-09-30 21:19:54 -07:00
dingusdev 72a33a1b8a Version 1.04c Prep 2026-09-30 18:18:04 -07:00
Mihai Parparita ab5699d7f9 control: handle reads and writes from the little-endian aperture
BeOS DR8.2 and DR8.3 use this - not handling it was causing graphical
corruption during boot.

We do the operation as usual in big endian mode (which handles the bank
logic) and then byte-swap the results. Note that the byte swapping
depends on the bit width, not the payload length (patent US5640545A
is presumed to describe some of the logic)
2026-09-30 17:03:16 -07:00
Mihai Parparita 387686aaee viacuda: Allow a specific RTC time to be set
Makes it possible to run time-limited OS versions like BeOS DR8.2
(which does not work after 1997-04-01).

This is now also used for deterministic mode (which had already been
hardcoding a 2001-03-24 RTC time).

Also document both flags in the manual.
2026-09-30 16:57:54 -07:00
Mihai Parparita 21c6e24c7c display: Refresh display when RAMDAC pixel width changes
When changing the bit depth, there are two display attributes that change: the
frame buffer pitch and the pixel width.

Mac OS (7.6.1) and BeOS (R3) do those updates in different order: Mac OS updates
the pixel width first, then the frame buffer pitch; BeOS does the opposite.

For Control and Platinum video, those are handled in separate components
(`ControlVideo`/`PlatinumCtrl` vs. `AppleRamdac`), and only the former had the
ability to trigger display configuration updates (which determines the
`convert_fb_cb` function that is selected). BeOS would thus be left with a stale
value, leading to display corruption.

To fix this, add a pixel width update callback (similar to the hardware cursor
change one) and use it to trigger a display configuration update from the
`AppleRamdac` side.
2026-09-28 06:22:03 -07:00
joevt 4d42720af9 adbkeyboard: Fix get_register_3.
The format of register 3 is incorrect. Use the adbdevice implementation.
2026-09-27 15:54:23 -07:00
joevt bf28e376ce adbdevice: Remove set_register_3 duplicate code. 2026-09-27 15:53:05 -07:00
joevt 8413e9245a dbdma: Add missing this. 2026-09-27 09:34:50 -07:00
joevt 019a15e6eb dbdma: Remove extra spaces. 2026-09-27 09:28:15 -07:00