Skip to content

RTG: Emulate the Z3660 video board#212

Merged
LinuxJedi merged 27 commits into
LinuxJedi:mainfrom
codewiz:feat/z3660-rtg
Jul 20, 2026
Merged

RTG: Emulate the Z3660 video board#212
LinuxJedi merged 27 commits into
LinuxJedi:mainfrom
codewiz:feat/z3660-rtg

Conversation

@codewiz

@codewiz codewiz commented Jul 17, 2026

Copy link
Copy Markdown
Contributor
Image

Summary

Emulates the Z3660 accelerator's FPGA RTG core as a Zorro III autoconfig
board (manufacturer 0x144B, product 1, one 128 MB window), driven by the
unmodified open-source Z3660.card Picasso96 driver. Workbench runs on
Z3660 screen modes in 8/16/32-bit with a working mouse pointer, and the
display switches cleanly between the native chipset and the RTG
framebuffer.

First RTG board for #19. The ZZ9000 (largely register-compatible with
this board) and a Copperline-native card discoverable by the bundled
AROS ROM's p96gfx HIDD are natural follow-ups on the same
infrastructure.

Enabled with:

[z3660]
enabled = true

What is emulated

  • Autoconfig identity and the 32-bit register file at window offsets
    0x100-0x7FF. Every register access and mailbox op is logged by name,
    so the board doubles as a driver-development rig.
  • FindCard/InitCard probes: FW_VERSION (reports v1.06), INT_STATUS,
    MONITOR_SWITCH (0 = no CIA display-switch fiddling).
  • VBLANK_STATUS follows a 60 Hz frame phase in emulated colour clocks,
    so WaitVerticalSync/GetVSyncState behave like hardware.
  • SetGC/SetPanning: custom modelines (CUSTOM_VIDMODE parameter pairs),
    MODE (vmode/colormode/scalemode), ORIG_RES, and the PAN op.
  • Scanout: the panned VRAM framebuffer is composed in all four pixel
    formats (CLUT through the captured palette, R5G6B5, R5G5B5,
    B8G8R8A8) and presented by the window and the CCP capture path;
    OP_CAPTUREMODE switches back to native chipset output.
  • The GFXData mailbox blitter ops, executed synchronously on the
    doorbell write as the bus-stalling hardware does: FILLRECT, COPYRECT
    (overlap-safe, 8-bit plane mask), COPYRECT_NOMASK, INVERTRECT,
    RECT_TEMPLATE and RECT_PATTERN (JAM1/JAM2/COMPLEMENT + INVERSVID),
    DRAWLINE (patterned, with the COMPLEMENT XOR mode the shell cursor
    uses), and the planar P2C/P2D blits that render icons and window
    gadget imagery.
  • The hardware sprite: the mouse pointer image, colours, and position
    ride the sprite ops and are composited over the output at present
    time, never touching VRAM -- like the real output-stage overlay.

Semantics follow the board's ARM firmware (z3660-firmware, GPL-3.0
like Copperline), including its quirks: the GFXData pitch field is
longwords for fill/copy/invert/line but raw bytes for
template/pattern, colours ride in guest byte order (the little-endian
ARM reads the 68k values byteswapped), and minterms are the firmware's
0-15 enum, not raw blitter bytes.

Not implemented yet (logged when hit): the ACC_OP surface ops, exotic
minterms, screen-split, overlays, and the video-capture path. RTG
frames are currently scaled into the Amiga-sized presentation texture;
pixel-perfect presentation is a follow-up.

Test plan

  • Unit tests for the register latch, palette capture, scanout in all
    pixel formats, pan, each blit-op family, the planar decodes, and the
    sprite compositing cycle (show/upload/colour/move/hide).
  • Live: Workbench 3.2 on Z3660:800x600 and 1920x1200 modes in 8, 16,
    and 32-bit with the real Z3660.card 1.06 built from source; window
    dragging, shell text and cursor, icons, and gadget imagery render;
    ScreenMode test-cycle and DISPLAYCHAIN=YES switch RTG <-> AGA both
    ways. Headless: deterministic boots driving the driver via the
    serial shell with CCP screenshots.
  • cargo test (1593), clippy, fmt clean.

