HDLBits练习汇总

您所在的位置:网站首页 verilog语言assign语句 HDLBits练习汇总

HDLBits练习汇总

2023-09-02 09:59| 来源: 网络整理| 查看: 265

always块(组合)

由于数字电路是由用导线连接的逻辑门组成的,因此任何电路都可以表示为模块和赋值语句的某种组合。然而,有时这并不是描述电路的最方便的方式。过程(其中总是块是一个示例)提供了一种用于描述电路的替代语法。

对于综合硬件,有两种类型的 always 块是相关的:

组合:always @( * ) 时序逻辑:always @(posedge clk)

组合always块等效于assign语句,因此总有一种方法可以双向表达组合电路。选择使用哪个,主要是哪个语法更方便的问题。程序块内部代码的语法与外部代码不同。程序块具有更丰富的语句集(例如,if-then、case),不能包含连续赋值*,但也引入了许多新的非直观的错误方式。 (*过程连续赋值确实存在,但与连续赋值有些不同,并且不可合成。)

例如,assign 和combinational always 块描述了相同的电路。两者都创建了相同的组合逻辑块。每当任何输入(右侧)更改值时,两者都会重新计算输出。 assign out1 = a & b | c ^ d; always @() out2 = a & b | c ^ d; 在这里插入图片描述 对于组合 always 块,始终使用()的敏感度列表。明确列出信号容易出错(如果您错过了),并且在硬件综合时会被忽略。如果您明确指定敏感度列表并遗漏了一个信号,合成的硬件仍然会像指定了(*)一样运行,但模拟不会也不匹配硬件的行为。(在 SystemVerilog 中,使用always_comb。)

关于 wire 与 reg 的说明:assign 语句的左侧必须是net类型(例如,wire),而过程赋值(在 always 块中)的左侧必须是变量类型(例如,reg)。这些类型(wire 与 reg)与合成的硬件无关,只是 Verilog 用作硬件模拟语言时遗留下来的语法。

练习

使用assign 语句和组合always 块构建AND 门。 模块声明

// synthesis verilog_input_version verilog_2001 module top_module( input a, input b, output wire out_assign, output reg out_alwaysblock ); 答案 // synthesis verilog_input_version verilog_2001 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 always块(时序)

对于硬件综合,有两种相关的always块:

组合:always @( * ) 时序逻辑:always @(posedge clk) 时钟always块创建组合逻辑块,就像组合总是块一样,但也在组合逻辑块的输出处创建一组触发器(或“寄存器”)。逻辑块的输出不是立即可见,而是仅在下一个 (posedge clk) 之后立即可见。

阻塞与非阻塞分配

Verilog 中有三种类型的赋值:

