[英]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 内部的模块有一个 output,我将它连接到 DUT 内部的wire
(最初是 System Verilog 版本中的一个reg
,否则会出错),然后使用电线在程序中分配给一个reg
块内的 DUT。
在内部模块内部,这个 output 基本上是直接从输入分配的。
现在,当我模拟这个时,内部模块中的输入很好,但是 output(应该是相同的,因为它是直接assign
)与 Xs 代替 1s 不同。
当内部模块( rd_data
)的 output 分配给电线( wb_rd_data
)时,问题才开始出现,这看起来很奇怪,因为我不知道将 output 端口连接到电线会如何影响其值。
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 中综合它才能找到问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.