Skip to content

Unexpected BRAM2BE synthesis results in Vivado 2022.2 #777

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

Open
ChienTeLi opened this issue Apr 9, 2025 · 1 comment
Open

Unexpected BRAM2BE synthesis results in Vivado 2022.2 #777

ChienTeLi opened this issue Apr 9, 2025 · 1 comment

Comments

@ChienTeLi
Copy link

ChienTeLi commented Apr 9, 2025

I tried to synthesize a module in Vivado, but I found that the synthesis result of BRAM2BE is not as expected.

As shown in the code, the synthesis results are compared below.

module test_bram_syn(
	input clk,
	input [7:0] ADDRA,
	input [7:0] ADDRB,
	input [15:0] DIA,
	input [15:0] DIB,
	input [1:0] WEA,
	input ENA,
	input ENB,
	output [15:0] DOA,
	output [15:0] DOB
);
    
	wire [1:0] WEB;
	assign WEB = 2'b11;
	BRAM2BE #(.PIPELINED(1'd0),
	    .ADDR_WIDTH(32'd8),
	    .DATA_WIDTH(32'd16),
	    .CHUNKSIZE(32'd8),
	    .WE_WIDTH(32'd2),
	    .MEMSIZE(9'd256)) axil_bram_inst_1_bram_inst_memory(.CLKA(clk),
								.CLKB(clk),
								.ADDRA(ADDRA),
								.ADDRB(ADDRB),
								.DIA(DIA),
								.DIB(DIB),
								.WEA(WEA),
								.WEB(WEB),
								.ENA(ENA),
								.ENB(ENB),
								.DOA(DOA),
								.DOB(DOB));
endmodule

Using original BRAM2BE.v from https://github.com/B-Lang-org/bsc/blob/main/src/Verilog.Vivado/BRAM2BE.v

Image
Image

Using modified BRAM2BE.v which references:

  • Vivado Design Suite User Guide: Synthesis (UG901)
    -- Byte Write Enable—True Dual Port with Byte-Wide Write Enable (Verilog)

`ifdef BSV_ASSIGNMENT_DELAY
`else
 `define BSV_ASSIGNMENT_DELAY
`endif

// Dual-Ported BRAM (WRITE FIRST) with byte enables
module BRAM2BE(CLKA,
               ENA,
               WEA,
               ADDRA,
               DIA,
               DOA,
               CLKB,
               ENB,
               WEB,
               ADDRB,
               DIB,
               DOB
              );

   parameter                      PIPELINED  = 0;
   parameter                      ADDR_WIDTH = 1;
   parameter                      DATA_WIDTH = 1;
   parameter                      CHUNKSIZE  = 1;
   parameter                      WE_WIDTH   = 1;
   parameter                      MEMSIZE    = 1;

   input                          CLKA;
   input                          ENA;
   input [WE_WIDTH-1:0]           WEA;
   input [ADDR_WIDTH-1:0]         ADDRA;
   input [DATA_WIDTH-1:0]         DIA;
   output [DATA_WIDTH-1:0]        DOA;

   input                          CLKB;
   input                          ENB;
   input [WE_WIDTH-1:0]           WEB;
   input [ADDR_WIDTH-1:0]         ADDRB;
   input [DATA_WIDTH-1:0]         DIB;
   output [DATA_WIDTH-1:0]        DOB;

   (* RAM_STYLE = "BLOCK" *)
   reg [DATA_WIDTH-1:0]           RAM[0:MEMSIZE-1] /* synthesis syn_ramstyle="no_rw_check" */ ;
   reg [DATA_WIDTH-1:0]           DOA_R;
   reg [DATA_WIDTH-1:0]           DOA_R2;
   reg [DATA_WIDTH-1:0]           DOB_R;
   reg [DATA_WIDTH-1:0]           DOB_R2;

`ifdef BSV_NO_INITIAL_BLOCKS
`else
   // synopsys translate_off
   integer                        i;
   initial
   begin : init_block
      for (i = 0; i < MEMSIZE; i = i + 1) begin
         RAM[i] = { ((DATA_WIDTH+1)/2) { 2'b10 } };
      end
      DOA_R  = { ((DATA_WIDTH+1)/2) { 2'b10 } };
      DOA_R2 = { ((DATA_WIDTH+1)/2) { 2'b10 } };
      DOB_R  = { ((DATA_WIDTH+1)/2) { 2'b10 } };
      DOB_R2 = { ((DATA_WIDTH+1)/2) { 2'b10 } };
   end
   // synopsys translate_on
`endif // !`ifdef BSV_NO_INITIAL_BLOCKS

   // PORT A
   integer j;
   always @(posedge CLKA) begin
      if (ENA) begin
         for(j = 0; j < WE_WIDTH; j = j + 1) begin: porta_we
            if (WEA[j]) begin
               RAM[ADDRA][j*CHUNKSIZE+:CHUNKSIZE] = `BSV_ASSIGNMENT_DELAY DIA[j*CHUNKSIZE+:CHUNKSIZE];
            end
         end
         DOA_R = `BSV_ASSIGNMENT_DELAY RAM[ADDRA];
      end
   end

   // PORT B
   integer k;
   always @(posedge CLKB) begin
      if (ENB) begin
         for(k = 0; k < WE_WIDTH; k = k + 1) begin: portb_we
            if (WEB[k]) begin
               RAM[ADDRB][k*CHUNKSIZE+:CHUNKSIZE] = `BSV_ASSIGNMENT_DELAY DIB[k*CHUNKSIZE+:CHUNKSIZE];
            end
         end
         DOB_R = `BSV_ASSIGNMENT_DELAY RAM[ADDRB];
      end
   end

   // Output drivers
   always @(posedge CLKA) begin
      DOA_R2 <= `BSV_ASSIGNMENT_DELAY DOA_R;
   end

   always @(posedge CLKB) begin
      DOB_R2 <= `BSV_ASSIGNMENT_DELAY DOB_R;
   end

   assign DOA = (PIPELINED) ? DOA_R2 : DOA_R;
   assign DOB = (PIPELINED) ? DOB_R2 : DOB_R;

endmodule // BRAM2BE

Image

Image

When the DATA_WIDTH is set to 16 and the WE_WIDTH is set to 2, the WE mapping on RAMB18E2 should be 'b11, but the result is only 'b1.
As a consequence, bits[15:8] cannot be written into the memory.
Strangely, when the DATA_WIDTH is set to 24, this problem does not occur.

@ChienTeLi ChienTeLi changed the title Unexpected BRAM2BE synthesis results in Vivado Unexpected BRAM2BE synthesis results in Vivado 2022.2 Apr 9, 2025
@ChienTeLi
Copy link
Author

In the port A/B always blocks, the choice between non-blocking or blocking assignments for RAM and DOA_R/DOB_R signals determines whether the port operates in READ_FIRST mode or WRITE_FIRST mode.

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

No branches or pull requests

1 participant