【FPGA/verilog -入门学习5】verilog中的genrate for 和for 以及数组的用法
本文参考:verilog generate语法总结-CSDN博客
for 的用法
在Verilog中,generate for
和for
都是用于循环的结构,但是它们具有不同的应用场合和语义。
for
循环:
for
循环主要用于行为描述(behavioral description),通常用于描述算法或数学运算。
for
循环在仿真时执行,因此,任何在for
循环中使用的变量都必须是仿真时间可访问的。
for
循环通常在初始化代码或在行为模型中使用,不适用于综合。示例:
在testbanch中测试使用的for代码
module test;
reg [7:0] vector[0:7];
integer i;
initial begin
for (i = 0; i < 8; i = i + 1) begin
vector[i] = i;
end
end
endmodule
generate for的用法
generate for
循环:
generate for
循环用于结构描述(structural description),用于实例化模块或生成多个类似的结构。
generate for
循环在编译时执行,生成的实例在编译后的网表中可见。
generate for
循环可用于综合和实现。示例:
实现批量例化的generate for 代码
module test;
genvar i;
generate
for (i = 0; i < 8; i = i + 1) begin : gen_block
my_module instance (.input(input[i]), .output(output[i]));
end
endgenerate
endmodule
在这个例子中,my_module
被实例化了8次,每次实例化都与不同的输入和输出相连接。genvar
关键字用于声明在generate for
循环中使用的变量。
总结区别
主要区别在于for
循环用于行为描述,在仿真时执行;
而generate for
循环用于结构描述,在编译时执行。此外,它们的变量类型也不同,for
循环使用integer
类型,而generate for
循环使用genvar
类型。
使用genrate for后面跟的 begin必须要有名称,也就是必须要有标签,因为标签会作为generate循环的实例名称。
补充
正常情况下,我们的for循环、if以及case语句都要写在always块中,
然而在always块里是不能例化模块的,
所以我们就没有办法使用这几种语句去例化模块。
可是使用了generate之后,我们就可以不在always块中使用for循环、if以及case语句,
从而可以使用这几种语句来例化模块,这样我们就可以方便的给不同的例化对象不同的参数以及实现在不同情况下例化不同模块的需求。
数组的用法
一、数组基础
reg [7:0] my_array [0:3];
表示数组元素个数有4个,每一个元素是8位
注意my_array 前后的写法 前面的位数是7:0 ,后面的个数是0:3
二、数组赋值
1. 声明时初始化
reg [7:0] my_array [0:3] = '{8'h11, 8'h22, 8'h33, 8'h44};
2. 按索引赋值
my_array[1] = 8'hAA;
3. 循环赋值
integer i;
always @(*) begin
for (i=0; i<4; i=i+1) begin
my_array[i] = i+1;
end
end
可以使用循环语句在always块中为数组元素进行赋值。在上面的例子中,我们使用了一个for循环来遍历数组索引,并将其值设置为在循环中计算的值。
问题:'Port' must not be declared to be an array:
端口不能定义成数组格式
修改:
示例:使用generate for 实现例化4个脉冲计数功能
需求
1,使用generate for 实现例化4个脉冲计数功能
需求分析
1,熟悉generate for 语句的用法
2,端口定义,注意端口不能出现数组的写法,需列出全部接口。但wire/reg 可使用数组的写法。
可以在generate for 例化中使用wire 类型的信号数组
最后使用assign 端口 = wire 的形式
3,数组的用法,注意 [位:0]name [0:个] name前后的 写法。
4,在testbanch 中for 的写法,区别于generate for。
5,rand = {random}%15 。random 的3种用法注意事项
vlg_design
/
/*
脉冲计数,当是能时,对pluse脉冲计数
实现步骤
1)产生pluse 上升沿脉冲 一个clk时钟
2)产生i_en 下降沿,当下降沿 o_state=1
3)对pluse上升沿计数,锁存在r_cnt
4)当o_state=1 时,o_cnt<=r_cnt
*/
/
`timescale 1ns/1ps
module vlg_design(
input clk,//100M
input pulse,//
input reset_n,
input i_en,
output reg[31:0] o_cnt, //输出计数值
output o_state
);
reg [1:0] r_pluse;
reg [1:0] r_en;
wire w_pluse_pos;
wire w_en_neg;
reg[31:0] r_cnt;
//产生一个pluse 上升沿脉冲时钟
always @(posedge clk) begin
if(!reset_n) r_pluse <='b00;
else r_pluse <= {r_pluse[0],pulse};
end
assign w_pluse_pos = r_pluse[0] & ~r_pluse[1];
//产生一个i_en 下降沿脉冲时钟
//en 下降沿时 o_state =1
always @(posedge clk) begin
if(!reset_n) r_en <='b00;
else r_en <= {r_en[0],i_en};
end
assign o_state = r_en[1] & ~r_en[0];
//EN = 1时候计数
always @(posedge clk) begin
if(!reset_n) r_cnt <= 'b0;
else if(i_en)
if(w_pluse_pos)r_cnt <= r_cnt + 1'b1;
else ;
else r_cnt <= 'b0;
end
//输出o_cnt
always @(posedge clk) begin
if(!reset_n) o_cnt <= 'b0;
else if(!i_en && r_cnt) begin
o_cnt <= r_cnt;
$display("r_cnt=%d\n",r_cnt);//显示
end
else o_cnt <= 'b0;
end
endmodule
vlg_cnt4
/
//使用generate for 例化端口
//设计一个脉冲计数器,其功能如下
//输入脉冲:16路脉冲信号,分别对每路进行脉冲检测并计数
//使能信号:高电平进行计数,低电平清零计数器
//计数器:在使能信号高电平期间,对脉冲信号的上升沿进行检测并递增计数值
//编写测试脚本,进行仿真验证
/
`timescale 1ns/1ps
module vlg_cnt4(
input clk,
input [3:0]pulse,
input reset_n,
input i_en,
output [31:0]o_cnt_0,o_cnt_1,o_cnt_2,o_cnt_3,
output [3:0]o_state
);
//定义32位的w_cnt 数组,数组元素个数4
wire [31:0]w_cnt[0:3];
//使用 generate for 例化端口
genvar i;
generate
for (i = 0; i < 4; i = i + 1) begin : gen_block
vlg_design uut_vlg_design (
.clk(clk),
.pulse(pulse[i]),
.reset_n(reset_n),
.i_en(i_en),
.o_cnt(w_cnt[i]),
.o_state(o_state[i])
);
end
endgenerate
//端口赋值
assign o_cnt_0 =w_cnt[0];
assign o_cnt_1 =w_cnt[1];
assign o_cnt_2 =w_cnt[2];
assign o_cnt_3 =w_cnt[3];
endmodule
testbench_top
`timescale 1ns/1ps
module testbench_top();
//参数定义
`define CLK_PERIORD 10 //时钟周期设置为10ns(100MHz)
//接口申明
reg clk;
reg [3:0]pulse;
reg reset_n;
reg i_en;
wire[31:0]o_cnt_0;
wire[31:0]o_cnt_1;
wire[31:0]o_cnt_2;
wire[31:0]o_cnt_3;
wire [3:0]o_state;
vlg_cnt4 uut_vlg_cnt4(
.clk(clk),
.pulse(pulse),
.reset_n(reset_n),
.i_en(i_en),
.o_cnt_0(o_cnt_0),
.o_cnt_1(o_cnt_1),
.o_cnt_2(o_cnt_2),
.o_cnt_3(o_cnt_3),
.o_state(o_state)
);
//时钟和复位初始化、复位产生
initial begin
clk <= 0;
reset_n <= 0;
#10;
reset_n <= 1;
clk <= 1;
pulse <= 'b0000; //初始化都为0
i_en <= 0;
end
//时钟产生
always #(`CLK_PERIORD/2) clk = ~clk;
integer i;
//测试激励产生
initial begin
@(posedge reset_n); //等待复位完成
@(posedge clk);
//生成一个4位的0~15的随机数,赋值给pluse
i_en <= 1;
@(posedge clk);
//10次循环,给4个pluse赋值
for(i = 0;i < 10;i = i+1) begin
pulse <= {$random} % 15;
repeat(3)@(posedge clk);
end
pulse <= 'b0000;
i_en <= 0;
#2_000_000;
$stop;
end
endmodule
仿真结果
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!