输出为高阻抗,回放缓冲器为未定义的输出和输入

High impedance for output, and undefined output and input for replay buffer

我正在尝试在 Verilog 中制作一个 8 KB 的重放缓冲区,并且在设置测试台和 运行 它时,我得到了未定义的输出状态,ready,数据的未定义输出,以及未定义的序列变量。我不确定如何让测试台显示正确的结果。我试过为序列变量分配数据,但似乎没有任何效果。

我的波形是这样的(https://imgur.com/a/hNt1bXU)。我的 reg 变量已初始化,但我不确定问题是什么以获得正确的波形输出。

回放缓冲区

`timescale 1ns / 1ps

module buffer_top(busy_n,clk,reset_n,ack_nak,seq,tim_out,ready,we,din,dout);
    parameter ADDR_WID = 12;
    parameter DATA_WID = 16;
    parameter DEPTH = 4096; /*MUST be 2^(ADDR_WID)*/
    input busy_n,clk,reset_n,tim_out,we;
    input[1:0] ack_nak;
    input[11:0] seq;
    input[DATA_WID-1:0] din;
    output ready;
    output[DATA_WID-1:0] dout;
    
    wire full,empty,rd,prg,wr,replay;
    wire[ADDR_WID-1:0] rd_inc,w_addr,r_addr,replay_addr;
    wire[DATA_WID-1:0] dcurrent;
    
    fifoSM u0(clk,reset_n,busy_n,we,ack_nak,seq,tim_out,full,empty,dcurrent,r_addr,ready,rd,prg,wr,rd_inc,replay);
    ram u1(clk,r_addr,w_addr,din,dout,wr,rd,dcurrent,replay_addr);
    fifo u2(clk,reset_n,wr,rd,prg,replay,rd_inc,full,empty,w_addr,r_addr,replay_addr);
  
endmodule

FIFO 状态机

`timescale 1ns / 1ps
module fifoSM(clk, reset_n,busy_n,we,ack_nak,seq,tim_out,full,empty,dcurrent,outptr,wrptr,ready,rd,prg,wr,rd_inc,replay );
    parameter ADDR_WID = 12;
    parameter DATA_WID = 16;
    parameter DEPTH = 4096;
    
    input clk,reset_n,busy_n,we,tim_out,full,empty;
    input [1:0] ack_nak;
    input [DATA_WID-1:0] dcurrent;
    input [11:0] seq;
    input [12:0] outptr,wrptr;
    output reg rd,prg,wr,ready,replay;
    output reg[ADDR_WID-1:0] rd_inc;
    
    reg seqFound;
    reg [1:0] format,nakcount;
    reg [12:0] calc_inc,lastread;
    reg [10:0] count;
    
    reg [4:0]state;
    localparam  idle=5'b00000, s1=5'b00001, s2=5'b00010, s3=5'b00011, s4=5'b00100, s5=5'b00101,s6=5'b00110, s7=5'b00111,
                s8=5'b01000,s9=5'b01001,s10=5'b01010,s11=5'b01011,s12=5'b01100,s13=5'b01101,s14=5'b01110;
        
    always@(posedge clk)
    begin
         if(!reset_n)begin
            state <= idle;
            nakcount <= 2'd0;
         end   
         else  begin
         case(state)
           idle:   begin
                       if(busy_n && !empty && outptr !=wrptr)  //read buffer if not empty and lane is open
                           state <= s3;
                       else if(ack_nak == 10 && !empty)begin //handle nak if not empty
                           if(nakcount == 2'b11) //if replay count full go to retrain state
                               state <= s14;//retrain state
                           else begin  //else go to purge section then after to replay states
                               state <= s8;   //purge state
                               nakcount <= nakcount + 1; 
                           end       
                       end 
                       else if(ack_nak == 2'b01 && !empty)begin//handle ack if not empty
                           state <= s8; //go to purge section
                           nakcount <= 2'd0; //reset replay counter
                       end  
                       else if(tim_out && !empty)begin    //handle time out if not empty
                            if(nakcount == 2'b11)//if replay count full
                               state <= s14;//go to retrain section
                           else begin //else go to replay state
                               state <= 11;
                               nakcount <= nakcount + 1; //increment replay count
                           end       
                       end    
                       else if(we && !full)     //write packet if not full and is we
                            state <= s1;
           end
           //write states (input)        
           s1:  begin
                state <= s2;
           end   
           s2: begin
                if(we)
                    state <= s2;
                else
                    state <= idle;    
           end  
           //read states (output) output rd=1 to fifo
           s3: begin
                state <= s4;
                count <= 0;
           end   
           s4: begin
                state <=s5;
                count <= 1;
               format = dcurrent[14:13];
               if(format[0]==0)begin
                   calc_inc = 13'd8;        //3dw including 1dw for lcrc
               end    
               else   
                   calc_inc = 13'd10;
           end
           s5: begin
                count <= 2;
                if(dcurrent[9:0] == 0)
                   calc_inc = calc_inc + (format[1] * 2048);
               else    
                   calc_inc = calc_inc + (format[1] * dcurrent[9:0]*2);
               state <= s6;
           end
           s6: begin
                count <= count + 1;
                if(count < calc_inc)
                    state <= s6;
                else
                    state <= idle;  
           end
           //purge
           s8:  begin //let rd_ptr increment r_ptr until found or do this
                    if(dcurrent == {"0000",seq})begin
                        state <=s9; 
                        seqFound <= 1;
                    end    
                    else begin
                        seqFound <=0;   
                    end           
                end
           s9:     begin //get format fields to get header length, output to fifo: prg = 1
                        state <=s10;
                        format = dcurrent[14:13];
                        if(format[0]==0)begin
                            calc_inc = 13'd8;        //3dw including 1dw for lcrc
                        end    
                        else   
                            calc_inc = 13'd10;  
                   end
           s10:     begin    //get length fields to add to increment
                     if(dcurrent[9:0] == 0)
                           calc_inc = calc_inc + (format[1] * 2048);
                       else    
                           calc_inc = calc_inc + (format[1] * dcurrent[9:0]*2);
                       if(seqFound)begin //if done purging
                          if(ack_nak==2'b01) //if ack go to idle
                            state <=idle;
                          else begin  //if nak go to replay states
                             state <= s11; 
                          end   
                       end
                       else
                          state <= s8;   //examine next seq num in buffer to compare with dllp seq num
                   end
           //replay  states
           s11:     begin //set up lastread before enter replay mode
                        state <= s12;
                        lastread <= outptr;  //set lastread to outptr before outptr changes in replay
                    end
           s12:      begin   //output replay = 1 to fifo
                         state <= s13;   //outptr will go back to where r_addr is
                    end        
           s13:     begin   //output read = 1 to fifo and repeat until outptr retruns to where it was
                        if(outptr < lastread)
                            state <=s13;   //repeat this state
                        else
                            state <= idle;       //if outptr back to where was go back
                   end  
           s14: state<= s14;   //link retrain  
           default: begin state <= idle; end
         endcase
         end
    end
    
    always@(state)
         case(state)
           idle:   begin replay = 0; ready = 0; rd = 0; wr = 0;  prg = 0;end
           s1:      begin ready = 1; wr = 1; end
           s2:      begin wr = 1; end
           s4:      begin rd = 1; end
           s8:     begin ready = 0; rd = 0; wr =0; prg = 1; rd_inc = 1; end
           s9:      begin rd_inc = 1; end
           s10:     begin  rd_inc = calc_inc; end
           s11:     begin replay = 0;  ready = 0;  rd = 0; wr =0; prg = 0;end //setup lastread with outptr
           s12:     begin replay = 1;  end  
           s13:     begin replay = 0; rd = 1; end
           s14:     begin ready = 0; rd = 0; wr= 0; prg= 0; end
           default: begin ready = 1; rd = 0; wr = 0;  prg = 0; end
         endcase
endmodule

内存

`timescale 1ns / 1ps
module ram(clk, r_addr, w_addr, din, dout, wr, rd, dcurrent, replay_addr);

    parameter ADDR_WID = 12;
    parameter DATA_WID = 16;
    parameter DEPTH = 4096;
    
    input clk, wr, rd;
    input [ADDR_WID-1:0] r_addr, w_addr, replay_addr;
    input [DATA_WID-1:0] din;
    
    output [DATA_WID-1:0] dout, dcurrent;
    
    reg [DATA_WID-1:0] dataout;
    reg [DATA_WID-1:0] mem [0:DEPTH-1];
    
    assign dout = (rd && !wr) ? dataout: 16'hzzzz;
    assign dcurrent = mem[replay_addr];
    
    always@(posedge clk) begin
        if(wr) mem[w_addr] = din;
    end
    
    always@(posedge clk) begin
        dataout = mem[r_addr];
    end
endmodule

先进先出

module fifo(clk,reset_n,wr,rd,prg,replay,rd_inc,full,empty,w_addr,r_addr,replay_addr);
    parameter ADDR_WID = 12;
    parameter DATA_WID = 16;
    parameter DEPTH = 4096;
    input    clk, reset_n, wr, rd, prg, replay;
    input   [ADDR_WID-1:0] rd_inc;
    output   full, empty;
    output [ADDR_WID-1:0]  w_addr, r_addr, replay_addr;
    reg    [ADDR_WID-1:0]  w_ptr, replay_ptr, r_ptr;
    
    always@(posedge clk)
    begin
       if(!reset_n)
       begin
         w_ptr <= 0;
         replay_ptr <= 0;
         r_ptr <= 0;
       end
       else
         if(wr && !full)
           w_ptr <= w_ptr + 1;
         if(prg && !empty)begin
           replay_ptr <= replay_ptr + rd_inc;  //or long way and check every address for seq num
         end  
         if(rd && !empty)
            r_ptr  <= r_ptr + 1;
         if(replay)
            r_ptr <= replay_ptr;   
    end
    
    assign full = ((r_ptr!=w_ptr) && (r_ptr[ADDR_WID-1:0]==w_ptr[ADDR_WID-1:0]))?1:0;
    assign empty = (r_ptr==w_ptr) ? 1 : 0;
    
    assign w_addr = w_ptr[ADDR_WID-1:0];
    assign out_addr = r_ptr[ADDR_WID-1:0];
    assign replay_addr = replay_ptr[ADDR_WID-1:0];
    
endmodule

回放缓冲区测试平台

`timescale 1ns / 1ps

module buffer_top_tb();

    parameter ADDR_WID = 12;
    parameter DATA_WID = 16;
    parameter DEPTH = 4096; /*MUST be 2^(ADDR_WID)*/
    
    reg busy_n,clk,reset_n,tim_out,we;
    reg[1:0] ack_nak;
    reg[11:0] seq;
    reg[DATA_WID-1:0] din;
    wire ready;
    wire[DATA_WID-1:0] dout;
    
    buffer_top u3(busy_n,clk,reset_n,ack_nak,seq,tim_out,ready,we,din,dout);
    
    always #2 clk = ~clk;

initial begin
  clk = 0; reset_n = 0; busy_n = 0; ack_nak = 2'b00; tim_out = 0; we = 0;  //initial state, everything zeroed out
  #3;
  reset_n = 1;
  
  /*Writing packets to buffer*/
  we = 1;
  //Memory Read Request to read DW at address 3F6BFC11C and return result to entity with ID 0x0000
  din = 16'h01a4; seq = 0;                              //seq# 420
  #4; din = 16'h0000; #4; din = 16'h0001;   //DW0
  #4; din = 16'h0000; #4; din = 16'h0c0f;   //DW1
  #4; din = 16'hfdaf; #4; din = 16'hf047;   //DW2
  #4; din = 16'h0f0f; #4; din = 16'hf0f0;   //LCRC
  #4;

  //Completion TLP w data 0xba5eba11
  din = 16'h01a5; seq = 1;                          //seq# 421
  #4; din = 16'h4A00; #4; din = 16'h0001;
  #4; din = 16'h0100; #4; din = 16'h0004;
  #4; din = 16'h0000; #4; din = 16'h0C40;
  #4; din = 16'hba5e; #4; din = 16'hba11;
  #4; din = 16'h0F0F; #4; din = 16'hf0f0;
  #4;
  
  //Memory Write Request 4DW + 1DW data
  din = 16'h01a6; seq = 2;                          //seq# 422
  #4; din = 16'h6000; #4; din = 16'h0001;
  #4; din = 16'h0000; #4; din = 16'h000F;
  #4; din = 16'hFDAF; #4; din = 16'hF040;
  #4; din = 16'hFCBA; #4; din = 16'h57ED;
  #4; din = 16'h9ABC; #4; din = 16'hDEF1;
  #4; din = 16'h0F0F; #4; din = 16'hf0f0;
  #4;
  
  //Memory Write Request 3DW + 1DW data
  din = 16'h01a7; seq = 3;                          //seq# 423
  #4; din = 16'h4000; #4; din = 16'h0001;
  #4; din = 16'h0000; #4; din = 16'h000F;
  #4; din = 16'hFDAF; #4; din = 16'hF040;
  #4; din = 16'h9ABC; #4; din = 16'hDEF1;
  #4; din = 16'h0F0F; #4; din = 16'hf0f0;
  #4;
  
  //IO Rd request 3DW no Data
  din = 16'h01a8; seq = 4;                         //seq# 424
  #4; din = 16'h0200; #4; din = 16'h0001;
  #4; din = 16'h0000; #4; din = 16'h000F;
  #4; din = 16'hFDAF; #4; din = 16'hF040;
  #4; din = 16'h0F0F; #4; din = 16'hf0f0;
  #4;
  /*End write phase*/
  
  #20;
  $stop;
end
            
endmodule

当我编译你的代码时,我收到了几个警告。这是第一个:

    fifoSM u0(clk,reset_n,busy_n,we,ack_nak,seq,tim_out,full,empty,dcurrent,r_addr,ready,rd,prg,wr,rd_inc,replay);
            |
xmelab: *W,CUVWSP 1 output port was not connected:
xmelab: replay

这表明您的设计存在连接错误。

当你比较fifoSM模块实例行和模块声明行时,你会发现ready信号没有正确连接。它连接到 wrptr 而不是 ready。这会导致顶层 ready 上的高阻抗 (z)。

如果您解决了这些连接问题,也许您的其他错误也会得到解决。


如果您的模拟器没有收到编译警告,请在 edaplayground 上的多个模拟器上尝试您的代码。


为了避免像这样的常见连接问题,最好使用按名称连接而不是按位置连接。请参阅 IEEE Std 1800-2017,第 23.3.2.2 节按名称连接模块实例端口。例如,要实例化 fifoSM 模块,请使用如下内容:

fifoSM dut (
        // Inputs:
    .ack_nak   (ack_nak),
    .busy_n    (busy_n),
    .clk       (clk),
    .dcurrent  (dcurrent),
    .empty     (empty),
    .full      (full),
    .outptr    (outptr),
    .reset_n   (reset_n),
    .seq       (seq),
    .tim_out   (tim_out),
    .we        (we),
    .wrptr     (wrptr),
        // Outputs:
    .prg       (prg),
    .rd        (rd),
    .rd_inc    (rd_inc),
    .ready     (ready),
    .replay    (replay),
    .wr        (wr)
);