2011年5月28日 星期六

UVM Hierarchical Connections

TLM1的連接形態


blocking vs nonblocking

從UVM user guide抽出的文句整理

blocking—
1. the tasks block execution until they complete;
2. they are not allowed to fail.
3. There is no mechanism for any blocking call to terminate abnormally or
otherwise alter the flow of control.
4, They simply wait until the request is satisfied.
5. In a timed system, this means that time may pass between the time the call was initiated and the time it returns.

nonblocking
1. call returns immediately.
2. call guarantee that the call returns in the same delta cycle in which it was issued, that is, without consuming any time, not even a single delta cycle.
3. In UVM, nonblocking calls are modeled as functions.

uvm_tlm_fifo使用blocking的另一個例子

這是從http://testbench.in/UT_14_UVM_TLM_2.html
uvm_tlm_4.tar
的例子


`include "uvm.svh"
import uvm_pkg::*;

`include "consumer.sv"
`include "producer.sv"

class env extends uvm_env;
producer p;
consumer c;
uvm_tlm_fifo #(int) f;

function new(string name = "env");
super.new(name);
p = new("producer", this);
c = new("consumer", this);
f = new("fifo", this);
endfunction

function void connect();
p.put_port.connect(f.put_export);
c.get_port.connect(f.get_export);
endfunction

task run();
#1000 global_stop_request();
endtask

endclass


module test;
env e;

initial begin
e = new();
run_test();
end

endmodule

class producer extends uvm_component;

uvm_blocking_put_port#(int) put_port;

function new(string name, uvm_component p = null);
super.new(name,p);
put_port = new("put_port", this);

endfunction

task run;

int randval;

for(int i = 0; i < 10; i++)
begin
#10;
randval = $urandom_range(11,100);
`uvm_info("producer", $sformatf("sending %d",randval), UVM_MEDIUM)
put_port.put(randval);
end
endtask

endclass : producer


class consumer extends uvm_component;

uvm_blocking_get_port#(int) get_port;

function new(string name, uvm_component p = null);
super.new(name,p);
get_port = new("get_port", this);
endfunction

task run;

int val;

forever
begin
get_port.get(val);
`uvm_info("consumer", $sformatf("receiving %d", val), UVM_MEDIUM)
end

endtask

endclass : consumer

2011年5月27日 星期五

改成blocking mode 的uvm_tlm_fifo

這個例子是從UVM example中挖出來的
原例是用non-blocking來實作的
此例把它改成blocking 的實作方法


module test;
import uvm_pkg::*;

class packet;
int i;
function new(int v); i=v; endfunction
endclass

class producer extends uvm_component;
uvm_blocking_put_port #(packet) data_out;
function new(string name, uvm_component parent);
super.new(name,parent);
data_out = new("data_out", this);
endfunction
task run();
packet p, pp;
#1 p=new(0);

//不用try_put了,直接put就好了,因為是blocking
//while(data_out.try_put(p)) begin
for (int i=0;i<10;i++) begin
#10 p = new(p.i);
$display("%0t: put data %0d", $time, p.i);
data_out.put(p);
end

//$display("try_put status return: %0d", p.i);

//$display("%0t: waiting to do a valid blocking put = %d", $time, p.i);
data_out.put(p);
$display("%0t: last blocking put = %d", $time, p.i);
endtask
endclass

class consumer extends uvm_component;
uvm_blocking_get_port #(packet) data_in;

function new(string name, uvm_component parent);
super.new(name,parent);
data_in = new("data_in", this);
endfunction

task run();
packet p;
/*
#100; // fifo will fill up
$display("%0t: getting one", $time);
data_in.get(p);
$display("%0t: valid recieved data %0d", $time, p.i);
#100; // let the blocking put succeed
*/
//因為blocking所以直接等待就可以了
forever begin
data_in.get(p);
$display("%0t: recieved data %0d", $time, p.i);
#10;
end

//$display ("%0t:; wait next data", $time);

/*
#100;

//data_in.get(p);
$display("%0t: got last recieved data %0d", $time, p.i);
*/
endtask

endclass

producer prod = new("prod", null);
consumer cons = new("cons", null);

uvm_tlm_fifo #(packet) fifo = new("fifo", null, 10);

initial begin
prod.data_out.connect(fifo.put_export);
cons.data_in.connect(fifo.get_export);

fork
run_test();
repeat(30) begin
$display("%0t: Show TOP FIFO level %0d of %0d", $time, fifo.used(), fifo.size());
#10;
end
#5us global_stop_request();
join
end

endmodule

轉移OVM VIP到UVM

如果我要將用OVM寫的testbench
改成用UVM

最好的方法是用手動更改
這樣會比較好debug
找出那裏改錯了

基本上將
OVM --> UVM

ovm --> uvm

`message -> `uvm_info
此處語法可參考下面
`uvm_info(get_type_name(), $psprintf("Transfer collected :\n%s",
trans_collected.sprint()), UVM_FULL)


