FPGA的设计艺术(18)如何使用Verilog中的数组对存储器进行建模?

李锐博恩 2021-03-20 13:22:58 10112

前言

Verilog中的二维数组很有用,可以使用for以及generate for配合二维数组进行使用,可以代替大量寄存器的场合,其实大量同类寄存器可以使用存储器进行代替,Verilog中可以使用二维数组对存储器进行建模。

存储器由FPGA的什么资源来构成,可以由综合属性来设定,或者由综合工具来自动设置。这不是本文的重点,具体可见:Vivado 随笔(1) 综合属性之 ram_style & rom_style?

下面一起来看Verilog中的数组以及如何使用数组对存储器进行建模。

存储器

存储器是数字存储元件,可帮助在数字电路中存储数据和信息。FPGA中的RAM以及ROM等存储器的模型大概都是如下这样,我们可以设计不同的位宽和深度:
内存结构

在FPGA中,我们可以使用EDA工具提供的IP核对存储元件进行定制,当然也可以使用Verilog中的数组进行建模,下面介绍:

Verilog中的数组

我们还可以在verilog中创建和使用数组类型。这些在内存建模中特别有用。

为了在verilog中声明一个数组,我们只需要在变量名后添加一个额外的字段即可声明数组中有多少个元素。

下面的代码段显示了用于在Verilog中声明数组类型的常规语法。我们使用字段声明数组的大小。

// General syntax to declare an array type

<type> <size> <variable_name> <elements>;

例如,假设我们要创建一个4位wire类型的数组。我们希望数组中总共有16个元素。下面的Verilog代码显示了如何创建此数组。

wire [3:0] example [15:0];

我们可以使用方括号访问数组类型中的各个元素。例如,下面的verilog代码显示了如何将Fh的值分配给示例数组中的第一个元素。

assign example[0] = 4'hF;

数组允许以Verilog为reg,wire,integer和real数据类型。

reg        y1 [11:0];        // y is an scalar reg array of depth=12, each 1-bit wide
wire [7:0] y2 [3:0]          // y is an 8-bit vector net with a depth of 4

必须指定每个维的索引才能访问数组的特定元素,并且可以是其他变量的表达式。可以为Verilog支持的任何不同数据类型形成一个数组。

y1 = 0;                         // Illegal - All elements can't be assigned in a single go

y2[0] = 8'ha2;          // Assign 0xa2 to index=0
y2[2] = 8'h1c;          // Assign 0x1c to index=2

多维数组

在verilog 1995标准中,我们只能创建一维数组,例如上一节中使用的数组。

但是,当我们使用verilog 2001标准时,我们还可以创建具有多个维度的数组。

为此,我们只需添加另一个字段即可定义所需元素的数量。

下面的代码段显示了用于在verilog中创建2D数组的常规语法。

// General syntax to declare an array type

<type> <size> <variable_name> <elements> <elements>;

举个例子,让我们考虑一下我们想从前面的例子中修改数组大小的情况。

现在,我们要创建一个变量,该变量可以存储2个元素,两个元素都有16个4位wire元素。

为此,我们只需在声明的末尾添加一个额外的字段即可。下面的代码段显示了我们将如何执行此操作。

wire [3:0] example [15:0][1:0];

reg  [7:0] y3 [0:1][0:3];    // y is a 2D array rows=2,cols=4 each 8-bit wide

我们也使用与一维数组相同的方法来对多维数组赋值。但是,我们现在使用一对方括号在数组的两个维度上定义元素。

例如,假设我们要为两个维度中的最后一个元素分配Ah的值。下面的verilog代码显示了如何将数据分配给数组中的该元素。

和上面数组一样的原则:

必须指定每个维的索引才能访问数组的特定元素,并且可以是其他变量的表达式。可以为Verilog支持的任何不同数据类型形成一个数组。

y3[1][2] = 8'hdd;   // Assign 0xdd to rows=1 cols=2
y3[0][0] = 8'haa;   // Assign 0xaa to rows=0 cols=0

example [15][1] = 4'ha;

example [15][0] = 4'ha;

数组建模以及初始化示例

mem1是一个8位向量,mem2是一个深度为4(由范围[0:3]指定)的8位数组,mem3是一个具有4行2列的16位向量2D数组。这些变量被分配了不同的值并被打印。

module des ();
  reg [7:0]  mem1;                          // reg vector 8-bit wide
  reg [7:0]  mem2 [0:3];                // 8-bit wide vector array with depth=4
  reg [15:0] mem3 [0:3][0:1];   // 16-bit wide vector 2D array with rows=4,cols=2

  initial begin
    int i;

    mem1 = 8'ha9;
    $display ("mem1 = 0x%0h", mem1);

    mem2[0] = 8'haa;
    mem2[1] = 8'hbb;
    mem2[2] = 8'hcc;
    mem2[3] = 8'hdd;
    for(i = 0; i < 4; i = i+1) begin
      $display("mem2[%0d] = 0x%0h", i, mem2[i]);
    end

    for(int i = 0; i < 4; i += 1) begin
      for(int j = 0; j < 2; j += 1) begin
        mem3[i][j] = i + j;
        $display("mem3[%0d][%0d] = 0x%0h", i, j, mem3[i][j]);
      end
    end
  end
endmodule

最终可以得到打印结果:

mem1 = 0xa9
mem2 [0] = 0xaa
mem2 [1] = 0xbb
mem2 [2] = 0xcc
mem2 [3] = 0xdd
mem3 [0] [0] = 0x0
mem3 [0] [1] = 0x1
mem3 [1] [0] = 0x1
mem3 [1] [1] = 0x2
mem3 [2] [0] = 0x2
mem3 [2] [1] = 0x3
mem3 [3] [0] = 0x3
mem3 [3] [1] = 0x4

在给一个存储器逻辑设计的例子:

在此示例中,存储器是一个深度为4的数组,每个深度的宽度为16位。设计模块接受一个称为addr的附加输入信号,以访问存储器中的特定索引。

module des (    input           clk,
                input           rstn,
                input  [1:0]    addr,
                input           wr,
                input           sel,
                input [15:0]    wdata,
                output [15:0]   rdata);

reg [15:0] register [0:3];
integer i;

always @ (posedge clk) begin
    if (!rstn) begin
        for (i = 0; i < 4; i = i+1) begin
            register[i] <= 0;
        end
    end else begin
        if (sel & wr)
            register[addr] <= wdata;
        else
            register[addr] <= register[addr];
    end
end

assign rdata = (sel & ~wr) ? register[addr] : 0;
endmodule

在硬件示意图中可以看到,存储器的每个索引都是一个16位触发器,并且输入地址用于访问一组特定的触发器。

综合图

声明:本文内容由易百纳平台入驻作者撰写,文章观点仅代表作者本人,不代表易百纳立场。如有内容侵权或者其他问题,请联系本站进行删除。
红包 98 8 评论 打赏
评论
0个
内容存在敏感词
手气红包
    易百纳技术社区暂无数据
相关专栏
置顶时间设置
结束时间
删除原因
  • 广告/SPAM
  • 恶意灌水
  • 违规内容
  • 文不对题
  • 重复发帖
打赏作者
易百纳技术社区
李锐博恩
您的支持将鼓励我继续创作!
打赏金额:
¥1易百纳技术社区
¥5易百纳技术社区
¥10易百纳技术社区
¥50易百纳技术社区
¥100易百纳技术社区
支付方式:
微信支付
支付宝支付
易百纳技术社区微信支付
易百纳技术社区
打赏成功!

感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~

举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

审核成功

发布时间设置
发布时间:
是否关联周任务-专栏模块

审核失败

失败原因
备注
拼手气红包 红包规则
祝福语
恭喜发财,大吉大利!
红包金额
红包最小金额不能低于5元
红包数量
红包数量范围10~50个
余额支付
当前余额:
可前往问答、专栏板块获取收益 去获取
取 消 确 定

小包子的红包

恭喜发财,大吉大利

已领取20/40,共1.6元 红包规则

    易百纳技术社区