连续赋值:(assign x = y;)。只能在不在过程内部时使用(“始终阻塞”)。 程序阻塞赋值:( x = y; )。只能在程序内部使用。 程序非阻塞赋值:( x 1 statement end 1'b0: out = 1'b0; default: out = 1'bx; endcase end case 语句以case开头,每个“case item”以冒号结尾。没有“switch”。每个 case 项只能执行一个语句。这使得 C 中使用的“break”变得不必要。但这意味着如果您需要多个语句,则必须使用begin … end。允许重复(和部分重叠)的case项。使用第一个匹配的。C 不允许重复的 case 项。 练习

如果有大量case项,Case 语句比 if 语句更方便。因此,在本练习中,创建一个 6 对 1 多路复用器。当sel在0到5之间时,选择对应的数据输入。否则,输出 0。数据输入和输出均为 4 位宽。 Module Declaration

// synthesis verilog_input_version verilog_2001 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 ); 答案 // synthesis verilog_input_version verilog_2001 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 // This is a combinational circuit case(sel) 0:out = data0; 1:out = data1; 2:out = data2; 3:out = data3; 4:out = data4; 5:out = data5; default:out = 4'b0000; endcase end endmodule case语句2

甲优先级编码器是一个组合电路,给定一个输入位向量时,输出第一的位置1中的向量位。例如,给定输入8’b100 1 0000的 8 位优先级编码器将输出3’d4,因为 bit[4] 是第一个高位。

练习

构建一个 4 位优先级编码器。对于这个问题,如果没有一个输入位为高(即输入为零),则输出零。请注意,一个 4 位数字有 16 种可能的组合。

Module Declaration

// synthesis verilog_input_version verilog_2001 module top_module ( input [3:0] in, output reg [1:0] pos ); 答案 // synthesis verilog_input_version verilog_2001 module top_module ( input [3:0] in, output reg [1:0] pos ); always@(*) begin // This is a combinational circuit case(in) 0:pos = 0; 1:pos = 0; 2:pos = 1; 3:pos = 0; 4:pos = 2; 5:pos = 0; 6:pos = 1; 7:pos = 0; 8:pos = 3; 9:pos = 0; 10:pos = 1; 11:pos = 0; 12:pos = 2; 13:pos = 0; 14:pos = 1; 15:pos = 0; default:pos = 4'b0000; endcase end endmodule casez语句

从上一个练习,case 语句中有 256 个 case。如果 case 语句中的 case 项支持 don’t-care 位,我们可以减少这种情况(减少到 9 个 case)。这就是z 的情况:它在比较中将具有z值的位视为不关心的。 例如,这将实现上一个练习中的 4 输入优先级编码器:

always @(*) begin casez (in[3:0]) 4'bzzz1: out = 0; // in[3:1] can be anything 4'bzz1z: out = 1; 4'bz1zz: out = 2; 4'b1zzz: out = 3; default: out = 0; endcase end

case 语句的行为就像是按顺序检查每个项目(实际上,它的作用更像是生成一个巨大的真值表然后制作门)。请注意某些输入(例如4’b1111)如何匹配多个 case 项。选择第一个匹配项(因此4’b1111匹配第一项out = 0,但不匹配后面的任何项)。

还有一个类似的casex将x和z 都视为无关紧要。我认为在casez上使用它没有多大意义。 ? 是z的同义词。所以2’bz0和2’b?0是一样的。

练习

为 8 位输入构建一个优先编码器。给定一个 8 位向量,输出应报告向量中的第一个位1。如果输入向量没有高位,则报告零。例如,输入8’b100 1 0000应该输出3’d4,因为 bit[4] 是第一个高位。 Module Declaration

// synthesis verilog_input_version verilog_2001 module top_module ( input [7:0] in, output reg [2:0] pos ); 答案 // synthesis verilog_input_version verilog_2001 module top_module ( input [7:0] in, output reg [2:0] pos ); always @(*) begin casez (in) 8'bzzzz_zzz1: pos = 0; 8'bzzzz_zz1z: pos = 1; 8'bzzzz_z1zz: pos = 2; 8'bzzzz_1zzz: pos = 3; 8'bzzz1_zzzz: pos = 4; 8'bzz1z_zzzz: pos = 5; 8'bz1zz_zzzz: pos = 6; 8'b1zzz_zzzz: pos = 7; default: pos = 0; endcase end endmodule 避免锁存器

假设您正在构建一个电路来处理来自游戏的 PS/2 键盘的扫描码。给定接收到的最后两个字节的扫描码,您需要指出是否按下了键盘上的箭头键之一。这涉及一个相当简单的映射,它可以实现为具有四个 case 的 case 语句(或 if-elseif)。 在这里插入图片描述 您的电路有一个 16 位输入和四个输出。构建这个电路来识别这四个扫描码并断言正确的输出。 为避免创建锁存器,必须在所有可能的条件下为所有输出分配一个值。仅仅有一个默认情况是不够的。您必须在所有四种情况和默认情况下为所有四个输出分配一个值。这可能涉及许多不必要的打字。解决此问题的一种简单方法是在 case 语句之前为输出分配一个“默认值” :

always @(*) begin up = 1'b0; down = 1'b0; left = 1'b0; right = 1'b0; case (scancode) ... // Set to 1 as necessary. endcase end

这种代码风格确保在所有可能的情况下为输出分配一个值(0),除非 case 语句覆盖分配。这也意味着default: case 项变得不必要了。逻辑合成器生成一个组合电路,其行为与代码描述的相同。硬件不会按顺序“执行”代码行。

Module Declaration

// synthesis verilog_input_version verilog_2001 module top_module ( input [15:0] scancode, output reg left, output reg down, output reg right, output reg up ); 练习答案 // synthesis verilog_input_version verilog_2001 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'he06b: left = 1'b1; 16'he072: down = 1'b1; 16'he074:right = 1'b1; 16'he075: up = 1'b1; endcase end endmodule


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3