路科V0P26P29-MCDT测试结构-实现激励发生器-监测器和检查器-顶层环境和测试用例

MCDT测试结构

MCDT测试平台结构

  • 要区分哪部分是硬件、哪部分是软件
    • HW : 待测的设计
    • SW : 测试环境
    • 软硬件之间交互通过interface
  • 要清楚验证环境的各个组件之间的位置层次关系和它们之间是否有数据通信
    • 验证组件之间的通信都是基于事务级的传送;
    • 验证组件和硬件的通信必须依赖接口,通过硬件时序才能实现;
  • 理解仿真如何开始运转,各个验证组件如何工作,最后仿真如何结束

一些要注意的细节:

  • channel initiator 和 channel monitor一一对应;
  • initiator和monitor被封装在了agent中;
  • 由于arbiter不需要与下行握手,所以只外置了mcdt monitor而不需要mcdt responder;
  • 所有的monitor都将监测到的数据送到mcdt checker;
  • MCDT checker内部例化了若干FIFO,是为了接收从MCDT的输入端和输出端的数据;
  • 由于checker输入端和输出端FIFO中存放的数据类型一致,也为数据比较带来了方便;

激励发生器

监测器

比较器

实现激励发生器

实现 channel stimulator

  • 数据事务:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    class chnl_trans;
    rand bit[31:0] data[];
    rand int ch_id;
    rand int pkt_id;
    rand int data_nidles;
    rand int pkt_nidles;
    bit rsp;
    local static int obj_id=0;

    constraint cstr {
    soft data.size inside {[4:8]};
    foreach (data[i])
    data[i] == 'hC000_0000 + (this.ch_id << 24) + (this.pkt_id << 8) + i;
    soft ch_id == 0;
    soft pkt_id == 0;
    data_nidles inside {[0:2]};
    pkt_nidles inside {[1:10]};
    };

    function new();
    this.obj_id++;
    endfunction

    function chnl_trans clone();
    chnl_trans c = new();
    c.data = this.data;
    c.ch_id = this.ch_id;
    c.pkt_id = this.pkt_id;
    c.data_nidles = this.data_nidles;
    c.pkt_nidles = this.pkt_nidles;
    c.rsp = this.rsp;
    return c;
    endfunction
    endclass: chnl_trans
  • 驱动激励的组件:
    • chnl_initiator的作用是从chnl_generator中获取chnl_trans的数据,并将其驱动到接口chnl_interface上面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
class chnl_initiator;
local string name;
local virtual chnl_intf intf;
mailbox #(chnl_trans) req_mb;
mailbox #(chnl_trans) rsp_mb;

function new(string name = "chnl_initiator");
this.name = name;
endfunction

//从外部获得虚拟指针,并赋值给自己的虚接口成员变量
function void set_interface(virtual chnl_intf intf);
if(intf == null)
$error("interface handle is NULL, please check if target interface has been intrantiated");
else
this.intf = intf;
endfunction

task run();
this.driver();
endtask

task drive();
chnl_trans req, rsp;
@(posedge intf.rstn); //系统复位信号
forever begin
this.req_mb.get(req); // 获取激励
this.chnl_write(req); // 写出到接口
rsp = req.clone(); //发送完毕之后克隆一份
rsp.rsp = 1;
this.rsp_mb.put(rsp);
end
endtask

