I am writing a simple system in which there is a memory module (simple reg with a read and write signals). Now this memory has to be accessed by several other modules (not simultaneously). So I create an instance of this memory and feed data to it. But I can't figure out how will my other modules access the same instance of the memory module. Any help?
Edit
Let me clarify a bit by some code. This is my memory module, simple signals.
module rom(
input [15:0] addr,
input [15:0] data_in,
input rd,
input wr,
input cs,
output reg [15:0] data_out
);
reg [15:0] mem[255:0];
integer k;
initial begin
for(k = 0;k<256;k=k+2)
mem[k] = 16'h0011;
for(k = 1;k<256;k=k+2)
mem[k] = 16'h0101;
end
always @(cs)begin
if(wr)
mem[addr] <= data_in;
if(rd)
data_out <= mem[addr];
end
endmodule
This will be instantiated in my top module, something like this
module Top;
// Inputs
reg [15:0] addr;
reg [15:0] data_in;
reg rd;
reg wr;
reg cs;
// Outputs
wire [15:0] data_out;
// Instantiate the Unit Under Test (UUT)
rom uut (
.addr(addr),
.data_in(data_in),
.rd(rd),
.wr(wr),
.cs(cs),
.data_out(data_out)
);
....
....
....
endmodule
Now this top module will also contain some other modules which would want to connect to memory. I don't really understand how I would connect them. Suppose there is one module like this
module IF_stage(
input clk,
input rst,
output reg [15:0] pc,
output [15:0] instruction
);
//pc control
always@(posedge clk or posedge rst)
begin
if(rst)
pc <= 16'hFFFF;
else
pc <= pc+1;
end
....
How would I access the memory module from here?
You need to modify IF_stage to add an interface that can communicate with the memory, something like this:
module IF_stage(
input clk,
input rst,
input [15:0] read_data_from_memory, //new
input read_data_from_memory_valid, //new
output reg [15:0] pc,
output [15:0] instruction
output do_memory_write //new
output do_memory_read //new
output [15:0] memory_write_data //new
output [15:0] addr //new
);
Then when an IF_stage wants to read or write memory, it puts addr/data on it's output port to issue command to the memory module, and then waits for read_data_from_memory(_valid) to be asserted on it's input port. These outputs and inputs get connected to the memory module at the top level.
You'll also have to deal with bus contention here, for instance if two instances of IF_stage try to read/write at the same time, you'll need some kind of arbiter module to acknowledge both requests, and then forward them one at a time to the memory, and return the valid data to the proper module.
Answering your comment, you don't instance the memory more than once. You create one instance of the memory at some level of the hierarchy, and then connect all the consumers to it via ports/wires. So in the top level you might have 3 modules that want to access memory, and 1 memory module. The three accessors each connect to the single instance, they don't instance their own memory.
The memory should be parallel to the other modules, not inside of them, if that makes sense.
First of all, the name of your memory is "rom", which is read only. I assume it is a typo, otherwise there is no need to have wr port and you can simply implement separate roms in clients and let synthesizer to optimize the design.
For your question, basically you need an arbiter to handle the contention between multiple clients. All clients can assume they occupy the memory exclusively but the memory is shared by all clients and cannot be accessed simultaneously.
Tim is right about the IF_stage. Every client must have a separate memory interface
output [15:0] addr;
output [15:0] data_out;
input [15:0] data_in;
output wr, rd, cs;
input rdy; // only when rdy == 1, the memory operation is finished
You will need a memory controller/arbiter, which behaves as a memory to all clients but actually handle the contention among clients. Assuming there are three clients and all clients access the memory less than once per three cycles, you can simply have something as follow:
module mem_ctl(
addr_c1, dw_c1, dr_c1, wr_c1, rd_c1, cs_c1,
addr_c2, dw_c2, dr_c2, wr_c2, rd_c2, cs_c2,
addr_c3, dw_c3, dr_c3, wr_c3, rd_c3, cs_c3,
addr_m, dw_m, dr_m, wr_m, rd_m, cs_m,
rdy_c1, rdy_c2, rdy_c3,
rst_n, clk
);
input clk, rst_n;
input [15:0] addr_c1, addr_c2, addr_c3, dw_c1, dw_c2, dw_c3; // addr and data_write from clients
output [15:0] dr_c1, dr_c2, dr_c3; // data read from clients
input wr_c1, wr_c2, wr_c3, rd_c1, rd_c2, rd_c3, cs_c1, cs_c2, cs_c3; // control from clients
output [15:0] addr_m, dw_m; // addr and data write to memory
input [15:0] dr_m;
output wr_m, rd_m, cs_m; // control the memory
output rdy_c1, rdy_c2, rdy_c3;
reg [15:0] dr_c1, dr_c2, dr_c3, dw_m, addr_m;
reg wr_m, rd_m, cs_m;
reg [1:0] cnt;
always @(posedge clk or negedge rst_n)
if (~rst_n)
cnt <= 0;
else if(cnt == 2'd2)
cnt <= 0;
else
cnt <= cnt + 1;
always @(*) // Verilog 2001, if not recognizable, fill in yourself
begin
case(cnt)
0: begin
dw_m = dw_c1;
wr_m = wr_c1;
cs_m = cs_c1;
rd_m = rd_c1;
dr_c1 = dr_m;
end
1: begin
dw_m = dw_c2;
wr_m = wr_c2;
cs_m = cs_c2;
rd_m = rd_c2;
dr_c2 = dr_m;
end
default: begin
dw_m = dw_c3;
wr_m = wr_c3;
cs_m = cs_c3;
rd_m = rd_c3;
dr_c3 = dr_m;
end
endcase
end
assign rdy_c1 = (cnt == 0) & cs_c1;
assign rdy_c2 = (cnt == 1) & cs_c2;
assign rdy_c3 = (cnt == 2) & cs_c3;
endmodule
However, this is only OK when the access rates of all clients are lower than once per three cycles. If the access rate is variant and higher than that, you will need a real arbiter in the mem_ctl module. I think a round-robin arbiter will be fine.
The final comment, if the accumulative access rates of all clients is larger than once per cycle, it is impossible to handle in hardware. In that case, you will need to do it in other ways.