4

我正在编写一个简单的系统,其中有一个内存模块(带有读写信号的简单 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

 ....

我如何从这里访问内存模块?

4

3 回答 3

2

首先,你的内存名称是“rom”,是只读的。我认为这是一个错字,否则不需要 wr 端口,您可以简单地在客户端中实现单独的 rom,并让合成器优化设计。

对于您的问题,基本上您需要一个仲裁器来处理多个客户端之间的争用。所有客户端都可以假设它们独占内存,但内存由所有客户端共享,不能同时访问。

Tim 对 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 模块中使用真正的仲裁器。我认为循环仲裁器会很好。

最后的评论,如果所有客户端的累积访问速率大于每个周期一次,则无法在硬件中处理。在这种情况下,您将需要以其他方式进行操作。

于 2012-04-12T14:15:13.700 回答
2

回答您的评论时,您不会多次实例化内存。您在层次结构的某个级别创建一个内存实例,然后通过端口/线路将所有消费者连接到它。因此,在顶层,您可能有 3 个要访问内存的模块和 1 个内存模块。三个访问器每个都连接到单个实例,它们不实例化自己的内存。

如果有意义的话,内存应该与其他模块平行,而不是在它们内部。

于 2012-04-11T19:36:16.370 回答
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 的两个实例尝试同时读取/写入,您将需要某种仲裁模块来确认这两个请求,然后一次转发它们时间到内存,并将有效数据返回到适当的模块。

于 2012-04-11T19:59:55.757 回答