前回のおさらい
Register階層を作成しました。
UVMモデルを介してDUTのレジスタにアクセスするためにAdapterを作成します。

サンプルコード
sample_sequence_item.svh
Register階層と接続するUVMモデル(Agent)のSequence_itemです。
class regbus_sequence_item extends uvm_sequence_item;
`uvm_object_utils(regbus_sequence_item)
rand bit write_en;
rand byte addr;
rand byte data;
function new(string name="regbus_sequence_item");
super.new(name);
endfunction
endclass
sample_reg_adapter.svh
uvm_reg_adapterを継承してsample_reg_adapterを作成します。
uvm_reg_adapterはpureメソッドのreg2busとbus2regを持っています。
この2つでRegister階層とUVMモデルで値を受け渡ししています。
class sample_reg_adapter extends uvm_reg_adapter;
`uvm_object_utils(sample_reg_adapter)
function new(string name="sample_reg_adapter");
super.new(name);
endfunction
// Register階層からモデルに値を渡す。
virtual function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);
regbus_sequence_item trans;
trans = regbus_sequence_item::type_id::create("trans");
trans.write_en = (rw.kind == UVM_READ) ? 0 : 1;
trans.addr = rw.addr;
trans.data = rw.data;
return trans;
endfunction
// モデルからRegister階層に値を渡す。
virtual function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);
regbus_sequence_item trans;
$cast(trans, bus_item);
rw.kind = trans.write_en ? UVM_READ : UVM_WRITE;
rw.addr = trans.addr;
rw.data = trans.data;
endfunction
endclass
sample_env.svh
AdapterとUVMモデルを接続します。
class sample_env extends uvm_env;
`uvm_component_utils(sample_env)
sample_reg_block regmodel;
sample_reg_adapter adapter; // Adapterを宣言
regbus_agent agent;
function new(string name="sample_env", uvm_component parent);
super.new(name, parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
adapter = sample_reg_adapter::type_id::create("adapter");
agent = regbus_agent::type_id::create("agent", this);
regmodel = sample_reg_block::type_id::create("regmodel");
regmodel.build();
regmodel.lock_model();
uvm_config_db#(sample_reg_block)::set(uvm_root::get(), "*", "regmodel", regmodel);
endfunction
virtual function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
regmodel.default_map.set_sequencer(agent.sequencer, adapter); // SequencerとAdapterを接続。
regmodel.default_map.set_base_addr('h0);
endfunction
endclass
sample_vseq.svh
uvm_regはbuilt-inメソッドでwriteを持っています。
<uvm_reg>.write(status, <値>)で、uvm_regで定義したレジスタに<値>をAdapter→UVMモデルという流れで書き込みます。
class sample_vseq extends uvm_sequence;
`uvm_object_utils(sample_vseq)
`uvm_declare_p_sequencer(sample_vsequencer)
function new(string name="sample_vseq");
super.new(name);
set_automatic_phase_objection(1);
endfunction
virtual task body();
uvm_status_e status;
p_sequencer.regmodel.STATUS.write(status, 'h1);
p_sequencer.regmodel.STATUS.write(status, 'h2);
endtask
endclass
その他のファイル
`include "regbus_pkg.svh"
module top;
`include "uvm_macros.svh"
import uvm_pkg::*;
import regbus_pkg::*;
`include "sample_reg_block.svh"
`include "sample_reg_adapter.svh"
`include "sample_env.svh"
`include "sample_vsequencer.svh"
`include "sample_vseq.svh"
`include "sample_test.svh"
initial begin
run_test("sample_test");
end
bit clk = 0;
always #1 clk = ~clk;
bit rst_n = 0;
initial #10 rst_n = 1;
logic write_en;
logic [7:0] addr;
logic [7:0] data;
regbus i_regbus (
.clk(clk),
.rst_n(rst_n),
.write_en(write_en),
.addr(addr),
.data(data)
);
endmodule
interface regbus_if (
logic clk,
logic rst_n
);
logic write_en;
logic [7:0] addr;
logic [7:0] data;
endinterface
module regbus #(
)(
input clk,
input rst_n,
output logic write_en,
output logic [7:0] addr,
output logic [7:0] data
);
`include "uvm_macros.svh"
import uvm_pkg::*;
regbus_if vif(
.clk(clk),
.rst_n(rst_n)
);
assign data = vif.data;
assign addr = vif.addr;
assign write_en = vif.write_en;
initial begin
uvm_config_db #(virtual regbus_if)::set(null, "*regbus*", "vif", vif);
end
endmodule
package regbus_pkg;
`include "uvm_macros.svh"
import uvm_pkg::*;
`include "regbus_sequence_item.svh"
`include "regbus_sequencer.svh"
`include "regbus_driver.svh"
`include "regbus_agent.svh"
endpackage
class regbus_sequencer extends uvm_sequencer #(regbus_sequence_item);
`uvm_component_utils(regbus_sequencer)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
endclass
class regbus_driver extends uvm_driver #(regbus_sequence_item);
`uvm_component_utils(regbus_driver)
virtual regbus_if vif;
function new(string name, uvm_component parent);
super.new(name, parent);
if (!uvm_config_db #(virtual regbus_if)::get(this, "regbus", "vif", vif))
`uvm_fatal(this.get_name(), "vif is invalid")
endfunction
task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req);
@(posedge vif.clk iff vif.rst_n);
vif.write_en = req.write_en;
vif.data = req.data;
vif.addr = req.addr;
@(posedge vif.clk);
seq_item_port.item_done(rsp);
end
endtask
endclass
class regbus_agent extends uvm_agent;
`uvm_component_utils(regbus_agent)
regbus_driver driver;
regbus_sequencer sequencer;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
driver = regbus_driver::type_id::create("driver", this);
sequencer = regbus_sequencer::type_id::create("sequencer", this);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
driver.seq_item_port.connect(sequencer.seq_item_export);
endfunction
endclass
class STATUS_reg extends uvm_reg; // レジスタクラス。
`uvm_object_utils(STATUS_reg)
function new(string name="STATUS_reg");
super.new(name, 8, UVM_NO_COVERAGE);
endfunction
rand uvm_reg_field status;
function void build();
status = uvm_reg_field::type_id::create("status");
status.configure(
.parent(this), // とりあえずthisでOK。
.size(8), // レジスタのビット幅
.lsb_pos(0), // LSBの開始位置
.access("RW"), // アクセスタイプ
.volatile(0), // わからん。
.reset(0), // 初期値
.has_reset(1), // リセット値を持つかどうか。
.is_rand(1), // 乱数対応
.individually_accessible(0) // わからん。
);
endfunction
endclass
class sample_reg_block extends uvm_reg_block; // レジスタクラスをまとめる。
rand STATUS_reg STATUS; // 作成したレジスタクラスを羅列する。
`uvm_object_utils(sample_reg_block)
function new(string name="sample_reg_block");
super.new(name, build_coverage(UVM_NO_COVERAGE));
endfunction
function void build();
STATUS = STATUS_reg::type_id::create("STATUS");
STATUS.configure(this);
STATUS.build();
default_map = create_map("", 0, 1, UVM_LITTLE_ENDIAN);
default_map.add_reg(STATUS, 'h1); // レジスタクラスを追加する。
endfunction
endclass
class sample_vsequencer extends uvm_sequencer;
`uvm_component_utils(sample_vsequencer)
regbus_sequencer seqr;
sample_reg_block regmodel;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
endclass
class sample_vseq extends uvm_sequence;
`uvm_object_utils(sample_vseq)
`uvm_declare_p_sequencer(sample_vsequencer)
function new(string name="sample_vseq");
super.new(name);
set_automatic_phase_objection(1);
endfunction
virtual task body();
uvm_status_e status;
p_sequencer.regmodel.STATUS.write(status, 'h1);
p_sequencer.regmodel.STATUS.write(status, 'h2);
endtask
endclass
まとめ
Adapterを作成してUVMモデルを介してレジスタアクセスしました。
コメント