-
Notifications
You must be signed in to change notification settings - Fork 9
4. Understand the MiSTer core
Before you start porting, you should first understand how the MiSTer core
works for an end-user. In the optimal case, you own a MiSTer and can actually
experiment and play with the core. But this is not mandatory. There are also a
lot of YouTube videos about many cores. It is important that you get an
overall "feeling" for the core and how it behaves. And even more important:
You need to understand how the MiSTer core performs disk mounting, ROM loading
and what configuration options are available to the end user, because all of
this helps you to understand a lot of things, including MiSTer's core
configuration string (CONF_STR
). The core configuration string is used to
generate the menu shown to the end-user (similar to M2M's OSM) and therefore
CONF_STR
is paramount to understanding many of the parameters, wiring and
default values that the core needs to run.
So you have played enough with the core and/or watched some YouTube videos and you feel you have understood the "end user view" of the MiSTer core you want to port to MEGA65? Great - then let's start to dive in at the deep end.
MiSTer has an excellent documentation for developers where you can learn how to port a core TO MiSTer. What we want to achieve here is learn how to port a core FROM MiSTer. Nevertheless, your MiSTer2MEGA65 porting experience will be much smoother if you start from first principles. Please read the following chapters of the MiSTer documentation before you proceed:
- Porting Cores
- Core Configuration String
- Overview of emu module
- sys - hps_io
- sys - video_freak
- sys - video_mixer
- sys - arcade_video
Don't worry if you don't understand everything written in these seven chapters. It is more important that you have a high-level overview of the concepts and that you have seen most of them now at least once and that you know where to look in case you get stuck at a later stage of your porting adventure.
Now it is time to examine the structure of the actual core you want to port. As an easy start, we suggest you go to the core's GitHub repository and browse the source code there. You might want to use the MiSTer Wiki as a starting point to find the repository of the core: Scroll down a bit and you will see the list of cores on the right side.
MiSTer is a very structured project, so we can rely on certain files and folders to always be present:
-
rtl
folder: Contains the actual core. Many MiSTer cores are enhanced versions of MiST cores or other cores. Therefore the MiSTer team encapsulates everything related to the core itself inside thertl
folder. -
sys
folder: This is the MiSTer framework that provides services similar to that of the MiSTer2MEGA65 framework. -
*.sv
file in the root folder that is named like the core: This is your starting point for any porting effort, because you will be able to study the "wiring" of the MiSTer core: How does MiSTer actually connect different parts of the core with its own framework? What kind of glue logic is necessary? What options does MiSTer offer to the users? ROMs? Drives? (Hint: The*.sv
file is actually not the top-file used to synthesize a MiSTer core. Instead,sys/sys_top.v
is used. But this does not matter for our porting purposes.)
The MiSTer framework is similar to our M2M framework in being a hardware abstraction layer. The core lives in its own bubble, while not being aware of the fact that it is not connected to the "real" hardware it expects.
What we need to find out as a next step is: What is the environment that the core needs to run in? Examples of "environment" are:
- Clocking and clock speed
- RAM
- ROM
- Keyboard
- Other peripherals (drives, joysticks, mouses, paddles, ...)
Additionally, you need to learn how the video and audio output of the core works and what settings, switches, and parameters can and need to be configured.
To learn everything about the environment, open the *.sv
file in the root
folder of the core and start looking for the instantiation of the "actual"
core. The *.sv
file usually contains a ton of glue logic and instantiations
of all the hardware needed to support the core. Additionally, it contains stuff
that is needed for the MiSTer framework. We need to ignore all of this for now
and instead locate the right module, the "Actual core".
Here are four examples:
Example core | Root *.sv file |
Actual core module |
---|---|---|
Apple II | Apple-II.sv | apple2_top |
Arkanoid | Arcade-Arkanoid.sv | Arkanoid |
Commodore 64 | c64.sv | fpga64_sid_iec |
GameBoy | Gameboy.sv | gb |
We will continue to use these four examples throughout this chapter.
Please note that it will be this "actual" core (instead of the emu
module
from MiSTer's root *.sv
file) that you will instantiate at a later stage
inside M2M's main.vhd
. We will get into the details in chapter
6. Basic wiring.
Instead of continuing to talk about the *.sv
file, in the following sections
we use emu
module instead.
MiSTer's system clock runs at 50 MHz. M2M's system clock runs at 100 MHz. Therefore both frameworks need to use PLLs or MMCMs to generate the clock or clocks needed by the retro core.
Most MiSTer cores instantiate a clocking module called pll
within the emu
module. Start by having a look at this instantiation to answer the following
questions:
- How many clocks are being generated?
- What are the names of the clock signals used inside
emu
? - Which clocks are used for the core itself?
- Which clocks are used for video output, RAM, other components?
- Is there a mechanism for any dynamic clock reconfiguration?
There is no recipe for answering these questions other than to read the
source code in the emu
module. It is important that you take a thorough look
at CONF_STR
while doing so because some of the menu items that the end user
can choose from are impacting the clock handling.
Last but not least, you need to learn more about the actual speed of the
clock(s). Please be aware that very often it is crucial for compatibility and
timing that you try to hit the actual clock speed "down to the Hertz" (or
at least very close). In most MiSTer cores, the folder with the file(s) where
you can learn more is called rtl/pll
. Also, in most MiSTer cores the name
of the clock signal generated in the emu
module's pll
section already
gives you a first hint of what is going on.
Here are some examples to make this more tangible. We recommend that you
open and read the emu
module source code (and other files as needed) while
reading through the examples.
pll pll
(
.refclk(CLK_50M),
.rst(0),
.outclk_0(CLK_VIDEO),
.outclk_1(clk_sys)
);
We learn that there are two clocks: A video clock CLK_VIDEO
and the actual
core clock clk_sys
. Since the names are not suggesting any actual clock
speed, let's have a look at rtl/pll/pll_0002.v
:
.number_of_clocks(2),
.output_clock_frequency0("57.272727 MHz"),
.phase_shift0("0 ps"),
.duty_cycle0(50),
.output_clock_frequency1("14.318181 MHz"),
.phase_shift1("0 ps"),
.duty_cycle1(50),
So we have two clocks that are not phase-shifted and that have the standard duty cycle of 50% high and 50% low. The video clock has the "odd" frequency of 57.272727 MHz and the core has the "odd" frequency of 14.318181 MHz.
When you encounter something like this, it often makes sense to check, if one clock is a multiple of the other. In our case the video clock is 4x the core clock.
Now search in the emu
module where CLK_VIDEO
is being used (other than
outputting it to the MiSTer framework): You will notice that there is a clock
divider which drives the clock enable signal for the pixel clock: ce_pix
.
And this clock divider either divides the video clock by 8 or by 4 depending
on status[16]
. As you might already know after having read MiSTer's
documentation on the
Core Configuration String,
status[16]
is a bit that reflects the end-user's choice in the MiSTer
on-screen-menu. 16
decimal is 0x10
hexadecimal and the CONF_STR
configuration reveals that we need to look for the letter G
to find out
the appropriate option and therefore the meaning:
"OG,Pixel Clock,Double,Normal;",
At this moment, we can only guess what this means and make a mental note to revert back, as soon as we look at the video output.
Now search for clk_sys
in the emu
module as this is the speed of the
actual retro core. To our surprise we find this:
apple2_top apple2_top
(
.CLK_14M(clk_sys),
.CLK_50M(CLK_50M),
So for some reason, the "actual" core needs a 50 MHz clock signal (which happens to be MiSTer's framework clock speed) additionally to the 14.318181 MHz core speed. (The latter one is clear and does not need further investigation.)
This is a good moment to dive one level deeper and open rtl/apple2_top.vhd
and check what's going on regarding the 50 MHz signal. You will find that
there is an instantiation of something called superserial
. If you are an
Apple II pro and already know what this is: Great! Otherwise
Wikipedia
comes to the rescue: This is a serial interface for the Apple II. The open
question that remains is: Does superserial
genuinely need 50 MHz - or - does
it need 50 MHz because the MiSTer framework runs at 50 MHz and therefore there
exists some interface logic between superserial
and some MiSTer framework
components that run at 50 MHz. In the first case we are fine and in the latter
case we need to make a mental note that additional glue logic or other
mechanisms (other than just providing a 50 MHz clock) might be needed to
support superserial
on MiSTer2MEGA.
To answer this question: Let's open the file rtl/ssc/super_serial_card.v
and
search for CLK_50M
. We find this code segment:
// 14.31818
// 50 MHz / 27 = 1.852 MHz
always @(posedge CLK_50M)
begin
if(RESET)
CLK_6551 <= 5'd0;
else
case(CLK_6551)
5'd26:
CLK_6551 <= 5'd0;
default:
CLK_6551 <= CLK_6551 + 1'b1;
endcase
end
We can derive two hints from this code segment:
- There seems to be a chip called 6551
- 50 MHz / 27 = 1.852 MHz
Searching the web for 6551 datasheet
for example reveals
this data sheet. We
learn that the 6551 is an asynchronous communication interface adapter from
Commodore's MOS Technology and that the 6551 prefers to run at 1.8432 MHz.
Close enough to the 1.852 MHz, so all good: superserial
genuinely needs
the 50 MHz to generate this 6551 clock signal so there is no MiSTer framework
specific reason. We will be able to support this in M2M without any additional
tricks.
pll pll
(
.refclk(CLK_50M),
.rst(0),
.outclk_0(CLK_48M),
.reconfig_to_pll(reconfig_to_pll),
.reconfig_from_pll(reconfig_from_pll),
.locked(locked)
);
Without the need to even look at the files in rtl/pll
we can deduce the
following from this module instantiation:
- The core only needs one clock, which seems to be running at 48 MHz.
- There seems to be a dynamic reconfiguration of the clock speed.
A best practice is to start looking inside the emu
module, where the clock
is being used. In the Arkanoid example we quickly find two points of interest:
- The instantiation of
arcade_video
: We make a mental note that the pixel clock is derived from the 48 MHz clock. (There are more details to that; for example as you can see in the MiSTer documentationarcade_video
also uses a clock enable signal calledce_pix
, which is being generated inemu
.) - The actual
Arkanoid
core uses theCLK_48M
input.
While browsing through the instantiation of the Arkanoid
core, you will
notice that some signals seem to control overclocking. Also in the core's
CONF_STR
there is an option to switch the game speed between "Native" and
"60Hz Adjust". So these are great hints what the purpose of the two signals
reconfig_to_pll
and reconfig_from_pll
might be used for.
Searching through the emu
module using the search string reconfig_to_pll
quickly brings us to the instantiation of pll_cfg
and the comment that is
written there says it all:
//Reconfigure PLL to apply an ~1.4% overclock to Arkanoid to bring video timings in spec for 60Hz VSync
So it looks like we're having an anti-flicker mechanism so that the game looks smooth on 60 Hz screen setups: This is for example needed for smooth HDMI outputs, because most HDMI screens are not supporting "odd" vertical sync frequencies.
In the last step, we open rtl/pll/pll_0002.v
and by looking at the line
.output_clock_frequency0("48.000000 MHz"),
we confirm, that the clock frequency is actually 48.0 MHz. We need the exact
frequency later in our porting process, for example for defining the
M2M constant CORE_CLK_SPEED
in M2M's globals.vhd
.
pll pll
(
.refclk(CLK_50M),
.outclk_0(clk48),
.outclk_1(clk64),
.outclk_2(clk_sys),
.reconfig_to_pll(reconfig_to_pll),
.reconfig_from_pll(reconfig_from_pll),
.locked(pll_locked)
);
So we have three different clocks plus the ability to reconfigure the clock
speed. Let's start to investigate the latter feature by looking at CONF_STR
.
This line within the configuration string shows us, that the core can be
switched between PAL and NTSC:
"P1O2,Video Standard,PAL,NTSC;",
Codebase64 explains us that the master clock used in actual retro PAL C64 hardware runs at 17.734475 MHz and at 14.31818 MHz in NTSC machines. And that the actual CPU speed for PAL and NTSC was then derived by using a clock divider of 18 for PAL and a clock divider of 14 for NTSC yielding these CPU frequencies:
CLOCK_PAL = 985248 Hz
CLOCK_NTSC = 1022727 Hz
This is already a strong hint why dynamic clock reconfiguration might be used
in the C64 core. Let's confirm this and look where the reconfig_to_pll
is
being used. We quickly find out that there is a MiSTer framework component
called pll_cfg
that allows the dynamic reconfiguration of the PLL. And
there, we see that the emu
module's cfg_write
signal that is wired to
pll_cfg
's mgmt_write
input.
To understand when and how the PLL is being reconfigured so that we understand
better what frequencies are used by the C64 core, let's search for cfg_write
in the emu
module's source code: We find a big
always @(posedge CLK_50M) begin
section and within this section we see a lot of hints referring to NTSC, so we can consider our theory as confirmed, that the two modes PAL and NTSC are one of the reasons why we have dynamic PLL reconfiguration.
Looking at other entries in CONF_STR
we find this:
"oEF,Turbo mode,Off,C128,Smart;",
"d6oGH,Turbo speed,2x,3x,4x;",
So there seems to be a "Turbo mode", which is also confirmed when we look at
the fpga64_sid_iec fpga64
instantiation which refers to the status
flags
controlled by the CONF_STR
menu:
.turbo_mode({status[47] & ~disk_access, status[46]}),
.turbo_speed(status[49:48]),
The question is: Are there additional clocks needed for the turbo mode?
The CONF_STR
documentation tells us, that when o
is used as a lower-case
letter, E
means 46
and F
means 47
. So since the 2-bit turbo mode flag
is set by using status[46]
and status[47]
we just need to check: Where
else are these status flags used? A search in the emu
module reveals:
Nowhere else. So we can ignore the turbo mode for now in the context of
clocking.
Now we need to learn more about clk48
, clk64
and clk_sys
:
-
As the name might suggest,
clk_sys
is the "actual" core's clock: You will see this when you search forclk_sys
in theemu
module source code. You will also notice that it drives a large number of components such as the tape drive, the IEC disk drive, the cartridge emulation, the RAM Expansion Unit (REU) and the mouse. -
The only use of
clk48
is to drive the Yamaha OPL based Sound Expander, which is controlled by theCONF_STR
entry"P1OC,Sound Expander,Disabled,OPL2;"
. -
clk64
is used to drive the pixel clock:assign CLK_VIDEO = clk64;
Additionally it is used by MiSTer's
sdram
component.
Now we open rtl/pll/pll_0002.v
to find out the actual speeds of the three
clocks:
-
clk48
runs at 47.291931 MHz -
clk64
runs at 63.055908 MHz -
clk_sys
runs at 31.527954 MHz
Please note that:
clk64 = (clk48 / 3) x 4
clk_sys = clk64 / 2
-
clk_sys / 32 = 985,248 Hz
(which is equal to the above-mentionedCLOCK_PAL
)
So the standard configuration of rtl/pll/pll_0002.v
(without performing
any dynamic clock reconfiguration) is PAL.
assign CLK_VIDEO = clk_ram;
pll pll
(
.refclk(CLK_50M),
.rst(0),
.outclk_0(clk_ram),
.outclk_1(clk_sys),
.locked(pll_locked)
);
The Game Boy's clocking system is easy: There is no dynamic clock
reconfiguration and there are two clock signals: clk_ram
and clk_sys
.
-
clk_ram
: The video clock is equal toclk_ram
and the only place whereclk_ram
is used is in the instantiation ofsdram
. -
clk_sys
is the retro system's base clock.
Looking at rtl/pll/pll_0002.v
reveals that clk_sys
runs at 33.554432 MHz
and that clk_ram
is running at 2x of this, i.e. 67.108864 MHz.
As we can read in the
Pan Docs,
the Game Boy's CPU runs at 4.194304 MHz. Please note that this is exactly
clk_sys
divided by 8.
Let's look at the instantiation of the actual core:
// the gameboy itself
gb gb (
.reset ( reset ),
.clk_sys ( clk_sys ),
.ce ( ce_cpu ), // the whole gameboy runs on 4mhnz
.ce_2x ( ce_cpu2x ), // ~8MHz in dualspeed mode (GBC)
We notice that there are multiple speed options which are being put into
effect by two different clock enable signals. Searching for ce_cpu
inside
the emu
module shows us, that there is a speedcontrol
component
responsible for generating the ce_cpu
and ce_cpu2x
signals. We make a
mental note that we need to handle this, as soon as we wire the Game Boy's
core module in M2M's main.vhd
.
-
Always validate inside the
emu
module how the clock signals are used. By doing so, you will sometimes find additional features or quirks of the core. -
Looking at the clock signal can quickly turn into a huge rabbit hole: Make sure that you focus on the above-mentioned main questions at this point in time.
-
The Arkanoid and C64 examples show: Some cores have complex clocking set-ups including dynamic frequency reconfiguration. The best practice is: Choose a simple "default" configuration, for example for Arkanoid without the flicker-fix and for the C64 choose PAL and ignore NTSC for getting started (or the other way round). Ignore any "Turbo mode" and other "artificial" and "non-retro" clock speeds and modes. The message is: It is already complex enough to get a first vital sign from your core while porting. So why bother supporting each and every bell and whistle? Focus is the key to success; you can always add more features later.
-
This "focus" best practice is also true for any fancy peripherals such as the Apple II "Super Serial Card" or the C64 OPL based "SFX Sound Expander": It does not harm to do your first steps without supporting all thinkable and unthinkable peripherals.
-
You might have noticed that the core clock and the video clock (also referred to as pixel clock) are often linked to each other, sometimes via multiples of the speed and sometimes by using a clock divider to drive a clock enable signal. Therefore, to understand the clocking you need to understand what a "pixel clock" actually is. Here is a good article that explains it. A pixel clocks is also often referred to as "dot clock". Here is another good article about it.
The MiSTer handles RAM quite differently than the MEGA65. While MiSTer has plenty of fast SDRAM (plus additionally also slower DDRAM), the MEGA65 needs to get by on the FPGA's built-in Block RAM (BRAM) and HyperRAM. While BRAM is super fast - even faster than SDRAM - HyperRAM suffers from a latency of 5 clock cycles for each read operation. HyperRAM can be quite fast (200 MByte/sec) when you use the burst transfer mode (for example in DMA situations).
The BRAM size of the MEGA65 (R3 and newer) is 1.6 MB and the built-in HyperRAM size is 8 MB. The MEGA65 has an expansion slot where you can add more HyperRAM.
M2M runs the HyperRAM with 100 MHz, so given the 5 clock cycles latency, a retro core CPU running at 20 MHz would not notice the latency. This theoretical limit is hard to reach in reality because you need to add some clock domain crossing mechanisms due to the HyperRAM's 100 MHz and the retro CPU's own frequency. If we assume for the sake of simplicity that this costs another 4 cycles, then we have 9 cycles latency and therefore a maximum retro core speed (for latency free HyperRAM access) of 100 MHz / 9 cycles, i.e. 11.11 MHz.
MiSTer2MEGA65 uses the HyperRAM also for scaling the retro core's video output
to 720p on HDMI, while applying great looking video filters, so this puts
additional strain on the HyperRAM bandwidth: Once, the scaling engine (Avalon
Scaler in ascal.vhd
) is in the middle of a burst transfer, we can not
interrupt it, and such a burst transfer can be up to 128 clock cycles.
In summary: At this moment in time, M2M can not guarantee any latency, therefore use it only for use cases that are OK with this constraint. And be aware that the current M2M version does not have implemented yet a HyperRAM "arbiter" for mediating between the Avalon Scaler's and the core's memory needs nor is there a defined way for the core to access HyperRAM. It is on our roadmap, but if you wanted to use HyperRAM right now, you are on your own, i.e. outside of a M2M framework supported used-case.
As of writing this tutorial in July 2022, the MiSTer2MEGA65 framework is still in its infancy and we do not yet have a ton of experience with it nor did we try to add a ton of ingenious tricks to handle the challenging RAM situation on the MEGA65.
M2M needs about 200 KB of BRAM (used as RAM and ROM). Given the latency restrictions of HyperRAM, this leads to the following rule of thumb:
If the sum of "fast" RAM and "fast" ROM that the MiSTer core you want to port needs is below 1.4 MB, then it is straightforward to port the MiSTer core to the MEGA65.
"Straightforward" means that you do not need to introduce heavy changes to the original MiSTer core. Instead, you can "just" use the RAM/ROM components of M2M, which instantiate BRAM.
If the sum is larger than 1.4 MB, then you might be still able to "kind of straightforwardly" port the core to the MEGA65:
(a) The retro machine that the core emulates might have had slow RAM by itself, i.e. there are (a lot of) wait states between the moment when the CPU puts an address on the bus and when it expects the value to be provided by the RAM. The Game Boy is such an example. If you are lucky, then the HyperRAM latency is smaller than what the core expects.
(b) You might be able to split the RAM/ROM needs in some "fast" and "slow" parts and then use BRAM for the fast parts and HyperRAM for the slow parts.
(c) You might be able to decide for a smaller memory configuration than the maximum that the MiSTer core supports and then configure the MiSTer core accordingly. Examples: Our C64 core is currently a plain C64 without a RAM expansion unit (REU). This obviously fits into BRAM. But even if we supported a 1 MB REU, it would still fit into BRAM. Another example is the (not yet available) Amiga core: Instead of supporting advanced chipsets such as ECS and AGA/AA, start with supporting the original chipset (OCS), which will fit into BRAM.
In all other cases you will need to apply heavy changes to the original MiSTer core and come up with ingenious solutions to introduce wait states to the core's CPU without totally spoiling the experience and compatibility. Maybe at a later stage of M2M's development we will provide some of these tools as part of the framework. But right now, they are not available.
If you have a look at the emu
module's input/output port definition, you
will find two sections that are all about RAM:
//High latency DDR3 RAM interface
//Use for non-critical time purposes
output DDRAM_CLK,
//SDRAM interface with lower latency
output SDRAM_CLK,
Searching the emu
module for SDRAM_CLK
will show you if and how SDRAM is
being used. The same is true for DDRAM_CLK
. We do not yet have any
experience with MiSTer's DDRAM usage, but our hypothesis is that the DDRAM
needs can be handled by HyperRAM.
The above-mentioned rule of thumb is about the sum of all SDRAM plus all ROMs
plus all other BRAM instantiations. When assessing the "fast RAM" and "fast
ROM" needs: Additionally to having a look at the SDRAM usage inside the
emu
module, you need to become creative and crawl the file hierarchy
of the MiSTer core (rtl
folder) in search for "hidden" RAMs (frame buffers
are "nice" candidates, but also RAMs within devices) and ROMs (which can be
quite large and add up, too). All these elements added together should not
exceed 1.4 MB as described in the above rule of thumb.
There are two types of ROMs:
a) ROMs that are synthesized into the bitstream and therefore available as soon as the hardware starts.
b) ROMs that are loaded dynamically from an SD card: Either manually by the user of the core or automatically by the M2M firmware on startup or reset.
Here are some examples to clarify this:
-
Our Apple II core has the vanilla Apple ROMs (system, font, keyboard) synthesized into the bitstream, so when you turn on the Apple II core, it "just works". Look how this is deeply "buried" inside the
rtl
file hierarchy, so as described above, you need to creatively search the MiSTer code to find all instances: Apple IIe system ROM, Video/font ROM and Keyboard are classical ROM files that are loaded. In contrast, the HDD ROM is described as a VHDL file containing the byte values of the ROM. -
Similar to the Apple II core, our Commodore 64 core has the vanilla Commodore ROM (KERNAL, BASIC and the character ROM as well as the VC1541's DOS) synthesized into the bitstream. And the ROMs are also similarly deeply buried inside the
rtl
file hierarchy: C64 ROM and VC1541 ROM -
The Game Boy on the other hand works differently: It has a firmware that is stored inside a ROM. Then, the actual games come on cartridges (in contrast to diskettes or a hard disk) and the cartridges are ROMs, too. Let's focus on the firmware first: Nintendo is notorious for being very litigative. Therefore we are shipping our Game Boy core by default with an Open Source ROM as you can see here. Additionally, the Game Boy core loads an original Game Boy ROM from the SD card (and replaces the Open Source ROM) in case it finds it on the SD card. And last but not least, the end-user can load game cartridges (i.e. ROMs) by using the on-screen-menu. We did not yet port these features from our Game Boy core (which predates M2M) to M2M itself. So this kind of ROM handling is on our roadmap but currently not yet available in M2M.
Make sure you are aware of all the ROMs that the core needs and make sure that
you have access to the necessary ROM files. Type (a) ROMs are very often
part of the MiSTer repository in the form of *.MIF
files and/or the MiSTer
core's README.md
file shares more information about where to obtain the
ROMs from. As a rule of thumb you can assume that without the proper ROMs in
place, you will not get any "vital sign" from the core.
Since M2M is currently not yet supporting type (b) ROMs, you need to live with being in a legal grey zone while shipping cores that contain ROMs.
MiSTer uses the Quartus toolchain while MEGA65 uses the Vivado toolchain.
Quartus supports *.MIF
files for ROMs while Vivado does not.
Have a look at the
C64 Kernal ROM
to learn how a typical *.MIF
file looks like. As you can for example see
in
Line 438
of the C64 Kernal ROM, *.MIF
is a "smart" format: It not only supports
address and (re)location data, but it also supports a simple form of data
compression.
M2M on the other hands only supports "dumb" formats such as *.HEX
that
contain the ROM contents as one hexadecimal value per line or such as *.ROM
that contains one binary value per line. Both formats come without any
address and (re)location data.
Here
is for example the above-mentioned C64 Kernal ROM converted to a 8-bit
*.HEX
. And if you open CORE/m2m-rom/m2m-rom.rom
, so can see an example of
the 16-bit "binary" representation.
Here is how you convert *.MIF
files to *.HEX
files:
@TODO TODO TODO @MJoergen
Please note that we consider it a best practice to name converted *.MIF
files *.MIF.HEX
because this enables you to replace parts of MiSTer's ROM
loading routines with own code without big changes inside the MiSTer source
code.
As you might have seen earlier in this chapter while reading through MiSTer's
documentation - particularly while looking at their
Porting Cores
chapter - MiSTer supports different clocks and therefore clock domains for
CLK_VIDEO
and CLK_SYS
. But they also write in their documentation of
module emu
within
Porting Cores
that CLK_VIDEO
normally equals to CLK_SYS
and that it is the clock enable
signal CE_PIXEL
that is making the difference. "Difference" as in deriving
lower clock frequencies from CLK_SYS
(and/or CLK_VIDEO
).
At this moment, M2M only supports the case CLK_VIDEO == CLK_SYS
. We might
enhance the framework at a later moment in time to be more flexible but right
now this is how it works. That means that you need provide M2M with a clock
enable signal relative to CLK_SYS
that fits the video mode that you want to
output.
Here
is a good primer on clock enable signals in general.
Providing M2M with such a clock enable signal either means to reuse a signal generated by the MiSTer core, MiSTer glue-logic or MiSTer framework - or - it means to generate/synthesize such a signal by yourself. We will look at some examples below.
M2M is designed such that on MEGA65's VGA (D-sub) connector we are delivering a signal that is as close as possible to the core's original retro video mode. A good compromise for being "as close as possible" and for making sure that monitors with a VGA (D-sub) input are actually able to display the video mode is to choose from these retro resolutions:
- PAL: 720 x 576 pixels at 50 Hz
- NTSC: 720 x 480 pixels at 60 Hz
- VGA: 640 x 480 pixels or 800 x 600 pixels at 50 Hz or 60 Hz
- 15 kHz analog RGB
M2M's video_modes_pkg.vhd gives you a good overview on video modes, resolutions, aspect ratios, pixel clock frequencies, etc.
When it comes to the MEGA65's HDMI output, M2M is designed to always deliver 720p on HDMI at 50 Hz or 60 Hz which means in pixels 1280 x 720. As this is a 16:9 resolution and most retro systems output 4:3 (or something similar), M2M makes sure to add black bars on the left and right side so that the display on a modern 16:9 display stays pixel perfect. You do not need to worry about the peculiarities of the HDMI output.
M2M features a video processing pipeline that handles the analog retro signal
to create an appropriate output on VGA/D-sub. And it converts and upscales
this retro signal to a digital HDMI 720p output. You can learn more about
M2M's video pipeline here but for now, when it
comes to understanding the MiSTer core it is important to know, that M2M needs
the following signals (provided in main.vhd
):
-- clock enable relative to clk_main
-- clk_main how MiSTer's CLK_SYS is called in M2M
video_ce_o : out std_logic;
-- RGB output
video_red_o : out std_logic_vector(7 downto 0);
video_green_o : out std_logic_vector(7 downto 0);
video_blue_o : out std_logic_vector(7 downto 0);
-- Horizontal and vertical sync and horizontal/vertical blank
video_hs_o : out std_logic;
video_vs_o : out std_logic;
video_hblank_o : out std_logic;
video_vblank_o : out std_logic;
If you compare these signals with the signals that the MiSTer framework needs
by having a look into the
porting documentation
and into the
video signals documentation
of the overview of emu module
then you will notice: M2M needs no
"data enable" signal called VGA_DE
in MiSTer and which is defined as
"not (vertical_blank or horizontal_blank)". Instead, M2M actually needs both
of these blanking signals.
What you now need to understand by examining the MiSTer core is:
- What is the retro video mode that you want to output via VGA/D-sub?
- How can you derive or create
video_ce_o
based on MiSTer'sCLK_SYS
(akaclk_main
in M2M)? - How can you provide the blanking signals that M2M needs?
- Will you need a scandoubler because a lot of today's monitors that offer VGA/D-sub inputs have difficulties managing a retro 15 kHz analog RGB signal?
- Does the core provide an analog signal at all or do you need to work with a frame buffer and synthesize an analog signal to satisfy M2M's signal needs?
There is no cookie cutter recipe when it comes to the video output handling.
You will need to examine the MiSTer source code. A good starting point is
to follow the video signals generated by the "actual retro core" (the one that
is located in the rtl
folder and that is instantiated in the *.sv
file
in the MiSTer root folder). Let's look at a few examples.
@TODO TODO TODO TODO TODO TODO TODO TODO
@TODO TODO TODO TODO TODO TODO TODO TODO
@TODO TODO TODO TODO TODO TODO TODO TODO
@TODO TODO TODO TODO TODO TODO TODO TODO
As we learned in the clocking section above, MiSTer's C64 core uses a
clk_sys
that runs at 31.527954 MHz
while it uses a clk64
that runs
at 63.055908 MHz
and which is used as CLK_VIDEO
. Since M2M only supports
situations where CLK_VIDEO == CLK_SYS
, on the surface this might turn into
a challenge. In the case of the Commodore 64, it does not. We are looking at
a PAL C64 in this chapter; for NTSC everything is similar but the absolute
values are different.
First, we notice, that clk64
runs exactly 2x the clock speed of clk_sys
.
Second,
Codebase64
explains us that the "VIC-II runs at a frequency which is exactly 8 times that
of the CPU.". Last-but-not least we know (see clocking section above),
that in the MiSTer implementation the C64's CPU clock is derived by dividing
clk_sys
by 32.
Putting it all together and doing the math:
CPU clock speed = 1/32 x clk_sys
Pixel clock speed = 8 x CPU clock speed
= 8 x 1/32 x clk_sys
= 8/32 x clk_sys
= 1/4 x clk_sys
So for providing the correct video timing to M2M, all we need to do is to
use clk_sys
as M2M's clk_main
and generate a clock enable signal
video_ce_o
that divides clk_main
by four. A quick look in C64MEGA65's
source code in main.vhd
shows us that this is exactly what is happening:
signal vga_ce : std_logic_vector(3 downto 0) := "1000"; -- Pixel clock is 1/4 of the main clock.
vga_ce_o <= vga_ce(0);
p_vga_ce : process (clk_main_i)
begin
if rising_edge(clk_main_i) then
vga_ce <= vga_ce(0) & vga_ce(vga_ce'left downto 1);
end if;
end process p_vga_ce;
Now that we have the pixel clock done and as the video_red_o
,
video_green_o
and video_blue_o
signals are straightforward for the C64
core, let's see how we can provide the horizontal and vertical sync and blank
signals. As written above, it is always a good practice to follow the signal
path in MiSTer's *.sv
file - in our case c64.sv
- from the "actual"
retro core - in our case fpga64_sid_iec
- to the outputs of the emu
module.
In c64.sv
we can see, that the fpga64_sid_iec
core outputs the following
video signals:
.hsync(hsync),
.vsync(vsync),
.r(r),
.g(g),
.b(b),
Tracing them, we find another module that uses these signals as an input:
video_sync sync
(
.clk32(clk_sys),
.pause(c64_pause),
.hsync(hsync),
.vsync(vsync),
.ntsc(ntsc),
.wide(wide),
.hsync_out(hsync_out),
.vsync_out(vsync_out),
.hblank(hblank),
.vblank(vblank)
);
Interestingly enough, this very video_sync
module outputs new horizontal
and vertical sync signals and it also output hblank and vblank signals, which
is exactly what we need for M2M. This is great - so we can wire them to the
appropriate M2M signals in main.vhd
after we made sure that we found out
what video_sync
actually does and after that instantiated MiSTer's
video_sync
module inside main.vhd
:
-- The M2M framework needs the signals vga_hblank_o, vga_vblank_o, and vga_ce_o.
-- This shortens the hsync pulse width to 4.82 us, still with a period of 63.94 us.
-- This also crops the signal to 384x270 via the vs_hblank and vs_vblank signals.
i_video_sync : entity work.video_sync
port map (
clk32 => clk_main_i,
pause => '0',
hsync => vga_hs,
vsync => vga_vs,
ntsc => '0',
wide => '0',
hsync_out => vga_hs_o,
vsync_out => vga_vs_o,
hblank => vga_hblank_o,
vblank => vga_vblank_o
); -- i_video_sync
In short, additionally to providing us with those vital blanking signals,
video_sync
ensures that our output signal does have the "nice" pixel
resolution 384 x 270. Why is this resolution "nice" and why did MiSTer choose
to crop the output of the C64 core?
Learn more
in our analysis. Another positive side effect is that 270 x 2 = 540 which
exactly fits that PAL resolution after scandoubling.
The C64MEGA65 core uses M2M's built-in scandoubler when producing a PAL signal that is compatible with most "VGA-ish" monitors that connect via a D-sub cable. And in the "VGA: Retro 15KHz RGB" mode, the scandoubler is deactivated.
@TODO TODO TODO TODO TODO TODO TODO TODO
@TODO TODO TODO TODO TODO TODO TODO TODO
@TODO TODO TODO TODO TODO TODO TODO TODO
@TODO TODO TODO TODO TODO TODO TODO TODO
@TODO TODO TODO TODO TODO TODO TODO TODO
@TODO TODO TODO TODO TODO TODO TODO TODO
@TODO TODO TODO TODO TODO TODO TODO TODO
@TODO TODO TODO TODO TODO TODO TODO TODO
@TODO TODO TODO TODO TODO TODO TODO TODO
@TODO TODO TODO TODO TODO TODO TODO TODO
@TODO TODO TODO TODO TODO TODO TODO TODO
@TODO TODO TODO TODO TODO TODO TODO TODO
@TODO TODO TODO TODO TODO TODO TODO TODO
@TODO TODO TODO TODO TODO TODO TODO TODO