Skip to content

feat: dual-mode menu core with switchable native FB reader#3

Open
asturur wants to merge 3 commits into
Zaparoo_Launcherfrom
feat/dual-mode-native-fb
Open

feat: dual-mode menu core with switchable native FB reader#3
asturur wants to merge 3 commits into
Zaparoo_Launcherfrom
feat/dual-mode-native-fb

Conversation

@asturur
Copy link
Copy Markdown
Member

@asturur asturur commented May 9, 2026

Summary

Adds a runtime-switchable native FB mode to the menu core without removing any of the original menu functionality. When status[9]=0 (default), the core behaves exactly like the upstream menu — same cosine+LFSR pattern, same PAL/NTSC scandoubler timing, same HDMI wallpaper compositor, F1 wallpaper cycle still works, OSD overlays unchanged. When status[9]=1 (set by Main_MiSTer/support/zaparoo/alt_launcher.cpp), native_video_top takes over and feeds VGA from the 320×240 RGBX8888 framebuffer the launcher writes into DDR.

This is the additive counterpart to #2 — same DDR reader, same timing, but layered on top of the original menu instead of replacing parts of it.

What's carried forward from PR #2 (codex/zaparoo-rgbx8888-native-core)

  • rtl/native_video_reader.sv — DDR burst reader with ping-pong buffers (control word at 0x3A000000, buf0 at 0x3A000100, buf1 at 0x3A04B100)
  • rtl/native_video_timing.sv — 320×240 @ 15.734 kHz NTSC native CRT timing
  • rtl/native_video_top.sv — wrapper
  • PLL output1: 20 MHz27.027 MHz (required for the 15.734 kHz NTSC line rate)

What's deliberately not carried forward

To preserve original menu behavior:

  • CONF_STR title stays "MENU" (so is_menu() in Main_MiSTer keeps matching; F1 wallpaper cycle keeps working)
  • VIDEO_ARX/ARY stay 0/0 (no aspect-ratio change in cosine mode)
  • Original ce_pix PAL/NTSC scandoubler logic intact
  • Original cosine HV counters intact

The mux

wire mode_zaparoo = status[9];
wire use_native   = mode_zaparoo & native_active;

assign VGA_DE  = use_native ? native_de : ~(HBlank | VBlank);
assign VGA_HS  = use_native ? native_hs : HSync;
assign VGA_VS  = use_native ? native_vs : VSync;
assign VGA_R   = use_native ? native_r  : comp_v;
assign VGA_G   = use_native ? native_g  : comp_v;
assign VGA_B   = use_native ? native_b  : comp_v;

native_active = enable & frame_ready, so until the launcher fills the first DDR buffer, the cosine pattern keeps driving the output — no undriven screen on toggle.

DDR clear loop

Removed. It was one-time boot scaffolding driving DDRAM_* with zeros; native_video_reader now owns those signals. When status[9]=0 the reader holds ddr_rd=0/ddr_we=0, so DDR is unused in default mode just as before.

Test plan

  • Quartus compile passes (CI build)
  • Default mode on real DE10-Nano: HDMI wallpaper renders, F1 cycles wallpapers, F12 OSD works, PAL/NTSC selectable as before
  • FB mode (driven by Main_MiSTer alt_launcher setting status[9]=1): 320×240 RGBX content from DDR appears on CRT and HDMI (HDMI via ascal scaling)
  • Toggle back: cosine path returns, wallpaper returns

Notes for follow-up (out of scope here)

  • HPS-side hotkey toggle (e.g. F2) wired into Main_MiSTer/menu.cpp to flip status[9] + video_fb_enable(0/1) + input_switch(0/1) atomically — keep tracking in a separate PR on the Main_MiSTer fork
  • PAL parametrization of native_video_timing (320×240 at 50 Hz with H_TOTAL=432, V_TOTAL=312) keyed off status[4] — defer until 320×240 NTSC is validated on hardware
  • 480i and other resolutions

🤖 Generated with Claude Code

Adds a runtime-switchable "FB mode" alongside the original menu behavior.
When status[9]=0 (default), the menu core renders the original cosine+LFSR
pattern through the unchanged PAL/NTSC scandoubler timing — every existing
menu surface (HDMI wallpaper compositor, OSD, F1 wallpaper cycle) keeps
working. When status[9]=1, native_video_top takes over and feeds VGA from
the 320x240 RGBX8888 framebuffer the HPS-side launcher writes into DDR.

Carried forward from codex/zaparoo-rgbx8888-native-core (PR #2):
  - rtl/native_video_reader.sv  — DDR burst reader with ping-pong buffers
  - rtl/native_video_timing.sv  — 320x240 NTSC native CRT timing
  - rtl/native_video_top.sv     — wrapper
  - PLL output1 20 MHz -> 27.027 MHz (required for 15.734 kHz NTSC line rate)

Deliberately NOT carried forward — preserves original menu functionality:
  - CONF_STR title stays "MENU" (so is_menu() in Main_MiSTer still matches,
    F1 wallpaper cycling still works)
  - VIDEO_ARX/ARY stay 0/0 (no aspect-ratio change in cosine mode)
  - PAL/NTSC scandoubler ce_pix logic intact
  - Original cosine HV counters intact

Mux on status[9] & native_active, with fallback to the cosine path until
the first DDR frame is loaded so the output is never undriven.

The DDR clear loop is removed — it was one-time boot scaffolding using the
same DDRAM_* signals the native reader now owns. native_video_reader holds
ddr_rd/ddr_we low when status[9]=0, so DDR is unused in the default mode.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 9, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9d51024a-e11f-473e-a5cb-7b9f703ec23e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/dual-mode-native-fb

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

asturur and others added 2 commits May 10, 2026 00:26
The previous commit kept the original cosine timing block (H_TOTAL=638,
forced_scandoubler-conditional ce_pix) but switched the PLL to 27.027 MHz.
That produced a line rate of ~42 kHz scandoubled or ~21 kHz interlaced —
nothing standard, so a CRT could not lock on the analog VGA output.

This commit makes native_video_timing the single source of truth for sync
and DE in both modes:

  - ce_pix is now a fixed /4 divider of CLK_VIDEO -> 6.756 MHz pixel rate
    -> 15.749 kHz line rate (within 0.1% of NTSC 15.734 kHz).
  - VGA_HS/VS/DE always come from native_video_top regardless of status[9].
  - The cosine + LFSR fallback paints into the active area only; outside DE
    we drive black so sync stays clean.
  - vvc steps on native_new_frame instead of the old vc wrap; cos LUT is
    indexed by vcount from the shared timing.
  - native_video_top exposes vcount and new_frame so the cosine path can
    reuse the same vertical position the FB reader sees.

The cosine pattern still renders (it was always intended as fallback noise),
but now at NTSC-spec 320x240 timing instead of broken 27 MHz / 638-cycle
timing. Sync locks on real CRTs.

PAL parametrisation is deferred — native_video_timing is currently NTSC-only.
forced_scandoubler is still wired from hps_io but unused; preserve it as a
known placeholder for the eventual PAL/scandoubler follow-up.
Shifts the active image by repartitioning the native timing's front and
back porches; H_TOTAL/V_TOTAL stay fixed so the CRT keeps the same line
and frame rate. V blanking rebalanced from 6/3/13 to 8/3/11 to give a
symmetric +/-8 budget without changing refresh rate.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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.

1 participant