我在System Verilog中有一个Modelsim测试台,用于测试Verilog顶层模块(ufm1
)和内部使用的另一个Verilog模块(wishbone
),还有一个System Verilog“ stub”( 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
至内部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
答案 0 :(得分:1)
问题是我在DUT中使用function extMatch(ext){
return new RegExp('^(.*?)\\.'+ext+'$');
}
/* Even shorter, but messing with base prototypes is frowned upon.
Use at your leisure. */
String.prototype.extMatch=function(ext){
let match=this.match(extMatch(ext));
return match && match[1];
}
let str='foobar.css';
let ext='css';
console.log(str.match(extMatch(ext))[1]);
console.log(str.extMatch(ext));
console.log(str.extMatch('zip')); // null if no match
导线的默认值:
wb_rd_data
所以应该就这样
wire [7:0] wb_rd_data = 0;
因此,它对同一条电线有多个分配-从端口和默认值开始,冲突的位以Xs出现。
我不得不尝试在Diamond中对此进行综合以发现问题。