“solve before是SystemVerilog中最容易被误解的语法之一。它实际上不是一个约束,因为它对随机结果的集合没有影响。它只影响可用集合中随机值的分布。”
掌握这个语法的最有效方法包括创建一个示例,进行实验,并观察施加solve before时,仿真结果如何演变。
定义了两个枚举变量:instr_group_t,表示CPU指令集中的指令组,instr_t,表示实际指令。
代表标准数据处理指令的DATA_PROC
代表移位指令的SHIFT
代表包装和拆包说明的PACK
在每个随机化周期中,仿真器将选择一个指令组,以及指令集中的指令。
typedef enum int {
/*DATA PROCESS*/ ADC, ADD, ADR, AND, BIC, CMP,
/*SHIFT*/ ASR, LSL, LSR,
/*PACK_UNPACK*/ SXTB, SXTH, UXTB
} instr_t;
每个变量定义和约束都将位于instr_item类中。
class instr_item extends uvm_object;
在该类中,定义了两个随机变量,一个用于指令组,另一个用于指令本身。
rand instr_group_t instr_group;
rand instr_t instr;
声明并初始化了三个指令队列,这将使我们能够轻松更改集合。
instr_t data_proc_q[$] = {ADC, ADD, ADR};
instr_t shift_q[$] = {ASR, LSL, LSR};
instr_t pack_q[$] = {SXTB, SXTH, UXTB};
此外,我们定义了四个静态变量,以跟踪每个随机化结果。
static int data_proc_cnt;
static int shift_cnt;
static int pack_cnt;
static int total_cnt;
约束块非常简单:它涉及从与该组关联的指令集中选择一个指令组和指令。
constraint inster_c {
// Choose instruction from group
if (instr_group==DATA_PROC) {
instr inside {data_proc_q};
}
else if (instr_group==SHIFT) {
instr inside {shift_q};
}
else {
instr inside {pack_q};
}
}
在post_randomize方法中,统计结果
function void post_randomize();
if (instr inside {data_proc_q}) begin
data_proc_cnt++;
total_cnt++;
end
else if (instr inside {shift_q}) begin
shift_cnt++;
total_cnt++;
end
else begin
pack_cnt++;
total_cnt++;
end
endfunction : post_randomize
我们可以观察到,每个小组都有三分之一的概率发生。