In the last few installments, we looked at using the Tang Nano 20K with both the GOWIN tools and some open-source tools. The open-source tools certainly had the advantage of letting you simulate and debug your design before sending it to the actual chip. However, as we’ll see, the GOWIN tools include a very easy-to-use, capable logic analyzer.
Setup
First, you’ll need a GAO config file. When you create one in the editor, you are given a number of complex options. With an active GAO file, the tool builds a logic analyzer into your design, and the file sets the trigger conditions.
Here’s a tip. You can only have one active GAO file. Sometimes you don’t want the logic analyzer. Other times you might want an alternate configuration. If you right-click almost any file in the IDE’s Design tab, you’ll see you can disable it. That gives it a big red X and excludes it from future builds. Well, at least until you enable it again. This lets you pick between multiple GAO files, or even multiple Verilog files, for a particular build (e.g., one for tests and another for production).
If you create a GAO file from scratch, it will ask you if you want “Lite Mode.” As far as I can tell, you will never want this mode. Always use Standard Mode. In addition, you nearly always want RTL mode, which shows you (mostly) the symbols you’ve defined and not the ones added during processing.
You can find the entire manual online, of course. However, the video below and the rest of the post will get you started quickly.
GAO Basics
To set up probing, we need to understand the design, so the rest of this post covers the Verilog we’ll use to test the logic analyzer feature, and you’ll see how the analyzer works in a video. Here are a few sneak peeks at what the analyzer output we’ll see at the end looks like:
The left-hand image shows the pulse that flips the LEDs, which is tricky because the sampling clock is 27 MHz. The right-hand side shows serial data and uses a slower clock specifically used for debugging.
Inside the Verilog
Verilog can be dangerous. If you already know how to program, Verilog looks just enough like a programming language to encourage you to think about it the wrong way. You can’t think of Verilog as code. It describes how you want hardware to behave. A key part of that is clocks.
Most practical digital systems have some kind of clock that makes things work. Very simple things like our last example might not need them, but practical systems almost always do. In theory, you can make asynchronous logic, but it is very difficult. Synchronous logic — those with a clock controlling things — is vastly more common.
Why Clocks?
We think of signals as changing instantly, but they don’t. They change at slightly different times for many reasons: wire length, capacitance, differences in device construction, temperature, and probably many other things. So let’s think of an exaggerated example. Suppose you have a super safe car. If it detects the motor is running and the door is open, it kills the engine. That’s an AND gate, and for the purposes of exaggeration, suppose the signals from the door and the engine that feed the AND gate take a random amount of time between 100 and 900 milliseconds to get to the AND gate.
Normally, it wouldn’t matter much. You close the door, check your mirror, turn on your playlist, and you start the car. But suppose you were in a panic. You jump in the car and immediately try to start it. The engine start signal could get there before the signal that the door is open turns off. Suddenly, your engine cuts off right after you start it. Not cool.
This is a bit made up, but the problem is real. Suppose you want to add two numbers. One number changes from 11 to 22 while the other changes from 5 to 10. You want 16 and 32 as results. But instead you get 16, 27, and then 32. Or maybe 16, 21, and then 32. Still not cool.
So clocks basically let you give everything enough time to settle down and then figure out the output. Those outputs will stay stable until the next clock. That’s grossly oversimplified, but we’ll talk more about it later. Each thing in your design takes some time, and the longest time, in general, will dictate your maximum clock rate. So if one part of your design takes a microsecond to reliably change, your frequency will have to have a longer period than that.
Check out the example file. This is regular Verilog, although SystemVerilog (.sv files) has some advantages that you can utilize that I’ll point out. The example we’ve been using is a very simple design that just drives some LEDs on the 20K board. The input clock will be 27 MHz, so to make the LEDs blink, we will need to count many clock cycles and only change the LEDs sometimes.
In addition, it is going to use IP — predefined blocks — to build a UART. The function is simple and contrived. By default, entering a character through the UART will echo it. However, if you push the user button on the board, it will switch the board to a mode where it adds one to the character before resending it. If you push the button again, the output will be a straight echo. When you push the button in either case, the device will send an asterisk.
From the Top
At the top of the file you’ll see this line:
default nettype none
This is a good idea because without it, Verilog will happily create new nets from typos. For example:
countt=count+1;
Now count doesn’t change, but a new wire, countt is set and never used. The only problem is that some of the GOWIN IP expects the default nettype to be wire so at the end of your files, you need to put it back:
default nettype wire
Another quirk is that while some tools will realize that if you specify an input or an output, it should infer that you mean a wire unless you say otherwise. The GOWIN tools will refuse to do this if you set the default type to none.
Modular
The next part is the led module. This is a reusable piece, in theory. However, it is also our top block. The #() syntax allows me to set some parameters you can change when you create one of these modules, as well as the defaults. For example, in the previous testbench I wrote:
led #(.CLOCK_FREQUENCY(10, .INTERVAL_MS(1000)) uut(.reset(reset), .Clock(clk)...
This sets a slow clock and interval for simulation purposes instead of using the defaults. Not all modules have parameters. After that, though, there is what looks like an argument list of inputs and outputs. These are the ports you can use if this isn’t your top module, but since this one is the top module, we’ll need constraints to assign them to particular pins on the FPGA.
The localparam statements are like #defines in C, and we use them to set the required counter and figure out the number of bits we need for the counter ($clog2 gives us the base 2 logarithm at compile time).
Most of the time we deal with wires. Something has to drive them. They are perfect for connecting to things. But then there are also regs. You might think these are flip-flops, but that’s not exactly true. They are just Verilog variables, if you will.
It is easy to think of wires and regs as being 1 or 0, but it turns out Verilog also supports values like X (unknown) and Z (sort of like open collector). In fact, SystemVerilog allows you to write logic instead of wire or reg, something we’ll talk about soon. However, there is so much “plain” Verilog out there that it is important to understand it even if you plan to use the more modern SystemVerilog in your own work.
Look at this line:
reg [COUNT_BITS-1:0] interval_count;

