要求1.1
画出验证化简框图,理解实验验证环境,明白功能测试点的展开位置。
要求1.2 功能点测试
代码完整性测试
该部分不需要修改代码,直接编译所给的文件,但是编译文件若使用Questa需要注意一定的顺序,使用VCS则需要注意文件列表 filelist.f 中文件的排列顺序。
在Verdi中显示波形如下图所示:
从图中可见,通道0,1,2以一定的优先级顺序进行发送数据。这在实验0中的控制寄存器描述可知,bit(2:1)是优先级的设置位,0最高,3最低,复位值位3。在代码中可见,通道0,1,2的优先级依次设置为了0,1,2。
寄存器读写测试
测试内容:所有控制寄存器、状态寄存器的读写测试。
测试通过标准:读写值是否正确。
代码
class mcdf_reg_write_read_test extends mcdf_base_test;
function new(string name = "mcdf_reg_write_read_test");
super.new(name);
endfunction
task do_reg();
bit[7:0] chnl_rw_addrs[] = '{`SLV0_RW_ADDR,`SLV1_RW_ADDR,`SLV2_RW_ADDR};
bit[7:0] chnl_ro_addrs[] = '{`SLV0_R_ADDR,`SLV1_R_ADDR,`SLV2_R_ADDR};
int pwidth = `PAC_LEN_WIDTH + `PRIO_WIDTH + 1;
// pwidth = 6,1<<6 - 1 = 63 = 6'b111111 = 32'h0000003f
bit[31:0] check_pattern[] = '{((1<<pwidth)-1),0,((1<<pwidth)-1)};
bit[31:0] wr_val, rd_val;
// read and write test for controlling register
foreach(chnl_rw_addrs[i]) begin
foreach(check_pattern[i]) begin
wr_val = check_pattern[i];
this.write_reg(chnl_rw_addrs[i],wr_val);
this.read_reg(chnl_rw_addrs[i],rd_val);
void'(this.diff_value(wr_val,rd_val));
end
end
// read test for state register
foreach(chnl_ro_addrs[i]) begin
this.read_reg(chnl_ro_addrs[i],rd_val);
end
// send IDLE command
this.idle_reg();
endtask
endclass:mcdf_reg_write_read_test
仿真结果
在Verdi查看波形,对于控制寄存器的读写测试,数据依次为32’h0000003f, 32’h00000000, 32’h0000003f。接着是对状态寄存器的读测试,数据三次固定随机化为32’h00000020。对于空闲周期的显示,在波形图中没有进行显示得到,但在仿真文件数据中可见。
寄存器稳定性测试
测试要求:对控制寄存器的保留位进行非法的读写操作,对状态寄存器的保留位进行非法写入操作,并将数据读出,验证是否能成功写入。
代码
与寄存器读写测试差不多,不同的是写入的数据是非法的。
class mcdf_reg_illegal_access_test extends mcdf_base_test;
function new(string name = "mcdf_reg_illegal_access_test");
super.new(name);
endfunction
task do_reg();
bit[7:0] chnl_rw_addrs[] = '{`SLV0_RW_ADDR,`SLV1_RW_ADDR,`SLV2_RW_ADDR};
bit[7:0] chnl_ro_addrs[] = '{`SLV0_R_ADDR,`SLV1_R_ADDR,`SLV2_R_ADDR};
int pwidth = `PAC_LEN_WIDTH + `PRIO_WIDTH + 1;
bit[31:0] check_pattern[] = '{3{32'hffff_ffc0}};
bit[31:0] wr_val, rd_val;
// illegal write and read for controlling register
foreach(chnl_rw_addrs[i]) begin
foreach(check_pattern[i]) begin
wr_val = check_pattern[i];
this.write_reg(chnl_rw_addrs[i],wr_val);
this.read_reg(chnl_rw_addrs[i],rd_val);
void'(this.diff_value(wr_val,rd_val));
end
end
// illegal write for state register
foreach(chnl_ro_addrs[i]) begin
wr_val = 32'hffff_ff00;
this.write_reg(chnl_ro_addrs[i],wr_val);
this.read_reg(chnl_ro_addrs[i],rd_val);
void'(this.diff_value(0,rd_val));
end
// send IDLE command
this.idle_reg();
endtask
endclass:mcdf_reg_illegal_access_test
仿真结果
从结果图中,可以看见对于非法写入,读出来的数据值是寄存器默认值。
数据通道开关测试
测试要求:失能控制状态寄存器的使能端en,测试在此状态下能否进行数据写入。
将监测的信号en传入到checker中,添加了do_channel_disable_test(int id)任务,以及在tb.sv中添加了数据通道连接部分,更改了set_interface函数的配置问题,以及在checker的run函数中调用添加的任务。最后可以仿真程序,没有在仿真文件中打印最后的summary信息。
代码
// mcdf_checker中添加
task do_channel_disable_check(int id);
forever begin
@(posedge this.mcdf_vif.clk iff (this.mcdf_vif.rstn && this.mcdf_vif.mon_ck.chnl_en[id]===0));
if(this.chnl_vifs[id].mon_ck.ch_valid===1 && this.chnl_vifs[id].mon_ck.ch_ready===1)
rpt_pkg::rpt_msg("[CHKERR]",
$sformatf("ERROR! %0t when channel disabled, ready signal raised when valid high",$time),
rpt_pkg::ERROR,
rpt_pkg::TOP);
end
endtask
// checker 中添加通道开关任务
task run();
fork
this.do_channel_disable_check(0);
this.do_channel_disable_check(1);
this.do_channel_disable_check(2);
this.do_compare();
this.refmod.run();
join
endtask
// 在tb.sv中 mcdf interface monitoring MCDF ports and signals
assign mcdf_if.chnl_en[0] = tb.dut.ctrl_regs_inst.slv0_en_o;
assign mcdf_if.chnl_en[1] = tb.dut.ctrl_regs_inst.slv1_en_o;
assign mcdf_if.chnl_en[2] = tb.dut.ctrl_regs_inst.slv2_en_o;
仿真结果
可以看到,成功比较了一百次信息,且比较的通道为没有失能的数据通道2。
优先级测试
测试要求:为不同数据通道配置相同或不同的优先级,在通道使能的情况下进行测试。
测试标准:优先级相同时,应该采用轮询机制进行接收;优先级不同时,按照优先级顺序进行接收。
1.优先级不同时的测试
对应于代码完整性测试的代码部分,将优先级设置为不同的数值,进行测试。
task do_reg();
bit[31:0] wr_val, rd_val;
// slv0 with len=8, prio=1, en=1
wr_val = (1<<3)+(1<<1)+1;
this.write_reg(`SLV0_RW_ADDR, wr_val);
this.read_reg(`SLV0_RW_ADDR, rd_val);
void'(this.diff_value(wr_val, rd_val, "SLV0_WR_REG"));
// slv1 with len=16, prio=2, en=1
wr_val = (2<<3)+(2<<1)+1;
this.write_reg(`SLV1_RW_ADDR, wr_val);
this.read_reg(`SLV1_RW_ADDR, rd_val);
void'(this.diff_value(wr_val, rd_val, "SLV1_WR_REG"));
// slv2 with len=32, prio=0, en=1
wr_val = (3<<3)+(0<<1)+1;
this.write_reg(`SLV2_RW_ADDR, wr_val);
this.read_reg(`SLV2_RW_ADDR, rd_val);
void'(this.diff_value(wr_val, rd_val, "SLV2_WR_REG"));
// send IDLE command
this.idle_reg();
endtask
如仿真结果图所示,通道数据发送顺序为优先级顺序,即2,0,1。
2.优先级相同时的测试(暂未解决)
在将三个数据通道的优先级均设置为0时,通过仿真来看,数据也是按照轮询仲裁的0,1,2进行发送的,但是并没有添加轮询仲裁机制,对代码的修改只是进行了优先级的设置。正确的做法,应该是加入轮询机制,但是在本次实验中,还未解决想明白。