参考:verilog数字系统设计教程【第四版】夏宇闻
repeat语句用阻塞赋值语句,与用非阻塞语句产生的结果差别非常大,所以将二者放在同一篇文章中。
1、赋值语句
2、repeat 语句介绍
2.1、用法要点
2.2、代码举例
代码1:always 语句实现 repeat n 次赋值
代码2:initial 语句实现 repeat n 次赋值
代码3:给 memory 类型数据赋值
代码4:实现 memory 类型储值
1、赋值语句
在 verilog HDL 语言中,信号有两种赋值方式,两者的区别见下表:
非阻塞赋值方式 (non_blocking) b<=a | 阻塞赋值方式 (blocking) b=a |
---|---|
在语句块中,上面语句所赋值的变量值不能立即为下面语句所用。 | b的值在赋值语句执行完后立刻改变 |
块结束后才能完成这次赋值操作,而所赋值的变量值是上一次赋值得到的。 | 赋值语句执行完毕后,块才结束 |
在编写可综合的时序逻辑模块时,这是最常用的赋值方法。 | 在时序逻辑中使用时,可能会产生意想不到的结果 |
仿真代码如下:
`timescale 1ns / 1ps
module tb_assignment;
reg clk;
reg rst;
initial begin
clk = 1;
rst = 1;
#99;
rst = 0;
end
always #1 clk = ~clk;
reg [7:0] count;
reg [7:0] count_r1;
reg [7:0] count_r2;
reg [7:0] non_count;
reg [7:0] non_count_r1;
reg [7:0] non_count_r2;
always @(posedge clk)begin
if(rst )begin
non_count <= 8'd0;
non_count_r1 <= 8'd0;
non_count_r2 <= 8'd0;
end else begin
non_count <= non_count + 1'd1;
non_count_r1 <= non_count;
non_count_r2 <= non_count_r1;
end
end
always @(posedge clk)begin
if(rst )begin
count = 8'd0;
count_r1 = 8'd0;
count_r2 = 8'd0;
end else begin
count = count + 1'd1;
count_r1 = count;
count_r2 = count_r1;
end
end
endmodule
仿真结果图
2、repeat 语句介绍
连续执行一条语句N次。
repeat语句格式
1、单语句
repeat(表达式)语句
2、多语句
repeat(表达式)begin
多条语句;
end
2.1、用法要点
表达式通常为常量表达式。
2.2、代码举例
代码1:always语句实现 repeat n 次赋值
实现乘法器
reg i_Clk;
reg i_rst;
initial begin
i_Clk = 1;
i_rst = 1;
#101;
i_rst = 0;
end
initial begin
forever #1 i_Clk = ~i_Clk;
end
reg [3:0] size = 4;
reg [3:0] data_a = 4'b0110;
reg [3:0] data_b = 4'b1100;
//===============================================================================
// always 语句
//===============================================================================
//============================================================= =
reg [7:0] result = 0;
reg [7:0] shift_a;
reg [7:0] shift_b;
always@(posedge i_Clk)begin
if(i_rst)begin
result = 8'd0;
shift_a = data_a;
shift_b = data_b;
end else
repeat(size) begin
if(shift_b[0])
result = result + shift_a;
shift_a = shift_a << 1;
shift_b = shift_b >> 1;
end
end
//============================================================= <=
reg [7:0] non_result = 0;
reg [7:0] non_shift_a;
reg [7:0] non_shift_b;
always@(posedge i_Clk)begin
if(i_rst)begin
non_result <= 8'd0;
non_shift_a <= data_a;
non_shift_b <= data_b;
end else
repeat(size) begin
if(non_shift_b [0])
non_result <= non_result + non_shift_a;
non_shift_a <= non_shift_a << 1;
non_shift_b <= non_shift_b >> 1;
end
end
仿真结果如下:
代码2:inital 语句实现 repeat n 次赋值
实现乘法器
//===============================================================================
// initial 只执行一次 同上个版本共用 i_Clk 等信号
//===============================================================================
//================================================ =
initial begin
result = 8'd0;
shift_a = data_a;
shift_b = data_b;
#10;
repeat(size) @(posedge i_Clk) begin
if(shift_b[0])
result = result + shift_a;
shift_a = shift_a << 1;
shift_b = shift_b >> 1;
end
end
//================================================ <=
initial begin
non_result <= 8'd0;
non_shift_a <= data_a;
non_shift_b <= data_b;
#10;
repeat(size) @(posedge i_Clk) begin
if(non_shift_b[0])
non_result <= non_result + non_shift_a;
non_shift_a <= non_shift_a << 1;
non_shift_b <= non_shift_b >> 1;
end
end
仿真结果如下:
因为 @(posedge i_Clk) 即实现下一时钟的作用,所以此处 <= 和 = 的仿真结果一样。
代码3:用于给 memory 类型数据赋值
reg i_Clk;
reg i_rst;
initial begin
i_Clk = 1;
i_rst = 1;
#20;
i_rst = 0;
end
initial begin
forever #1 i_Clk = ~i_Clk;
end
//==============================================
// assgn memory
//==============================================
reg [3:0] test_data = 0;
reg [3:0] i = 0;
reg [3:0] buffer[7:0];
reg [3:0] j = 0;
reg [3:0] non_buffer[7:0];
always @ (posedge i_Clk)begin
if(i_rst)
test_data <= 4'd0;
else
test_data <= test_data + 1'd1;
end
//================================================================= =
always @(posedge i_Clk) begin
i = 0 ;
if (i_rst) // repeat 8 times to assign initial value
repeat (8) begin
buffer[i] = 4'b0 ;
i = i + 1 ;
end
else
repeat (5) begin
buffer[i] = test_data ;
i = i + 1 ;
end
end
/* 错误写法
always @(posedge i_Clk) begin
i = 0 ;
if (i_rst)
repeat (8) //i在下一时钟上升沿即变为8
i = i + 1 ;
else
repeat (5) //i在下一时钟上升沿即变为5
i = i + 1 ;
end
always @(posedge i_Clk) begin
i = 0 ;
if (i_rst)
repeat (8) //在下一时钟上升沿buffer[8]变为0,其他buffer[]未赋初值
buffer[i] = 4'b0 ;
else
repeat (5) //在下一时钟上升沿buffer[5]变为test_data,其他buffer[]未赋值
buffer[i] = test_data;
end
*/
//================================================================= <=
always @(posedge i_Clk) begin
j <= 0 ;
if (i_rst)
repeat (8) begin
non_buffer[j] <= 4'b0; //此处 = 和 <= 结果都无影响
j <= j + 1 ;
end
else
repeat (5) begin
non_buffer[j] <= test_data; //此处 = 和 <= 结果都无影响
j <= j + 1 ;
end
end
/* 将 j 和 buffer 分开
always @(posedge i_Clk) begin
j <= 0 ;
if (i_rst)
repeat (8)
j <= j + 1 ;
else
repeat (5)
j <= j + 1 ;
end
always @(posedge i_Clk) begin
if (i_rst)
repeat (8)
non_buffer[j] <= 4'b0 ;//此处 = 和 <= 结果都无影响
else
repeat (5)
non_buffer[j] <= test_data ; //此处 = 和 <= 结果都无影响
end
*/
代码4:实现 memory 类型储值
reg i_Clk;
reg i_rst;
initial begin
i_Clk = 1;
i_rst = 1;
#30;
i_rst = 0;
end
initial begin
forever #4 i_Clk = ~i_Clk;
end
reg data_valid;
reg [3:0] data_demo;
reg [3:0] buffer_cnt;
reg [3:0] buffer_demo [7:0];
always @ (posedge i_Clk)begin
if(i_rst) begin
data_valid <= 1'd0;
data_demo <= 4'd0;
end else begin
if (data_demo == 4'd15)
data_demo <= data_demo;
else
data_demo <= data_demo + 1'd1;
if (data_demo == 4'd8)
data_valid <= 1'd0;
else if(data_demo == 4'd0)
data_valid <= 1'd1;
end
end
always@(posedge i_Clk)begin
if(i_rst)
buffer_cnt <= 4'd0;
else if(data_valid)
if(buffer_cnt == 4'd7)
buffer_cnt <= buffer_cnt;
else
buffer_cnt <= buffer_cnt + 1'd1;
else
buffer_cnt <= 4'd0;
end
always @(posedge i_Clk) begin
j = 0 ;
if (i_rst)
repeat (8) begin
buffer_demo[j] <= 4'b0;
j = j + 1 ;
end
else if(data_valid)
buffer_demo[buffer_cnt] <= data_demo;
end
仿真结果图: