RAM的多种例化和初始化方法

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/yinyeyy/article/details/104546018

本文所述的内容均以使用Xilinx器件为前提,不需要进行修改,或者做出少量修改就可以在Altera器件上应用。

RAM的例化

我常使用的例化方法主要有三种。

  • 使用IP Catalog例化

  • 通过代码让编译器推断出RAM

  • 调用原语

上述方法各有优缺点。

IP Catalog的方法容易上手,但是修改起来很是繁琐,需要重新customize,重新OOC综合......,而且不能实现参数化;通过特定代码风格使编译器推断出RAM的方式更为灵活,也可以实现参数化,而且只要设计者对Xilinx的一些约束足够熟悉(比如RAM_STYLE、ROM_STYLE)也可以达到其他方式一样的效果,同时只有这种实现方法可以实现代码在不同厂商间兼容,只是该方法对设计者要求高,尤其是一些复杂应用,如非对称RAM;调用原语的好处是使用灵活,修改方便,可参数化。

个人认为,如果不是为了厂商间兼容,使用原语(即XPM)是更好的实现方式。

通过代码让编译器推断出RAM时,可以参考ug901的RAM HDL Coding Techniques章节。如果使用XPM则可以参考ug974。

RAM的初始化

IP Catalog例化的RAM的初始化

这种情况下都是通过COE文件进行初始化。在IP生成向导中有步骤让使用者指定所需要的COE文件,当然文件内容需要使用者编辑。COE文件具体格式通过直接搜索“COE File Syntax”就可以找到,不同内容的COE文件的格式略有区别,大致都是下面的样子。

******************************************************************
********  Example of Single Port Block Memory .COE file  *********
******************************************************************
; Sample memory initialization file for Single Port Block Memory, 
; v3.0 or later.
;
; This .COE file specifies initialization values for a block 
; memory of depth=16, and width=8. In this case, values are 
; specified in hexadecimal format.
memory_initialization_radix=16;
memory_initialization_vector=
ff,
ab,
f0,
11,
11,
00,
01,
aa,
bb,
cc,
dd,
ef,
ee,
ff,
00,
ff;

COE文件对格式的要求相对严格。

自定义数组和XPM RAM的初始化

自定义数组可以使用.mem文件初始化,XPM RAM只能通过该文件初始化。初始化的语法通常像下面这样。

module tb();
    reg [7:0] test_memory [0:15];
    initial begin
        $readmemh("rom_init.mem", test_memory);
    end
endmodule

使用readmemh和readmemb进行初始化,重点是,这两个命令是可以综合的!!!他们的语法如下。

$readmemh("hex_init.mem", memory_array, [start_address], [end_address]);
$readmemb("bin_init.mem", memory_array, [start_address], [end_address]);

其中memory_array是用户定义的数组,start_address和end_address定义了memory_array的哪部分将被初始化,hex_init.mem和bin_init.mem是用户编辑的初始化数据。.mem文件中数据通过空格、tab或者换行符分隔,比如下面这样的格式。

reg [7:0] t_memory [0:3];
 
$readmemh("init1.mem", t_memory);
 
// Init memory file content
 
beed beef
5a5a a5a5

初始化数据的可读性

由于格式的限制,当存储器的位宽很宽时,上述初始化文件的可读性比较差。比如一个存储单元item[255:0]有多个涵义不同的段组成,每个段的宽度也不同。我在初始化的时候希望数据表述很清晰,每段位宽一目了然。但是上述文件格式做不到。所以在之前的项目中,我使用下面的verilog代码的方式赋值。

always @ (posedge clk) begin
    if( en ) begin 
        case( addr )
    `PAT_ADDR_WID'h00: data <= {`PAT_RESV1'h0,  `ADDR'h000000000,   `CMD'h00,   `PAT_RESV2'h0,  `OPERA'h00000000,   `TIMING'h0000,  `VEC'h0000_0000_0000_0000_0000_0000_0000_0010};
    `PAT_ADDR_WID'h01: data <= {`PAT_RESV1'h0,  `ADDR'h000000001,   `CMD'h00,   `PAT_RESV2'h0,  `OPERA'h00000000,   `TIMING'h0000,  `VEC'h0000_0000_0000_0000_0000_0000_0000_0001};
    `PAT_ADDR_WID'h02: data <= {`PAT_RESV1'h0,  `ADDR'h000000002,   `CMD'h00,   `PAT_RESV2'h0,  `OPERA'h00000000,   `TIMING'h0001,  `VEC'h0000_0000_0000_0000_0000_0000_0000_0010};
    `PAT_ADDR_WID'h03: data <= {`PAT_RESV1'h0,  `ADDR'h000000003,   `CMD'h00,   `PAT_RESV2'h0,  `OPERA'h00000000,   `TIMING'h0002,  `VEC'h0000_0000_0000_0000_0000_0000_0000_0001};
    `PAT_ADDR_WID'h04: data <= {`PAT_RESV1'h0,  `ADDR'h000000004,   `CMD'h00,   `PAT_RESV2'h0,  `OPERA'h00000000,   `TIMING'h0003,  `VEC'h0000_0000_0000_0000_0000_0000_0000_0010};
 
    `PAT_ADDR_WID'h05: data <= {`PAT_RESV1'h0,  `ADDR'h000000005,   `CMD'h00,   `PAT_RESV2'h0,  `OPERA'h00000004,   `TIMING'h0003,  `VEC'h0000_0000_0000_0000_0000_0000_0000_0001};
    `PAT_ADDR_WID'h06: data <= {`PAT_RESV1'h0,  `ADDR'h000000006,   `CMD'h00,   `PAT_RESV2'h0,  `OPERA'h00000008,   `TIMING'h0000,  `VEC'h0000_0000_0000_0000_0000_0000_0000_0077};
    `PAT_ADDR_WID'h07: data <= {`PAT_RESV1'h0,  `ADDR'h000000007,   `CMD'h00,   `PAT_RESV2'h0,  `OPERA'h00000000,   `TIMING'h0000,  `VEC'h0000_0000_0000_0000_0000_0000_0000_0077};
    `PAT_ADDR_WID'h08: data <= {`PAT_RESV1'h0,  `ADDR'h000000008,   `CMD'h00,   `PAT_RESV2'h0,  `OPERA'h00000000,   `TIMING'h0000,  `VEC'h0000_0000_0000_0000_0000_0000_0000_0077};
    `PAT_ADDR_WID'h09: data <= {`PAT_RESV1'h0,  `ADDR'h000000009,   `CMD'h09,   `PAT_RESV2'h0,  `OPERA'h00000000,   `TIMING'h0000,  `VEC'h0000_0000_0000_0000_0000_0000_0000_0010};
        endcase
    end
end

可以看到上述方式能够清晰的看到256bits数据由哪些段组成,每段的涵义,每段的值都非常清楚。下面把这种方式和.mem格式初始化数据的内容放在一起对比,就有一个更直观的认识。

`PAT_ADDR_WID'h04: data <= {`PAT_RESV1'h0,  `ADDR'h000000004,   `CMD'h00,   `PAT_RESV2'h0,  `OPERA'h00000000,   `TIMING'h0003,  `VEC'h0000_0000_0000_0000_0000_0000_0000_0010};
 
0000000000000004000000000000000300000000000000000000000000000010

第一行表示的数据和最后一行表示的数据是一致的,哪一个更清楚就不用多说了!当然在这里我使用的方式也有局限性,更适合用在位宽大、深度相对小的RAM或ROM上。

最新文章

最新文章