基于UVM的相位累加器测试平台设计疑问及编译错误排查
相位累加器UVM测试平台问题解答
问题1:监控类设计合理性分析
你的设计是合理的,完全适配自由运行型DUT的特性:
- 自由运行的相位累加器每个时钟沿都会更新输出(
phase、cycle_end),因此每个时钟沿采集输出是正确的,能完整捕获DUT的连续输出行为。 load信号是配置激励的触发信号,仅在load有效时采集tuning_word和load状态,能精准记录DUT的配置变更点,这比盲目采集所有时钟的输入更高效。
需要注意的是,计分板需要处理激励与连续输出的关联逻辑:每次load触发后,要记录当前生效的tuning_word,后续所有输出都要基于这个tuning_word进行预期值计算,直到下一次load更新配置。这种关联是自由运行DUT验证的核心,也是和单次激励对应单次输出场景的主要区别。
问题2:编译错误原因分析
编译错误的核心原因和解决点如下:
时钟触发方式错误:
你用@(vif.clk)会等待时钟信号的任意变化(上升沿+下降沿),而DUT是时钟沿触发更新输出,下降沿时输出尚未更新,且部分仿真器不允许在这种“电平变化触发”的代码块中直接实例化类对象。
正确的做法是等待时钟上升沿:@(posedge vif.clk),这样只在DUT更新输出后采样,也能避免上下文导致的编译问题。代码笔误:
out.phase_quadrant = cif.phase_quadrant;中的cif是笔误,应为vif;if (vif.ld)中的ld是笔误,对应DUT的输入信号应为load;stimulus.tunning_word拼写错误,应为stimulus.tuning_word;- 虚拟接口声明
virtual reg_if vif与config_db中获取的acc_if类型不匹配,应改为virtual acc_if vif。
你提到把实例化放入if(vif.clk)条件块后错误消失,本质是这个条件过滤掉了下降沿的触发(仅在clk为高电平时执行),间接规避了错误的触发时机,但不如直接使用@(posedge vif.clk)规范。
附相关代码
DUT代码(phase_acc模块)
module phase_acc #( parameter PHASE_ACC_WIDTH = 16, parameter TUNNING_WORD_WIDTH = 8 ) ( input wire clk, input wire reset, input wire load, input wire [TUNNING_WORD_WIDTH-1 : 0] tuning_word, output reg [PHASE_ACC_WIDTH-1 : 0] phase, output wire cycle_end, output wire [1:0] phase_quadrant ); assign phase_quadrant = phase[PHASE_ACC_WIDTH-1:PHASE_ACC_WIDTH-2]; assign cycle_end = (phase + tuning_word) > {PHASE_ACC_WIDTH{1'b1}}; always @(clk) begin if (reset == 1) begin phase <= 0; end else begin phase <= phase + tuning_word; end end endmodule
monitor类代码(修正后)
class monitor extends uvm_monitor; `uvm_component_utils(monitor) function new(string name = "monitor", uvm_component parent = null); super.new(name, parent); endfunction uvm_analysis_port #(acc_stimulus) mon_stimulus_analysis_port; uvm_analysis_port #(acc_output) mon_output_analysis_port; virtual acc_if vif; semaphore sema4; virtual function void build_phase(uvm_phase phase); super.build_phase(phase); if (!uvm_config_db#(virtual acc_if)::get(this, "", "acc_if", vif)) `uvm_fatal("MON", "Could not get vif") sema4 = new(1); mon_stimulus_analysis_port = new("mon_stimulus_analysis_port", this); mon_output_analysis_port = new("mon_output_analysis_port", this); endfunction virtual task run_phase(uvm_phase phase); super.run_phase(phase); forever begin fork begin @(posedge vif.clk); // output acc_output out = new; out.phase = vif.phase; out.cycle_end = vif.cycle_end; out.phase_quadrant = vif.phase_quadrant; `uvm_info(get_type_name(), $sformatf("Monitor found output %s", out.convert2str()), UVM_LOW) mon_output_analysis_port.write(out); end begin @(posedge vif.clk); // stimulus if (vif.load) begin acc_stimulus stimulus = new; stimulus.tuning_word = vif.tuning_word; stimulus.load = vif.load; `uvm_info(get_type_name(), $sformatf("Monitor found stimulus %s", stimulus.convert2str()), UVM_LOW) mon_stimulus_analysis_port.write(stimulus); end end join end endtask endclass
内容的提问来源于stack exchange,提问作者peter
相关产品推荐
相关产品推荐

