【FPGA/verilog -入门学习5】verilog中的genrate for 和for 以及数组的用法

发布时间:2023年12月18日

本文参考:verilog generate语法总结-CSDN博客

Verilog数组赋值_笔记大全_设计学院

for 的用法

在Verilog中,generate forfor都是用于循环的结构,但是它们具有不同的应用场合和语义。

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

仿真结果

文章来源:https://blog.csdn.net/cengqiu4314/article/details/134893806
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。