Electrical – how to access the same RAM module from different modules

ramverilog

I have a cyclone v gx starter kit. It comes with 4884 bits onchip memory.
I want to write a module for accessing the onchip memory.
So, I have generated the ram ip reference design from ip catalog like this:

module onchipmem (
    aclr,
    address,
    clken,
    clock,
    data,
    rden,
    wren,
    q);

    input     aclr;
    input   [7:0]  address;
    input     clken;
    input     clock;
    input   [15:0]  data;
    input     rden;
    input     wren;
    output  [15:0]  q;
`ifndef ALTERA_RESERVED_QIS
// synopsys translate_off
`endif
    tri0      aclr;
    tri1      clken;
    tri1      clock;
    tri1      rden;
`ifndef ALTERA_RESERVED_QIS
// synopsys translate_on
`endif
wire [15:0] sub_wire0;
wire [15:0] q = sub_wire0[15:0];

altsyncram  altsyncram_component (
          ...
          );

I can write / read data by creating an instance of this module:

onchipmem write_mem (
    .aclr(reset),
    .address(address),
    .clken(ce),
    .clock(clk),
    .data(data),
    .rden(1'b0),
    .wren(1'b1),
    .q()
    );

I want to save data by onchipmem in one module and read data from the same instance of onchipmem from another module. However, creating multiple instances of onchipmem will allocate duplicated block of RAM per instance.

In other words, a single RAM module cannot be called by multiple modules.
So how to implement a share RAM module for multiple modules to access?

I found this answer and suggested to use arbiter. He provided some sample codes of an arbiter but it is not completed.

I am new to fpga and cannot get how it works.

So I am looking for a real and completed example so that I can learn and test it in modelsim.

Please advise.

Best Answer

An Arbiter is the general way of doing it.

An Arbiter is esentially a block that is connected to your RAM and reads/writes data from/to the RAM.

The arbiter exports interfaces (can be an arbitrary count) to other modules. Through these interfaces modules can access the RAM via the arbiter. The arbiter internally handles the request from its input. There are several ways of handling requests:

  • The different modules have different priorities.
  • The requests are processed in a round-robin-loop
  • etc.

The specific implementation highly depends on the interface used. The inferface from the arbiter to the RAM is given by the RAM module you use. However these interface standards are mostly not usable for the input ports of an arbiter as they are not able to handle variable timings. If a module wants to write to the RAM but another is given access at the moment the arbiter has to stall the interface until it can process the request.

On Altera systems the AvalonMM bus is a common way and compatible with many Altera IP cores. But you could also go with Wishbone or a custom bus.

I don't have a complete example because it highly depends on your requirements. However, a simple arbiter is a nice project for learning.


Another quick way to connect two modules to a RAM is generating a dual port RAM with the Altera Wizard. This RAM has 2 independly usable RAM ports.