Verilog DUT 系统 Verilog 测试台:输出到接线分配 1s 替换为 Xs

Verilog DUT System Verilog testbench: output to wire assignment 1s replaced with Xs

我在 System Verilog 中有一个 Modelsim 测试台,用于测试一个 Verilog 顶层模块 (ufm1) 以及其中使用的另一个 Verilog 模块 (wishbone),还有一个 System Verilog“存根” (wishbone_sim) 连接到测试台中的 DUT。

DUT 和内部模块最初在 System Verilog 中并且工作正常,但我必须将它们转换为 Verilog 才能使用 Diamond LSE(将测试平台留在 System Verilog 中)

DUT 内部的内部模块有一个输出,我正在连接到 DUT 内部的 wire(在 System Verilog 版本中最初是 reg,否则会出错)然后使用电线分配给 DUT 内程序块中的 reg

在内部模块中,这个输出基本上是直接从输入分配的。

现在,当我模拟这个时,内部模块中的输入很好,但输出(应该是相同的,因为它是直接 assign)与 Xs 不同,而不是 1s。

当内部模块 (rd_data) 的输出分配给电线 (wb_rd_data) 时,问题才开始出现,这看起来很奇怪,因为我看不到如何连接电线的输出端口会影响其值。

DUT 内部的电线是 wb_rd_data,连接到内部 wishbone 模块的 rd_data 端口。

我该如何解决这个问题?

待测物:

module ufm1(clk, ufm_wr_rq, ufm_rd_rq, ufm_wr_data, ufm_wr_ack, ufm_rd_data, ufm_rd_ack, ufm_done, wb_clk, wb_rst, wb_cyc, wb_stb, wb_we, wb_addr, wb_dat_i, wb_dat_o, wb_ack);

input clk;
input ufm_wr_rq, ufm_rd_rq;
input [7:0] ufm_wr_data;
output reg ufm_wr_ack;
output [7:0] ufm_rd_data;
output ufm_rd_ack;
output reg ufm_done = 0;

