always 语句
always 语句是重复执行的。always 语句块从 0 时刻开始执行其中的行为语句;当执行完最后一条语句后,便再次执行语句块中的第一条语句,如此循环反复。多用于仿真时钟的产生,信号行为的检测等。
always语句的格式:
always @(posedge clk) begin
temp = a ;
a = b ;
b = temp ;
end
()中可以是*,表示:每当任何输入发生变化时执行begin和end之间的语句。也可以是posedge clk,表示:时钟上升沿时执行begin和end之间的语句。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
连续性赋值,过程性赋值 :连续性赋值总是处于激活状态,任何操作数的改变都会影响表达式的结果;过程赋值只有在语句执行的时候,才会起作用。
阻塞赋值与非阻塞赋值 :是过程赋值的两种类型。
阻塞赋值 :阻塞赋值属于顺序执行,下一条语句执行前,当前语句一定会执行完毕。使用等号 = 作为赋值符。initial语句用阻塞赋值。
非阻塞赋值 :并行执行,即下一条语句的执行和当前语句的执行是同时进行的,它不会阻塞位于同一个语句块中后面语句的执行。使用 <= 作为赋值符。
使用非阻塞赋值是为了避免竞争冒险,那么实际使用中只需要记住:always时序逻辑块中多用非阻塞赋值<=(后面的时序逻辑电路会另外介绍),always组合逻辑块中多用阻塞赋值=; 在仿真电路时,initial 块中一般多用阻塞赋值=。 例如下面代码中,用assign语句,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
endmodule
if 语句格式
if (condition1) true_statement1 ;
else if (condition2) true_statement2 ;
else if (condition3) true_statement3 ;
else default_statement ;
如果只有两种情况,就只有if和else。下面用上一节中MUX2_1做练习,上一节中采用了assign的三元运算符语句,这里使用always if语句实现2选1的功能:
module mux2_1
(
input wire in1,
input wire in2,
input wire sel,
output reg out
);
always@(*) begin
if(sel == 1'b1)//当“if...else...”中只有一个变量时不需要加“begin...end".但是为了不遗漏,还是加上
out = in1; //always块中的组合逻辑关系时使用阻塞赋值“=”进行赋值
else
out = in2;
end
endmodule
3-8译码器的实现
从真值表看译码器功能:A2A1A0=000-111共8种输入,对应输出Y的下标,对应下标的输出为1(高电平),其他输出为0(低电平)。3-8译码器的作用:按照之前点亮LED灯的思路,如果一个I/O端口控制一个LED灯,那么I/O端口很有可能不够用,这时候聪明人就想出用3-8译码器的方式,3个I/O口就可以控制8个LED。
设计规划
这个示例中,绘制波形图如图所示。
编写代码
module decoder3_8
(
input wire in1 ,
input wire in2 ,
input wire in3 ,
output reg [7:0] out
);
always@(*) begin
//使用"{}"位拼接符将3个1bit数据按照顺序拼成一个3bit数据
if({in1, in2, in3} == 3'b000)
out = 8'b0000_0001;
else if({in1, in2, in3} == 3'b001)
out = 8'b0000_0010;
else if({in1, in2, in3} == 3'b010)
out = 8'b0000_0100;
else if({in1, in2, in3} == 3'b011)
out = 8'b0000_1000;
else if({in1, in2, in3} == 3'b100)
out = 8'b0001_0000;
else if({in1, in2, in3} == 3'b101)
out = 8'b0010_0000;
else if({in1, in2, in3} == 3'b110)
out = 8'b0100_0000;
else if({in1, in2, in3} == 3'b111)
out = 8'b1000_0000;
else
out = 8'b0000_0001;
end
endmodule
代码中使用always组合逻辑块。由于if对应的执行语句只有一句,可以不使用begin,end但是由于怕以后复杂代码会遗漏,还是选择加上。always组合逻辑使用阻塞语句,用=进行赋值。
上面RTL代码综合出的RTL视图:
编写testbench
`timescale 1ns/1ns
module tb_decoder3_8();
//reg define
reg in1;
reg in2;
reg in3;
wire [7:0] out;
//初始化输入信号
initial begin
in1 <= 1'b0;
in2 <= 1'b0;
in3 <= 1'b0;
end
always #10 in1 <= {$random} % 2;
always #10 in2 <= {$random} % 2;
always #10 in3 <= {$random} % 2;
//-------------decoder3_8_inst----------------
decoder3_8 decoder3_8_ins
(
.in1(in1),
.in2(in2),
.in3(in3),
.out(out)
);
endmodule
经过两个实例后,testbench已经超级熟悉了吧。
对比波形
看看波型:
验证了波形的正确性
全部0条评论
快来发表一下你的评论吧 !