2011年7月2日 星期六

SVA 再了解(五)
























實際上,我們trace這個REQ的$rose,它的trigger 點是在CLK的edge上
,然後對REQ的上一個cycle到這個cycle的變化為rising時,視之為條件成立

SVA 再了解(四)

SVA 提供了 3 个内嵌函数,用于检查信号的边沿变化。

$rose(布尔表达式或信号名) 一個bit
当信号/表达式的最低位由 0 或 x 变为 1 时返回真值。

$fell(布尔表达式或信号名) 一個bit
当信号/表达式的最低位由 1 变为 0 或 x 时返回真值。

$stable(布尔表达式或信号名) 一個bit
当信号/表达式的最低位不发生变化时返回真值。

2011年7月1日 星期五

SVA 再了解(三)

使用序列的重复操作符进行检查

序列的重复操作符分为 3 类:连续重复,跳转重复和非连续重复。
“[*m]”为连续重复操作符。“a[*3]”表示 a 被连续重复 3 次,“a[*1:3]”表示 a 被
连续重复 1~3 次。连续重复的相邻两次重复之间只有一个时钟间隔。
連續訊號

“[->m]”为跳转重复操作符。“a[->3]”表示 a 被跳转重复 3 次,“a[->1:3]”表示 a
被跳转重复 1~3 次。跳转重复的每一次重复之前可以有任意个时钟周期的间隔。
像pulse或連續訊號

“[=m]”为非连续重复操作符。“a[=3]”表示 a 被非连续重复 3 次,“a[=1:3]”表示 a
被非连续重复 1~3 次。非连续重复的每一次重复之前可以有任意个时钟周期的间隔,最后一
次重复之后可以有任意个时钟周期的间隔。
像pulse一樣的,全部都是斷續的

property cons_rep_p;
@(posedge sclk) $rose(a) |-> ##1 b[*3] ##1 c;
endproperty

property goto_rep_p;
@(posedge sclk) $rose(a) |-> ##1 b[->3] ##1 c;
endproperty

property non_cons_rep_p;
@(posedge sclk) $rose(a) |-> ##1 b[=3] ##1 c;
endproperty

SVA 再了解(二)

|=>與 |->的不同

|=>
非交叠蕴含操作符“|=>”表示:如果先行算子匹配,后序算子在下一个时钟周期开始计算。
The operator |=> means “then at the next clock
cycle”, and it is called non-overlapping suffix implication.

|->
交叠蕴含操作符“|->”表示如果先行算子匹配,后序算子在同一个时钟周期开始计算。
(operator |->, called overlapping suffix implication

另一個用SystemC寫的Counter

與前一個相同,指是改用class方式來寫

#include

//SC_MODULE (counter) {
class counter : public sc_module {

public:
sc_in reset;
sc_in clock;
sc_out out_value;
sc_unit<4> cout;

void counter_in(){
if (reset)
cout = 0;
else
cout ++;

out_value.write(cout);
}

SC_CTOR(counter) {
SC_MODULE(counter_in);
sensitive << clock.pos();
sensitive << reset;
}
};

//SC_MODULE (power_on) {
class power_on : public sc_module {

public:

sc_signal reset;

void por() {
wait (3, SC_NS);
reset = sc_bit('1');
wait (5, SC_NS);
reset = sc_bit('0');
}

SC_CTOR(power_on) {
SC_THREAD(por);
}
};

int sc_main (int argc, char* argv[]) {

sc_signal cout_value;
sc_signal reset;

sc_clock clock ("my_clock", 3, 0.5, SC_NS);

counter my_cnt("My_COUNTER");

power_on my_power_on("My_POWER_ON");

my_power_on.reset(reset);

my_cnt.clock (clock);
my_cnt.reset (reset);
my_cnt.out_value(cout_value);


sc_trace_file *wf = sc_create_vcd_trace_file ("sc_test");
sc_trace(wf, clock, "clock");
sc_trace(wf, reset, "reset");

sc_trace(wf, my_cnt.cout, "my_cnt_value");
sc_trace(wf, cout_value, "count_value");

sc_start(150, SC_NS);

sc_close_vcd_trace_file(wf);

return 0;

}

2011年6月30日 星期四

UVM Register(十六)

Backdoor的好處

我們在測試一個register或者是memory時
一般的做法是先寫入一個値,然後在讀出來作比對。
但是如果我們的Read/Write interface的錯誤是相同時
這時寫入與讀出是一樣的,

如果遇到這種case,只有用backdoor來對register/memory直接讀寫
並與interface的讀寫來作比對,才能找出這種錯誤。

但是這種錯誤我是沒遇過,
以後不知遇到的機會不知大不大?

UVM Register(十五)

uvm_reg的predict()及mirror_reg()的使用範例

在DUT design中的code
module blk_dut #(int BASE_ADDR='h0) (apb_if apb,
input bit rst);

