| Posts | Music | Github | LinkedIn | Games | Resume | About |

NeoVGA: Neo Geo Line Doubler in VHDL

Sat. May 10, 2014
Categories: Arcade, Display Tech, Game Consoles, Hardware

NeoVGA is a scaling solution to facilitate enjoyment of the Neo Geo on modern high-resolution displays without scaling artifacts or processing lag. Here’s an image of it working well to draw you in:

I’ve been messing with FPGAs and VHDL recently, and did a project I’ve wanted to do for a while – kind of.

I have a lot of old systems that output a ~240-line RGB signal, with a 15KHz horizontal sync and 60Hz vertical sync. Newer displays are seldom compatible with it – even my old 90s CRT TV took some modification to get RGB happening on there.

CRTs are very interesting technology and they are still my favorite type of display. However, it’s not good to be locked into them only, as they are obviously worse for watching movies or doing anything made after the 90s. Interlacing looks awful but it’s the only reasonable way to watch movies or do anything modern on it, which is no good.

Feeding an analogue signal directly to a newer TV means it typically has to capture a frame, render it to a buffer, do scaling / interpolation / other image processing, and then output it to the display. This adds latency, and can also severely degrade the image as those algorithms are usually intended for live action scenes and will make anything with high contrast lines and edges look like a mess. It gets worse when you consider how lossy composite video already is, and that almost every modern TV interprets the signal as an interlaced one. Getting an analogue signal, let alone RGB onto a new display is either expensive or mediocre. The best solution would seem to be a good line doubler like the XRGB-3 in B0 mode, which shouldn’t add any lag to the output. An XRGB-3 costs a lot of money though, as do comparable solutions.

So, here comes the DIY solution! The goal here is to make a 2:1 line doubler that simply doubles the horizontal scan rate to 30Khz by doubling each line. This generates a VGA-compatible signal, and further encoding to DVI or HDMI shouldn’t be too difficult as timings are compatible. Now, the “easy” way of doing this might involve capturing a frame into a buffer, scaling that up to the output resolution’s dimensions, then outputting that. In the best case, this involves a frame of latency, and might necessitate interpolation or blocky uneven pixels. Neither is desirable.

The other solution is the classical “line doubling”. Here, the horizontal scan rate is set to be exactly double that of the source signal. Two line buffers are used here. As the RGB source signal renders one line, it is captured into one of the buffers. During this time, the VGA signal is drawing the other buffer twice. Then, the buffers swap, and it runs again, forever. So long as everything is kept in lockstep, this will be a very efficient, no-lag low-memory form of line doubling.

The trouble with this technique is that a doubled scan rate must be obtained. I’m pretty new to VHDL, and while I know I need a phase-locked loop to get my new frequency, I don’t know a thing about how to actually implement such a thing, so I’m stuck there. That’s why the Neo Geo is a system of interest. It has a discrete RGB DAC, with a 6MHz pixel clock that is exposed to me – I don’t have to pull information from the sync signal at all. More importantly, that 6MHz pixel clock is just 1/4 the 24MHz master clock. I decided to take advantage of the 12MHz CPU clock (master / 2) and use it as my doubled clock for line doubling.

Here’s the Neo Geo MV-1C DAC pinned out:

I got this concept first working using just a single bit, and cycle counting:

Here’s my ghetto setup running on an Altera DE2:

I had some stability issues relating partially to poor wiring and GPIO pin choices, making it go crazy sometimes:

I re-did the wiring, making a breakout section on the Neo Geo:

Now it works great:

Scanlines are optional, too. Here it is working on my desktop LCD monitor:

I moved it over to my Xilinx Virtex 2 Pro Dev kit, as I actually own it (unlike the rented Altera board…)

I’m still dealing with a few stability issues since I’ve moved it over, so I have to check over wiring and maybe make a few timing changes. The last thing I want to do is also use the composite sync coming from the JAMMA egde as a sort of reality check to be sure timings have not drifted, as on some bright scenes the screen will start to scroll left or right. I think there is interference making it miss a clock / register an extra one, so I’ll see what can be done with that.

Here’s a video of it in action:

Update: I’ve moved it over fully to the XUP V2P development kit I have, and it has become pretty reliable. I fixed a few color accuracy mistakes as well, and fixed up the sync signal. I am still working on compatibility as a few monitors still don’t want to sync to it properly. The picture above is it working on a GDM series SONY CRT monitor. Check out these close-up shots of KoF ’99 Kasumi Todoh with and without scanlines:

6 Responses to “NeoVGA: Neo Geo Line Doubler in VHDL”

  1. Neo Geo Gets Line Doubled - RaspberryPiBoards Says:

    [...] looks on our new LCD monitors. [Michael] feels the same way, so he’s created¬†NeoVGA, A Neo Geo Line Doubler in VHDL. Neo Geo, like many classic consoles, didn’t use the full [...]

  2. marshallh Says:

    congrats. you’re lucky to have a CRT taking vga here. They are very tolerant of sync ranges (basically anything works)
    OTOH LCDs are all over the place. Some will take most anything, with artifacts. Others won’t sync. Several of my test monitors would show light/dark vertical banding due to heterodying of its sampling pixel clock vs. my own clock which was 0.25mhz off.
    This is why I had to move to full-frame buffering for sync conversion on the n64 board. Turns out a single frame is not really noticeable compared to the several frame lag most modern tvs incur on compmosite et al.

  3. mikejmoffitt Says:

    Yes, the CRT is much more tolerant, but I’ve been doing most of my testing on an LCD monitor as they are much pickier. The difference of the single frame is not strongly noticeable, and it’s definitely better than what any television’s upscaling processor will introduce, but I still prefer to try to defeat it if it’s reasonably possible. Here it is working on my Dell 2007FPB: http://mikejmoffitt.com/img/neovga/lcd_full.JPG

    That said, the CRT made it much more obvious where my mistakes were – my vsync pulse was too long, and this was shown by the way there was this odd curve at the top of the screen. By shortening my pulse to exactly two lines’ worth, it was fixed: http://mikejmoffitt.com/img/neovga/v2psetup/sync_skewing.JPG

    On many LCDs, this didn’t happen and it looked perfect. I would have never known about it unless I tested on the CRT. I’ve found one of the oddest thing is that putting out any pixel data during the porches can offset the average color for that entire line. I suppose it grabs the signal level as a reference during that period to use for the line. This happens on every monitor I tested with.

    I had some similar problems with not sampling at exactly the right rate, but then I started clocking off of the CPU clock, which happens to be exactly double that of the pixel clock. That made timings much easier and is the reason this project is hard to adapt to other systems. There’s no clock on my design, it is only using the Neo Geo clock.

  4. Jenn Says:

    Try the Lattice MachXO2 dev board for the CPLD solution. It is cheep and probably has enough horsepower & space to fit inside the NeoGEO.

  5. Jens Andrée Says:

    Do you have any plans to put the VHDL for this on github? (or elsewhere)
    I want to get my old Amigas to run on modern monitors and I have a MachXO2 breakout board to use for input analogue RGB and if possible output HDMI/DVI but I’m new to FPGA and could use a pointer or two in the right direction with regards to processing a video signal…
    The microcontrollers I normally use are way too slow to attempt something like this.

    Great writeup by the way :)

    Many thanks in advance!

  6. mikejmoffitt Says:

    Yeah, I want to make it public, but as I learn more VHDL I see how crappy the original code I wrote is. I will want to do a rewrite soon, and then publish that.