Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

synth for ECP5, inferred true dual port ram is not allocated DP16KD ram .. #1101

Closed
bmentink opened this issue Jun 18, 2019 · 5 comments · Fixed by #3189
Closed

synth for ECP5, inferred true dual port ram is not allocated DP16KD ram .. #1101

bmentink opened this issue Jun 18, 2019 · 5 comments · Fixed by #3189

Comments

@bmentink
Copy link

bmentink commented Jun 18, 2019

Steps to reproduce the issue
I have inferred ram like so:

module bram_tdp #(
    parameter DATA = 72,
    parameter ADDR = 10
) (
    // Port A
    input   wire                a_clk,
    input   wire                a_wr,
    input   wire    [ADDR-1:0]  a_addr,
    input   wire    [DATA-1:0]  a_din,
    output  reg     [DATA-1:0]  a_dout,

    // Port B
    input   wire                b_clk,
    input   wire                b_wr,
    input   wire    [ADDR-1:0]  b_addr,
    input   wire    [DATA-1:0]  b_din,
    output  reg     [DATA-1:0]  b_dout
);

// Shared memory
reg [DATA-1:0] mem [(2**ADDR)-1:0];
  initial begin
    $readmemh("../build/nuc.hex", mem);
  end

// Port A
always @(posedge a_clk) begin
    a_dout      <= mem[a_addr];
    if(a_wr) begin
        a_dout      <= a_din;
        mem[a_addr] <= a_din;
    end
end

// Port B
always @(posedge b_clk) begin
    b_dout      <= mem[b_addr];
    if(b_wr) begin
        b_dout      <= b_din;
        mem[b_addr] <= b_din;
    end
end

endmodule

Expected behavior
DP16KD >0

Actual behavior

The routing report with nextpnr-ecp5 results in:

Info: Device utilisation:
Info:          TRELLIS_SLICE: 38529/41820    92%
Info:             TRELLIS_IO:    49/  364    13%
Info:                   DCCA:     3/   56     5%
Info:                 DP16KD:     0/  208     0%
Info:             MULT18X18D:     0/  156     0%
Info:                 ALU54B:     0/   78     0%
Info:                EHXPLLL:     1/    4    25%
Info:                EXTREFB:     0/    2     0%
Info:                   DCUA:     0/    2     0%
Info:              PCSCLKDIV:     0/    2     0%
Info:                IOLOGIC:     0/  224     0%
Info:               SIOLOGIC:     0/  140     0%
Info:                    GSR:     0/    1     0%
Info:                  JTAGG:     0/    1     0%
Info:                   OSCG:     0/    1     0%
Info:                  SEDGA:     0/    1     0%
Info:                    DTR:     0/    1     0%
Info:                USRMCLK:     0/    1     0%
Info:                CLKDIVF:     0/    4     0%
Info:              ECLKSYNCB:     0/    8     0%
Info:                DLLDELD:     0/    8     0%
Info:                 DDRDLL:     0/    4     0%
Info:                DQSBUFM:     0/   14     0%
Info:        TRELLIS_ECLKBUF:     0/    8     0%

Any idea's ? Something to try ..

@daveshah1
Copy link

Right now Yosys' BRAM doesn't support shared read/write ports such as in a true dual port RAM. If you can suffice with one write and two read ports, then Yosys would be able to map this. Otherwise unfortunately you'll have to rely on instantiation until someone gets round to fixing memory_bram to support these kinds of ports.

@bmentink
Copy link
Author

Ok, thanks, that explains it ....

@daveshah1 daveshah1 changed the title synth for ECP5, inferred ram is not allocated DP16KD ram .. synth for ECP5, inferred true dual port ram is not allocated DP16KD ram .. Jun 18, 2019
@bmentink
Copy link
Author

Tried one write two read ports, (i.e removed the write section in Port B above ) still did not map ....

@daveshah1
Copy link

Looks like it might be triggering the same bug as #1087, Yosys currently doesn't accept this style of read-after-write.

@minecraft2048
Copy link

minecraft2048 commented Mar 27, 2020

