DornerWorks

Setting VHDL Generics in FPGA Verification Made Easy with Cocotb

Posted on December 3, 2019 by Juan Morales

If you’re already using cocotb, you likely have already discovered its ease of use and accessibility in verification tasks. It proves particularly helpful when setting VHDL generics, and here’s how you can take advantage of that capability.

As mentioned in the previous post, “Install Cocotb on Windows 10 to Boost FPGA Verification Productivity,” cocotb is a testbench environment for verifying RTL code using Python. The open source verification framework provides several advantages over the current mainstream ASIC and FPGA verification methodologies of SystemVerilog and UVM, among those being the abilities to edit and rerun test cases without recompiling RTL code, abstract RTL simulator interaction, and reduce overhead in testbench creation.

As a hypothetical case, suppose you have a module with a generic whose value you wish to update for simulation. Generic values allow static parameters like timing and size data to be sent from one architecture in a design unit, but apply to the whole of the DU.

Now, how can you update them using cocotb?

Let’s start by using the adder example provided in the git repo for cocotb.

 -- Adder DUT
library ieee ;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

 

entity adder is
generic(
DATA_WIDTH : positive := 4);
port(
A : in  unsigned(DATA_WIDTH-1 downto 0);
B : in  unsigned(DATA_WIDTH-1 downto 0);
X : out unsigned(DATA_WIDTH downto 0)
);
end adder;

 

architecture RTL of adder is
begin
process(A, B)
begin
X <= resize(A, X'length) + B;
end process;
end RTL;

In order to change the generic  DATA_WIDTH , you can pass the  GENERICS  variable to make.

make SIM=questa GUI=1 TOPLEVEL_LANG=vhdl GENERICS="DATA_WIDTH=10"

When QuestaSim opens up, the value for  DATA_WIDTH  should be 10. The signals A and B should be 10 bits wide. The signal X should be 11 bits wide.

The value for  DATA_WIDTH  can be used in cocotb tests. Add a new test to test_adder.py.

@cocotb.test()
def adder_big_test(dut):
"""Test for adding 2 numbers to maximize DATA_WIDTH"""
yield Timer(2)
data_width = dut.DATA_WIDTH.value
max_val = 2**data_width - 1
A = max_val
B = max_val
dut.A = A
dut.B = B
yield Timer(2)
if int(dut.X) != adder_model(A, B):
raise TestFailure(
"Adder result is incorrect: %s + %s = %s" %
(int(dut.A), int(dut.B), int(dut.X)))
else:  # these last two lines are not strictly necessary
dut._log.info("Ok!")

The value of  DATA_WIDTH  is read by  dut.DATA_WIDTH.value . With  DATA_WIDTH  set to 10,  max_val  should take on the value of 0x3FF. When QuestaSim runs  test_adder.adder_big_test , signals A and B should be set to 0x3FF. The signal X should compute a value of 0x7FE.

Updating VHDL generics and using generic in tests is painless once you know cocotb’s method for setting and using those values.

Additional information on cocotb can be found on the project’s GitHub page found at https://github.com/potentialventures/cocotb. There, you can read more documentation, raise a bug, request feature enhancements, join the mailing list, email the developers, or follow the project on Twitter.

By Juan Morales

Juan Morales
by Juan Morales
Embedded Engineer
Juan Morales is an embedded engineer at DornerWorks.