Xilinx 中的 Verilog 异步内存

Verilog asynch mem in Xilinx

我正在尝试在 verilog 中创建内存移位操作,并且想知道执行此操作的最佳方法。示例代码是:

reg [MSB:0] a [0:NO_OF_LOCATIONS];
// after some processing
for(i =0; i <= NO_OF_LOCATIONS; i= i+1)
  a[i] = a[i+1]

如果我在 Xilinx 中使用 ROM,它只能进行同步写入,我需要在一个时钟周期内完成所有移位。如果我确实使用上述内存,我不确定板载实现是否会导致亚稳态或不关心传播。

还有什么是代替 for 循环的最佳方法?

我假设这是时钟同步块的一部分,即类似下面的内容(否则它没有多大意义,你写了 "I need to do all the shifts within one clock cycle",这意味着这是同步设计的一部分) :

reg [MSB:0] a [0:NO_OF_LOCATIONS];

always @(posedge clk)
  if (...) begin
    for(i =0; i < NO_OF_LOCATIONS; i= i+1)
      a[i] <= a[i+1];
    a[NO_OF_LOCATIONS] <= ...;
  end

// also use a[] somewhere
assign a0 = a[0];

顺便说一句:a[] 中有 NO_OF_LOCATIONS+1 个位置。我不确定这是否有意,但我只是那样离开了。通常 a[] 的范围对于 NO_OF_LOCATIONS 个内存位置将写为 [0:NO_OF_LOCATIONS-1]

请注意,我已将分配 = 更改为 <=。当在时钟始终块中分配某些内容并且您分配的内容在该始终块之外的任何地方被读取时,您必须分配非阻塞(即使用 <=)以避免模拟中可能导致的竞争条件模拟-综合不匹配。

另请注意,我已分解出对 a[NO_OF_LOCATIONS] 的赋值,因为它会从 a[NO_OF_LOCATIONS+1] 中获取其值,这是越界的,因此始终为 undef。如果没有这种改变,综合工具会正确地假设 a[] 的所有元素都是常量 undef,并且会简单地用常量 'bx.

替换该数组上的所有读取。

这是完美的代码。我不确定你为什么提出亚稳态,但只要 ... 表达式与 clk 同步,该电路中就没有亚稳态。但它并没有真正模拟记忆。好吧,确实如此,但是一个具有 NO_OF_LOCATIONS 个写入端口和 NO_OF_LOCATIONS 个读取端口(仅计算该 for 循环推断的读取端口)。即使你有这样的内存:这样使用它会非常低效,因为内存端口的昂贵之处在于它能够寻址任何内存位置,但本例中的所有端口都有一个常量内存地址(i 在展开 for 循环后保持不变)。因此,大量的读写端口将迫使综合工具将该内存实现为一堆单独的寄存器。但是,如果您的目标架构具有专用的移位寄存器资源(例如许多 fpgas),那么这可能会转换为移位寄存器。

对于较大的 NO_OF_LOCATIONS 值,您可以考虑使用游标将 fifo 实现到内存中,而不是将整个内存的内容从一个元素转移到下一个元素。这只会从 for 循环内部推断出一个写入端口而没有读取端口。例如:

reg [MSB:0] a [0:NO_OF_LOCATIONS];

parameter CURSOR_WIDTH = $clog2(NO_OF_LOCATIONS+1);
reg [CURSOR_WIDTH-1:0] cursor = 0;

always @(posedge clk)
  if (...) begin
    a[cursor] <= ...;
    cursor <= cursor == NO_OF_LOCATIONS ? 0 : cursor+1;
  end

assign a0 = a[cursor];