Verilog HDL题库练习--题目来源HDLBits

本文精选HDLBits上的VerilogHDL题目,涵盖组合逻辑电路与时序逻辑电路设计,深入解析基本门电路、多路选择器、运算电路及触发器等内容,通过实例加深对硬件电路的理解。

写在开头:

HDLBits 上有很多Verilog HDL语言的题目,题目很有价值,有些题目也很有意思,让人脑洞打开。更重要的是,通过每道题目的铺垫以及层层递进的难度,让我对硬件电路有了更深刻的理解。因此我会在这篇文章里提取出一些有意思、有难度、也能引起思考的题目,分享给大家。btw,这是我第100篇博客,坚持到现在不容易,如果你能看到这里,请给我点个赞吧。个人能力有限,文章难免有多少错误,欢迎指正。


目录

一、Verilog HDL 语法

二、Combinational Logic Circuits组合逻辑电路

2.1 Basic Gates 基本门电路

2.2 Mutiplexers 多路选择器

1、2-to-1 multiplexer

2、2-to-1 bus multiplexer

3、9-to-1 multiplexer

4、256-to-1 multiplexer

5、256-to-1 4-bit multiplexer

2.3 Arithmetic Circuit 运算电路

2.3.1 Half adder

2.3.2 full adder 全加器 

2.3.3 3-bit binary adder 3位二进制加法器 

 2.3.4 Adder 加法器

 2.3.5 Signed addition overflow 有符号数的加法溢出检测

2.3.6 100-bit binary adder

2.3.7 4-digit BCD adder

2.4 Karnaugh Map to Circuit 电路的卡诺图描述

2.4.1 3-varible 3变量

2.4.2 4-variable 4变量

2.4.3 4-variable

2.4.4 4-variable

2.4.5 Minimum SOP and POS

2.4.6 Karnaugh Map

2.4.7  Karnaugh Map

2.4.8 K-map implemented with a multiplexer

三、Sequential Logic 时序逻辑电路

3.1 Latches and Flip-Flops 寄存器和触发器

3.1.1 D flip-flop D触发器

3.1.2 D flip-flops D触发器组合

3.1.3 DFF with reset 带复位的D触发器

3.1.4 DFF with reset value 带复位的D触发器

3.1.5 DFF with asynchromous reset 异步复位的DFF

3.1.6 DFF with byte enable 带使能位的DFF

3.1.7 D Latch D锁存器

3.1.8 DFF

3.1.9 DFF

3.1.10 DFF + gate

3.1.11 Mux and DFF

3.1.12 Mux and DFF

3.1.13 DFFs and gates

3.1.14 Create circuit from truth table

3.1.15 Detect an edge

3.1.16 Detect both edges

3.1.17 Edge capture register

3.1.18 Dual-edge triggered flip-flop

3.2 Counters 计数器

3.3 Shift Registers 移位寄存器

3.4 More Circuits

3.5 Finite State Machines 有限状态机



一、Verilog HDL 语法

二、Combinational Logic Circuits组合逻辑电路

2.1 Basic Gates 基本门电路

2.2 Mutiplexers 多路选择器

1、2-to-1 multiplexer

Create a one-bit wide, 2-to-1 multiplexer. When sel=0, choose a. When sel=1, choose b.

Expected solution length: Around 1 line.

 题目分析:用一行代码实现二选一选择器,那么就不能用if语句,这里选择条件运算符,也是唯一的三目运算符:<条件1>?<条件2>:<条件3>

它执行如下运算:在运算中,首先对第一个表达式进行检验,如果为真,则返回表达式2的值;如果为假,则返回表达式3的值。

再利用连续幅值语句assign,故所缺程序为:assign out = (sel) ? b : a;

module top_module( 
    input a, b, sel,
    output out ); 

    assign out = (sel) ? b : a;
endmodule

 当然,也可以对向量进行选择,这里不再赘述,直接提供程序:

2、2-to-1 bus multiplexer

module top_module( 
    input [99:0] a, b,
    input sel,
    output [99:0] out );

    assign out = (sel) ? b : a;
endmodule

3、9-to-1 multiplexer

Create a 16-bit wide, 9-to-1 multiplexer. sel=0 chooses a, sel=1 chooses b, etc. For the unused cases (sel=9 to 15), set all output bits to '1'.

Expected solution length: Around 15 lines.

题目分析:要求我们根据sel的值来对某一个输入直接输出。sel的情况较多,但是可以一一列举,因此选择case语句列举出所有情况,且新增程序没有超过15行。

直接给出完整程序:

module top_module( 
    input [15:0] a, b, c, d, e, f, g, h, i,
    input [3:0] sel,
    output [15:0] out );
    
    always@(*)
        begin
            case(sel)
                4'b0000: out = a;
                4'b0001: out = b;
                4'b0010: out = c;
                4'b0011: out = d;
                4'b0100: out = e;
                4'b0101: out = f;
                4'b0110: out = g;
                4'b0111: out = h;
                4'b1000: out = i;
                default:out = 16'hffff;
            endcase
        end
                  

endmodule

这里我们注意一下,Verilog数据常量的写法:

数字表达式:<位宽><进制><数字>
’b:二进制 //eg.4'b1110 表示4位二进制数1110
‘h:十六进制 //eg 8'hef、4’ha等
'd:十进制 //eg 2'd3、4‘d15(不能写16,4位宽最大15)等

计算位宽时,都要转成二进制来计算,因为时序元件只能存储二值电平。

4、256-to-1 multiplexer

前面几题都比较简单,一些小知识点写出来全当做复习了,后面两题会有点难度。

Create a 1-bit wide, 256-to-1 multiplexer. The 256 inputs are all packed into a single 256-bit input vector. sel=0 should select in[0], sel=1 selects bits in[1], sel=2 selects bits in[2], etc.

Expected solution length: Around 1 line.

Module Declaration

module top_module( 
    input [255:0] in,
    input [7:0] sel,
    output out );

题目分析:要求我们根据sel的值选择in的某一位输出,因为sel有8bit,因此有2^8=256种可能,正好填满了in中的所有位。

没有思路前可以先试着写前几个:

sel=0,out=in[0];

sel = 1,out = in[1];

所以很明显,sel值就是要输出的in的下标,因此我们确实可以用1行代码来搞定它,直接给出完整程序:

module top_module( 
    input [255:0] in,
    input [7:0] sel,
    output out );

    assign out = in[sel];
endmodule

5、256-to-1 4-bit multiplexer

Create a 4-bit wide, 256-to-1 multiplexer. The 256 4-bit inputs are all packed into a single 1024-bit input vector. sel=0 should select bits in[3:0], sel=1 selects bits in[7:4], sel=2 selects bits in[11:8], etc.

Expected solution length: Around 1–5 lines.

Module Declaration

module top_module( 
    input [1023:0] in,
    input [7:0] sel,
    output [3:0] out );

 题目:上一题只能算小试身手,这题才是开胃大菜。要求我们根据sel的值,选择in的某连续4位进行输出,这里题目给了提示,我们也来康康:

  • With this many options, a case statement isn't so useful.
  • Vector indices can be variable, as long as the synthesizer can figure out that the width of the bits being selected is constant. It's not always good at this. An error saying "... is not a constant" means it couldn't prove that the select width is constant. In particular, in[ sel*4+3 : sel*4 ] does not work.
  • Bit slicing ("Indexed vector part select", since Verilog-2001) has an even more compact syntax.

 提示分析:1、由于情况太多,case语句写起来太冗长了;

2、“向量索引是可以变化的”(意思是可以用变量来表示索引),但是后面又说“只要合成器能算出被选择位的宽度是恒定的”,否则编译器会报错。这句话翻译成人话就是:可以用变量来表示向量索引,但是编译器会因为无法识别出被选择位的宽度而报错,比如说in[ sel*4+3 : sel*4 ] 这个语句就不能用,因为其宽度没有直接指定。

3、可以使用“位切片”的方法来实现,只不过这是更高级的语法。

说了这么多,其实我们还不知道正确答案是什么,我们直接看网上的程序:

example1:

assign out = {in[sel * 4 + 3], in[sel * 4 + 2], in[sel * 4 + 1], in[sel * 4]};

这种写法很好地避免了被选择位宽度无法识别的问题,又使用了变量来表示索引,是比较容易理解的一种答案。作为学习,我们当然也得看看提示中说的更高级的解法啊。

example2:

assign out = in[sel*4 +: 4];

这句话的意思是:从sel*4开始,选择比特序号大于sel*4的4位bit,相当于[sel*4+3:sel*4]。这种写法应该是这题出题人的意图了,这种语法只在Verilog 2001适用:

verilog-1995中,可以选择向量的任一位输出,也可以选择向量的连续几位输出,不过此时连续几位的始末数值的index需要是常量。而在Verilog-2001中,可以用变量作为index,进行part select。

[base_expr +: width_expr] //positive offset

[base_expr -: width_expr] //negative offset

其中base_expr可以是变量,而width_expr必须是常量。+:表示由base_expr向上增长width_expr位,-:表示由base_expr向上递减width_expr位。例如:

reg [63:0] word;

reg [3:0] byte_num; //a value from 0 to 7

wire [7:0] byteN = word[byte_num*8 +: 8];

如果byte_num的值为4,则word[39:32]赋值给byteN。

 example3:

有了上面的解释,第三种答案也就出来了:

assign out = in[sel*4+3-:4];

从sel*4+3开始,选择比特序号小于sel*4+3的4位bit,相当于[sel*4+3:sel*4]

总结一下答案如下:

module top_module( 
    input [1023:0] in,
    input [7:0] sel,
    output [3:0] out );
    
    assign out = {in[sel*4+3],in[sel*4+2],in[sel*4+1],in[sel*4]};//这种方式最直接、容易理解
    //assign out = = in[sel*4 +: 4];
    //assign out = in[sel*4+3-:4];

endmodule

2.3 Arithmetic Circuit 运算电路

2.3.1 Half adder

Create a half adder. A half adder adds two bits (with no carry-in) and produces a sum and carry-out.

Expected solution length: Around 2 lines.

题目分析:创建一个半加器(无低位进位) ,2行代码。

比较简单,直接po出程序

module top_module( 
    input a, b,
    output cout, sum );
    
    assign {cout,sum} = a + b; 

endmodule

2.3.2 full adder 全加器 

Create a full adder. A full adder adds three bits (including carry-in) and produces a sum and carry-out.

Expected solution length: Around 2 lines.

 题目分析:创建一个全加器(含低位进位)

与上题一样,直接给出程序:

module top_module( 
    input a, b, cin,
    output cout, sum );
    
    assign {cout,sum} = a + b +cin;

endmodule

2.3.3 3-bit binary adder 3位二进制加法器 

Now that you know how to build a full adder, make 3 instances of it to create a 3-bit binary ripple-carry adder. The adder adds two 3-bit numbers and a carry-in to produce a 3-bit sum and carry out. To encourage you to actually instantiate full adders, also output the carry-out from each full adder in the ripple-carry adder. cout[2] is the final carry-out from the last full adder, and is the carry-out you usually see.

Module Declaration

module top_module( 
    input [2:0] a, b,
    input cin,
    output [2:0] cout,
    output [2:0] sum );
评论 8
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cheeky_man

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值