此前,我们通过tester/put&get port/driver将激励和测试平台分割开来,但是我们并没有将data stimulus从structure中分离出来。tester需要创建新的transaction,并将其送至测试平台,这意味着tester需要选择transaction的顺序,并经其送至测试平台。我们可以通过override transaction type控制data的随机化,但是我们必须重写整个tester来改变transaction的发送数量,顺序等。一个好的测试平台需要将order of transaction(the stimulus)和测试平台组件testbench structure分离开来。
class sequence_item extends uvm_sequence_item; //uvm_sequence_item扩展自uvm_transaction
`uvm_object_utils(sequence_item);
function new(string name = "");
super.new(name);
endfunction : new
rand byte unsigned A;
rand byte unsigned B;
rand operation_t op;
shortint unsigned result; //新增result 变量
......
endclass : sequence_item
class driver extends uvm_driver #(sequence_item);
`uvm_component_utils(driver)
virtual tinyalu_bfm bfm;
function void build_phase(uvm_phase phase);
if(!uvm_config_db #(virtual tinyalu_bfm)::get(null, "*","bfm", bfm))
`uvm_fatal("DRIVER", "Failed to get BFM")
endfunction : build_phase
task run_phase(uvm_phase phase);
sequence_item cmd;
forever begin : cmd_loop
shortint unsigned result; //get_next_item一直阻塞至sequencer将sequence item送入端口
seq_item_port.get_next_item(cmd); //和put/get_port、analysis port类似方式获取数据
bfm.send_op(cmd.A, cmd.B, cmd.op, result);
cmd.result = result;
seq_item_port.item_done(); //将数据通过send_op送到BFM,并将result数据传回
end : cmd_loop //通过调用item_done函数告诉sequencer,可以开始发送下一个sequence item
endtask : run_phase
function new (string name, uvm_component parent);
super.new(name, parent);
endfunction : new
endclass : driver
class env extends uvm_env;
`uvm_component_utils(env);
sequencer sequencer_h; //在环境中声明sequencer
coverage coverage_h;
scoreboard scoreboard_h;
driver driver_h;
command_monitor command_monitor_h;
result_monitor result_monitor_h;
function new (string name, uvm_component parent);
super.new(name,parent);
endfunction : new
function void build_phase(uvm_phase phase);
// stimulus
sequencer_h = new("sequencer_h",this);
driver_h = driver::type_id::create("driver_h",this);
// monitors
command_monitor_h = command_monitor::type_id::create("command_monitor_h",this);
result_monitor_h = result_monitor::type_id::create("result_monitor",this);
// analysis
coverage_h = coverage::type_id::create ("coverage_h",this);
scoreboard_h = scoreboard::type_id::create("scoreboard",this);
endfunction : build_phase
function void connect_phase(uvm_phase phase);
driver_h.seq_item_port.connect(sequencer_h.seq_item_export);
//调用driver中的sequence_item_port的connect函数,并将sequencer中的seq_item_export作为参数传入
//不需要使用TLM FIFO链接sequencer和dirver
command_monitor_h.ap.connect(coverage_h.analysis_export);
command_monitor_h.ap.connect(scoreboard_h.cmd_f.analysis_export);
result_monitor_h.ap.connect(scoreboard_h.analysis_export);
endfunction : connect_phase
endclass : env
class fibonacci_sequence extends uvm_sequence #(sequence_item); //扩展自uvm_sequencem,并传入sequence item类型的变量
`uvm_object_utils(fibonacci_sequence);
function new(string name = "fibonacci");
super.new(name);
endfunction : new
task body(); //在task函数中实现sequence的产生
byte unsigned n_minus_2=0;
byte unsigned n_minus_1=1;
sequence_item command;
command = sequence_item::type_id::create("command"); //创建sequence_item用于存储数据
start_item(command); //阻塞,直至uvm_sequencer准备好接受sequence item
command.op = rst_op; //解除阻塞之后,先进行DUT的Reset
finish_item(command); //阻塞,直到driver完成当前命令
`uvm_info("FIBONACCI", " Fib(01) = 00", UVM_MEDIUM);
`uvm_info("FIBONACCI", " Fib(02) = 01", UVM_MEDIUM);
for(int ff = 3; ff<=14; ff++) begin //循环多次,产生固定序列的uvm sequence item
start_item(command); // wait sequencer
command.A = n_minus_2; // update data & opcode
command.B = n_minus_1;
command.op = add_op;
finish_item(command); // wait driver's item_done
n_minus_2 = n_minus_1; // loop after driver has send last sequence item
n_minus_1 = command.result; // driver 将计算结果写回了result变量,取出来累加
`uvm_info("FIBONACCI", $sformatf("Fib(%02d) = %02d", ff, n_minus_1),
UVM_MEDIUM);
end
endtask : body
endclass : fibonacci_sequence
virtual class tinyalu_base_test extends uvm_test;
env env_h; //例化env,其中包括sequencer
sequencer sequencer_h; //test中同样声明sequencer
function void build_phase(uvm_phase phase);
env_h = env::type_id::create("env_h",this);
endfunction : build_phase
function void end_of_elaboration_phase(uvm_phase phase);
sequencer_h = env_h.sequencer_h; //将test中的sequencer指向env中的sequencer
endfunction : end_of_elaboration_phase
function new (string name, uvm_component parent);
super.new(name,parent);
endfunction : new
endclas
class fibonacci_test extends tinyalu_base_test;
`uvm_component_utils(fibonacci_test);
task run_phase(uvm_phase phase);
fibonacci_sequence fibonacci; //
fibonacci = new("fibonacci");
phase.raise_objection(this);
fibonacci.start(sequencer_h);
phase.drop_objection(this);
endtask : run_phase
function new(string name, uvm_component parent);
super.new(name,parent);
endfunction : new
endclass
class runall_sequence extends uvm_sequence #(uvm_sequence_item);
`uvm_object_utils(runall_sequence);
protected reset_sequence reset;
protected maxmult_sequence maxmult;
protected random_sequence random;
protected sequencer sequencer_h;
protected uvm_component uvm_component_h;
function new(string name = "runall_sequence");
super.new(name);
uvm_component_h = uvm_top.find("*.env_h.sequencer_h"); //uvm_top.find返回环境中的sequencer componentk类型
if (uvm_component_h == null)
`uvm_fatal("RUNALL SEQUENCE", "Failed to get the sequencer")
if (!$cast(sequencer_h, uvm_component_h)) //将找到的component转换为sequecer,以备后续使用
`uvm_fatal("RUNALL SEQUENCE", "Failed to cast from uvm_component_h.")
reset = reset_sequence::type_id::create("reset");
maxmult = maxmult_sequence::type_id::create("maxmult");
random = random_sequence::type_id::create("random");
endfunction : new
task body(); //顺序执行三个sequence
reset.start(sequencer_h); //将find返回的sequencer传递给各个sequence的start函数
maxmult.start(sequencer_h);
random.start(sequencer_h);
endtask : body
endclass : runall_sequence
class full_test extends tinyalu_base_test;
`uvm_component_utils(full_test);
runall_sequence runall_seq;
task run_phase(uvm_phase phase);
runall_seq = new("runall_seq");
phase.raise_objection(this);
runall_seq.start(null); //调用virtual时,不需要传入sequencer
phase.drop_objection(this); //virtual通过uvm_top.find函数,自己寻找sequencer
endtask : run_phase
function new (string name, uvm_component parent);
super.new(name,parent);
endfunction : new
endclass
class parallel_sequence extends uvm_sequence #(uvm_sequence_item);
`uvm_object_utils(parallel_sequence);
protected reset_sequence reset;
protected short_random_sequence short_random;
protected fibonacci_sequence fibonacci;
function new(string name = "parallel_sequence");
super.new(name);
reset = reset_sequence::type_id::create("reset");
fibonacci = fibonacci_sequence::type_id::create("fibonacci");
short_random = short_random_sequence::type_id::create("short_random");
endfunction : new
task body();
reset.start(m_sequencer);
fork
fibonacci.start(m_sequencer);
short_random.start(m_sequencer);
join
endtask : body
endclass : parallel_sequence
class parallel_test extends tinyalu_base_test;
`uvm_component_utils(parallel_test);
parallel_sequence parallel_h;
function new(string name, uvm_component parent);
super.new(name,parent);
parallel_h = new("parallel_h");
endfunction : new
task run_phase(uvm_phase phase);
phase.raise_objection(this);
parallel_h.start(sequencer_h);
phase.drop_objection(this);
endtask : run_phase
endclass
得到的结果如下:
其中fibonacci和random sequence交替运行,并且两个进程之间没有相互干扰,fabinacci依然按照此前的值进行累加。
the uvm primer的学习暂时告一段段落,后面按照<