This is a fork of Videodr0me/Arcade-StarWars_MiSTer. It keeps Videodr0me's excellent Star Wars MiSTer port intact and adds The Empire Strikes Back (1985) — the sequel that ran on the same Atari color-vector cabinet — along with a bit-exact AVG drawer rewrite. One Arcade-StarWars.rbf runs both games, chosen by which .mra you launch.
| Videodr0me/Arcade-StarWars_MiSTer (upstream) | This fork | |
|---|---|---|
| Games | Star Wars (1983) | Star Wars (1983) + The Empire Strikes Back (1985) |
| Slapstic protection | n/a (Star Wars has no slapstic) | Atari 137412-101 alternate ("devious") banking — rtl/slapstic101.vhd, a faithful port of MAME's decapped type-101. This is the piece that makes The Empire Strikes Back actually playable. |
| AVG drawer | original Black Widow-heritage drawer | PROM-driven, bit-exact to MAME 0.287 (three per-VCTR math fixes, verified by a Python-vs-MAME stroke diff) |
| Star Wars itself | — | byte-identical to upstream (every addition is either Empire-Strikes-Back-gated via mod_esb, or a drawer-level fix) |
Everything else — the dual 6809 cores, the mathbox, the audio chain (POKEY / TMS5220 / TL084 / Reticon), the DDR3 framebuffer pipeline, the OSD options, and NVRAM — is Videodr0me's. Videodr0me's original Star Wars README is preserved in full below the divider.
The detailed breakdown of what changed:
- Original SW MiSTer port (CPU, mathbox, AVG state machine, audio chain, NVRAM)
vector_fb_ddram.svtriple-buffer DDR3 framebuffer + MISTER_FB display path- Black Widow drawer heritage and the original analytic-endpoint Bresenham rewrite
- All hardware peripheral models (POKEY, TMS5220, TL084, Reticon, etc.)
- Original OSD options and DIP plumbing
- Audio filter modelling
HDL math: bit-exact match to MAME 0.287 (rtl/avg/avg.vhd, rtl/avg/vector_drawer.vhd)
Three bugs in the per-VCTR math were found by running a Python model of our HDL pipeline alongside a Python port of avg_starwars_device and diffing the per-stroke endpoint trace. The fixes are:
- SVEC opcode cycles — MAME's
m_op=2(SVEC, OP1=1) path usescycles = 2^(8 - total_shift)instead of the VCTR2^(15 - total_shift). A 128× difference. Without compensating, every short-vector glyph (= all small text) renders at 128× MAME's size — visible as the "3000% UI text" symptom. Fix: bump effectivetotal_shiftby 7 for SVEC. - scale_factor off-by-one — MAME uses
m_scale ^ 0xff(range 0..255); the HDL used256 - m_scale(range 1..256). The mismatch accumulates and is wildly wrong atm_scale=255. Fix: bitwise NOT instead of subtract. - High total_shift truncation — MAME's cycles formula keeps producing 8, 4, 2, 1 at
total_shift=12..15. The HDLvd_scaletable truncated to zero above 11, dropping ~5% of strokes (the long-normalized small-magnitude ones). Fix: pre-shiftrel_x/rel_yby(total_shift - 11)fortotal_shift > 11, usevd_scale = 1.
Additionally the >>3 truncation on rel_x/rel_y is now applied at the drawer input (matching MAME's (m_dvx >> 3) ^ 0x200 - 0x200 sign-mapping) and the vd_scale table was widened 8× to compensate. The framebuffer pixel pitch is 2^14, calibrated against MAME's coordinate system.
The Python diff tool (sim/diff_decoders.py) verifies 100% per-VCTR exact match across all four captured attract scenes (6522 strokes total).
Frame timing — tried and reverted
The "spread vggos across one CRT frame" approach (vblank-aligned EOF + a triple-buffer same-cycle race fix) was implemented and then reverted at 534f2cb. With the math fixes in place, each vggo produces correct MAME-equivalent content on its own, so Videodr0me's per-vggo swap rate gives a clean display without needing cross-vggo accumulation. The reroute introduced a 3-4 Hz black flash that was never root-caused (sim of the buffer state machine didn't reproduce it; ground truth would need SignalTap).
Lesson: Videodr0me's triple-buffer pipeline was designed and tested for the per-vggo EOF rate. Dropping that rate ~4× exposes timing characteristics they didn't validate. Don't reroute FRAME_DONE without a sim of the consequent buffer dynamics.
Sim infrastructure (sim/)
avg_starwars_mame.py— MAME-faithful Python AVG decoder (port ofmame_avgdvg_ref.cppavg_starwars_device) with per-vg_add_point_buftrace outputavg_starwars_hdl.py— Python emulation of our HDL pipeline, sharing the AVG state machine but using HDL drawer mathdiff_decoders.py— per-VCTR side-by-side diff producing a CSV ordered by divergence magnituderender_mame_faithful.py/render_hdl_emulated.py— PNG renderers using each decodertb_drawer.vhd— stroke-cap latching fix so per-stroke endpoints survive the WALK → IDLE transition
The diff workflow is what found and validated all three math bugs above. Three iterations of "diff → identify pattern → fix Python → re-diff" reduced total divergence from 939 billion to 0.
The Empire Strikes Back (rtl/slapstic101.vhd, releases/Empire Strikes Back.mra, mod_esb plumbing)
The Empire Strikes Back runs on physically identical hardware to Star Wars per MAME's esb_main_map — same AVG (same PROM CRC), same mathbox, same audio chain, same inputs — and is selectable at runtime via the MRA's <rom index="1"> byte (no rebuild to switch games). The one genuinely hard part was the Atari slapstic 137412-101 copy-protection chip:
- The slapstic's direct bank switching is simple, but The Empire Strikes Back's gameplay depends on its alternate ("devious") banking — confirmed against MAME (
mame.exe esb -logover real play shows 51 alternate-banking sequences reaching banks 0/2). Attract mode uses only direct banking, which is exactly why the game would boot, render one perfect frame, then freeze ~5 frames into gameplay (a computed jump into non-ROM). rtl/slapstic101.vhdis a faithful port of MAME's decapped type-101 (src/mame/atari/slapstic.{cpp,h}, Aaron Giles & Frank Palazzolo). The key insight: it must see the full 16-bit address on every 6809 bus cycle — not just the$8000-$9FFFwindow — so it catches the out-of-range$FFFFdummy cycle that the alternate sequence pivots on. The earlier in-range-only implementation could never do this. GHDL-verified (11/11, including the negative case), and confirmed working on hardware.- 32 KB slapstic ROM (4 banks × 8 KB) at CPU
$8000-$9FFF; 64 KB Empire main ROM (banked); 32 KB Empire audio ROM. Themod_esbselector inArcade-StarWars.svreadsioctl_index=1— default is Star Wars; the Empire Strikes Back MRA sets it to 1. The Star Wars path is untouched whenmod_esb=0.
⬇️ Everything below is Videodr0me's original Star Wars README, preserved as-is. It documents the upstream Star Wars core (hardware, controls, MiSTer settings, OSD options, ROMs) and applies to both games except where this fork's notes above differ.
An FPGA implementation of Atari's classic 1983 color vector arcade game Star Wars for the MiSTer FPGA platform.
Atari's 1983 Star Wars remains one of the most beloved arcade games ever made. With its glowing wire-frame Death Star trench, digitized voices of Obi-Wan and Darth Vader, and the iconic flight yoke controller, it was the closest thing to climbing into an X-wing cockpit — and for a generation of players, "Use the Force, Luke" still gives them chills.
Hey, Videor0me here! If you're having a blast with this core, consider to
Your contributions show me that there is interest in these arcade projects. With enough support, I'd love to dedicate time to tackle other complex vector games like Tempest and The Empire Strikes Back or to improve the analog vector rendering effects.
The original Star Wars arcade machine (Atari part number 136021) is built from the following major components:
| Subsystem | Original Hardware | FPGA Implementation |
|---|---|---|
| Main + Audio CPU | Motorola MC6809E @ 1.5 MHz | Cavnex mc6809e Verilog core with AVMA/VMA wrapper |
| Math Processor | Custom TTL Mathbox (PROM-sequenced matrix processor, 74LS384 serial multiplier, 15-step restoring divider) | Fully modeled in mathbox.sv |
| Vector Generator | Atari Analog Vector Generator (AVG) with state machine PROM, 10-bit DACs, analog integrators | Digital AVG in avg.vhd driving a raster framebuffer |
| Sound | 4× Atari C012294 POKEY + TI TMS5220 speech synthesizer | POKEY in VHDL + TMS5220 with variable rate (TMS5220C mode) |
| Audio Filters | TL084 quad op-amp low-pass filter + Reticon R5106 delay/reverb line | Modeled in audio_filter_tl084.sv and reticon_r5106.sv |
| Display | Amplifone XY color vector monitor (RGB analog) | 980×700 DDRAM framebuffer, vector_fb_ddram.sv |
| Controls | Custom flight yoke with analog potentiometers (2-axis) | Mapped to MiSTer analog stick inputs |
| Non-volatile RAM | 256 bytes battery-backed NOVRAM (high scores, settings) | Saved to MiSTer SD card via NVRAM system |
Star Wars uses an analog flight yoke. The yoke's X and Y axes are mapped to the primary analog axes of your MiSTer controller.
🕹️ Calibration Tip: The game auto-calibrates to your controller's range. When you first start playing, move the analog stick in a full circle through its extreme positions — this lets the game learn your stick's full range of motion. You can do this at any time, but the stage select screen is the ideal moment.
| Input | Function |
|---|---|
| Analog Stick | Move crosshairs (Pitch / Yaw) — proportional, recommended |
| Fire (Button A) | Fire lasers — also starts the game after inserting coins |
| Shield (Button B) | Shield button |
| Aux Coin (Button Start) | Auxiliary coin input (also used to navigate Test Mode menus) |
| Coin L / Coin R | Insert coins (mapped to R / L by default) |
Tip: The original arcade machine has no "Start" button. After inserting a coin, pressing Fire on the yoke starts the game. An analog stick is strongly recommended for the best experience.
At 720p, the framebuffer maps perfectly the display without scaling and is also best for 4K TVs/Monitors (Aspect Ratio: Optimized or Pixel Perfect). This is the recommended setting and also enables the optional 120Hz mode for ultra-smooth vector rendering.
Append these settings to your MiSTer INI file:
[Star Wars]
video_mode=0 ; 720p 60Hz — 1:1 pixel mapping in optimized and pixel perfect modes. Also ideal for 4K displays.
vsync_adjust=2 ; Low-latency — locks HDMI output to core timing
vscale_mode=0 ; Let the core's auto aspect ratio control scaling
hdmi_limited=0 ; Full range RGB (use 1 for TVs with limited range)
hdr=1 ; HDR output — improves contrast/luminosity
vfilter_default= ; No filters — 720p is pixel-perfect, filtering would blur the vectors
vfilter_vertical_default= ; Override any global vertical filter
vfilter_scanlines_default=; Override any global scanline filter
With these settings, you can also enable 120Hz (720p only) in the core's OSD menu for double the refresh rate. Your display must support 720p @ 120Hz (most modern TVs and monitors do). There is no need to set 120Hz in MiSTer INI.
Tip: The empty filter lines (
vfilter_default=etc.) ensure that any global filters from your[MiSTer]section are overridden. Without them, a globally set bilinear or scanline filter would still apply and blur the crisp vector lines.
At 1080p, the framebuffer is scaled by 1.5×. Because 1.5× scaling means some lines are 1 pixel and others are 2 pixels wide, enabling the bilinear sharp filters is necessary:
[Star Wars]
video_mode=1920,1080,60 ; 1080p output
vsync_adjust=2 ; Low-latency — locks HDMI output to core timing
vscale_mode=0 ; Let the core's auto aspect control scaling
hdmi_limited=0 ; Full range RGB (use 1 for TVs with limited range)
hdr=1 ; HDR output — improves contrast/luminosity
vfilter_default=Upscaling - SharpBilinear/SharpBilinear_100.txt ; Smooth 1.5x vertical scaling
vfilter_vertical_default= ; No additional vertical filter
vfilter_scanlines_default=; No scanline overlay — vectors don't have scanlines
Note: The 120Hz option is automatically disabled and greyed out at resolutions above 720p.
| Option | Description |
|---|---|
| Aspect Ratio | Optimized (recommended) auto-detects HDMI resolution and picks the cleanest scale factor. Pixel Perfect forces 1:1 pixel mapping (980×700 centered). Stretched fills the screen (not recommended). |
| Unbuffered Vectors | When On, bypasses buffering and uses simple double-buffer ping-pong. Fakes a vector look, best used at 120Hz. |
| 120Hz (720p only) | Doubles the refresh rate to ~120Hz. Reduces Frame Pacing Latency and improves the look of Unbuffered Vectors. |
The original Star Wars arcade cabinet features analog audio processing that goes beyond simple DAC output. This core models Filter, Delay and Reverb stages, giving you an authentic stereo audio rendition like never before:
| Option | Default | Description |
|---|---|---|
| TL 084 Filter | On | Models the original TI TL084 quad op-amp low-pass filter on the audio output board. |
| Reticon Del/Rev | On | Models the Reticon R5106 analog delay line used in the original cabinet for spatial reverb effects. Adds a subtle authentic stereo "cockpit echo" to explosions and speech. |
The audio mixing stage models the original summing amplifier (TL084, 1/4 of IC 4C) with per-channel gain based on the schematic resistor values matching the original cabinet's audio balance.
Tip: For the most authentic arcade sound experience, keep both options On. Turning the TL 084 Filter off yields a more modern Hi-Fi flavour of the audio.
The recommended way to change game settings is NOT through the DIP switches, but through the game's built-in Test Mode menu, just like arcade operators did on the original machine:
- Wait for Demo Loop and Open the MiSTer OSD (F12)
- Go to DIP Settings → set Test Mode to On
- Close the OSD — the game enters the game setup / diagnostic screen
- Use the flight yoke (analog stick) to navigate the on-screen menu
- Press Fire to select options
- Configure difficulty, coinage, bonus shields, and other game parameters
- The game saves your settings to NVRAM automatically
- Set Test Mode back to Off in the OSD to return to normal gameplay
Settings changed through Test Mode are preserved in NVRAM alongside your high scores. Don't forget to save the NVRAM or use Auto Save. Auto Saves on entering the F12 Menu. The DIP switches in the OSD can configure starting shields, difficulty, coinage, and other game parameters. However, changing DIPs requires clearing NVRAM, which erases all saved high scores.
*** Attention ***
ROMs are not included. In order to use this arcade core, you need to provide the
correct ROMs.
Quick reference for folders and file placement on your MiSTer SD card:
/_Arcade/Star Wars (Rev 2).mra
/_Arcade/cores/Arcade-StarWars.rbf
/_Arcade/mame/starwars.zip
This core renders vectors as 1-pixel-wide lines on a raster framebuffer. A real Amplifone XY color vector monitor is an analog CRT where a focused electron beam traces each vector directly onto phosphor. Several visual characteristics of the original display are not (yet) reproduced:
| Area | Limitation | Detail |
|---|---|---|
| Vector Rendering | Not cycle-exact | The AVG vector drawer does not run cycle-exact. There might be slight variance in speed compared to original hardware. |
| Bloom & Spot Size | Not modeled | Higher beam current increases the spot diameter, making bright vectors appear wider and softer with a visible luminous halo. |
| Beam Velocity | Not modeled | Perceived brightness is inversely proportional to beam velocity. This core draws all vectors at uniform brightness per Z-level regardless of length. |
| Phosphor Persistence | Not modeled | The P22 phosphor used in color vector CRTs has a visible afterglow decay (~1–10 ms depending on color channel). Moving objects leave fading trails. |
| Beam Overlap | Not modeled | Where two vectors cross or overlap on a real CRT, the phosphor is excited twice, producing additive brightness and enhanced bloom at the intersection. |
| Overdrive & Saturation | Not modeled | Extreme beam current events (e.g., the Death Star explosion) overdrive the CRT — the spot blooms dramatically, colors shift toward white, creating a diffuse full-screen glow. |
| Intensity | Limited Z-level support | The current implementation uses a simplified intensity mapping with fewer effective levels. |
The project uses Quartus Prime Lite targeting the Cyclone V on the Terasic DE10-Nano.
- Open
Arcade-StarWars.qpfin Quartus - Run the full compilation flow (Analysis → Fitter → Assembler → Timing)
- The output
Arcade-StarWars.rbfis generated inoutput_files/
The sys/ directory contains the standard MiSTer framework. All core-specific RTL is in rtl/.
- Original Game: Mike Hally (project lead), Greg Rivera & Norm Avellar (programming), Jed Margolin (hardware engineering), Ed Rotberg (original concept) — Atari, 1983
- Upstream: Videodr0me/Arcade-StarWars_MiSTer — the entire MiSTer port this fork builds on
- Initial FPGA Foundation: Jeroen Domburg (Black Widow MiSTer core)
- 6809 CPU Core: Greg Miller (Cavnex mc6809e)
- MiSTer Platform: Sorgelig and the MiSTer community
This project is provided for educational and personal use. See individual source files for their respective licenses.