reg [7:0] R;

reg [31:0] pr_data;

wire in_range;

wire [31:0] pr_addr;

assign in_range = (apb.paddr - BASE_ADDR) < 'h100;
assign pr_addr = apb.paddr - BASE_ADDR;

assign apb.prdata = (apb.psel && apb.penable && !apb.pwrite && in_range) ? pr_data : 'z;


always @ (posedge apb.pclk)
begin
if (rst) begin
R <= 'h00;
pr_data <= 32'h0;
end
else begin

// Wait for a SETUP+READ or ENABLE+WRITE cycle
if (apb.psel == 1'b1 && apb.penable == apb.pwrite) begin
pr_data <= 32'h0;
if (apb.pwrite) begin
casex (pr_addr)
32'h00000000:
R <= apb.pwdata[7:0];
32'h00000001:
casez (apb.pwdata[1:0])
2'b01: R++;
2'b10: R--;
2'b11: R <= 0;
endcase
32'h00000002:
casez (apb.pwdata[1:0])
2'b01: R<=R+2;
2'b10: R<=R-2;
2'b11: R<= 8'hff;
endcase
endcase
end
else begin
casex (pr_addr)
32'h00000000: pr_data <= {24'h0, R};
default: pr_data <= 32'h0;
endcase
#1;
end
#0;
end
end
end

endmodule

