(draft - WIP)
I’ve been wanting to learn more about some of the EDA tools avialable, in particular the open source Edalize that Olof Kindgren has created.
There was a minor stumble during my first attempt just to install Edalize on WSL. It seems I had a Python library dependency that was ever-so-slightly the wrong version.
First, I also have an old version of Python
installed, so this failed:
$ python -m pip install -e .
DEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 won't be maintained after that date. A future version of pip will drop support for Python 2.7.
File "setup.py" not found. Directory cannot be installed in editable mode: /home/gojimmypi
You are using pip version 19.0.2, however version 20.3.4 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
You can see which versions of Python libraries are isntalled with pip freeze
and pip3 freeze
.
As noted in edalize #258, my Jinja2
was a bit outdated, and was fixed like this: pip3 install -U Jinja2
The Edalize install script is named setup.py
Here’s what I did to install Edalize:
# on WSL, I keep all my stuff in C:\workspace
mkdir -p /mnt/c/workspace
cd /mnt/c/workspace/
git clone https://github.com/olofk/edalize.git
cd edalize
# update dependencies:
pip3 install -U Jinja2
pip3 install -U MarkupSafe
# install Edalize
python3 -m pip install -e .
Next, I created a Edalize_blinky directory with these files:
cd /mnt/c/workspace/
mkdir Edalize_blinky
cd Edalize_blinky
echo "" >> blinky.v
echo "" >> blinky_tb.v
echo "" >> myTest.py
echo "" >> vlog_tb_utils.v
A matter of personal preference, I like to have samples files complete, rather than separate narrated sections. This is from the How to use it:
# file name: myTest.py
#
# First we have to import Edalize objects:
from edalize import *
# The os module is also required for this tutorial:
import os
# Then register the files to use:
work_root = 'build'
files = [
{'name' : os.path.relpath('blinky.v', work_root),
'file_type' : 'verilogSource'},
{'name' : os.path.relpath('blinky_tb.v', work_root),
'file_type' : 'verilogSource'},
{'name' : os.path.relpath('vlog_tb_utils.v', work_root),
'file_type' : 'verilogSource'}
]
# The design has a toplevel Verilog parameter with the name clk_freq_hz that accepts integers.
# We set its default value to 1000. The testbench also has an option to enable waveform dumping by setting a plusarg called vcd:
parameters = {'clk_freq_hz' : {'datatype' : 'int', 'default' : 1000, 'paramtype' : 'vlogparam'},
'vcd' : {'datatype' : 'bool', 'paramtype' : 'plusarg'}}
# Let Edalize know we intend to use Icarus Verilog for our simulation:
tool = 'icarus'
# And put it all into a single data structure together with some info about the toplevel and name for the project:
edam = {
'files' : files,
'name' : 'blinky_project',
'parameters' : parameters,
'toplevel' : 'blinky_tb'
}
# Now we need to get ourselves a backend object from Edalize:
backend = get_edatool(tool)(edam=edam,
work_root=work_root)
# Create the directory and the project files:
os.makedirs(work_root)
backend.configure()
# At this point, we still haven't run the actual EDA tool and the files in the `work_root` directory
# can be used without Edalize if that is preferred. But let's continue the example with Edalize.
# Build the simulation model:
backend.build()
# And finally run it, with our arguments. Some types of parameters (e.g. plusargs) are defined aat runtime,
# and at this point we can change their value by passing the name and new value to run(). Or we could skip
# it altogether, and the default value from the configure stage would be used. Let's run with VCD logging enabled:
args = {'vcd' : True}
backend.run(args)
The blinky.v:
module blinky
#(parameter clk_freq_hz = 0)
(input clk,
output reg q = 1'b0);
reg [$clog2(clk_freq_hz)-1:0] count = 0;
always @(posedge clk) begin
count <= count + 1;
if (count == clk_freq_hz-1) begin
q <= !q;
count <= 0;
end
end
endmodule
The blinky_tb.v file:
`timescale 1ns/1ns
module blinky_tb;
parameter clk_freq_hz = 50_000;
parameter pulses = 5;
localparam clk_half_period = 1000_000_000/clk_freq_hz/2;
reg clk = 1'b1;
always #clk_half_period clk <= !clk;
wire led;
vlog_tb_utils vtu();
blinky
#(.clk_freq_hz (clk_freq_hz))
dut
(.clk (clk),
.q (led));
integer i;
time last_edge = 0;
initial begin
@(posedge clk);
@(led);
last_edge = $time;
for (i=0; i<pulses;i=i+1) begin
@(led);
if (($time-last_edge) != 1_000_000_000) begin
$display("Error! Length of pulse was %0d ns", $time-last_edge);
$finish;
end else
$display("Pulse %0d/%0d OK!", i+1, pulses);
last_edge = $time;
end
$display("Testbench finished OK");
$finish;
end
endmodule
The vlog_tb_utils.v file:
/*
* Utility module for verilog testbenches
*
* Copyright (C) 2016 Olof Kindgren <olof.kindgren@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
module vlog_tb_utils;
parameter MAX_STRING_LEN = 128;
localparam CHAR_WIDTH = 8;
//Force simulation stop after timeout cycles
reg [63:0] timeout;
initial
if($value$plusargs("timeout=%d", timeout)) begin
#timeout $display("Timeout: Forcing end of simulation");
$finish;
end
//FIXME: Add more options for VCD logging
reg [MAX_STRING_LEN*CHAR_WIDTH-1:0] testcase;
initial begin
if($test$plusargs("vcd")) begin
if($value$plusargs("testcase=%s", testcase))
$dumpfile({testcase,".vcd"});
else
$dumpfile("testlog.vcd");
$dumpvars;
end
end
//Heartbeat timer for simulations
reg [63:0] heartbeat;
initial begin
if($value$plusargs("heartbeat=%d", heartbeat))
forever #heartbeat $display("Heartbeat : Time=%0t", $time);
end
endmodule // vlog_tb_utils
See also: