{"id":3674,"date":"2026-07-15T11:32:47","date_gmt":"2026-07-15T03:32:47","guid":{"rendered":"http:\/\/manufacturing.wiki\/?p=3674"},"modified":"2026-07-15T11:32:51","modified_gmt":"2026-07-15T03:32:51","slug":"basic-operations-of-on-site-programmable-gate-array-simulation-tools","status":"publish","type":"post","link":"http:\/\/manufacturing.wiki\/index.php\/2026\/07\/15\/basic-operations-of-on-site-programmable-gate-array-simulation-tools\/","title":{"rendered":"Basic operations of on-site programmable gate array simulation tools"},"content":{"rendered":"\n<h1 class=\"wp-block-heading\">FPGA Simulation Tools: Basic Operations Every RTL Designer Needs to Know<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Writing RTL code is only half the job. The other half is proving that the code actually does what you think it does. That is where simulation tools come in. They let you run your design in software before you ever touch hardware. Catch a bug in simulation and it costs you five minutes. Catch that same bug on the board and it costs you a respin.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Every FPGA project needs a simulation flow. The tools vary, but the operations are the same across the board. This guide covers the fundamentals you need to get started, regardless of which simulator you end up using.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Setting Up Your First Simulation Project<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Before you write a single testbench, you need to understand the three files that make up any simulation.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The design under test (DUT). This is your RTL module, the thing you actually want to verify. It could be a state machine, a FIFO, a DSP block, whatever you are building.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The testbench. This is a separate module that instantiates the DUT, drives inputs with known patterns, and checks outputs against expected results. The testbench never gets synthesized. It exists only for simulation.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The simulation script or project file. This tells the tool which files to compile, in what order, and what the top-level module is. Without this, the tool does not know where to start.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A minimal Verilog testbench looks like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>verilog1`timescale 1ns \/ 1ps\n2\n3module tb_adder;\n4    reg &#91;7:0] a, b;\n5    wire &#91;7:0] sum;\n6    \n7    \/\/ Instantiate the design under test\n8    adder #(.WIDTH(8)) dut (\n9        .a(a),\n10        .b(b),\n11        .sum(sum)\n12    );\n13    \n14    initial begin\n15        \/\/ Test case 1\n16        a = 8'd10; b = 8'd20;\n17        #10;\n18        if (sum !== 8'd30) $display(\"FAIL: 10+20 != 30\");\n19        \n20        \/\/ Test case 2\n21        a = 8'd255; b = 8'd1;\n22        #10;\n23        if (sum !== 8'd0) $display(\"FAIL: overflow not handled\");\n24        \n25        $finish;\n26    end\n27endmodule\n28<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">That is the entire flow. Instantiate, stimulate, observe, report. Everything else is just variations on this theme.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Running Simulation: The Step-by-Step Workflow<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Most simulation tools follow the same four-step process. Learn this once and it applies everywhere.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 1: Compile the Design Files<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The tool reads your RTL files and builds an internal database of modules, signals, and connections. This is called elaboration. Errors here are usually syntax mistakes, missing semicolons, undeclared signals, or port mismatches between the DUT and the testbench.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you get a &#8220;module not found&#8221; error, check your include paths. The tool needs to know where to look for your files.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 2: Load the Simulation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Once compilation succeeds, the tool loads the design into memory. At this point, no time has passed yet. The simulation is frozen at time zero, waiting for you to tell it to start.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 3: Run the Simulation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">You tell the tool to advance time. It executes every&nbsp;<code>always<\/code>&nbsp;block, every&nbsp;<code>initial<\/code>&nbsp;block, every assignment, in the order the scheduler determines. Time moves forward based on your&nbsp;<code>timescale<\/code>&nbsp;directive.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You can run the simulation in different modes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Run all. The tool runs until it hits a&nbsp;<code>$finish<\/code>&nbsp;statement or runs out of events. This is what you use for most testbenches.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Run for N nanoseconds. Useful when your testbench does not have a&nbsp;<code>$finish<\/code>&nbsp;and you just want to see what happens over a specific time window.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Run continuously. The tool keeps going until you manually stop it. Good for debugging interactions that happen over long periods, like a UART transmission or a memory write sequence.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 4: Inspect the Waveforms<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">This is where you actually see what your design is doing. The waveform viewer shows every signal in your design plotted against time. You zoom in, you measure delays, you check setup and hold times visually.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The golden rule: if your waveform does not look right, the design is wrong. Do not trust a simulation that passed but you never looked at. Always open the waveform viewer and actually watch the signals toggle.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Writing a Testbench That Actually Catches Bugs<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A testbench that only checks one happy-path scenario is worse than no testbench at all. It gives you false confidence. Here is how to write one that finds real problems.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Stimulate Every Input Combination That Matters<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Do not just test normal cases. Test boundary conditions. Test overflow. Test underflow. Test reset behavior. Test what happens when two inputs change at the exact same time.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For a simple adder, that means testing:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Zero plus zero. Maximum plus zero. Maximum plus maximum. Negative values if signed. Random values in a loop that runs a thousand times.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>verilog1integer i;\n2initial begin\n3    for (i = 0; i &lt; 1000; i = i + 1) begin\n4        a = $random;\n5        b = $random;\n6        #5;\n7        if (sum !== a + b) $display(\"MISMATCH at time %0t\", $time);\n8    end\n9end\n10<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This catches corner cases that your hand-written test vectors would miss.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Use Self-Checking Testbenches<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Manual waveform inspection is slow. A self-checking testbench compares the DUT output against a reference model and prints pass or fail automatically.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>verilog1reg &#91;7:0] expected;\n2<strong>always @<\/strong>(*) begin\n3    expected = a + b;\n4    if (sum !== expected) begin\n5        $display(\"ERROR: %0d + %0d = %0d, expected %0d\", a, b, sum, expected);\n6        error_count = error_count + 1;\n7    end\n8end\n9<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">At the end of simulation, you print the error count. Zero errors means the design passed. Non-zero means something is broken. No waveform viewer needed.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Check Clock Domain Crossing Carefully<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Most bugs in real FPGA designs happen at clock domain boundaries. Your testbench must model this. If your DUT has two clock domains, your testbench needs two clock generators with a known phase relationship.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>verilog1reg clk_a, clk_b;\n2initial begin\n3    clk_a = 0;\n4    forever #5 clk_a = ~clk_a;\n5end\n6\n7initial begin\n8    clk_b = 0;\n9    forever #7 clk_b = ~clk_b;\n10end\n11<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Different frequencies. Different phases. This is what your design will see in hardware, so this is what your simulation must see.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Common Simulation Mistakes That Waste Hours<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Forgetting the timescale directive. Without&nbsp;<code>`timescale<\/code>, the simulator does not know what&nbsp;<code>#10<\/code>&nbsp;means. Is it 10 nanoseconds? 10 picoseconds? 10 seconds? The default varies by tool, and it will not be what you expect. Always put&nbsp;<code>`timescale<\/code>&nbsp;at the top of every file.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Using&nbsp;<code>$display<\/code>&nbsp;instead of&nbsp;<code>$monitor<\/code>. The&nbsp;<code>$display<\/code>&nbsp;statement prints once when it executes. The&nbsp;<code>$monitor<\/code>&nbsp;statement prints every time any signal in its list changes. For debugging,&nbsp;<code>$monitor<\/code>&nbsp;saves you from adding print statements everywhere.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Not resetting the design. If your testbench does not assert reset at time zero, your DUT starts in an unknown state. Every simulation run gives different results. Always add a reset sequence at the beginning of your testbench.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>verilog1initial begin\n2    rst_n = 0;\n3    #20;\n4    rst_n = 1;\n5    #10;\n6    \/\/ now start applying test vectors\n7end\n8<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Simulating at the wrong abstraction level. Behavioral simulation is fast but does not show timing. Post-synthesis simulation includes gate delays but takes forever. Post-place-and-route simulation is accurate but painfully slow. Know which level you need for what you are verifying. For most functional bugs, behavioral simulation is enough.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">A Practical Simulation Checklist<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Before you say your design is verified, run through this list.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Did you simulate with reset asserted at the start? Yes or no.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Did you test all boundary conditions, not just the middle of the range? Yes or no.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Did you check clock domain crossings with realistic clock relationships? Yes or no.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Did you look at the actual waveforms, not just the pass\/fail log? Yes or no.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Did you run the simulation long enough to catch slow interactions? Yes or no.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If any answer is no, go back and fix it. Simulation is not optional. It is the cheapest debug tool you will ever use. Skip it and you pay for it later on the board.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">ChipApex is a global distributor of electronic components: ICs, semiconductors, passives &amp; interconnects. Source active &amp; obsolete parts with wholesale pricing, fast RFQ response, and worldwide delivery.Official website address:chipapex.com<\/p>\n","protected":false},"excerpt":{"rendered":"<p>FPGA Simulation Tools: Basic Operations Every RTL Desig &hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-3674","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"http:\/\/manufacturing.wiki\/index.php\/wp-json\/wp\/v2\/posts\/3674","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/manufacturing.wiki\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/manufacturing.wiki\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/manufacturing.wiki\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/manufacturing.wiki\/index.php\/wp-json\/wp\/v2\/comments?post=3674"}],"version-history":[{"count":1,"href":"http:\/\/manufacturing.wiki\/index.php\/wp-json\/wp\/v2\/posts\/3674\/revisions"}],"predecessor-version":[{"id":3675,"href":"http:\/\/manufacturing.wiki\/index.php\/wp-json\/wp\/v2\/posts\/3674\/revisions\/3675"}],"wp:attachment":[{"href":"http:\/\/manufacturing.wiki\/index.php\/wp-json\/wp\/v2\/media?parent=3674"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/manufacturing.wiki\/index.php\/wp-json\/wp\/v2\/categories?post=3674"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/manufacturing.wiki\/index.php\/wp-json\/wp\/v2\/tags?post=3674"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}