uvm_reg_block的code
default_map.add_reg(CTL, 'h2, "RW");

在sequence的code
// Perform a random number of INC operations
n = ($urandom() % 5) + 3;
`uvm_info("blk_R_test_seq", $psprintf("Incrementing 2 in R %0d times...", n), UVM_NONE);
repeat (n) begin
//write_reg(model.CTL, status, reg_fld_B_CTL_CTL::INC);

write_reg(model.CTL, status, 1);

data=data+2;
void'(model.R.predict(data));

`uvm_info("model.R, predict ", $psprintf("data = %0d ", data), UVM_NONE);
end

// void'(model.R.predict(data));


// Check the final value
mirror_reg(model.R, status, UVM_CHECK);

`uvm_info("model.R, mirror_reg again ", $psprintf("status = %0d ", status), UVM_NONE);


結果如下
UVM_INFO blk_seqlib.sv(188) @ 550: reporter@@blk_R2_test_seq [model.R, peek_reg ] rd_data = 113
UVM_INFO blk_seqlib.sv(195) @ 550: reporter@@blk_R2_test_seq [blk_R_test_seq] Incrementing 2 in R 3 times...
UVM_INFO blk_seqlib.sv(204) @ 630: reporter@@blk_R2_test_seq [model.R, predict ] data = 115
UVM_INFO blk_seqlib.sv(204) @ 710: reporter@@blk_R2_test_seq [model.R, predict ] data = 117
UVM_INFO blk_seqlib.sv(204) @ 790: reporter@@blk_R2_test_seq [model.R, predict ] data = 119
UVM_INFO blk_seqlib.sv(213) @ 870: reporter@@blk_R2_test_seq [model.R, mirror_reg again ] status = 0

2011年6月29日 星期三

UVM Register(十四)

一個簡單的UVM Register的run top
這邊與基本的UVM的其它用法是一樣的,
只是因為是UVM Register的case
所以特別貼出


`include "uvm_pkg.sv"
`include "apb.sv"
`include "blk_reg_pkg.sv" //將uvm_reg的code分開包裝
`include "blk_pkg.sv" //uvm_reg 相關的環境另外包裝
`include "blk_top.sv" // design與interface的包裝

program tb;

import uvm_pkg::*;
import blk_reg_pkg::*;
import blk_pkg::*;

`include "blk_testlib.sv" //test lib

initial
begin
static blk_env env = new("env");

//設定apb_vif就是root層的top下的apb0
uvm_config_db#(apb_vif)::set(env, "apb", "vif", $root.blk_top.apb0);

run_test();
end

endprogram

UVM Register(十三)

一個基本的uvm register的testcase

typedef class dut_reset_seq;
class blk_R_test extends uvm_test;

`uvm_component_utils(blk_R_test)

blk_env env;

function new(string name="blk_R_test", uvm_component parent=null);
super.new(name, parent);
endfunction

function void build_phase(uvm_phase phase);
if (env == null)
$cast(env, uvm_top.find("env"));
endfunction

task run_phase(uvm_phase phase);
uvm_sequence_base reset_seq;
blk_R_test_seq seq;

phase.raise_objection(this); //啟動這個phase flow控制

begin //使用一個reset的sequence
dut_reset_seq rst_seq;
rst_seq = dut_reset_seq::type_id::create("rst_seq", this);
rst_seq.start(null);
end
env.model.reset(); //使用uvm_reg_block內建的reset機制

//使用一個test用的sequence
seq = blk_R_test_seq::type_id::create("blk_R_test_seq",this);
seq.model = env.model;
seq.start(null);

phase.drop_objection(this);//關閉這個phase flow控制
endtask

endclass


class dut_reset_seq extends uvm_sequence;

function new(string name = "dut_reset_seq");
super.new(name);
endfunction

`uvm_object_utils(dut_reset_seq)

virtual task body();
blk_top.rst = 1;
repeat (5) @(negedge blk_top.clk);
blk_top.rst = 0;
endtask
endclass

2011年6月28日 星期二

ASIC Design & Verification 最重要的十件事

Top-10 List

轉貼自http://www.mindspring.com/~tcoonan/asicdv.html

1.0 Simulate Everything

While seemingly obvious to ASIC folks, this is step #1. FPGAs can often be very productively tested in the lab (that's part of the point, right?). With ASICs, you get only one shot, or at least you pay the $100000 penalty per re-spin. A wise designer once said "That which is not simulated will not operate correctly".

"Everything" is a little ambitious, of course. Formal testing methodologies dictate that your design be specified in a document containing detailed, numbered paragraphs of each and every feature and function with numbers for any minimums and maximums. Formal test methodologies then require that a testing document specify a matrix cross-referencing every system feature/function against a very specific test that verifies that feature/function including those min/max parameters.

For FPGA folks, note that the heavy emphasis on simulation goes beyond just testing the design thouroughly. Chip vendors require the submission of test vectors which requires this kind of testbenching.

2.0 Regression, Regression and Regression

Regression testing means you can run a test suite on your design at any time in an easy manner require little additional setup and little analysis. The idea is that you can retest everything whenever something changes or periodically as a matter of course. This is sometimes refered to the "Always Working" model, where the design is kept in an always working state. "Always working" is made easier by using an RCS or other source code control system such that an official "release" directory contains the source code, and only source code that has passed the full regression test.

Is this just mindless testing repetition? Here are some reasons for doing this kind of repeated regression test. 1) A seemingly small tweak of the design will lead to a problem. Nobody on the surface believes the tweak justifies another round of tedious tests. 2) The design is really part of a larger system where another team's module has been fiddled with. They make a tweak and falsely believe it does not impact your block.. 3) Netlist changes! Quick - does the design still work? (see #10) 4) A new version of a tool was installed last night and will eventually cause a problem. Better to detect this sooner than later.

Regression Tests should be repeatable and traceable. A test should first be repeatable. If randomness is built into a test, then it may be important to specify an initial SEED for a test in order to replicate an error detected on a previous run. Traceability means that when an anomoly or error is reported in a test enough additional information is reported to allow you to zero-in on the problem. This means that you should display messages about major events in the test and include the simulation time (e.g. use the %t and $time feature!). This allows you to rerun a test, and selectively capture simulation data (e.g. waveforms or VCD) around the time the error occurs. In other words, if you have a test that runs for 9 hours and an error pops up 5 hours into the test; will you be able to diagnose that error?

A good goal is to pass the "Weekend Run Test". This test says that when you leave work on friday afternoon, are you able to kick off your test suite and know that you can easily review the results on Monday morning? Obviously, this requires an automated test suite but it also implies that the results are easy enough to check out at the end. Results that require a minimum 4 hours to analyse discourages the casual "weekend run". So, the goal is feel free to kick of the regression test suite at any time.

3.0 PASS or FAIL, Please!

Each test should report an unambiguous, succinct indication of pass or fail. This is also refered to as the Self-Checking Testbench. Viewing waveforms is great for diagnosing problems, but not the way to repetitevly assess whether your test and your design is working.

Establish a convention for reporting PASS/FAIL. What is best is a one line print statement containing the DATE/TIME the test completed, the name of the test and either the word PASS or FAIL. More information is fine as long as there is this bottom-line PASS/FAIL. This line should have some unique keyword like ENDTEST in it. Imagine a system where each test is in its own directory and a script runs a "test suite", or a key set of these tests. After the last test runs, the script could do a 'grep ENDTEST */results | mail me@widgetco.com'. You receive an email listing a one line PASS/FAIL per test for the entire test suite that ran.

4.0 Keeping the design robust and flexible

This is almost a design issue and not so much a verification issue, however, the act of testing often reveals opportunities for beefing up the design robustness. A robust design partially means that it can be tweaked in order to handle unforseen circumstances. If a module ends up being problematic, it might be useful to disable it. Always include a DISABLE bit. Include alternative paths or even ways to bypass modules and features. If there is a shred of doubt about data formats or parameters, provide programmable settings. Option bits can selectively complement data, change bit ordering, little/big-endianness, or byte ordering. Programmable wait states might be key in fixing a fragile interface. All this may have speed and area costs, but risk reduction is important, too. Just remember, that one option bit you add may save your design in the lab.

5.0 Coverage and the "Time as a Tool" test

Are you testing all possible lengths, options, fields, rates and cases? Probably not, but are you covering the minimums and the maximums and at least one example of each major case? If you think you are(maybe you have a test that is supposed to test this), but aren't sure, how can you verify that you're verifying what you think you are verifying?! This is all about Coverage. There are tools that help with this. Code Coverage tools (like Synopsys Covermeter) will analyse your test and report on every line of your RTL and Test code as to whether the line was executed at some point during the tests. There is also Functional Coverage where you measure how much of your system functionality is exercised with the tests. Tools like Specman Elite from Verisity address this issue.

Consider adding psuedo-random stimulus creation. Randomly select parameters, options, etc. This is especially good if it is unrealistic to attempt to generate a test case for all possible combinations. One goal is to pass the "Time as a Tool" test. The question is; if you had another N hours to run a particular test, would you increase your test coverage? In other words, the longer the test runs the more nooks and crannies will be explored because you are randomly exploring more and more cases. Pseudo-random testing ties back into coverage. Beware of a false sense of security where you assume you really are covering all possible cases just because you have some randomness in your test. Verify your coverage!

A more homebrew scheme to address test coverage can be done in your regular HDL. Instrument your code so that whenever your code tests a particular case or sets some parameter value, display a message indicating this. This HDL can be activated with a '+define+SHOW_COVERAGE' option in the simulation command line. Some creative GREPing of the log file after the test suite finishes can actually report a % coverage.

6.0 Maximize Controllability

Control the design and the testbench. Can you inject data into almost any point in the design? Can you do this injecting of data only in the testbench, or could you do it in the real thing? Can you bypass any module? Can you disable modes? Can you emulate certain things at interfaces so that you can still simulate operation if certain external modules are absent (e.g. testing "stubs" or behavioral models).

7.0 Maximize Observability

Be able to observe data and operation anywhere in the design. Can you extract data at all major interfaces (without constantly having to use a waveform viewer!) in the design? Can you include test modes into the actual design allowing data streams or signals to be routed out to observable pins on the chip? Can you observe important events and signals easily? Can you observe those events and signals from C code running in your processor?

Consider adding HDL "monitors" to your testbench. For example, within your actual HDL code, you might include code like this:

    // synopsys translate_off
    parameter MONITOR_START = 0;
    initial begin
      while (MONITOR_START) begin
        @(posedge start);
        $display ("MONITOR_START: 'start' detected at %t in module
          %m", $time);
      end
    end
    // synopsys translate_on

You can easily enable this monitor code in a top-level testbench by using a defparam statement. Becareful that using monitors embedded in the RTL may not be availble during a gate-level simulation.

Counters can also greater increase observability. Consider adding in some counters within the actual design. Counters can count major system events, errors, etc. The counters are accessible to software running in a processor or even by HDL code. Counters cost area. One trick, is to use a single test counter in a particular module but then provide some control bits that select the event to be counted (another control bit can clear the counter).

8.0 C Code anyone?

Many ASICs these days inlcude or are controlled by a processor running C code. Some ASIC folks loathe C code, but consider the advantages to using C code in your testbenches in additional to your normal simulation HDL. Many people use Bus Functional Models to emulate the C code and the processor. BFMs emulate the reading and writing of memory and I/O addresses and can be made to exactly emulate the ultimate C code. However, using actual C code brings you closer to what the software engineer will actually be doing. Also, using C code in Design Verification tests can be reused on the lab bench.

C code can be brought into the HDL simulation using behavioral/RTL/gate-level processor models, cross compilers and linkers and the Verilog $readmemh PLI function for loading code images into memory models. There are also commercial tools catering to Co-simulation requirements such as Seamless from Mentor. Such tools allow you to simultaneously use, for example, a source-level debugger for the C code running on a processor model and the traditional HDL simulator. Simpler more homebrew methodolies exist such as using PLI routines. Obviously, there are significant tools issues involved in bringing together the HDL and C code but there are high payoffs.

9.0 The LAB..

Can all the hard work you expended creating these tests in the simulation world transition to the lab? Can the C code (if applicable) be easily ported to the real platform? Can data created in the simulation environment be introduced into the lab environment? Can live data be extracted and compared against the simulated data?

10.0 RTL, Gates, Timing.. Whatever..

ASIC folks are called upon to verify the design at various stages in the flow. Not only must the RTL code be tested, but often the Gate-level netlist must be tested. The netlist can be tested before and after scan is inserted, or with back-annotated timing etc. etc. Modern methodologies relying on Static Timing Analysis sometimes suggest that gate-level simulation is unneccessary. Some amount of gate-level simulation should be considered in order to catch subtle synthesis problems and modeling issues. Make sure the tests can be run on these netlists as well as the RTL. Sometimes, this means that certain HDL monitors may not work well with a gate-level netlist and embedded actual counters in the design is the better approach. Just be careful about how you construct the tests!

Back to Tom Coonan's Home Page

UVM Register(十二)

一個使用uvm_register的testbench env基本設定範例

class blk_env extends uvm_env;

`uvm_component_utils(blk_env)

reg_block_B model;
apb_agent apb;

function new(string name = "blk_env", uvm_component parent = null);
super.new(name, parent);
endfunction: new

// 先用build_phase將相關的元件build起來
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);

