Hi all,
First off, thanks for creating and sustaining MyHDL! It is a fantastic tool, and I have thoroughly enjoyed using it.
I have a question, and I suspect that as I am new to MyHDL and FPGA development, the error may lie in my use of the tools as opposed to a bug. The issue is the following:
- I believe it is often the case that we want to pre-initialize BRAMs with some predetermined values. This is generally done with the
initial
syntax in Verilog, and viatoVerilog.initial_values = True
support in MyHDL. - When I enable initial value support on MyHDL, it wants to initialize the output of the data register for the BRAM.
- Yosys then decides that since the output of the RAM has an initial value that it is incompatible with the BRAM model, and pushes the entire memory out of BRAMs.
Here is a sample test case:
@block
def case_for_test(clock, reset, values):
addr = Signal(intbv(0)[4:])
data = Signal(intbv(0)[8:])
ram = [Signal(intbv(x)[8:]) for x in range(16)]
cnt = Signal(modbv(0, min=0, max=16))
we = Signal(bool(0))
@always(clock.posedge)
def rom():
if we:
ram[addr].next = 0
else:
data.next = ram[addr]
@always_seq(clock.posedge, reset=reset)
def cycle():
cnt.next = cnt + 1
addr.next = cnt
values.next = data
return instances()
I had to add the unused we
line to convince MyHDL that the memory was driven (so that initial values made it to the output). Here is the generated Verilog
// File: ../gen/case_for_test.v
// Generated by MyHDL 0.11
// Date: Mon Oct 14 11:43:58 2019
`timescale 1ns/10ps
module case_for_test (
clock,
reset,
values
);
input clock;
input reset;
output [7:0] values;
reg [7:0] values;
reg [3:0] addr = 0;
reg [3:0] cnt = 0;
reg [7:0] data = 0;
wire we;
reg [7:0] ram [0:16-1];
initial begin
ram[0] <= 0;
ram[1] <= 1;
ram[2] <= 2;
ram[3] <= 3;
ram[4] <= 4;
ram[5] <= 5;
ram[6] <= 6;
ram[7] <= 7;
ram[8] <= 8;
ram[9] <= 9;
ram[10] <= 10;
ram[11] <= 11;
ram[12] <= 12;
ram[13] <= 13;
ram[14] <= 14;
ram[15] <= 15;
end
assign we = 1'd0;
always @(posedge clock) begin: CASE_FOR_TEST_ROM
if (we) begin
ram[addr] <= 0;
end
else begin
data <= ram[addr];
end
end
always @(posedge clock, negedge reset) begin: CASE_FOR_TEST_CYCLE
if (reset == 0) begin
cnt <= 0;
addr <= 0;
values <= 0;
end
else begin
cnt <= (cnt + 1);
addr <= cnt;
values <= data;
end
end
endmodule
The heartburn is from this line:
reg [7:0] data = 0;
The Yosys synthesis pass claims:
Checking rule #1 for bram type $__ICE40_RAM4K_M0 (variant 1):
Bram geometry: abits=8 dbits=16 wports=0 rports=0
Estimated number of duplicates for more read ports: dups=1
Metrics for $__ICE40_RAM4K_M0: awaste=240 dwaste=8 bwaste=3968 waste=3968 efficiency=3
Rule #1 for bram type $__ICE40_RAM4K_M0 (variant 1) accepted.
Mapping to bram type $__ICE40_RAM4K_M0 (variant 1):
Read port #0 is in clock domain !~async~.
Bram port A1.1 has incompatible clock type.
Failed to map read port #0.
Mapping to bram type $__ICE40_RAM4K_M0 failed.
And the complaint about the read port being in the async clock domain appears linked to its initial value. If I remove that initial value, I get the following:
Number of cells: 24
SB_CARRY 2
SB_DFFR 16
SB_LUT4 5
SB_RAM40_4K 1
And the BRAM is correctly synthesized.
Any suggestions/advice on how to proceed? I can’t imagine I’m the first one to encounter this issue, but searching has so far been unhelpful.
Samit