Generated with Claude Code

@codewiz codewiz mentioned this pull request Jul 17, 2026

@LinuxJedi LinuxJedi left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

This is an AI code review performed by Claude Code (Fable 5), posted on behalf of @LinuxJedi.

Review: z3660: emulate the Z3660 RTG board (Picasso96)

Overview

Adds a new Zorro III device (src/z3660.rs, ~1360 lines) modelling the Z3660 accelerator's FPGA RTG core: autoconfig identity, the 32-bit register file at window offsets 0x100-0x7FF, 64 MB of backed board RAM, the GFXData mailbox blitter executor (fill/copy/invert/template/pattern/line/planar), palette capture, a 60 Hz vblank phase in emulated colour clocks, and a hardware-sprite mouse pointer composited at scanout. Presentation is hooked into both the window path (render_rtg_frame_if_active) and the CCP capture path (render_frame in control/exec.rs). Config plumbing ([z3660] enabled) follows the A2065 pattern exactly.

Overall: high-quality, well-structured work that fits the codebase's conventions. The tricky integration points were checked against the base tree and hold up. The blockers are stale documentation that contradicts the code, and two guest-controllable unbounded allocations.

Verified as correct

  • Vblank timing under tick batching: is_idle() defaults to true, but Zorro devices are ticked unconditionally in tick_timed_devices, and the deferred batch is flushed before every device-register read (flush_timed_devices), so VBLANK_STATUS advances correctly and WaitVerticalSync cannot hang. Batching is exact since tick is linear in cck.
  • Presentation buffer reshaping: the RTG path resizes present_fb to h * FB_WIDTH (possibly smaller or larger than the native FB_WIDTH * OUT_HEIGHT). This is safe: copy_present_frame/save_present_frame scale arbitrary src_rows via scaled_source_row, the sync native path resizes per frame (refresh_present_from_deinterlacer), and the threaded path replaces the whole Vec.
  • Threaded-render race handling: draining in-flight chipset results before the RTG compose is the right order -- a stale native frame cannot land on top of an RTG frame. At worst there is a one-frame native flash at the switch boundary, which self-corrects.
  • CCP capture consistency: both render_frame consumers slice fb[..FB_WIDTH * lines], matching the RTG buffer's exact size.
  • Save states: BoardDevice::Z3660 is correctly appended last (bincode variant-index rule); no existing struct changes shape, so no STATE_VERSION bump is needed. MachineDescriptor carries no board fields, consistent with existing boards.
  • Byte-order plumbing (the trickiest part): the guest-order pixel stores, the 0x00RRGGBB palette/sprite-colour representation, and the RGBA-low-byte-R presentation output are all mutually consistent, including the sprite composite swizzle. The two-halfword register-landing rule (off + size == aligned + 4) correctly handles 68k split 32-bit writes.
  • 128 MB is a valid Zorro III size; the register-file window shadows the first 2 KB of RAM harmlessly.

Issues

1. Documentation contradicts the code (should fix before merge)

The user-facing docs describe an earlier iteration of the branch:

  • src/config.rs -- both Config::z3660 and RawZ3660 doc comments say "Bring-up stub: registers are logged, no display output yet." The PR ships a full display pipeline.
  • copperline.example.toml -- says "planar blits, line draws, and surface ops are not implemented yet", but OP_P2C/OP_P2D and OP_DRAWLINE are implemented (the PR description confirms this). Only the ACC_OP surface ops are stubbed.
  • docs/guide/configuration.md -- same stale list, plus the "RTG board stub" heading.
  • src/emulator.rs -- the build comment and info! line also say "stub ... registers logged".

The module doc in z3660.rs is accurate; the rest should be reconciled to it. Given the project's docs-in-same-change rule, this is a merge blocker. Minor: consider a line in docs/zorro.md alongside the A2065 section.

2. Unbounded guest-controlled allocations (robustness)

Everything in the executor is carefully bounds-checked per byte except two allocations sized directly from mailbox fields:

  • OP_COPYRECT's overlap snapshot: vec![0u8; x1 * y1 * bpp] -- up to 65535 x 65535 x 4 = ~17 GB from one doorbell write. A buggy or hostile guest program aborts the emulator host.
  • OP_SPRITE_BITMAP: vec![0u8; w * h] -- w <= 16 * hires, but hires = y2 + 1 can be 65536, so this does not actually bound w; up to ~4 GB.

