欢迎来到从零开始的DFT工程师第一期。

本期主要进行verilog和systemverilog的相关软件安装和基本语法复习。

verilog

关于运行verilog的软件选择很多,这里选择使用vivado和iverilog+gtkwave.

vivado的安装我之前写过,具体是在archlinux(当时的linux内核版本未记录)上进行vivado2024.2版本的安装,详情可见此处,但是由于此后相关库版本更新,需要自行创立软连接来补全相应的库(下载旧版本的库首先需要进行版本管理,这本身就是比较复杂的事,况且很多更新都是更新了实现,接口没有变化)。

我们用一下例子做一个简单的介绍:

wrong

这里我们发现vivado提示说找不到libtinfo.so.5, 我们已经有的是libtinfo.so.6,去下载一个新的不仅占地方,有些时候还会导致引用模糊相互冲突,这里可以用一个取巧的办法,也就是给libtinfo.so.6 创建一个名为libtinfo.so.5的副本,并指向libtinfo.so.6,如下操作:

1
2
3

sudo ln -s /usr/lib/libtinfo.so.6 /usr/lib/libtinfo.so.5

这样我们就简单的完成了vivado启动必须环境的准备。

solved

iverilog+gtkwave 的下载十分简单,只需用pacman下载即可:

1
sudo pacman -S iverilog gtkwave

systemverilog

关于systemverilog相关软件的下载就有些麻烦了。相关的软件有:

  • QuestaSim,支持systemverilog+UVM,coverage,SVA,transcation-level仿真。

  • Synopsys VCS,优势在于性能和大规模的SoC仿真支持,也支持UVM.

  • cadence Xcelium(Incisive),功能和以上类似,似乎通信和ASIC公司用的多。

但是尴尬的是这三个都是闭源软件,下载比较困难,不过也都是有办法下载的,之后我会慢慢更新三个软件的下载方式。

此处我有一个cadence软件的虚拟机,包含 cadence virtuoso + simvision + incisive,详情如下:

cadence

虽然incisive是一个较老的版本,virtuoso版本也只有6.1.8-64b,不过简单的需求也已经可以满足了。

对于开源工具来说,verilator是一个选择,但是当前他对于UVM的支持还不太好,不怎么建议使用;slang和surelog+UHDM是一个新兴的工具,但是目前似乎更多的是实验性质,工业界用的很少,不过还是展示一下下载方式:

1
2
3
4
5
6
7
8
9
10
11
12
13

# archlinux, 6.16.7-arch1-1, linux core

sudo pacman -S git base-devel cmake python

sudo pacman -S yosys verilator

yay -S slang

yay -S surelog

yay -S uhdm

这些工具的使用我们之后再谈。

verilog syntax

此处我们复习基本的verilog常用的设计语法,testbench写法,以及moore和mealy状态机的简单设计方法。

module define

1
2
3
4
5
6
7
8
9
10
11

module <module name>(
input <port type> <port name>,
output wire led_control.
inout reg signal
);


<function decription>

endmodule

data type

  • wire: for signal wire, mostly used for signal that connect modules, must be give value continuously, can not store value.

  • reg: register type, but not have to be real register, it can hold value until its value is changed.

assignment

  • assign, used for combination logic.
1
2
3

assign c = a & b;

  • process, used for timing logic.
1
2
3
4
5

always @(posedge clk) begin
d <= a;
end

the difference between = and <=: = for blocked assignment, next must be excute when the previous statement completely done; <= for unblocked assignment, all unblocked statement will be executed at a same time.

timing logic

  • always: it can be triggered by clockedge.
1
2
3
4
5
6

always @(posedge clk) begin

end


and can be triggered by changes in signal.

1
2
3
4
5

always @* begin

end

@* means monitor all the signals that appeared in the always block.

verilog testbench syntax

basic structure

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

module testbench;
// define test signal
reg clk, rst;
wire out;



// instantiate the measured modules.
module-name uut(.clk(clk), .rst(rst), .out(out));


/generate clock signal
always begin
#5 clk = ~clk;
end


initial begin
clk = 0;
rst = 0;
#10 rst = 1;
#20 rst = 0;
#1000 $stop;

end

