cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
jonathanrainer
Visitor
Visitor
1,717 Views
Registered: ‎01-19-2017

How to correctly instantiate XPM memories so that write_mem_info/updatemem produces a correct MMI file?

I'm trying to create a bitfile for a hardware design that includes HDL and Xilinx IP Cores. It includes a softcore processor (Pulpino RI5CY Core) connected to 2 separate BlockRAM Controllers. I'm trying to use XPM (Xilinx Parameterized Macros) to specify the BlockRAMs the processor is connected to so that I can specify their contents without having to constantly re-synthesise my design. I followed the steps as laid out in UG898 (page 173 onwards) however when I try to generate the MMI file I need to complete Step 18. I get the following error message:

The XPM instance: <kuuga_ila_i/inst_bram/inst/xpm_memory_spram_inst/xpm_memory_base_inst> is part of IP: <kuuga_ila_i/inst_bram>. This XPM instance will be excluded from the .mmi because updatemem is prohibited from making changes to an XPM that is part of an IP.

I've tried several methods to alleviate the problem including trying to manually write the MMI file and using the write_mmi TCL script that's included in this AR. But they have both been unsuccessful in generating me the file I need.

My intuition is that the problem is in Step 14 where UG898 talks about: "Complete the definition of the HDL file by adding the appropriate entity and/or module definition". I've tried to do this in the code included below and then added it to my exisiting Block Design by instantiating that code as an RTL Module again as per UG898. But due to the ambiguity of the instructions and my inability to find an example online of someone who has done this I can't find a correct example to study and understand. I can somewhat see what I might need to do in terms of instantiating the XPM another way but I don't know how that would be possible while still connecting everything into my existing Block Design.

Verilog Code for instantiation of XPM (Mostly a copy of the Xilinx Template with module code added around it)

module bram
#(
    READ_DATA_WIDTH_A = 32,
    ADDR_WIDTH_A = 32,
    WRITE_DATA_WIDTH_A = 32
)
(
    output  [READ_DATA_WIDTH_A-1:0]     douta,
    input   [ADDR_WIDTH_A-1:0]          addra,
    input                               clk_a,
    input   [WRITE_DATA_WIDTH_A-1:0]    dina,
    input                               ena,
    input                               regcea,
    input                               rst_a,
    input   [3:0]                       wea
);
    xpm_memory_spram #(
      .ADDR_WIDTH_A(ADDR_WIDTH_A),              // DECIMAL
      .AUTO_SLEEP_TIME(0),           // DECIMAL
      .BYTE_WRITE_WIDTH_A(32),       // DECIMAL
      .ECC_MODE("no_ecc"),           // String
      .MEMORY_INIT_FILE("none"),     // String
      .MEMORY_INIT_PARAM("0"),       // String
      .MEMORY_OPTIMIZATION("true"),  // String
      .MEMORY_PRIMITIVE("auto"),     // String
      .MEMORY_SIZE(65536),            // DECIMAL
      .MESSAGE_CONTROL(0),           // DECIMAL
      .READ_DATA_WIDTH_A(READ_DATA_WIDTH_A),        // DECIMAL
      .READ_LATENCY_A(2),            // DECIMAL
      .READ_RESET_VALUE_A("0"),      // String
      .USE_MEM_INIT(1),              // DECIMAL
      .WAKEUP_TIME("disable_sleep"), // String
      .WRITE_DATA_WIDTH_A(WRITE_DATA_WIDTH_A),       // DECIMAL
      .WRITE_MODE_A("read_first")    // String
   )
   xpm_memory_spram_inst (

  .douta(douta),                   // READ_DATA_WIDTH_A-bit output: Data output for port A read operations.

  .addra(addra),                   // ADDR_WIDTH_A-bit input: Address for port A write and read operations.
  .clka(clk_a),                     // 1-bit input: Clock signal for port A.
  .dina(dina),                     // WRITE_DATA_WIDTH_A-bit input: Data input for port A write operations.
  .ena(ena),                       // 1-bit input: Memory enable signal for port A. Must be high on clock
                                   // cycles when read or write operations are initiated. Pipelined
                                   // internally.

  .regcea(regcea),                 // 1-bit input: Clock Enable for the last register stage on the output
                                   // data path.

  .rsta(rst_a),                     // 1-bit input: Reset signal for the final port A output register stage.
                                   // Synchronously resets output port douta to the value specified by
                                   // parameter READ_RESET_VALUE_A.

  .wea(wea)                        // WRITE_DATA_WIDTH_A-bit input: Write enable vector for port A input
                                   // data port dina. 1 bit wide when word-wide writes are used. In
                                   // byte-wide write configurations, each bit controls the writing one
                                   // byte of dina to address addra. For example, to synchronously write
                                   // only bits [15-8] of dina when WRITE_DATA_WIDTH_A is 32, wea would be
                                   // 4'b0010.

   );

   // End of xpm_memory_spram_inst instantiation

endmodule               

Is following Step 14 my problem or is there a different way to instantiate the XPM that I haven't yet found? Am I going about this the wrong way and I should actually just try and generate the MMI file manually? Any help would be very appreciated.

TL:DR I've tried to use XPM so I can set BlockRAM contents after my bit-file is made but I can't generate the MMI file to do so and it has something to do (I think) with how I've instantiated the XPM.

(A very similar question is posted on Stack Overflow but I wondered if I might get a better response here)

0 Kudos
Reply
2 Replies
jonathanrainer
Visitor
Visitor
1,696 Views
Registered: ‎01-19-2017

So I managed to solve my immediate problem, if you instantiate the XPM instances in the top-level wrapper file for the Block Design and add external ports from the Block Design to pipe the XPM data into the AXI BRAM controller everything proceeds as would be expected and both write_mem_info and updatemem appear to work as designed. If this is the only way for write_mem_info to work should UG898 be updated to reflect this?

I'll not mark the question as complete yet because I'd still like to know if there's a solution that works if you follow UG898 exactly but at least I have a workaround for now.

0 Kudos
Reply
binarybrain
Visitor
Visitor
1,400 Views
Registered: ‎09-17-2018

Wondering if you have any updates to report on this problem/solution? 

Our situation is almost exactly the same as the problem you described.  We are trying to implement an embedded non-Microblaze processor and would like a way to update the bit file when the processor code changes without having to re-build the entire design.   We also tried to generate an mmi file ourselves but so far without success.  Finally we tried embedding the xpm_memory into the top level wrapper file and were also successful in creating an mmi file.  

But placing embedded memories at the top of the hierarchy is hardly an ideal way to design a system.   Ideally we would want to put the memory inside the hierarchy next to the processor that uses the memory.  However this is the message when you try that:

"This XPM instance will be excluded from the .mmi because updatemem is prohibited from making changes to an XPM that is part of an IP."

Followed by an Error code 17-69.

It would be nice if Xilinx would not "prohibit making changes to an XPM that is part of an IP".   Any idea why they do that?

More generally it would be even better if  Xilinx would simply support a write_mem_info command that  could extract all block RAMs into an mmi file.  

0 Kudos
Reply