You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为自动售货机设计编写UVM Driver与Sequence Item(面试题)

自动售货机DV面试实现优化建议

一、Sequence Item问题与优化

原实现的问题点

  1. 枚举类型错误:定义的currency枚举包含3,但规格明确货币面额为1、2、5、10,属于规格不符。
  2. randc使用不当:randc currency value中randc是周期性不重复随机,仅用于同面额约束场景,用普通rand即可,避免不必要的随机限制。
  3. 约束过于僵化:constraint c1 {amount.sum() >=60 ;}强制总金额≥60,但测试场景需要覆盖总金额不足60的情况(如59美元),应改为可动态开关的约束,或默认不限制,由sequence按需添加。
  4. 缺少UVM必要宏与构造函数:未添加uvm_object_utils注册宏及构造函数,无法正常在UVM环境中实例化与使用。
  5. 输出信号定义冗余:change和soda_out是DUT的输出信号,无需在sequence item中随机化,应作为预期值的存储变量,可添加计算函数自动生成预期结果,方便后续比对。

优化后的Sequence Item示例

class vending_pkt extends uvm_sequence_item;
  typedef enum {DOLLAR_1, DOLLAR_2, DOLLAR_5, DOLLAR_10} currency_t;
  rand currency_t amount[]; 
  rand currency_t same_currency; // 用于同面额约束,替换原randc
  int expected_change;
  bit expected_soda_out;

  // UVM注册宏
  `uvm_object_utils(vending_pkt)

  // 构造函数
  function new(string name = "vending_pkt");
    super.new(name);
  endfunction

  // 默认不限制总金额,由sequence根据场景添加约束
  constraint amount_size {amount.size() inside {[1:100]};} // 限制数组长度合理范围

  // 同面额约束:可通过sequence的constraint_mode控制开关
  constraint same_currency_c {
    foreach(amount[i]) amount[i] == same_currency;
  }

  // 包含所有面额约束:可通过constraint_mode控制开关
  constraint all_currency_c {
    amount.sum() with (int'(item == DOLLAR_1)) > 0;
    amount.sum() with (int'(item == DOLLAR_2)) > 0;
    amount.sum() with (int'(item == DOLLAR_5)) > 0;
    amount.sum() with (int'(item == DOLLAR_10)) > 0;
  }

  // 自动计算预期输出
  function void post_randomize();
    int total = 0;
    foreach(amount[i]) begin
      case(amount[i])
        DOLLAR_1: total += 1;
        DOLLAR_2: total += 2;
        DOLLAR_5: total += 5;
        DOLLAR_10: total += 10;
      endcase
    end
    if(total >= 60) begin
      expected_soda_out = 1;
      expected_change = total - 60;
    end else begin
      expected_soda_out = 0;
      expected_change = 0; // 若设计要求退钱则改为total,需按规格调整
    end
  endfunction
endclass

二、Driver问题与优化

原实现的问题点

  1. 时序不符合规格:
    • 规格要求“每次投入货币后,valid信号在下一周期拉高”,原代码中valid拉高后未拉低,会持续保持高电平,不符合“拉高一个周期”的要求。
    • done信号仅赋值为1,未处理拉低逻辑,且未考虑与最后一次valid信号的时序关系。
  2. run_phase结构错误:仅执行一次get_next_item就结束,无法持续处理sequence发送的多个交易。
  3. 时钟域不一致:drive任务中混用vif.cb和@(posedge clk),应统一使用virtual interface的clocking block,保证时序对齐。

优化后的Driver伪代码

virtual task run_phase(uvm_phase phase);
  vending_pkt req;
  forever begin // 持续获取交易
    seq_item_port.get_next_item(req);
    drive(req);
    seq_item_port.item_done();
  end
endtask

virtual task drive(vending_pkt req);
  int i = 0;
  // 初始化信号
  vif.cb.amount <= '0;
  vif.cb.valid <= 1'b0;
  vif.cb.done <= 1'b0;

  repeat(req.amount.size()) begin
    // 1. 投放当前面额货币
    case(req.amount[i])
      DOLLAR_1: vif.cb.amount <= 1;
      DOLLAR_2: vif.cb.amount <= 2;
      DOLLAR_5: vif.cb.amount <= 5;
      DOLLAR_10: vif.cb.amount <= 10;
    endcase
    @(posedge vif.cb);

    // 2. 下一周期拉高valid一个周期
    vif.cb.valid <= 1'b1;
    @(posedge vif.cb);
    vif.cb.valid <= 1'b0; // valid拉低
    i++;
  end

  // 3. 所有货币投入完成后,下一周期拉高done一个周期
  @(posedge vif.cb);
  vif.cb.done <= 1'b1;
  @(posedge vif.cb);
  vif.cb.done <= 1'b0; // done拉低
endtask

三、补充测试场景

在你列出的基础场景外,需补充以下关键测试场景:

  • 找零组合验证:总金额为73(找零13,即10+2+1)、87(找零27,即10+10+5+2)等,验证DUT找零的面额组合是否正确。
  • 小面额凑单场景:用最多1美元(60个1)、最多2美元(30个2),或零散小面额凑60(如58个1+1个2),验证金额累加逻辑的正确性。
  • 异常信号时序场景:
    • valid连续多周期拉高(未切换amount)
    • valid与done同时拉高
    • done信号在货币未投完时提前拉高
  • 非法面额输入场景:输入规格外的面额(如3、20),验证DUT的错误处理逻辑(如忽略、报错)。
  • 连续交易场景:连续完成多次购买(如第一次投60拿汽水,第二次投70拿汽水+找零10),验证DUT的状态重置是否正常。
  • 大额超额场景:投入100美元,验证找零40美元的计算与输出是否正确。
  • 金额不足的退钱场景:若设计支持投钱未达60时退钱,需测试投59美元后拉done,验证DUT是否退回全部金额。

内容的提问来源于stack exchange,提问作者Grace90

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 05:30:18