将第一个寄存器分配给零并且不写
Assign first register to zero and do not write
我是 Verilog 的新手,正在尝试创建一个包含 32 位寄存器的寄存器文件。我能够正确地写入和读取所有内容,但是,位于地址 5'b00000 的第一个寄存器(我们将其命名为 R0)必须始终等于 0,并且在任何时候都不能更改。在测试台上读取时,当 R0 突然变成 "xxxxxxxx" 而不是 0 或 00000000 时,问题就出现了。其余寄存器读取正确。我在代码中可能做错了什么,解决这个问题的方法是什么?下面是代码:
module regfile (
clk,
nrst,
rd_addrA,
rd_addrB,
wr_addr,
wr_en,
wr_data,
rd_dataA,
rd_dataB
);
//Input and output ports
input wire clk;
input wire nrst;
input wire [4:0] rd_addrA;
input wire [4:0] rd_addrB;
input wire [4:0] wr_addr;
input wire wr_en;
input wire [31:0] wr_data;
output reg [31:0] rd_dataA;
output reg [31:0] rd_dataB;
reg [31:0] regfile[0:31];
integer i;
always @ (nrst)
begin: RESET
if(nrst == 0) begin
for(i = 0; i < 32; i++) begin
regfile[i] = 0;
end
end
end
always @(rd_addrA or rd_addrB)
begin: READ
if(rd_addrA) begin
case (rd_addrA)
5'b00000: rd_dataA = regfile[0];
5'b00001: rd_dataA = regfile[1];
5'b00010: rd_dataA = regfile[2];
5'b00011: rd_dataA = regfile[3];
5'b00100: rd_dataA = regfile[4];
5'b00101: rd_dataA = regfile[5];
5'b00110: rd_dataA = regfile[6];
5'b00111: rd_dataA = regfile[7];
5'b01000: rd_dataA = regfile[8];
5'b01001: rd_dataA = regfile[9];
5'b01010: rd_dataA = regfile[10];
5'b01011: rd_dataA = regfile[11];
5'b01100: rd_dataA = regfile[12];
5'b01101: rd_dataA = regfile[13];
5'b01110: rd_dataA = regfile[14];
5'b01111: rd_dataA = regfile[15];
5'b10000: rd_dataA = regfile[16];
5'b10001: rd_dataA = regfile[17];
5'b10010: rd_dataA = regfile[18];
5'b10011: rd_dataA = regfile[19];
5'b10100: rd_dataA = regfile[20];
5'b10101: rd_dataA = regfile[21];
5'b10110: rd_dataA = regfile[22];
5'b10111: rd_dataA = regfile[23];
5'b11000: rd_dataA = regfile[24];
5'b11001: rd_dataA = regfile[25];
5'b11010: rd_dataA = regfile[26];
5'b11011: rd_dataA = regfile[27];
5'b11100: rd_dataA = regfile[28];
5'b11101: rd_dataA = regfile[29];
5'b11110: rd_dataA = regfile[30];
5'b11111: rd_dataA = regfile[31];
default: rd_dataA = 16'hXXXX;
endcase
end
if(rd_addrB) begin
case (rd_addrB)
5'b00000: rd_dataB = regfile[0];
5'b00001: rd_dataB = regfile[1];
5'b00010: rd_dataB = regfile[2];
5'b00011: rd_dataB = regfile[3];
5'b00100: rd_dataB = regfile[4];
5'b00101: rd_dataB = regfile[5];
5'b00110: rd_dataB = regfile[6];
5'b00111: rd_dataB = regfile[7];
5'b01000: rd_dataB = regfile[8];
5'b01001: rd_dataB = regfile[9];
5'b01010: rd_dataB = regfile[10];
5'b01011: rd_dataB = regfile[11];
5'b01100: rd_dataB = regfile[12];
5'b01101: rd_dataB = regfile[13];
5'b01110: rd_dataB = regfile[14];
5'b01111: rd_dataB = regfile[15];
5'b10000: rd_dataB = regfile[16];
5'b10001: rd_dataB = regfile[17];
5'b10010: rd_dataB = regfile[18];
5'b10011: rd_dataB = regfile[19];
5'b10100: rd_dataB = regfile[20];
5'b10101: rd_dataB = regfile[21];
5'b10110: rd_dataB = regfile[22];
5'b10111: rd_dataB = regfile[23];
5'b11000: rd_dataB = regfile[24];
5'b11001: rd_dataB = regfile[25];
5'b11010: rd_dataB = regfile[26];
5'b11011: rd_dataB = regfile[27];
5'b11100: rd_dataB = regfile[28];
5'b11101: rd_dataB = regfile[29];
5'b11110: rd_dataB = regfile[30];
5'b11111: rd_dataB = regfile[31];
default: rd_dataB = 16'hXXXX;
endcase
end
end
always @ (posedge clk)
begin: WRITE
if(wr_en == 1'b1) begin
if(wr_addr != 5'd0) begin
regfile[wr_addr] = #1 wr_data;
//$display("%X", regfile[wr_addr]);
end
else begin
$display("R0: %X", regfile[wr_addr]);
end
end
end
endmodule
非常感谢您的帮助。
if(rd_addrA)
被解释为 if(rd_addrA>0)
。因此无法读取 regfile[0]
。因为所有条目都有效,所以您不需要 if-statement.
其他与您的主要问题无关的问题:
您的代码不可综合,因为 regfile
分配在两个不同的 always 块中。您需要将 regfile
的重置和写入合并到一个 always 块中。 always @(posedge clk)
用于同步复位(对 FPGA 重新启动)。 always @(posedge clk or negedge nrst)
用于异步复位(针对 ASIC 重新开始)。
在组合块中指定灵敏度是旧样式,仅在 1995 版中才需要。自 2001 年以来,自动选择性(always @*
或同义词 always @(*)
)是启动组合块的完美方式。自 Verilog-1995 以来,模块 header 样式建议也发生了变化,因此您也应该继续阅读。 Verilog-1995 风格仍然有效并受支持;只是不再完美。
同步逻辑(又名由时钟或锁存器启用分配的寄存器)应分配 non-blocking 分配 (<=
)。如果您不适当地使用阻塞和 non-blocking 赋值,您 运行 在 RTL 和门之间 miss-match 行为的风险更高。
您的案例陈述可以简化为一行:rd_dataA = regfile[rd_addrA];
。但是请务必检查您的合成结果,因为与 case-statement.
相比,某些合成器使用这种风格的优化效果不佳。
我是 Verilog 的新手,正在尝试创建一个包含 32 位寄存器的寄存器文件。我能够正确地写入和读取所有内容,但是,位于地址 5'b00000 的第一个寄存器(我们将其命名为 R0)必须始终等于 0,并且在任何时候都不能更改。在测试台上读取时,当 R0 突然变成 "xxxxxxxx" 而不是 0 或 00000000 时,问题就出现了。其余寄存器读取正确。我在代码中可能做错了什么,解决这个问题的方法是什么?下面是代码:
module regfile (
clk,
nrst,
rd_addrA,
rd_addrB,
wr_addr,
wr_en,
wr_data,
rd_dataA,
rd_dataB
);
//Input and output ports
input wire clk;
input wire nrst;
input wire [4:0] rd_addrA;
input wire [4:0] rd_addrB;
input wire [4:0] wr_addr;
input wire wr_en;
input wire [31:0] wr_data;
output reg [31:0] rd_dataA;
output reg [31:0] rd_dataB;
reg [31:0] regfile[0:31];
integer i;
always @ (nrst)
begin: RESET
if(nrst == 0) begin
for(i = 0; i < 32; i++) begin
regfile[i] = 0;
end
end
end
always @(rd_addrA or rd_addrB)
begin: READ
if(rd_addrA) begin
case (rd_addrA)
5'b00000: rd_dataA = regfile[0];
5'b00001: rd_dataA = regfile[1];
5'b00010: rd_dataA = regfile[2];
5'b00011: rd_dataA = regfile[3];
5'b00100: rd_dataA = regfile[4];
5'b00101: rd_dataA = regfile[5];
5'b00110: rd_dataA = regfile[6];
5'b00111: rd_dataA = regfile[7];
5'b01000: rd_dataA = regfile[8];
5'b01001: rd_dataA = regfile[9];
5'b01010: rd_dataA = regfile[10];
5'b01011: rd_dataA = regfile[11];
5'b01100: rd_dataA = regfile[12];
5'b01101: rd_dataA = regfile[13];
5'b01110: rd_dataA = regfile[14];
5'b01111: rd_dataA = regfile[15];
5'b10000: rd_dataA = regfile[16];
5'b10001: rd_dataA = regfile[17];
5'b10010: rd_dataA = regfile[18];
5'b10011: rd_dataA = regfile[19];
5'b10100: rd_dataA = regfile[20];
5'b10101: rd_dataA = regfile[21];
5'b10110: rd_dataA = regfile[22];
5'b10111: rd_dataA = regfile[23];
5'b11000: rd_dataA = regfile[24];
5'b11001: rd_dataA = regfile[25];
5'b11010: rd_dataA = regfile[26];
5'b11011: rd_dataA = regfile[27];
5'b11100: rd_dataA = regfile[28];
5'b11101: rd_dataA = regfile[29];
5'b11110: rd_dataA = regfile[30];
5'b11111: rd_dataA = regfile[31];
default: rd_dataA = 16'hXXXX;
endcase
end
if(rd_addrB) begin
case (rd_addrB)
5'b00000: rd_dataB = regfile[0];
5'b00001: rd_dataB = regfile[1];
5'b00010: rd_dataB = regfile[2];
5'b00011: rd_dataB = regfile[3];
5'b00100: rd_dataB = regfile[4];
5'b00101: rd_dataB = regfile[5];
5'b00110: rd_dataB = regfile[6];
5'b00111: rd_dataB = regfile[7];
5'b01000: rd_dataB = regfile[8];
5'b01001: rd_dataB = regfile[9];
5'b01010: rd_dataB = regfile[10];
5'b01011: rd_dataB = regfile[11];
5'b01100: rd_dataB = regfile[12];
5'b01101: rd_dataB = regfile[13];
5'b01110: rd_dataB = regfile[14];
5'b01111: rd_dataB = regfile[15];
5'b10000: rd_dataB = regfile[16];
5'b10001: rd_dataB = regfile[17];
5'b10010: rd_dataB = regfile[18];
5'b10011: rd_dataB = regfile[19];
5'b10100: rd_dataB = regfile[20];
5'b10101: rd_dataB = regfile[21];
5'b10110: rd_dataB = regfile[22];
5'b10111: rd_dataB = regfile[23];
5'b11000: rd_dataB = regfile[24];
5'b11001: rd_dataB = regfile[25];
5'b11010: rd_dataB = regfile[26];
5'b11011: rd_dataB = regfile[27];
5'b11100: rd_dataB = regfile[28];
5'b11101: rd_dataB = regfile[29];
5'b11110: rd_dataB = regfile[30];
5'b11111: rd_dataB = regfile[31];
default: rd_dataB = 16'hXXXX;
endcase
end
end
always @ (posedge clk)
begin: WRITE
if(wr_en == 1'b1) begin
if(wr_addr != 5'd0) begin
regfile[wr_addr] = #1 wr_data;
//$display("%X", regfile[wr_addr]);
end
else begin
$display("R0: %X", regfile[wr_addr]);
end
end
end
endmodule
非常感谢您的帮助。
if(rd_addrA)
被解释为 if(rd_addrA>0)
。因此无法读取 regfile[0]
。因为所有条目都有效,所以您不需要 if-statement.
其他与您的主要问题无关的问题:
您的代码不可综合,因为 regfile
分配在两个不同的 always 块中。您需要将 regfile
的重置和写入合并到一个 always 块中。 always @(posedge clk)
用于同步复位(对 FPGA 重新启动)。 always @(posedge clk or negedge nrst)
用于异步复位(针对 ASIC 重新开始)。
在组合块中指定灵敏度是旧样式,仅在 1995 版中才需要。自 2001 年以来,自动选择性(always @*
或同义词 always @(*)
)是启动组合块的完美方式。自 Verilog-1995 以来,模块 header 样式建议也发生了变化,因此您也应该继续阅读。 Verilog-1995 风格仍然有效并受支持;只是不再完美。
同步逻辑(又名由时钟或锁存器启用分配的寄存器)应分配 non-blocking 分配 (<=
)。如果您不适当地使用阻塞和 non-blocking 赋值,您 运行 在 RTL 和门之间 miss-match 行为的风险更高。
您的案例陈述可以简化为一行:rd_dataA = regfile[rd_addrA];
。但是请务必检查您的合成结果,因为与 case-statement.