为了巩固一下sv的知识,使用sv做一下synopsys的router得完整验证流程。router是一个16×16的路由器,具体spec文档我这边没有找到,只有源代码,如果有同学有可以发我一下不胜感激。
源代码如下:
module router(
reset_n, clock, frame_n, valid_n, din, dout, busy_n, valido_n, frameo_n);
input reset_n, clock;
input [15:0] din, frame_n, valid_n;
output [15:0] dout, valido_n, busy_n, frameo_n;
wire reset;
wire [15:0] arb0, arb1, arb2, arb3, arb4, arb5, arb6, arb7;
wire [15:0] di;
wire [15:0] arb8, arb9, arb10, arb11, arb12, arb13, arb14, arb15;
wire [15:0] arb_head, okstep;
tri0 [15:0] doint;
tri1 [15:0] valdoint_n, frameoint_n;
reg [15:0] dout, valido_n, frameo_n;
reg [3:0] arb_head_num;
assign di = din; //将din赋值给di
assign reset = ~reset_n; //将reset_n信号取反后赋值给reset
assign arb_head = 1 << arb_head_num; //将arb_head_num左移一位赋值给arb_head
rtslice rts0(reset,clock,frame_n[0],valid_n[0],di[0],
arb0,arb1,arb_head[0],okstep[0],
doint,busy_n[0],valdoint_n,frameoint_n);
rtslice rts1(reset,clock,frame_n[1],valid_n[1],di[1],
arb1,arb2,arb_head[1],okstep[1],
doint,busy_n[1],valdoint_n,frameoint_n);
rtslice rts2(reset,clock,frame_n[2],valid_n[2],di[2],
arb2,arb3,arb_head[2],okstep[2],
doint,busy_n[2],valdoint_n,frameoint_n);
rtslice rts3(reset,clock,frame_n[3],valid_n[3],di[3],
arb3,arb4,arb_head[3],okstep[3],
doint,busy_n[3],valdoint_n,frameoint_n);
rtslice rts4(reset,clock,frame_n[4],valid_n[4],di[4],
arb4,arb5,arb_head[4],okstep[4],
doint,busy_n[4],valdoint_n,frameoint_n);
rtslice rts5(reset,clock,frame_n[5],valid_n[5],di[5],
arb5,arb6,arb_head[5],okstep[5],
doint,busy_n[5],valdoint_n,frameoint_n);
rtslice rts6(reset,clock,frame_n[6],valid_n[6],di[6],
arb6,arb7,arb_head[6],okstep[6],
doint,busy_n[6],valdoint_n,frameoint_n);
rtslice rts7(reset,clock,frame_n[7],valid_n[7],di[7],
arb7,arb8,arb_head[7],okstep[7],
doint,busy_n[7],valdoint_n,frameoint_n);
rtslice rts8(reset,clock,frame_n[8],valid_n[8],di[8],
arb8,arb9,arb_head[8],okstep[8],
doint,busy_n[8],valdoint_n,frameoint_n);
rtslice rts9(reset,clock,frame_n[9],valid_n[9],di[9],
arb9,arb10,arb_head[9],okstep[9],
doint,busy_n[9],valdoint_n,frameoint_n);
rtslice rts10(reset,clock,frame_n[10],valid_n[10],di[10],
arb10,arb11,arb_head[10],okstep[10],
doint,busy_n[10],valdoint_n,frameoint_n);
rtslice rts11(reset,clock,frame_n[11],valid_n[11],di[11],
arb11,arb12,arb_head[11],okstep[11],
doint,busy_n[11],valdoint_n,frameoint_n);
rtslice rts12(reset,clock,frame_n[12],valid_n[12],di[12],
arb12,arb13,arb_head[12],okstep[12],
doint,busy_n[12],valdoint_n,frameoint_n);
rtslice rts13(reset,clock,frame_n[13],valid_n[13],di[13],
arb13,arb14,arb_head[13],okstep[13],
doint,busy_n[13],valdoint_n,frameoint_n);
rtslice rts14(reset,clock,frame_n[14],valid_n[14],di[14],
arb14,arb15,arb_head[14],okstep[14],
doint,busy_n[14],valdoint_n,frameoint_n);
//rtslicef rts15(reset,clock,frame_n[15],valid_n[15],di[15],
// arb15,arb0,arb_head[15],okstep[15],
// doint,busy_n[15],valdoint_n,frameoint_n);
rtslice rts15(reset,clock,frame_n[15],valid_n[15],di[15],
arb15,arb0,arb_head[15],okstep[15],
doint,busy_n[15],valdoint_n,frameoint_n);
always @(posedge reset)
begin
arb_head_num <= 4'b0;
end
always @(posedge clock)
begin
dout <= doint;
valido_n <= valdoint_n;
frameo_n <= frameoint_n;
if (reset == 1'b0)
begin
if (okstep[arb_head_num] == 1'b1)
arb_head_num <= arb_head_num + 1;
end
end
endmodule //router
//模块rtslice开始
module rtslice(reset,clock,frame_n,valid_n,din,
iarbin,arbout,arbhead,okstep,
dout,busy_n,valido_n,frameo_n);
input reset,clock,frame_n,valid_n,din, arbhead;
output busy_n,okstep;
input [15:0] iarbin;
output [15:0] arbout,dout,valido_n;
inout [15:0] frameo_n;
reg [4:0] addrsf, addrsel;
reg [5:0] addrfsr;
reg din1, busy_n, frame1_n, frame2_n, vald1_n, arbena;
wire [15:0] dout;
wire [15:0] arbin;
wire busy1_n;
wire [4:0] addrsel_g;
reg [3:0] i;
assign arbin = (arbhead == 1'b1) ? 16'hffff : iarbin;
assign addrsel_g = (arbena == 1'b1) ? addrsel : 5'h0;
// always @ ( posedge clock)
// begin
assign dout[0] =
(addrsel_g == 5'h10 && arbin[0] == 1'b1) ? din1 : 1'bZ;
// end
assign dout[1] =
(addrsel_g == 5'h11 && arbin[1] == 1'b1) ? din1 : 1'bZ;
assign dout[2] =
(addrsel_g == 5'h12 && arbin[2] == 1'b1) ? din1 : 1'bZ;
assign dout[3] =
(addrsel_g == 5'h13 && arbin[3] == 1'b1) ? din1 : 1'bZ;
assign dout[4] =
(addrsel_g == 5'h14 && arbin[4] == 1'b1) ? din1 : 1'bZ;
assign dout[5] =
(addrsel_g == 5'h15 && arbin[5] == 1'b1) ? din1 : 1'bZ;
assign dout[6] =
(addrsel_g == 5'h16 && arbin[6] == 1'b1) ? din1 : 1'bZ;
assign dout[7] =
(addrsel_g == 5'h17 && arbin[7] == 1'b1) ? din1 : 1'bZ;
assign dout[8] =
(addrsel_g == 5'h18 && arbin[8] == 1'b1) ? din1 : 1'bZ;
assign dout[9] =
(addrsel_g == 5'h19 && arbin[9] == 1'b1) ? din1 : 1'bZ;
assign dout[10] =
(addrsel_g == 5'h1a && arbin[10] == 1'b1) ? din1 : 1'bZ;
assign dout[11] =
(addrsel_g == 5'h1b && arbin[11] == 1'b1) ? din1 : 1'bZ;
assign dout[12] =
(addrsel_g == 5'h1c && arbin[12] == 1'b1) ? din1 : 1'bZ;
assign dout[13] =
(addrsel_g == 5'h1d && arbin[13] == 1'b1) ? din1 : 1'bZ;
assign dout[14] =
(addrsel_g == 5'h1e && arbin[14] == 1'b1) ? din1 : 1'bZ;
assign dout[15] =
(addrsel_g == 5'h1f && arbin[15] == 1'b1) ? din1 : 1'bZ;
assign frameo_n[0] =
(addrsel_g == 5'h10 && arbin[0] == 1'b1) ? frame1_n : 1'bZ;
assign frameo_n[1] =
(addrsel_g == 5'h11 && arbin[1] == 1'b1) ? frame1_n : 1'bZ;
assign frameo_n[2] =
(addrsel_g == 5'h12 && arbin[2] == 1'b1) ? frame1_n : 1'bZ;
assign frameo_n[3] =
(addrsel_g == 5'h13 && arbin[3] == 1'b1) ? frame1_n : 1'bZ;
assign frameo_n[4] =
(addrsel_g == 5'h14 && arbin[4] == 1'b1) ? frame1_n : 1'bZ;
assign frameo_n[5] =
(addrsel_g == 5'h15 && arbin[5] == 1'b1) ? frame1_n : 1'bZ;
assign frameo_n[6] =
(addrsel_g == 5'h16 && arbin[6] == 1'b1) ? frame1_n : 1'bZ;
assign frameo_n[7] =
(addrsel_g == 5'h17 && arbin[7] == 1'b1) ? frame1_n : 1'bZ;
assign frameo_n[8] =
(addrsel_g == 5'h18 && arbin[8] == 1'b1) ? frame1_n : 1'bZ;
assign frameo_n[9] =
(addrsel_g == 5'h19 && arbin[9] == 1'b1) ? frame1_n : 1'bZ;
assign frameo_n[10] =
(addrsel_g == 5'h1a && arbin[10] == 1'b1) ? frame1_n : 1'bZ;
assign frameo_n[11] =
(addrsel_g == 5'h1b && arbin[11] == 1'b1) ? frame1_n : 1'bZ;
assign frameo_n[12] =
(addrsel_g == 5'h1c && arbin[12] == 1'b1) ? frame1_n : 1'bZ;
assign frameo_n[13] =
(addrsel_g == 5'h1d && arbin[13] == 1'b1) ? frame1_n : 1'bZ;
assign frameo_n[14] =
(addrsel_g == 5'h1e && arbin[14] == 1'b1) ? frame1_n : 1'bZ;
assign frameo_n[15] =
(addrsel_g == 5'h1f && arbin[15] == 1'b1) ? frame1_n : 1'bZ;
assign valido_n[0] =
(addrsel_g == 5'h10 && arbin[0] == 1'b1) ? vald1_n : 1'bZ;
assign valido_n[1] =
(addrsel_g == 5'h11 && arbin[1] == 1'b1) ? vald1_n : 1'bZ;
assign valido_n[2] =
(addrsel_g == 5'h12 && arbin[2] == 1'b1) ? vald1_n : 1'bZ;
assign valido_n[3] =
(addrsel_g == 5'h13 && arbin[3] == 1'b1) ? vald1_n : 1'bZ;
assign valido_n[4] =
(addrsel_g == 5'h14 && arbin[4] == 1'b1) ? vald1_n : 1'bZ;
assign valido_n[5] =
(addrsel_g == 5'h15 && arbin[5] == 1'b1) ? vald1_n : 1'bZ;
assign valido_n[6] =
(addrsel_g == 5'h16 && arbin[6] == 1'b1) ? vald1_n : 1'bZ;
assign valido_n[7] =
(addrsel_g == 5'h17 && arbin[7] == 1'b1) ? vald1_n : 1'bZ;
assign valido_n[8] =
(addrsel_g == 5'h18 && arbin[8] == 1'b1) ? vald1_n : 1'bZ;
assign valido_n[9] =
(addrsel_g == 5'h19 && arbin[9] == 1'b1) ? vald1_n : 1'bZ;
assign valido_n[10] =
(addrsel_g == 5'h1a && arbin[10] == 1'b1) ? vald1_n : 1'bZ;
assign valido_n[11] =
(addrsel_g == 5'h1b && arbin[11] == 1'b1) ? vald1_n : 1'bZ;
assign valido_n[12] =
(addrsel_g == 5'h1c && arbin[12] == 1'b1) ? vald1_n : 1'bZ;
assign valido_n[13] =
(addrsel_g == 5'h1d && arbin[13] == 1'b1) ? vald1_n : 1'bZ;
assign valido_n[14] =
(addrsel_g == 5'h1e && arbin[14] == 1'b1) ? vald1_n : 1'bZ;
assign valido_n[15] =
(addrsel_g == 5'h1f && arbin[15] == 1'b1) ? vald1_n : 1'bZ;
assign arbout[0] =
(addrsel_g != 5'h10 && arbin[0] == 1'b1) ? 1'b1 : 1'b0;
assign arbout[1] =
(addrsel_g != 5'h11 && arbin[1] == 1'b1) ? 1'b1 : 1'b0;
assign arbout[2] =
(addrsel_g != 5'h12 && arbin[2] == 1'b1) ? 1'b1 : 1'b0;
assign arbout[3] =
(addrsel_g != 5'h13 && arbin[3] == 1'b1) ? 1'b1 : 1'b0;
assign arbout[4] =
(addrsel_g != 5'h14 && arbin[4] == 1'b1) ? 1'b1 : 1'b0;
assign arbout[5] =
(addrsel_g != 5'h15 && arbin[5] == 1'b1) ? 1'b1 : 1'b0;
assign arbout[6] =
(addrsel_g != 5'h16 && arbin[6] == 1'b1) ? 1'b1 : 1'b0;
assign arbout[7] =
(addrsel_g != 5'h17 && arbin[7] == 1'b1) ? 1'b1 : 1'b0;
assign arbout[8] =
(addrsel_g != 5'h18 && arbin[8] == 1'b1) ? 1'b1 : 1'b0;
assign arbout[9] =
(addrsel_g != 5'h19 && arbin[9] == 1'b1) ? 1'b1 : 1'b0;
assign arbout[10] =
(addrsel_g != 5'h1a && arbin[10] == 1'b1) ? 1'b1 : 1'b0;
assign arbout[11] =
(addrsel_g != 5'h1b && arbin[11] == 1'b1) ? 1'b1 : 1'b0;
assign arbout[12] =
(addrsel_g != 5'h1c && arbin[12] == 1'b1) ? 1'b1 : 1'b0;
assign arbout[13] =
(addrsel_g != 5'h1d && arbin[13] == 1'b1) ? 1'b1 : 1'b0;
assign arbout[14] =
(addrsel_g != 5'h1e && arbin[14] == 1'b1) ? 1'b1 : 1'b0;
assign arbout[15] =
(addrsel_g != 5'h1f && arbin[15] == 1'b1) ? 1'b1 : 1'b0;
assign busy1_n = (arbout != arbin) ? 1'b1 : ~addrsel[4];
assign okstep = (arbout == arbin) ? 1'b1 : 1'b0;
always @(posedge reset)
begin
if (reset == 1'b1)
begin
addrsel <= 5'b0;
addrfsr <= 6'b0;
arbena <= 1'b0;
end
end
always @(posedge clock)
begin
frame1_n <= frame_n;
frame2_n <= frame1_n;
busy_n <= busy1_n;
din1 <= din;
vald1_n <= valid_n | ~busy_n ;
if (reset == 1'b0)
begin
if (frame2_n != frame1_n && frame1_n == 1'b1)
begin // frame is now inactive
addrsel <= 5'b0; // clear the address register
addrfsr <= 6'b0; // clear the address flag reg.
arbena <= 1'b0;
end
else
begin
if (addrsel[4] == 1'b1 && frameo_n[addrsel[3:0]] == 1'b1)
arbena <= 1'b1;
end
if (frame1_n != frame_n && frame_n == 1'b0)
addrfsr <= 6'b11_1111;
if (addrfsr[5:4] == 2'b10)
addrsel <= {addrsf[0],addrsf[1],addrsf[2],addrsf[3],addrsf[4]};
if (addrfsr[4] == 1'b1) addrsf <= (addrsf << 1) | { 4'b0, din1 };
if (addrfsr[5] == 1'b1) addrfsr <= addrfsr << 1;
end
end
endmodule //rtslice
module rtslicef(reset,clock,frame_n,valid_n,din,
iarbin,arbout,arbhead,okstep,
dout,busy_n,valido_n,frameo_n);
input reset,clock,frame_n,valid_n,din, arbhead;
output busy_n,okstep;
input [15:0] iarbin;
output [15:0] arbout,dout,valido_n;
inout [15:0] frameo_n;
reg [4:0] addrsf, addrsel;
reg [5:0] addrfsr;
reg din1, busy_n, frame1_n, frame2_n, vald1_n, arbena;
wire [15:0] dout;
wire [15:0] arbin;
wire busy1_n;
wire [4:0] addrsel_g;
assign arbin = (arbhead == 1'b1) ? 16'hffff : iarbin;
assign addrsel_g = (arbena == 1'b1) ? addrsel : 5'h0;
assign dout[0] =
(addrsel_g == 5'h10 && arbin[0] == 1'b1) ? din1 : 1'bZ;
assign dout[1] =
(addrsel_g == 5'h11 && arbin[1] == 1'b1) ? din1 : 1'bZ;
assign dout[2] =
(addrsel_g == 5'h12 && arbin[2] == 1'b1) ? din1 : 1'bZ;
assign dout[3] =
(addrsel_g == 5'h13 && arbin[3] == 1'b1) ? din1 : 1'bZ;
assign dout[4] =
(addrsel_g == 5'h14 && arbin[4] == 1'b1) ? din1 : 1'bZ;
assign dout[5] =
(addrsel_g == 5'h15 && arbin[5] == 1'b1) ? din1 : 1'bZ;
assign dout[6] =
(addrsel_g == 5'h16 && arbin[6] == 1'b1) ? din1 : 1'bZ;
assign dout[7] =
(addrsel_g == 5'h17 && arbin[7] == 1'b1) ? din1 : 1'bZ;
// stuck at x
assign dout[8] =
// (addrsel_g == 5'h18 && arbin[8] == 1'b1) ? din1 : 1'bZ;
(addrsel_g == 5'h18 && arbin[8] == 1'b1) ? 1'bx : 1'bZ;
assign dout[9] =
(addrsel_g == 5'h19 && arbin[9] == 1'b1) ? din1 : 1'bZ;
assign dout[10] =
(addrsel_g == 5'h1a && arbin[10] == 1'b1) ? din1 : 1'bZ;
assign dout[11] =
(addrsel_g == 5'h1b && arbin[11] == 1'b1) ? din1 : 1'bZ;
assign dout[12] =
(addrsel_g == 5'h1c && arbin[12] == 1'b1) ? din1 : 1'bZ;
assign dout[13] =
(addrsel_g == 5'h1d && arbin[13] == 1'b1) ? din1 : 1'bZ;
assign dout[14] =
(addrsel_g == 5'h1e && arbin[14] == 1'b1) ? din1 : 1'bZ;
assign dout[15] =
(addrsel_g == 5'h1f && arbin[15] == 1'b1) ? din1 : 1'bZ;
assign frameo_n[0] =
(addrsel_g == 5'h10 && arbin[0] == 1'b1) ? frame1_n : 1'bZ;
assign frameo_n[1] =
(addrsel_g == 5'h11 && arbin[1] == 1'b1) ? frame1_n : 1'bZ;
assign frameo_n[2] =
(addrsel_g == 5'h12 && arbin[2] == 1'b1) ? frame1_n : 1'bZ;
assign frameo_n[3] =
(addrsel_g == 5'h13 && arbin[3] == 1'b1) ? frame1_n : 1'bZ;
assign frameo_n[4] =
(addrsel_g == 5'h14 && arbin[4] == 1'b1) ? frame1_n : 1'bZ;
assign frameo_n[5] =
(addrsel_g == 5'h15 && arbin[5] == 1'b1) ? frame1_n : 1'bZ;
assign frameo_n[6] =
(addrsel_g == 5'h16 && arbin[6] == 1'b1) ? frame1_n : 1'bZ;
assign frameo_n[7] =
(addrsel_g == 5'h17 && arbin[7] == 1'b1) ? frame1_n : 1'bZ;
assign frameo_n[8] =
(addrsel_g == 5'h18 && arbin[8] == 1'b1) ? frame1_n : 1'bZ;
assign frameo_n[9] =
(addrsel_g == 5'h19 && arbin[9] == 1'b1) ? frame1_n : 1'bZ;
assign frameo_n[10] =
(addrsel_g == 5'h1a && arbin[10] == 1'b1) ? frame1_n : 1'bZ;
assign frameo_n[11] =
(addrsel_g == 5'h1b && arbin[11] == 1'b1) ? frame1_n : 1'bZ;
assign frameo_n[12] =
(addrsel_g == 5'h1c && arbin[12] == 1'b1) ? frame1_n : 1'bZ;
assign frameo_n[13] =
(addrsel_g == 5'h1d && arbin[13] == 1'b1) ? frame1_n : 1'bZ;
assign frameo_n[14] =
(addrsel_g == 5'h1e && arbin[14] == 1'b1) ? frame1_n : 1'bZ;
assign frameo_n[15] =
(addrsel_g == 5'h1f && arbin[15] == 1'b1) ? frame1_n : 1'bZ;
assign valido_n[0] =
(addrsel_g == 5'h10 && arbin[0] == 1'b1) ? vald1_n : 1'bZ;
assign valido_n[1] =
(addrsel_g == 5'h11 && arbin[1] == 1'b1) ? vald1_n : 1'bZ;
assign valido_n[2] =
(addrsel_g == 5'h12 && arbin[2] == 1'b1) ? vald1_n : 1'bZ;
assign valido_n[3] =
(addrsel_g == 5'h13 && arbin[3] == 1'b1) ? vald1_n : 1'bZ;
assign valido_n[4] =
(addrsel_g == 5'h14 && arbin[4] == 1'b1) ? vald1_n : 1'bZ;
assign valido_n[5] =
(addrsel_g == 5'h15 && arbin[5] == 1'b1) ? vald1_n : 1'bZ;
assign valido_n[6] =
(addrsel_g == 5'h16 && arbin[6] == 1'b1) ? vald1_n : 1'bZ;
assign valido_n[7] =
(addrsel_g == 5'h17 && arbin[7] == 1'b1) ? vald1_n : 1'bZ;
assign valido_n[8] =
(addrsel_g == 5'h18 && arbin[8] == 1'b1) ? vald1_n : 1'bZ;
assign valido_n[9] =
(addrsel_g == 5'h19 && arbin[9] == 1'b1) ? vald1_n : 1'bZ;
assign valido_n[10] =
(addrsel_g == 5'h1a && arbin[10] == 1'b1) ? vald1_n : 1'bZ;
assign valido_n[11] =
(addrsel_g == 5'h1b && arbin[11] == 1'b1) ? vald1_n : 1'bZ;
assign valido_n[12] =
(addrsel_g == 5'h1c && arbin[12] == 1'b1) ? vald1_n : 1'bZ;
assign valido_n[13] =
(addrsel_g == 5'h1d && arbin[13] == 1'b1) ? vald1_n : 1'bZ;
assign valido_n[14] =
(addrsel_g == 5'h1e && arbin[14] == 1'b1) ? vald1_n : 1'bZ;
assign valido_n[15] =
(addrsel_g == 5'h1f && arbin[15] == 1'b1) ? vald1_n : 1'bZ;
assign arbout[0] =
(addrsel_g != 5'h10 && arbin[0] == 1'b1) ? 1'b1 : 1'b0;
assign arbout[1] =
(addrsel_g != 5'h11 && arbin[1] == 1'b1) ? 1'b1 : 1'b0;
assign arbout[2] =
(addrsel_g != 5'h12 && arbin[2] == 1'b1) ? 1'b1 : 1'b0;
assign arbout[3] =
(addrsel_g != 5'h13 && arbin[3] == 1'b1) ? 1'b1 : 1'b0;
assign arbout[4] =
(addrsel_g != 5'h14 && arbin[4] == 1'b1) ? 1'b1 : 1'b0;
assign arbout[5] =
(addrsel_g != 5'h15 && arbin[5] == 1'b1) ? 1'b1 : 1'b0;
assign arbout[6] =
(addrsel_g != 5'h16 && arbin[6] == 1'b1) ? 1'b1 : 1'b0;
assign arbout[7] =
(addrsel_g != 5'h17 && arbin[7] == 1'b1) ? 1'b1 : 1'b0;
assign arbout[8] =
(addrsel_g != 5'h18 && arbin[8] == 1'b1) ? 1'b1 : 1'b0;
assign arbout[9] =
(addrsel_g != 5'h19 && arbin[9] == 1'b1) ? 1'b1 : 1'b0;
assign arbout[10] =
(addrsel_g != 5'h1a && arbin[10] == 1'b1) ? 1'b1 : 1'b0;
assign arbout[11] =
(addrsel_g != 5'h1b && arbin[11] == 1'b1) ? 1'b1 : 1'b0;
assign arbout[12] =
(addrsel_g != 5'h1c && arbin[12] == 1'b1) ? 1'b1 : 1'b0;
assign arbout[13] =
(addrsel_g != 5'h1d && arbin[13] == 1'b1) ? 1'b1 : 1'b0;
assign arbout[14] =
(addrsel_g != 5'h1e && arbin[14] == 1'b1) ? 1'b1 : 1'b0;
assign arbout[15] =
(addrsel_g != 5'h1f && arbin[15] == 1'b1) ? 1'b1 : 1'b0;
assign busy1_n = (arbout != arbin) ? 1'b1 : ~addrsel[4];
assign okstep = (arbout == arbin) ? 1'b1 : 1'b0;
always @(posedge reset)
begin
if (reset == 1'b1)
begin
addrsel <= 5'b0;
addrfsr <= 6'b0;
arbena <= 1'b0;
end
end
always @(posedge clock)
begin
frame1_n <= frame_n;
frame2_n <= frame1_n;
busy_n <= busy1_n;
din1 <= din;
vald1_n <= valid_n | ~busy_n ;
if (reset == 1'b0)
begin
if (frame1_n != frame_n && frame_n == 1'b0)
addrfsr <= 6'b11_1111;
if (frame2_n != frame1_n && frame1_n == 1'b1)
begin // frame is now inactive
addrsel <= 5'b0; // clear the address register
addrfsr <= 6'b0; // clear the address flag reg.
arbena <= 1'b0;
end
else
begin
if (addrsel[4] == 1'b1 && frameo_n[addrsel[3:0]] == 1'b1)
arbena <= 1'b1;
end
if (addrfsr[5:4] == 2'b10)
addrsel <= {addrsf[0],addrsf[1],addrsf[2],addrsf[3],addrsf[4]};
if (addrfsr[4] == 1'b1) addrsf <= (addrsf << 1) | { 4'b0, din1 };
if (addrfsr[5] == 1'b1) addrfsr <= addrfsr << 1;
end
end
endmodule //rtslicef
一、ip spec 理解
1.管脚图
2.信号列表
该路由器端口有5个输入分别为:
- din[15:0]为用户输入信号,可以选择16个通道中任何一个通道进行信号输入;
- clock为时钟信号;reset_n复位信号
- frame_n[15:0]为输入信号的传输状态信号,默认拉高,例如通道6有信号输入即din[5]时,frame_n[5]拉低开始信号传输,din[5]最后一bit时拉高frame_n[5],表示传输结束;
- valid_n[15:0]为数据位状态信号,同样和din通道对应,协议规定当发送pad时必须拉高,发送data时拉低
- dout_n[15:0]为输出信号,输出信号只包含数据位,输出端口与输入端口无关联,如可以从5端口输入,12端口输出
- frameo_n[15:0]为输出信号的传输状态信号,默认拉高,例如通道6有信号输出即dout[5]时,frameo_n[5]拉低开始信号传输,dout[5]最后一bit时拉高frameo_n[5],表示传输结束;
- valido_n[15:0]为数据位状态信号,同样和dout通道对应,协议规定发送data时拉低
- busy_n为通道状态信号,当通道被占用时,拉低一个周期
3.时序图
以上为其复位协议时序图,有以下几点需要注意:
1.复位时,reset_n为低电平,frame_n和valid_n为高电平
2.有效复位至少保持1个clk
3.复位后至少等待15个时钟周期后才可以发送数据
以上为输入信号时序图,有以下几点需要注意:
din信号:
1.din[i]中的i表示输入地址,din第一段4bit的数据表示输出地址(低位开始)
2.地址传输完毕后拉高进入隔离段
3.隔离段结束后开始传输数据(低位开始)
frame_n信号:
1.下降沿指示packet的第一位数据
2.上升沿指示packet的最后一位数据
valid_n信号:
1.其在din的地址输入时间段可为任意值x
2.在隔离段pad拉高
3.其拉低时表示数据有效,因此在payload段若其拉高,则din数据无效
4.数据输入完毕后拉高
输出信号时序图如上,比较简单,当valido_n和frameo_n均为低时数据有效,除了packet最后一位输出数据时frameo_n为高 。 其中当busy_n拉低时,valido_n将在下一个周期拉高,而busy_n控制逻辑将在后面说明
二、确定验证计划验证点
验证策略:白盒测试+随机、定向case测试
验证计划:
验证点 | 详细描述 | case类型 |
时钟以及复位信号 | 1、不同频率下,时钟工作 2、复位信号为低时复位,复位后工作 3、工作后复位 | 1、随机case 2、3、定向case |
单通道正常收发数据 | 1、16个通道混合收发数据功能,同一时刻覆盖所有通道 2、固定输入通道连续多笔数据发送不同通道,固定输出通道连续多笔数据输入 3、16输入输出通道顺序、乱序遍历输入输出 4、改变数据包长度以及pad长度 5、进对上述行交叉 | 1346随机case 25定向case |
异常情况 | 1、同时向同一输出端口发送不同数据 2、设置pad以及数据的大小超过边界 | 12定向case |
三、环境搭建以及smoke case test
接下来开始进行sv环境搭建,最基础的功能需要有发送包文件tr,激励生成gen,激励驱动drv,激励检测mon,激励对比scb,测试case test_case以及顶层文件top
3.1.1 interface
首先是最简单基础的interface,读完dut后我们理清楚输入输出信号,创建接口interface
其中default后面表示输入输出都有延迟,更符合实际情况,这点可以从波形看出,略与clk上升沿不同
3.1.2 top顶层文件
接下来将dut例化与interface连接,例化base_test,加入波形生成函数,生成全局时钟,只要在test_base中加入reset函数就实现最基础的时钟 复位信号生成。内容为:
- 例化dut,test
- 生成时钟
- 调用波形生成函数,生成fsdb文件供verdi查看波形
3.1.3 transaction
transaction中为din所包含的数据,地址以及部分控制信号,包括包对比函数,供scoreboard调用,copy函数供其他组件调用,display函数用于debug,具体内容总结如下:
- 包含输入变量并进行约束
- compare函数进行包对比,供别人调用
- copy函数供别人调用进行深复制
- display函数将每个产生的包打印出来进行debug
其中i_addr为输入地址,o_addr为源地址,payload为数据队列,队列大小限制在1到15个8bit数,pad_size为中间输入周期的pad持续时间,持续时间需要大于5(后面讨论),设置约束为5到15个周期。并且需要注意在别的地方调用compare函数时需要提前声明并初始化对应的tr,同时compare函数返回的值为0或1。
3.1.4 generator
generator负责生成随机化过的数据包,并将其传输给driver,具体内容:
- 产生随机化的包并将其通过mailbox传输给driver
需要注意的是这里使用了port_id进行控制,如果pord_id被顶层赋值不为-1则令tr中的输入地址i_addr 等于port_id,而顶层port_id是0-15满足输入地址随机化要求
3.1.5 driver
接下来是driver的书写,这里一般涉及到dut信号的时序以及数据传输设计,较为复杂,实现功能为:
- 收到gen传递过来的包,并将其中的数据缓存下来驱动到dut上,并将相应输入控制信号对应设置
- 将驱动后的包打包发送给scoreboard与mon监控到的包进行对比,注意此时是因为该lab比较简单,没有对应reference model,正常过程应该是reference model产生结果与mon监控到的dut输出进行对比
注意此时用了几个for循环,因为我们din输入是一位一位单bit输入,因此需要每一位进行驱动,此时在第61行动用了旗语,因为在env中我们同时例化声明了16个driver进行工作,为了防止不同的driver往同个输出通道写数据,因此使用了旗语来控制。
3.1.6 monitor
monitor的作用是监控dut行为,主要内容为:
- 进行dut行为监控,把dut输出存到例化的tr中,并传输给scoreboard
这个代码控制稍微复杂一点,get_payload函数中首先在红框里做了一个检测,检测到信号从1拉低时,跳出循环执行下面黄色框的代码,其中for循环中没有进行i++,因为实际逻辑是采样到数据才会加1,而当没触发绿框控制语句时,执行下面蓝色的push进队列的操作,当frameo_n拉高,执行上面的push进队列的操作并结束任务。
还有一个问题,就是mon怎么知道o_addr是哪个的问题,我刚开始做是会drv发送的包发送给mon一份告诉mon o_addr是哪一个,这样稍显复杂,自己写不知道怎么去简化,而参考代码中直接例化了16个mon,监控16个通道,就是不管你要从那个通道输出我都可以看到,这样就不用考虑包对应的o_addr的问题
3.1.7 scoreboard
scoreboard是为了进行仿真结果分析,具体内容为:
- 收到mon以及drv发送来的包并进行对比,输出对比结果
- 定义covergroup以及进行覆盖率收集
scoreboard设计的比较巧妙,可以设想一下两个方向来的包时间有先后,并且每个方向都有大量的包传送过来,如何对应输入输出并对比结果变成了一个问题,因为硬件dut输出耗时,代码先拿到一个monitor监测的包,然后把所有的drv发过来的包全部放到tr的动态队列tr_check中,再通过寻找索引的方式将这个包找出来进行对比,输出对比结果。
可以思考一下,如果直接收gen生成的包,或者先把drv的包收到在收mon的包是否会出错
直接收gen生成的包将会发生一个问题,因为gen不耗时一下子把所有包都发过来了,必然会有o_addr相同的包,这时边无法用o_addr去区分包,同样的先收drv的包也会造成这个情况,只有先收第一批drv发送到dut上被mon监测后的包在收drv发过来的包进行对比才能避免这种情况,因为drv使用旗语确定在这个时间内只有一笔数据被写到其中每一个o_addr,同时思考后不难看出drv中的63行也只能写到drv()函数后面保证发送的是写成功的
3.1.8 env
env是将所有的组件有机组合在一起并实现完整流程,具体内容:
- 例化,创建各组件的对象,并连接mailbox并附参数
- 创建完整仿真流程并等待仿真结束
可以思考一下,为什么scb只创建一个,可以创建16个对不同输出通道进行对比吗
不可以这么做,多个scoreboard采用大致的逻辑,根据时间先后将不同o_addr的包放到同一个scb中在进行对比,也能完成对比,但是会增加很多代码量,drv就必须要能看到包里的o_addr并传送给对应的scb,但是代码中同一个drv[i]与gen[i]连接并有相同的i_addr,而具有相同的i_addr的drv[i]却具有不同的o_addr,drv[i]中的mailbox无法与scb固定连接。
换句话说drv用i_addr区分,而scb用o_addr区分,无法统一
3.1.9 test_base
test_base里做了env的例化,调用env函数进行仿真,并进行reset复位
注意'1,'b1,1'b1的差别,其中'1是各位全为1,如图中16位全为1。
3.2 心得体会以及错误总结
心得体会:
1、文件放置顺序以及对象声明例化要保持从上至下顺序的原则,即本层用到的变量,方法一定在本层或上层能找得到或者直接调用,在本层进行对象创建一定保持该对象对应类所在得的文件在本层文件之前,上层与下层重复赋值的变量,顶层会覆盖下面的层次
例如此时的run_num以及DEBUG_ON下层是能看得见的,且如果下层即使也赋值了也是没用的
文件的include顺序也应满足从上至下顺序原则,例如generator中例化了transaction因此须在transaction以后
2、一些控制信号最好在顶层进行赋值以及覆盖,底层实现模块中使用if语句进行条件选择如何执行,当然常规的做法其实是写一个config配置文件,由于本文中参数较少便没有进行这种操作,当项目较大时这样会方便很多,且复用性高
例子上是调试信息以及仿真时间的控制
上面为生成包的输入地址的控制
3、函数的封装一定要简洁明了,可以多用函数,顶层直接调用函数,这样程序可读性强,尽量修改代码时只在test case中进行部分参数的修改,base_test尽量覆盖可能多的随机情况
错误总结:
1、各种new带来的错误
对象的new在函数中要放在最前面,否则会报错
只当作句柄使用时指向对象时可以不new,如果是对其对象中的变量赋值等则必须要new
上述代码中的i_tr以及o_tr均没有new,只指向maailbox送过来的tr,而mailbox送过来的tr必须要new 进行空间分配
2、this的使用
SV中遇到同名变量需要索引时,可以对变量名加上前缀来区分,如super,this和local;如果不加前缀,SV会自动采用就近原则,索引最近的变量。因此涉及到父类子类以及函数传参给类中的变量时需要添加this,就是你觉得如果就近原则可能会引起错误的情况下你就可以加,当然只能在class内部加this,program以及module是不行的
3、scoreboard收发包以及对比的逻辑
在正常验证过程中,对比双方一般是referencemodel以及monitor采集到的dut的响应,要注意收发时序逻辑,谁快谁慢,可以将收到的包都放进队列进行对比,避免对比不及。
四、随机case以及定向case收集覆盖率
在随机了50000次之后功能覆盖率达到99.97%,深刻体会到后面的覆盖率提升有多困难,3000次就90%了,到最后50000次才到99.97%。接下来可以增添定向case使覆盖率达到100%,由于还有别的事情要做,这个lab也比较简单就不往下推进了,有兴趣的可以做做交流一下。