当前位置:网站首页>【HDLBits 刷题】Verilog Language(4)Procedures 和 More Verilog Features 部分
【HDLBits 刷题】Verilog Language(4)Procedures 和 More Verilog Features 部分
2022-07-29 21:15:00 【Linest-5】
目录
写在前面
本篇博客对 Verilog Language 剩余两个部分的题目写完,首先对题干先读懂是关键,然后思考如何实现并验证,这里采用先对题目解读,也就是要让我们干什么,然后直接给出答案。
Procedures
Alwaysblock1
分别用 assign 语句和 always @(*) 块语句实现与门操作。
module top_module(
input a,
input b,
output wire out_assign,
output reg out_alwaysblock
);
assign out_assign = a & b;
always @(*) begin
out_alwaysblock = a & b;
end
endmodule
Alwaysblock2
连续赋值(assign x = y;)。不能在 always 块中使用。
过程阻塞赋值:(x = y;)。只能在过程中使用。
过程非阻塞赋值:(x <= y;)。只能在过程中使用。
在组合 always 块中,使用阻塞赋值。
在时序 always 块中,使用非阻塞赋值。
module top_module(
input clk,
input a,
input b,
output wire out_assign,
output reg out_always_comb,
output reg out_always_ff
);
assign out_assign = a ^ b;
always @(*) begin
out_always_comb = a ^ b;
end
always @(posedge clk) begin
out_always_ff <= a ^ b;
end
endmoduleAlways if
if 语句通常创建一个 2 对 1 多路复用器,如果条件为 ture,则选择一个输入,如果条件为 false,则选择另一个输入。这等效于使用带有条件运算符的连续赋值:
assign out = (condition) ? x : y;
构建一个在 a 和 b 之间进行选择的 2 对 1 多路复用器。如果sel_b1和sel_b2都为真,请选择 b。否则,请选择 a。执行相同的操作两次,分别使用赋值语句和过程 if 语句。
module top_module(
input a,
input b,
input sel_b1,
input sel_b2,
output wire out_assign,
output reg out_always
);
assign out_assign = (sel_b1 & sel_b2) ? b : a;
always @(*) begin
if (sel_b1 & sel_b2) begin
out_always = b;
end
else begin
out_always = a;
end
end
endmoduleAlways if2
学习如何避免产生 latch, 比如在 always 块中所列举的情况没有完全,会出现你没有列举的情况时,那输出会是什么呢?Verilog的答案是:保持输出不变。这种“保持输出不变”的行为意味着需要记住当前状态,从而产生latch。组合逻辑不能保存任何状态。组合电路必须在所有条件下为所有输出分配一个值。这通常意味着始终需要为输出分配 else 子句或默认值。
module top_module (
input cpu_overheated,
output reg shut_off_computer,
input arrived,
input gas_tank_empty,
output reg keep_driving ); //
always @(*) begin
if (cpu_overheated) begin
shut_off_computer = 1;
end
else begin
shut_off_computer = 0;
end
end
always @(*) begin
if (~arrived) begin
keep_driving = ~gas_tank_empty;
end
else begin
keep_driving = 0;
end
end
endmoduleAlways case
case语句的练习。case 语句以 case 开头,每个“case 项”都以冒号结尾。
每个事例项只能执行一条语句。这意味着,如果需要多个语句,则必须使用begin结束。允许重复(和部分重叠)案例项目。使用第一个匹配的。
在本练习中,创建一个 6 对 1 多路复用器。当 sel 介于 0 和 5 之间时,选择相应的数据输入。否则,输出 0。数据输入和输出均为4位宽。
module top_module (
input [2:0] sel,
input [3:0] data0,
input [3:0] data1,
input [3:0] data2,
input [3:0] data3,
input [3:0] data4,
input [3:0] data5,
output reg [3:0] out
);
always @(*) begin
case(sel)
0: out = data0;
1: out = data1;
2: out = data2;
3: out = data3;
4: out = data4;
5: out = data5;
default: out = 0;
endcase
end
endmoduleAlways case2
优先级编码器是一种组合电路,当给定输入位矢量时,输出矢量中第一个1位的位置。例如,给定输入 8'b100 1 0000 的 8 位优先级编码器将输出 3'd4,因为 bit[4] 是第一个高位。构建 4 位优先级编码器。对于此问题,如果输入位均为零,则输出为零。请注意,4 位数字有 16 种可能的组合。
module top_module (
input [3:0] in,
output reg [1:0] pos
);
always @(*) begin
case(in)
4'b0000: pos = 0;
4'b0001: pos = 0;
4'b0010: pos = 1;
4'b0100: pos = 2;
4'b1000: pos = 3;
4'b0011: pos = 0;
4'b0110: pos = 1;
4'b1100: pos = 2;
4'b0101: pos = 0;
4'b1010: pos = 1;
4'b1001: pos = 0;
4'b0111: pos = 0;
4'b1110: pos = 1;
4'b1011: pos = 0;
4'b1101: pos = 0;
4'b1111: pos = 0;
endcase
end
endmoduleAlways casez
case 语句就像是按顺序检查每个情况,这是一个很大的组合逻辑函数。请注意,某些输入(例如,4'b1111)将如何匹配多个事例项。选择第一个匹配项(因此 4'b1111 匹配第一个项目,out = 0,但后面的任何一个都不匹配)。还有一个类似的案例,它将x和z视为不在乎。我看不出在casez上使用它有多大意义。数字 ? 是 z 的同义词。所以 2'bz0 与 2'b?0 相同。
module top_module (
input [7:0] in,
output reg [2:0] pos
);
always @(*) begin
casez(in)
8'bzzzzzzz1: pos = 0; //z表示不在乎这个是什么值。只需要满足后面位的情况
8'bzzzzzz10: pos = 1;
8'bzzzzz100: pos = 2;
8'bzzzz1000: pos = 3;
8'bzzz10000: pos = 4;
8'bzz100000: pos = 5;
8'bz1000000: pos = 6;
8'b10000000: pos = 7;
endcase
end
endmoduleAlways nolatches
在使用case语句时避免产生latch的方法。
为避免产生锁存器,必须在所有可能条件下为所有输出分配一个值。仅仅有一个默认的案例是不够的。必须为所有四种情况下的所有四个输出分配一个值,并在所有默认情况下分配一个值。这可能涉及大量不必要的键入。
解决此问题的一种方法是在case语句之前为输出分配一个“默认值”:
always @(*) begin
up = 1'b0; down = 1'b0; left = 1'b0; right = 1'b0;
case (scancode)
... // Set to 1 as necessary.
endcase
end
这种代码样式可确保在所有可能的情况下为输出分配一个值,除非case语句覆盖赋值。
提醒:逻辑合成器生成一个组合电路,其行为与代码描述的行为等效。硬件不会按顺序“执行”代码行。
module top_module (
input [15:0] scancode,
output reg left,
output reg down,
output reg right,
output reg up
);
always @(*) begin
up = 1'b0;
down = 1'b0;
left = 1'b0;
right = 1'b0;
case(scancode)
16'he075: up = 1'b1;
16'he072: down = 1'b1;
16'he06b: left = 1'b1;
16'he074: right = 1'b1;
default: begin
up = 1'b0;
down = 1'b0;
left = 1'b0;
right = 1'b0;
end
endcase
end
endmoduleMore Verilog Features
Conditional
给定四个无符号数字,找到最小值。无符号数字可以与标准比较运算符(a < b)进行比较。使用条件运算符制作双向最小电路,然后组合其中的几个以创建 4 路最小电路。可能需要一些导线向量作为中间结果。
module top_module (
input [7:0] a, b, c, d,
output [7:0] min
);
wire [7:0] smaller0;
wire [7:0] smaller1;
wire [7:0] smaller2;
assign smaller0 = (a > b)? b : a;
assign smaller1 = (c > d)? d : c;
assign smaller2 = (smaller0 > smaller1)? smaller1 : smaller0;
assign min = smaller2;
endmodule注:也可以设计为流水线的形式,流水线的设计方法可以使系统的运行速率提高。
Reduction
奇偶校验通常用作通过不完美通道传输数据时检测错误的简单方法。创建一个电路,该电路将计算 8 位字节的奇偶校验位(这将向该字节添加第 9 位)。将使用“偶数”奇偶校验,奇偶校验位只是所有8个数据位的XOR。
一个简单的连续位做异或运算。
module top_module (
input [7:0] in,
output parity
);
assign parity = ^in;
endmoduleGates100
在[99:0]中构建具有100个输入的组合电路。
有 3 个输出:
- out_and:输出100输入与门 &。
- out_or:100 输入 OR 门 | 的输出。
- out_xor:100 输入异或门 ^ 的输出。
module top_module(
input [99:0] in,
output out_and,
output out_or,
output out_xor
);
assign out_and = & in;
assign out_or = | in;
assign out_xor = ^ in;
endmoduleVector100r
给定一个 100 位输入向量 [99:0],反转其位排序。
module top_module(
input [99:0] in,
output [99:0] out
);
integer i;
always @(*) begin
for (i=0;i<100;i=i+1) begin
out[i] = in[99-i];
end
end
endmodulePopcount255
对输入位宽为255的数计算其各个位为 1 的个数并输出
module top_module(
input [254:0] in,
output [7:0] out
);
reg [7:0] cnt;
integer i;
always @(*) begin
cnt = 'd0;
for (i=0;i<255;i=i+1) begin
cnt = (in[i])? (cnt+1'b1):cnt;
end
end
assign out = cnt;
endmoduleAdder100i
通过实例化 100 个全加器来创建一个 100 位二进制行波进位加法器。加法器将两个 100 位数字和一个随身数字相加,以产生 100 位总和并执行。实际实例化全加器,还要从行波进位加法器中的每个全加器输出执行。cout[99]是最后一个全加器的最终执行。
注意对第一个全加器计算时的特殊情况。
module top_module(
input [99:0] a, b,
input cin,
output [99:0] cout,
output [99:0] sum
);
genvar i;
generate
for(i=0;i<100;i=i+1) begin:adder
if(i==0)
assign{cout[0],sum[0]}=a[0]+b[0]+cin;
else
assign{cout[i],sum[i]}=a[i]+b[i]+cout[i-1];
end
endgenerate
endmodule
Bcdadd100
以一个四位的全加器模块,计算两个输入数据的相加,其位宽为400。
在这里吐槽一下 HDLBits 自带的编译器有点神经质,有些没必要的细节过度把控,而有些带有技巧性的语法又不支持...
module top_module(
input [399:0] a,b,
input cin,
output cout,
output [399:0] sum
);
wire [99:0] cin_cnt;
genvar i;
generate
for (i=0;i<100;i=i+1) begin:test
if (i == 0) begin
bcd_fadd bcd_fadd_inst(a[3:0],b[3:0],cin,cin_cnt[0],sum[3:0]);
end
else begin
bcd_fadd bcd_fadd_inst(a[4*(i+1)-1:4*i],b[4*(i+1)-1:4*i],cin_cnt[i-1],cin_cnt[i],sum[4*(i+1)-1:4*i]);
end
end
assign cout = cin_cnt[99];
endgenerate
endmodule边栏推荐
- 针对自动识别大麦网滑块验证码,提出解决方案,并进行分析、总结
- 微信小程序如何开通支付功能?
- First thoughts on the first attempt to avoid killing without a file (Part 1)
- 华为畅享50 Pro评测:HarmonyOS加持 更流畅更安全
- Cobaltstrike and BurpSuite desktop shortcut configuration
- 一文理解分布式开发中的服务治理
- GET_ENTITYSET Method Implementation Guide for SAP ABAP OData Service Data Provider Class
- Chrome浏览器打印flash log
- [ACTF2020 新生赛]Exec 1
- 剑指 Offer II 097. 子序列的数目
猜你喜欢

VSCode配置终端为系统命令行

TCP协议详解

Huawei Enjoy 50 Pro evaluation: HarmonyOS blessing is smoother and safer

1. Promise usage in JS, 2. The concept and usage of closures, 3. The difference between the four methods and areas of object creation, 4. How to declare a class

南信大提出TIPCB,一个简单但有效的用于基于文本的人员搜索的基于部分的卷积baseline

网络通信编程基础,BIO,NIO

AI全流程开发难题破解之钥

爽朗的一天

Fully automated machine learning modeling!The effect hangs the primary alchemist!

惠普服务器硬盘指示灯不亮或显示蓝色
随机推荐
太卷了,企业级的智慧物业系统,也完全开源....
酷客导航助你商场轻松购物,业务办理不迷茫
数组和List互转
打破原则!MongoDB 引入 SQL?
Break the rules!MongoDB introduces SQL?
leetcode122. Best Time to Buy and Sell Stock II
相亲信息
bright day
C# 窗体与子线程数据交互
02-SDRAM:自动刷新
品牌广告投放平台的中台化应用与实践
MySQL Data Query - Union Query
容器网络硬核技术内幕 (小结-下)
错误解决:Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255]
VR直播营销需求增加,数据模块为我们铺路
Cobaltstrike和BurpSuite桌面快捷配置
【593. 有效的正方形】
组合模式(Composite Pattern)
.NET 6.0中使用Identity框架实现JWT身份认证与授权
Minimal jvm source code analysis