具有DATA-IN和DATA-OUT的verilog中的可重新配置的存储器实例作为参数传递

问题描述 投票:0回答:1

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

我试过的是根据设计参数生成写指针值,例如DATA-IN 32位,写指针在写入时每个周期递增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
memory verilog fifo hdl vlsi
1个回答
0
投票

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

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
© www.soinside.com 2019 - 2024. All rights reserved.