# Why is this Verilog RAM modification better in terms of resource usage?

I'm using the open-source toolchain Yosys > NextPnr > IcePack for synthesising code for the Lattice HX8K FPGA. Here's a common version of a 1Kb RAM (that I'm using as Video RAM for a VGA module):

module text_ram #(
parameter A = 10,
parameter D = 8
) (
input  clk,
input  we,
input  [D-1:0] din,
output reg [D-1:0] dout
);

reg [D-1:0] vram [0:(1<<A)-1];   // 2^A memory spaces of D bits

initial
$readmemh("lib/video.hex", vram, 0, 1024); always @(posedge clk) begin if (we) vram[addr] <= din; dout <= vram[addr]; end endmodule  Analysing the resources with icebox_stat (alongside with all the other logic I have; sorry, but I don't know how to isolate the stats for a single component), it reports: DFFs: 21 LUTs: 204 CARRYs: 26 BRAMs: 3 IOBs: 4 PLLs: 0 GLBs: 3  Now, with this simple modification (which, granted, makes dout different, but ok for my intended purpose):  always @(posedge clk) if (we) vram[addr] <= din; always @(*) dout <= vram[addr];  It reports: DFFs: 21 LUTs: 151 CARRYs: 26 BRAMs: 0 IOBs: 4 PLLs: 0 GLBs: 1  Not only it's 53 less LUTs, but what really surprises me is that the BRAM usage seems gone! Can someone please explain me why? Also, how can I inspect such cases to make sure I understand the underlying decisions of Yosys and NextPnr? ## 2 Answers As Joshua says, something is clearly wrong here. The synthesis tool has clearly optimized away your memory. Having had a quick readup on the ice40 blockram it seems to have registered output, so making the output combinatorial would force the tool to use a big bunch of registers instead of a blockram. Speculating a bit here, but I wonder if readmemh only works on things that the synthesis tool was able to infer as blockram, and not on "big hunks of registers". Another possibility is you have forgotten to hook up some of the inputs and/or outputs properly. With the aggressive optimization that synthesis tools do, you can't really test resource usage without having a functional design. • Actually, you are right on spot; BRAM inference needs registered output. By making my output combinatorial, the $readmemh just loaded my file into a series of LUTs. Because I had so many zeros there, the resulting LUTs actually became lower than the logic needed to access BRAM. And because my test design didn't attempted to actually write to the memory, I basically ended up with a sort of ROM. Once I put more stuff into lib/video.hex, the number of LUTs went way up! Lesson learned... – Hugo Sereno Ferreira Dec 24 '19 at 1:37
• Now you have given more details we can reconstruct what happened, first because you made it combinatorial the synthesis tool was forced to use registers instead of bram, then because you had no write activity those registers could be optimised away and replaced with constant values. Then, because of the zeros in your data the read mux could be mostly optimised away. At the end of the day very little was left. – Peter Green Dec 24 '19 at 9:18
• I’m surprised the initial statement and file operations like \$readmemh are evaluated by the synthesis tool. If I recall correctly, Synopsys Design Compiler (for ASICs) ignores all initial statements. – Michael Dec 24 '19 at 13:05
• @Michael I think that's a divide between FPGA and ASIC targets; FPGAs often have a dedicated global reset line that the synthesis tools are aware of, while AFAIK most ASIC designs require a manual global reset that gets laid out along with the logic. – nanofarad Dec 24 '19 at 20:26

Normally if my design shows a drop in resources it means that it actually 'optimized' something away; I suspect the same has happened here.

Typical FPGA toolchains will cut everything away that does not directly or indirectly influence an output pin.

Best way to check what Yosys is doing seems to include using the 'show' command: http://www.clifford.at/yosys/files/yosys_appnote_011_design_investigation.pdf