一、赛题描述
在RTL的设计中,有一部分是组合逻辑(combinational logic),一部分是时序逻辑(sequential logic)。一般而言,时序逻辑的每个输出只能有一个驱动(driver),该驱动可以是组合/时序逻辑的输出。如下图:
在实际RTL开发中,有一类比较常见的错误,就是一个时序电路的输出(如Q)会有多个驱动,如下图:
通常,这种错误往往在仿真结果出现问题的时候才能发现,就像刚才说的,验证工具读入verilog design,生成可执行程序,执行可执行程序,如果发现结果错误,这个时候用户需要调试。对于用户来说,调试起来周期非常长,尤其是RTL设计非常大的时候。
理想的情况是验证工具进行静态检查,让这类问题在编译阶段报出,从而节省用户的调试时间。这个需求最早是由INTEL公司提出来的。
本赛题就是要求参赛选手开发这样一种静态检查的功能。
二、驱动冲突的规则
1、驱动冲突的检查对象是变量(variable),而非 wire(net type) , 因为 IEEE 标准已经确保了 wire 是不能用被时序电路驱动的。变量的类型包括 reg, integer 等。
2、驱动冲突的检查模块是 always block,在其他 scope 下,多个驱动是允许的。如两个initial block 里驱动同一个变量是合法的。但是同一个变量同时被一个 initial block 和 always block 驱动就是有冲突的。
3、在同一个 always block 中的多次写操作不视为驱动冲突。
always @(posedge clk) begin
if (sel)
Q <= D1;
else
Q <= D2;
end
三、测例描述
RTL 设计以 Verilog 形式,如下图所示:
module dut (input a, b, c, e, output q);
wire a, b, c;
reg r;
reg clk;
reg q;
reg d;
always @(a, b, c)
d = a & (b | c);
always @(e)
q = e;
always @(posedge clk)
q <= d;
endmodule
输出:屏幕上需要打出如下报错信息(至少两个)
The following drivers conflict:
Line 12
Line 15
四、评分标准
评分标准包括功能的覆盖程度、代码质量、 测试,及性能等几部分。
4.1、功能覆盖及质量 ( 80 分)
1、基本功能(20 分)
支持 scalar【标量类型】(如:reg 等), 以各种 driver【驱动类型】。
没有范围规范的net或reg声明应该被认为是1位宽,被称为标量【scalar】。
driver类型是指continue assign和procedure assign;要看的是variable类型的driver,例如reg类型。
2、支持 vector、memory、select ( 30 分)
多位net和reg数据类型必须通过指定一个范围来声明,这个范围称为向量【vector】。(类比C语言的一维数组)
memory是一个寄存器数组,如
reg\[3:0\] memo\[255:0\]
表示 256个4位存储器,该存储器地址范围是0-255。(类比C语言的二维数组)
如:
reg [3:0] aa
always @(bb)
aa[0] = bb;
always @(posedge clk)
aa[1] = cc;
这个例子应该是没有冲突的,因为他们的 select 不同,而下面这个会在 a[1]有冲突:
always @(bb)
aa[1:0] = bb;
always @(posedge clk)
aa[3:1] = cc;
3、支持 for loop 分析 (30 分):
a)、支持单层的 for loop ( 15 分)
reg [0:7] aa;
reg [0:7] bb;
reg [0:7] cc;
always @(posedge clk)
for (i = 0; i < 4; i++)
aa[i] <= cc[i];
always @(posedge clk) begin
for (i = 3; i < 8; i++)
aa[i] <= bb[i];
end
这里, aa[3] 是有冲突的, 其他位没有冲突
b)、支持嵌套的 for loop (15 分)
reg [0:7] aa [0:15];
always @(posedge clk)
for (i = 0; i < 7; i++)
for (j = 0; j < i + 1; j++)
aa[i][j] = cc;
always @(posedge clk)
for (i = 0; i < 7; i++)
for (j = i+1; j < 15; j++)
aa[i][j] = bb;
以上两个是没有冲突的。
4.2、代码及测试 (10 分)
主要评估标准:
- 1)选手代码的整洁程度,可读性,可调试性
- 2)对原开源源代码的改动在满足性能/功能的前提下,要尽可能的小(避免重复开发而导致质量问题)
- 3)是否有测试方案以确保软件的正确性
4.3、性能 (10 分)
根据一组提供的 benchmark(性能测试集), 以 compile time(CT)为衡量依据。性能超越 80%参赛选者得 10 分,性能超越 50%参赛选手者得 5 分。
4.4、附加题 (20 分)
Verilog 有一种概念是 hierarchical reference【层次参考】 , 即从一个 module 可以访问定义在另一个module 的 variable. 例如:
module top;
sub s0();
wire r;
endmodule
module sub;
wire w;
assign top.r = w; //hierarchical reference
endmodule
其对应的概念是:
如果 ‘sub’ module 在 ’top’ 下面有多个 instance , 会造成’r’ 有多个驱动。完整的例子如下:
module top;
reg q;
submod s1();
submod s2();
endmodule
module submod();
reg d, clk;
always @(posedge clk)
top.q <= d;
endmodule
由于这个驱动在源代码中只有一处,为了给用户更多信息,需要把这个驱动所在的 hierarchal path 打出来:
The following drivers conflict:
Line 8, in instance top.s1,
Line 8, in instance top.s2
五、测试集
最后提交的是一个可执行程序。要求:速度快、内存小。【功能、性能】
比赛开始时,将提供 50 个左右单元测试供参赛选手使用。
验收时,将在另外一个测试集 (100-200 个 case)中测试选手的提交的软件,以通过率作为功能覆盖率(4.1)的打分标准。另外,会有一个性能测试集(20 个左右 benchmark),作为性能(4.3)的打分标准。
六、技术要点
6.1、技术要点1
本题用到的例子是一个RTL design。通常,RTL design由组合逻辑和时序逻辑构成。一个数字电路的网表抽象出来后就是一个图,每个变量是一个节点,变量之间的连线就是边。每个节点会有驱动(driver),和负载(load)【驱动和负载时相互的】。
要想实现本赛题的驱动检查,首先需要从表面的Verilog语言建立出一个这样的图,方便查询每个节点的驱动
6.2、技术要点2
RTL design的抽象程度要高于门级(gate level)。这意味着,会有vector, memory这样的word-level 的数据类型,以及 for loop 这样的控制类型语句。
always @(posedge clk) begin
if (reset)
for (i = 3; i < 8; i++)
aa[i] <= bb[i];
end
七、iverilog数据结构
Verilog 文件经过parse,elaboration以后,变成了netlist。Parsing 阶段会把Verilog 文件转换成中间格式pform。 elaborate阶段会把design展开,链接符号,生成一个完全展开的netlist。
其中,top的class名字叫scope【NetScope
】,他有两个children,一个叫s1,一个叫s2。s1也是一个scope【NetScope
】,他里面有自己的一些成员函数。
主要的数据结构都在文件netlist.h中,并且每种数据类型都有非常详细的注释。通过学习这个文件,我们需要了解Verilog的module,always, 赋值语句,continue,assign等分别对应于哪个数据结构,这是我们做题的前提条件。
上述右侧verilog代码第10行和第12行发生冲突。
类NetNet:verilog的wire、reg类型都在这个类里面,其中的type可以来表示其到底是wire还是reg。
类Netproc:定义了一个statement(整个赋值语句),可以是阻塞赋值q=e
、非阻塞赋值q<=d
、if语句、for语句。【是一个子类、继承了阻塞赋值和非阻塞赋值】
类NetExpr:表达式(赋值语句的右值)。比如a & (b | c)、e、d
类NetAssign_:赋值语句的左值。NetAssign_
包含了NetNet
,故上述的d也是一个NetAssign_
类NetScope:通过该类,可以找到每一个变量或者语句。
类NetProcTop:NetProcess代表了一个链表,由多个always或initial块组成,而NetProcTop表示的是该链表的Header(头)。
八、解题思路
本赛题要求参赛者在编译阶段检查驱动冲突,在做完 Elaboration后,整个design的hierarchy(层级结构)已经建立起来, 各节点的连接关系都可以遍历。函数入口在main.cc 里的elaborate(),参赛者可以在elaborate() 结束后检查驱动冲突。
遍历所有的gate,将其输出放到一个map里,如果它的个数大于1,那他就是一个multdriver,这种思路不是很高效!
把整个图都建立起来,遍历每个点,如果这个点有很多的driver,那么就把这个点报出来!
参考
- IEEE1364 Verilog Standard
- 数字IC设计工程师的知识结构
- Iverilog : http://iverilog.icarus.com/home
- https://github.com/steveicarus/iverilog
- https://iverilog.fandom.com/wiki/Installation_Guide#Compiling_on_MS_Windows_.28MinGW.29
- https://iverilog.fandom.com/wiki/Talk:Installation_Guide
- ftp://ftp.icarus.com/pub/eda/verilog/tests/
- https://iverilog.fandom.com/wiki/User_Guide