首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用Verilog VPI实现模拟器中的超前时间

使用Verilog VPI实现模拟器中的超前时间
EN

Stack Overflow用户
提问于 2013-06-11 20:33:31
回答 2查看 1.7K关注 0票数 4

我想要使用VPI编写一个Verilog任务来比特绑定一个接口;但是,我不知道如何从VPI任务中提前模拟时间。我目前正在使用Mentor Graphics Questa,但也可以访问Icarus Verilog。我已经成功地在我有兴趣控制的端口上强制值,但模拟时间不会提前,即使在vpi_put_value上指定了延迟也是如此。

这通常是如何实现的?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-06-12 17:19:32

您不能从VPI (例如,从always块)提前模拟时间-这会扰乱调度器。您的VPI代码在零模拟时间内被调用;您创建新事务,并告诉调度程序何时对这些事务执行操作。通常通过使用vpi_put_value的参数3和4来创建新事务(例如,指定阻塞或非阻塞,或将来的某个时间)。这基本上就是你在进程/总是块中所做的事情--一旦你返回了控制权,调度程序就会决定要做什么。

因此,简而言之,使用您的C代码来调度将来(或立即)的事务,然后返回,以便调度器可以确定要做什么。你不能在你的C代码中间放一个(模拟)等待。我认为,在你的例子中,你想要做的是在Verilog中有一个主控循环,使用#10的东西,并在适当的时候调用你的C代码。

编辑

Re您的评论:我不认为有任何规范,如果您尝试多次调用vpi_put_delay,但在返回之前有不同的延迟;您看到的只是最后一个延迟,这并不让我感到惊讶。也许有一点类似,在always块中有多个NBA指向同一个对象;最后一个获胜。如果您确实希望在返回之前在同一对象上调度多个事务,请使用带有多个延迟列表的vpi_put_delays (例如在Sutherland,p194中)。

但是有什么意义呢?这实际上为您提供了VHDL的after功能,以及一个事务列表。它不会提前模拟时间。您同时将所有事务添加到事件队列中。您不能在“稍后”的模拟时间读取任何其他对象的值,因为没有较晚的模拟时间。参见2005lrm中的5.6.4 (不是SystemVerilog LRM;它是另一种语言)。这就像在always块中有多个具有RHS延迟的非阻塞赋值-所有RHS操作数都会立即读取,而不会提前时间,但LHS更新会安排在以后进行。

忘记时间的前进。你不能这样做,因为你会弄乱调度器队列上的其他所有东西。如果其他人在您的时间推进过程中安排了更新,该怎么办?您需要将控制权返回给Verilog代码(即,给调度器),从而调度器可以提前时间。

票数 2
EN

Stack Overflow用户

发布于 2014-01-04 07:41:50

我知道这个答案有点晚,但我不确定之前的答案是否解决了您最初的请求,尽管它们不是错误的。

您不能在一个模拟步骤中多次调用同一句柄上的vpi_put_value,以便及时对值进行排队。只有最后一个调用才会有任何效果。

您想要做的是调用vpi_put_value来强制您现在需要的值,然后使用cbAfterDelay注册一个回调,以便您下次更改该值时使用。当您的回调处理程序执行时,模拟时间将提前到这一点,因此您可以在句柄上强制使用下一个值。

您的回调函数将执行以下操作:

代码语言:javascript
复制
static int32_t handle_vpi_callback(p_cb_data cb_data) {
    // advance your driver state using user_data to retrieve current state
    // call vpi_put_value with new signal value
    // determine next time value requiring action
    // register another callback
}

并注册定时回调:

代码语言:javascript
复制
s_cb_data cb_data_s;
s_vpi_time vpi_time_s;
p_vpi_cb_user_data user_data;

vpi_time_s.type = vpiSimTime;
vpi_time_s.high = (uint32_t)(time_ps>>32);
vpi_time_s.low  = (uint32_t)(time_ps);

cb_data_s.reason    = cbAfterDelay;
cb_data_s.cb_rtn    = handle_vpi_callback;
cb_data_s.obj       = NULL;
cb_data_s.time      = &vpi_time_s;
cb_data_s.value     = NULL;
cb_data_s.user_data = (char *)user_data;

vpiHandle new_hdl = vpi_register_cb(&cb_data_s);

这在行为上等同于Verilog代码:

代码语言:javascript
复制
#10 value = something;
#5  value = something_else;

如果您的总线与时钟同步,您可能希望仅使用cbAfterDelay驱动时钟(或从Verilog中的进程驱动它),并通过在时钟本身上注册cbValueChange来提升驱动程序状态。这将模拟在模拟器中运行的时钟进程。

如果您熟悉Python,那么您可能会对一个名为Cocotb的开源项目感兴趣,该项目将VPI抽象出来,为在模拟器中运行的被测设备提供一个很好的Pythonic接口。如果您有想要接口的现有C++代码,那么使用Python语言可能会节省一些时间。

例如,要通过接口发送缓冲区,驱动程序发送例程可能如下所示:

代码语言:javascript
复制
def send(dut, buffer):
    """Send a buffer over a packetised bus"""

    bus_width = len(dut.data) / 8
    firstword = True

    while buffer:
        yield RisingEdge(dut.clk)

        nbytes = min(len(buffer), bus_width)
        dut.data.value = buffer[:nbytes]
        dut.valid.value = 1
        dut.startofpacket.value = int(firstword)

        if nbytes <= buswidth:
            dut.endofpacket.value = 1
            dut.empty.value = bus_width - len(buffer)
            buffer = ""
        else:
            buffer = buffer[buswidth:]

        firstword = False

    yield RisingEdge(dut.clk)
    dut.valid.value = 0
    dut.endofpacket.value = 0

免责声明:我是Cocotb开发人员之一。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17044202

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档