为8x9 FIFO存储器的Verilog代码获取错误?

问题描述 投票:0回答:1

使用Verilog,设计FIFO存储器。使其深8位,宽9位。声明读取信号后,应启用FIFO的输出,否则应为高阻抗。当写信号有效时,写入9位寄存器之一。使用RdInc和WrInc作为输入信号来增加指示要读取或写入哪个寄存器的指针。使用RdPtrClrWrPtrClr作为输入信号,将指针重置为指向数组中的第一个寄存器。不要实施满信号或空信号。

使用这些信号名称:

  • [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
verilog fifo hdl electronics
1个回答
0
投票

您的代码在某些方面无效。 我不会为您重写完整的模块,因为这似乎是一项家庭作业,但是会给您一些提示,指出这里出了什么问题。

不正确的范围

在您的RTL中,条件语句周围的范围不正确。如果使用ifelse ifelse关键字,则执行此关键字之后的语句。如果我们在下面查看您的原始代码:

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块。要解决此问题,您应该添加适当的beginend关键字来定义条件块的范围。

添加锁存器而不是组合逻辑

上述代码块使我们遇到第二个问题:(通常)在使用always@(*)时,您想实现combinational logic。但是,根据您的情况,您正在实现闩锁。在我对这个问题的回答中,在我对另一个问题的先前回答中,我对RTL中发生的事情进行了更深入的解释,如下所示:Incomplete assignment and latches

不区分组合逻辑和顺序逻辑

最后一个问题是您不区分combinational logicsequential logic。前者通过使用always@(*)(或在SystemVerilog中,最好为always_comb)来实现,而后者通过使用always@(posedge clk)(或在SystemVerilog中,最好为always_ff @(posedge clk))来实现。

总结差异:

  • 组合逻辑是指将多个输入信号连接到logic gates(例如ANDNANDINVOR)。结果将在同一时钟周期内立即[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]:简化,实际集成电路中的每个逻辑门和每条线都会有一个小的延迟。

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.