就可以了
目前我的case這樣就可以動了
其他還沒遇到


如果不採用手動
有一個寫好的perl
放在
http://bbs.eetop.cn/viewthread.php?tid=282024
請自行下載

在我自己的case上
遇到不少問題

uvm_tlm_fifo在uvm library中的範例

這個例子是從UVM example中挖出來的
此例是用non-blocking來實作的

原來的example上的說明有誤
我將它作了一些修改

module test;
import uvm_pkg::*;

class packet;
int i;
function new(int v); i=v; endfunction
endclass

class producer extends uvm_component;
uvm_put_port #(packet) data_out;
function new(string name, uvm_component parent);
super.new(name,parent);
data_out = new("data_out", this);
endfunction
task run();
packet p, pp;
#1 p=new(0);

while(data_out.try_put(p)) begin
$display("%0t: try put data %0d", $time, p.i);
#10 p = new(p.i+1);
end

$display("try_put status return: %0d", p.i);

$display("%0t: waiting to do a valid non-blocking put = %d", $time, p.i);
data_out.put(p);
$display("%0t: last non-blocking put = %d success", $time, p.i);
endtask
endclass

class consumer extends uvm_component;
uvm_get_port #(packet) data_in;

function new(string name, uvm_component parent);
super.new(name,parent);
data_in = new("data_in", this);
endfunction

task run();
packet p;
#100; // fifo will fill up
$display("%0t: getting one", $time);
data_in.get(p);
$display("%0t: valid recieved data %0d", $time, p.i);
#100; // let the blocking put succeed

while(data_in.try_get(p)) begin
$display("%0t: try recieved data %0d", $time, p.i);
#10;
end

endtask

endclass

producer prod = new("prod", null);
consumer cons = new("cons", null);

uvm_tlm_fifo #(packet) fifo = new("fifo", null, 10);

initial begin
prod.data_out.connect(fifo.put_export);
cons.data_in.connect(fifo.get_export);

fork
run_test();
repeat(30) begin
$display("%0t: Show TOP FIFO level %0d of %0d", $time, fifo.used(), fifo.size());
#10;
end
#5us global_stop_request();
join
end

endmodule

蘇軾:和子由澠池懷舊

我很喜歡的一首詩

人生到處知何似,恰似飛鴻踏雪泥;

泥上偶然留指爪,鴻飛那復計東西。

老僧已死成新塔,壞壁無由見舊題;

往日崎嶇還記否,路長人困蹇驢嘶。

uvm_tlm_fifo的实现简单模型

一個轉貼的例子
從http://electron64.blog.163.com/blog/static/1060339702011293395214/

這是uvm_tlm_fifo內部機制的原型

我們可以看到uvm_tlm_fifo內部的機制是採用mailbox來實作的

