【SV书的章节练习题】Chap.3 Combinational Logic Using SystemVerilog Gate Models
前言
Chap.3 Combinational Logic Using SystemVerilog Gate Models
这一章主要考了基本的组合逻辑、testbench、delay三种方式怎么加、阻塞赋值和非阻塞赋值。
《Digital system design with SystemVerilog》-Zwoliński, Mark
《SystemVerilog数字系统设计》-夏宇闻
Problem 3.1
题目
Write a description of a three-input NAND gate with a delay of 5 ps using a continuous assignment.
分析:delay defined from continuous assignment
- 这里要求的5ps的延时,指的是三输入的与非门(nand3)输出output的延时。因为1000ps=1ns,如果扫描的时间精度不够的话,就会忽视掉这样一个延时的变化,为了更加清晰地看到延时的波形变化,我想设置仿真时间单位为1ps级而不是ns级。
`timescale 1ns/10ps
// 仿真时间单位/时间精度
//<timeprecision> must be at least as precise as <timeunit>.
`timescale 1ps/1ps
- 模块例化 Module instance
The hierarchy of modules is created by instantiating one module inside another, you may connect signals to the module by port name or port position.For instance:
module mod_a ( output out, input in1, input in2);
在实例化模块时,有两种常用的方式来进行模块端口的信号连接:
- 按端口顺序,mod_a U_mod_a(out, a, b); //使用按照端口顺序的方式 声明信号连接 分别连接到模块的 第一个端口(in1),第二个端口(in2)以及第三个端口(out)。这里所谓的端口顺序指的是模块端口的定义顺序。这种方式的弊端在于,一旦端口列表发生改变,所有模块实例化中的端口连接都需要改变。
- 按端口名称,mod_a instance2 ( .out©, .in1(a), .in2(b) ); 在这种方式中根据端口名称指定外部信号的连接。这样一来就和端口声明的顺序完全没有关系。一旦模块出现改动,只要修改相应的部分即可。实际上,一般都使用这种方式来进行模块实例化。
- To verify the timing, the simulation model must include timing information. A delay can be associated with a continuous assignment. For instance:
assign #10ps z = x & y;
源代码 & 解答
nand3.sv
`timescale 1ps/1ps
module nand3 (output wire y, input wire a,b,c);
assign #5ps y = ~(a & b & c);//表示,输出y有着5ps的延迟
endmodule
nand3_tb.sv
//`include "nand3.sv"
`timescale 1ps/1ps
module nand3_tb;
wire out_y;
reg in_a,in_b,in_c;
nand3 g1 (.y(out_y),.a(in_a),.b(in_b),.c(in_c));
initial
begin
in_a = '1;
in_b = '1;
in_c = '1;
#5ps in_a = '0;
#5ps in_b ='0;
#5ps in_c ='0;
end
initial begin
$monitor ("%t | a = %d| b = %d| c = %d| y = %d", $time, in_a, in_b,in_c, out_y);
$dumpfile("dump.vcd");
$dumpvars();
end
endmodule
仿真结果波形分析
- NAND3的逻辑:可以看到y = ~(a & b & c),当a、b、c输入均为1时,y应该变为0。由于assign上的延迟导致了输出y延迟了5ps才拉低到0。
Problem 3.2
题目
Write a description of a three-input NAND gate with a parameterizable delay
using a continuous assignment.
分析:parameterizable delay
The statement:
assign #5ps z = x & y;
defines the exact delay for an AND gate. Different technologies, and indeed different instances, will have different delays. We could declare a number of alternative modules for an AND gate, each with a different delay. It would be better to write the statement as:
assign #delay z = x & y;
and to define delay as a parameter to the SystemVerilog model.
module And2 #(parameter delay) (output wire z,
input wire x, y);
assign #delay z = x & y;
endmodule
When the gate is used in a netlist, a value is passed to the model as a parameter:
And2 #(5ps) g2 (p, b, q);
源代码 & 解答
nand3.sv
`timescale 1ps/1ps
module nand3 #(parameter delay) (output wire y, input wire a,b,c);
assign #delay y = ~(a & b & c);
endmodule
nand3_tb.sv
//`include "nand3.sv"
`timescale 1ps/1ps
module nand3_tb;
wire out_y;
reg in_a,in_b,in_c;
nand3 #(5ps) g1 (.y(out_y),.a(in_a),.b(in_b),.c(in_c));
initial
begin
in_a = '0;
in_b = '0;
in_c = '0;
#5ps in_a = '1;
#5ps in_b ='1;
#5ps in_c ='1;
end
initial begin
$monitor ("%t | a = %d| b = %d| c = %d| y = %d", $time, in_a, in_b,in_c, out_y);
$dumpfile("dump.vcd");
$dumpvars();
end
endmodule
仿真结果波形分析
Problem 3.3、3.4
题目
A full adder has the truth table of Table 3.2 for its sum (S) and carry (Co) outputs, in terms of its inputs, A, B and carry in (Ci).
< center>Table 3.2 Truth Table for Exercise 3.3< center>
A | B | Ci | S | Co |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
0 | 0 | 1 | 1 | 0 |
0 | 1 | 0 | 1 | 0 |
0 | 1 | 1 | 0 | 1 |
1 | 0 | 0 | 1 | 0 |
1 | 0 | 1 | 0 | 1 |
1 | 1 | 0 | 0 | 1 |
1 | 1 | 1 | 1 | 1 |
Derive expressions for S and Co using only AND and OR operators. Hence write a SystemVerilog description of a full adder as a netlist of AND and OR gates and inverters. Do not include any gate delays in your models.
3.4 Write a SystemVerilog testbench to test all combinations of inputs to the full adder of Exercise 3.3. Verify the correctness of your full adder and of the testbench using a SystemVerilog simulator.
分析
full adder 全加器
全加器就是考虑进位的加法运算器。根据真值表画卡诺图,然后利用卡诺图写表达式,然后代数化简。这里要求的是用AND和OR门,特指二输入的AND和OR门。
因为我所使用的是纯组合逻辑电路,所以我这里可以只用阻塞赋值(Non-blocking,其对应的电路结构往往与电平触发有关)。
要求使用的是systemverilog自带的AND、NOT、OR函数。如果编程的方法是指定了这几个门,那么综合后就是这三种门,在硬件上也会寻找这三种门。但是,如果编程只写了有运算符的逻辑表达式,那么经过编译后或者综合后,可能编译器生成了所使用的门不止这些种类这些数量。具体看需求和要求了。
源代码 & 解答
写法一:逻辑表达式的形式,这里主要为了演示功能。本道题正确形式,应该看下文的写法二
full_adder.sv
`timescale 1ns / 1ps
module full_adder(output wire s,co , input wire a,b,ci);
assign s = (a*~b+~a*b)*~ci + (~a*~b+a*b)*ci;
assign co = a*b+(a*~b+~a*b)*ci;
endmodule
可以看到并没有指定门的形式为与门、或门、非门的组合。具体可以看下文写法二。
full_adder_tb.sv
//`include "full_adder.sv"
`timescale 1ns / 1ps
module full_adder_tb;
// Inputs
reg in_a;
reg in_b;
reg in_ci;
// Outputs
wire out_s;
wire out_co;
// Instantiate the Unit Under Test (UUT)
full_adder u_full_adder (
.s(out_s),
.co(out_co),
.a(in_a),
.b(in_b),
.ci(in_ci)
);
initial
begin
#10 in_a=1'b0;in_b=1'b0;in_ci=1'b0;
#10 in_a=1'b0;in_b=1'b0;in_ci=1'b1;
#10 in_a=1'b0;in_b=1'b1;in_ci=1'b0;
#10 in_a=1'b0;in_b=1'b1;in_ci=1'b1;
#10 in_a=1'b1;in_b=1'b0;in_ci=1'b0;
#10 in_a=1'b1;in_b=1'b0;in_ci=1'b1;
#10 in_a=1'b1;in_b=1'b1;in_ci=1'b0;
#10 in_a=1'b1;in_b=1'b1;in_ci=1'b1;
#10$stop;
end
initial
begin
$monitor(" time=%0d A=%b B=%b Cin=%b S=%b Co=%b",$time,in_a,in_b,in_ci,out_s,out_co);
end
endmodule
写法二:netlist的形式
full_adder_1.sv
`timescale 1ns / 1ps
module full_adder_1(output wire s,co , input wire a,b,ci);
wire e, f, g,h,i,j,k,l,m,n,o,p;
//d=~ci; e=~a, f=~b,g=a*b,h=a*~b,i=~a*b;j=~a*~b;k=(a*~b+~a*b);l=(a*~b+~a*b)*~ci;
//m= (~a*~b+a*b);n=(~a*~b+a*b)*ci;o=s = (a*~b+~a*b)*~ci + (~a*~b+a*b)*ci;p=(a*~b+~a*b)*ci;
not g0 (d,ci);
not g1 (e,a);
not g2 (f,b);
and g3 (g,a,b);
and g4 (h,a,f);
and g5 (i,e,b);
and g6 (j,e,f);
or g7 (k,h,i);
and g8 (l,k,d);
or g9 (m,j,g);
and g10 (n,m,ci);
or g11 (s,l,n);
and g12 (p,k,ci);
or g13 (co,g,p);
/*
assign s = (a*~b+~a*b)*~ci + (~a*~b+a*b)*ci;
assign co = a*b+(a*~b+~a*b)*ci;
*/
endmodule
full_adder_tb_1.sv
//`include "full_adder.sv"
`timescale 1ns / 1ps
module full_adder_1_tb;
// Inputs
reg in_a;
reg in_b;
reg in_ci;
// Outputs
wire out_s;
wire out_co;
// Instantiate the Unit Under Test (UUT)
full_adder_1 u_full_adder (
.s(out_s),
.co(out_co),
.a(in_a),
.b(in_b),
.ci(in_ci)
);
initial
begin
#10 in_a=1'b0;in_b=1'b0;in_ci=1'b0;
#10 in_a=1'b0;in_b=1'b0;in_ci=1'b1;
#10 in_a=1'b0;in_b=1'b1;in_ci=1'b0;
#10 in_a=1'b0;in_b=1'b1;in_ci=1'b1;
#10 in_a=1'b1;in_b=1'b0;in_ci=1'b0;
#10 in_a=1'b1;in_b=1'b0;in_ci=1'b1;
#10 in_a=1'b1;in_b=1'b1;in_ci=1'b0;
#10 in_a=1'b1;in_b=1'b1;in_ci=1'b1;
#10$stop;
end
initial
begin
$monitor(" time=%0d A=%b B=%b Cin=%b S=%b Co=%b",$time,in_a,in_b,in_ci,out_s,out_co);
end
endmodule
仿真结果波形分析
这里我为了读数方便,以列表的形式打印出了输出值,方便和真值表对比看功能是否完全实现。
- 写法二的门级逻辑综合图(Quartus II)
符合要求:a netlist of AND and OR gates and inverters.
Quartus II综合的时候,直接把反相器NOT门,直接综合到AND和OR的输入输出端口上了。
ps,全加器的最简表达式
Problem 3.5
题目
Modify the gate models of Exercise 3.3 such that each gate has a delay of 1 ns. What is the maximum delay through your full adder? Verify this delay by simulation
分析:gate dalay
The simplest way to include timing information is to model the delay through each gate.1 For example, a delay of 10 ps through a NAND gate would be written as:
nand #10ps g1 (y, a, b);
The hash symbol (#) is used to denote a parameter. We will see further examples of parameters in later chapters. Notice that the delay parameter is placed between the type of gate (nand) and the name of the instance (g1).
本题要求让每一个门都有1ns的延迟。很简单,就在上文的写法二的形式里,给每一个门都加上“#1ns”
源代码
full_adder_1.sv
`timescale 1ns / 1ps
module full_adder_1(output wire s,co , input wire a,b,ci);
wire e, f, g,h,i,j,k,l,m,n,o,p;
//d=~ci; e=~a, f=~b,g=a*b,h=a*~b,i=~a*b;j=~a*~b;k=(a*~b+~a*b);l=(a*~b+~a*b)*~ci;
//m= (~a*~b+a*b);n=(~a*~b+a*b)*ci;o=s = (a*~b+~a*b)*~ci + (~a*~b+a*b)*ci;p=(a*~b+~a*b)*ci;
not #1ns g0 (d,ci);
not #1ns g1 (e,a);
not #1ns g2 (f,b);
and #1ns g3 (g,a,b);
and #1ns g4 (h,a,f);
and #1ns g5 (i,e,b);
and #1ns g6 (j,e,f);
or #1ns g7 (k,h,i);
and #1ns g8 (l,k,d);
or #1ns g9 (m,j,g);
and #1ns g10 (n,m,ci);
or #1ns g11 (s,l,n);
and #1ns g12 (p,k,ci);
or #1ns g13 (co,g,p);
/*
assign s = (a*~b+~a*b)*~ci + (~a*~b+a*b)*ci;
assign co = a*b+(a*~b+~a*b)*ci;
*/
endmodule
full_adder_1_tb.sv
这里我有一个小改动,相比于Problem3.3里。我在testbench激励文件中把信号的输入,改成了非阻塞赋值的方法,因为要计算延时,所以输入应当是同时变化的。
具体区别可看这篇文章:阻塞赋值与非阻塞赋值
//`include "full_adder.sv"
`timescale 1ns / 1ps
module full_adder_1_tb;
// Inputs
reg in_a;
reg in_b;
reg in_ci;
// Outputs
wire out_s;
wire out_co;
// Instantiate the Unit Under Test (UUT)
full_adder_1 u_full_adder (
.s(out_s),
.co(out_co),
.a(in_a),
.b(in_b),
.ci(in_ci)
);
initial
begin
#10 in_a<=1'b0;in_b<=1'b0;in_ci<=1'b0;
#10 in_a<=1'b0;in_b<=1'b0;in_ci<=1'b1;
#10 in_a<=1'b0;in_b<=1'b1;in_ci<=1'b0;
#10 in_a<=1'b0;in_b<=1'b1;in_ci<=1'b1;
#10 in_a<=1'b1;in_b<=1'b0;in_ci<=1'b0;
#10 in_a<=1'b1;in_b<=1'b0;in_ci<=1'b1;
#10 in_a<=1'b1;in_b<=1'b1;in_ci<=1'b0;
#10 in_a<=1'b1;in_b<=1'b1;in_ci<=1'b1;
#10$stop;
end
initial
begin
$monitor(" time=%0d A=%b B=%b Cin=%b S=%b Co=%b",$time,in_a,in_b,in_ci,out_s,out_co);
end
endmodule
解答
- Maximum delay through your full adder:5ns
用ModelSim打开DataFlow,观察数据的流向。
- 最初始的时候,abc都为0,使得g6的输出保持为1。使得g9的输出保持为1。使得g10与门的两个输入之一,一直是1
- 当第一次有数据变化时,a、b、ci=0、0、1。ci=1的时候使得g10输出为1。经过非门g11,直接输出s为1。数据流向的过程中只经过两个门。
- 其他情况也可像这样分析出来。也可以直接在输出窗口打印每一次的数据变化的时候的时间和输出值。
Reference
- 阻塞赋值与非阻塞赋值
- HDLBits 中文导学
- Verilog的运算符及优先级
- 数字电路 逻辑函数的化简之 公式化简法
- digital_logic根据一位全加器的真值表,画卡诺图,推到输出逻辑函数表达式
- Verilog实现1位全加器及输出逻辑解析
- 《Digital system design with SystemVerilog》-Zwoliński, Mark
- 《SystemVerilog数字系统设计》-夏宇闻