ovm学习的一点小积累
时间:10-02
整理:3721RD
点击:
学习可能始于模仿。学习新的软件工具往往先要借助一些实例,有时也急于见到结果,看看到底能得到了什么?
我们先介绍一个OVM实例,类似的例子可在网上找得到。可与本例比较一下,看看有什么不同。由于篇幅所限,注释可能过于简洁。参见的部分可要认真阅读才会有好的收获哟。
从www.ovmworld.com网站下载的OVM框架工具里有很多实例,可供学习了解OVM之用。有空可以去看看,现在uvm出世之后 好像变为了http://www.verificationacademy.com/verification-methodology,以下实例是我当时学习的时候在“杜蕾斯”网站上面看到的
例
`include "ovm_macros.svh"
interface io_if();
logic [7:0] address;
logic [7:0] data_i;
logic [7:0] data_o;
logic rw_n;
modport memory_if(input address, input data_i,
output data_o, input rw_n);// DUT接口
modport test_if(output address, output data_i,
input data_o, output rw_n);// 测试模块接口,本文没有用到
endinterface
//===============================================
module memory(io_if.memory_if io, input bit clock);
reg [7:0] mem [0:255];
always @(negedge clock)
if(io.rw_n)
io.data_o<=mem[io.address];
else
mem[io.address]<=io.data_i;
endmodule
//===================================================
package my_pkg;
import ovm_pkg::*;
//〖原则〗验证程序中的事件要继承ovm_transaction:
class my_transaction extends ovm_transaction;//
rand logic [7:0] address;
rand logic [7:0] data_i;
rand logic rw_n;
function new (string name = "");
super.new(name);
endfunction: new
constraint c_address { address >= 0; address < 256; }//产生随机事件的约束条件
constraint c_data_i{ data_i>= 0; data_i< 256; }
virtual function void randomize_();//如果randomize()函数不能用时,用此函数
address = $random & 8'hff;//$random产生32bit随机数,这里只需要8bit
data_i= $random & 8'hff;
rw_n= $random & 1'b1;
endfunction
`ovm_object_utils_begin(my_transaction)//在程序中注册此事件
`ovm_field_int(address, OVM_ALL_ON + OVM_DEC)//
`ovm_field_int(data_i,OVM_ALL_ON + OVM_DEC)
`ovm_field_int(rw_n,OVM_ALL_ON + OVM_BIN)
`ovm_object_utils_end
endclass: my_transaction
//〖建议〗验证程序中连接DUT的驱动器可继承ovm_driver:
class my_driver extends ovm_driver;//
`ovm_component_utils(my_driver)//注册本类,这个宏的结尾没有符号;
virtual io_if v_io;//装载虚拟接口
ovm_get_port #(my_transaction) get_port;//装载与激励发生器通信的通道接口:
function new(string name, ovm_component parent);
super.new(name, parent);
//〖建议〗验证程序中可写一些ovm_report_info的语句供提示用:
ovm_report_info("", "Called my_driver::new");//在测试结果显示此函数被调用
endfunction: new
function void build;
super.build();
ovm_report_info("", "Called my_driver::build");
get_port = new("get_port", this);//初始化
endfunction : build
virtual task run;
ovm_report_info("", "Called my_driver::run");
forever
begin
my_transaction tx;
#100 get_port.get(tx);//从通道中取一个事件
ovm_report_info("",$psprintf("Driving cmd = %s, address = %2h, data_i = %2h",
(tx.rw_n ? "R" : "W"), tx.address, tx.data_i));
v_io.memory_if.address = tx.address;//送到DUT
v_io.memory_if.data_i= tx.data_i;
v_io.memory_if.rw_n= tx.rw_n;
end
endtask: run
endclass: my_driver
//〖建议〗一般用继承ovm_env的类包装验证程序中的事件处理器-元件
class my_env extends ovm_env;//
`ovm_component_utils(my_env)//注册本类
ovm_random_stimulus #(my_transaction) env_stimulus;//装载激励器
tlm_fifo#(my_transaction) env_fifo;//装载通道
my_driverenv_driver;//装载驱动器
function new(string name = "my_env", ovm_component parent = null);
super.new(name, parent);
ovm_report_info("", "Called my_env::new");
endfunction: new
virtual function void build;
super.build();
ovm_report_info("", "Called my_env::build");
env_stimulus = new("env_stimulus", this);//初始化激励器
env_fifo= new("env_fifo",this);//初始化通道
env_driver= new("env.driver",this);//初始化驱动器
endfunction: build
virtual function void connect;//设定连接关系
ovm_report_info("", "Called my_env::connect");
env_stimulus.blocking_put_port.connect(env_fifo.put_export);//激励器侧接口-放事件
env_driver.get_port.connect(env_fifo.get_export);//驱动器侧接口-取事件
endfunction: connect
virtual function void configure;//
ovm_report_info("", "Called my_env::configure");
env_stimulus.set_report_id_action("stimulus generation", OVM_NO_ACTION);//限制显示信息
endfunction: configure//你可删除上一行,看看有什么变化?
task run();
ovm_report_info("","Called my_env::run");
endtask: run
virtual function void report;
ovm_report_info("", "Called my_env::report");
endfunction: report
//在运行下面的run_test()函数时,以上函数将自动依次运行
endclass: my_env
endpackage: my_pkg
`timescale 1ns/1ps
module top;
import ovm_pkg::*;
import my_pkg::*;
parameter clock_cycle = 100;
bit clock;
io_if my_io();//装载接口
memory memory1(.io(my_io), .clock(clock));//装载DUT
//〖建议〗在验证程序顶级模块中一般采用继承ovm_test的类包装继承 ovm_env的类
class my_test extends ovm_test;
`ovm_component_utils(my_test)//注册本类
my_env top_env;//装载环境-top_env
function new(string name = "my_test", ovm_component parent = null);
super.new(name,parent);
ovm_report_info("", "Called my_test::new");
endfunction: new
virtual function void build;
super.build();
ovm_report_info("", "Called my_test::build");
top_env=new();//初始化
//〖建议〗在验证程序中可设定看门狗
set_global_timeout(3us);
endfunction: build
virtual function void connect;
ovm_report_info("", "Called my_test::connect");
top_env.env_driver.v_io = my_io;//连接虚拟接口到驱动器的物理接口
endfunction: connect
task run;
my_transaction tx;
tx = new();
ovm_report_info("", "Called my_test::run");
top_env.env_stimulus.generate_stimulus(tx, 20);//激励器产生20个事件
endtask: run
endclass: my_test
initial
run_test("my_test");//全球函数-验证程序的起始点
initial begin
clock=0;
forever begin
#(clock_cycle/2)
clock = ~clock;//产生时钟信号,供模拟器作比对用
end
end
endmodule: top
我们先介绍一个OVM实例,类似的例子可在网上找得到。可与本例比较一下,看看有什么不同。由于篇幅所限,注释可能过于简洁。参见的部分可要认真阅读才会有好的收获哟。
从www.ovmworld.com网站下载的OVM框架工具里有很多实例,可供学习了解OVM之用。有空可以去看看,现在uvm出世之后 好像变为了http://www.verificationacademy.com/verification-methodology,以下实例是我当时学习的时候在“杜蕾斯”网站上面看到的
例
`include "ovm_macros.svh"
interface io_if();
logic [7:0] address;
logic [7:0] data_i;
logic [7:0] data_o;
logic rw_n;
modport memory_if(input address, input data_i,
output data_o, input rw_n);// DUT接口
modport test_if(output address, output data_i,
input data_o, output rw_n);// 测试模块接口,本文没有用到
endinterface
//===============================================
module memory(io_if.memory_if io, input bit clock);
reg [7:0] mem [0:255];
always @(negedge clock)
if(io.rw_n)
io.data_o<=mem[io.address];
else
mem[io.address]<=io.data_i;
endmodule
//===================================================
package my_pkg;
import ovm_pkg::*;
//〖原则〗验证程序中的事件要继承ovm_transaction:
class my_transaction extends ovm_transaction;//
rand logic [7:0] address;
rand logic [7:0] data_i;
rand logic rw_n;
function new (string name = "");
super.new(name);
endfunction: new
constraint c_address { address >= 0; address < 256; }//产生随机事件的约束条件
constraint c_data_i{ data_i>= 0; data_i< 256; }
virtual function void randomize_();//如果randomize()函数不能用时,用此函数
address = $random & 8'hff;//$random产生32bit随机数,这里只需要8bit
data_i= $random & 8'hff;
rw_n= $random & 1'b1;
endfunction
`ovm_object_utils_begin(my_transaction)//在程序中注册此事件
`ovm_field_int(address, OVM_ALL_ON + OVM_DEC)//
`ovm_field_int(data_i,OVM_ALL_ON + OVM_DEC)
`ovm_field_int(rw_n,OVM_ALL_ON + OVM_BIN)
`ovm_object_utils_end
endclass: my_transaction
//〖建议〗验证程序中连接DUT的驱动器可继承ovm_driver:
class my_driver extends ovm_driver;//
`ovm_component_utils(my_driver)//注册本类,这个宏的结尾没有符号;
virtual io_if v_io;//装载虚拟接口
ovm_get_port #(my_transaction) get_port;//装载与激励发生器通信的通道接口:
function new(string name, ovm_component parent);
super.new(name, parent);
//〖建议〗验证程序中可写一些ovm_report_info的语句供提示用:
ovm_report_info("", "Called my_driver::new");//在测试结果显示此函数被调用
endfunction: new
function void build;
super.build();
ovm_report_info("", "Called my_driver::build");
get_port = new("get_port", this);//初始化
endfunction : build
virtual task run;
ovm_report_info("", "Called my_driver::run");
forever
begin
my_transaction tx;
#100 get_port.get(tx);//从通道中取一个事件
ovm_report_info("",$psprintf("Driving cmd = %s, address = %2h, data_i = %2h",
(tx.rw_n ? "R" : "W"), tx.address, tx.data_i));
v_io.memory_if.address = tx.address;//送到DUT
v_io.memory_if.data_i= tx.data_i;
v_io.memory_if.rw_n= tx.rw_n;
end
endtask: run
endclass: my_driver
//〖建议〗一般用继承ovm_env的类包装验证程序中的事件处理器-元件
class my_env extends ovm_env;//
`ovm_component_utils(my_env)//注册本类
ovm_random_stimulus #(my_transaction) env_stimulus;//装载激励器
tlm_fifo#(my_transaction) env_fifo;//装载通道
my_driverenv_driver;//装载驱动器
function new(string name = "my_env", ovm_component parent = null);
super.new(name, parent);
ovm_report_info("", "Called my_env::new");
endfunction: new
virtual function void build;
super.build();
ovm_report_info("", "Called my_env::build");
env_stimulus = new("env_stimulus", this);//初始化激励器
env_fifo= new("env_fifo",this);//初始化通道
env_driver= new("env.driver",this);//初始化驱动器
endfunction: build
virtual function void connect;//设定连接关系
ovm_report_info("", "Called my_env::connect");
env_stimulus.blocking_put_port.connect(env_fifo.put_export);//激励器侧接口-放事件
env_driver.get_port.connect(env_fifo.get_export);//驱动器侧接口-取事件
endfunction: connect
virtual function void configure;//
ovm_report_info("", "Called my_env::configure");
env_stimulus.set_report_id_action("stimulus generation", OVM_NO_ACTION);//限制显示信息
endfunction: configure//你可删除上一行,看看有什么变化?
task run();
ovm_report_info("","Called my_env::run");
endtask: run
virtual function void report;
ovm_report_info("", "Called my_env::report");
endfunction: report
//在运行下面的run_test()函数时,以上函数将自动依次运行
endclass: my_env
endpackage: my_pkg
`timescale 1ns/1ps
module top;
import ovm_pkg::*;
import my_pkg::*;
parameter clock_cycle = 100;
bit clock;
io_if my_io();//装载接口
memory memory1(.io(my_io), .clock(clock));//装载DUT
//〖建议〗在验证程序顶级模块中一般采用继承ovm_test的类包装继承 ovm_env的类
class my_test extends ovm_test;
`ovm_component_utils(my_test)//注册本类
my_env top_env;//装载环境-top_env
function new(string name = "my_test", ovm_component parent = null);
super.new(name,parent);
ovm_report_info("", "Called my_test::new");
endfunction: new
virtual function void build;
super.build();
ovm_report_info("", "Called my_test::build");
top_env=new();//初始化
//〖建议〗在验证程序中可设定看门狗
set_global_timeout(3us);
endfunction: build
virtual function void connect;
ovm_report_info("", "Called my_test::connect");
top_env.env_driver.v_io = my_io;//连接虚拟接口到驱动器的物理接口
endfunction: connect
task run;
my_transaction tx;
tx = new();
ovm_report_info("", "Called my_test::run");
top_env.env_stimulus.generate_stimulus(tx, 20);//激励器产生20个事件
endtask: run
endclass: my_test
initial
run_test("my_test");//全球函数-验证程序的起始点
initial begin
clock=0;
forever begin
#(clock_cycle/2)
clock = ~clock;//产生时钟信号,供模拟器作比对用
end
end
endmodule: top
谢谢小编的分享,我来顶一下!
小编的学习方法不错。谢谢分享。
好长啊,先顶后看
谢谢分享
谢谢分享
谢谢指导!
C++ 结合verilog
给小编赞一个
小编真有心
有点看不懂,先顶一个,慢慢看!