ke10g
ke10g

Reputation: 27

reading multiple block ram indexes in one write clock cycle

I have an application where I'm continuously writing to a block ram at a slow clock speed (clk_a) and within this slow clock cycle need to read three indexes from the block ram at a fast clock speed (clk_b) to use these values as operands in a math module, the result being written back to the block ram on the next slow clock. These three indexes are the current address written to at posedge of the slow clock, plus the two immediate neighbouring addresses (addr_a -1 and addr_a +1).

What is an efficient way to synthesize this? My best attempt to date uses a small counter (triplet) running at fast clock rate that increments the addresses but I end up running out of logic as it looks like Yosys does not infer the ram properly. What is a good strategy for this?

here is what I have:

module myRam2 (
 input clk_a,
 input clk_b,
 input we_a,
 input re_a,
 input [10:0] addr_a,
 input [10:0] addr_b,
 input [11:0] din_a,
 output [11:0] leftNeighbor,
 output [11:0] currentX,
 output [11:0] rightNeighbor
);
  parameter MEM_INIT_FILE2 = "";
 initial
    if (MEM_INIT_FILE2 != "")
      $readmemh(MEM_INIT_FILE2, ram2);
     
reg [11:0] ram2 [0:2047];
reg [1:0] triplet = 3;
reg [10:0] old_addr_a;
reg [11:0] temp;

always @(posedge clk_a) begin
    ram2[addr_a] <= din_a;
end

always@(posedge clk_b) 
if (old_addr_a != addr_a) begin
        triplet <= 0;
        old_addr_a <= addr_a;
        end
    else 
        if(triplet < 3) begin
            triplet <= triplet +1;
        end



  
  always @(posedge clk_b) begin
        temp <= ram2[addr_a + (triplet - 1)];
end

always @(posedge clk_b) begin
case(triplet)
0: leftN <= temp;
1: X <= temp;
2: rightN <= temp;
endcase
end



reg signed [11:0] leftN;
reg signed [11:0] X;
reg signed [11:0] rightN;


assign leftNeighbor = leftN;
assign currentX = X;
assign rightNeighbor = rightN;

endmodule

Upvotes: 0

Views: 893

Answers (1)

Christian B.
Christian B.

Reputation: 824

Regarding the efficiency the following approach should work and removes the need for a faster clock:

module myRam2 (
 input wire clk,
 input wire we,
 input wire re,
 input wire [10:0] addr_a,
 input wire [10:0] addr_b,
 input wire [11:0] din_a,
 output reg [11:0] leftNeighbor,
 output reg [11:0] currentX,
 output reg [11:0] rightNeighbor
);

reg [11:0] ram2 [2047:0];/* synthesis syn_ramstyle = "no_rw_check" */;

always @(posedge clk) begin
    if(we)  ram2[addr_a]                            <= din_a;
    if(re)  {leftNeighbor,currentX,rightNeighbor}   <= {ram2[addr_b-1],ram2[addr_b],ram2[addr_b+1]};
end

endmodule

The synthesis keyword helped me in the past to increase the likelyhood of correctly inferred ram.

EDIT: removed second example suggesting a 1D mapping. It turned out that at least Lattice LSE cannot deal with that approach. However the first code snipped should work according to Active-HDL and Lattice LSE.

Upvotes: 0

Related Questions