0

如何制作一个内存模块,其中DATA总线宽度作为参数传递给每个实例,我的设计根据参数重新配置自己?例如,假设我有字节可寻址存储器,DATA-IN总线宽度为 32 位(每个周期写入 4 个字节)并且DATA-OUT为 16 位(每个周期读取 2 个字节)。对于其他实例DATA-IN是 64 位和DATA-OUT16 位。对于所有这些情况,我的设计都应该有效。

我尝试的是根据设计参数生成写指针值,例如DATA-IN32位,写指针在写时每个周期都会增加4。对于 64 位,增量将是 8,依此类推。

问题是:如何根据传递给实例的参数,在单个周期内写入 4 个或 8 个或 16 个字节?

//Something as following I want to implement. This memory instance can be considered as internal memory of FIFO having different datawidth for reading and writing in case you think of an application of such memory

module mem#(parameter DIN=16, parameter DOUT=8, parameter ADDR=4,parameter BYTE=8)
(
  input  [DIN-1:0]  din,
  output [DOUT-1:0] dout,
  input             wen,ren,clk
);

localparam DEPTH = (1<<ADDR);
reg [BYTE-1:0] mem [0:DEPTH-1];
reg wpointer=5'b00000;
reg rpointer=5'b00000;
reg [BYTE-1:0] tmp [0:DIN/BYTE-1];

function [ADDR:0] ptr;
input [4:0] index;
integer i;
  begin
    for(i=0;i<DIN/BYTE;i=i+1)  begin 
      mem[index] = din[(BYTE*(i+1)-1):BYTE*(i)]; // something like this I want to implement, I know this line is not allowed in verilog, but is there any alternative to this?
      index=index+1;
    end
    ptr=index;
  end
endfunction

always @(posedge clk) begin 
  if(wen==1)
    wpointer <= wptr(wpointer);
end

always @(posedge clk) begin
  if(ren==1)
    rpointer <= ptr(rpointer);
end

endmodule
4

1 回答 1

0

din[(BYTE*(i+1)-1):BYTE*(i)]不会在 Verilog 中编译,因为 MSB 和 LSB 选择位都是变量。Verilog 需要一个已知的范围。+:is for part-select(也称为切片)允许变量选择索引和恒定范围值。它是在 IEEE Std 1364-2001 § 4.2.1 中引入的。您还可以在IEEE Std 1800-2012 § 11.5.1 中阅读更多相关信息,或参考之前提出的问题:什么是 `+:` 和 `-:`?索引向量和数组 +:

din[BYTE*i +: BYTE]应该适合你,或者你可以使用din[BYTE*(i+1)-1 -: BYTE].

此外,您应该使用非阻塞赋值 ( <=) 到mem. 在您的代码中,读取和写入可以同时发生。使用阻塞时,在访问相同字节之间存在竞争条件。它可能会综合,但您的 RTL 和门模拟可能会产生不同的结果。我也强烈建议代理使用分配内存的功能。没有令人讨厌的惊喜的可合成代码中的函数需要自我包含,而不需要对函数外部的任何内容进行引用,并且任何内部变量总是在函数开始时重置为静态常量。

根据上面提到的指导方针,我建议重新编码如下。这是一个开始的模板,而不是免费的午餐。我省略了超出范围的指数补偿,让您自己弄清楚。

...
localparam DEPTH = (1<<ADDR);
reg [BYTE-1:0] mem [0:DEPTH-1];
reg [ADDR-1:0] wpointer, rpointer;
integer i;
initial begin // init values for pointers (FPGA, not ASIC)
  wpointer = {ADDR{1'b0}};
  rpointer = {ADDR{1'b0}};
end
always @(posedge clk) begin
  if (ren==1) begin
    for(i=0; i < DOUT/BYTE; i=i+1) begin
        dout[BYTE*i +: BYTE] <= mem[rpointer+i];
    end
    rpointer <= rpointer + (DOUT/BYTE);
  end
  if (wen==1) begin
    for(i=0; i < DIN/BYTE; i=i+1) begin
        mem[wpointer+i] <= din[BYTE*i +: BYTE];
    end
    wpointer <= wpointer + (DIN/BYTE);
  end
end
于 2014-10-13T18:13:37.613 回答