if (model == null) begin
model = reg_block_B::type_id::create("reg_blk_B");
model.build();
model.set_hdl_path_root("blk_top.dut");
model.lock_model();

apb = apb_agent::type_id::create("apb",this);
end
endfunction: build_phase

//再來就是將相關的元件連結起來
virtual function void connect_phase(uvm_phase phase);
if (model.get_parent() == null) begin
reg2apb_adapter reg2apb = new;

model.default_map.set_sequencer(apb.sqr, reg2apb);
//將uvm_reg_block的uvm_reg_adapter與sequencer連結起來

model.default_map.set_auto_predict(1); // 只要設定為1的話就用內建的uvm_reg_predictor
end
endfunction

endclass: blk_env

2011年6月27日 星期一

UVM Register(十一)

uvm_reg_predictor

The predictor accepts bus transactions from a connected bus monitor. It uses the preconfigured adapter to obtain the canonical address and data from the bus operation. The map is used to lookup the register object associated with that address. The register’s predict() method is then called with the observed data to update the mirror value. If the register width is wider than the bus, the predictor will collect multiple observed bus operations before calling predict() with the register’s full value. As a final step, a generic uvm_reg_item descriptor representing the abstract register operation is broadcast to subscribers of its analysis port.

參考例圖























將看到bus上的值收集起來,然後透過uvm_reg_item傳送出去
其中adapter是在predictor裡面

monitor與predictor的連結方式
apb.monitor.ap.connect(apb2reg_predictor.bus_in);

ap在monitor中的設定
uvm_analysis_port#(apb_rw) ap;

bus_in是uvm_reg_predictor內建的
uvm_analysis_imp #(BUSTYPE, uvm_reg_predictor #(BUSTYPE)) bus_in;

當連結起來後,monitor上的看到的bus動作就會傳到uvm_reg_predictor
然後進入到adapter

UVM Register(十)

uvm_reg_adapter

This class defines an interface for converting between uvm_reg_bus_op and a specific bus transaction.

這個class主要在產生一個 transaction adapter,然後利用
reg2bus() and bus2reg() 這兩個method來
連結傳送transaction在bus與uvm_reg_sequence之間

傳輸之間的bus介面在uvm_reg_adapter是透過uvm_reg_bus_op
這是一個uvm內建的一個bus介面

一個user guide的例子
class reg2apb_adapter extends uvm_reg_adapter;

`uvm_object_utils(reg2apb_adapter)

function new(string name = "reg2apb_adapter");
super.new(name);
endfunction

virtual function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);
apb_rw apb = apb_rw::type_id::create("apb_rw");
apb.kind = (rw.kind == UVM_READ) ? apb_rw::READ : apb_rw::WRITE;
apb.addr = rw.addr;
apb.data = rw.data;
return apb;
endfunction

virtual function void bus2reg(uvm_sequence_item bus_item,
ref uvm_reg_bus_op rw);
apb_rw apb;
if (!$cast(apb,bus_item)) begin
`uvm_fatal("NOT_APB_TYPE","Provided bus_item is not of the correct type")
return;
end
rw.kind = apb.kind == apb_rw::READ ? UVM_READ : UVM_WRITE;
rw.addr = apb.addr;
rw.data = apb.data;
rw.status = UVM_IS_OK;
endfunction

endclass


reg2bus

Extensions of this class must implement this method to convert a uvm_reg_item to the uvm_sequence_item subtype that defines the bus transaction.

The method must allocate a new bus-specific uvm_sequence_item, assign its members from the corresponding members from the given generic rw bus operation, then return it.


bus2reg

Extensions of this class must implement this method to copy members of the given bus-specific bus_item to corresponding members of the provided bus_rw instance. Unlike reg2bus, the resulting transaction is not allocated from scratch. This is to accommodate applications where the bus response must be returned in the original request.


這個例子的uvm_sequence_item

class apb_rw extends uvm_sequence_item;

typedef enum {READ, WRITE} kind_e;
rand bit [31:0] addr;
rand logic [31:0] data;
rand kind_e kind;

`uvm_object_utils_begin(apb_rw)
`uvm_field_int(addr, UVM_ALL_ON | UVM_NOPACK);
`uvm_field_int(data, UVM_ALL_ON | UVM_NOPACK);
`uvm_field_enum(kind_e,kind, UVM_ALL_ON | UVM_NOPACK);
`uvm_object_utils_end

function new (string name = "apb_rw");
super.new(name);
endfunction

function string convert2string();
return $sformatf("kind=%s addr=%0h data=%0h",kind,addr,data);
endfunction

endclass: apb_rw


uvm_reg_bus_op

uvm_reg_bus_op
Struct that defines a generic bus transaction for register and memory accesses, having kind (read or write), address, data, and byte enable information.
Variables
kindKind of access: READ or WRITE.
addrThe bus address.
dataThe data to write.
n_bitsThe number of bits of uvm_reg_item::value being transferred by this transaction.
byte_enEnables for the byte lanes on the bus.
statusThe result of the transaction: UVM_IS_OK, UVM_HAS_X, UVM_NOT_OK.



2011年6月26日 星期日

UVM Register(九)

一個簡單的uvm_reg_sequence的使用例

class blk_R_test_seq extends uvm_reg_sequence;

`uvm_object_utils(blk_R_test_seq)

