JTFRAME is a framework for FPGA computing on the MiST and MiSTer platform. JTFRAME is also a collection of useful verilog modules, simulation models and utilities to develop retro hardware on FPGA.
You can show your appreciation through
- Patreon: https://patreon.com/topapate
- Paypal: https://paypal.me/topapate
Many repositories depend on JTFRAME for compilation:
- CAPCOM arcades prior to CPS1
- CAPCOM SYSTEM aka CPS1
- Technos Double Dragon 1 & 2 arcade games
- Konami Contra
- Nintendo Popeye
- More to come thanks to Patreon supporters
These are the compilation steps:
- You need linux. I use Ubuntu mate but any linux will work
- You need 32-bit support if you're going to compile MiST/SiDi cores
- There are some linux dependencies that you can sort out with
sudo apt install
, I will eventually list them - Populate the arcade core repository including submodules recursively. I believe in using submodules to break up tasks and sometimes submodules may have their own submodules. So be sure to populate the repository recursively. Be sure to understand how git submodules work
- Now jtframe should be located in
core-folder/modules/jtframe
go there and enter thecc
folder. Runmake
. Make sure all files compile correctly and install whatever you need to make them compile. All should be in your standard linux software repository. Nothing fancy is needed - Now go to the
core-folder
and runsource setprj.sh
- Now you can compile the core using the
jtcore
script.
The complete list of possible verilog macros is in here.
jtcore is the script used to compile the cores. It does a lot of stuff and it does it very well. Taking as an example the CPS0 games, these are some commands:
jtcore gng -sidi
Compiles Ghosts'n Goblins core for SiDi.
jtcore tora -mister
Compiles Tiger Road core for MiSTer.
Some cores, particularly if they only produce one RBF file, may alias jtcore. For CPS1 do:
jtcore -mister
And that will produce the MiSTer version.
Some CPUs are included in JTFRAME. Some of them can be found in other repositories in Github but the versions in JTFRAME include clock enable inputs and other improvements.
Many arcade games and 80's computers use 74-series devices to do discrete logic. There are some files in JTFRAME that help analyze these systems using the following flow:
- Draw the schematics in KiCAD using the libraries in the kicad folder
- Generate a netlist in standard KiCAD format
- Use the pcb2ver utility in the cc folder to convert the output from KiCAD to a verilog file
- Prepare a module wrapper for the new verilog file and include the verilog file in the wrapper via an include command
- Simulate the file with a regular verilog simulator.
There is a verilog library of 74-series gates in the hdl folder: hdl/jt74.v. The ones that include // ref and // pin comments can be used for KiCAD sims. It is very easy to add support for more cells. Feel free to submit pull merges to Github.
It makes sense to simulate delays in 74-series gates as this is important in some designs. Even if some cells do not include delays, later versions of jt74.v may include delays for all cells. It is not recommended to set up your simulations with Verilator because Verilator does not support delays and other modelling constructs. The jt74 library is not meant for synthesis, only simulation.
You can use a hex file with inputs for simulation. Enable this with the macro SIM_INPUTS. The file must be called sim_inputs.hex. Each line has a hexadecimal number with inputs coded. Active high only:
bit meaning 0 coin 1 1 coin 2 2 1P start 3 2P start 4 right (may vary with each game) 5 left (may vary with each game) 6 down (may vary with each game) 7 up (may vary with each game) 8 Button 1 9 Button 2
Each line will be applied on a new frame.
The macro JTFRAME_OSDCOLOR should be defined with a 6-bit value encoding an RGB tone. This is used for the OSD background. The meanins are:
Value | Meaning | Colour |
---|---|---|
6'h3f | Mature core | Gray |
6'h1e | Almost done | Green |
6'h3c | Playable with problems | Yellow |
6'h35 | Very early core | Red |
##JTFRAME_SDRAM
jtframe_sdram is a generic SDRAM controller that runs upto 48MHz because it is designed for CL=2. It mainly serves for reading ROMs from the SDRAM but it has some support for writting (apart from the initial ROM download process).
This module may result in timing errors in MiSTer because sometimes the compiler does not assign the input flip flops from SDRAM_DQ at the pads. In order to avoid this, you can define the macro JTFRAME_SDRAM_REPACK. This will add one extra stage of data latching, which seems to allow the fitter to use the pad flip flops. This does delay data availability by one clock cycle. Some cores in MiSTer do synthesize with pad FF without the need of this option. Use it if you find setup timing violation about the SDRAM_DQ pins.
SDRAM is treated in top level modules as a read-only memory (except for the download process). If the game core needs to write to the SDRAM the JTFRAME_WRITEBACK macro must be defined.
By default only the first bank of the SDRAM is used, allowing for 8MB of data organized in 4 M x 16bits. In order to enable access to the other three banks the macro JTFRAME_SDRAM_BANKS is used. Once this macro is defined the game module is expected to provide the following signals
[1:0] prog_bank bank used during SDRAM programming [1:0] sdram_bank bank used during regular SDRAM use
These signals should be used in combination with the rest of prog_ and sdram_ signals in order to control the SDRAM.
The data bus is held down all the time and only released when the SDRAM is expected to use it. This behaviour can be reverted using JTFRAME_NOHOLDBUS. When this macro is defined, the bus will only be held while writting data and released the rest of the time. For 48MHz operation, holding the bus works better. For 96MHz it doesn't seem to matter.
In simulation data from the SDRAM can be double checked in the jtframe_rom/ram_xslots modules if JTFRAME_SDRAM_CHECK is defined. The simulation will stop if the read data does not meet the expected values.
##JTFRAME_SDRAM_BANK
jtframe_sdram_bank is a high-performance SDRAM controller that achieves high data throughput by using bank interleaving.
HF parameter should be set high if the clock frequency is above 64MHz
Performance results (MiST)
Frequency | Efficiency | Data throughput | Latency (min) | Latency (ave) | Latency (max) |
---|---|---|---|---|---|
<64MHz | 100% | f*2 =128MB/s | 7 (109ns) | 9 (140ns) | 29 (453ns) |
96MHz | 66.7% | f2.667=128MB/s | 9 ( 73ns) | 11 (114ns) | 30 (312ns) |
Performance results (MiSTer - A lines shorted to DQM)
Frequency | Efficiency | Data throughput | Latency (min) | Latency (ave) | Latency (max) |
---|---|---|---|---|---|
<64MHz | 72% | f2.72 = 92MB/s | 7 (109ns) | 9 (140ns) | 32 (500ns) |
96MHz | 53.3% | f2.533=102MB/s | 9 ( 73ns) | 12 (125ns) | 36 (375ns) |
Note that latency results are simulated with refresh and write cycles enabled.
Starting from the Dec. 2020 firmware update, MiST can now delegate the ROM load to the FPGA. This makes the process 4x faster. This option is enabled by default. However, it can be a problem because the ROM transfer will be composed of full SD card sectors so there will be some garbage sent at the end of the ROM. If the core is not compatible with this and it relies on exact sizing of the ROM it needs to define the macro JTFRAME_MIST_DIRECT and set it to zero:
set_global_assignment -name VERILOG_MACRO "JTFRAME_MIST_DIRECT=0"
In order to preserve the 8-bit ROM download interface with MiST, jtframe_mister presents it too. However it can operate internally with 16-bit packets if the macro JTFRAME_MR_FASTIO is set to 1. This has only been tested with 96MHz clock. Indeed, if JTFRAME_CLK96 is defined and JTFRAME_MR_FASTIO is not, then it will be defined to 1.
The measured speed for data transfers in MiSTer is about 1.2MHz (800ns) per request. If JTFRAME_MR_FASTIO is set, each request is 16-bit words, otherwise, 8 bits.
To enable support of DIP switches in MRA files define the macro JTFRAME_MRA_DIP. The maximum length of DIP switches is 32 bits. To alter the value of DIP switches in simulation use JTFRAME_SIM_DIPS.
In MiST, DIP switches are incorporated into the status word. As some bits in the status word are used for other OSD settings, DIP switches are by default located in range 31:16. This is set by the macro JTFRAME_MIST_DIPBASE, whose default value is 16. Note that the MRA should match this, the base attribute can be used in the MRA dip definition to shift the switch bits up.
Macro | Effect |
---|---|
JTFRAME_SIM_DIPS | 32-bit value of DIPs used in simulation only |
JTFRAME_OSD_NOLOAD | Do not display load file |
JTFRAME_OSD_NOCREDITS | Do not display Credits |
JTFRAME_OSD_FLIP | Display flip option (only for vertical games) |
JTFRAME_OSD_NOSND | Do not display sound options |
Status bits in the configuration string are indicated with characters. This is the reference of the position for each character:
bit 00000000001111111112222222222233
number : 01234567890123456789012345678901
status char: 0123456789abcdefghijklmnopqrstuv
Values above 8 are not available in MiST if JTFRAME_MRA_DIP is defined.
bit | meaning | Enabled with macro |
---|---|---|
0 | Reset in MiST | |
1 | Flip screen | JTFRAME_VERTICAL && JTFRAME_OSD_FLIP |
2 | Rotate controls | JTFRAME_VERTICAL (MiST) |
2 | Rotate screen | JTFRAME_VERTICAL (MiSTer) |
3-4 | Scan lines | Scan-line mode (MiST only) |
3-5 | Scandoubler Fx | Scan line mode and HQ2X enable (MiSTer only) |
6-7 | FX Volume | JTFRAME_OSD_VOL |
8 | FX enable/disable | JTFRAME_OSD_SND_EN |
9 | FM enable/disable | JTFRAME_OSD_SND_EN |
10 | Test mode | JTFRAME_OSD_TEST |
11 | Horizontal filter | MiSTer only |
12 | Credits/Pause | JTFRAME_OSD_NOCREDITS (disables it) |
14-15 | Aspect Ratio | MiSTer only |
If JTFRAME_FLIP_RESET is defined a change in dip_flip will reset the game.
To add game specific OSD strings, the recommended way is by adding a line to the .def file:
CORE_OSD="O6,Turbo,Off,On;",
Only one CORE_OSD can be defined, but it an contain multiple values separated by colon.
First you need to get the xml with all the information:
mame -listxml > mame.xml
The file mamefilter.cc is an example of how to extract a subset of machine definitions from the file.
The files mamegame.hpp and mamegame.cc contain some classes and a function to process the MAME XML into easy-to-use C++ objects. An example of this in use can be seen in JTCPS1 core.
Some JTFRAME features are configured via an ARC or MRA file. This is used to share a common RBF file among several games. The mod byte is introduced in the MRA file using this syntax:
<rom index="1"><part> 01 </part></rom>
And in the ARC file with
MOD=1
This is the meaning for each bit. Note that core mod is only 7 bits in MiST.
Bit | Meaning | Default value |
---|---|---|
0 | 1 = vertical screen | 1 |
1 | 1 = 4 way joystick | 0 |
The vertical screen bit is only read if JTFRAME was compiled with the JTFRAME_VERTICAL macro. This macro enables support for vertical games in the RBF. Then the same RBF can switch between horizontal and vertical games by using the MOD byte.
By default the frame supports two joysticks only and will try to connect to game modules based on this assumption. For games that need four joysticks, define the macro JTFRAME_4PLAYERS. Note that the registers containing the coin and start button inputs are always passed as 4 bits, but the game can just ignore the 2 MSB if it only supports two players.
Analog controllers are not connected to the game module by default. In order to get them connected, define the macro JTFRAME_ANALOG and then these input ports:
input [15:0] joystick_analog_0,
input [15:0] joystick_analog_1,
Support for 4-way joysticks (instead of 8-way joysticks) is enabled by setting high bit 1 of core_mod. See MOD BYTE.
A model for SDRAM mt48lc16m16a2 is included in JTFRAME. The model will load the contents of the file sdram.hex if available at the beginning of simulation.
The current contents of the SDRAM can be dumped at the beginning of each frame (falling edge of vertical blank) if JTFRAME_SAVESDRAM is defined. Because this is quite an overhead, it is possible to restrict it to dump only a certain DUMP_START frame count has been reached. All frames will be dumped after it. The macro DUMP_START is the same one used for setting the start of signal dump to the VCD file.
To simulate the SDRAM load operation use -load on sim.sh. The normal download speed 1/270ns=3.7MHz. This is faster than the real systems but speeds up simulation. It is possible to slow it down by adding dead clock cycles to each transfer. The macro JTFRAME_SIM_LOAD_EXTRA can be defined with the required number of extra cycles.
ID | Part No | Units | Size |
---|---|---|---|
1 | AS4C32M16SB-6TIN | 2 | 128 |
2 | W9825G6KH-6 | 1 | 32 |
3 | AS4C16M16SA-6TCN | 1 | 32 |
4 | AS4C32M16SB-7TCN | 2 | 128 |
5 | W9825G6KH-6 | 1 | 32 |
6 | AS4C32M8SA -7TCN | 2 | 64 |
7 | AS4C32M8SA -7TCN | 4 | 128 |
8,9 | AS4C32M16SB-6TIN | 2 | 128 |
All time values in ns, capacitance in pF
Part No | Op. Current (mA) | Ci | Ci/o | tRRD | tRP | tAC CL=2 | tOH | tHZ |
---|---|---|---|---|---|---|---|---|
AS4C16M16SA -6/-7 | 60/55 (1 bank) | 2-4 | 4-6 | 12/14 | 18/21 | 6/6 | 2.5 | 5/5.4 |
AS4C32M16SA -6/-7 | 120/110(1 bank) | 3.5-5.5 | 4-6 | 12/14 | 18/21 | 6/6 | 2.5 | 5/5.4 |
AS4C32M8SA -6/-7 | 60/55 (1 bank) | 2-4 | 4-6 | 12/14 | 18/21 | 6/6 | 2.5 | 5/5.4 |
W9825G6KH-6 | 60 | <3.8 | <6.5 | 15 | 15 | 6 | 3 | 6 |
MiST uses a single SDRAM module, with about 4pF per pin. In order to charge it up to 3.3V in 4ns we need 3.3mA. Current per pin is limited to 4mA in order to prevent noise.
Pin view with SDRAM on top, ethernet cable on the bottom right
DQ1 DQ3 DQ5 DQ7 DQ14 NC DQ13 DQ11 DQ9 DQ12 A9 A7 A5 WE VDD CAS CS1 BA1 BA0 A2 DQ0 DQ2 DQ4 DQ6 DQ15 GND DQ12 DQ10 DQ3 CLK A11 A8 A6 A4 GND RAS BA0 A10 A1 A3
On MiSTer SDRAM modules as of December 2020 have a severe VDD ripple. VDD can go above 4V and reach 2.4V. 32MB modules are slightly better.
MiSTer SDRAM modules also suffer of intersymbol interference. Although it is not clear which lines couple more closely -no layout parasitics for any board are available- setting the DQ bus from the FPGA for a write at the time of RAS showed worse results than setting it at CAS time for Contra core using the sdram_bank controller (based on 7e93cc5 commit).
Measurements of A3 line and VDD (SDRAM module #4 with 10uF electrolytic added):
Slew Rate | Max V(A3) | Min V(A3) | tr/tf (ns) |
---|---|---|---|
Fast (2) | 3.92 | -0.92 | 3 |
Slow (0) | 3.76 | -0.60 | 4 |
VDD ripple also improves with slower slew rates (module #8):
Slew Rate | Max VDD | Min VDD |
---|---|---|
Fast (2) | 4.12 | 2.58 |
Slow (0) | 3.98 | 2.74 |
Using the slowest slew rate fixes Contra load on all tested modules, regardless of when DQ is set at write time:
Module | DQ at RAS | DQ at CAS |
---|
| fast | slow | fast | slow
-------|------|------|------|------ 1 | NG | OK | OK | OK 2 | NG | OK | NG | OK 3 | OK | OK | NG | OK 4 | NG | OK | OK | OK 7 | NG | OK | NG | OK 8 | NG | OK | OK | OK
9 | NG | OK | OK | OK |
---|---|---|---|---|
Fails | 6 | 0 | 3 | 0 |
Faster slew rates mean more current going through the connector, thus more ripple at both the signal pin and VDD. So both problems become better. This doesn't mean they are completely solved. VDD ripple is still out of spec with the current capacitor set used. And slowing down further the bus should also help.
I made a clock shift sweep using JTCONTRA commit 5633ee41. These are the results of valid values:
Module | Min | Max | Remarks |
---|---|---|---|
1 | 3.5 | 8.25 | |
2 | 2.5 | 8.5 | 32MB |
3 | 2.5 | 8.75 | 32MB |
4 | 3.0 | 8.0 | 10uF added |
7 | 4.0 | 8.25 | min improved to 3.5ns by adding 33uF |
8 | 3.5 | 8.0 | |
9 | 3.25 | 8.25 | |
AV sys | 3.0 | 8.25 | Same results with fan on/off |
The wider the difference is between max and min, the cleaner signals are.
Most cores in the official MiSTer repository seem to use a strategy of a full 180ΒΊ clock shift. This has the advantage of providing an accurate value of the clock at the pin as it can be generated using an IO primitive. However, it means that the last word of the burst is read with the bus at high impedance, so it has a higher potential for failures. It helps when timing cannot be met as it simplifies internal routing. Enable it with JTFRAME_180SHIFT
Games are expected to operate on a 48MHz clock using clock enable signals. There is an optional 6MHz that can be enabled with the macro JTFRAME_CLK6. This clock goes in the game module through a clk6 port which is only connected to when that macro is defined. jtbtiger is an example of game using this feature.
clock input | Macro Needed |
---|---|
clk | 48MHz unless JTFRAME_SDRAM96 is defined, then 96MHz |
clk96 | JTFRAME_CLK96 |
clk48 | JTFRAME_CLK48 |
clk24 | JTFRAME_CLK24 |
clk6 | JTFRAME_CLK6 |
Note that although clk6 and clk24 are obtained without affecting the main clock input, if JTFRAME_SDRAM96 is defined, the main clock input moves up from 48MHz to 96MHz. The 48MHz clock can the be obtained from clk48 if JTFRAME_CLK48 is defined too. This implies that the SDRAM will be clocked at 96MHz instead of 48MHz. The constraints in the SDC files have to match this clock variation.
If STA was to be run on these pins, the SDRAM clock would have to be assigned the correct PLL output in the SDC file but this is hard to do because the TCL language subset used by Quartus seems to lack control flow statements. So we are required to do another text edit hack on the fly, which is not nice. Apart from changing the PLL output, when using 96MHz clock the input data should have a multicycle path constraint as it takes an extra clock cycle for the data to be ready. If you just change the PLL clock then you'll find plenty of timing problems unless you define the multicycle path constraint.
This is the code needed:
create_generated_clock -name SDRAM_CLK -source \
[get_pins {emu|pll|pll_inst|altera_pll_i|general[5].gpll~PLL_OUTPUT_COUNTER|divclk}] \
-divide_by 1 \
[get_ports SDRAM_CLK]
set_multicycle_path -from [get_ports {SDRAM_DQ[*]}] -to [get_clocks {emu|pll|pll_inst|altera_pll_i|general[4].gpll~PLL_OUTPUT_COUNTER|divclk}] -setup -end 2
set_multicycle_path -from [get_ports {SDRAM_DQ[*]}] -to [get_clocks {emu|pll|pll_inst|altera_pll_i|general[4].gpll~PLL_OUTPUT_COUNTER|divclk}] -hold -end 2
This only applies to MiSTer. For MiST the approach is different and there are two different PLL modules which produce the SDRAM clock at the same pin. So a single create_generated_clock
applies to both. Due to different SDRAM shifts used, the multicycle path constraint does not seem needed in MiST.
The script jtcore handles this process transparently.
By default unless JTFRAME_MR_FASTIO is already defined, JTFRAME_CLK96 will define it to 1. This enables fast ROM download in MiSTer using 16-bit mode in hps_io.
Although original JTFRAME supported a variety of scan doublers, the support has been simplified down to the following:
Macro Def. | Module | Description |
---|---|---|
NOVIDEO | none | by pass values without scan doubler. Useful for sims |
SIMULATION | none | same as above |
JTFRAME_SCAN2x | jtframe_scan2x | simple and fast scan doubler. Small area footprint |
no macro | arcade_video | from MiSTer framework. Large area footprint |
jtframe_scan2x and arcade_video both depend on macros VIDEO_WIDTH and VIDEO_HEIGHT. But with a difference:
Macro | Module | Meaning |
---|---|---|
VIDEO_HEIGHT | both | Visible vertical pixels |
VIDEO_WIDTH | arcade_video | Visible horizontal pixels |
VIDEO_WIDTH | jtframe_scan2x | Total horizontal pixels |
No image problems might be related to misdefinition of these macros.
For MiST, OSD control of arcade_video features is enabled with macro MISTER_VIDEO_MIXER
In MiSTer the aspect ratio through the scaler can be controlled via the core. By default it is possible to switch between 16:9 and 4:3. However, if the game AR is different, the following macros can be used to redefine it:
Macro | Default | Meaning |
---|---|---|
JTFRAME_ARX | 4 | horizontal magnitude |
JTFRAME_ARY | 3 | vertical magnitude |
Internally each value is converted to an eight bit signal.
There are some facilities to help with the upsampling needed for the DACs. Some modules need a hex file containing the value of the coefficients to be copied into the MiST(er) folder for compilation. The hex files are available in hdl/sound folder.
The module jtframe_fir is designed to operate on a stereo signal input to apply a FIR filter of up to 127 coefficients. It takes one BRAM block. As it needs about 256 clocks per sample, the input sampling frequency must be lower than clk/256.
IIR filter to remove the DC value of a signal.
This covers the usual situation of having two JT49 instances in a core. This module will add the two outputs, remove DC and filter out frequencies about 14kHz (for a JT49 clock of 1.5MHz). There is a qip file for this module.
If JTFRAME_RELEASE is not defined, some extra features within JTFRAME will operate.
In debug mode keys F7-F10 will switch the gfx_en[3:0] signal. This can be used internally by the core for debugging. The original intent was to get each bit enable/disable a given GFX layer, hence the name.
Define and export the following environgment variables to have these modules added to your simulation when using sim.sh
YM2203 YM2149 YM2151 MSM5205 M6801 M6809 I8051
Credits can be displayed using the module JTFRAME_CREDITS. This module needs the following files inside the patrons folder:
Input File | Output File | Tool | Function |
---|---|---|---|
msg | msg.hex | msg2hex | text shown |
avatars | avatar.hex | avatar.py | avatar images. 4bpp indexed |
avatars | avatar_pal.hex | avatar.py | avatar paletters |
lut | lut.hex | lut2hex | avatar tiles location in 8-pixel multiples |
avatars contains a line with the path from $JTROOT or $JTROOT/cores (if cores exists) to the PNG image. There should be one line per image.
lut contains the object look-up table. Each line has four fields:
- Tile code
- x position
- y position
- Palette
- Line starting with # character are treated as comments
- A line can start with the scape code \6, which means that the following four fields should be expanded to a full 2x3 sprite, adjusting tile code and positions accordingly
- Another scape code is \9, and will expand to a full 3x3 sprite
- The table end is marked by an object with ID 255
avatar.py needs a .png image that complies with:
- x-y sizes are multiples of 8
- Maximum 16 colours in the image
- Alpha channel present in the PNG
- Image format is RGB (not indexed)
Once the three files msg, avatars and lut are available, jtcore will process them as part of the compilation.
Features 1-bpp text font and 4-bpp objects. Enable it with macro JTFRAME_CREDITS. By default there are three pages of memory reserved for this. If a different number is needed define the macro JTFRAME_CREDITS_PAGES with the right value. Avatars are enabled with JTFRAME_AVATARS
Converts from a text file (patrons/msg) to a hex file usable by JTFRAME_CREDITS. Type text for ASCII conversion. Escape characters can be introduced by \ with the following meaning:
Escape | Meaning |
---|---|
R | RED palette (index 0) |
G | GREEN palette (index 1) |
B | BLUE palette (index 2) |
W | WHITE palette (index 3) |
jtcore can also program the FPGA (MiST or MiSTer) with the -p
option. In order to use an USB Blaster cable in Ubuntu you need to setup two urules files. The script jtblaster does that for you.
Part | Author | License | Logic Cells (MiST) | BRAM (MiST) | URL |
---|---|---|---|---|---|
m6801 | 1100 | JTFRAME | |||
m6809 | Greg | 3000 | JTFRAME | ||
YM2151 | Jose Tejada | GPLv3 | 3500 | 12 | JT51 |
YM2203 | Jose Tejada | GPLv3 | 1700 | 12 | JT12 |
YM2149 | Jose Tejada | GPLv3 | 70 | JT49 | |
OKI 6295 | Jose Tejada | GPLv3 | 650 | 4 | JT6295 |
Z80 | 2200 | T80v - Verilog | |||
Z80 | 2400 | T80s - VHDL | |||
8051 | 4200 | ||||
M68000 | 5200 | 6 | fx68k | ||
JTFRAME MiST | Jose Tejada | GPLv3 | 2400 jtframe_scan2x | 4 | JTFRAME |
JTFRAME MiST* | Jose Tejada | GPLv3 | 4600 arcade_video | 4 | JTFRAME |
jtframe_rom | Jose Tejada | GPLv3 | 120*slot+80 | JTFRAME | |
JTFRAME_CREDITS | Jose Tejada | GPLv3 | 180 | 6 | JTFRAME |
Contact the author for special licensing needs. Otherwise follow the GPLv3 license attached.