FPGA core of the IGS PGM2 arcade board (2007 - 2011: IGS036 ARM9 CPU with an encrypted program ROM, IGS037 video, Yamaha
YMZ774 sound) for the MiSTer. Written from MAME 0.289's pgm2 driver; MAME was the oracle for everything (the CPU's view of
the machine, the video chip's memories, the sound chip's samples, the IC card traffic), and the result is checked against it
in simulation and on a real MiSTer. It runs all five games MAME runs, in all 21 versions MAME 0.289 knows. No ROMs or other
copyrighted data are in this repository: you supply your own MAME 0.289 romsets. Needs the 128 MB SDRAM module.
The five games' title screens, as MAME 0.289 draws them (to show what kind of games these are).
![]() |
![]() |
| Oriental Legend 2 (2007) | Knights of Valour 2 New Legend (2008) |
![]() |
![]() |
| Knights of Valour 3 (2011) | The King of Fighters '98 Ultimate Match HERO (2009) |
![]() |
|
| DoDonPachi Dai-Ou-Jou Tamashii (2010, vertical) |
The zip of a release (PGM2_MiSTer_<date>.zip) unpacks over the root of the SD card. By hand:
- Put
releases/_Arcade/cores/PGM2_<date>.rbfin/media/fat/_Arcade/cores/and the contents ofmra/in/media/fat/_Arcade/(the other versions of a title are in_alternatives/_<Title>/). MiSTer finds the core by the MRA's<rbf>name and takes the newest: delete olderPGM2_*.rbffiles. - Put your MAME 0.289 romsets in
/media/fat/games/mame/: the merged sets (every version of a game in the parent's zip), or the split sets together with their parent zip. Each MRA looks for its files by CRC, in the set's own zip first and then in the parent's, so a clone's files are found whatever they are called in the zip. - Start the game from the Arcade menu. With a recent Main_MiSTer the ROM image (138 - 154 MB) loads in a few seconds
(fast loading: the MRAs carry
address="0x32000000", which makes Main_MiSTer copy the whole image into the DDR3 at once, and the core plays it from there into the SDRAM); an older Main_MiSTer ignores the attribute and streams the image, which takes much longer. Use the MRAs of the same release as the core.
| MRA | Set | ROM zips (MAME 0.289) |
|---|---|---|
| Oriental Legend 2 (V104, Oversea) | orleg2 | orleg2 |
| Oriental Legend 2 (V103, Oversea) | orleg2_103 | orleg2_103 + orleg2 |
| Oriental Legend 2 (V101, Oversea) | orleg2_101 | orleg2_101 + orleg2 |
| Xiyou Shi E Zhuan 2 (V104, China) | orleg2_104cn | orleg2_104cn + orleg2 |
| Xiyou Shi E Zhuan 2 (V103, China) | orleg2_103cn | orleg2_103cn + orleg2 |
| Xiyou Shi E Zhuan 2 (V101, China) | orleg2_101cn | orleg2_101cn + orleg2 |
| Saiyuu Shakuyakuden 2 (V104, Japan) | orleg2_104jp | orleg2_104jp + orleg2 |
| Saiyuu Shakuyakuden 2 (V103, Japan) | orleg2_103jp | orleg2_103jp + orleg2 |
| Saiyuu Shakuyakuden 2 (V101, Japan) | orleg2_101jp | orleg2_101jp + orleg2 |
| Knights of Valour 2 New Legend (V302, Oversea) | kov2nl | kov2nl |
| Knights of Valour 2 New Legend (V301, Oversea) | kov2nl_301 | kov2nl_301 + kov2nl |
| Knights of Valour 2 New Legend (V300, Oversea) | kov2nl_300 | kov2nl_300 + kov2nl |
| Sanguo Zhan Ji 2 Gaishi Yingxiong (V302, China) | kov2nl_302cn | kov2nl_302cn + kov2nl |
| Sanguo Zhan Ji 2 Gaishi Yingxiong (V301, China) | kov2nl_301cn | kov2nl_301cn + kov2nl |
| Sanguo Zhan Ji 2 Gaishi Yingxiong (V300, China) | kov2nl_300cn | kov2nl_300cn + kov2nl |
| DoDonPachi Dai-Ou-Jou Tamashii (V201, China) | ddpdojt | ddpdojt |
| Knights of Valour 3 (V104, China, Hong Kong, Taiwan) | kov3 | kov3 |
| Knights of Valour 3 (V102, China, Hong Kong, Taiwan) | kov3_102 | kov3_102 + kov3 |
| Knights of Valour 3 (V101, China, Hong Kong, Taiwan) | kov3_101 | kov3_101 + kov3 |
| Knights of Valour 3 (V100, China, Hong Kong, Taiwan) | kov3_100 | kov3_100 + kov3 |
| The King of Fighters '98 - Ultimate Match HERO (China, V100, 09-08-23) | kof98umh | kof98umh |
The versions of a game differ in the CPU's internal ROM (the region: the WARNING screen's text and language) and the program
ROM; the Knights of Valour 3 versions also in the program module's keys. tools/pgm2_mra.py writes the MRAs from MAME's ROM
lists, and tools/mra_check.py checks every part against the romsets (CRC and size). Not included: Bu Bu Car, which MAME
0.289 does not run either (not fully dumped / decrypted).
Knights of Valour 2 New Legend, Knights of Valour 3 and the Chinese Oriental Legend 2 sets save a player's progress on an IC
card. The cards are files in MAME's format (.pg2, 264 bytes): copy the blank card out of your romset zip
(blank_kov2nl_overseas_card.pg2 in kov2nl.zip, blank_gsyx_china.pg2 for the Chinese kov2nl sets,
blank_kov3_china_card.pg2 in kov3.zip, blank_orleg2_china_card.pg2 for the Chinese Oriental Legend 2 sets) into a
folder named after the game's set name: /media/fat/games/kov2nl/, /media/fat/games/kov3/ (for the alternative versions
their own set name, such as games/kov2nl_302cn/; not games/mame/, which holds the ROM zips). Give it a name of your own
ending in .pg2, and insert it with OSD → IC Cards → Card P1 (P2 - P4 for the other players). The core writes the game's
saves straight back to the file and inserts the card again the next time you start that game; Backspace in the card's file
menu removes it. A card works in MAME too, and MAME's cards work in the core.
| Joystick | directions, buttons A - D, Start, Coin; up to four players |
| Keyboard | 1 - 4 start, 5 - 8 coin, F1 test (service menu), 9 service |
The MRAs give MiSTer each game's names for the buttons (Define buttons asks only for the ones the game uses):
| Game | A | B | C | D |
|---|---|---|---|---|
| Oriental Legend 2, Knights of Valour 2 New Legend, Knights of Valour 3 | Attack | Jump | View Items | Use Items |
| DoDonPachi Dai-Ou-Jou Tamashii | Shoot / Laser (held) | Bomb / Hyper | Auto (shoots while held) | not used |
| The King of Fighters '98 Ultimate Match HERO | Light Punch | Light Kick | Heavy Punch | Heavy Kick |
The names are the games' own where they show them (Oriental Legend 2's HOW TO PLAY, the button screens of Knights of Valour 3 and The King of Fighters '98 after Start), else a player's report, checked in MAME. In Oriental Legend 2 and Knights of Valour 3 Start also shows the equipment during play.
| Option | Values | |
|---|---|---|
| Aspect ratio | Original, Full Screen, [ARC1], [ARC2] | Original is 4:3 |
| Orientation | Vert, Horz | DoDonPachi only: Vert turns the picture upright on the HDMI output through a frame buffer; Horz gives the game's raster as it is (a monitor turned on its side; the analog output is always the raster) |
| Flip Screen | Off, On | every game: the picture turned 180 degrees in the video chip itself |
| Scale | Normal, V-Integer, HV-Integer, Narrower HV-Integer, HV-Integer+ | integer scaling on the HDMI scaler; not shown while DoDonPachi is turned upright |
| Scandoubler Fx | None, HQ2x, CRT 25 / 50 / 75 % | |
| CRT Adjust (a page of its own) | Off / On, H-Size, H-Position, V-Shift | for the 15 kHz analog output, after rmonic79's MiSTer-CRT-Adjust (modules/crt_adjust) |
| DIP switches | per game | the board's switch (Service Mode and the like) |
| IC Cards (a page of its own) | Card P1 - P4 | see IC cards |
| Autosave Backup RAM | On, Off | the battery-backed SRAM (settings, bookkeeping, high scores) is saved to the SD card when the OSD is opened |
| Save Backup RAM | saves it now | |
| Reset | restarts the machine |
The OSD's info line shows "Sound: samples late" if the sound chip ever had to skip a sample (see Status).
Verification. MAME 0.289 is the reference. In simulation (Verilator, the games' real programs, the real memory path):
the video chip renders MAME's states pixel for pixel (hundreds of frames of every game and screen mode, including the sprite
bitmap's DDR3 path and the real SDRAM controller); the whole board boots every set to its WARNING screen as MAME shows it,
and the 16 alternative versions to their own region's screen; the sound chip's output equals an integer model of MAME's
YMZ774 sample for sample on all five games; the IC card reader replays MAME's card sessions byte for byte; the CPU's video
state follows MAME's word for word through long attract demos. docs/ has the details.
On a real MiSTer (the owner's): all five main sets boot and play with picture and sound (HDMI, an RT4K over DV1 and a 15 kHz CRT); fast loading and CRT Adjust were confirmed on the board. The IC card reader and the alternative versions have been checked in simulation only.
Known issues
- DoDonPachi Dai-Ou-Jou Tamashii's busiest scenes need nearly a whole frame of the core's 40 MHz CPU (the real IGS036's clock is unknown; MAME's 100 MHz is a guess): scenes heavier than its attract demo could still slow down.
- Knights of Valour 3 V101: MAME marks its program ROM as a bad dump and runs it with made-up module values; the core uses the same values.
- The board's calendar starts from 0 at every load, as in MAME.
The IGS037 has a 32 x 32 tile background with line scroll, an 8 x 8 tile text layer and a sprite engine that draws the
sprite list into a bitmap at vblank, shown one frame later, as MAME does it. The core keeps the two sprite bitmaps in the
HPS DDR3 (rtl/pgm2_bitmap.sv) and fetches each row just before it is shown. Three screen modes: 448 x 224 (Oriental Legend 2,
Knights of Valour 2 New Legend, DoDonPachi), 512 x 240 (Knights of Valour 3) and 320 x 240 (King of Fighters '98 UMH), on a
15.6 kHz raster (59.2 Hz; 59.1 Hz in the 320 mode) that a CRT takes as it is.
Sound: the YMZ774 decodes the games' MPEG-like AMM sample streams in hardware (rtl/ymz_dec.sv) for 16 voices with its
sequencers, volume and pan, mixed to 44.1 kHz stereo (the chip's equaliser is not emulated, as in MAME). The sample ROM
(16 / 32 MB) is in the DDR3 behind a small cache.
Quartus Prime Lite 17.0 (the version MiSTer's framework needs):
quartus_sh --flow compile PGM2 -> output_files/PGM2.rbf
Rename the RBF to PGM2_<date>.rbf. The design runs at 40 MHz (the system and the CPU) and 80 MHz (the SDRAM); the timing of
each release was checked in all four corner models. tools/package.py <date> writes the release zip (the SD card structure)
from releases/ and mra/.
The ARM core is Chisel (cpu/gamebub-arm); its generated SystemVerilog is in cpu/generated/ (tools/build_cpu.sh
regenerates it, which needs JDK 17 and sbt).
Verilator benches in sim/, driven by the Python scripts in tools/ (run in WSL, with mister/ as the working directory:
the sound chip loads its tables with $readmemh("rtl/ymz_*.mem")):
| Bench | What it runs |
|---|---|
tools/bench_video.py (sim/tb_igs037.cpp) |
the video chip on MAME's frozen states, pixels compared with MAME's |
tools/bench_igs_sd.sh (sim/tb_igs_sd.cpp) |
the video chip with the real SDRAM controller and a chip model, the sprite bitmap in a DDR3 model; also the line engines' deadlines under CPU load |
tools/bench_soc3.py (sim/tb_soc3.cpp) |
the whole board: ARM core, memory system, video, sound, IC card slots |
tools/bench_top.py (sim/tb_top.cpp, sim/top/) |
the MiSTer top (PGM2.sv) loaded from the MRA's byte stream as Main_MiSTer sends it |
tools/bench_ymz774.py (sim/tb_ymz774.cpp) |
the sound chip on MAME's register writes, against the integer model, under DDR3 latency |
tools/boot_check.py |
every set booted in the whole-board bench and compared with MAME's power-on frames |
tools/capture.py and tools/lua/ run MAME headless to capture frames, video states and register traffic; tools/pgm2_ref.py
(video), tools/ymz_ref.py / tools/ymz_fixed.py (sound) are the Python reference models; tools/pgm2_rom.py builds the
benches' ROM images from the romsets. The tools find MAME 0.289, its source and the romsets through tools/paths.py.
PGM2.sv, PGM2.q*, PGM2.sdc, files.qip |
the MiSTer top level (OSD, inputs, video, audio, the loader's hookup) and the Quartus project |
rtl/ |
the machine: IGS037 video (pgm2_igs037.sv, pgm2_bg/fg/spr/ram/vtiming.sv, the DDR3 sprite bitmap pgm2_bitmap.sv), YMZ774 (ymz774.sv, ymz_dec.sv, ymz_synth.sv, tables ymz_*.mem), IGS036 peripherals (igs036_aic.sv, igs036_decrypt.sv, the card reader MCU igs036_mcu.sv with pgm2_card.sv), memory system (igs036_mem.sv, pgm2_sdram_if.sv, the PGM1 core's SDRAM controller sdram.sv), ROM loader (pgm2_loader.sv), Knights of Valour 3's program module (pgm2_kov3mod.sv), the SoC (pgm2_core.sv) |
cpu/ |
the ARM7TDMI in Chisel (gamebub-arm/, extended to the IGS036's ARMv5T: BLX, CLZ, CP15, interworking loads, ARMv5 halfword loads) and its generated SystemVerilog (generated/) |
modules/ |
other people's HDL with their licences (modules/VENDOR.md) |
sys/ |
the MiSTer framework |
mra/ |
the MRAs: one per game in the folder, the other versions in _alternatives/_<Title>/ |
releases/ |
the current release as it goes on the SD card (_Arcade/), with its release notes |
docs/ |
hardware.md (the board as MAME models it), video_rtl.md, sound_notes.md, cpu_notes.md, mister_top.md (the top level, memory map, verification and the decisions behind them), screenshots/ |
sim/, tools/ |
benches, MAME scripts, reference models, MRA writer / checker, packaging |
- MAME (the
pgm2driver by David Haywood, Xing Xing and Andreas Naive; the YMZ770 / YMZ774 by Olivier Galibert, R. Belmont and MetalliC; BSD-3-Clause): the hardware knowledge and the oracle for every comparison. The sound chip's tables and decoder follow MAME's. - Eli Lipsitz (the ARM7TDMI in Chisel of the Game Bub, GPL-3.0), packaged as
gamebub-armin the IGS PGM core for MiSTer (Arcade-IGSPGM_MiSTer), which also gave the SDRAM controller and parts of the framework setup. - rmonic79 (MiSTer-CRT-Adjust, GPL-3.0-or-later).
- The MiSTer framework (Sorgelig and contributors); the loader and memory structure follow the owner's other cores.
GPL-3.0 (LICENSE; the ARM core derives from GPL-3.0 code). The ymz_*.mem tables and the sound decoder derive from MAME
(BSD-3-Clause); vendored modules keep their own licences. No ROM data is part of the repository.