I have this code:

module dds(input clk, output reg [15:0] signal1, output reg [15:0] signal2);
    reg [9:0] phase_accumulator_1;
    reg [9:0] phase_accumulator_2;
    reg [15:0] sine_table [0:255];

    initial begin
        $readmemh("sine_lut.mem",sine_table);
    end

    always @(posedge clk) begin
        phase_accumulator_1 <= phase_accumulator_1 + 1;
        phase_accumulator_2 <= phase_accumulator_2 + 2;
    end

    always @(posedge clk) begin
        signal1 <= sine_table[phase_accumulator_1[9:2]];
        //signal2 <= sine_table[phase_accumulator_2[9:2]];
    end

    always @(posedge clk) begin
        //signal1 <= sine_table[phase_accumulator_1[9:2]];
        signal2 <= sine_table[phase_accumulator_2[9:2]];
    end

endmodule

Here is Yosys master output with signal 2 always block commented out:
2.52. Printing statistics.

=== dds ===

   Number of wires:                  8
   Number of wire bits:             91
   Number of public wires:           8
   Number of public wire bits:      91
   Number of memories:               0
   Number of memory bits:            0
   Number of processes:              0
   Number of cells:                 16
     CCU2C                           5
     DP16KD                          1
     TRELLIS_FF                     10

Here is the output with full code:

2.52. Printing statistics.

=== dds ===

   Number of wires:                 14
   Number of wire bits:            159
   Number of public wires:          14
   Number of public wire bits:     159
   Number of memories:               0
   Number of memory bits:            0
   Number of processes:              0
   Number of cells:                 31
     CCU2C                          10
     DP16KD                          2
     TRELLIS_FF                     19

I'm expecting the 2 signals to share the same DP16KD cell, especially since both of them are read only

Here is the output of MEMORY_BRAM pass:

