Sometimes you start something simple and then it just leads to a chain reaction of things. I wanted to write a post about doing state machines in Verilog and target the Lattice iCEstick board that we often use for quick FPGA projects. That
Sometimes you start something simple and then it just leads to a chain reaction of things. I wanted to write a post about doing state machines in Verilog and target the Lattice iCEstick board that we often use for quick FPGA projects. That led to a small problem: how do you show what’s going on inside? In this series of posts, we’ll look at building a logic analyzer into an FPGA to help debug itself, instantiating memory, and — finally — state machines.
Logic analysis is a common tool in FPGA development. If you use Altera, they have Signal Tap available that lets you build a simple logic analyzer into the FPGA that talks back to your PC. Xilinx has ChipScope which is about the same. Sometimes those tools either cost money or are limited in some way in the free versions. I have my sights set on a tool that can be used with the Lattice architecture.
Sure, you can ship data out on I/O pins and then use a regular logic analyzer to pick up the data. But that isn’t very handy. So I thought about writing a generic logic analyzer component. But before I did I decided to check to see if someone else had already done it.
Spoiler alert: they did, but I wanted something a little different so I wound up extending the program significantly. What I wound up with is a reasonably portable Verilog logic analyzer that can produce traces like this one:
Keep in mind, this isn’t a simulation. This is real data pulled off the actual FPGA. Yes, that is gtkwave producing the plots, but the input data is a VCD file generated from samples taken inside the FPGA.
Good News and Bad News
The good news is I found the verbosely named OpenVeriFla code on OpenCores. The bad news is it was about 11 years old and didn’t seem to work right. Some of it was configuration problems on my part, but there was at least one bug that showed up if you sampled data that rapidly changed. Naturally, after I spent a few days fixing bugs, a new update showed up. So then I had to go figure out what the original author had changed and fix things up in my branch. I wound up making enough changes that I simply forked it and decided to make significant enhancements to make things more useful. However, after correspondence, the author did make a parallel change in the original to squash the same bug, so either fork should be free of the original bug that started me on this journey.
OpenVeriFla is really two parts. There’s a set of Verilog files you have to include with your project. You set the general configuration with a header file. There’s also a Java program that reads the data. This requires the flaky Java serial I/O which had some trouble finding the port on my system. Of course, the real problem will be if you use the serial port in your design — you might have to wire up a temporary serial port on an unused pair of pins just for the logic analyzer to use. In some cases, you might be able to disable your serial port just for debugging but that won’t work if your problem involves the serial port.
You’d think the Java program would display the captured data or create a VCD file that a waveform viewer could consume. But it doesn’t. It creates a Verilog model of the recorded data. You then have to simulate that model to get a VCD file. There might be sometimes that is useful, but I’ll be fixing that so you can directly generate a VCD file if you use my fork.
Not Enough Memory
The first problem I contended with was there didn’t seem to be sufficient memory on the iCEstick board to capture many samples. I suspected I knew the problem, but for the moment, I just reduced the sample size down to something very low. I didn’t want to fix the memory problem until I was certain the bug was something I wanted to spend the time to fix.
I figured if it worked for 16 samples, I could always fix the memory and add more. As I suspected, the memory component was written in such a way that the Lattice FPGA couldn’t use its onboard memory and, instead, had to build all the memory out of regular flip flops. I’ll have more to say about that later.
The configuration of the original code is all done in a file config_of_verifla.v. You can change lots of parameters, although in the original code there are a few other places things have to change. In my rewrite, as you’ll see, I changed how the configuration works a little to make things easier.
My first attempts were to simply read a toggling output line. This seemed to fail. After some investigation, I found that if a signal changed on every clock cycle, the code would miss it. It was an easy fix and the upstream made a similar fix, as well.
After that, things se