我有一个 Verilog 模块,它从 32 位总线读取数据,一次一个字,并将这些字组合成一个更宽的 reg,作为其他几个模块的输入。输入总线是内存总线,所以每个字都带有一个地址,用于标识我必须将它存储在哪里。
我使用部分选择将单词存储到reg中。因为总线上最低地址的字对应于寄存器中最重要的字,所以我通过翻转地址的位然后附加三个 0 位以将其从字节偏移量转换为有点偏移。
这实际上工作得很好。但是因为我在几个地方使用了“翻转位然后添加三个零”逻辑,所以我决定将它分配给一条线,然后使用该线作为部件选择中的偏移量。但是,当我这样做时,突然它根本不起作用。第一次写入字 0 有效。但是在第二个周期,写入字 1 会覆盖字 0!然后对字 2 的以下写入保存在字 1 中。就好像电线是一个 reg,并且直到下一个周期才看到计算偏移量的结果。这看起来很奇怪,因为我认为电线只是地址总线的线路穿过一些非门;每当地址改变时,偏移量就会改变。
我将问题提炼为以下两个示例。我使用 3 位地址总线和 8 位值只是为了更容易看到发生了什么。谁能解释为什么他们表现出不同的行为?我认为这是由于 Verilog 调度块的方式有些特殊,但我无法解释。显然,我可以只使用工作版本,或者使用数组而不是广泛的 reg,但我认为理解其原因将在未来帮助我。
谢谢!
作品:
module busif(
input clock,
input [2:0] address,
input read,
input write,
input [7:0] data_in,
output reg [7:0] data_out
);
// 8 bytes of memory (3-bit address).
reg [63:0] memory;
always @(posedge clock) begin
if (write) begin
memory[{~address, 3'b000} +: 8] <= data_in;
end
// (read case omitted)
end
endmodule
不起作用(偏移似乎需要 1 个周期才能通过“电线”传播):
module busif(
input clock,
input [2:0] address,
input read,
input write,
input [7:0] data_in,
output reg [7:0] data_out
);
// 8 bytes of memory (3-bit address).
reg [63:0] memory;
wire [5:0] offset;
assign offset = {~address, 3'b000};
always @(posedge clock) begin
if (write) begin
memory[offset +: 8] <= data_in;
end
// (read case omitted)
end
endmodule