目录
前言
把 HDLBits 上的题目简单刷了一遍,自己验证过答案的源码已经汇总至 Github ,这篇博客把主要知识点再梳理一遍。
给这个Verilog的在线刷题网站给出好评,简介易用、层层铺垫,循序渐进,对于Verilog基础语法和数字逻辑的学习有很大帮助。
1. Getting Started
该网站旨在数字逻辑的教学,使用硬件描述语言Verilog HDL进行编码,提供编译(逻辑综合)和仿真环境。
本节作为开始章节,是两道非常简单的题目,使用assign进行置一和置零。
介绍了两种Verilog不同标准的端口声明形式,两者等价。
module top_module ( zero ); output zero; // Verilog-1995 endmodule
module top_module ( output zero ); // Verilog-2001 endmodule
2. Verilog Language
2.1 Basic
本节有8个小题,十分容易。
涉及知识点:
- wires 是有方向的(directional);
- assign
- 右侧向左侧赋值;(assign left_side = right_side; )
- 连续赋值 (continuous),即使右侧未改变;
- assign 出现的顺序无关;
- 区分按位与(&)和逻辑与(&&);
- 常见门电路及其运算符。
2.2 Vectors
本节有9个小题,十分容易。
涉及知识点:
- 位宽声明,type [upper:lower] vector_name;
- 切片操作,part-selected,参考Vecrot1和Vector2;
- 拼接运算符 “{ }“,{a,b,c} 将相关信号a、b、c组合起来便于操作;
- 大端小端声明时确定,
assign out[7:0] = in[0:7];的反向是无效的; - 复制运算符,{num{vector}}; 将vector重复num次;
2.3 Modules: Hierarchy
本节有9个小题,介绍模块及层次结构,十分容易。
涉及知识点:
- 模块的概念和声明;
- 模块的调用(例化):按端口顺序调用、按端口名调用;
- 简单的加法器:
- 脉动进位加法器( ripple carry adder );
- 进位选择加法器( carry-select adder );
- 加减器( Adder–subtractor ).
2.4 Procedures
本节有8个小题,介绍常见过程控制语句,程序块内可以使用if-else,case相关语句。
涉及知识点:
- always 程序块
- Combinational: always @(*) 和 assign 等效。
- assign 左侧必须是 net 类型(如wire);
- always 内,左侧必须是 variable 类型(如reg);
- wire、reg 和硬件综合无关,只是Verilog语法要求。
- Clocked: always @(posedge clk)
- Combinational: always @(*) 和 assign 等效。
- 三种赋值
- 连续赋值(continuous,assign x = y;),非程序块内;
- 阻塞赋值(blocking,x = y;),Combinational always内;
- 非阻塞赋值(non-blocking,x <= y;),Clocked always内。
- if-else
- 通常产生 2-1 多路复用器(2-to-1 multiplexe);
- 三元运算符,assign out = (condition) ? x : y;
- 锁存器(Latches),错误综合的代码产生(combinational logic + flip-flops),导致”需要保持输出不改变“,意味着”需要记住当前状态“,所以产生了latches。
- case
- 相当于一系列 if-elseif-else
- case,casex,casez 相关使用
- 避免产生latches,对于所有可能的情况都必须对输出赋值
- 在case前对所有可能的情况赋值
- 使用default
2.5 More Verilog Features
本节有7个小题,介绍了更多Verilog特性。
涉及知识点:
- 三元运算符,(condition ? if_true : if_false)
- 缩减运算符,是一个单元运算符,相当于按位与、按位或、按位异或等:
- & a[3:0] // AND: a[3]&a[2]&a[1]&a[0]. Equivalent to (a[3:0] == 4’hf)
- | b[3:0] // OR: b[3]|b[2]|b[1]|b[0]. Equivalent to (b[3:0] != 4’h0)
- ^ c[2:0] // XOR: c[2]^c[1]^c[0]
- 循环控制,for-loop;
- 生成块,generate for-loop。
3. Circuits
3.1 Combinational Logic
3.1.1 Basic Gates
本节有17个小题,主要介绍了基本门电路。
涉及知识点:
- 基本门电路:与、或、异或、与非、或非、异或非等;
- 根据真值表编码;
- 根据基本门电路和模块示意图编码;
- thinking “The motor is on when ___”, rather than “If (vibrate mode) then ___”.
- 使用拼接和切片简化代码。
3.1.2 Multiplexers
本节有5个小题,主要介绍多路复用器的实现。
涉及知识点:
- 2-1多路复用,使用if-else或三元运算符实现;
- 9-1多路复用,使用case实现;
- 256-1多路复用,使用下表索引实现,[7:0] sel, in[sel]是可行的;
- 256-1 4位多路复用,切片的索引不能同时为变量,使用下列特性实现
reg [31:0] dword; reg [7:0] byte0; reg [7:0] byte1; reg [7:0] byte2; reg [7:0] byte3; assign byte0 = dword[0 +: 8]; // Same as dword[7:0] assign byte1 = dword[8 +: 8]; // Same as dword[15:8] assign byte2 = dword[16 +: 8]; // Same as dword[23:16] assign byte3 = dword[24 +: 8]; // Same as dword[31:24] dword[8*sel +: 8] // variable part-select with fixed width
3.1.3 Arithmetic Circuits
本节有7个小题,主要介绍算术逻辑电路,包括半加器、全加器。
涉及知识点:
- 有符号数;
- 补码,原码取反加1;
- 溢出,加数与被加数符号位相同,但与和数符号位不同;
- 4位BCD码,每4位二进制表示一个十进制数。
3.1.4 Karnaugh Map to Circuit
本节有8个小题,主要介绍卡诺图。
涉及知识点:
- 卡诺图的化简
- 与-或表达式、或-与表达式
3.2 Sequential Logic
3.2.1 Latches and Flip-Flops
本节有18个小题,介绍锁存器和触发器。
涉及知识点:
- 锁存器和触发器:
- 锁存器(Latches),电平敏感,时序逻辑,非阻塞复制
- 触发器(Flip-Flops),边沿敏感,时序逻辑,非阻塞复制
- 无法同时在敏感列表中设置时钟的上升沿和下降沿;
- 用两个always分别检测,然后使用2-1复用器;
3.2.2 Counters
本节有8个小题,介绍计数器。本小节开始,出现中等规模电路的题目,进行思路介绍。
涉及知识点:
- 4位二进制计数器,0~15,自动归零,无需判定;
- 4位十进制计数器,0~9,需判定归零;同理,1~12计数;
- 1000计数器,可以使用3个带有使能信号的0-9十进制计数器实现;
例题介绍:Count clock
Create a set of counters suitable for use as a 12-hour clock (with am/pm indicator). Your counters are clocked by a fast-running clk, with a pulse on ena whenever your clock should increment (i.e., once per second).
reset resets the clock to 12:00 AM. pm is 0 for AM and 1 for PM. hh, mm, and ss are two BCD (Binary-Coded Decimal) digits each for hours (01-12), minutes (00-59), and seconds (00-59). Reset has higher priority than enable, and can occur even when not enabled.
The following timing diagram shows the rollover behaviour from 11:59:59 AM to 12:00:00 PM and the synchronous reset and enable behaviour.

solution:
题解:时钟为1~12计数器;分钟和秒钟分别为0~60,分解为0~5和0~9计数器。分别带有使能信号,通过判断边界条件确定使能条件,使用模块例化实现完整功能。
module top_module( input clk, input reset, input ena, output pm, output [7:0] hh, output [7:0] mm, output [7:0] ss); //clock enable signal wire SecL_EN,SecH_EN,MinL_EN,MinH_EN,Hour_EN; assign SecL_EN = ena; assign SecH_EN = ena && (ss[3:0] == 4'h9); assign MinL_EN = ss == 8'h59; assign MinH_EN = (mm[3:0] == 4'h9)&&(ss == 8'h59); assign Hour_EN = (mm == 8'h59)&&(ss == 8'h59); //clock counter10 SecL (clk,reset,SecL_EN,ss[3:0]); counter6 SecH (clk,reset,SecH_EN,ss[7:4]); counter10 MinL (clk,reset,MinL_EN,mm[3:0]); counter6 MinH (clk,reset,MinH_EN,mm[7:4]); counter12 HourHL (clk,reset,Hour_EN,hh[7:4],hh[3:0],pm); endmodule module counter10( input clk, input reset, input en, output [3:0] Q); always@(posedge clk) begin if(reset) Q <= 4'b0000; else if(~en) Q <= Q; else if(Q == 4'b1001) Q <= 4'b0000; else Q <= Q+1'b1; end endmodule module counter6( input clk, input reset, input en, output [3:0] Q); always@(posedge clk) begin if(reset) Q<=4'b0000; else if(~en) Q<=Q; else if(Q == 4'b0101) Q<=4'b0000; else Q<=Q+1'b1; end endmodule module counter12( input clk, input reset, input en, output [3:0] CntH, output [3:0] CntL, output pm); always@(posedge clk) begin if(reset) begin {CntH,CntL}<=8'h12;pm <= 1'b0; end else if(~en) {CntH,CntL}<={CntH,CntL}; else if ( {CntH,CntL}==8'h12 ) begin {CntH,CntL}<=8'h01; end else if(CntL ==9) begin CntH<=CntH+1'b1; CntL<=4'b0000;end else if ({CntH,CntL}==8'h11 ) begin CntH<=CntH; CntL<=CntL+1'b1;pm <= ~pm; end else begin CntH<=CntH; CntL<=CntL+1'b1;end end endmodule
3.2.3 Shift Register
本节有9个小题,介绍移位寄存器。
涉及知识点:
- 算术移位:
- 算术左移:左移,符号位不变,低位补0;
- 算术右移:右移,符号位不变,高位补符号位;
- 逻辑移位:
- 逻辑左移:高位移出,低位补0;
- 逻辑右移:低位移出,高位补0;
- 循环移位:
- 循环左移:高位移出,补入低位;
- 循环右移:低位移出,补入高位;
3.2.4 More Circuits
该小节详见 几道有趣的HDL题目(from HDLBits)
3.2.5 Finite State Machines
该小节有33道题目,主要介绍有限状态机。
这部分虽然题量比较大,掌握三段式状态机的典型写法后,需要注意具体问题的状态转换条件。Moore和Mealy可以互相转换,一般推荐Moore,组合逻辑输出时不用考虑输入,做法是将Mealy有不同输出的单一状态分为两个状态。
涉及知识点:
- 分类:
- Moore,输出只和当前状态有关
- Mealy,输出与当前状态以及输入有关
- 三段式状态机(状态转化、状态更新、状态输出);
- 独热码状态机;
- 根据状态转换图、状态表,设计有限状态机。
部分挑选的习题详解见 Finite State Machines (from HDLBits)
3.3 Building Large Circuits
该小节详见 Building Larger Circuits ( from HDLBits )
4. Verification: Reading Simulations
4.1 Finding bugs in code
本节有5个小题,主要考察修复bug的能力,相对容易。
这些容易出现的bug包括:
- 将位宽不同的信号进行按位操作;
- 模块未按端口顺序调用;
- 模块例化互连错误;
- if-else缺失else;
- case没有匹配值;
- case前的预先赋值和default。
4.2 Build a circuit from a simulation waveform
本节有10个小题,主要考察根据时序图编写代码的能力,相对容易。
5. Verification: Weiting Testbenches
本节有5个小题,主要介绍testbenches。