How to infer block RAM in Verilog

匿名 (未验证) 提交于 2019-12-03 01:20:02

问题:

I've got one very specific problem with a project that has been haunting me for days now. I have the following Verilog code for a RAM module:

module RAM_param(clk, addr, read_write, clear, data_in, data_out);     parameter n = 4;     parameter w = 8;      input clk, read_write, clear;     input [n-1:0] addr;     input [w-1:0] data_in;     output reg [w-1:0] data_out;      reg [w-1:0] reg_array [2**n-1:0];      integer i;     initial begin         for( i = 0; i < 2**n; i = i + 1 ) begin             reg_array[i] <= 0;         end     end      always @(negedge(clk)) begin         if( read_write == 1 )             reg_array[addr] <= data_in;         if( clear == 1 ) begin             for( i = 0; i < 2**n; i = i + 1 ) begin                 reg_array[i] <= 0;             end         end         data_out = reg_array[addr];     end endmodule 

It behaves exactly as expected, however when I go to synthesize I get the following:

Synthesizing Unit <RAM_param_1>.     Related source file is "C:\Users\stevendesu\---\RAM_param.v".         n = 11         w = 16     Found 32768-bit register for signal <n2059[32767:0]>.     Found 16-bit 2048-to-1 multiplexer for signal <data_out> created at line 19.     Summary:     inferred 32768 D-type flip-flop(s).     inferred 2049 Multiplexer(s). Unit <RAM_param_1> synthesized. 

32768 flip-flops! Why doesn't it just infer a block RAM? This RAM module is so huge (and I have two of them - one for instruction memory, one for data memory) that it consumes the entire available area of the FPGA... times 2.4

I've been trying everything to force it to infer a block RAM instead of 33k flip flops, but unless I can get it figured out soon I may have to greatly reduce the size of my memory just to fit on a chip.

回答1:

I just remove something your code, the result like this:

 module RAM_param(clk, addr, read_write, clear, data_in, data_out); parameter n = 4; parameter w = 8;  input clk, read_write, clear; input [n-1:0] addr; input [w-1:0] data_in; output reg [w-1:0] data_out;  // Start module here! reg [w-1:0] reg_array [2**n-1:0];  integer i; initial begin     for( i = 0; i < 2**n; i = i + 1 ) begin         reg_array[i] <= 0;     end end  always @(negedge(clk)) begin     if( read_write == 1 )         reg_array[addr] <= data_in;     //if( clear == 1 ) begin         //for( i = 0; i < 2**n; i = i + 1 ) begin             //reg_array[i] <= 0;         //end     //end     data_out = reg_array[addr]; end endmodule   

Init all zeros may dont't need code, if you want to init, just do it:

initial begin     $readmemb("data.dat", mem); end 

Then the result that I got from ISE 13.1

Synthesizing (advanced) Unit <RAM_param>. INFO:Xst:3231 - The small RAM <Mram_reg_array> will be implemented on LUTs in order to maximize performance and save block RAM resources. If you want to force its implementation on block, use option/constraint ram_style.      -----------------------------------------------------------------------     | ram_type           | Distributed                         |          |     -----------------------------------------------------------------------     | Port A                                                              |     |     aspect ratio   | 16-word x 8-bit                     |          |     |     clkA           | connected to signal <clk>           | fall     |     |     weA            | connected to signal <read_write>    | high     |     |     addrA          | connected to signal <addr>          |          |     |     diA            | connected to signal <data_in>       |          |     |     doA            | connected to internal node          |          

Update here!: Strong thanks to mcleod_ideafix Sorry about forgot your question: it's block RAM, not distributed. For block RAM, you must force it: Synthesis - XST -> Process Properties -> HDL option -> RAM style -> Change from auto to Block. The result will be this:

Synthesizing (advanced) Unit <RAM_param>. INFO:Xst:3226 - The RAM <Mram_reg_array> will be implemented as a BLOCK RAM, absorbing the following register(s): <data_out>     -----------------------------------------------------------------------     | ram_type           | Block                               |          |     -----------------------------------------------------------------------     | Port A                                                              |     |     aspect ratio   | 16-word x 8-bit                     |          |     |     mode           | read-first                          |          |     |     clkA           | connected to signal <clk>           | fall     |     |     weA            | connected to signal <read_write>    | high     |     |     addrA          | connected to signal <addr>          |          |     |     diA            | connected to signal <data_in>       |          |     |     doA            | connected to signal <data_out>      |          |     -----------------------------------------------------------------------     | optimization       | speed                               |          |     ----------------------------------------------------------------------- Unit <RAM_param> synthesized (advanced). 

End of Update

I recommend you read xst user guide for RAM sample code and the device data sheet. For example, in some FPGA LUT RAM: the reset signal is not valid. If you tried to reset it, the more logic module to reset must be integrate it. It leads to D-FF instead of RAM. The Reset signal will auto-assign to system reset.

In case of Block RAM (not LUT RAM), I prefer to specific depth/data-width or core generation or call it directly from library. More source code for general usage (ASIC/FPGA) can be found here: http://asic-world.com/examples/verilog/ram_dp_sr_sw.html



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!