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 [A-1:0] addr,
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?