Forum Discussion

EugenyB's avatar
EugenyB
Icon for Occasional Contributor rankOccasional Contributor
4 years ago

Quartus joins two RAMs?

In my design I deliberately designed two dual-port RAMs of single M9K block each, using them through both ports A and B in parallel.

I spent several days debugging the application I am designing failing in very strange way. Simulation and data captured from live system does not help to find the problem.

I started to dig into the deeps of Quartus reports (mostly out of desperation), and found that in fitter's RAM summary tab the location for both RAMs is the same (M9K_X15_Y19_N0) and that "Resource utilization per entity" list shows that one RAM is having 1 M9K assigned to it, and second does not!

Does it mean that Quartus "optimized" the design compacting two explicit memories into one physical memory?

This is technically fairly possible because I only use halves of these RAMs. However I can not understand how it can be done from interfacing point of view because I use ALL interfaces of both RAMs - are they time shared when combined?

How can I tell Quartus NOT to do it and leave separate M9K memories alone as they are designed?

11 Replies

  • sstrell's avatar
    sstrell
    Icon for Super Contributor rankSuper Contributor

    Did you add the RAMs through code inference or by adding them as IP through the IP Catalog? If it was code inference, that might be the issue. If you show your code, that could help diagnose the problem.

    Also, if you are using code inference, check out the templates in the Quartus text editor (Edit menu -> Insert Template) to make sure you are following the coding guidelines to have your design synthesized the way you intend.

    • EugenyB's avatar
      EugenyB
      Icon for Occasional Contributor rankOccasional Contributor

      Hello, thank you for your reply.

      I used MegaWizard.

      Code as simple as this:

      reg [8:0] r_fir_RAM_address = {9{1'b0}};
      wire [15:0] w_fir_RAM_data_out_lo;
      wire [15:0] w_fir_RAM_data_out_hi;
      reg [15:0] r_fir_RAM_data_in_lo = {16{1'b0}};
      reg [15:0] r_fir_RAM_data_in_hi = {16{1'b0}};
      reg r_fir_RAM_we = 1'b0;
      fir_ram_lo fir_ram_lo (
      .clock(FFCLK), 
      // address - same for both channels, even/odd
      .address_a( { r_fir_RAM_address[8:0], 1'b0 } ),// even byte
      .address_b( { r_fir_RAM_address[8:0], 1'b1 } ),// odd byte
      // write enable
      .wren_a(r_fir_RAM_we),
      .wren_b(r_fir_RAM_we),
      // indata
      .data_a(r_fir_RAM_data_in_lo[7:0]),
      .data_b(r_fir_RAM_data_in_lo[15:8]),
      // outdata
      .q_a(w_fir_RAM_data_out_lo[7:0]),
      .q_b(w_fir_RAM_data_out_lo[15:8])
      );
      fir_ram_hi fir_ram_hi (
      .clock(FFCLK),
      // address - same for both channels, even/odd
      .address_a( { r_fir_RAM_address[8:0], 1'b0 } ),// even byte
      .address_b( { r_fir_RAM_address[8:0], 1'b1 } ),// odd byte
      // write enable
      .wren_a(r_fir_RAM_we),
      .wren_b(r_fir_RAM_we),
      // indata
      .data_a(r_fir_RAM_data_in_hi[7:0]),
      .data_b(r_fir_RAM_data_in_hi[15:8]),
      // outdata
      .q_a(w_fir_RAM_data_out_hi[7:0]),
      .q_b(w_fir_RAM_data_out_hi[15:8])
      );
      and then I set up common address and read 4 bytes in parallel into registers, or write 4 bytes in parallel to all RAMs. Address is really set up the way that its MSb is always zero, so Quartus knows that I do not use half of RAMs. Both RAMs are pre-initialized with their own data.
      • EugenyB's avatar
        EugenyB
        Icon for Occasional Contributor rankOccasional Contributor

        There seem to be a weak workaround (if it is a valid workaround at all) distributing the data across the whole M9K block. But there's a risk that at some stage Quartus (or its other version) identifies that design does not use specific addresses in the space, and pack everything as it wants and as it was not designed by the developer, causing problems and penalties in performance.

        Thus I need explicit command/instruction for Quartus for NOT doing any RAM space optimizations, and leave M9K block and connections to it as designed in the project.

        I am still not sure from previous replies if what I see is Quartus behavior as it was designed. I can not find any related information, articles, datasheets or whitepapers on the subject. The mechanism of this "optimization" is unclear as from my perspective it is, with current M9K block usage, simply impossible without any tricks or undocumented features.

        Update: looked through, and played with all the options available in the "setting" section (compilation and fitting), which look like may affect the problem. No change. Nothing suitable in the "device" menus.

  • SyafieqS's avatar
    SyafieqS
    Icon for Super Contributor rankSuper Contributor

    Hi Eugeny,


    1. May I know what device you are targeting and Quartus version used?

    2. I can see the code snippet provided, could you try to provide a design and achieve it here .qar. I will try to reproduce it at my end. You can email or private message me if it is confidential.


    Thanks,

    Regards


    • EugenyB's avatar
      EugenyB
      Icon for Occasional Contributor rankOccasional Contributor

      Hello, I am using Cyclone 3, Quartus versions tried are 12.0 SP2 and 13.0 SP1.

      As a starting point I have put the definition of RAMs in one of my replies above, and briefly said how I used them. Putting code here is not appropriate as it is relatively big. The data being addressed through the address wires are in the first part of RAM, address MSb is always 0.

      How can I send you a private message? Suspect that when I click your anonymous icon I must see something useful, but there's only progress indicator rotating.

      Is your email address "SyafieqS_Intel@intel.com"? Who I am talking to?

  • SyafieqS's avatar
    SyafieqS
    Icon for Super Contributor rankSuper Contributor

    Hi Eugeny,


    Noted and glad to hear the issue had been addressed. Let me know if you have any other concern on this.