Hi everyone, I just wanted to create a new post around the work to generate Y/C straight out of the MiSTer and let everyone know why I created it, how it works, how many cores have this function and it getting added to the framework.
UPDATE
Y/C and Composite have now been added to the MiSTer framework, to enable the feature please ensure the following are changed in the ini file. The cores are aggressively being updated to include the new framework so please be patient or notify me or the core developer if there is one that's been missed.
Code: Select all
;ypbpr=0 ; (obsolete. see vga_mode)
vga_mode=svideo ; supported modes: rgb, ypbpr, svideo, cvbs. rgb is default.
ntsc_mode=0 ; Only for S-Video and CVBS vga_mode. 0 - normal NTSC, 1 - PAL-60, 2 - PAL-M.
CVBS is not recommended and will not work with any passive or active adapters well. It may work if you are using an external scalar for HDMI.
Sync on Green - disable - (If using an external passive or active adapter)
Dot Crawl - A yc.txt file is now required in the MiSTer root folder to provide accurate reference NTSC / PAL frequencies for each core (This is required to eliminate dot crawl). If the core displays any signs of dot crawl, this may be missing or there may be a typo in this file. If you do notice any issues please send a message to myself or the core developer to see if it can be addressed. (NES defaults with dot crawl as it exists on real hardware, you can change that in the yc.txt file)
Here is an example of what you would see for the SNES, where a new reference frequency (Phase Increment) value is required any time the framerate changes or interlaced mode was toggled:
Code: Select all
SNES_60.1=91625968981
SNES_60.0i=91625968981
Note: Y/C will still work if these values are not in the yc.txt file but they are auto calculated within the framework and will have dot crawl issues, so it is recommended that they be added.
Quick reference link for anyone looking for breakout board designs, cores and sample code:
https://github.com/MikeS11/MiSTerFPGA_YC_Encoder
A bit of History
Back in 2021 I found an old commodore 1702 monitor and picked it up to use in my retro collection. To my surprise, I didn’t know how good the monitor looked compared to my 27 Sony Trinitron TV and when I found out I didn’t have an easy way to connect my MiSTer to the commodore monitor, I created an external encoder using an Analog Digital AD724 encoder with a trim capacitor knowing there were issues with dot crawl.
While the external encoder worked, I found the trim capacitor to be a tiresome task to try to reduce any dot crawl when switching cores, some cores could never remove all the dot crawl, and after a while the trim capacitor failed over wear and tear. I gave this up after a few months and decided to try to write a module to modulate the colour straight from the core.
I started looking at writing the module in Verilog in early 2022 and after a couple months, multiple iterations and support from Kitrinx, Grabulosaure and Paulb-nl I built a functional module that was modular and could be added to the framework if a developer enabled it. Since then I’ve created custom Y/C versions of most cores; this was more or less a challenge to get through the tuning phase of ironing out any dot crawl and as of writing this, there are roughly 140 cores.
How the Y/C Module Works
How the module works is fairly straightforward if you’ve read the book: “Video Demystified: A Handbook for the Digital Engineer”.
Luma and Chroma are generated using the YUV601 colorspace where:
Y (Luma) = 0.299R´ + 0.587G´ + 0.114B´
U = 0.492(B´ – Y)
V = 0.877(R´ – Y)
R´ – Y = 0.701R´ – 0.587G´ – 0.114B´
B´ – Y = –0.299R´ – 0.587G´ + 0.886B´
C (Chroma) = U sin ωt + V cos ωt
Note 1: V is flipped every other line when PAL is enabled, as well a 90% phase shift in the colorburst.
Note 2: Colorburst targets the standard NTSC / PAL specifications, where they are 9-10 cycles and roughly 280-300mV in magnitude. Many consoles will vary in magnitude and may be something that I make flexible in the future, though the impacts to the image are negligible.
Fundamentally, the Y/C module has 3 inputs, and is driven by the cores CLK_VIDEO.
A Phase Increment Value – Used to create the 3.579 Mhz / 4.43 Mhz NTSC or PAL colorburst and chroma signals.
A Colorburst Length – A colorburst start and end value that is dependent on the CLK_VIDEO.
PAL Enable – Switches the Chroma modulation to the PAL standard.
Generating 3.579 Mhz
Because the module is using the CLK_VIDEO clock of the core, the sample rate of the NTSC reference signal is limited to the input clock. E.g 42.954544 Mhz from the NES / SNES core means 12 samples per cycle to generate one fundamental frequency of 3.579 Mhz.
Since each core has a different video clock and they are more likely not to be an exact multiple of the NTSC / PAL frequencies, direct digital synthesis was used to generate the reference frequency at any input frequency.
The Phase Accumulator
The phase accumulator is a 40 bit register where the 8 bits at [39:32] are the integer component of the accumulator and the following 32 bits are the fractional component.
Simply at 3.579 Mhz a 40 bit register should give an accuracy of 0.00002 Hz. I initially had a 32 bit phase increment with an accuracy of 0.005Hz but it still had problems with keeping its frequency locked and had some drift overtime.
The calculation to create the phase accumulator is:
(NTSC Ref * 240) / CLK_VIDEO
Example: Arcade Cores with a 48 Mhz CLK_VIDEO
= (3.579545 * 240) / 48
= 81994819784
Note 1: While this calculation will get the module functional, some cores may also require some additional tuning to remove any dot crawl when using composite. E.g. Vball tuned is 81995085016 and removes any dot crawl artifacts. There is a Test_Pattern_YC core that provides an example of the tuning logic.
Note 2: There is a limitation seen when you start to drive the Y/C module with frequencies under 30 Mhz, surprisingly you can still drive the module at 20 Mhz, but artifacts will be visible to some extent. (This is completely avoided at higher frequencies)
Example Source (Emu): Vball Arcade
The emu module requires the following, where there are 4 parameters to be modified:
Code: Select all
`ifdef MISTER_ENABLE_YC // Old Code Reference
parameter NTSC_REF = 3.579545;
parameter PAL_REF = 4.43361875;
localparam [6:0] COLORBURST_START = (3.7 * (CLK_VIDEO_NTSC/NTSC_REF));
localparam [9:0] COLORBURST_NTSC_END = (9 * (CLK_VIDEO_NTSC/NTSC_REF)) + COLORBURST_START;
localparam [9:0] COLORBURST_PAL_END = (10 * (CLK_VIDEO_PAL/PAL_REF)) + COLORBURST_START;
// Modified Variables
parameter CLK_VIDEO_NTSC = 48; // Must be filled E.g XX.XXX Hz
parameter CLK_VIDEO_PAL = 48; // Must be filled E.g XX.XXX Hz
localparam [39:0] NTSC_PHASE_INC = 40'd81995085016; // ((NTSC_REF**2^40) / CLK_VIDEO_NTSC);
localparam [39:0] PAL_PHASE_INC = 40'd0; // ((PAL_REF*2^40) / CLK_VIDEO_PAL) ;
assign CHROMA_PHASE_INC = PALFLAG ? PAL_PHASE_INC : NTSC_PHASE_INC;
assign YC_EN = status[22];
assign PALFLAG = 0; // if applicable, Change the status to match your configuration.
assign COLORBURST_RANGE = {COLORBURST_START, COLORBURST_NTSC_END, COLORBURST_PAL_END};
`endif
Cores Available:
There are currently 20 Console cores, 11 PC cores and 119 Arcade cores that are available.
https://github.com/MikeS11/MiSTerFPGA_Y ... C%20Builds
I’ve spent months tuning most of the cores available so they have Y/C out with no dot crawl for both NTSC and PAL systems. The tuned values can be found here for reference: https://docs.google.com/spreadsheets/d/ ... sp=sharing
Display Methods
I would first check out the guide at: https://mister-devel.github.io/MkDocs_M ... by-mikes11
If you can hack up a cheap cable for S-Video, you really don’t need anything else, but if you’re using composite, you will need to add in a luma trap.
Custom Breakout Boards (Passive / Active Options)
Alternatively, I’ve built two different breakout boards, one is a fairly cheap passive board with a luma trap. The other is an active breakout board with an amplifier (THS7374) IC as well as two modes that make sure the voltages match NTSC spec if you're connected through the Analog IO board or Direct Video.
Details on the breakout boards can be found here:
https://github.com/MikeS11/MiSTerFPGA_Y ... t%20Boards
Adding the Y/C Module to the Framework
A lot have asked if this will be added to the framework in the future and I believe there is good hope to have this added to the framework in the future. The module is compact and modular and I’ve tried to make it as easy as possible to integrate.
A lot of the leg work was developing a list of “tuned” values for the cores, and that’s mostly complete now.
I’ve also forked the MiSTer Main / Template sources to show how the Y/C module can be integrated.
MiSTer Main:
Adding a yc_out toggle to the ini file to activate the Y/C module:
https://github.com/MikeS11/Main_MiSTer/ ... bb2f4641be
MiSTer Template:
Adding Y/C to the MiSTer Template: https://github.com/MikeS11/Template_MiS ... fcb65b9f90
Note: The current module does not use main to look for the flag in the ini file, it's triggered through the menu options. E.g Video Signal - (RGBS/YPbPr or Y/C)
Patiently Waiting
Learnings from the Process
Timing is important….
When calculating the U / V values I initially didn't account for the delays in the blue and red signals, which was really hard to notice until you look at the colorbleeding.
Rainbowing and Luma traps….
Composite is bad, but there are a lot of CRT TV’s in North America which only have composite as an option. If you can get away with S-Video, I would go down that path for Y/C. But in the case you want that blurry retro feel, a luma trap is a necessity and getting it right is a bit of a pain in the ass to get closer to 100% acceptance. Note the subtle change from the passive breakout board to active below.. That little difference which took months to get was at least worth it to me . But even just a simple hack of a 10uH inductor / 200 pF cap into luma cable works wonders.
There are a lot of ways to go abouts doing it but a passive second order LC filter can make really good improvements.
Here is composite without a luma trap in a worst-case scenario Sonic on the Genesis
This is the same frame with a luma trap using the passive / active breakout boards as well as an external encoder:
Most External encoders have rainbowing issues as well but they are harder to pin down because of the excessive dot crawl to mask it.
Direct Video
Generating Chroma through an VGA to HDMI converter works just as it would through the Analog IO board though there are some caveats. A sync needs to be added to the luma signal, and the ADV7513, which transmits the HDMI signal, creates a dead zone in the RGB signal where the H / V syncs are transmitted. This is through the data enable (DE) flag that gets sent to the ADV7513.
This is not an issue for the composite signal because the chroma and luma signals are combined but S-Video can have the saturation thrown off slightly because of the notch in the signal. I’ve not noticed an issue with my consumer televisions, but I do have to slightly adjust the chroma on my PVM, and the 1702 monitor has a hard time locking onto the color signal.
Simply, there is no problem if you're using composite, and there shouldn't be a problem if you have a consumer CRT, but some of the niche monitors may have compatibility issues. E.g a PVM will need to dial the chroma back slightly.
There is probably a way to fix this through the ADV7513, but I've not found a way to fix this little bug.
Lastly
I still cant stress enough the amazing support from the community and though I probably annoyed many of you out there with stupid questions, I cant thank everyone enough . I'm hoping to take some time now to try to port some old MiST cores over to MiSTer, starting with Nova 2001 and Raiders5.