This tells us that we have a reg named interval_count. It has bits that range from bit 0 (least significant) to COUNT_BITS-1. Note that you can reverse those if it makes sense for your design. Or start at bit 1, for example. This is not an array, although Verilog does support arrays. This is a multi-bit variable. If you don’t specify the bits (like the interval_tick definition that appears next) then the variable is a single bit.
The next bit of code defines reg and wire variables that will connect to the UART. For now, we aren’t building our own UART. We’re using the IP provided by GOWIN. One problem with this is that it is really made to connect to a microprocessor, so we are going to cheat a little to make it simple to use. You can insert IP into a project from the Tools menu under IP Core Generator.
The final setup section handles the pushbutton input and LED state. The pushbuttons are not synchronized to the clock and this can lead to a major problem. Plus, mechanical switches can bounce — that is, they don’t go off then on. They go off, on, off, on, off, on, off, and then — after a few milliseconds — they settle in the on state. There is a debounce module included to help with these problems. For now, we’ll just use it like we’ll use the UART, even though this module is in debounce.v.
Instantiation
Here’s how we create a debounce module. You could, in theory, create as many as you like:
debounce #(
.CLOCK_FREQUENCY (CLOCK_FREQUENCY),
.DEBOUNCE_MS (10)
) button_filter (
.Clock (Clock),
.reset (reset),
.noisy_button (pushbtn),
.clean_button (button)
);
The name of the instance is button_filter, and we’ve set parameters to tell it our clock frequency and the debounce time, which is 10 milliseconds. The connectors are the clock and reset lines, along with the button input and a clean version of the button as an output.
Assignment: UART
There are a few lines that start with assign. These are Verilog’s soldering irons. You can connect a wire output to some variable or expression, and then that is what that wire will be. We’ve seen that in the earlier LED-only demos.
Then there is a much more complex instantiation of the UART. Although it has more ins and outs, it is basically the same as connecting the debounce module. Note that in some cases I just force fixed data to a pin (e.g., 3’b001, which is a three-bit binary constant, or 8’hff, which is an 8-bit FF hex. Some connections are wires or regs. Some are expressions like ~reset (the inverse of reset).
The upshot is simple. When uart_rx_ready_n goes low, you can read a character from uart_rx_data. The transmit has a similar setup.
The Flop
The rest of the file has three always expressions. There are two things you can do with always (in fact, SystemVerilog separates these out as we will see in the future). For now, we will focus on how to write clocked flip flops using always @.
The simplest one is the last one that toggles the LED state:
always @(posedge Clock) begin
if (reset)
led_state <= 1'b0;
else if (interval_tick)
led_state <= ~led_state;
end
This will create a flip-flop that triggers on the positive edge of Clock. If the reset line is high, the flip-flop will set led_state to 0. Otherwise, it will set the led state to the inverse of whatever it was before.
There are a few things to note here. First, led_state can’t be set anywhere else but inside this always block. The other problem is a bit trickier. Note that the assignments use <= and not =. You could write = but that leads to a problem. Imagine this code inside an always block:
qout=3'b000; if (b) quot=~quot;
Verilog would interpret this to mean that quot should be set to 0 before the next line. Remember, though, that Verilog at “run time” doesn’t step through code line-by-line. So it would infer a latch to hold this value and feed it to the logic that handles the second line.
Not only is this not what you want, but it generates strange things on the device that will not operate efficiently. Instead, you want to use the <= assignment. In essence, every value of quot read in the always block will be whatever quot was at the clock edge. Then, at the end of the block, the last <= assignment “wins.”
This is probably what you really meant anyway and avoids creating strange latches that will, at best, slow down your design. In practice, you can think of it as the flip-flops will capture inputs on the clock edge, then produce outputs that will be ready (at least) by the next clock edge.
Metastability

I mentioned the debounce module did two things: debounces the mechanical switch and synchronizes with the clock. The problem is that we imagine flip-flops to be perfect but, of course, they are not. Any practical flip-flop has a setup time and a hold time. Imagine a very bad flip-flop that had a setup time of 100 milliseconds and a hold time of 50 milliseconds. That would mean that an input has to be stable for at least 100 milliseconds before the clock trigger and can’t change until 50 milliseconds after the trigger.
This is one thing that affects your maximum clock speed. Logic has to have time to stabilize before the clock triggers. But if something is coming from another clock or, worse still, asynchronously, then you run a risk. If the flip-flop’s requirements are not met, it can go metastable, where it could be in an indeterminate state or even oscillate wildly.
The most common way to combat this is to delay the signal with a few flip-flops. The idea is that even if one flip-flop goes metastable, it won’t go all through the system. Just something to be aware of if you deal with something asynchronous or try to connect flip-flops using one clock to those using a different clock.
If a Picture’s Worth…
Now that we know what’s going on in the Verilog, we’re ready to set up the logic analyzer. You can find out how that works in the video below. You can also grab the files on GitHub.
Be sure to drop by the Discord. If you need a refresher on digital logic, there are always the FPGA Bootcamps.



I’d love to take my Spartan 6 eval board out of the dusty drawer but sadly I really have nothing that I can think of, to use it for.
I’d really love to buy an FPGA and get started learning this stuff, but same problem. What do I do with the thing?
The eval boards generally come with some sort of a video out and like, buttons or something, so it’s not that hard to port various arcade games to them (older, obviously, when they were a lot of dedicated logic).
Obviously there are designs out there to do that already, but doing it yourself helps you understand how they work and easily add features to it.
The world needs something like Exercism for FPGAs the learning curve is a bit steep, from “lets blink a LED” directly to implementing a CPU with caching DDR3 ram controller. There used to be a MIT or similar open course video set that was pretty smooth increase in complexity. To a first approximation, take a microcontroller class, then do the labs in a virtual CPU in the FPGA with custom accelerated hardware peripherals for the CPU (like make your own hardware I2C controller as a project). Then try stuff like implement the Game Of Life outputing HDMI using four microblaze (if xylinx) or other CPU cores in the CPU. The MIT (or whatever) class videos I watched a decade ago had a fun project, generate drum/cymbal sounds using an array of on chip processors calculating drum movement from first principles, its a cool project glad I didn’t have to put that kind of time in when I was in school.
Excellent article, Al!
The “default nettype” behavior is something that has bitten everyone, so we should probably tattoo it on our foreheads…
Btw, regarding the metastability – what Al describes in the article is a mandatory conversion of asynchronous to synchronous signal, where the “synchronous” means “synchronized with the current clock domain”. You can see this also called “registration” (which means “passed through a register”) or “reclocking” (which means “synchronized with a specific clock”), or even “glitch filters”, “debouncers” (especially with signals being input from mechanical switches), or “synchronizers”.
What I’m trying to say – metastability of an external signal being input to a synchronous digital circuit is impossible to eliminate. But each synchronization step both reduces the probability of it, and concentrates the metastable behavior mostly inside the synchronization stage.
Metastability is a huge issue in both ASICs and FPGAs, and basically all designs have to take some practical mitigation measures for it.
And finally – what is metastability? It is a phenomenon, where a synchronous digital circuit (e.g. one with digital clock signal) starts to behave like crazy when subjected to an external signal with inappropriate timing. Here “crazy” means 2 basic, very nasty things:
[1] – The digital circuit stops reacting to external signal and clock events.
[2] – The digital circuit creates a random, erratic series of glitch pulses.
The duration of these is random, but there are statistical models describing it. The basic explanation is: the more time the circuit is inside the metastable state, the higher the probability to exit it, but the actual time is unbounded.
Kind regards.
PS: Please don’t hesitate to share corrections for any of my incorrect statements.
“The most common way to combat this is to delay the signal with a few flip-flops.”
Metastability is so much worse than this. You can’t actually just reregister something because the synthesis/implementation doesn’t know that it’s not supposed to use the entire clock for routing – and in some FPGAs, they have special resources for shift registers that you don’t want to use for clock synchronization.
If it uses the entire clock for routing, you’re not actually giving it time to settle because the next register is still seeing the instability right after it gets clocked.
Xilinx tools have an attribute for this (ASYNC_REG) whereas the Altera tools are supposed to “magically detect it” (yeah, right). Don’t know about Gowin – my guess would be they take the Altera route and say “uh… don’t worry about it.”
You also really need a delay constraint between the source and synchronizer, because if you tell it “you can take forever”… it will. And if your clocks are fast and the FPGA is big, you can get Really Weird results. Usually I just set it to the period of the slower of the two clocks.
Can it be mitigated by clocking out from the FPGA on a dedicated pin, and using some external de-glitching hardware ? I don´t know much about this topic but that is the first thing that come to my mind.
No, for a few reasons. First, actually getting off chip will make the problem worse because the output buffers will slow the transition down and widen the “this signal is changing” region.
But second, FPGAs really are excellent synchronizers, because you have tons of registers and can pack them incredibly close together.
The issue isn’t hardware, it’s software: understanding the timing requirements when you have multiple clocks is just hard, and not even the engineers at the FPGA companies know what’s needed. Seriously, there are debates in the Xilinx forums between their own employees on this stuff.
The entire key to dealing with multiple clocks is to understand the timing model and how this stuff works. Once it’s clear, handling the synchronization stuff is easy.
Also there’s a good article series here (this is #2 and has a good simple graphic) on synchronization and what’s needed:
https://www.linkedin.com/pulse/reliable-cdc-constraints-2-counters-fifos-lukas-vik-ist5c/
You’ll note that the date in this article is 2024: these topics are actually all fairly recent concerns because 10-15 years ago FPGAs weren’t realistically fast/big enough that you could get these issues – the tools didn’t even have the ability to constrain bus skews like this.
(They’re also still not good enough, because they calculate bus skew incorrectly, but that’s apparently only a fight I care about because the Xilinx engineers never acknowledged the issues I filed).
Hi Al:
I finally had a chance to look at some of the code, and you’re unfortunately falling into one of the traps in Verilog: if clauses containing unrelated logic.
As you mentioned it’s tempting to think of Verilog like programming, so you get stuff like: “if reset, clear register A and B. Else if condition A, increment A. Else if condition B, increment B.”
This is in the debounce module, for instance. The problem with this is that it creates a dependency on condition A for B that isn’t wanted. In other words, if condition A happens, it ignores condition B and that doesn’t happen.
Even if this doesn’t do anything (in the debounce module it won’t do anything wrong) it usually creates excess logic, because the synthesizer isn’t smart enough to realize it can’t do anything.
So in the debounce module, for instance, there’s probably a conditional that gets generated for “clean_button” where if it’s reset, it gets set to zero, and then it gets set to sync_ff2 only if debounce_count is reached and sync_ff2 is not clean_button.
Instead, you really want to split the if clauses entirely: so the clean_button logic would be purely “if reset, clean_button = 0, if debounce_count is reached, capture sync_ff2. and then the similar split off logic for the counter.
Counting up is also more costly than counting down and looking for a rollover, but that’s a separate issue. Multiple statements inside if clauses is a lot more dangerous.
I appreciate you looking at this in such detail. I do think we’ll have to agree to disagree. Sure, if/else can create priority logic for unrelated items. However, in the debounce module, the conditions are related. In this case, we want only certain assignments to occur based on the logic of the if. That’s intentional and Verilog handles that easily both in simulation and in synthesis.
I also think modern synthesizers (at least the ones I usually use, although I can’t speak with certainty about Gowin’s) are pretty good at optimizing this sort of thing. Much like modern C compilers, they’re generally capable of recognizing redundant operations and simplifying them. Removing a condition that the synthesizer can eliminate anyway doesn’t necessarily save hardware, but it may make the source less readable.
The same goes for counting down. A zero comparison can certainly be cheaper than comparing against an arbitrary constant, but whether the overall counter implementation is more efficient depends on the target architecture and how the synthesis tool maps the logic. Counting down isn’t inherently better. It would be interesting to further decompose debounce.v and then look at resource usage both ways. Same for count down.
The only way to know for sure with a particular synthesizer is to try the alternatives and examine the resource utilization and timing. With the more mature tools, I would expect little difference for something this simple, and you might even find differences that go in the opposite direction from what you expected. Granted, I don’t know whether Gowin’s synthesizer is in that category.
I think unnecessarily coaxing the synthesizer to optimize is much like trying to hand-optimize C code for a modern compiler. You can often improve the algorithm better than the compiler can, but trying to second-guess its code generation is much less productive. I’d rather write clear RTL that expresses the intended behavior and optimize it when the synthesis results demonstrate a reason to do so.
But I do agree that countdown timers are often more efficient and I also agree that unrelated logic surrounded by ifs can be a bad thing. In this case, though, I don’t think these were inappropriate.
“The only way to know for sure with a particular synthesizer is to try the alternatives and examine the resource utilization and timing. With the more mature tools, I would expect little difference for something this simple,”
Yup, I’ve done that. Before life (sigh) got in the way, I had started writing up the results in a series called “Synthesizers are Terrible”
https://u.osu.edu/dbarawn/2025/08/05/synthesizers-are-terrible-prologue/
Unfortunately I never got to the unrelated logic section, but the difference isn’t small. ZipCPU has a good page on that:
https://zipcpu.com/blog/2017/06/12/minimizing-luts.html
The biggest effect with unrelated logic in if statements is actually that you often end up creating lots of incompatible control sets, and you will run out of those faster than you run out of resources. This is common on smaller FPGAs and is a royal pain, since you’ll generally hit it around as low as 30-40% utilization. Usually the biggest benefit is “consider whether or not you really need a reset for every signal”, since getting rid of the set/reset is generally the biggest cost.
“I think unnecessarily coaxing the synthesizer to optimize is much like trying to hand-optimize C”
Synthesizers aren’t code generation engines. They’re far more like basic pattern matching with a little bit (but not a lot) of logic reduction. Most of the ‘smart’ portion is in identifying state machine logic and pushing constants. They (frighteningly) don’t even optimize basic arithmetic, especially constant integer multiplies, which are abysmal.
And they’re trying to match to individual flipflops with LUTs in front of them, so writing in that style helps a lot.
I’ll just have to disagree on readability – including unrelated logic doesn’t help readability because it makes it harder to see what actually happens. For instance, in the debounce code (where again, it’s unimportant, because it’s a simple module), is it obvious that the (sync_ff2 == clean_button) conditional does nothing to the clean_button assignment? To me, I wouldn’t say so.
It’s not widely known, but Microchip FPGAs feature 2 dedicated pins that can be routed out to the signal of all Logic Element.
Furthermore, you can dynamically switch which signal is connected to these pins in real time.
Since this eliminates the need for re-compilation, it is remarkably convenient
—far more so than other similar tools.