rtg_frame already clamps to 4096x4096; the executor should clamp rect/sprite dimensions similarly (real VRAM bounds them on hardware). This also caps the synchronous-blit stall time (a 65535x65535 FILLRECT is ~4.3 billion iterations on the doorbell write).

3. Logging volume and cost (style/perf)

  • Every register read/write logs at info! (only VBLANK is demoted to trace!), and log_gfxdata logs every blit op at info! -- on a live Workbench desktop that is a firehose at the default level, for every user with the board enabled, not just driver developers.
  • log_gfxdata builds three Vec<u16>s and does a dozen big-endian reads before the macro, so the cost is paid even when the level is filtered out -- on every blit.

Suggestion: keep info! for the one-time init probes (FW_VERSION, mode set, vidmode params), demote steady-state register traffic and per-blit mailbox dumps to debug!/trace!, and gate the log_gfxdata field extraction behind log::log_enabled!.

4. Minor points

  • Frozen display edge case: render_rtg_frame_if_active returns Some(false) when rtg_active() is true but rtg_frame composes None (e.g. MODE written before ORIG_RES, or an invalid colormode). That suppresses the chipset render too, freezing the last frame indefinitely rather than falling back to native output. Returning None on compose failure would degrade more gracefully.
  • Main-thread compose cost: the RTG path bypasses the render worker; at 1920x1200 that is ~2.3M per-pixel colormode matches plus a horizontal nearest scale per frame, synchronously. Fine for now, but worth a note next to the "pixel-perfect presentation" follow-up. Hoisting the colormode dispatch out of the pixel loop in rtg_frame would be a cheap win.
  • Save-state size: the 64 MB vram rides the zlib stream. Mostly-zero VRAM compresses to almost nothing, but a busy 32-bit 1920x1200 desktop adds real megabytes and 64 MB of compressor work per save. Acceptable; worth knowing.
  • RECT_PATTERN assumes user0 is a power of two (& (pat_rows - 1)); if the firmware guarantees this, a comment saying so would help.

Test coverage

Good breadth for a first pass: palette capture, activation gating, CLUT/565/32-bit scanout, pan, fillrect edges, overlapping copyrect, template JAM2, P2C and P2D decode, and the full sprite lifecycle. Gaps worth closing, since these regress silently:

  • OP_DRAWLINE -- especially the COMPLEMENT XOR path the shell cursor depends on, and pattern rotation.
  • OP_RECT_PATTERN, OP_INVERTRECT, OP_COPYRECT_NOMASK (the pitch1/src-surface variant).
  • 15-bit (R5G5B5) scanout decode -- the only pixel format with no test.
  • The split-write landing rule: two halfword writes high-first firing reg_written exactly once.
  • compose_rtg_present scaling (both w < FB_WIDTH and w > FB_WIDTH).

Security

The Zorro window is guest-facing attack surface; apart from the two allocations in issue 2, all VRAM accesses are bounds-checked and out-of-range accesses are dropped and logged. No host filesystem/network exposure. Determinism is preserved (all state advances on emulated cck), so headless runs and replay stay byte-identical.

Verdict

Approve once issue 1 (stale docs) and issue 2 (allocation clamps) are addressed; issue 3 and the test gaps are strongly recommended but could be fast follow-ups.


🤖 Generated with Claude Code

@LinuxJedi LinuxJedi left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

This is an AI code review performed by OpenAI Codex, posted on behalf of @LinuxJedi.

I found eight correctness issues not already covered by Claude's review. They affect panning, inverse drawing, line rasterization, planar conversion, doubled sprites, save-state compatibility, and cold-reset behavior. Requesting changes until these are addressed.

