【前端验证】被动响应型uvm_model环境搭建——以握手型ram_model为例

简介: 【前端验证】被动响应型uvm_model环境搭建——以握手型ram_model为例

前言

我最近的学习趋势,完全是在弥补之前一些没来得及探究的问题导致的遗憾。因为我是从vmm入门的,而vmm方法学是更加接近于朴素的systemverilog验证思路,因此环境搭建比较散当然也比较灵活。而之后转到uvm方法学后,我只是简单了解了下思路就直接转方向了,因此一直遗留几个问题没有搞清楚,今天的被动响应型uvm_model环境就是其中一个。


场景

这个场景最初的需求是,环境产生一些原始数据,然后从中拆分出一些信息给DUT,另外一些给环境,DUT再根据得到信息从环境中获取剩余的信息,如果搭建朴素的验证环境结构基本就是下图:



这个结构在vmm中是很好实现的,因为generate和各类driver都是散装的,想怎么例化都可以,但是如何用uvm实现却难倒了当时的我。最近因为工作比较忙,所以突然有时间研究了一下这个问题(不是,在仔仔细细的把sequence和virtual sequence看完了之后,我突然有些顿悟。其实sequence就类似于上面的model,他的内部是可以做很多的操作的比如等待一个请求到来后做出相应发送一个包返回,而类似于多个drv协调工作的场景是可以通过virtual sequence来实现的。


于是呢今天我就要做一个简单的ram_model来实操下被动相应的模型搭建,同时后面工作中也可能会用到这样一个model。


思路

最后做出来的环境大体上就是这样的当然了并没有其中的dut。ram_model为uvm_env类型,直接例化于base_test中,只接收总线的读写信息,更新内部的ram array,并且根据读请求返回rdata。




最终完成的项目路径为 uvm_test_root: 汇总下各种uvm test 中的uvm_rw_test目录,其中agent的生成还是通过 gen_uvm_agent: 创建一个简单的握手型uvm随机接口agent 来快速实现,当然这个脚本我也有一些更新已经同步上传。


关键处理

关键处理就在于对sequence理解,以前我始终不明白,seq并不是一个component组件(我不太确定)可以挂在uvm_test这颗大树上,那除了发包之外还能怎么处理复杂的行为呢?看了书我才知道,原来只要sqr挂在了书上就可以了,而seq是可以借助`uvm_declare_p_sequencer(ram_sequencer)来通过p_sequencer使用对应sqr中的各种对象的。


所以最终vritual sequence的代码如下:

class ram_sequence extends uvm_sequence;
    bit[31:0] ram[15:0];
    extern function new(string name = "ram_sequence");
  extern virtual task body();
    extern virtual task r_body();
    extern virtual task w_body();
    `uvm_object_utils(ram_sequence)
    `uvm_declare_p_sequencer(ram_sequencer)
endclass: ram_sequence
function ram_sequence::new(string name = "ram_sequence");
  super.new(name);
endfunction: new
task ram_sequence::body();
    fork
        r_body();
        w_body();
    join_none
endtask: body
task ram_sequence::r_body();
    ar_transaction a_trc;
    //fork
    while(1)begin
        p_sequencer.a_port.get(a_trc);
        `uvm_warning("ram_sequence", "get a ar_trc!");
        for(int i=0; i<a_trc.size; i=i+32)begin
            r_transaction  r_trc = new();
            bit pkt_last = (i >= a_trc.size-32) && (i < a_trc.size);
            bit [31:0]pkt_data = ram[a_trc.addr];
            `uvm_warning("r_body", $sformatf("send r_trc.data='h%0h, last='h%0h", pkt_data, pkt_last));
            fork
            `uvm_do_on_with(r_trc, p_sequencer.r_sqr, {r_trc.data == pkt_data; r_trc.last == pkt_last; r_trc.cycle_post == 0;})
            join_none
        end
    end
endtask: r_body
task ram_sequence::w_body();
    w_transaction  w_trc;
    while(1)begin
        p_sequencer.w_port.get(w_trc);
        ram[w_trc.addr] = w_trc.data;
        //`uvm_warning("w_body", $sformatf("ram = 'h%0h", w_trc.data));
    end
endtask: w_body


而virtual sqr的任务就更加简单了,就是把a_agt.mon采集到的包和w_agt.mon采集到的包放在port里,等待seq使用。

class ram_sequencer extends uvm_sequencer;
    ar_sequencer a_sqr;
    r_sequencer  r_sqr;
    w_sequencer  w_sqr;
    uvm_blocking_get_port #(ar_transaction) a_port;
    uvm_blocking_get_port #(w_transaction)  w_port;
  extern function new(string name = "ram_sequencer", uvm_component parent=null);
  `uvm_component_utils(ram_sequencer)
endclass: ram_sequencer
function ram_sequencer::new(string name = "ram_sequencer", uvm_component parent=null);
  super.new(name, parent);
    a_port = new("a_port", this);
    w_port = new("w_port", this);
endfunction: new



在调行为的时候还发现了一个问题,那就是`uvm_do_on_with(r_trc, p_sequencer.r_sqr, {r_trc.data == pkt_data; r_trc.last == pkt_last; r_trc.cycle_post == 0;})这个操作的结束是依靠driver中的seq_item_port.item_done()来实现的,这也就导致如果DUT的r_ready一直为低会影响进程中取出ar_trc的时间点,明明ar早就到了也被接收了但是由于内部环境中取完了最终导致返回了错误的数据(这期间w_trc可能已经修改了ram值),因此这里采用fork-join_none的方式避免阻塞取ar_trc的操作。


相关文章
|
8月前
|
Web App开发 JavaScript 前端开发
从脚手架开始学前端 【第3期】Node.js环境搭建(CentOS 7)
从脚手架开始学前端 【第3期】Node.js环境搭建(CentOS 7)
131 0
|
8月前
|
Web App开发 JavaScript 前端开发
从脚手架开始学前端 【第2期】Node.js环境搭建(windows)
从脚手架开始学前端 【第2期】Node.js环境搭建(windows)
107 0
|
前端开发 测试技术
【前端验证】记录将发包量作为传参以加速debug的环境优化记录
【前端验证】记录将发包量作为传参以加速debug的环境优化记录
|
3月前
|
JSON 前端开发 Java
震惊!图文并茂——Java后端如何响应不同格式的数据给前端(带源码)
文章介绍了Java后端如何使用Spring Boot框架响应不同格式的数据给前端,包括返回静态页面、数据、HTML代码片段、JSON对象、设置状态码和响应的Header。
188 1
震惊!图文并茂——Java后端如何响应不同格式的数据给前端(带源码)
|
3月前
|
监控 JavaScript 前端开发
前端的混合之路Meteor篇(六):发布订阅示例代码及如何将Meteor的响应数据映射到vue3的reactive系统
本文介绍了 Meteor 3.0 中的发布-订阅模型,详细讲解了如何在服务器端通过 `Meteor.publish` 发布数据,包括简单发布和自定义发布。客户端则通过 `Meteor.subscribe` 订阅数据,并使用 MiniMongo 实现实时数据同步。此外,还展示了如何在 Vue 3 中将 MiniMongo 的 `cursor` 转化为响应式数组,实现数据的自动更新。
|
3月前
|
前端开发 数据安全/隐私保护
angular前端基本页面验证
angular前端基本页面验证
37 1
|
3月前
|
存储 前端开发 Java
验证码案例 —— Kaptcha 插件介绍 后端生成验证码,前端展示并进行session验证(带完整前后端源码)
本文介绍了使用Kaptcha插件在SpringBoot项目中实现验证码的生成和验证,包括后端生成验证码、前端展示以及通过session进行验证码校验的完整前后端代码和配置过程。
419 0
验证码案例 —— Kaptcha 插件介绍 后端生成验证码,前端展示并进行session验证(带完整前后端源码)
|
4月前
|
开发框架 前端开发 JavaScript
【博客开发】前端应用开发环境搭建(可复用)
【博客开发】前端应用开发环境搭建(可复用)
58 5
|
5月前
|
前端开发 JavaScript
这篇文章介绍了如何使用form表单结合Bootstrap格式将前端数据通过action属性提交到后端的servlet,包括前端表单的创建、数据的一级和二级验证,以及后端servlet的注解和参数获取。
这篇文章介绍了使用AJAX技术将前端页面中表单接收的多个参数快速便捷地传输到后端servlet的方法,并通过示例代码展示了前端JavaScript中的AJAX调用和后端servlet的接收处理。
这篇文章介绍了如何使用form表单结合Bootstrap格式将前端数据通过action属性提交到后端的servlet,包括前端表单的创建、数据的一级和二级验证,以及后端servlet的注解和参数获取。
|
5月前
|
开发者 图形学 API
从零起步,深度揭秘:运用Unity引擎及网络编程技术,一步步搭建属于你的实时多人在线对战游戏平台——详尽指南与实战代码解析,带你轻松掌握网络化游戏开发的核心要领与最佳实践路径
【8月更文挑战第31天】构建实时多人对战平台是技术与创意的结合。本文使用成熟的Unity游戏开发引擎,从零开始指导读者搭建简单的实时对战平台。内容涵盖网络架构设计、Unity网络API应用及客户端与服务器通信。首先,创建新项目并选择适合多人游戏的模板,使用推荐的网络传输层。接着,定义基本玩法,如2D多人射击游戏,创建角色预制件并添加Rigidbody2D组件。然后,引入网络身份组件以同步对象状态。通过示例代码展示玩家控制逻辑,包括移动和发射子弹功能。最后,设置服务器端逻辑,处理客户端连接和断开。本文帮助读者掌握构建Unity多人对战平台的核心知识,为进一步开发打下基础。
173 0