我正在尝试在verilog的ARM CPU中实现寄存器文件。我对verilog很新,所以我遇到了麻烦。
我想让寄存器文件保存在它的第15个寄存器中,值为PC + 8,在寄存器号0中保存值为0,这样寄存器文件能够在输入其中一个时给PC + 8作为输出。读寄存器是15,依此类推。
目前,我已经编写了这样的代码
reg[31:0] register[15:0];
initial
begin
register[15] = register15;//register15 is the input holding PC+8 as it's value
register[0] = 32'h00000000;
end
always @(posedge clk)
begin
outreg1 <= register[A1];// outreg1,2 are outputs (values of register A1, A2)
outreg2 <= register[A2];
end
但是,当发生“寄存器读取”时,我想让它完全发生在clk的构造中。但是,如果我这样做,我是否必须在@(posedge clk)中使用阻塞赋值'='使所有语句按顺序排列并首先分配15和0?
我对阻塞和解除阻塞任务的理解不是很清楚,所以我不确定这是否有效。
因此,这似乎是尝试将输入值'register0,... register15'重新映射到一组'outreg1 ...',使用'A1 ...'作为地图操纵器。
在这种情况下,您不能使用initial
块。初始块在模拟开始时仅运行一次,不能对输入变化做出反应。它们也不是可合成的。既然你说'registerN'也是输入,你最好创建2个不同的always_blocks;
reg[31:0] register[15:0];
always @*
begin
register[15] = register15;//register15 is the input holding PC+8 as it's value
register[0] = 32'h00000000;
end
always @(posedge clk)
begin
outreg1 <= register[A1];// outreg1,2 are outputs (values of register A1, A2)
outreg2 <= register[A2];
end
阻塞和非阻塞分配之间的区别在于,对于非阻塞分配,在对设计中的所有此类块进行所有此类块的评估之后,将在稍后将实际值分配给变量。这使得仿真在触发器和锁存器方面更像硬件。即如果你有一个翻牌圈A
在同一个'posedge clk'中输入另一个翻牌圈B
,翻牌圈B
将会抓住A
的输出,因为它存在于posedge之前。这是硬件的行为方式。对于阻塞分配,在这种情况下,模拟的结果将是不可预测的,这取决于模拟器实现。
因此,经验法则是对代表锁存器和触发器的always
块的所有“输出”使用非阻塞分配。其他一切都必须阻止。这意味着如果需要,翻转/锁存块可以对中间变量使用阻塞,但最好避免使用。