cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Highlighted
Contributor
Contributor
228 Views
Registered: ‎04-25-2019

Multichannel BRAM in Vivado IP Packager

Hi, 

I have had great success using the Vivado design flow from start (designing IP in Verilog) to finish (deployed and running in the real world). I am now looking to investigate improvements to my signal processing system and this requires me to instantiate a variable number of BRAM Ports, depending on the number of channels I want in my own custom IP. This could be up to 12, so I want to avoid a manual copy and paste approach. I have implemented this in code using genvar and it appears to be recognising and instantiating BRAM Port instances correctly, according to value of my CHANNELS parameter (please see code below): 

#(parameter integer CHANNELS = 2)(
// #################### BRAM 0 ##########################
// BRAM PORT A
output wire bram_porta_clk,
output wire bram_porta_rst,
output wire [BRAM_ADDR_WIDTH-1:0] bram_porta_addr,
output wire [BRAM_DATA_WIDTH-1:0] bram_porta_wrdata,
input wire [BRAM_DATA_WIDTH-1:0] bram_porta_rddata,
output wire bram_porta_we,
// BRAM PORT B
output wire bram_portb_clk,
output wire bram_portb_rst,
output wire [BRAM_ADDR_WIDTH-1:0] bram_portb_addr,
output wire [BRAM_DATA_WIDTH-1:0] bram_portb_wrdata,
input wire [BRAM_DATA_WIDTH-1:0] bram_portb_rddata,
output wire bram_portb_we
); // ################### END of BRAM 0 ######################

// ############ Instantiate N Channel BRAMs ############### genvar i; generate for(i=0; i<CHANNELS; i=i+1) begin : gen_UUT1 bram_ports #( .BRAM_DATA_WIDTH(BRAM_DATA_WIDTH), .BRAM_ADDR_WIDTH(BRAM_ADDR_WIDTH) ) UUT1 ( // BRAM PORT A .bram_porta_clk(bram_porta_clk), .bram_porta_rst(bram_porta_rst), .bram_porta_addr(bram_porta_addr), .bram_porta_wrdata(bram_porta_wrdata), .bram_porta_rddata(bram_porta_rddata), .bram_porta_we(bram_porta_we), // BRAM PORT B .bram_portb_clk(bram_portb_clk), .bram_portb_rst(bram_portb_rst), .bram_portb_addr(bram_portb_addr), .bram_portb_wrdata(bram_portb_wrdata), .bram_portb_rddata(bram_portb_rddata), .bram_portb_we(bram_portb_we) ); end : gen_UUT1 endgenerate

First of all, I know that the code above is not scalable to N Channels as I don't know how I would specifically address X Channel in my code. So my first question is what would be the appropriate syntax? (my logic tells me the below but that doesn't work)