Comment thread src/z3660.rs Outdated
Comment thread src/z3660.rs Outdated
Comment thread src/z3660.rs Outdated
Comment thread src/z3660.rs Outdated
Comment thread src/z3660.rs Outdated
Comment thread src/z3660.rs Outdated
Comment thread src/zorro_device.rs
Comment thread src/z3660.rs

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds initial emulation and presentation support for the Z3660 RTG (Picasso96) board as a Zorro III autoconfig device, including scanout/blitter behavior and frontend integration so RTG modes can be displayed (and captured) alongside existing chipset output.

Changes:

  • Introduces a new Z3660 Zorro device implementation (register file, backed VRAM, basic mailbox/blitter ops, scanout, sprite overlay) and wires it into the Zorro chain/device enum.
  • Adds RTG-aware presentation paths: native-resolution GPU texture overlay in the desktop window and RTG-aware headless capture/screenshot composition.
  • Adds configuration/docs plumbing ([z3660].enabled), plus save-state version bump for the new BoardDevice variant.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/zorro.rs Adds a BoardSpec::z3660() helper to describe the autoconfig board.
src/zorro_device.rs Appends BoardDevice::Z3660 and wires dispatch into the device trait methods.
src/z3660.rs New Z3660 RTG device implementation + unit tests.
src/video/window/rtg_texture.rs New GPU texture/pipeline to present RTG frames at native resolution.
src/video/window.rs Integrates RTG composition + GPU overlay into the window render path.
src/video/present_common.rs Adds RTG-to-screenshot presentation composition helper.
src/savestate.rs Bumps save-state version for the new BoardDevice variant.
src/lib.rs Exposes the new z3660 module.
src/emulator.rs Fits the Z3660 board onto the Zorro chain when enabled in config.
src/control/exec.rs Makes headless capture prefer RTG output when RTG is active.
src/config.rs Adds [z3660] enabled parsing and Config::z3660 flag.
src/bus.rs Adds Bus::rtg_active() and Bus::rtg_frame() queries.
docs/guide/configuration.md Documents the new [z3660] configuration block.
copperline.example.toml Adds an example snippet for enabling [z3660].

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/video/present_common.rs
Comment thread src/z3660.rs
Comment thread src/z3660.rs Outdated
Comment thread src/z3660.rs
@codewiz
codewiz requested a review from LinuxJedi July 19, 2026 14:59
@codewiz codewiz changed the title z3660: emulate the Z3660 RTG board (Picasso96) z3660: emulate the Z3660 RTG board (P96) Jul 20, 2026
@codewiz codewiz changed the title z3660: emulate the Z3660 RTG board (P96) RTG: Emulate the Z3660 video board Jul 20, 2026
codewiz and others added 20 commits July 20, 2026 18:10
Autoconfigs the Z3660 FPGA RTG core (mfr 0x144B, product 1, 128 MB
Zorro III window) so the open-source Z3660.card P96 driver finds it.
Registers are latched and logged by name; FW_VERSION, INT_STATUS and
MONITOR_SWITCH answer the FindCard/SetSwitch probes, and the VRAM and
GFXData region is backed RAM. No display output yet.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
VBLANK_STATUS now follows a 60 Hz frame phase ticked in colour clocks
instead of flipping on every read. Doorbell writes decode the GFXData
mailbox (op name, offsets, rects, pitch, colormode, mask, minterm),
and MODE / ORIG_RES / CUSTOM_VIDMODE writes log the modeline by
parameter name.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Capture the palette from the OP_DATA/OP upload stream (primary and
secondary banks), the framebuffer start and width from the PAN op, and
the display switch from MODE + OP_CAPTUREMODE (the Z3660 has no CIA
pass-through switching; capture mode showing native video is the
emulator presenting chipset output as usual). rtg_frame() composes the
panned VRAM as presentation pixels in all four RGB formats.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The window presentation and the CCP capture path both check the board
before rendering the chipset frame: when a mode is set and video
capture is off, the panned VRAM framebuffer is composed into the
presentation buffer (scaled into the FB_WIDTH stride) instead, falling
back to native chipset output when capture mode is on. Drained render
worker results propagate their outcome so redraw scheduling still sees
chipset frames.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
FILLRECT, COPYRECT (overlap-safe, 8-bit plane mask), COPYRECT_NOMASK
(SRC minterm), INVERTRECT, RECT_TEMPLATE and RECT_PATTERN
(JAM1/JAM2/COMPLEMENT + INVERSVID), synchronously on the doorbell as
the bus-stalling hardware does. Colours are handled in guest byte
order (the LE ARM reads the 68k values byteswapped), and the pitch
field is longwords for fill/copy/invert but raw bytes for
template/pattern, matching the firmware. DRAWLINE, P2C/P2D, ACC_OP,
and the sprite remain logged stubs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
SetSprite shows/hides via REG_SPRITE_BITMAP, OP_SPRITE_BITMAP decodes
the 2-plane pointer image from the template scratch, OP_SPRITE_COLOR
sets pens 1-3 (driver sends idx+1, bytes B,G,R), OP_SPRITE_XY tracks
the position. The pointer is drawn over the composed frame at present
time and never touches VRAM, like the real output-stage overlay.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
DRAWLINE walks the signed deltas with the 16-bit rotating pattern
(JAM1/JAM2, COMPLEMENT inverting the destination -- the shell XOR
cursor). P2C decodes the staged bitplanes to pens; P2D looks pens up
in the 256-entry destination-format CLUT staged ahead of the planes.
Minterms are the firmware 0-15 enum (P96 sends 12 = SRC); only
SRC/NOTSRC are executed, the rest log. This completes the ops
Workbench uses: icons and window gadget imagery render on RTG.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Mode set, modeline parameters, and resolution stay at info; the
register access trace and GFXData op dumps move to debug now that the
driver contract is mapped.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The firmware encodes INVERSVID in bit 2 (rtg/gfx.h: JAM in bit 0,
COMPLEMENT in bit 1, INVERSVID in bit 2). Using 0x08 meant inverse
video was never triggered for valid draw modes, so inverse text and
patterned drawing rendered without their source inversion.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The config docs, the emulator build comment/log line, and the
configuration guide still described the early "bring-up stub, no
display" state. Describe the working RTG board instead, keeping the
user-facing docs free of hardware internals.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Appending BoardDevice::Z3660 changes the bincode enum shape, so a state
holding a Z3660 board fails to decode on a build without the variant.
Bump the version so the mismatch is reported cleanly instead of as a
deep bincode error.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The sprite decoder rejected any pointer wider than 16 pixels, so a
doubled (BIF_BIGSPRITE) or 32-wide pointer -- the OS 3.2 32x48 pointer
uses one -- was cleared and the mouse pointer vanished while position
tracking kept working. Decode the 2-bitplane image with the plane-0
then plane-1 row layout from the firmware, and scale a doubled
sprite from its half-size source to 2x2 output blocks. Clamped to the
firmware 32x48 buffer bound.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
render_rtg_frame_if_active returned Some(false) when the board was
active but the frame failed to compose (e.g. MODE written before
ORIG_RES), which suppressed the chipset render and froze the display
on the last frame. Return None so the native path renders instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The GFXData rect width/height fields are guest-controlled, so a bogus
op could size the COPYRECT overlap snapshot at up to ~17 GB or spin a
multi-billion-iteration fill on the doorbell write. Clamp the extents
to a sane maximum (shared with the framebuffer bound); no real screen
or blit approaches it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
BlitPlanar2Chunky does not set the mailbox colormode, so it can carry
a stale 16/32-bit value from a prior op. P2C output is always one
chunky byte per pixel, so use a fixed 1-byte destination stride rather
than the colormode-derived bpp; otherwise the pixels are written on a
2- or 4-byte stride. The regression test now uses a stale 16-bit
colormode on the P2C op.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Bus::power_on_reset zeroes the machine RAM, but the board device reset
left VRAM (guest-readable board RAM) untouched, so a cold boot could
see stale framebuffer data. Clear it in reset(); a warm reset re-inits
the board and repaints, so clearing there too is harmless.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The RTG window path composited the board frame into the fixed FB_WIDTH
presentation buffer, so a mode wider than that buffer -- or shown in a
window larger than it -- was sampled from a lower-resolution
intermediate and looked soft, worst at high resolutions on a HiDPI
display. Give the native frame its own GPU texture at the mode real
resolution and draw it, linear-filtered, straight into the display
sub-rect of the surface in the pixels render_with pass, after the UI
buffer: a single hardware scale from native pixels to the physical
display rect, at full fractional-scale resolution, with no
shared-texture cap. The UI, cursor mapping, and the screenshot path
(still reading present_fb) are unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The P96 DrawLine specification requires Bresenham rasterization and
makes Line.Length authoritative over the raw dX/dY -- that is how a
clipped line segment draws the right pixel count. The board op
interpolated between the endpoints instead and ignored Length (mailbox
user[0]), so diagonals landed on the wrong pixels and a clipped segment
overshot its extent. Step the line with Bresenham and honour Length,
keeping the 16-bit pattern rotation and the
JAM1/JAM2/COMPLEMENT/INVERSVID handling.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A pixel past the end of a row addressed the start of the next one, so a
line overrunning the right edge wrapped around instead of being clipped.
Found while validating DrawLine against P96's own software rasteriser
with p96cts, a conformance suite for P96 card drivers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
codewiz and others added 7 commits July 20, 2026 18:10
SetPanning passes signed x/y viewport offsets in x[0]/y[0] and the
bitmap's row width in x[1]. Both were ignored: the offsets never reached
the scanout base, and x[1] overrode the visible width, so a bitmap wider
than the display mode scanned its whole virtual row into the window.

Fold the offsets into the scanout base, keep the visible size from
ORIG_RES, and use the width only as the row stride. The sprite needs no
adjustment: SetSpritePosition already sends viewport coordinates.

The firmware derives the base by shifting the offsets by the colormode,
which matches the pixel size except for 15-bit, where it strides 8 bytes
per pixel. We scan by the pixel size instead: P96's semantics are what a
driver is checked against.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The nearest-neighbour copy indexed the left edge of each output pixel's
source span, so `x * w / FB_WIDTH` topped out below `w - 1` whenever the
board frame was wider than FB_WIDTH: the rightmost source columns never
reached a downscaled screenshot. Sample the centre of the span instead,
which reaches the last column and keeps the sampling unbiased.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two ways a driver could reach past the blitter's intent:

The surface bases added VRAM_OFFSET to a guest 32-bit offset in usize.
usize is 32 bits on wasm32, where an offset near the top of the address
space wrapped to 0x1FFFF0 -- inside the mailbox region -- and corrupted
it. Widen to u64 and saturate, so an out-of-range base stays out of
range and every access below fails its bounds check.

COPYRECT snapshotted the whole source rect to survive overlap. x1/y1 are
clamped to MAX_DIM apiece, so that reached 64 MiB per blit for a pair of
guest-supplied numbers. Buffer a single row instead and walk rows away
from the destination, which keeps overlap correct at a bounded cost.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`[z3660] enabled` named the board in the section and repeated it in the
key, and left no room for a second card without a second section. Follow
[scsi] controller instead: one [rtg] section whose `card` names the
board, "none" by default.

