UVM组件故事版 · driver:那个把"指令"翻译成"电信号"的人

UVM组件故事版 · driver:那个把"指令"翻译成"电信号"的人


想象一下打仗。

将军坐在指挥部里,写了一份作战命令:"明天凌晨三点,从A点向B点发起进攻,炮火掩护从C方向过来。"

这份命令写得很清楚,但问题来了------士兵在战壕里,拿到的是一张写满字的纸。他们听不懂"炮火掩护从C方向"是什么意思,他们只知道:什么时候该扣扳机,往哪个方向开枪,火力往哪打。

中间需要一个人,把将军的命令翻译成士兵能执行的具体动作。

这个翻译官,就是driver。


driver到底在干什么

在UVM的世界里,这个场景是这样的:

arduino 复制代码
sequence(将军)→ 发送一个transaction:"我想要你发一个读命令,读地址0x1000"
    ↓
sequencer(传令兵)→ 把transaction传递给driver
    ↓
driver(翻译官)→ 把transaction转换成具体的时序信号,送到DUT的接口上
    ↓
DUT(士兵)→ 收到电信号,执行实际操作

driver做的事情本质上是两件:

1. 接收上层传来的数据对象(transaction)

2. 把这个对象"翻译"成DUT能看懂的时序信号

比如DUT是一个UART模块,它的接口信号长这样:

复制代码
uart_tx    → 发送数据的信号
baud_rate  → 波特率信号

driver从sequence那里拿到一条"发数据0x55"的消息,driver要做的事情是:

markdown 复制代码
1. 把0x55转成二进制:01010101
2. 按照UART协议加上起始位、校验位、停止位
3. 在对应的时钟沿上,把这些bit一个个送到uart_tx信号上

这中间涉及到很精确的时序控制------早了不行,晚了不行,数据宽度不对不行。driver就是那个必须分毫不差的人。


为什么会有人把driver写错

见过两种典型错误:

第一种:把所有事情都塞给driver

有人觉得driver是唯一能接触DUT的人,所以恨不得把所有的判断逻辑都写在driver里:

kotlin 复制代码
driver里写:if (data == 0x55) { 发送A } else if (data == 0xAA) { 发送B }

这是新手常干的事情。driver不是用来判断"做什么"的地方,那是sequence和test的工作。driver的职责是:我收到了一个任务,把它正确地执行下去。

第二种:不懂得和sequencer配合

driver和sequencer之间有一个握手机制:

arduino 复制代码
driver发送req给sequencer:"我准备好了,给我下一个任务"
sequencer把下一个transaction传给driver
driver执行,然后再次请求

这个握手叫seq_item_port,是UVM里最常见的组件间通信方式。很多人写driver的时候跳过了这个理解,导致driver只跑一次就卡住了,或者跑起来之后和sequence的节奏完全对不上。


driver的正确打开方式

一个正确的driver,通常长这样:

