天天看點

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

目錄

RAM的例化

RAM的初始化

IP Catalog例化的RAM的初始化

自定義數組和XPM RAM的初始化

初始化資料的可讀性

本文所述的内容均以使用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上。