endmodule

system task

  • $monitor: print signal(when changed).
1
2
3

$monitor("at time %t, rst = %b, out = %b", $time, rst, out);

  • $display: output(instantly) debugging info.
1
2
3

$display("signal out = %b", out);

$strobe: low execute priority, so it can print info after timing assignment(after current simulation step).

1
2
3

$strobe("message, reg1 = %b", reg1);

design for state machine.

  1. define state.

  2. state trans.

  3. according state(and input, mealy) and output.

systemverilog syntax

systemverilog 是用于硬件描述和验证的语言,扩展了传统的verilog,增加了更多用于验证,测试平台搭建,高级数据类型,精确的并发控制等新特性,结合硬件描述和高级语言的特点,被广泛的用于硬件设计以及其验证测试自动化。由于并非课程必修(此处参考XJTU微电子科学与工程,集成电路与计算机科学与技术实验班的培养放案),此处会较为详细地进行介绍。

data type(commonly used)

  • logic: in systemverilog, it is used to replace the reg and wire, its value can be 0, 1, x, z.
1
2
3
4

logic a, b;
logic [7:0] c;

  • bit: one bit.

  • byte: 8 bits.

1
2
3
4
5

bit d;

byte e;

  • int: 32 bits signed integer.(like integer in verilog).
1
2
3
4
5

int i;

integer j;

  • real: float, user for valid and test.
1
2
3

real f;

  • struct: combine signals.

  • union: signals share common memory, all the sigals’ address is same, so the memory size is decided by the biggest member.

1
2
3
4
5
6
7
8
9
10

struct{
logic [7:0] a;
logic [15:0] b;


}my_struct;



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

// 定义一个联合体
union {
bit [7:0] byte_data; // 一个字节的数据
bit [15:0] word_data; // 一个字的数据
bit [31:0] dword_data; // 一个双字的数据
} data_packet;

initial begin
// 使用 byte_data
data_packet.byte_data = 8'hA5; // 给字节字段赋值
$display("byte_data: %h", data_packet.byte_data);

// 使用 word_data
data_packet.word_data = 16'h1234; // 给字字段赋值
$display("word_data: %h", data_packet.word_data);

// 使用 dword_data
data_packet.dword_data = 32'hDEADBEEF; // 给双字字段赋值
$display("dword_data: %h", data_packet.dword_data);
end

endmodule

module define

just like verilog, use module and endmodule define a module, use interface to pass signals.

1
2
3
4
5
6
7
8
9
10
11

module my_module(input logic clk, input logic rst, output logic [3:0] out);

always_ff @(posedge clk or posedge rst) begin

if(rst) out <= 4'b0;
else out <= out + 1;
end

endmodule

process control

systemverilog have always_comb , always_ff, and always latch to decribe combine logic, timing logic, and a latch.

always can be used for combine logic in verilog (always @*)

  • always_comb: for combine logic, do no depend on clock edge.
1
2
3
4
5
6

always_com begin
out = a & b;

end

  • always_ff: for timing logic.
1
2
3
4
5
6

always_ff @(posedge clk) begin
out <= a + b;

end

  • always_latch: a latch, but recommand do not use.
1
2
3
4
5

always_latch begin
if(en) q = d;
end

constraints and interface

  • constraints, we can limit the value’s range of data-type.
1
2
3
4
5
6
7
8

class my_class; //OOP

