当前位置:   article > 正文

【FPGA/verilog -入门学习5】verilog中的genrate for 和for 以及数组的用法_fpga数组如何定义及赋值

fpga数组如何定义及赋值

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

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

for 的用法

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

for循环:

for循环主要用于行为描述(behavioral description),通常用于描述算法或数学运算。

for循环在仿真时执行,因此,任何在for循环中使用的变量都必须是仿真时间可访问的。

for循环通常在初始化代码或在行为模型中使用,不适用于综合。示例:

在testbanch中测试使用的for代码

  1. module test;
  2. reg [7:0] vector[0:7];
  3. integer i;
  4. initial begin
  5. for (i = 0; i < 8; i = i + 1) begin
  6. vector[i] = i;
  7. end
  8. end
  9. endmodule

generate for的用法

generate for循环:

generate for循环用于结构描述(structural description),用于实例化模块或生成多个类似的结构。

generate for循环在编译时执行,生成的实例在编译后的网表中可见。

generate for循环可用于综合和实现。示例:

实现批量例化的generate for 代码

  1. module test;
  2. genvar i;
  3. generate
  4. for (i = 0; i < 8; i = i + 1) begin : gen_block
  5. my_module instance (.input(input[i]), .output(output[i]));
  6. end
  7. endgenerate
  8. 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. 循环赋值

  1. integer i;
  2. always @(*) begin
  3. for (i=0; i<4; i=i+1) begin
  4. my_array[i] = i+1;
  5. end
  6. 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

  1. /
  2. /*
  3. 脉冲计数,当是能时,对pluse脉冲计数
  4. 实现步骤
  5. 1)产生pluse 上升沿脉冲 一个clk时钟
  6. 2)产生i_en 下降沿,当下降沿 o_state=1
  7. 3)对pluse上升沿计数,锁存在r_cnt
  8. 4)当o_state=1 时,o_cnt<=r_cnt
  9. */
  10. /
  11. `timescale 1ns/1ps
  12. module vlg_design(
  13. input clk,//100M
  14. input pulse,//
  15. input reset_n,
  16. input i_en,
  17. output reg[31:0] o_cnt, //输出计数值
  18. output o_state
  19. );
  20. reg [1:0] r_pluse;
  21. reg [1:0] r_en;
  22. wire w_pluse_pos;
  23. wire w_en_neg;
  24. reg[31:0] r_cnt;
  25. //产生一个pluse 上升沿脉冲时钟
  26. always @(posedge clk) begin
  27. if(!reset_n) r_pluse <='b00;
  28. else r_pluse <= {r_pluse[0],pulse};
  29. end
  30. assign w_pluse_pos = r_pluse[0] & ~r_pluse[1];
  31. //产生一个i_en 下降沿脉冲时钟
  32. //en 下降沿时 o_state =1
  33. always @(posedge clk) begin
  34. if(!reset_n) r_en <='b00;
  35. else r_en <= {r_en[0],i_en};
  36. end
  37. assign o_state = r_en[1] & ~r_en[0];
  38. //EN = 1时候计数
  39. always @(posedge clk) begin
  40. if(!reset_n) r_cnt <= 'b0;
  41. else if(i_en)
  42. if(w_pluse_pos)r_cnt <= r_cnt + 1'b1;
  43. else ;
  44. else r_cnt <= 'b0;
  45. end
  46. //输出o_cnt
  47. always @(posedge clk) begin
  48. if(!reset_n) o_cnt <= 'b0;
  49. else if(!i_en && r_cnt) begin
  50. o_cnt <= r_cnt;
  51. $display("r_cnt=%d\n",r_cnt);//显示
  52. end
  53. else o_cnt <= 'b0;
  54. end
  55. endmodule

vlg_cnt4

  1. /
  2. //使用generate for 例化端口
  3. //设计一个脉冲计数器,其功能如下
  4. //输入脉冲:16路脉冲信号,分别对每路进行脉冲检测并计数
  5. //使能信号:高电平进行计数,低电平清零计数器
  6. //计数器:在使能信号高电平期间,对脉冲信号的上升沿进行检测并递增计数值
  7. //编写测试脚本,进行仿真验证
  8. /
  9. `timescale 1ns/1ps
  10. module vlg_cnt4(
  11. input clk,
  12. input [3:0]pulse,
  13. input reset_n,
  14. input i_en,
  15. output [31:0]o_cnt_0,o_cnt_1,o_cnt_2,o_cnt_3,
  16. output [3:0]o_state
  17. );
  18. //定义32位的w_cnt 数组,数组元素个数4
  19. wire [31:0]w_cnt[0:3];
  20. //使用 generate for 例化端口
  21. genvar i;
  22. generate
  23. for (i = 0; i < 4; i = i + 1) begin : gen_block
  24. vlg_design uut_vlg_design (
  25. .clk(clk),
  26. .pulse(pulse[i]),
  27. .reset_n(reset_n),
  28. .i_en(i_en),
  29. .o_cnt(w_cnt[i]),
  30. .o_state(o_state[i])
  31. );
  32. end
  33. endgenerate
  34. //端口赋值
  35. assign o_cnt_0 =w_cnt[0];
  36. assign o_cnt_1 =w_cnt[1];
  37. assign o_cnt_2 =w_cnt[2];
  38. assign o_cnt_3 =w_cnt[3];
  39. endmodule

testbench_top

  1. `timescale 1ns/1ps
  2. module testbench_top();
  3. //参数定义
  4. `define CLK_PERIORD 10 //时钟周期设置为10ns(100MHz)
  5. //接口申明
  6. reg clk;
  7. reg [3:0]pulse;
  8. reg reset_n;
  9. reg i_en;
  10. wire[31:0]o_cnt_0;
  11. wire[31:0]o_cnt_1;
  12. wire[31:0]o_cnt_2;
  13. wire[31:0]o_cnt_3;
  14. wire [3:0]o_state;
  15. vlg_cnt4 uut_vlg_cnt4(
  16. .clk(clk),
  17. .pulse(pulse),
  18. .reset_n(reset_n),
  19. .i_en(i_en),
  20. .o_cnt_0(o_cnt_0),
  21. .o_cnt_1(o_cnt_1),
  22. .o_cnt_2(o_cnt_2),
  23. .o_cnt_3(o_cnt_3),
  24. .o_state(o_state)
  25. );
  26. //时钟和复位初始化、复位产生
  27. initial begin
  28. clk <= 0;
  29. reset_n <= 0;
  30. #10;
  31. reset_n <= 1;
  32. clk <= 1;
  33. pulse <= 'b0000; //初始化都为0
  34. i_en <= 0;
  35. end
  36. //时钟产生
  37. always #(`CLK_PERIORD/2) clk = ~clk;
  38. integer i;
  39. //测试激励产生
  40. initial begin
  41. @(posedge reset_n); //等待复位完成
  42. @(posedge clk);
  43. //生成一个4位的0~15的随机数,赋值给pluse
  44. i_en <= 1;
  45. @(posedge clk);
  46. //10次循环,给4个pluse赋值
  47. for(i = 0;i < 10;i = i+1) begin
  48. pulse <= {$random} % 15;
  49. repeat(3)@(posedge clk);
  50. end
  51. pulse <= 'b0000;
  52. i_en <= 0;
  53. #2_000_000;
  54. $stop;
  55. end
  56. endmodule

仿真结果

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/243921
推荐阅读
相关标签
  

闽ICP备14008679号