Digital Hardware Design : From Zero to One

Digital Hardware Design : From Zero to One

A fast ramp up on digital system design. Blog 1 of many.

I recently started delving into some projects related digital circuits at work and I found myself back in tutorial hell. Took me some time but I was finally able to make some progress on the digital design front. By all means, I am no expert but I'll be sharing what I think is a fairly fast way to get started with digital design.

Verilog : Hardware Description Language

Syntactically Verilog is similar to C/C++ but semantically the language is based on concurrent hardware operation which is very different from sequential execution of C/C++. Just like in any other language, there are many different ways of achieving a result but the focus of this blog series is to quickly get to a point where we are able to design hardware. So i'll try to come up with a verilog skeleton that we can use to generate hardware that is synthesizable in a better-safe-than-sorry approach.

Setting up the environment

I'm a big fan of open-source tools and running stuff locally on my machine rather than on servers. You could get by using an online verilog compiler but i'll be using Icarus Verilog, GTKWave and CocoTB to simulate, view waveforms and write testbenches respectively. To set this environment up, you can refer to one of my previous blogs.

Verilog Skeleton

module modulename
// Port Declration
(
input wire in0, in1,
output wire out0
);
// Internal Signal Declaration
wire sig0, sig1;
// Block logic
assign out0 = sig0 & sig1;
assign sig0 = in0 & in1;
assign sig1 = ~in0 & ~in1;

endmodule

The above is a sample verilog code, we'll try to understand the basic syntax of the language used in this example and i'll leave it upto the reader to figure out the syntax in future examples as we move forward.

Port Declaration

The port declaration specifies the modes, data-types and names of the module's I/O. Modes are typically input, output or inout, data-type is usually wire but other data-types like reg, realtime, integer exist but not all of them can be physically synthesized.

Internal Signal Declaration

This section specifies the internal signals and parameters and can be thought of as the internal wires connecting various circuit parts in a module.

Module Logic

This is the program body of a verilog module and can be thought of as a combination of circuit parts that execute concurrently. There are several ways to describe a circuit part. We have used continuous assignment in the example above but there are other ways like the "Always Block" that are used in more complicated circuits.

Testbench

Once a module is developed, it can be simulated to verify functional correctness. Usually in companies there's a whole another team to run thorough checks using simulation where they use things like UVM, etc. But once you write code it's still worthwhile to do some basic checks on your own. Simulation is usually performed with the same HDL framework but we're seeing more options availble like cocoTb that allows you to write your test bench in python rather than verilog which gives you access to more advanced computation libraries like numpy, pytorch and scikit-learn.

`timescale 1ns/10ps

module modulename_testbench;
    reg test_in0, test_in1;
    wire test_out;

    modulename uut(.in0(test_in0), .in1(test_in1), .out0(test_out));

    initial begin
        $dumpfile("sample.vcd");
        $dumpvars(0, modulename_testbench);
        // Test Vector
        test_in0 = 1'b0;
        test_in1 = 1'b0;
        // Wait time
        # 100;
        test_in0 = 1'b1;
        test_in1 = 1'b0;
        # 100;
        test_in0 = 1'b0;
        test_in1 = 1'b1;
        # 100;
        test_in0 = 1'b1;
        test_in1 = 1'b1;
        # 100;
        $finish();
    end
endmodule

Simulation - Verilog

If you're a college student you probably have access to some kind of tools like Cadence Xcelium or Vivado but if you don't have access to those tools and still would like to simulate your circuit, Icarus Verilog is pretty good. You won't be able to simulate a full fledged AMS design but purely digital designs should not be an issue.

iverilog -o samp modulename.v modulename_testbench.v
vvp sample
gtkwave sample.vcd

Simulation - Cocotb

To simulate with cocotb we do not need to write a testbench in Verilog. But if you remember we were using the testbench to also generate the VCD file to view the waveform.

module modulename
// Port Declration
(
input wire in0, in1,
output wire out0
);
// Internal Signal Declaration
wire sig0, sig1;
// Block logic
assign out0 = sig0 & sig1;
assign sig0 = in0 & in1;
assign sig1 = ~in0 & ~in1;

initial begin
    $dumpfile("waves.vcd");
    $dumpvars;
end

endmodule

The python test bench looks something like this.

import cocotb
from cocotb.triggers import Timer, RisingEdge

@cocotb.test()
async def test_modulename(dut):
    a = (0,1,0,1)
    b = (0,0,1,1)
    y = (0,1,1,0)

    for i in range(4):
        dut.in0.value = a[i]
        dut.in1.value = b[i]
        await Timer(10, 'ns')
        # assert dut.out0.value == y[i], f"Error at iteration {i}"

The assert statement can be used to make the simulation "stop on fail" where it matches the "out0" signal to an element in array y.

Cocotb makefile and other additional files are in this github repo.

Parting thoughts

This was the first blog and I hope to write more as I learn more about digital design, there's alot of interesting topics that I would like to discuss like BIST, DfT in due time.

Let me know what you guys thought about this one. Feedback is always appreciated.