rand bit [7:0] a;
constraint c { a != 8b'0000_0000;}

endclass

  • interfaces, package the signal sets, for interconnect among modules.
1
2
3
4
5
6
7
8
9
10
11

interface my_interface(input logic clk, input logic rst);
logic [7:0] data;
endinterface


module top(my_interface intf);
// directly use intf;

endmodule

task and function

  • task, perform certain behavior, can have multiple input and output parameters.
1
2
3
4
5
6
7

task my_task(input logic a, input logic b, output logic c);

c = a & b;

endtask

  • function, execute a computation, return result instantly.
1
2
3
4
5

function logic my_function(input logic a, b);
return a & b;
endfunction

assert and cover

  • assert: verify signals meet a specific condition or not, if not, an error will be thrown.
1
2
3

assert (a == b) else $fatal("assertion failed.");

  • cover: track whether certain conditions occur.
1
2
3

cover (a == 1);

class and object

class define:

1
2
3
4
5
6
7
8
9
10
11

class my_class;

int a;
function new();
a = 0;
endfunction


endclass

class instantiate:

1
2
3

my_class obj = new();

cycle control

1
2
3
4
5
6
7

foreach (arr[i]) begin

// content of cycle

end

parallel execution

1
2
3
4
5
6
7
8
9

fork
// task 1
task1();

task2();

join

总之,systemverilog在硬件的设计和验证中提供了一些增强功能,新的数据类型,精确的时序控制,更高级的断言,覆盖,约束机制,以及接口和面向对象编程的支持,都让systemverilog不仅适用于硬件设计,更有很强的验证和测试平台的构建能力。

这里推荐两个SV学习网站:

chipverify 的systemverilog指南

asic-world

demo of iverilog + gtkwave

现在我们进行一个iverilog和gtkwave组合技的使用回顾。

我们写一个counter.v 文件,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15


module counter4 (
input clk,
input rst_n,
input en,
output reg [3:0] q
);
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
q <= 4'b0000;
else if (en)
q <= q + 1'b1;
end
endmodule

我们编写tb_counter.v文件如下作为测试文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

`timescale 1ns/1ps

module tb_counter4;
reg clk;
reg rst_n;
reg en;
wire [3:0] q;


counter4 uut (
.clk(clk),
.rst_n(rst_n),
.en(en),
.q(q)
);

initial clk = 0;
always #5 clk = ~clk;

initial begin

$dumpfile("counter.vcd");
$dumpvars(0, tb_counter4);


rst_n = 0; en = 0;
#12;
rst_n = 1;
en = 1;


#100;
en = 0;
#40;
en = 1;
#50;

$finish;
end
endmodule

那么我们现在有了设计文件和测试文件,我们就可以进行编译和运行了。

1
2
3
4
5
6
7
8
9
10
11

#compile
iverilog -o counter_tb counter.v tb_counter.v

#generate the VCD waveform
vvp counter_tb


#check waveform
gtkwave counter.vcd

结果展示如下:

result

插播一条重要设置: virtualbox shared folder

由于我们的cadence运行在一个虚拟机里面,为了使得文件交流方便一点,创建一个shared folder就能很大程度上提高我们的工作效率。

这里我使用的工具是virtualbox,选择他的主要原因是他可以在很多linux版本平稳(相对于隔壁vmware接口常变来说)使用。不过virtualbox创建shared folder比vmware要麻烦一点,因为他的shared folder是需要依托guest additions来完成的。

创建shared folder

我们首先在virtualbox的设置里面创建一个shared folder。

在virtualbox里面,global folder 的意思是所有的虚拟机都可以访问,machine folder是只有指定的虚拟机才能访问,显然选择machine才是更合理的。之后我们选择path为宿主机的实际路径,比如说我选择的是~/cadence_shared/这个文件夹,access选择full,并且选上auto mount.

Guest additions

此时我们打开虚拟机发现并没有出现共享文件夹,自己创建一个也无法实现共享文件的功能,这是因为我们需要配置好guest additions才能正常使用这一功能。

我们需要关闭虚拟机,在virtualbox里面选中虚拟机,在settings的storage下面,找到controller:IDE或者是controller:SATA,点右边的小光标add optical drive, 选择系统自带的VBoxGuestAddtions.iso, 选择挂载;

之后我们就进入虚拟机,挂载这个iso:

1
2
3
4
5
6
7

mkdir mntx
sudo mount /dev/cdrom mntx/cdrom
# or : sudo mount /dev/sr0 mntx/cdrom

cd mntx/cdrom
sudo ./VBoxLinuxAddtions.run

如果没有编译环境,就先安装:

1
sudo yum install -y gcc kernel-devel kernel-headers make bzip2 dkms

把当前用户加入vboxsf组:

1
2
3

sudo usermod -aG vobxsf user.name

安装完成之后重启虚拟机,我们就可以发现一个sf_cadence_shared,这个就是共享文件夹了。

从零开始的DFT工程师! homepage

project homepage is here.