我想要使用VPI编写一个Verilog任务来比特绑定一个接口;但是,我不知道如何从VPI任务中提前模拟时间。我目前正在使用Mentor Graphics Questa,但也可以访问Icarus Verilog。我已经成功地在我有兴趣控制的端口上强制值,但模拟时间不会提前,即使在vpi_put_value上指定了延迟也是如此。
这通常是如何实现的?
发布于 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代码(即,给调度器),从而调度器可以提前时间。
发布于 2014-01-04 07:41:50
我知道这个答案有点晚,但我不确定之前的答案是否解决了您最初的请求,尽管它们不是错误的。
您不能在一个模拟步骤中多次调用同一句柄上的vpi_put_value,以便及时对值进行排队。只有最后一个调用才会有任何效果。
您想要做的是调用vpi_put_value来强制您现在需要的值,然后使用cbAfterDelay注册一个回调,以便您下次更改该值时使用。当您的回调处理程序执行时,模拟时间将提前到这一点,因此您可以在句柄上强制使用下一个值。
您的回调函数将执行以下操作:
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
}并注册定时回调:
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代码:
#10 value = something;
#5 value = something_else;如果您的总线与时钟同步,您可能希望仅使用cbAfterDelay驱动时钟(或从Verilog中的进程驱动它),并通过在时钟本身上注册cbValueChange来提升驱动程序状态。这将模拟在模拟器中运行的时钟进程。
如果您熟悉Python,那么您可能会对一个名为Cocotb的开源项目感兴趣,该项目将VPI抽象出来,为在模拟器中运行的被测设备提供一个很好的Pythonic接口。如果您有想要接口的现有C++代码,那么使用Python语言可能会节省一些时间。
例如,要通过接口发送缓冲区,驱动程序发送例程可能如下所示:
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开发人员之一。
https://stackoverflow.com/questions/17044202
复制相似问题