2011年5月29日 星期日

關於uvm_analysis_port

Analysis Ports:

The uvm_analysis_port is a specialized TLM port whose interface consists of a single function, write().
The analysis port contains a list of analysis_exports that are connected to it.
When the component calls analysis_port.write(), the analysis_port cycles through the list and calls the write() method of each connected export.

















Analysis Exports

The implementation is write() via an analysis_export.
The uvm_subscriber base component can be used to simplify this operation,

class sub1 #(type T = simple_trans) extends uvm_subscriber #(T);
...
function void write(T t);
// Record coverage information of t.
endfunction
endclass


對比的UVM example 如下

/*


Walk through the test:
A thread *gen* will use an uvm_blocking_put_port to put a transaction.

A *conv* thread will use an uvm_blocking_put_port to put a transaction,an uvm_blocking_get_port to get a transactions, and an uvm_analysis_ port to a writte a transaction through it.

Another thread *bfm* will use an uvm_blocking_get_port to only get the transactions that has been sent by the other threads.

A *listener* will extends the uvm_subscriber, to implement the analysis port write function.

A *producer* component will use uvm_blocking_put_port and uvm_analysis_port and a uvm_tlm_fifo, to connect the *gen* and *conv* put, get and analysis ports through the fifo exports.

A *consumer* component will use uvm_blocking_put export and connect it directly to a fifo export, also will connect the *bfm* get port to the fifo export

At *top* env, the *producer*, *consumer*, and the the *listener* will be connected

*/


`include "uvm_macros.svh"


module test;

import uvm_pkg::*;

//----------------------------------------------------------------------
// class transaction
//----------------------------------------------------------------------
class transaction extends uvm_transaction;

rand int data;
rand int addr;

function string convert2string();
string s;
$sformat(s, "[ addr = %x, data = %x ]", addr, data);
return s;
endfunction

endclass

//----------------------------------------------------------------------
// component gen
//----------------------------------------------------------------------
class gen extends uvm_component;

uvm_blocking_put_port #(transaction) put_port;

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

task run;
transaction t;
string msg;

for(int i=0; i < 20; i++) begin
t = new();
///assert(t.randomize());
  /// 此處改成類似DMA的傳輸
t.addr = 32+i*2;
t.data = i*1024;
`uvm_info("gen", $sformatf("sending : %s", t.convert2string()), UVM_MEDIUM)
put_port.put(t);
end
endtask

endclass


//----------------------------------------------------------------------
// componenet conv
//----------------------------------------------------------------------
class conv extends uvm_component;

uvm_blocking_put_port #(transaction) put_port;
uvm_blocking_get_port #(transaction) get_port;
uvm_analysis_port #(transaction) cap;

function new(string name, uvm_component parent);
super.new(name, parent);
put_port = new("put_port", this);
get_port = new("get_port", this);
cap = new("analysis_port", this);
endfunction

task run;
transaction t;

forever begin
get_port.get(t);
cap.write(t); // uvm_analysis_port 呼叫write function,但這個write() is void
put_port.put(t);
end
endtask

endclass

//----------------------------------------------------------------------
// componenet bfm
//----------------------------------------------------------------------
class bfm extends uvm_component;

uvm_blocking_get_port #(transaction) get_port;

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

task run;
transaction t;

forever begin
get_port.get(t);
`uvm_info("bfm", $sformatf("receiving: %s", t.convert2string()),UVM_MEDIUM)
end
endtask

endclass

class listener extends uvm_subscriber #(transaction);
function new(string name, uvm_component parent);
super.new(name,parent);
endfunction // new

  // 真正的uvm_analysis_port所用到的write()是在此
function void write(input transaction t);
`uvm_info(m_name, $sformatf("Received: %s", t.convert2string()), UVM_MEDIUM)
endfunction // write
endclass // listener

//----------------------------------------------------------------------
// componenet producer
//----------------------------------------------------------------------
// begin codeblock producer
class producer extends uvm_component;

uvm_blocking_put_port #(transaction) put_port;
uvm_analysis_port #(transaction) pap; 

gen g;
conv c;
uvm_tlm_fifo #(transaction) f;

function new(string name, uvm_component parent);
super.new(name, parent);
put_port = new("put_port", this);
pap = new("analysis_port", this);
g = new("gen", this);
c = new("conv", this);
f = new("fifo", this);
endfunction

function void connect();
g.put_port.connect(f.blocking_put_export); // A
c.get_port.connect(f.blocking_get_export); // B
c.put_port.connect(put_port); // C
c.cap.connect(pap); //第一次analysis_port連結,此時為port對port
endfunction

endclass

//----------------------------------------------------------------------
// componenet consumer
//----------------------------------------------------------------------
class consumer extends uvm_component;

uvm_blocking_put_export #(transaction) put_export;

bfm b;
uvm_tlm_fifo #(transaction) f;

function new(string name, uvm_component parent);
super.new(name, parent);
put_export = new("put_export", this);
f = new("fifo", this);
b = new("bfm", this);
endfunction

function void connect();
put_export.connect(f.blocking_put_export);
b.get_port.connect(f.blocking_get_export);
endfunction

endclass

//----------------------------------------------------------------------
// componenet top
//----------------------------------------------------------------------
class top extends uvm_env;

producer p;
consumer c;
listener l;

function new(string name, uvm_component parent);
super.new(name, parent);
p = new("producer", this);
c = new("consumer", this);
l = new("listener", this);

// Connections may also be done in the constructor, if you wish
p.put_port.connect(c.put_export);
p.pap.connect(l.analysis_export); //這是第二次的analysis_port連結,此時連結到了uvm_subscriber
endfunction
task run;
begin
end
endtask

endclass

//----------------------------------------------------------------------
// environment env
//----------------------------------------------------------------------
class env extends uvm_env;
top t;

function new(string name = "env");
super.new(name);
t = new("top", this);
endfunction

task run;
#1000;
global_stop_request();
endtask

endclass

//----------------------------------------------------------------------
// module test
//----------------------------------------------------------------------
env e;

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

endmodule // test