output wb_clk;
output wb_rst;
output wb_cyc;
output wb_stb;
output wb_we;
output [7:0] wb_addr;
output [7:0] wb_dat_i;
input [7:0] wb_dat_o;
input wb_ack;

      parameter WR_OF = 8'h10;
      parameter WR_CF = 8'h11;
      parameter WR = 8'h12;
      parameter WRE = 8'h13;
      parameter RD = 8'h20;
      parameter RDI = 8'h21;
      parameter JMPI = 8'h30;
      parameter END = 8'h40;

      parameter Z00 = 8'h00;
      parameter FF = 8'hFF;

      parameter WR_CMDS = 4'h1;
      parameter RD_CMDS = 4'h2;
      parameter JMP_CMDS = 4'h3;
      parameter END_CMDS = 4'h4;

      parameter CMD_EN_CFG_I = 8'h74;
      parameter CMD_DIS_CFG_I = 8'h26;
      parameter CMD_RD_ST = 8'h3C;
      parameter CMD_ZERO_ADDR = 8'h47;
      parameter CMD_RD_UFM = 8'hCA;
      parameter CMD_WR_UFM = 8'hC9;
      parameter CMD_ERASE_UFM = 8'hCB;
      parameter CMD_BYPASS = 8'hFF;

      parameter ST_IDL = 3'd0;
      parameter ST_NEXT_CMD = 3'd1;   
      parameter ST_WT_WR = 3'd2;
      parameter ST_WT_RD = 3'd3;

      parameter CMDS_NUM = 9'd196;
      parameter WR_PRG_START_INDEX = 9'd103;

      parameter [CMDS_NUM*8-1:0] CMDS = {
            //**** Erase and read
            //Enabled configuration interface
            WR_OF, WR, CMD_EN_CFG_I, WR, 8'h08, WR, Z00, WR, Z00, WR_CF,
            //Read config status register and repeat till not busy
            WR_OF, WR, CMD_RD_ST,    WR, Z00,   WR, Z00, WR, Z00, RD, RD, RD, WR_CF, JMPI,
            //Zero UFM address
            WR_OF, WR, CMD_ZERO_ADDR,WR, Z00,   WR, Z00, WR, Z00, WR_CF,
            //Read UFM page 0 (16 bytes) 
            WR_OF, WR, CMD_RD_UFM, WR,   Z00,   WR, Z00, WR, 8'h01,
            RDI,RDI,RDI,RDI,RDI,RDI,RDI,RDI,RDI,RDI,RDI,RDI,RDI,RDI,RDI,RDI,
            WR_CF,
            //Erase UFM
            WR_OF, WR, CMD_ERASE_UFM,WR, Z00,   WR, Z00, WR, Z00, WR_CF,
            //Read config status register and repeat till not busy
            WR_OF, WR, CMD_RD_ST,    WR, Z00,   WR, Z00, WR, Z00, RD, RD, RD, WR_CF, JMPI, 
            //Disable configuration interface
            WR_OF, WR, CMD_DIS_CFG_I, WR, Z00, WR, Z00, WR_CF,
            //Bypass (NOP)
            WR_OF, WR, CMD_BYPASS,    WR, FF,  WR, FF,  WR,  FF, WR_CF,

            END,  
            
            //**** Write
            //Enabled configuration interface
            WR_OF, WR, CMD_EN_CFG_I, WR, 8'h08, WR, Z00, WR, Z00, WR_CF,
            //Read config status register and repeat till not busy
            WR_OF, WR, CMD_RD_ST,    WR, Z00,   WR, Z00, WR, Z00, RD, RD, RD, WR_CF, JMPI,
            //Zero UFM address
            WR_OF, WR, CMD_ZERO_ADDR,WR, Z00,   WR, Z00, WR, Z00, WR_CF,
            //Write UFM page 0 (16 bytes) 
            WR_OF, WR, CMD_WR_UFM, WR,   Z00,   WR, Z00, WR, 8'h01,
            WRE,WRE,WRE,WRE,WRE,WRE,WRE,WRE,WRE,WRE,WRE,WRE,WRE,WRE,WRE,WRE,
            WR_CF,
            //Read config status register and repeat till not busy
            WR_OF, WR, CMD_RD_ST,    WR, Z00,   WR, Z00, WR, Z00, RD, RD, RD, WR_CF, JMPI, 
            //Disable configuration interface
            WR_OF, WR, CMD_DIS_CFG_I, WR, Z00, WR, Z00, WR_CF,
            //Bypass (NOP)
            WR_OF, WR, CMD_BYPASS,    WR, FF,  WR, FF,  WR,  FF, WR_CF,

            END  
      };

      

      reg wb_wr_rq = 0, wb_rd_rq = 0;
      reg [7:0] wb_wr_data = 0;
      wire [7:0] wb_rd_data = 0;
      reg [7:0] addr = 0;       

      wishbone wishbone(.clk(clk), .wr_rq(wb_wr_rq), .rd_rq(wb_rd_rq), .wr_data(wb_wr_data), .rd_data(wb_rd_data),
                        .addr(addr), .done(wb_done), .wb_clk(wb_clk), .wb_rst(wb_rst), .wb_cyc(wb_cyc), .wb_stb(wb_stb),
                        .wb_we(wb_we), .wb_addr(wb_addr), .wb_dat_i(wb_dat_i), .wb_dat_o(wb_dat_o), .wb_ack(wb_ack));


      reg [2:0] st = 0;
      reg [2:0] prev_st = 0;
      reg [7:0] prev_cmd = 0;
      reg [CMDS_NUM*8-1:0] cmds = CMDS;
      reg [8:0] cmd_index = 0;
      reg [7:0] lst_rd_data = 0;
      
      wire [7:0] cur_cmd = cmds[((CMDS_NUM-cmd_index-1)*8)+:8];
      wire [7:0] next_cmd = cmds[((CMDS_NUM-cmd_index-2)*8)+:8];

      assign is_cmd_wre = (cur_cmd == WRE);
      assign is_1cmd_wr = (cur_cmd == WRE || cur_cmd == WR_OF || cur_cmd == WR_CF);

      assign ufm_rd_ack = (prev_st == ST_WT_RD) && (prev_cmd == RDI) && wb_done;
      assign ufm_rd_data = ufm_rd_ack ? wb_rd_data : 0;

      always @(posedge clk)
      begin

        prev_st <= st;
        prev_cmd <= cur_cmd;

        case(st)
          ST_IDL:
          begin
            ufm_done <= 0;
            if(ufm_rd_rq)
            begin            
              st <= ST_NEXT_CMD;
            end
            else
            if(ufm_wr_rq)
            begin
              st <= ST_NEXT_CMD;
              cmd_index <= WR_PRG_START_INDEX;
            end           
          end          
          ST_NEXT_CMD:           
            case(cur_cmd[7:4])
               WR_CMDS:
               begin
                 wb_wr_rq <= 1;
                 wb_wr_data <= (cur_cmd == WR_OF) ? 8'h80 :
                           (cur_cmd == WR_CF ? 8'h00 : (is_cmd_wre ? ufm_wr_data : next_cmd));
                 addr <= (cur_cmd == WR_OF || cur_cmd == WR_CF) ? 8'h70 : 8'h71;
                 ufm_wr_ack <= is_cmd_wre;                                   
                 st <= ST_WT_WR;
               end

               RD_CMDS:
               begin
                 wb_rd_rq <= 1;
                 addr <= 8'h73;
                 st <= ST_WT_RD;                  
               end

               JMP_CMDS:
               begin
                 st <= ST_NEXT_CMD;

                 if(lst_rd_data[4]) //if busy
                 begin
                   cmd_index <= cmd_index - 13; //assuming the previous command is reading the status register 
                 end
                 else
                 begin
                   cmd_index <= cmd_index + 1;
                 end
               end 

               END_CMDS:
               begin
                 st <= ST_IDL;
                 cmd_index <= 0;
                 ufm_done <= 1;
               end              
            endcase

          ST_WT_WR:
          begin
            wb_wr_rq <= 0;
            ufm_wr_ack <= 0;
            if(wb_done)
            begin
               wb_wr_data <= 0; //todo: not necessary, can be removed if doesn't fit
               cmd_index <= cmd_index + (is_1cmd_wr ? 1 : 2);
               st <= ST_NEXT_CMD;
            end
          end

          ST_WT_RD:
          begin
            wb_rd_rq <= 0;
            if(wb_done)
            begin              
              lst_rd_data <= wb_rd_data;
              cmd_index <= cmd_index + 1;
              st <= ST_NEXT_CMD; 
            end
          end         
        endcase
      end

endmodule

内部模块:

module wishbone(clk, wr_rq, rd_rq, done, addr, wr_data, rd_data, wb_clk, wb_rst, wb_cyc, wb_stb, wb_we, wb_addr, wb_dat_i, wb_dat_o, wb_ack);

input clk;
input wr_rq, rd_rq;
output done;
input [7:0] addr;
input [7:0] wr_data;
output [7:0] rd_data;


output wb_clk;
output wb_rst;
output wb_cyc;
output wb_stb;
output wb_we;
output [7:0] wb_addr;
output [7:0] wb_dat_i;
input [7:0] wb_dat_o;
input wb_ack;

reg wr_in_progress = 0;
reg rd_in_progress = 0;

assign done = wb_ack;
assign wb_clk = clk;
assign wb_addr = (wr_in_progress || rd_in_progress) ? addr : 0;
assign wb_dat_i = wr_in_progress ? wr_data : 0;
assign rd_data = wb_dat_o;
assign wb_rst = 0;
assign wb_cyc = wr_in_progress || rd_in_progress;
assign wb_stb = wb_cyc;
assign wb_we = wr_in_progress;

always @(posedge clk)
begin
    if(!wr_in_progress && !rd_in_progress)
    begin
         if(wr_rq)
         begin
            wr_in_progress <= 1;            
         end
         else if(rd_rq)
         begin
            rd_in_progress <= 1;
         end
    end
    else if(wr_in_progress && wb_ack)
    begin
         wr_in_progress <= 0;
    end
    else if(rd_in_progress && wb_ack)
    begin
         rd_in_progress <= 0;         
    end   
end

endmodule

测试平台:

`timescale 100ps / 100ps

module ufm1_tb;

      parameter WR_OF = 8'h10;
      parameter WR_CF = 8'h11;
      parameter WR = 8'h12;
      parameter WRE = 8'h13;
      parameter RD = 8'h20;
      parameter RDI = 8'h21;
      parameter JMPI = 8'h30;
      parameter END = 8'h40;

      parameter Z00 = 8'h00;
      parameter FF = 8'hFF;

      parameter WR_CMDS = 4'h1;
      parameter RD_CMDS = 4'h2;
      parameter JMS_CMDS = 4'h3;

      parameter CMD_EN_CFG_I = 8'h74;
      parameter CMD_DIS_CFG_I = 8'h26;
      parameter CMD_RD_ST = 8'h3C;
      parameter CMD_ZERO_ADDR = 8'h47;
      parameter CMD_RD_UFM = 8'hCA;
      parameter CMD_WR_UFM = 8'hC9;
      parameter CMD_ERASE_UFM = 8'hCB;
      parameter CMD_BYPASS = 8'hFF;

parameter CD = 200; //100ps*200=20nS (50MHz)
parameter HCD = CD/2; 
parameter QCD = CD/4;

parameter IGNORE = 8'h00;
parameter BUSY = 8'h10;
parameter FREE = 8'h00;

parameter [7:0] DATA [] = '{
            //**** erase/read
            //First busy wait
            IGNORE, IGNORE, BUSY,
            IGNORE, IGNORE, FREE,
            //UFM Page 0 read
            8'hA0,8'hA1,8'hA2,8'hA3,8'hA4,8'hA5,8'hA6,8'hA7,8'hA8,8'hA9,8'hAA,8'hAB,8'hAC,8'hAD,8'hAE,8'hAF,
            //Second busy wait 
            IGNORE, IGNORE, BUSY,
            IGNORE, IGNORE, BUSY,
            IGNORE, IGNORE, FREE,

            //**** write
            //First busy wait
            IGNORE, IGNORE, BUSY,
            IGNORE, IGNORE, FREE,
            
            //Second busy wait 
            IGNORE, IGNORE, BUSY,
            IGNORE, IGNORE, BUSY,
            IGNORE, IGNORE, FREE 
      };

parameter [7:0] DELAYS [] = '{{dut.CMDS_NUM}{8'h0}};
parameter [7:0] WRDATA [] = '{8'hBF,8'hBE,8'hBD,8'hBC,8'hBB,8'hBA,8'hB9,8'hB8,8'hB7,8'hB6,8'hB5,8'hB4,8'hB3,8'hB2,8'hB1,8'hB0};

parameter ST_IDLE = 0;
parameter ST_READING = 1;
parameter ST_WRITING = 2;
parameter ST_FINISHED = 3;

reg clk = 0;

always #(HCD) clk = ~clk;

wishbone_sim
#(
  .CD(CD),
  .DATA(DATA),
  .NUM_OPERATIONS(dut.CMDS_NUM),
  .DELAYS('{{dut.CMDS_NUM}{0'h0}})
)
wb_sim(.wb_clk(dut.wb_clk), .wb_rst(dut.wb_rst), .wb_stb(dut.wb_stb), .wb_cyc(dut.wb_cyc), .wb_we(dut.wb_we), .wb_addr(dut.wb_addr), .wb_dat_i(dut.wb_dat_i), .wb_dat_o(dut.wb_dat_o), .wb_ack(dut.wb_ack));

reg ufm_wr_rq = 0;
reg ufm_rd_rq = 0;
reg [3:0] st = ST_IDLE;
reg [7:0] ufm_wr_data = 8'bZ;
reg [4:0] ufm_wr_data_idx = 0;

wire [7:0] ufm_rd_data;
wire [7:0] wb_addr;
wire [7:0] wb_dat_i;
wire [7:0] wb_dat_o;

ufm1 dut(clk, ufm_wr_rq, ufm_rd_rq, ufm_wr_data, ufm_wr_ack, ufm_rd_data, ufm_rd_ack, ufm_done,
         wb_clk, wb_rst, wb_cyc, wb_stb, wb_we, wb_addr, wb_dat_i, wb_dat_o, wb_ack);

always @(posedge clk)
begin
   case(st)
      ST_IDLE:
      begin
        ufm_rd_rq <= 1;
        st <= ST_READING;        
      end
      ST_READING:
      begin
        ufm_rd_rq <= 0;
        if(ufm_done)
        begin
          ufm_wr_rq <= 1;
          ufm_wr_data <= WRDATA[ufm_wr_data_idx];
          ufm_wr_data_idx <= ufm_wr_data_idx + 1;
          st <= ST_WRITING;
        end
      end
      ST_WRITING:
      begin
        ufm_wr_rq <= 0;
        if(ufm_wr_ack)
        begin
          ufm_wr_data <= WRDATA[ufm_wr_data_idx];
          ufm_wr_data_idx <= ufm_wr_data_idx + 1;
        end
        if(ufm_done) st <= ST_FINISHED;
      end
   endcase    
end

endmodule

问题是我对 DUT 内部的 wb_rd_data 线有一个默认值:

wire [7:0] wb_rd_data = 0;

所以应该只是

wire [7:0] wb_rd_data;

所以它对同一条线路有多个分配 - 从端口和默认值以及冲突的位出现为 Xs。

我不得不尝试在 Diamond 中合成它以找到问题所在。