《Verilog数字系统设计教程》读书笔记——第一部分初级篇
第一讲 Verilog的基础知识
-
- 前仿(RTL级):没有真实延时,只能验证逻辑功能
- 后仿(Gate级):包含真实延时,验证延时带来的问题
- 不带SDF的netlist仿真,SDF由Prime Time自动生成
- 带SDF的netlist仿真,有门级延时和线延时;SDF有后端APR后提供
-
-
实现(implementation):布局布线的过程。综合后生成的门级网表(Netlist)只是表示了门与门之间虚拟的连接关系,并没有规定每个门的位置以及连线的长度等。布局布线就是一个将门级网表中的门的位置以及连线信息确定下来的过程。
-
IP核(Intellectual Property Core)
-
软核(Soft Core IP):“经验证的、可综合的,且总门数在5000门以上的 Verilog HDL模型 ,称之为软核”。 软核是RTL级代码,只经过功能仿真,在使用前还需要进行综合和布局布线等工作。软核的优点在于灵活性高、可移植性强,允许用户自主配置;缺点在于对模块的预测性较低,在后续的设计过程中会存在一定设计风险。
-
固核(Firm Core IP):“经验证是正确的,且总门数在5000门以上的 电路结构编码文件 ,称之为固核”。 通常以RTL代码和对应具体工艺网表的混合形式提供。将RTL描述结合具体标准单元库进行综合优化设计,形成门级网表,再通过布局布线工具即可使用。固核是IP核的主流形式之一。
-
硬核(Hard Core IP):“经验证是正确的,且总门数在5000门以上的 电路结构版图掩膜 ,称之为硬核”。 经过前端和后端验证、布局和工艺固定的设计,不能被设计人员进行修改,最可靠,但是不能修改。
第二讲 Verilog语法的基本概念
2.0、Verilog HDL5种抽象级别
- 系统级(system-level):用语言提供的高级结构能够实现待设计模块的外部性能的模型。
- 算法级(algorithm-level):用语言提供的高级结构能够实现算法运行的模型。
- RTL级(register transfer level):描述数据在寄存器之间的流动和如何处理、控制这些数据流动的模型。
- 门级(gate-level):描述逻辑门以及逻辑门之间连接的模型。与逻辑电路有确定的连接关系,以上4种数字系统设计工程师必须掌握。
- 开关级(switch-level):描述器件中三极管和储存节点以及它们之间连接的模型。这与具体的物理电路有对应关系,工艺库元件和宏部件设计人员必须掌握,将在高级教程中介绍。
前三种都属于行为描述,只有RTL级才有与逻辑电路有明确的对应关系。系统级和算法级别差别不大,一般可以用高级语言来描述,如C/C++、Python、MATLAB等。
Verilog HDL行为描述语言作为一种结构化和过程性的语言,其语法结构非常适合于算法级和RTL级的模型设计。
第三讲 模块的结构、数据类型、变量和基本运算符号
3.1、模块的结构
3.2、数据类型(Verilog-2005)
| 序号 | 类型 | 数据类型 | 说明 |
| 1 |
Net Type 线网类型 |
wire |
1、模块中的input信号只能用wire 2、实例中的output信号只能用wire 3、线网类型中只有wire可综合,其余的都不可综合 |
| 2 | wand | wire and,线与 | |
| 3 | wor | wire or,线或 | |
| 4 | tri |
tri-state三态线网 与wire类似,表示电路间的物理连线 与wire不同,tri描述多个驱动源同时驱动一根线的线网类型,主要用于多驱动源建模 |
|
| 5 | triand | tri and,线与 | |
| 6 | trior | tri or,线或 | |
| 7 | tri0 | 表示当无驱动时,连线状态为0,也就是自带下拉电阻; | |
| 8 | tri1 | 表示当无驱动时,连线状态为1,也就是自带上拉电阻; | |
| 9 | trireg | ||
| 10 | supply0 | GND,被用来对电路中的电源建模。 | |
| 11 | supply1 | VCC ,被用来对电路中的电源建模。 | |
| 12 | uwire |
Verilog-2005新增, Uwire是一个未决的或unidriver的线,被用来对只有一个驱动器的net建模。Uwire类型被用来加强这个限制。 将uwire网络的任何位连接到一个以上的驱动程序都将是一个错误。将uwire网络连接到双向通开关的双向终端应该是错误的。 |
|
| 13 |
Register 寄存器类型
Variable |
reg |
1、reg型只表示被定义的信号将用在always块中,并非一定是寄存器或锁存器输出,也可以是组合逻辑输出。 2、always块内被赋值的信号必须定义成reg型。 |
| 14 | time | 不可综合 | |
| 15 | integer | 可以综合 | |
| 16 | real | 不可综合 | |
| 17 | realtime | 不可综合 | |
| 18 |
Charge strength (只针对trireg) |
large | |
| 19 | medium | ||
| 20 | small | ||
| 21 | parameter | ||
| 22 | scalared | ||
| 23 | vectored |
- 只有连续赋值assign和实例引用可以独立于过程块(Procedural Block),过程块包括always和initial。
- always中reg并非一定是寄存器或锁存器输出,也可以是组合逻辑输出,此时综合出来的就是wire,而不是寄存器。
- 凡是在always或initial语句中赋值的变量,一定是寄存器变量;凡是在assign语句中赋值的变量,一定是线网变量。
第四讲 运算符、赋值语句和结构说明语句
运算符优先级
| 优先级别 | ||
| 逻辑运算,位运算 | ! ~ |
最高优先级
最低优先级 |
| 算数运算 | * / % | |
| 算数运算 | + - | |
| 移位运算 | << >> | |
| 关系运算 | < <= > >= | |
| 等式运算 | == != === !=== | |
| 位运算 | & | |
| 位运算 | ^ ^~ | |
| 位运算 | | | |
| 逻辑运算 | && | |
| 逻辑运算 | || | |
| 三目运算 | ?; | |
第八讲 语法概念总复习练习
(1)
(4)指出下面几个信号的最高位和最低位
| MSB | LSB | |
| reg [1:0] SEL | SEL[1] | SEL[0] |
| input [0:2] IP | IP[0] | IP[2] |
| wire [16:23] A | A[16] | A[23] |
(5)P,Q,R都是4位的输入矢量(Vector),下面哪一种表达形式是正确的
| input P[3:0], Q, R | 语法没有错误,但是都是标量Scalar |
| input P, Q, R[3:0] |
语法没有错误,但是都是标量Scalar |
| input P[3:0], Q[3:0], R[3:0] | 语法没有错误,但是都是标量Scalar |
| input [3:0] P [3:0] Q, [3:0] R | 语法错误,input [位宽-1:0] 端口名1,端口名2... |
| input [3:0] P Q, R | 正确答案 |
(6)请将下面选项中的正确答案填入空的方括号中
1) (0:2) 2) (P:0) 3) (Op1:Op2) 4) (7:7) 5) (2:0) 6 (7:0)
reg [7:0] A; reg [2:0] Sum, Op1, Op2; reg P, OneBit; initial begin Sum=Op1+Op2; P=1; A[ ?]=Sum; ..... end
参考答案:5) (2:0),
(7:0)为什么不对?A[7:0] = Sum只是A[7:3]高5位会被赋值成0,语法上没有问题。
(7)请根据以下两条语句,从选项中找出正确答案。
7.1) reg [7:0] A;
A=2'hFF;
| 8'b0000_0011 | 8'h03 | 8'b1111_1111 | 8'b11111111 |
参考答案:8'b0000_0011或8'h03
7.2)reg [7:0] B;
B=8'bZ0;
| 8'0000_00Z0 | 8'bZZZZ_0000 | 8'b0000_ZZZ0 | 8'bZZZZ_ZZZ0 |
参考答案:8'bZZZZ_ZZZ0,在最左边的0、X或Z具有扩展性,详情见第28题
(8)请指出下面几条语句中变量的类型。
1) assign A=B;
2) always #1
Count=C+1;
参考答案:
A(wire):连续赋值语句assign中被赋值的变量只能是wire
B(wire/reg)
Count(reg):always中被赋值的变量只能是reg
C(wire/reg)
(9)指出下面模块中Cin,Cout,C3,C5的类型。
module FADD(A,B,Cin,Sum,Cout); input A, B, Cin; output Sum, Cout; .... endmodule module Test; ... FADD M(C1,C2,C3,C4,C5); // 实例化 ... endmodule
参考答案:
Cin(wire):模块中input信号只能是wire
Cout(wire/reg):模块中output信号可以是wire,也可以是reg
C3(wire/reg):实例中input信号可以是wire,也可以是reg
C5(wire):实例中output只能是wire
(10)在下一个程序段中,当ADDRESS的值等于5'b0X000时,问casex执行完后A和B的值是多少。
A=0; B=0; casex(ADDRESS) 5'b00???: A=1; // 这条command被执行 5'b01???: B=1; // 上一条command执行后就跳出case了,所以这条command不会执行 5'b10?00,5'b11?00: begin A=1; B=1; end endcase
参考答案:A = 1, B = 0
(11)在下题中,事件A分别在10,20,30发生,而B一直保持X状态,问在50时Count的值是多少。
reg [7:0] Count; initial Count=0; always begin @(A) Count=Count+1; @(B) Count=Count+1; end
参考答案:Count=1;这是因为当A第一次发生时,Count的值由0变为1,然后事件控制 @(B) 阻挡了进程。
(12)在下题中initial块执行完后I,J,A,B的值会是多少。
reg [2:0] A; reg [3:0] B; integer I, J; initial begin I=0; A=0; I=I-1; // -1 J=I; // -1 A=A-1; // -1, 3'b111 B=A; // 4'b0111 J=J+1; // 0 B=B+1; // 4'b1000
end
参考答案:
I=-1 (整数可为负数),J=0,A=7 (A为reg型为非负数,又因为A为3位即为111),B=8 (在B=A时,B=0111,然后B=B+1,所以B=4’b1000)
(13)在下题中,当V的值发生变化且为-1时,执行完always块后 Count的值应是多少?
reg[7:0]V; reg[2:0]Count; always @(V) begin Count=0; while(~V[Count]) Count=Count+1; end
参考答案:Count=0,V = -1 = 8'b11111111,V[0] = 1,while语句不会被执行
(14)在下题中循环执行完后,V的值是多少?
reg [3:0] A; reg V ,W; integer K; .... A=4'b1010; for(K=2;K>=0;K=K-1) begin V=V^A[k]; W=A[K]^A[K+1]; end
参考答案:V的值是它进人循环体前值的取反。因为V的值分别与0,1,0 进行了异或,与1的异或改变了V的值。
(15)在下题中,给出了几种硬件实现,问以下的模块被综合后可能是哪一种?
always @(posedge Clock) if(A) C=B;
1.不能综合。
2.一个上升沿触发器和一个多路器。
3.一个输入是A,B,Clock的三输入与门。
4.一个透明锁存器。
5.一个带clock有始能引脚的上升沿触发器。
参考答案:2和5,为什么?
(16)在下题中,always状态将描述一个带异步Nreset和Nset输入端的上升沿触发器,则空括号内应填入什么,可从以下五种答案中选择。
always @( ) if(!Nreset) Q<=0; else if(!Nset) Q<=1; else Q<=D;
1.negedge Nset or posedge Clock
2.posedge Clock
3.negedge Nreset or posedge Clock
4.negedge Nreset or negedge Nset or posedge Clock
5.negedge Nreset or negedge Nset
参考答案:4
(17)下面给出了几种硬件实现,问以下模块被综合后可能是哪一种?
- 带异步复位端的触发器
- 不能综合或与预先设想不一致
- 组合逻辑
- 带逻辑的透明锁存器
- 带同步复位端的触发器
// 1,参考答案是5,带同步复位端的触发器
always @(posedge Clock)
begin
A <= B;
if(C)
A <= 1'b0;
end
// 2,参考答案是2,与预设不一致 always @(A or B) case(A) 1'b0: F = B; 1'b1: G = B; endcase // 3,参考答案是1,带异步复位端(A)的触发器 always @(posedge A or posedge B) if(A) C <= 1'b0; else C <= D; // 4,参考答案是2,本意想异步复位,应该if(!rst) always @(posedge clk or negedge rst) if(rst) A <= 1'b0; else A <= B;
(18)在下题中,模块被综合后将产生几个触发器?
always @(posedge Clk) begin: Blk reg B, C; C = B; D <= C; B = A; end
1. 2个寄存器 B和 D
2. 2个寄存器 B和 C
3. 3个寄存器 B, C 和 D
4. 1个寄存器 D
5. 2个寄存器 C 和D
参考答案:1,1和2有什么区别?为什么答案不是1?
(19)在下题中,各条语句的顺序是错误的。请根据电路图调整好它们的次序。
Output=FF3 reg FF1,FF2,FF3; FF2=FF1; always @ (posedge Clock) end FF3=FF2; begin


