从几个其他模块内部访问一个模块的实例? (Verilog的)

时间:2012-04-11 18:59:32

标签: verilog

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

 ....

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

3 个答案:

答案 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模块中需要一个真正的仲裁器。我认为循环仲裁者会没事的。

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