0

I've been having trouble the last little while with a project that uses look up table arrays quite a bit and getting yosys to infer them as block ram. Yosys keeps thinking one or the other of my arrays should be implemented using logic cells.

example:

reg signed [11:0] dynamicBuffer [0:2047];

gets inferred as IceStorm LC and thus quickly overflows my logic cell budget.

Info: Device utilisation:
Info:            ICESTORM_LC: 83524/ 7680  1087%
Info:           ICESTORM_RAM:    18/   32    56%
Info:                  SB_IO:    36/  256    14%
Info:                  SB_GB:     8/    8   100%
Info:           ICESTORM_PLL:     2/    2   100%
Info:            SB_WARMBOOT:     0/    1     0%

I've read that an array needs to have a registered output or Yosys does not see it as ram (is this true?) I've tried to rework things such that my arrays are ultimately routed to a register at each clock count. But I still cannot get it working. What is the right way of working with multiple arrays, copying them one to the other, and getting yosys to infer them as block ram? What do I need to avoid?

ke10g
  • 27
  • 4
  • I recall that I had a lot of trouble with inferred mem as well but I used the official toolchain. However peeking into my code yielt following line: ```reg [15:0] mem [255:0] /* synthesis syn_ramstyle = "no_rw_check" */;``` maybe the keyword does the magic or the chosen mem layout has to match the layout of the available blocks. – Christian B. Jul 04 '20 at 14:56
  • This is interesting thanks. I'll give this a try next time I run into trouble. – ke10g Jul 07 '20 at 20:07

3 Answers3

1

I've read that an array needs to have a registered output or Yosys does not see it as ram (is this true?)

Yes, its true. Only way I can make Yosys infer to BRAM is to make it an asynchronous BRAM with Input and Output. I took this from my VFD display controller project

module GRAM(
input R_CLK,
input W_CLK,

input [7:0]GRAM_IN,
output reg [7:0]GRAM_OUT,

input [11:0] GRAM_ADDR_R,
input [11:0] GRAM_ADDR_W,

input G_CE_W,
input G_CE_R);

reg [7:0] mem [3002:0];// change this to what you want.

initial mem[0] <= 255;// fill the first byte to let Yosys infer to BRAM.

always@(posedge R_CLK) begin// reading from RAM sync with reading clock.
    if(G_CE_R)
        GRAM_OUT <= mem[GRAM_ADDR_R];   
end 

always@(posedge W_CLK) begin// writing to RAM sync with writing clock.
    if(G_CE_W)
        mem[GRAM_ADDR_W] <= GRAM_IN;
end

endmodule// GRAM
TinLethax
  • 11
  • 3
0

Assuming you are using a for loop like in your last example, for loops in hardware do not run sequentially like in software but do the entire copy in one clock. You need to use a counter and a state machine for the copy, not a Verilog for loop.

gatecat
  • 1,156
  • 2
  • 8
  • 15
  • I actually tried the for loop only because the my previous attempts using clocking and counter were not working. Believe me I've tried lots of different things over the last few days. The array keeps being inferred as logic. – ke10g Jul 03 '20 at 10:38
  • for instance I just tried another build with : always@(posedge clk) begin tempBuffer[waveIndex] <= dynamicWaveBuffer[waveIndex]; end – ke10g Jul 03 '20 at 10:41
  • So the problem is elsewhere. Here is something that may be a hint. My project builds if I disconnect the array from another module where it is being read, and just only read it internally to the module it is instantiated in. Amother hint may be that I get warnings about wires having no driver: but as far as I can tell, they are all driven by clocks (I've removed conditional arguments so that on every clock there is something driving the wire. There are some external pins being read, but these all go immediately to registers before being read off by clocks and driving subsequent wires... – ke10g Jul 03 '20 at 10:46
  • I really can't give any better advice without the full code, or even better a MCVE (minimum complete verifiable example). – gatecat Jul 03 '20 at 10:51
  • I understand. I'll try to reduce the project down to just these components and post it. – ke10g Jul 03 '20 at 11:01
-1

The solution in this case was to implement an asynchronous fifo.

I was crossing clock domains when I connected the two modules so needed to synchronize reading and writing from the array. The lack of coordination between reads and writes to the array was causing yosys to infer that the array was not to be implemented as block ram.

ke10g
  • 27
  • 4
  • BRAM should generally support reads and writes from different clock domains, so assuming you used a common pattern the FIFO should not be needed. Note that the BRAM should always be contained within one module, rather than trying to share the BRAM using a port. – gatecat Jul 07 '20 at 21:39