在tlm_fifo中,运行了两个进程,这两个进程通过mailbox进行同步。他们分别对应了get_t()和put_t()。 可以通过`define VERBOSE看tlm_fifo中函数调用状况。

1 /**

2 ** tlm_fifo.sv

3 ** 说明: 通过简单的模型来阐述 UVM/OVMTLM uvm_tlm_fifo

4 ** 的基本原理。直接编译运行即可。

5 ** 作者:http://electron64.blog.163.com

6 */

7 virtual class port_base#(type T=int) ; // 构造一个抽象类

8 typedef port_base#(T) this_type;

9 protected this_type port_handle; // 申明一个对象句柄(指针)

10

11 virtual task get_t(output T trans);

12 endtask // 虚函数,get_portget_imp都必须以它为基类

13 virtual task put_t(T trans); // 虚函数,put_portput_imp都必须以它为基类

14 endtask

15 function void connect(this_type port); // connect仅仅是实现对象句柄的赋值

16 port_handle = port;

17 endfunction // connect

18

19 endclass // port_base

20

21 class get_port#(type T=int) extends port_base#(T);

22 virtual task get_t(output T trans);

23 port_handle.get_t(trans);

24 endtask // get_t

25 endclass // get_port

26

27 class get_imp#(type T=int, type IMP=int) extends port_base#(T);

28 local IMP m_imp; // imp表示具体实现get_t()函数的对象句柄。

29 function new(IMP imp);

30 m_imp = imp;

31 endfunction // new

32

33 virtual task get_t(output T trans);

34 m_imp.get_t(trans); // 调用实现对象对应的get_t()函数

35 endtask // get_t

36

37 endclass // get_imp

38

39 class put_port#(type T=int) extends port_base#(T);

40 virtual task put_t(T trans);

41 port_handle.put_t(trans);

42 endtask // put_t

43 endclass // put_port

44

45 class put_imp#(type T=int, type IMP=int) extends port_base#(T);

46 local IMP m_imp; // imp表示具体实现put_t()函数的对象句柄。

47 function new(IMP imp);

48 m_imp = imp;

49 endfunction // new

50

51 virtual task put_t(T trans);

52 m_imp.put_t(trans); // 调用实现对象对应的put_t()函数

53 endtask // put_t

54

55 endclass // put_imp

56

57 class tlm_fifo#(type T=int);

58 typedef tlm_fifo#(T) this_type;

59 put_imp#(T,this_type) put_export;

60 get_imp#(T,this_type) get_export;

61

62 local mailbox #(T) m;

63

64 function new();

65 m = new(1);

66 put_export = new(this);

67 get_export = new(this);

68 endfunction // new

69

70 virtual task put_t(T trans);

71 m.put(trans);

72 `ifdef VERBOSE

73 $display("[tlm_fifo.put_t]: Generate transaction:%d", trans);

74 `endif

75 endtask // put_t

76

77 virtual task get_t(output T trans);

78 m.get(trans);

79 `ifdef VERBOSE

80 $display("[tlm_fifo.get_t]: Get transaction:%d", trans);

81 `endif

82 endtask // get_t

83

84 endclass // tlm_fifo

85

86

87 class producer;

88 put_port#(int) m_put_port;

89 function new();

90 m_put_port = new();

91 endfunction // new

92

93 task run(int num=10);

94 int trans;

95 for(int i=0; i i++) begin // 顺序产生10int类型的transaction.

96 trans = $random;

97 #5 m_put_port.put_t(trans);

98 $display("@%0t [Producer]: Generate transaction:<%0d>", $time, trans);

99 end

100 endtask // run

101 endclass // producer

102

103 class consumer;

104 get_port#(int) m_get_port;

105 function new();

106 m_get_port = new();

107 endfunction // new

108

109 task run(int num=10);

110 int t;

111 t = -1;

112 for(int i=0; i i++) begin // 顺序产生10int类型的transaction.

113 #i m_get_port.get_t(t);

114 $display("@%0t [Consumer]: Get transaction:@{%0d}@", $time, t);

115 end

116 endtask // run

117 endclass // consumer

118

119 module top;

120 producer p;

121 consumer c;

122 tlm_fifo f;

123 initial begin

124 p = new();

125 c = new();

126 f = new();

127 c.m_get_port.connect(f.get_export); //通过句柄赋值进行连接

128 p.m_put_port.connect(f.put_export);

129 fork

130 c.run();

131 p.run();

132 join

133 #10 $finish;

134 end

135 endmodule

136