(20)根据左表中SEL与OP的对应关系,在右边模块的空括号中填入相应的值。
|
SEL:OP 000:1 001:3 010:1 011:3 100:0 101:3 110:0 111:3 |
casex(SEL) 3'b( ): OP=3; 3'b( ): OP=1; 3'b( ): OP=0; endcase
|
参考答案:
casex(SEL) 3'bXX1: OP=3; 3'b0X0: OP=1; 3'b1X0: OP=0; endcase
(21)在以下表达式中选出正确的
| 4'b1010 & 4'b1101 = 1'b1 | 错误,按位与,应该是4'b1010 & 4'b1101 = 4'b1000 |
| ~4'b1100 = 1'b1 | 错误,按位取反,应该是4'b1100 = 4'b0011 |
| !4'b1011 || !4'b0000 = 1'b1 | 正确,(!4'b1011) || (!4'b0000) = 0 || 1 = 1'b1 |
| &4'b1011 = 1'b1 | 错误,按位与,1'b0 |
| !1'b0 || !1'b1 = 1'b1 | 正确,(!1'b0) || (!1'b1) = 1 || 0 = 1'b1 |
| 4'b1011 && 4'b0100 = 4'b1111 | 错误,逻辑与,4'b1011 && 4'b0100 = 1'b1 |
| 4'b0101 << 1 = 5'b01011 | 错误,4'b0101 << 1 = 5'b01010 |
| !4'b0010 is 1'b0 | 正确 |
| 4'b0001 || 4'b0000 = 1'b1 | 正确 |
(22)在下一个模块旁的括号中填入display的正确值。
integer I; reg[3:0]A; reg[7:0]B; initial begin I=-1;A=I;B=A; $display("%b",B);( ) A=A/2; $display("%b",A);( ) B=A+14 $diaplay("%d",B);( ) A=A+14; $display("%d",A);( ) A=-2;I=A/2; $display("%d",I);( ) end
参考答案:
I=-1;A=I;B=A;
$display("%b",B);(00001111)
A=A/2;
$display("%b",A);(0111)
B=A+14
$diaplay("%d",B);(21)
A=A+14;
$display("%d",A);(5)(A为4位,所以21被截为5)
A=-2;I=A/2;
$display("%d",I);(7)(A=-2,则是1110)
(23)请问{1, 0}与下面哪一个值相等?
| 2'b01 | |
| 2'b10 | |
| 2'b00 | |
| 64'H0000000000000002 | |
| 64'H0000000100000000 | 正确,位拼接运算符必须指明位数,不然默认32位 |
(24)根据下题给出的程序,确定应将哪一个选项填入尖括号内。
1. defs.Reset 2."defs.v".Reset
3. M.Reset 4.Reset

1 参考答案:1
(模块间调用时,若引用其他模块定义的参数,要加上其他模块名,做为这个参数的前缀。)
module M 'include "defs.v" .... if(OP==<defs.Reset>) Bus=0; endmodule
2. 参考答案:4
parameter Reset=8'b10100101; (File defs.v) // 什么意思?? module M 'include "defs.v" .... if(OP==<Reset>) Bus=0; endmodule
(25)如果调用Pipe时,想把Depth的值变为8,问程序中的空括号内应填入何值?
Module Pipe(IP,OP) parameter Option=1; parameter Depth=1; ... endmodule Pipe( ) P1(IP1,OP1);
参考答案:#(1,8),其中1对应参数Option,8对应参数Depth.
(26)若想使P1中的Depth的值变为16,则应向空括号中填入哪个选项。
module Pipe (IP ,OP); parameter Option =1; parameter Depth = 1; ………… endmodule module Pipe P1(IP1 ,OP1); ( ); endmodule
1.defparam P1.Depth=16;
2.parameter P1.Depth=16;
3.parameter Pipe.Depth=16;
4.defparam Pipe.Depth=16;
参考答案:1,用后缀改变引用模块的参数要用defparam及用本模块名作为引用参数的前缀,如p1.Depth。
备注:defparam不可综合
(27)如果我们想在Test的monitor语句中观察Count的值,则在空括号中应填入什么?
Module Test Top T(); initial $monitor( ) endmodule module Top; Block B1(); Block B2(); endmodule module Block; Counter C(); endmodule module Counter; reg [3:0] Count; .... endmodule
参考答案:T.B1.C.Counter Test.T.B1.C.Count
(28)下题中用initial块给reg[7:0]V符值,请指明每种情况下V的8位都是什值。
这道题说明在数的表示时,已标明字宽的数若用XZ表示某些位,只有在最左边的X或Z具有扩展性。




浙公网安备 33010602011771号