2.26. Executing MEMORY_BRAM pass (mapping $mem cells to block memories).
Processing dds.sine_table:
  Properties: ports=2 bits=4096 rports=2 wports=0 dbits=16 abits=8 words=256
  Checking rule #1 for bram type $__ECP5_PDPW16KD (variant 1):
    Bram geometry: abits=9 dbits=36 wports=0 rports=0
    Estimated number of duplicates for more read ports: dups=1
    Metrics for $__ECP5_PDPW16KD: awaste=256 dwaste=20 bwaste=14336 waste=14336 efficiency=22
    Rule #1 for bram type $__ECP5_PDPW16KD (variant 1) accepted.
    Mapping to bram type $__ECP5_PDPW16KD (variant 1):
      Read port #0 is in clock domain \clk.
        Mapped to bram port B1.1.
      Read port #1 is in clock domain \clk.
        Failed to map read port #1.
      Growing more read ports by duplicating bram cells.
      Read port #0 is in clock domain \clk.
        Mapped to bram port B1.1.
      Read port #1 is in clock domain \clk.
        Mapped to bram port B1.2.
      Updated properties: dups=2 waste=28672 efficiency=11
      Storing for later selection.
  Checking rule #2 for bram type $__ECP5_DP16KD (variant 1):
    Bram geometry: abits=10 dbits=18 wports=0 rports=0
    Estimated number of duplicates for more read ports: dups=1
    Metrics for $__ECP5_DP16KD: awaste=768 dwaste=2 bwaste=14336 waste=14336 efficiency=22
    Rule #2 for bram type $__ECP5_DP16KD (variant 1) accepted.
    Mapping to bram type $__ECP5_DP16KD (variant 1):
      Read port #0 is in clock domain \clk.
        Mapped to bram port B1.1.
      Read port #1 is in clock domain \clk.
        Failed to map read port #1.
      Growing more read ports by duplicating bram cells.
      Read port #0 is in clock domain \clk.
        Mapped to bram port B1.1.
      Read port #1 is in clock domain \clk.
        Mapped to bram port B1.2.
      Updated properties: dups=2 waste=28672 efficiency=11
      Storing for later selection.
  Checking rule #2 for bram type $__ECP5_DP16KD (variant 2):
    Bram geometry: abits=11 dbits=9 wports=0 rports=0
    Estimated number of duplicates for more read ports: dups=1
    Metrics for $__ECP5_DP16KD: awaste=1792 dwaste=2 bwaste=16640 waste=16640 efficiency=11
    Rule #2 for bram type $__ECP5_DP16KD (variant 2) accepted.
    Mapping to bram type $__ECP5_DP16KD (variant 2):
      Read port #0 is in clock domain \clk.
        Mapped to bram port B1.1.
      Read port #1 is in clock domain \clk.
        Failed to map read port #1.
      Growing more read ports by duplicating bram cells.
      Read port #0 is in clock domain \clk.
        Mapped to bram port B1.1.
      Read port #1 is in clock domain \clk.
        Mapped to bram port B1.2.
      Updated properties: dups=2 waste=33280 efficiency=5
      Storing for later selection.
  Checking rule #2 for bram type $__ECP5_DP16KD (variant 3):
    Bram geometry: abits=12 dbits=4 wports=0 rports=0
    Estimated number of duplicates for more read ports: dups=1
    Metrics for $__ECP5_DP16KD: awaste=3840 dwaste=0 bwaste=15360 waste=15360 efficiency=6
    Rule #2 for bram type $__ECP5_DP16KD (variant 3) accepted.
    Mapping to bram type $__ECP5_DP16KD (variant 3):
      Read port #0 is in clock domain \clk.
        Mapped to bram port B1.1.
      Read port #1 is in clock domain \clk.
        Failed to map read port #1.
      Growing more read ports by duplicating bram cells.
      Read port #0 is in clock domain \clk.
        Mapped to bram port B1.1.
      Read port #1 is in clock domain \clk.
        Mapped to bram port B1.2.
      Updated properties: dups=2 waste=30720 efficiency=3
    Rule for bram type $__ECP5_DP16KD rejected: requirement 'min efficiency 5' not met.
    Mapping to bram type $__ECP5_DP16KD failed.
  Checking rule #2 for bram type $__ECP5_DP16KD (variant 4):
    Bram geometry: abits=13 dbits=2 wports=0 rports=0
    Estimated number of duplicates for more read ports: dups=1
    Metrics for $__ECP5_DP16KD: awaste=7936 dwaste=0 bwaste=15872 waste=15872 efficiency=3
    Rule #2 for bram type $__ECP5_DP16KD (variant 4) rejected: requirement 'min efficiency 5' not met.
  Checking rule #2 for bram type $__ECP5_DP16KD (variant 5):
    Bram geometry: abits=14 dbits=1 wports=0 rports=0
    Estimated number of duplicates for more read ports: dups=1
    Metrics for $__ECP5_DP16KD: awaste=16128 dwaste=0 bwaste=16128 waste=16128 efficiency=1
    Rule #2 for bram type $__ECP5_DP16KD (variant 5) rejected: requirement 'min efficiency 5' not met.
  Selecting best of 3 rules:
    Efficiency for rule 2.2: efficiency=5, cells=4, acells=1
    Efficiency for rule 2.1: efficiency=11, cells=2, acells=1
    Efficiency for rule 1.1: efficiency=11, cells=2, acells=1
    Selected rule 2.1 with efficiency 11.
    Mapping to bram type $__ECP5_DP16KD (variant 1):
      Read port #0 is in clock domain \clk.
        Mapped to bram port B1.1.
      Read port #1 is in clock domain \clk.
        Failed to map read port #1.
      Growing more read ports by duplicating bram cells.
      Read port #0 is in clock domain \clk.
        Mapped to bram port B1.1.
      Read port #1 is in clock domain \clk.
        Mapped to bram port B1.2.
      Creating $__ECP5_DP16KD cell at grid position <0 0 0>: sine_table.0.0.0
      Creating $__ECP5_DP16KD cell at grid position <0 0 1>: sine_table.0.0.1

It knows there are 2 read ports but for some reason it fails to map it so it duplicates it instead

EDIT: make new issue: #1836

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants