Konami's Gaiapolis (1993, GX123 "pre-GX" hardware) for the MiSTer FPGA platform.
This is a MiSTer platform layer around the Gaiapolis core that plasticbugs wrote for the
Analogue Pocket (analogue-pocket-gaiapolis):
the whole machine is theirs and is used here (rtl/) with two changes, the raster timing option
described under "Video timing" below and the sound-chip fixes under "Sound" -- the 68000 and the Z80
sound board with its two K054539s, the ER5911 EEPROM, the K054000, and the video chain
(K056832 tilemaps, K053936 rotating plane, K053247 sprites, K055555 mixer), pixel-exact
against MAME in their verification. What is new here is everything around it: the memories,
clocks, video, audio, controls and ROM/NVRAM loading through the MiSTer framework
(Gaiapolis.sv, target/mister/, rtl/pll*, mra/).
No ROMs or other copyrighted data are in this repository; you supply your own MAME gaiapols.zip.
Tested on a real MiSTer, and it works, on a CRT screen and, in direct video, through a RetroTINK 4K.
Flip Screen (added in gaiapolis_20261005.rbf) and the Video timing option (gaiapolis_20261008.rbf)
have been tried on the board too, both timings, and so have CRT Adjust and the sound fixes
(gaiapolis_20261010.rbf). The Scandoubler Fx / forced scandoubler fix (gaiapolis_20261011.rbf) was
tried on the setup of the user who reported the problem, and it fixed it. Fast loading and the Scale option
(gaiapolis_20261014.rbf) have been run on the board by the repository owner and work (what they do, and what was
checked in simulation, is under "Fast loading" and "Scale" below). The rotating background's colour fix
(gaiapolis_20261023.rbf: the dark squares on the world map) has been run on the board by the repository owner too:
the squares are gone and nothing else looks worse (see "World map colours" below). So has the Colours option
(gaiapolis_20261024.rbf: the board's video DAC curve, the default), which matches the PCB footage (see "Colours" below).
Known issues:
- The open items inherited from the Pocket core (see "Differences from the Pocket core").
What was checked before the hardware tests, in simulation and in the Quartus tool flow:
sim/run_mem.sh: the new memory subsystem against behavioural SDRAM and Avalon DDR3 models -- loader, every region through every port, caches, tile RAM, all ports under contention, built-in memory test. 0 errors. (details:docs/mister-memory.md)sim/emu/run_emu.sh: the real MiSTer top level (Gaiapolis.sv, with onlyhps_ioand the PLL stubbed) with the full 20 MB image streamed in through the ioctl port, the EEPROM default after it, then the built-in memory test at full size and 260 frames of the machine running. All seven regions read back correct and stable, the tile RAM is ok, no render line overran, the DDR3 write queue never overflowed, the rotated frame buffer in DDR3 is exactly the picture turned a quarter clockwise (every pixel, over 25 million frame-buffer writes against a DDR3 model that pushes back), and the EEPROM reads back through the save path. (sim/emu/decode_overlay.pyreads the overlay out of a captured frame.)sim/run_flip.sh: Flip Screen's frame buffers behind the DDR3 arbiter, against a DDR3 model with randomBUSY, a synthetic raster,screen_rotate's writes and a random memory client as competing traffic, with the option switched on and off at random points inside frames. Every visible pixel of every frame is checked (turned 180 degrees from the frame before, or unchanged), and so is every beat the client reads. 0 errors, at DDR3 latencies of 8 to 100 clocks and up to 50 %BUSY.sim/emu/run_emu.shwithPROBE=1 FLIP=1 NOLOAD=1checks the same on the real top level: the picture the scaler gets is exactly the overlay turned 180 degrees, a frame late, and the rotated frame buffer still matches it.sim/emu/run_emu.shwith CRT Adjust (CRT=1 HSIZE=.. HPOS=.. VSHIFT=..): at zero amounts the picture and its geometry (rows, start of each row, width, the first row's distance from the vsync pulse) are those of the unadjusted output, byte for byte, with both timings; each amount moves or stretches the picture by exactly what it says, the picture's 376 x 224 pixels unchanged; Flip Screen and the rotated frame buffer still match.sim/emu/run_sd.sh: the real raster (gaia_video.sv, one pixel in twelve clocks) into the framework'sarcade_video, which is where the scandoubler lives, with Scandoubler Fx or the forced scandoubler on. Per frame it checks the vertical sync, the lines (448 picture rows of 376 pixels, 526 lines at 31.5 kHz), the frame period, and that each source line comes out twice, in order. Before thehdefix it showed no vertical sync at all; the 15 kHz run is the same as before (263 lines, 224 rows).- Fast loading (
gaiapolis_20261014):sim/emu/run_emu.shwithFAST=1models the HPS side of the MRA'saddress=attribute on the whole top level: the image is replayed from the DDR3 in 0.73 s at 96 MHz (the loader's rate is the limit) and every one of its 10,158,080 words is where the ports read it, 0 wrong, with frames, timing, the rotated frame buffer and the EEPROM as in a streamed load.sim/run_mem.shreplays it intogaia_memwith the DDR3 pushing back and the ROZ regions poisoned first: 0 wrong words, the memory test's sums equal to the image's, and the same after a download that starts part-way through the replay. - Scale:
sim/emu/run_emu.shwithSCALE= AR= HW= HH=(video path only) compares the size the core asks the scaler for with the framework's integer rule worked out in the bench from the picture's rows and width: 18 runs, none off. With Orientation Horz: Normal, V-Integer, HV-Integer, Narrower and HV-Integer+ at 1920 x 1080 (aspect Original), HV-Integer with Full Screen and with ARC1, HV-Integer+ with Full Screen and with CRT Adjust on, HV-Integer with the forced scandoubler (448 rows), Narrower at 1280 x 720, HV-Integer+ at 3840 x 2160, at 200 x 150 and in direct video (the scaler's size unknown). Turned (Vert, the default), with Scale on Normal, HV-Integer+, and HV-Integer with Full Screen, and with ARC1: the aspect ratio passes through as before (Scale has no effect), and the rotated frame buffer matches the picture pixel for pixel withvideo_freakin the path. - World map colours (
gaiapolis_20261023): the Pocket repository's frozen-state ROZ bench (sim/run_roz.shthere, 24 MAME states, the RTL against the reference renderer pixel for pixel) passes with the reference renderer reading the colour nibbles the new way; read MAME's way it differs in 19 of the 24 ROZ layers. In the finished frames the change shows only in the intro's flight over the land (21 to 5,014 pixels of a frame, all on colour edges); a player select state and the stage states are unchanged. The whole top level with a fast load runs as before. - Colours (
gaiapolis_20261024):sim/emu/run_emu.shrun twice, with Colours on Board DAC and withCOLOURS_MAME=1, andsim/emu/dac_check.pyon the two pictures: every pixel of the Board DAC picture is the MAME run's pixel looked up in the table, at the same place (0 of 252,672 channel values off), with the picture's geometry, the frame timing and the rotated frame buffer the same in both runs. The table (rtl/data/k054573_dac.hex, fromtools/make_dac_table.py) is, value for value, the MiSTer gamma file that was tried on the board first. sim/run_system.sh: the whole machine from reset with the real ROM set through that memory subsystem, 1,500 frames. It boots through the self-test (the 68000's wait loop runs 19,287 iterations a frame where MAME's is 19,314; the PCM checksum through both K054539s from the SDRAM completes at frame ~915 as in MAME's trace) into the game's intro -- sunset clouds, the bird sprite, "CREDIT 000" -- with the vblank handler running from frame ~1312, no render line overrun in any frame, no unsupported mode, and 25 s of non-silent audio. (That run was of the revision before the ROZ-map lookup was pipelined by one clock and the machine reset registered, both covered bysim/run_mem.shand the end-to-end run, which use the final RTL. It has not yet reached the ROZ-heavy scenes, character select and the stages: those were checked against the DDR3 latency instead, indocs/mister-memory.md.)- Quartus Prime Lite 17.0.2 (MiSTer's toolchain) compiles the project for the 5CSEBA6U23I7:
49 % of the ALMs, 71 % of the block RAM (532 of 553 blocks, so there is almost none left), 65 DSPs, and
timing closes at 96 MHz with every check positive (
gaiapolis_20261024: setup +0.15 ns, hold +0.24, recovery +1.66, removal +2.22 in the slow 100 C model,releases/gaiapolis_20261024.sta.summary;gaiapolis_20261023: setup +0.36;gaiapolis_20261014: setup +0.11;gaiapolis_20261011: setup +0.36;gaiapolis_20261010: setup +0.40;gaiapolis_20261008: setup +0.19;gaiapolis_20261005: setup +0.26; the first build,gaiapolis_20261004: setup +0.71). The fitter seed matters:gaiapolis_20261024was built with seed 2 (the seed inGaiapolis.qsf, 1, closed too, setup +0.09 ns),gaiapolis_20261023closes with the seed inGaiapolis.qsf(1) and missed with seed 2 (by 0.08 ns),gaiapolis_20261014closed with seeds 1 and 2 (seed 2 setup +0.18 ns),gaiapolis_20261011closed with seed 1 and missed with seed 2 (by 0.24 ns),gaiapolis_20261010closed with seeds 1 and 2, and the sound change on its own, without CRT Adjust, missed with seeds 1 and 3 (by 0.03 and 0.48 ns) and closed with seed 2.
- Download the newest RBF in
releases/(gaiapolis_20261024.rbf, with Flip Screen, Video timing, CRT Adjust, the sound fixes, the scandoubler fix, fast loading, Scale, the world map colour fix and the Colours option) and the three.mrafiles frommra/(or clone this repository). Put the RBF in/media/fat/_Arcade/cores/and the MRAs in/media/fat/_Arcade/. Keep the RBF'sgaiapolis_name and date: MiSTer finds the core by the MRA's<rbf>name plus the date, and takes the newest if there are several. The earlier builds stay inreleases/(gaiapolis_20261004.rbfis the first, without Flip Screen;gaiapolis_20261005.rbfadds Flip Screen and runs MAME's 59.19 Hz timing only;gaiapolis_20261008.rbfadds the Video timing option;gaiapolis_20261010.rbfadds CRT Adjust and the sound fixes; none of the four has a vertical sync with the scandoubler on, whichgaiapolis_20261011.rbffixes;gaiapolis_20261014.rbfadds fast loading and Scale;gaiapolis_20261023.rbffixes the colours of the rotating background, the world map's dark squares;gaiapolis_20261024.rbfadds the Colours option). The three.mrafiles carry theaddress=attribute that fast loading needs, and (the update of 2026-10-21,Gaiapolis_MiSTer_20261021.zip, with the same RBF) the button names Attack / Beast / Magic: use the ones from this repository or the newest zip, not older copies. - Put your MAME 0.289
gaiapols.zipin/media/fat/games/mame/(the parent set; the Japan and USA versions' ROMs are in the merged set, or ingaiapolsj.zip/gaiapolsu.zipnext to it). No ROMs are distributed here. - Start
Gaiapolis (World ver EAF)from the Arcade menu. The ROM image is 20 MB. With a recent Main_MiSTer (one that knows the MRA'saddress=attribute) it is copied to the DDR3 in one go and loaded in about a second; an older one streams it through the HPS port, as before, which takes far longer (see "Fast loading").
| Option | Values | |
|---|---|---|
| Aspect ratio | Original, Full Screen, [ARC1], [ARC2] | Original is 3:4 when rotated (Vert) and 4:3 when not; ARC1 / ARC2 are the custom ratios from MiSTer.ini |
| Scale | Normal, V-Integer, HV-Integer, Narrower HV-Integer, HV-Integer+ | Integer scaling for the HDMI scaler (the framework's video_freak; the 15 kHz analog output is not touched). Normal leaves the picture's size to the scaler. Shown with Orientation Horz only: turned through the frame buffer (Vert, the default) the picture stays Normal. See "Scale" below |
| Orientation | Vert, Horz | Not shown in direct video (see below). Vert: rotated for a monitor on its side (the frame buffer in DDR3, the framework's screen_rotate). Horz: the native raster |
| Rotation | CW, CCW | Not shown in direct video (see below). Which way Vert turns the picture, if your screen wants it the other way |
| Flip Screen | Off, On | The picture turned 180 degrees, on every output (analog, direct video, HDMI). Done on the finished picture through a frame buffer in the DDR3, so it adds one frame (16 ms) of delay while it is on and nothing when it is off. See below |
| Video timing | Board 59.88Hz, MAME 59.19Hz | The raster's size and sync widths. Board (the default) is what the board's K053252 timing chip produces from the values the game programs into it; MAME is MAME's fixed 512 x 264. See "Video timing" below. Takes effect at the next frame |
| Colours | Board DAC, MAME | Board DAC (the default) puts R, G and B through the curve of the board's video DAC, darker mid tones as on a real board; MAME is the palette as it is, as MAME shows it (and every build before gaiapolis_20261024). On every output. Switch MiSTer's own gamma correction off with Board DAC. See "Colours" below |
| Scandoubler Fx | None, HQ2x, CRT 25%, CRT 50%, CRT 75% | |
| CRT Adjust | submenu: CRT Adjust Off, On; then CRT H-Size 0..+8 / -16..-1, CRT H-Position -48..+28, CRT V-Shift -16..+15 | Fits the picture to a 15 kHz analog (CRT) output: its width, its place in the line and its place in the frame, without the monitor losing sync. Does nothing while the scandoubler is in use. Off by default. See "CRT Adjust" below |
| Test Mode | Off, On | The board's test switch: the game's service menu |
| Audio | Stereo, Mono | The board's mono/stereo input; Mono puts the left mix on both channels |
| Diagnostic overlay | Off, On | Three rows of 32 squares along the bottom of the picture, and the built-in memory test (a few seconds, black screen) after each ROM load |
| SDRAM read capture | Normal, Late | Late samples SDRAM reads one clock later, for a module that answers slowly; try it if the picture is garbage and the overlay shows the SDRAM regions red |
| Reset | Restarts the machine (the ROM stays loaded) |
Where Orientation and Rotation apply, by output:
- HDMI through MiSTer's scaler (the default): the items are shown. Vert (the default) turns the picture for a monitor on its side, and Rotation picks the direction. (Not yet tried on hardware: the tester used direct video.)
- Analog VGA / RGB (a CRT): the picture is the core's native raster, straight from the core, and the
items change nothing there (a CRT on its side needs no rotation). With
vga_scaler=1inMiSTer.inithe analog output comes through the scaler and follows the items like HDMI. - Direct video (
direct_video=1, e.g. a RetroTINK 4K in DV1 mode): the picture bypasses the scaler and its frame buffer, which is what does the rotating, so the core sends the raw unrotated raster and the two items are hidden. The device on the other end turns the picture, from the game direction MiSTer reports (the MRA's<rotation>vertical (cw)</rotation>).
Controls: joystick or gamepad for both players -- three buttons, Start and Coin each, named in MiSTer's button mapping menu by what they do (the names come from the MRA): Attack (the weapon), Beast (order the beast that an egg gives you to attack, or call it back) and Magic (cast the magic that crystals have charged). All three are used by the game; none is a spare. On a gamepad the default mapping is A / B / R for Attack / Beast / Magic, Start for Start and Select for Coin (remap it in MiSTer's usual way). From the keyboard: 1 / 2 start, 5 / 6 coin and F2 for the test switch, on top of MiSTer's usual keyboard-as-joystick. The game's own settings and high scores live in its EEPROM, which MiSTer saves and restores.
Scandoubler Fx and MiSTer.ini's forced_scandoubler make the core's 15 kHz picture a 31 kHz one (every line
twice; HQ2x and the CRT filters on top). In every build up to and including gaiapolis_20261010 they gave no
vertical sync at all: the monitor, or the HDMI scaler, saw a stream without frames and showed a frozen picture (reported on a
1080p vertical monitor: sound, a frozen picture, and 31.5 kHz in MiSTer's video info). Fixed in gaiapolis_20261011: the framework's
scandoubler takes its line timing from the horizontal blank's edges and needs them on every line, vertical
blanking included, and this core's blank was the picture window, high through the whole vertical blank. The core
now gives it the horizontal blank alone (hde from gaia_video.sv) with the vertical blank separate. With
the 15 kHz output, the picture, and its timing, are as they were.
Flip Screen is not the game's own flip setting. That setting only asks the video chips to flip, and
the Pocket core's renderers do not implement a global flip (it is on the list of unsupported modes in
rtl/k056832_tilemap.sv), so wiring the OSD option to it would leave the picture unchanged or
half flipped. Instead the finished picture is turned 180 degrees in target/mister/flip_buf.sv: each
frame is written to a frame buffer in the DDR3 and the next frame is shown from it, read backwards. The
controls are not flipped. Switching it on or off never shows half a frame: the first frame after
switching on is shown as it is, the second is the first flipped one. It is checked pixel for pixel in
simulation (sim/run_flip.sh, and sim/emu/run_emu.sh with PROBE=1 FLIP=1 NOLOAD=1).
CRT Adjust fits the picture to a CRT. It is rmonic79's MiSTer-CRT-Adjust
(modules/crt-adjust), used the way their other cores use it: the picture goes through a line buffer
and only the picture moves, never the sync pulses' rate, so the monitor keeps its lock while you adjust.
Switch CRT Adjust on and the three amounts appear:
- CRT H-Size (0..+8, -16..-1): the width of the picture. Each step is about 2 % (a pixel lasts a quarter of a clock longer or shorter; 12 clocks is the normal pixel); plus is wider, minus is narrower.
- CRT H-Position (-48..+28): the picture's place in the line, in pixels. Plus is right.
- CRT V-Shift (-16..+15): the picture's place in the frame, in lines (the vertical sync is moved the other way). Plus is down.
Things to know:
-
It is for the 15 kHz analog output (and direct video). With Scandoubler Fx on, or the framework's
forced_scandoubler(31 kHz VGA), there is nothing to adjust and the options do nothing. -
The picture is 376 pixels in a line of 508 (512 with MAME timing): it starts 104 pixels after the hsync pulse and ends 28 before the next one. So it cannot go further right than +28 pixels, and making it wider uses that room up: without moving it, +2 is the most that fits; moved to -48, +8 is. Past that the right edge is cut off. (Moving the picture left costs nothing until it reaches the end of the hsync pulse.)
-
Nothing of the picture is shown during the hsync pulse, so a setting that would push part of it there loses that part rather than breaking the line.
-
Switching it off puts the picture back on the path it always had. The picture itself is not changed in either case, only where and how wide it is drawn: with the options at 0 the picture, its size and its place in the line and the frame are exactly those of the unadjusted output.
-
The OSD menu is placed from the start of the picture, so expect it to move with the picture.
-
Tried on a CRT: it works. Video timing. MAME runs this game on a fixed 512 x 264 raster (15.625 kHz, 59.1856 Hz) that ignores the values the game writes into the K053252 timing chip. The board's chip produces something slightly different, and the default here follows it:
-
The schematic of the board (PWB353396A, Franck78's) shows the K053252's clock pin wired to the 32 MHz output of the oscillator module, and its three SEL pins tied to ground: it divides by 4, an 8 MHz pixel clock.
-
The game programs a horizontal count of 0x1FB and a vertical count of 0x106 (and the porches and sync widths in the other registers) at boot. SiliconRE's model of the chip, traced from the silicon, turns those into 508 x 263 clocks: 15.748 kHz and 59.88 Hz, with a 48-pixel hsync and an 8-line vsync (MAME's raster has 32 pixels and 3 lines).
-
The visible 376 x 224 picture, its origin and everything the renderers see are the same in both. The game's logic is locked to the vertical interrupt, so on the board it runs about 1.2 % faster than in MAME; the sound, which has its own clocks, does not.
The option is read at the start of each frame, so it can be switched while playing. The part of this that cannot be checked without the real board is the exact phase of the vertical interrupt inside the chip's 386 x 225 active window; it stays at the end of the visible picture, as in MAME.
Sound. The two K054539 PCM chips were compared with MAME's: a 130-second attract-mode run of gaiapols
in MAME 0.289, with every Z80 write to both chips logged, replayed through this core's chips and compared
with MAME's own audio second by second. The Pocket core's chip had a median correlation of 0.915 (31 of
the 68 sounding seconds below 0.9). Four differences from MAME's chip, fixed in rtl/k054539.sv, bring it
to 0.964 (one second below 0.9), and the fixed chip agrees with a line-by-line transcription of MAME's
k054539.cpp:
- a 16-bit PCM sample steps two bytes at a time and is read from whatever address the channel has, aligned or not (the core forced an even address, which an odd start address, common in this game's music, broke);
- MAME's
UPDATE_AT_KEYON: while register 0x22f bit 0 is set, writes to a channel's position registers (0x0c-0x0e) are held and only copied in by that channel's key-on, so a note programmed while the last one still sounds no longer restarts it at once (a burst of noise); key-on and key-off are gated by bit 7; - the reverb ring's index adds the position twice, as MAME does;
- in
rtl/gaia_sound.sv, the sum of the two chips saturates instead of wrapping, as MAME's mixer clips.
The left and right channels changed side. MAME routes each chip's output 0 to the right speaker and
output 1 to the left (mystwarr.cpp's "stereo channels are inverted", which gaiapols uses too), and the
comparison confirms it (0.97 correlation with the swap, 0.4-0.66 without). The core used the other
order in every build before gaiapolis_20261010, so a panned sound now comes out of the opposite speaker. Audio Mono
still puts the left mix on both channels.
The whole-machine bench is silent for its first 110 frames, so these fixes were checked against MAME's audio at the chip level, not in the full machine's simulation, and then on the board.
Fast loading. The three MRAs carry address="0x32000000" on the ROM image's <rom>. A recent
Main_MiSTer then does not stream the 20 MB image through the HPS port a byte at a time but copies the
assembled image into the DDR3 in one go and ends a download that has no data, only a start address:
the image's length. The core stays in reset, reads the image back from the DDR3 in 256-byte blocks
(target/mister/gaia_mem.sv; byte 0x32000000, clear of the ROZ memories, the Flip Screen buffers and the rotated
frame buffer) and pushes the words into the same loader FIFO the streamed bytes go through, so the memory layout,
the cache sweep and the memory test behave as before (the memory test is handed the replayed bytes too, so its sums
are the image's). A Main_MiSTer that does not know the attribute streams the bytes as before (ioctl_addr is 0 at
the start of such a download, which is how the two are told apart), so one RBF and one set of MRAs serve both. To
see which of the two you got, switch on the Diagnostic overlay: the download square (row 0, 11th from the left)
is lit for about a second with fast loading and for the whole, much longer streamed load without. How it works:
docs/mister-memory.md, "Fast load".
Scale. Normal, V-Integer, HV-Integer, Narrower HV-Integer and HV-Integer+: the framework's video_freak after
arcade_video, for the HDMI scaler, which gets an exact size in pixels instead of the aspect ratio (the 15 kHz
analog output is not affected). It works from the finished picture (the scandoubler and CRT Adjust included) and
the scaler's own output size; with Scale on Normal VIDEO_ARX / VIDEO_ARY are what they were. Full Screen with an
integer Scale is given the screen's own proportions, since Full Screen has none for the integer rule to work from.
It acts with Orientation Horz only, and the menu entry is hidden with Vert: with the picture turned through
the DDR3 frame buffer the scaler shows that buffer, which video_freak does not know about, so the sizes it would work
out would be those of the unturned picture. Integer scaling of the turned picture is not there yet.
World map colours. The world map between stages showed dark squares and lighter or pink blocks next to the place
names and route lines (NEOMOSC, TURAN, ...). MAME shows the same (MAME Testers issue 00231 reported "black blocks in the
map" in 2008 and suspected a bad dump of the ROZ ROMs), and every build of this core up to gaiapolis_20261014
copied it. The ROMs are fine: the rotating background layer (the K053936 ROZ plane) takes each tile's palette from
the map ROM, where one byte holds the palette numbers of two neighbouring tiles, one per half-byte, and MAME's
get_gai_936_tile_info (the reference the Pocket core was written against) gives the even tile the high half and
the odd tile the low one. It is the other way round. That only shows where the colour changes between the two tiles
of a byte -- on the map, the edge of every label and route, and a route that is not yet lit has a dark palette,
hence the dark squares. Read the other way, every label and route of the map is one clean run of its own colour
with plain land around it (88 stray tiles on the world map before, none after; elsewhere in the map ROM the new
order is as clean or cleaner). A recording of a real board (a 1CC run, "Gaiapolis - Prince 10,102 - No Elixir 1CC
[PCB]") confirms it: its map has no squares, and in the intro's flight over the forest it shows a green crater, grass
and stone posts where MAME's order draws a red crater, a brown log and white streaks along the grass. Fixed in
rtl/k053936_roz.sv (one line); gaiapolis_20261023 is the first build with it. Tried on the board: the squares
are gone and nothing else looks worse.
Colours. A real board's picture has darker mid tones than MAME's. MAME shows the palette as straight 8-bit values, which is what the colour chip computes, and the PCB recording above fits no straight line. The difference is in the video DAC:
- The chain, from Franck78's schematic of this board: the K054338 colour chip (18F) puts 8-bit R, G and B on its pins, straight into three Konami K054573 DAC modules (U71 red, U77 green, U72 blue). Its 8-bit brightness output goes to a K054574 (U79), whose three outputs set the current each 054573 runs on. SiliconRE's trace of the 054338's silicon shows plain integer arithmetic inside (blending, shadows) and no table or curve, so the curve can only be in the DAC. Its brightness code 0 is wired to 0xFF, and that is the only level Gaiapolis selects, so the DACs run at one fixed current through the whole game.
- The 054573 is a small sealed module. Traced from the Gerbers and BOM of Ace's reproduction of it (UKVAC): each data bit drives an open-collector buffer (74LS07) that, while the bit is 0, pulls one summing node down through its own resistor (49k, 24k, 12k, 6k, 3.1k, 1.7k, 800R and 380R for D0..D7); the node is fed by the brightness current and has 1.2k to ground, and two diodes and an emitter follower take it to the output. That is a conductance divider, not a resistor ladder: the voltage is the current divided by the conductance of the bits that are 0, which rises faster towards the top, so mid tones come out darker than a linear DAC gives.
- Solving that circuit for every code, with the brightness current as the one free value, fits the PCB recording's title screen to 0.7 of 255 (rms over its colours, each channel with the capture's own gain and offset); a straight line, MAME's, is 10.5 off, and the best plain gamma curve 1.9. With the current from that fit it also predicts the colours of the intro's grass, path and clouds to within a few levels.
- Board DAC maps code 0 to black and 0xEF, the brightest value the game writes, to full white, with the circuit's curve
in between (0x40 becomes 26, 0x80 74, 0xC0 151).
tools/make_dac_table.pyholds the model and writes the table (rtl/data/k054573_dac.hex); inGaiapolis.svit sits right after the mixer, before the diagnostic overlay, Flip Screen, CRT Adjust and the scaler, so every output gets it. Tried on the board: it matches the PCB footage.
It is a model, not a measurement: the resistor values are the repro's (the original modules are sealed), the transistors and diodes generic, and the one free value comes from a video capture whose own levels are not known. The shape is the circuit's, the scale the footage's; an oscilloscope on a real board's RGB output would settle it. Switch MiSTer's own gamma correction (Video processing) off with Board DAC, or the curve is applied twice; with Colours on MAME a MiSTer gamma file can still be used.
The core's ports are the same; what sits behind them is not, because MiSTer has no PSRAM or
SRAM. The programs moved to the SDRAM behind caches, the ROZ plane's memory to the DDR3, the
tile RAM to block RAM. The reasoning and the numbers are in docs/mister-memory.md.
The ROZ plane's colour nibbles are read the other way round from the Pocket core (and MAME): see "World map
colours" above. The colours go through the board's DAC curve by default (the Colours option, in Gaiapolis.sv;
the Pocket core shows the palette as MAME does): see "Colours" above.
Open items inherited from the Pocket core (its README): the ROZ plane's lead when the game writes its registers late in vblank; a dozen frames of dropped tilemap lines at the start of the intro after a new game on the Pocket's memories (the MiSTer SDRAM carries far less of the line, so this should not occur here -- not yet measured on the board); two shadow objects on one pixel; and the attract intro running longer than MAME's before the music.
| Path | |
|---|---|
Gaiapolis.sv, Gaiapolis.q*, Gaiapolis.sdc, files.qip |
the MiSTer top level (emu), Quartus project, timing constraints |
target/mister/ |
the memory subsystem (gaia_mem, rom_cache, ddr_arb), SDRAM controller, memory test |
rtl/ |
the Gaiapolis machine, the Pocket core's apart from the raster timing option and the hde output (the horizontal blank alone) in gaia_video.sv and gaia_core.sv, and the sound fixes in k054539.sv and gaia_sound.sv (rtl/data/ generated tables, rtl/pll* the clock PLL) |
modules/ |
vendored TG68K.C, tv80 and CRT Adjust (modules/VENDOR.md) |
sys/ |
the MiSTer framework (identical to Template_MiSTer) |
mra/ |
the three MRAs, generated by tools/make_mra.py |
releases/ |
the tested RBF, with its timing and fitter summaries |
sim/ |
Verilator benches: memory subsystem, whole machine, and the MiSTer top level end to end |
docs/mister-memory.md |
the memory design: partition, caches, timing, latency sweep, build results |
tools/ |
MRA generator and builder, the Board DAC table's generator (the 054573 model), PNG helpers for the benches |
Quartus Prime Lite 17.0.2 (the version MiSTer's framework is built with):
quartus_sh --flow compile Gaiapolis
tools/make_mra.py gaiapols.zip regenerates the MRAs.
The simulation benches need Verilator 5 and a C++ compiler, and a ROM image you build yourself from
your own romset with tools/mra_build.py (it checks every part's CRC and the image's md5):
python tools/mra_build.py "mra/Gaiapolis (World ver EAF).mra" gaiapols.zip gaiapols.rom # 20,316,160 bytes
sim/emu/run_emu.sh gaiapols.rom gaiapols.nv [frames]takes that image as is, plus the 128-bytegaiapols.nvfrom the romset (the EEPROM default).sim/run_mem.sh <image>andsim/run_system.sh <image> [frames]want the same image with the 128-bytegaiapols.nvappended (the Pocket layout, 20,316,288 bytes).
Run the benches from a Linux filesystem (WSL's own, not /mnt/c); the full-system bench simulates
at about a quarter of a MHz, so a thousand frames takes hours.
- plasticbugs -- the Gaiapolis core for the Analogue Pocket (the machine,
rtl/; the SDRAM controllertarget/mister/sdram_ctrl.svand the memory testmem_test.sv, adapted;tools/mra_build.py), and through it the MAME team's work as the reference, Tobias Gubener's TG68K.C (LGPL-3.0) and Guy Hutchison's tv80 (MIT), vendored undermodules/. - Claude (Anthropic's AI model, used through Claude Code) -- the MiSTer layer, written together with the repository owner: the memory subsystem, video, audio and controls, the MRAs, the simulation benches and this documentation. The hardware testing is the owner's.
- Sorgelig and the MiSTer team -- the framework (
sys/, GPL). - The K054539 and mixer fixes were worked out and checked against MAME in another core of the repository owner's that uses the same chip, and brought over here.
- rmonic79 (Umberto Parisi), with help from Andrea Bogazzi (asturur) --
MiSTer-CRT-Adjust, the module behind the CRT Adjust options
(
modules/crt-adjust/crt_adjust.sv, with a one-line sign fix noted inmodules/VENDOR.md; GPL-3.0 or later). - furrtek -- SiliconRE's silicon-traced model of the K053252 timing chip, and Franck78 -- the Konami Gaiapolis schematic of the board (PWB353396A). Together they are the basis of the board video timing (the "Video timing" option): the chip's behaviour from the first, how it is clocked and wired on this board from the second. SiliconRE's K054338 trace and the same schematic's video DAC chain are, with Ace's Gerbers and BOM of the K054573 / K054574 reproductions, the basis of the Colours option.
- Jose Tejada (jotego) -- JTFRAME's MiSTer SDRAM clock phase and read-capture timing, which this core's PLL and controller settings follow.
GPL-3.0, as the Pocket core this is built on (see LICENSE). The vendored TG68K.C (LGPL-3.0), CRT Adjust (GPL-3.0 or later) and
tv80 (MIT) in modules/ keep their own licences (modules/VENDOR.md), and the MiSTer framework in sys/
is GPL (see the headers of its files).