Picture of fpcga


Published September 18, 2017

I found and bought an IBM 5153 monitor at the annual MIT flea market for just $5, hoping to use it as a dedicated terminal device. On my way out, someone stopped me and said "You know, you'll never get that thing to work." Turns out the DB9 connector on it is not for serial but for CGA, an interface that has long since been abandoned for more modern ones like DVI, VGA, HDMI, and DisplayPort. Rather than giving up, I bought a cheap Cyclone II FPGA board and spent many hours of programming in Verilog to make it work as a serial terminal graphics adapter!

I was able to support most terminal control sequences needed to get basic shells and programs running in 16 colors without problems. From personal experience, the monitor makes an awesome dedicated htop or nyancat display. It's a bit less fun to write code on it, and not only because Neovim assumes support for newer control sequences that would be impossible to properly implement on this hardware setup.

I ended up designing a dedicated breakout PCB for the FPGA kit. It connects a DB9 connector directly to the FPGA, and routes the serial IO through an FTDI serial-to-USB converter and a USB-C port, truly bringing this monitor into the modern era.

I coded up a Linux program that allowed me to capture input to an opened terminal emulator and forward it to be shown on the monitor instead. This was surprisingly difficult to accomplish, but allowed me to integrate it with my normal tiling window manager workflow as a secondary monitor.

I also created a Verilog testbench - with some clever use of readmemb, fwrite and ifdef directives, I was able to preload the contents of a file into the simulated command buffer, run long enough to consume all the contents of the buffer, and finally assert a test-only signal that would dump the contents of the simulated character buffer directly to a file. Then, with a small amount of Python scripting and the help of the script command, I implemented a complete test framework that could record all of the command sequences from sessions in a terminal emulator and save them into a full regression test suite.

porting to the iCEBreaker

Using a proprietary IDE like Quartus is a painful experience, but was the only real option at the time. Eventually I learned about the open source Yosys suite and IceStorm toolchain, which I was eager to try out on a new iCEBreaker board. Porting it was not an easy process.

The first thing I discovered is that the inferred RAM and ROM blocks were not being detected, so I had to rewrite those. The Cyclone II had a dual port RAM block that had no equivalent on the iCEBreaker's iCE40UP5k FPGA. Drawing a character to the screen and requires reading the character buffer, and scroll operations require reading the character buffer to copy characters to new locations on the screen. Drawing and scrolling were previously supported concurrently by the dual ports, so I had to rewrite the character buffer to be used exclusively by one at a time.

The next thing I discovered is that I had no clue what pipelining was when I made the initial implementation. I had some insanely long logic paths! Retrospectively, I'm shocked that it ever worked on the Quartus II, but yosys was much more strict about clock cycle timing and I had to split pipelines up with register gates.

Neither of those were small changes, but I eventually got it working on the iCEBreaker!

current status

At one point I began adding some basic support for Unicode characters. There isn't enough ROM on the FPGA for a full Unicode character map, but I wanted to make sure multi-byte Unicode characters could occur without messing up the terminal spacing or causing other unintended side effects. I also wanted to add support for fallback to "similar-enough" characters in the extended ASCII range, notably for broken line-drawing characters I'd seen in a few programs.

I hadn't quite finished Unicode support by the time I was porting to the iCEBreaker, so I'd disabled it altogether. I intended to enable it, finish it, and finally publish everything as open source.

In the midst of that upgrade, I packed up the monitor and moved across the country to San Francisco. I put the monitor in its own box with a bunch of clothes and bubble wrap as padding... but it shattered horrendously in multiple places, including the vacuum tube inside. I now have an antique pile of debris and a codebase that only sorta works. I'd like to get a new one and get my code out there, but I'm now wary of how fragile these things really are.

At least in the meantime, I've already published klostro, the font I designed for the monitor, and mkfontrom to translate it and other character grids into hardware synthesizable memory initializers.

I still think it's safe to say I proved the person at the flea market wrong.