2012-04-11 125 views
4

我正在写一个简单的系统,其中有一个内存模块(带有读写信号的简单寄存器)。现在这个内存必须被其他几个模块访问(不是同时)。所以我创建了这个内存的一个实例并向它提供数据。但我不知道我的其他模块将如何访问内存模块的相同实例。任何帮助?从其他几个模块内部访问一个模块的实例? (verilog)

编辑

让我通过一些代码澄清一下。这是我的记忆模块,简单的信号。

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 
    [email protected](posedge clk or posedge rst) 
    begin 
     if(rst) 
      pc <= 16'hFFFF; 
     else 
      pc <= pc+1; 
    end 

.... 

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

+2

“访问模块”是什么意思?你只需要像其他任何东西一样连接电线。你能否再描述一下层次结构,并解释为什么你不能通过端口/电线连接模块? – Tim 2012-04-11 19:14:41

+0

@Tim我无法通过电线连接它们(据我所知)。内存模块是一个,所有其他模块都希望从中访问数据。所以如果我在任何其他模块中创建一个实例,它将是一个不同的实例。你如何建议我通过电线连接它们? – 2012-04-11 19:24:41

回答

1

回答您的评论,你不会多次实例化内存。您在层次结构的某个级别创建一个内存实例,然后通过端口/线路将所有使用者连接到它。所以在顶层你可能有3个模块需要访问内存,1个内存模块。三个访问器分别连接到单个实例,但它们没有实例化自己的内存。

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

+0

查看新代码添加到问题中,也许这会澄清我的问题 – 2012-04-11 19:51:14

2

您需要修改IF_stage增加一个接口,可以与内存沟通,是这样的:当一个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 

); 

然后,它把地址/数据上它的输出端口向内存模块发出命令,然后等待在其输入端口上声明read_data_from_memory(_valid)。这些输出和输入连接到顶层的内存模块。

您还需要在这里处理总线争用,例如,如果IF_stage的两个实例试图同时读/写,则需要某种仲裁器模块来确认这两个请求,然后转发它们一次一个地存储到内存中,并将有效数据返回到适当的模块。

1

首先,你的记忆名称是“rom”,它是只读的。我认为这是一个错字,否则就没有必要使用wr port,你可以简单地在客户端实现单独的ROM,并让合成器优化设计。

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

蒂姆是正确的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 

您将需要一个内存控制器/仲裁者,其表现为内存的所有客户端,但实际处理客户之间的争用。假设有三个客户和所有客户端访问的内存比每3个周期,一旦少,你可以简单地有东西如下:

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

最后的评论,如果所有客户端的累计访问速率大于每个周期一次,则不可能在硬件上处理。在这种情况下,您需要以其他方式来完成。