使用Verilog,设计FIFO存储器。使其深8位,宽9位。声明读取信号后,应启用FIFO的输出,否则应为高阻抗。当写信号有效时,写入9位寄存器之一。使用RdInc和WrInc作为输入信号来增加指示要读取或写入哪个寄存器的指针。使用RdPtrClr
和WrPtrClr
作为输入信号,将指针重置为指向数组中的第一个寄存器。不要实施满信号或空信号。
使用这些信号名称:
clk
:时钟RdPtrClr
:清除读取指针,以重置读取指针WrPtrClr
:清除写指针,以重置写指针]rdinc
:读取指针增加信号wrinc
:写指针增加信号DataIn
:数据输入总线DataOut
:数据输出总线rden
:读取(输出)启用wden
:写入(输入)使能所以这是代码,请别人纠正。
module FIFO8x9(
input clk, rst,
input RdPtrClr, WrPtrClr,
input RdInc, WrInc,
input [8:0] DataIn,
output reg [8:0] DataOut,
input rden, wren
);
//signal declarations
reg [8:0] fifo_array[7:0];
reg [7:0] wrptr, rdptr;
wire [7:0] wr_cnt, rd_cnt;
reg [9:0]dmuxout;
always@(*)
begin
if (rst==1)
dmuxout=0;
wr_cnt=0;rd_cnt=0;
end
if(wren)
wrptr<=DataIn;
wrptr<=wrptr+WrInc;
wr_cnt<=wr_cnt+"8'b00000001"
end
if(rden)
dmuxout<=rdptr;
rdptr<=rdptr+RdInc;
rd_cnt<=rd_cnt+"8'b00000001"
else if(rden==0)
dmuxout<='zzzzzzzzz';
end
if(RdPtrClr)
rdptr<=8'b00000000;
end
if(WrPtrClr)
wrdtr<=8'b00000000;
end
Dataout<=dmuxout;
end
endmodule
//there is a logic error with this code can someone help me out
您的代码在某些方面无效。 我不会为您重写完整的模块,因为这似乎是一项家庭作业,但是会给您一些提示,指出这里出了什么问题。
在您的RTL中,条件语句周围的范围不正确。如果使用if
,else if
或else
关键字,则执行此关键字之后的语句。如果我们在下面查看您的原始代码:
always@(*)
begin
if (rst==1)
dmuxout=0;
wr_cnt=0;
rd_cnt=0;
end
这实际上表示以下内容:
always@(*)
begin
if (rst==1)
begin
dmuxout=0;
end
wr_cnt=0;
rd_cnt=0;
end
因此,仅dmuxout
的块分配属于if
分支和,您用该always
关闭end
块。要解决此问题,您应该添加适当的begin
和end
关键字来定义条件块的范围。
上述代码块使我们遇到第二个问题:(通常)在使用always@(*)
时,您想实现combinational logic。但是,根据您的情况,您正在实现闩锁。在我对这个问题的回答中,在我对另一个问题的先前回答中,我对RTL中发生的事情进行了更深入的解释,如下所示:Incomplete assignment and latches
最后一个问题是您不区分combinational logic和sequential logic。前者通过使用always@(*)
(或在SystemVerilog中,最好为always_comb
)来实现,而后者通过使用always@(posedge clk)
(或在SystemVerilog中,最好为always_ff @(posedge clk)
)来实现。
总结差异:
组合逻辑是指将多个输入信号连接到logic gates(例如AND
,NAND
,INV
,OR
)。结果将在同一时钟周期内立即[1]可用。例如,以下代码是组合逻辑。在此,b
将在a
更改时立即更改。
always_comb // cleaner way for always@(*)
begin
if (a == 0)
b = 0;
else
b = 1;
end
顺序逻辑是将状态保存在通常为flip-flop的存储元素中的时间。这意味着结果将仅在下一个时钟周期可用。在下面的示例中,保存在b
中的结果仅在next时钟周期内可用。
always_ff @(posedge clk) // cleaner way for always@(posedge clk)
begin
if (a == 0)
b <= 0;
else
b <= 1;
end
注意块分配(即=
)和非块分配(即<=
)之间的差异。 In my answer I referenced before,我总结一下Clifford E. Cummings撰写的一篇论文。他很好地解释了阻塞式分配和非阻塞式分配之间的区别,以及为什么要知道这种区别很重要。参见Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!
通常,您的复位信号会将触发器设置为默认状态。在许多情况下,重置会出现asynchronously(意味着它可以在任何时候出现,并且应该立即应用),并且重置为[[active-low(意味着如果存在,则应该应用重置)值是'0')。
要实现异步,低电平有效复位,可以在SystemVerilog中编写以下内容:always_ff @(posedge clk or negedge rst_n)
begin
if (!rst_n)
b <= 0; // reset value
else if (a == 0)
b <= 0;
else
b <= 1;
end
当您要实现重置时,不需要为重置信号的边缘增加灵敏度。在这种情况下,重置将应用于时钟的上升沿。synchronous
[1]:简化,实际集成电路中的每个逻辑门和每条线都会有一个小的延迟。