参考 UVM 序列
Reference to UVM Sequence
我需要监控一个寄存器的状态。我创建了一个 UVM 序列来读取寄存器并将它们存储在本地。现在在我的测试代码中,我需要访问这些
寄存器。这是一个 sudo 代码:
typedef struct {
int a;
} my_regs;
class my_seq extends uvm_sequence;
// register to uvm db
reg_map map;
my_regs regs;
uvm_status_e status;
task build_phase(uvm_phase phase);
endtask
task run_phase(uvm_phase phase);
map.CORE.reg_a.read(status, regs.a, UVM_BACKDOOR)
endtask
endclass
class test_reg extends uvm_test;
// register to uvm db
my_seq seq;
my_regs regs;
task build_phase(uvm_phase phase);
seq = my_seq::type_id::create("reg_seq", this);
regs = seq.regs;
endtask
task run_phase(uvm_phase phase);
reg_seq.start(null);
// read reg values from seq??????
if(rqgs.a>1)
//do some thing
endtask
endclass
如您所见,我一直在启动序列,以免错过任何更新。我相信 start 任务顺序不会创建新对象
因此对象内的值在开始调用之间应保持不变。
假设我不是每次都从 seq 读取 regs 值,测试 class 的 regs 将不会从 seq 获得更新。这意味着 regs = seq.regs; 不会创建对 seq.regs 的实际引用。我想知道为什么会这样以及如何创建对该对象的绝对引用? (这样我就不会浪费模拟周期来读取和更新测试 class 中的 regs 值)。如果有更好的方法,请告诉我。
首先是一个小修复。序列没有构建或 运行 阶段。与其他 uvm_components 不同,它们不会自动启动 [使用定相系统]。
一个序列有一个主体任务,它被覆盖以实现功能(在本例中是读取寄存器)。因此需要将 run_phase 中的代码移动到主体函数中。
class my_seq extends uvm_sequence;
// register to uvm db
reg_map map;
my_regs regs;
uvm_status_e status;
function new(string name="my_seq");
super.new(name);
endfunction
task body ();
map.CORE.reg_a.read(status, regs.a, UVM_BACKDOOR);
endtask
endclass
调用序列后,它将从 RTL 寄存器中读取值并更新 class my_seq 中 regs 中的 "a" 字段。
regs = seq.regs; //
regs(在测试中)将为序列中的 regs 字段提供一个永久的 link。因此,每当序列读取寄存器并更新 regs 字段时,test_reg 中的变量 regs 都会发生变化,但这意味着必须从 RTL 读取寄存器。 test_reg 需要执行循环以定期读取寄存器(通过调用序列 my_seq)。这是因为变量 regs 或寄存器字段 map.CORE.reg_a 不是直接 link 到 RTL 中的寄存器。
您将需要花费模拟周期读取 RTL 寄存器,因为 uvm_register 只是一个 mirror/copy,它仅在发出读取时更新。
问题是固件如何访问寄存器?如果寄存器是通过轮询机制访问的,最好在测试用例中模仿它。
task run_phase(uvm_phase phase);
task_done = 0;
while ( !task_done )
begin
// wait for some delay as backdoor access takes 0 simulation time
reg_seq.start(null); // regs is updates
// read reg values from seq - done
if(regs.a>1) // check for bit to be set
begin
task_done = 1;
//do some thing
end
// else continue to poll register
end
end task
或者,我们可以等待 RTL 信号发生变化,然后发出读取(这种方法不可取,因为我们正在从测试台访问 RTL 信号。)
task run_phase(uvm_phase phase);
wait ( RTL.module.reg.CORE.reg_a == 1 ) ;
reg_seq.start(null); // regs file is updates
// read reg values from seq - done
if(regs.a>1) // check for bit to be set
//do some thing
endtask
我需要监控一个寄存器的状态。我创建了一个 UVM 序列来读取寄存器并将它们存储在本地。现在在我的测试代码中,我需要访问这些 寄存器。这是一个 sudo 代码:
typedef struct {
int a;
} my_regs;
class my_seq extends uvm_sequence;
// register to uvm db
reg_map map;
my_regs regs;
uvm_status_e status;
task build_phase(uvm_phase phase);
endtask
task run_phase(uvm_phase phase);
map.CORE.reg_a.read(status, regs.a, UVM_BACKDOOR)
endtask
endclass
class test_reg extends uvm_test;
// register to uvm db
my_seq seq;
my_regs regs;
task build_phase(uvm_phase phase);
seq = my_seq::type_id::create("reg_seq", this);
regs = seq.regs;
endtask
task run_phase(uvm_phase phase);
reg_seq.start(null);
// read reg values from seq??????
if(rqgs.a>1)
//do some thing
endtask
endclass
如您所见,我一直在启动序列,以免错过任何更新。我相信 start 任务顺序不会创建新对象 因此对象内的值在开始调用之间应保持不变。
假设我不是每次都从 seq 读取 regs 值,测试 class 的 regs 将不会从 seq 获得更新。这意味着 regs = seq.regs; 不会创建对 seq.regs 的实际引用。我想知道为什么会这样以及如何创建对该对象的绝对引用? (这样我就不会浪费模拟周期来读取和更新测试 class 中的 regs 值)。如果有更好的方法,请告诉我。
首先是一个小修复。序列没有构建或 运行 阶段。与其他 uvm_components 不同,它们不会自动启动 [使用定相系统]。 一个序列有一个主体任务,它被覆盖以实现功能(在本例中是读取寄存器)。因此需要将 run_phase 中的代码移动到主体函数中。
class my_seq extends uvm_sequence;
// register to uvm db
reg_map map;
my_regs regs;
uvm_status_e status;
function new(string name="my_seq");
super.new(name);
endfunction
task body ();
map.CORE.reg_a.read(status, regs.a, UVM_BACKDOOR);
endtask
endclass
调用序列后,它将从 RTL 寄存器中读取值并更新 class my_seq 中 regs 中的 "a" 字段。
regs = seq.regs; //
regs(在测试中)将为序列中的 regs 字段提供一个永久的 link。因此,每当序列读取寄存器并更新 regs 字段时,test_reg 中的变量 regs 都会发生变化,但这意味着必须从 RTL 读取寄存器。 test_reg 需要执行循环以定期读取寄存器(通过调用序列 my_seq)。这是因为变量 regs 或寄存器字段 map.CORE.reg_a 不是直接 link 到 RTL 中的寄存器。
您将需要花费模拟周期读取 RTL 寄存器,因为 uvm_register 只是一个 mirror/copy,它仅在发出读取时更新。
问题是固件如何访问寄存器?如果寄存器是通过轮询机制访问的,最好在测试用例中模仿它。
task run_phase(uvm_phase phase);
task_done = 0;
while ( !task_done )
begin
// wait for some delay as backdoor access takes 0 simulation time
reg_seq.start(null); // regs is updates
// read reg values from seq - done
if(regs.a>1) // check for bit to be set
begin
task_done = 1;
//do some thing
end
// else continue to poll register
end
end task
或者,我们可以等待 RTL 信号发生变化,然后发出读取(这种方法不可取,因为我们正在从测试台访问 RTL 信号。)
task run_phase(uvm_phase phase);
wait ( RTL.module.reg.CORE.reg_a == 1 ) ;
reg_seq.start(null); // regs file is updates
// read reg values from seq - done
if(regs.a>1) // check for bit to be set
//do some thing
endtask