scss 复制代码
class uart_driver extends uvm_driver #(uart_transaction);
  virtual uart_if vif;  // 硬件接口的虚接口
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    if (!uvm_config_db #(virtual uart_if)::get(this, "", "vif", vif))
      `uvm_fatal("NOVIF", "virtual interface must be set");
  endfunction
  
  // driver的核心:不断从sequencer拿任务,执行它
  task run_phase(uvm_phase phase);
    forever begin
      seq_item_port.get_next_item(req);  // 从sequencer拿任务(阻塞等待)
      drive_transaction(req);             // 执行任务
      seq_item_port.item_done();          // 告诉sequencer任务完成了
    end
  endtask
  
  // 把transaction翻译成时序信号
  virtual protected task drive_transaction(uart_transaction tr);
    vif.rst_n <= 0;  // 假设要reset一下
    #10;
    vif.rst_n <= 1;
    
    // 发送起始位
    vif.uart_tx <= 1'b0;
    #(BIT_PERIOD);
    
    // 发送8位数据
    for (int i = 0; i < 8; i++) begin
      vif.uart_tx <= tr.data[i];
      #(BIT_PERIOD);
    end
    
    // 停止位
    vif.uart_tx <= 1'b1;
    #(BIT_PERIOD);
  endtask
endclass

核心循环就三步:

scss 复制代码
get_next_item() → drive_transaction() → item_done()

理解了这三步,driver就不难了。


打个比方收尾

sequence是将军,写作战计划。sequencer是传令官,把计划传递给翻译官。driver是翻译官,把将军的命令翻译成士兵能执行的具体动作------几时几分,从哪个方向,开什么枪。

翻译官不需要知道为什么要打这一仗,那是将军的事。翻译官只需要把命令准确无误地执行到位。

driver在UVM验证环境里的角色,就是这样:精确执行,不多不少。


下篇预告:monitor------那个躲在角落里,把一切看见的都记下来的人。




UVM军事系列 · 第一篇:driver------那个把命令翻译成战场语言的人


特种作战行动开始前,指挥部传来一份任务书:

"凌晨0300,A组从东侧突入,B组掩护,C组接应。炮火支援在C组进入位置后30秒启动。"

这份任务书写得清清楚楚,但问题是------前线的士兵拿到的是无线电里嘈杂的指令,他们听不懂"炮火支援在C组进入位置后30秒启动"这种协调语言,他们只知道:什么时候冲,往哪开枪,枪口抬多高。

中间需要一个人,把指挥部的命令翻译成前线士兵能执行的具体动作。

这个人叫通讯兵 ,也叫传译官

在UVM的世界里,这个角色,叫driver


driver到底在干什么

特种部队的通讯兵,是指挥部和前线之间唯一的翻译通道。

他的工作看起来很简单:收到命令,执行命令。但细看下去,每一步都藏着细节:

复制代码
mission_order(任务书)→ 作战参谋排序 → 通讯兵接收任务 → 翻译成战场信号 → 士兵执行
    指挥部                      调度官                通讯兵              物理动作

driver做的事情本质上只有两件:

第一,接收上层传来的指令对象(mission order)。

第二,把这个指令翻译成DUT能看懂的时序信号。

比如,DUT是一个通信电台模块,它的物理接口信号长这样:

css 复制代码
tx_data[7:0]    → 8位数据线
tx_valid        → 数据有效信号(高电平表示data有效)
tx_ready        → 电台准备好了(握手信号)
clk             → 时钟信号

driver从sequencer那里拿到一条"发送数据0xA5"的消息,driver要做的事情是:

arduino 复制代码
第一步:在tx_valid上拉高一个时钟周期,同时把0xA5放到tx_data上
第二步:等待tx_ready握手信号(告诉士兵"我收到命令了")
第三步:清空tx_valid,一个命令执行完毕

这中间涉及精确的时序控制------早了,电台还没准备好,数据丢了;晚了,士兵的火力窗口错过了。driver就是那个必须分毫不差的人。


为什么会有人把通讯兵派错岗位

见过两种典型的错误:

第一种:让通讯兵去决定打不打。

有人觉得通讯兵是唯一能接触前线的人,所以把"战术判断"也塞给他:

arduino 复制代码
driver里写:if (urgent_mission) { 立即执行 } else { 排队等 }

这是新手常干的事。通讯兵不是战术决策者,那是作战参谋的活。通讯兵的职责是:我收到命令了,准确地翻译和执行。 翻译官不需要知道为什么要打这一仗,那是将军的事。

第二种:通讯兵不听参谋的调度,擅自行动。

driver和sequencer之间有一个握手机制:

arduino 复制代码
通讯兵(driver):"我执行完了,下一个任务是什么?"
作战参谋(sequencer):"收到,给你新的任务。"
通讯兵执行新任务,再问:"执行完了,下一个呢?"
......循环往复

这个握手在UVM里叫seq_item_port,是UVM中最常见的通讯方式。多数人写driver的时候跳过了这个理解,导致通讯兵只跑一轮就停在那里,或者自顾自地一直发,完全不听参谋的节奏。


driver的正确打开方式

一个正确的通讯兵(driver),是这样的:

scala 复制代码
class comm_driver extends uvm_driver #(mission_item);
  virtual radio_if vif;  // 电台物理接口
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    // 从配置池里拿到电台接口
    if (!uvm_config_db #(virtual radio_if)::get(this, "", "vif", vif))
      `uvm_fatal("NORADIO", "电台接口未配置,通讯兵没有电台怎么打仗?")
  endfunction
  
  // 通讯兵的日常:等命令 → 执行 → 报告完成 → 等下一个
  task run_phase(uvm_phase phase);
    forever begin
      // 从作战参谋那里拿到任务(阻塞等待,没有任务就待命)
      seq_item_port.get_next_item(req);  
      transmit_mission(req);              // 执行任务
      seq_item_port.item_done();           // 报告参谋:任务完成
    end
  endtask
  
  // 具体的翻译工作:把任务对象变成电台信号
  virtual protected task transmit_mission(mission_item tr);
    // 第一步:把数据放到数据线上,同时拉高有效信号
    @(posedge vif.clk);
    vif.tx_valid <= 1'b1;
    vif.tx_data  <= tr.payload;
    
    // 第二步:等待电台握手确认
    do begin
      @(posedge vif.clk);
    end while (vif.tx_ready == 1'b0);  // 电台没ready就一直等
    
    // 第三步:任务完成,清除有效信号
    @(posedge vif.clk);
    vif.tx_valid <= 1'b0;
  endtask
endclass

核心循环就三步:

scss 复制代码
get_next_item()  →  transmit_mission()  →  item_done()
  从参谋拿任务       执行翻译              报告完成

理解这三步,通讯兵就不难当了。


打个比方收尾

sequence是将军,写作战命令。sequencer是作战参谋,把命令排序整理。driver是通讯兵,把参谋整理好的命令翻译成前线士兵能执行的具体动作------几点几分,从哪个方向,打什么目标,打几发。

通讯兵不需要知道为什么要打这一仗,那是将军的事。通讯兵只需要把命令准确无误地传达下去。

迟一秒不行,早一秒也不行,信号错了更不行。

这就是driver在UVM验证环境里的角色:精确执行,不多不少。


下篇预告:monitor------那个躲在暗处,把战场上发生的一切都记录下来的人。侦察兵不上前线,但战场上没有人比他更清楚发生了什么。

相关推荐
森利威尔电子-2 天前
森利威尔SL3150H |PIN TO PIN 替换 MRDC88-1 10~150V 输入 0.6A 降压电源芯片
单片机·嵌入式硬件·物联网·集成电路·芯片
zhangfeng11332 天前
那nvidia orim车载gpu tee安全飞地 和天垓 100 gpgpu的 飞地 ,大概有多大存储量 ,解密流程
人工智能·深度学习·安全·语言模型·gpu算力·芯片
zhangfeng11332 天前
天数智芯天垓 100 加密大模型分布式部署安全方案
人工智能·分布式·安全·transformer·gpu算力·芯片
zhangfeng11332 天前
车载gpu 飞地 只保存密钥 不保存 权重 Orin确实有TEE安全飞地(TSEC/OP-TEE)
服务器·网络·人工智能·安全·transformer·芯片
zhangfeng11332 天前
把权重写死在芯片的架构 Taalas(HC1)芯片:车载 GPU / 智能驾驶 / 机器人 / 算力卡适配总结
人工智能·深度学习·语言模型·架构·机器人·gpu算力·芯片
IC修真院3 天前
高赞问题:NPU可不可以代替GPU?
gpu·ic设计·芯片·微电子·数字ic·npu
zhangfeng11333 天前
2021-2026 年全球 传统厂家AI 算力卡 GPU 前沿技术研究报告
人工智能·深度学习·语言模型·gpu算力·芯片
zhangfeng11333 天前
光驱动的 AI 算力卡,也就是光子计算(Photonic Computing)芯片,用光子(光)代替电子来做矩阵乘法和数据传输
人工智能·语言模型·矩阵·架构·transformer·芯片
zhangfeng11333 天前
定制化,面向大语言模型的GPU,Etched 把 Transformer 架构直接“烧“进硅片
语言模型·架构·transformer·芯片
zhangfeng11333 天前
非传统架构 AI 算力卡前沿研究报告:技术痛点、破局路2021-2026
人工智能·语言模型·transformer·gpu算力·芯片