A machine takes at most one RTG card -- screens come from whichever the
Picasso96 driver finds -- so this stays a single key rather than a set of
per-board sections.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A cycle row alongside Chipset, so the board can be fitted without hand-
editing a config file. Writes [rtg] card only when it differs from the
profile default, as the other rows do, keeping saved files minimal.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The RTG texture is drawn after the CPU frame into the same display
region, so a menu or panel was painted over and vanished: the controls
still hit-tested, they just could not be seen. Present through the CPU
path while the UI is up, which composites it on top as usual.

That path applied the TV aperture, a chipset crop rect, to whatever it
was given; an RTG frame fills the buffer on its own terms, so suppress
it there or the board's screen shows as a sub-rect.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Z3660 is a Zorro III board, so gate it on the rule Zorro III RAM
already uses -- a CPU with a 32-bit address bus -- rather than a list of
machine models. That fits it by default on the A3000 and A4000, and on
any future profile that qualifies, so RTG needs no config step beyond
installing the guest driver.

Asking for it on a 24-bit-bus machine is now an error instead of a board
the CPU could never reach.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@LinuxJedi LinuxJedi left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fantastic stuff. Many thanks for adding this.

@LinuxJedi
LinuxJedi merged commit 71ddf0e into LinuxJedi:main Jul 20, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants