HDLBits 是一组小型电路设计习题集,使用 Verilog/SystemVerilog 硬件描述语言 (HDL) 练习数字硬件设计~
网址如下:
https://hdlbits.01xz.net/
关于HDLBits的Verilog实现可以查看下面专栏:
https://www.zhihu.com/column/c_1131528588117385216
缩略词索引:
SV:SystemVerilog
关于Verilog中的wire变量介绍,HDLBits有详细的介绍,这里不再赘述。介绍一下SV中关于wire变量介绍:
网络用于将设计元素连接在一起,例如将一个模块的输出端口连接到另一个模块的输入端口。网络在三个重要方面不同于变量:
网络没有像变量一样的临时存储,相反,网络反映了网络驱动器的当前值(电容性trireg网络似乎存储了一个值,但实际上代表了驱动网络的电容器的行为),
网络可以计算多个驱动因素的结果值,其中变量只能有一个来源(如果对一个变量进行了多个程序赋值,则最后一个赋值是结果值,而不是解析所有赋值的结果)。
网络反映驱动器值(0、l、Z或X)和驱动器强度。
驱动器的强度级别以0~7的步长表示。每个级别由一个关键字表示。大多数建模构件的默认强度级别为“强”,即级别6。强度级别对于晶体管级建模很重要,但不用于RTL建模。强度的表示和使用超出了本文关于RTL建模的范围。
通过同时指定类型和数据类型来声明网络。类型可以是表3-3和3-4中列出的任何关键字。数据类型必须是关键字logic,可以显式指定或隐式推断。
每个SystemVerilog网络类型都有特定的语义规则,这些规则会影响多个驱动程序的解析方式。虽然所有网络类型都表示硅行为,但并非所有网络类型都可以用标准ASIC和FPGA技术表示。表3-3列出了ASIC和FPGA综合编译器支持的网络类型。
表3-3:可综合网络类型类型 | 代表 |
---|---|
wire | 使用CMOS行为解析多个驱动器的互连网络 |
tri | wire的同义词在所有方面都相同,可用于强调预期具有三态值的网络 |
Supply0 | 在电源强度级别具有恒定逻辑0的互连网络。可用于表示接地轨(GND、VSS) |
Supply1 | 在电源强度级别具有恒定逻辑1的互连网络。可用于表示供电轨(VCC、VDD) |
SystemVeriIog有几种网络类型,综合编译器并不普遍支持这些类型,如表3-4(第77页)所示。
表3-4:一般不可综合的网络类型类型 | 代表 |
---|---|
uwire | 不允许或不解析多个驱动程序的互连网络 |
pull0 | 一种互连网络,具有将下拉电阻器连接到网络的特性 |
Pull1 | 一种互连网络,具有将上拉电阻器连接到该网络的特性 |
wand | 一种互连网络,通过对驱动值进行AND运算来解析多个驱动程序 |
triand | wand的同义词,在所有方面都相同;可用于强调预期具有三态值的网络 |
wor | 一种互连网络,通过对驱动值进行OR来解析多个驱动程序 |
trior | wor的同义词,在所有方面都相同;可用于强调预期具有三态值的网络 |
trireg | 具有电容性的互连网络;如果所有驱动器均为高阻抗,则电容反映最后解析的驱动值 |
某些RTL综合编译器可能支持一种或多种网络类型。最佳实践编码风格是不使用这些类型,以确保RTL模型与任何综合编译器兼容。如果使用其中一种类型,设计工程师应检查项目中使用的所有工具是否支持该类型。
创建一个具有一个输入和一个输出的模块,其行为类似于wire(网络)。
图片来自 HDLBits这个题目的核心就是上面的图片,模块和端口已经被定义好了,黑色的框图以及箭头代表模块和端口。我们需要做的工作是完成图中绿色的部分,即完成这条连线。
图中已经给出了实现这条线的关键语句:assign。关于assign语句SV中的关键点如下:
给wire赋值。wire可以从两种类型的源接收值:作为output or inout port端口的连接,以及作为连续赋值(assign语句)的左侧。不能在程序赋值的左侧使用wire。
在整个仿真过程中对连续赋值进行求值,赋值右侧的任何更改都会导致对右侧表达式进行求值,并更新左侧表达式。左侧可以是变量或wire。wire的连续赋值可以是显式的,也可以是隐式的。显式连续赋值以关键字assign开始。
隐式连续赋值结合了网络声明和对该网络的赋值。组合中未使用assign关键字。
注意不要混淆内嵌变量初始化和隐式连续赋值。
这两个构造的语法可能看起来很相似,但行为却截然不同。在线变量初始化是一次评估和赋值,在前面的示例中,如果a或b的值在以后的仿真中发生变化,则不会更新变量。隐式连续赋值,顾名思义,是在整个仿真过程中不断求值的表达式。在前面的示例中,每次仿真期间a或b的值发生变化时,n1都会更新。
连接大小不匹配。wire用于将设计块连接在一起,例如将一个模块的输出端口连接到一个或多个其他模块的输入端口。通常,端口和互连网络的向量宽度相同,但SystemVerilog允许向量大小不同。例如16位标量网络可以将32位宽的输出端口连接到8位宽的输入端口。这种尺寸不匹配可能是设计错误,但在SystemVerilog中,只会生成警告。
SystemVerilog语言具有解决端口/连接不匹配的规则:
port的比特数少于连接到的网络或变量-值的最左边的比特被截断,导致值的最重要比特丢失。
一个端口的比特数大于连接到它的网络或变量的比特数-网络或变量的值保持扩展状态,如果端口、网络/变量中有一个无符号,则该值为零扩展。如果端口和网络/变量都有符号,则该值为有符号。
仿真器和综合编译器将生成连接大小不匹配的警告消息。这些警告不容忽视!连接不匹配通常是需要纠正的设计错误。 |
module top_module( input in, output out );
这个没什么说的,一句话就可以了“assign out = in;”。难度不大,对于SV/Verilog来说,重点关注assign实现组合逻辑的一些注意点。
- module top_module( input logic in,
- output logic out
- );
-
- assign out = in ;
-
- endmodule
点击Submit,等待一会就能看到下图结果:
注意图中的Ref是参考波形,Yours是你的代码生成的波形,网站会对比这两个波形,一旦这两者不匹配,仿真结果会变红(后面会展示)。
这一题就结束了。
创建一个具有 3 个输入和 4 个输出的模块,其行为类似于下面演示的这些连线:
- a -> w
- b -> x
- b -> y
- c -> z
图片来自 HDLBits
这个题目的核心就是上面的图片,模块和端口已经被定义好了,黑色的框图以及箭头代表模块和端口。我们需要做的工作是完成图中绿色的部分,即完成这条连线。
- module top_module(
- input a,b,c,
- output w,x,y,z );
主要使用assign语句实现上面的连线,难度较低。
- module top_module(
- input logic a,b,c,
- output logic w,x,y,z
- );
-
- assign w = a;
- assign x = b;
- assign y = b;
- assign z = c;
-
- endmodule
点击Submit,等待一会就能看到下图结果:
注意图中的Ref是参考波形,Yours是你的代码生成的波形,网站会对比这两个波形,一旦这两者不匹配,仿真结果会变红(后面会展示)。
这一题就结束了。
创建一个实现非门(Notgate)的模块。
图片来自 HDLBits从这个题目开始实现几个经典组合电路,非门的的核心就是上面的图片,模块和端口已经被定义好了,黑色的框图以及箭头代表模块和端口。我们需要做的工作是完成图中绿色的部分,实现一个非门。
module top_module( input in, output out );
主要使用assign语句实现非门,也很简单就一个语句“assign out = ~in;”。这里注意一个逻辑取反和逐位取反的区别。
- module top_module( input logic in,
- output logic out
- );
-
- assign out = ~in ;
-
- endmodule
上面使用“assign out = ~in ;”和“assign out = !in ;”无区别,因为只有一位变量。
点击Submit,等待一会就能看到下图结果:
注意图中的Ref是参考波形,Yours是你的代码生成的波形,网站会对比这两个波形,一旦这两者不匹配,仿真结果会变红(后面会展示)。
这一题就结束了。
创建一个与门(Andgate)模块。。
图片来自 HDLBits与门的的核心就是上面的图片,模块和端口已经被定义好了,黑色的框图以及箭头代表模块和端口。我们需要做的工作是完成图中绿色的部分,实现一个与门。
- module top_module(
- input a,
- input b,
- output out );
主要使用assign语句实现与门,也很简单就一个语句“assign out = a & b;”。值得注意的是 & 和 && 的区别。
- module top_module(
- input logic a,
- input logic b,
- output logic out );
-
- assign out = a & b;
-
- endmodule
点击Submit,等待一会就能看到下图结果:
注意图中的Ref是参考波形,Yours是你的代码生成的波形,网站会对比这两个波形,一旦这两者不匹配,仿真结果会变红(后面会展示)。
这一题就结束了。
创建一个实现 NOR 门的模块。或非门(Norgate)是一个输出反相的或门。用 Verilog 编写的 NOR 门需要两个运算符。
图片来自 HDLBits或非门的的核心就是上面的图片,模块和端口已经被定义好了,黑色的框图以及箭头代表模块和端口。我们需要做的工作是完成图中绿色的部分,实现一个或非门。从图中可以看出就是一个或门输出取反,核心就是先实现一个或门,之后再输出端取反即可,可以使用两个assign语句或者一个assign语句实现。
- module top_module(
- input a,
- input b,
- output out );
这一题的关键是看懂题目给的符号,给大家一个常用的门电路示意图:
HDLbits网站上的使用的是国外流行图形符号一栏,从题目给定的符号,对比上一图就是典型的或非门,由或门和非门组合实现。
- module top_module(
- input logic a,
- input logic b,
- output logic out );
-
- assign out = ~(a | b);
-
- endmodule
代码中(a|b)实现一个或门,然后取反即可~(a | b)。
点击Submit,等待一会就能看到下图结果:
注意图中的Ref是参考波形,Yours是你的代码生成的波形,网站会对比这两个波形,一旦这两者不匹配,仿真结果会变红。
一开始代码写错了,写成:
- module top_module(
- input logic a,
- input logic b,
- output logic out );
-
- assign out = ~a | b;
-
- endmodule
仿真结果如下:
造成上面结果的主要原因还是因为Verilog/SV中逻辑操作,运算符等有优先级(和数学里的加减乘除乘除一样),具体优先级如下:
所以上面的代码会优先做~a然后在和b或,加上括号解决。
今天的5道题就结束了,整体难度不大,后面的题目难度会越来越大~
最后我这边做题的代码也是个人理解使用,有错误欢迎大家批评指正,祝大家学习愉快~
代码链接:
https://github.com/suisuisi/SystemVerilog/tree/main/SystemVerilogHDLBits
往期推荐
HDLBits: 在线学习 SystemVerilog(零)-在线“巡礼” HDLBits