UUT1[0].bram_porta_addr = {(BRAM_ADDR_WIDTH){1'b0}}; 

Secondly, how would this be set in the Vivado IP Packager GUI? Would I have to assign up to 12 BRAM ports manually and then set a dependency condition for each one or is there some smart way of doing this. From the Vivado blocks I know that AXI Interconnect can potentially have a large number of output ports, surely this was coded/setup programmatically?

Edit: this answer record helped me solve my 2nd question. https://www.xilinx.com/support/answers/61620.html

I am also open to alternative approaches, since it is my first time doing this. 

Thank you for your time. 

Best Regards, Ren

0 Kudos
1 Reply
Highlighted
Contributor
Contributor
176 Views
Registered: ‎04-25-2019

Update: 

I have read this article which instructs how to create an interface array using System Verilog: https://stackoverflow.com/questions/42484688/systemverilog-interface-array-with-different-parameters I have since updated my top to SV and modified my code shown below: 

interface itf #(
  parameter integer BRAM_DATA_WIDTH = 64,
  parameter integer BRAM_ADDR_WIDTH = 16
)
(
  // PORT A
  output logic                        bram_porta_clk,
  output logic                        bram_porta_rst,
  output logic  [BRAM_ADDR_WIDTH-1:0] bram_porta_addr,
  output logic  [BRAM_DATA_WIDTH-1:0] bram_porta_wrdata,
  input logic   [BRAM_DATA_WIDTH-1:0] bram_porta_rddata,
  output logic                        bram_porta_we,
  // PORT B 
  output logic                        bram_portb_clk,
  output logic                        bram_portb_rst,
  output logic  [BRAM_ADDR_WIDTH-1:0] bram_portb_addr,
  output logic  [BRAM_DATA_WIDTH-1:0] bram_portb_wrdata,
  input logic   [BRAM_DATA_WIDTH-1:0] bram_portb_rddata,
  output logic                        bram_portb_we
);

assign bram_portb_we = 1'b0;
assign bram_portb_wrdata = {(BRAM_DATA_WIDTH){1'b0}};

endinterface 

// ************** Multiple Interfaces ********************
interface itfa #(
  parameter integer BRAM_DATA_WIDTH = 64,
  parameter integer BRAM_ADDR_WIDTH = 16,
  parameter integer CHANNELS = 3
)
(
  // PORT A 
  output logic                        bram_porta_clk,
  output logic                        bram_porta_rst,
  output logic  [BRAM_ADDR_WIDTH-1:0] bram_porta_addr,
  output logic  [BRAM_DATA_WIDTH-1:0] bram_porta_wrdata,
  input logic   [BRAM_DATA_WIDTH-1:0] bram_porta_rddata,
  output logic                        bram_porta_we,
  // PORT B 
  output logic                        bram_portb_clk,
  output logic                        bram_portb_rst,
  output logic  [BRAM_ADDR_WIDTH-1:0] bram_portb_addr,
  output logic  [BRAM_DATA_WIDTH-1:0] bram_portb_wrdata,
  input logic   [BRAM_DATA_WIDTH-1:0] bram_portb_rddata,
  output logic                        bram_portb_we
);
  generate
    genvar i;
    for (i = 0; i < CHANNELS-1; i++)
    begin : interfaces
      itf #(.BRAM_DATA_WIDTH(BRAM_DATA_WIDTH),
            .BRAM_ADDR_WIDTH(BRAM_ADDR_WIDTH)            
            )
      itf_inst (
        // Port A
        .bram_porta_clk(bram_porta_clk),        .bram_porta_rst(bram_porta_rst),
        .bram_porta_addr(bram_porta_addr),      .bram_porta_wrdata(bram_porta_wrdata),
        .bram_porta_rddata(bram_porta_rddata),  .bram_porta_we(bram_porta_we),
        // Port B
        .bram_portb_clk(bram_portb_clk),        .bram_portb_rst(bram_portb_rst),
        .bram_portb_addr(bram_portb_addr),      .bram_portb_wrdata(bram_portb_wrdata),
        .bram_portb_rddata(bram_portb_rddata),  .bram_portb_we(bram_portb_we)
      );
    end
  endgenerate
endinterface

module top #(
    parameter integer AXIS_TDATA_WIDTH = 64,
    parameter integer BRAM_DATA_WIDTH = 64,
    parameter integer BRAM_ADDR_WIDTH = 16,
    parameter integer CHANNELS = 3  
  )
  ( // BRAM Cycle Interface  
    itfa                               itfs
);
endmodule : top

It can successfully infer one instance of 'itfs' in the Ports and Interfaces window, is there some further configuration or syntax which I need to implement in order to get this working ?

I would really like to know otherwise I will have to implement some complex variable BRAM memory logic. I also forgot to mention that I do indeed require separate instances of BRAMs since I need to implement a sliding window in each one. 

It also appears that this 'array of interfaces' functionality was added to Vivado recently as of 2019 according to: https://forums.xilinx.com/t5/Simulation-and-Verification/Arrays-of-Interfaces/td-p/801616

Any help would be greatly appreciated. 

Best Regards, Ren 

bram_ip_packager.PNG
0 Kudos