我正在编写一个简单的系统,其中有一个内存模块(带有读写信号的简单reg)。现在,这个内存必须由其他几个模块访问(不是同时)。所以我创建了这个内存的实例并将数据提供给它。但我无法弄清楚我的其他模块将如何访问内存模块的同一个实例。有什么帮助吗?
修改
让我通过一些代码澄清一下。这是我的记忆模块,简单的信号。
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
这将在我的顶级模块中实例化,类似这样
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
现在这个顶级模块还将包含一些其他想要连接到内存的模块。我真的不明白我将如何连接它们。假设有一个像这样的模块
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
....
我如何从这里访问内存模块?
答案 0 :(得分:2)
您需要修改IF_stage以添加可与内存通信的接口,如下所示:
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
);
然后,当IF_stage想要读取或写入内存时,它会在其输出端口上放置addr / data以向内存模块发出命令,然后等待read_data_from_memory(_valid)在其输入端口上声明。这些输出和输入连接到顶层的存储器模块。
你还必须在这里处理总线争用,例如,如果两个IF_stage实例同时尝试读/写,你需要某种仲裁模块来确认这两个请求,然后转发它们一次一个到内存,并将有效数据返回到适当的模块。
答案 1 :(得分:1)
回答您的评论,您不必多次实例化内存。您可以在层次结构的某个级别创建一个内存实例,然后通过端口/连接将所有使用者连接到它。所以在顶层你可能有3个想要访问内存的模块和1个内存模块。这三个访问器都连接到单个实例,它们不会实例化自己的内存。
如果有意义,内存应该与其他模块并行,而不是在其中。
答案 2 :(得分:1)
首先,你的记忆名称是“rom”,这是只读的。我认为这是一个错字,否则就没有必要使用wr端口,你可以在客户端中简单地实现单独的roms,让合成器优化设计。
对于您的问题,基本上您需要一个仲裁器来处理多个客户端之间的争用。所有客户端都可以假设它们只占用内存,但内存由所有客户端共享,无法同时访问。
蒂姆对IF_stage是正确的。每个客户端都必须有一个单独的内存接口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
您将需要一个内存控制器/仲裁器,它作为所有客户端的内存,但实际上处理客户端之间的争用。假设有三个客户端,并且所有客户端每三个周期访问内存不到一次,您可以简单地得到以下内容:
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
但是,只有当所有客户端的访问速率低于每三个周期一次时,才可以。如果访问速率是变量且高于该值,则在mem_ctl模块中需要一个真正的仲裁器。我认为循环仲裁者会没事的。
最后评论,如果所有客户端的累积访问速率大于每个周期一次,则无法在硬件中处理。在这种情况下,您需要以其他方式进行。