task chnl_write(input chnl_trans t);
foreach(t.data[i]) begin
@(posedge intf.clk);
intf.ch_valid <= 1; //在时钟上升沿置为有效
intf.ch_data <= t.data[i];
@(negedge intf.clk);
wait(intf.ch_ready == 'b1);
$display("%0t: channel initiator [%s] sent data %x", $time, name, t.data[i]);
repeat(t.data_nidles) chnl_idle(); //插入空闲周期
end
repeat(t.pkt_nidles) chnl_idle();
endtask

task chnl_idle();
@(posedge intf.clk);
intf.ch_valid <= 0;
intf.ch_data <= 0;
endtask
endclass: chnl_initiator
  • chnl_generator
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
class chnl_generator;
rand int pkt_id = -1;
rand int ch_id = -1;
rand int data_nidles = -1;
rand int pkt_nidles = -1;
rand int data_size = -1;
rand int ntrans = 10;
mailbox #(chnl_trans) req_mb;
mainbox #(chnl_trans) rsp_mb;

constraint cstr {
soft ch_id == -1;
soft pkt_id == -1;
soft data_size == -1;
soft data_nidles == -1;
soft pkt_nidles == -1;
soft ntrans == 10;
}

function new();
this.req_mb = new();
this.rsp_mb = new();
endfunction

// 调用了多次创建数据事务,并且发送给chnl_initiator的任务send_trans
task run();
repeat(ntrans) send_trans;
run_stop_flags.put();
endtask

// 生成transaction并put进入maibox
task send_trans();
chnl_trans req, rsp;
req = new();
assert(req.randomize with {
local::ch_id >=0 -> ch_id == local::ch_id;
local::pkt_id >=0 -> pkt_id == local::pkt_id;
local::data_nidles >=0 -> data_nidles == local::data_nidles;
local::pkt_nidles >=0 -> pkt_nidles == local::pkt_nidles;
local::data_size >=0 -> data_size == local::data_size;
})
else
$fatal("[RNDFAIL] channel packet randomization failure!");
this.pkt_id++;
this.req_mb.put(req);
this.rsp_mb.get(rsp);
assert(rsp.rsp)
else $error("[RSPERR] %0t error response received!", $time);
endtask
endclass: chnl_generator

监测器和检查器

监测器

用户自定义结构体mon_data_t用来存放监测到的数据,被chnl_monitormcdt_monitor使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// chnl_monitor
typedef struct packed {
bit[31:0] data;
bit[1:0] id;
} mon_data_t;

class chnl_monitor;
local string name;
local virtual chnl_intf intf;
mailbox #(mon_data_t) mon_mb;
function new(string name = "chnl_monitor");
this.name = name;
endfunction

function void set_interface(virtual chnl_intf intf);
if(intf == null)
$error("interface handle is NULL, please check if target interface has been intrantiated");
else
this.intf = intf;
endfunction

task run();
this.mon_trans();
endtask
// 三个等号判断四值逻辑变量是否相等
task mon_trans();
mon_data_t m;
forever begin
@(posedge intf.clk iff (intf.ch_valid==='b1 && intf.ch_ready ==='b1));
m.data = intf.ch_data;
mon_mb.put(m);
$display("%0t %s channel monitor data %8x", $time, this.name, m.data);
end
endtask
endclass: chnl_monitor

再实现一个mcdt_monitor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// mcdt_monitor
class mcdt_monitor;
local string name;
local virtual mcdt_intf intf;
mailbox #(mon_data_t) mon_mb;
function new(string name = "mcdt_monitor");
this.name = name;
endfunction

function void set_interface(virtual mcdt_intf intf);
if(intf == null)
$error("interface handle is NULL, please check if target interface has been intrantiated");
else
this.intf = intf;
endfunction

task run();
this.mon_trans();
endtask

task mon_trans();
mon_data_t m;
forever begin
@(posedge intf.clk iff intf.mcdt_val==='b1);
m.data = intf.mcdt_data;
m.id = intf.mcdt_id;
mon_mb.put(m);
$display("%0t %s mcdt monitor data %8x and id %0d", $time, this.name, m.data, m.id);
end
endtask
endclass: mcdt_monitor

检查器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// mcdt_checker
class mcdt_checker;
local string name;
local int error_count;
local int cmp_count;
mailbox #(mon_data_t) in_mbs[3];
mainbox #(mon_data_t) out_mb;

function new(string name = "mcdt_checker");
this.name = name;
foreach(this.in_mbs[i])
this.in_mbs[i] = new();
this.out_mb = new();
this.error_count = 0;
this.cmp_count = 0;
endfunction

task run();
this.do_compare();
endtask

// 每次从输出端out_mb中取出一个数据,然后通过id判断从哪个输入端获取数据,比较
task do_compare();
mon_data_t im, om;
forever begin
out_mb.get(m);
case(om.id)
0: in_mbs[0].get(im);
1: in_mbs[1].get(im);
2: in_mbs[2].get(im);
default: $fatal("id %0d is not available", om.id);
endcase
if(om.data != im.id) begin
this.error_count++;
$error("[CMPFAIL] Compared failed! mcdt out data %8x ch_id %0d is not equal with channel in data %8x", om.data, om.id, im.data);
end
else begin
$display("[CMPSUCD] Compared success! mcdt out data %8x ch_id %0d is equal with channel in data %8x", om.data, om.id, im.data);
end
this.cmp_count++;
end
endtask
endclass: mcdt_checker

顶层环境和测试用例

实现顶层环境1-agent

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class chnl_agent;
local string name;
chnl_initiator init;
chnl_monitor mon;
virtual chnl_intf vif;

function new(string name = "chnl_agent");
this.name = name;
this.init = new({name, ".init"});
this.mon = new({name, ".mon"});
endfunction

// 自身获得虚接口,然后传递给ini和mon
function void set_interface(virtual chnl_intf vif);
this.vif = vif;
init.set_interface(vif);
mon.set_interface(vif);
endfunction

task run();
fork:
init.run();
mon.run();
join
endtask
endclass: chnl_agent

实现顶层环境2-mcdt_root_test

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// mcdt_root_test
// 包含3个gen,3个agent,1个checker
class mcdt_root_test;
chnl_generator gen[3];
chnl_agent agents[3];
mcdt_monitor mcdt_mon;
mcdt_checker chker;
protected string name;
event gen_stop_e;
function new(string name = "mcdt_root_test");
this.name = name;
this.chker = new();

foreach(agents[i]) begin
this.agents[i] = new($sformatf("agent%0d", i));
this.gen[i] = new();
this.agents[i].init.req_mb = this.gen[i].req_mb;
this.agents[i].init.rsp_mb = this.gen[i].rsp_mb;
this.agents[i].mon.mon_mb = this.chker.in_mbs[i];
end

this.mcdt_mon = new();
this.mcdt_mon.mon_mb = this.chker.out_mb;
$display("%s instantiated and connected objects", this.name);
endfunction

virtual task gen_stop_callback();
endtask

// 等待三个gen都发送完激励数据后,交还钥匙给旗语run_stop_flags
virtual task run_stop_callback();
$diplay("run_stop_callback enterred");
$display("%s: wait for all generators have generated and tranferred transcations", this.name);
run_stop_flags.get(3);
$finish();
endtask

virtual task run();
this.do_config(); //决定产生多少个怎样的随机数据
fork
agents[0].run();
agents[1].run();
agents[2].run();
mcdt_mon.run();
chker.run();
join_none
fork : gen_threads
gen[0].run();
gen[1].run();
gen[2].run();
join
run_stop_callback();
endtask

virtual function void set_interface(virtual chnl_intf ch0_vif,
virtual chnl_intf ch1_vif,
virtual chnl_intf ch2_vif,
virtual mcdt_intf mcdt_vif);
agents[0].set_interface(ch0_vif);
agents[1].set_interface(ch1_vif);
agents[2].set_interface(ch2_vif);
mcdt_mon.set_interface(mcdt_vif);
endfunction

virtual function void do_config();
// 在这里配置gen的参数,用一个子类的方法去实现他
endfunction
endclass: mcdt_root_test

实现测试用例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class mcdt_basic_test extends mcdt_root_test;
function new(string name = "mcdt_basic_test");
super.new(name);
endfunction

virtual function void do_config();
super.do_config();
assert(gen[0].randomize() with {ntrans==100; data_nidles==0; pkt_nidles==0; data_size==8;})
else $fatal("[RNDFAIL] gen[0] randomize failed");
assert(gen[1].randomize() with {ntrans==50; data_nidles inside {[1:2]}; pkt_nidles inside {[3:5]}; data_size==6;})
else $fatal("[RNDFAIL] gen[1] randomize failed");
assert(gen[2].randomize() with {ntrans==80; data_nidles inside {[0:1]}; pkt_nidles inside {[1:2]}; data_size==32;})
else $fatal("[RNDFAIL] gen[2] randomize failed");
endfunction
endclass: mcdt_basic_test

路科V0P26P29-MCDT测试结构-实现激励发生器-监测器和检查器-顶层环境和测试用例

https://dustofstars.github.io/IC验证/路科V0/路科v0p26p29-mcdt测试结构-实现激励发生器-监测器和检查器-顶层环境和测试用例/

作者

Gavin

发布于

2022-05-16

更新于

2022-05-16

许可协议

CC BY-NC-SA 4.0

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×