function new(string name = "blk_R_test_seq");
super.new(name);
endfunction: new

reg_block_B model; // 設定對那一個uvm_reg_block作讀寫的動作

virtual task body();
uvm_status_e status; // uvm 內定的
uvm_reg_data_t data, rd_data;
int n;

// Initialize R with a random value then check against mirror
data[7:0] = $urandom(); //先亂數得到一個數值

write_reg(model.R, status, data); //將data寫入uvm_reg_block的R這個uvm_reg的變數
read_reg (model.R, status, rd_data); //uvm_reg_block的R這個uvm_reg的變數的值讀出

...


以下是所用的部份在uvm library內的資料

typedef enum {
UVM_IS_OK,
UVM_NOT_OK,
UVM_HAS_X
} uvm_status_e;

// Type: uvm_reg_data_t
//
// 2-state data value with <`UVM_REG_DATA_WIDTH> bits
//
typedef bit unsigned [`UVM_REG_DATA_WIDTH-1:0] uvm_reg_data_t ;


write_reg

virtual task write_reg( input uvm_reg rg,


output uvm_status_e status,


input uvm_reg_data_t value,


input uvm_path_e path = UVM_DEFAULT_PATH,

input uvm_reg_map map = null,

input int prior = -1,

input uvm_object extension = null,

input string fname = "",

input int lineno = 0 )

write_reg(model.regA, status, value); //其它的可不設

=== model.regA.write(status, value, .parent(this));

因為write_reg這個function就是在內部呼叫regA的write(),並填上所需的相關變數


read_reg

virtual task read_reg( input uvm_reg rg,


output uvm_status_e status,


output uvm_reg_data_t value,


input uvm_path_e path = UVM_DEFAULT_PATH,

input uvm_reg_map map = null,

input int prior = -1,

input uvm_object extension = null,

input string fname = "",

input int lineno = 0 )

read_reg(model.regA, status, value);
=== model.regA.read(status, value, .parent(this));

因為read_reg這個function就是在內部呼叫regA的read(),並填上所需的相關變數


許多的uvm_reg_sequence所用到的function都是內部再去呼叫
uvm_req或uvm_mem的function來用,只是經過一層包裝而已


以下是相關的列表
Convenience Write/Read APIThe following methods delegate to the corresponding method in the register or memory element.

write_regWrites the given register rg using uvm_reg::write, supplying ‘this’ as the parent argument.
read_regReads the given register rg using uvm_reg::read, supplying ‘this’ as the parent argument.
poke_regPokes the given register rg using uvm_reg::poke, supplying ‘this’ as the parent argument.
peek_regPeeks the given register rg using uvm_reg::peek, supplying ‘this’ as the parent argument.
update_regUpdates the given register rg using uvm_reg::update, supplying ‘this’ as the parent argument.
mirror_regMirrors the given register rg using uvm_reg::mirror, supplying ‘this’ as the parent argument.
write_memWrites the given memory mem using uvm_mem::write, supplying ‘this’ as the parent argument.
read_memReads the given memory mem using uvm_mem::read, supplying ‘this’ as the parent argument.
poke_memPokes the given memory mem using uvm_mem::poke, supplying ‘this’ as the parent argument.
peek_memPeeks the given memory mem using uvm_mem::peek, supplying ‘this’ as the parent argument.


UVM Reference Flow

這是UVM組織提供的一個練習的包裝

可從http://www.uvmworld.org上去下載

參考說明在
http://www.uvmworld.org/uvm-reference-flow.php