Verilog DUT System Verilog testbench: вывод для назначения провода 1с заменен на X - PullRequest
0 голосов
/ 19 сентября 2019

У меня есть стенд для тестирования Modelsim в System Verilog, который тестирует модуль верхнего уровня Verilog (ufm1) с другим модулем Verilog (wishbone), который используется внутри него, есть также заглушка System Verilog (wishbone_sim)это связано с тестируемым устройством в стенде.

Изначально DUT и внутренний модуль были в System Verilog и работали нормально, но мне пришлось преобразовать их в Verilog, чтобы иметь возможность использовать Diamond LSE (оставляя тестовый стенд в System Verilog)

внутренний модуль внутри DUT имеет выход, который я подключаю к wire (изначально был reg в версии System Verilog, потому что в противном случае он выдавал ошибку) внутри DUT, а затем использовал провод для назначения reg в процедурном блоке внутри DUT.

Внутри внутреннего модуля этот выход в основном назначается непосредственно с входа.

Теперь, когда я моделирую это, вход во внутреннем модулехорошо, но вывод (должен быть таким же, потому что это прямой assign) отличается от X вместо 1 с.

Эта проблема появляется только тогда, когда вывод внутреннего модуля (rd_data)назначен проводу (wb_rd_data), что выглядит странно, потому что я не вижу, как подключение выходного порта к проводу повлияет на его значение.

Провод внутри проверяемого устройства wb_rd_data, который подключен к порту rd_data внутреннего модуля wishbone.

Как это исправить?

DUT:

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

1 Ответ

1 голос
/ 19 сентября 2019

Проблема заключалась в том, что у меня было значение по умолчанию для провода wb_rd_data внутри DUT:

wire [7:0] wb_rd_data = 0;

Так что это должно было быть просто

wire [7:0] wb_rd_data;

Так что он имеет несколькоприсвоения тому же проводу - из порта, значения по умолчанию и конфликтующих битов - X.

Мне пришлось попытаться синтезировать это в Diamond, чтобы найти проблему.

...