如何在继续TCL脚本之前等待Modelsim模拟完成

时间:2015-06-08 19:43:23

标签: tcl vhdl modelsim

我正在尝试在Modelsim中执行回归测试。我调用一个TCL脚本来编译我的源文件并启动vsim。我启动一个.do文件,它运行一系列测试工具,所有测试工具都输出结果文件。我要添加的是一个自动检查器,用于验证结果文件是否与已知的良好运行匹配。问题是在启动modelsim之后,TCL脚本在执行检查程序之前不会等待完成模拟" results_pass.py"。

set nice_pid [open "|$modelsim_dir/vsim.exe -do do_files/vsim.do -novopt -gui"]
cd ../../Scripts
set script_name "results_pass.py"
set tb_name "rcp"
call_python $script_name $tb_name
vwait forever

对于那些想知道我为什么要调用Python脚本的人。主要是因为我对TCL知之甚少,但没有时间将传统的TCL脚本更改为Python。

无论如何,我相信我可以在第1行和第2行之间留下一些东西,等待modelsim已经完成执行我的.do文件的某些指示。任何建议都表示赞赏。

5 个答案:

答案 0 :(得分:4)

您是否尝试过VUnit?https://github.com/LarsAsplund/vunit

它是一个开源的VHDL测试框架,已经做了你想要的。

它可以并行运行测试以及不同的泛型值。

测试平台可以有多个测试,可以在独立的模拟中运行,也可以在同一个模拟中运行。

它可以发出Jenkins理解的测试报告,其中包含测试输出,运行时和状态。

它附带了一个方便功能的VHDL库,例如check_equal。

它具有完整的VHDL依赖扫描,因此可以添加文件,VUnit将知道要逐步编译的内容,以加快编辑/编译/运行周期。

可以运行用户定义的模拟后检查以验证例如针对黄金数据的输出文件。

除了批量运行外,它还可以在带有单个标志的GUI中启动测试。

它支持与Aldec和NVC即将推出的Modelsim和GHDL。

我个人用它来管理200多个测试用例。

免责声明我是主要作者之一。 它的创建是为了避免世界上每个VHDL团队用不同质量的内部脚本重新发明轮子。

答案 1 :(得分:2)

回答我自己的问题,在收到回复之前我最终开始工作。其他建议的解决方案可能会更好。

首先,我修改了我的.do文件,在下面添加第3行。

page('/tvAdd', function () {
  app.route = 'tv';
  app.childRoute = 'tvAdd';
});

然后我按如下方式修改了我的TCL脚本。

project open my_project.mpf
do do_files/regression.do
file delete -force "lock.txt"

这样调用进程在继续之前等待Modelsim完成。

对于任何想要在这里使用它的人来说,我发现了here

的call_python proc
set nice_pid [open "|$modelsim_dir/vsim.exe -do do_files/vsim.do -novopt -gui"]

,# Create a "lock file" that is cleared at the completion of the .do file.
set lock_file "lock.txt"
set lock_PID [open $lock_file w]
close $lock_PID  

while {[file exists $lock_file]} 
    {after 1000}

cd ../../Scripts
set script_name "results_pass.py"
set tb_name "my_tb"
call_python $script_name $tb_name
vwait forever

$ tb_name只是我的python脚本的参数。

答案 2 :(得分:1)

您应该使用读写打开子进程并设置fileevent以侦听来自子进程管道的可读事件。当子进程退出时,它会关闭它的标准输出,当你从这个管道读取时,你会收到一个[eof]为真的可读事件。

如果你不熟悉tcl和异步通道处理,我已经做了一个使用两个tcl脚本的快速示例,客户端驱动服务器进程。当服务器在stdin上“退出”时它将退出。客户端进程看到通道关闭并清理然后退出。关键命令是fconfigure,用于将通道设置为非阻塞,fileevent设置在管道上发生可读事件时调用的过程。

server.tcl

proc main {} {
    while {[gets stdin line] != -1} {
        if {[string match "quit" [string trim $line]]} {
            break
        }
        puts "ECHO $line"
    }
    return 0
}
main

client.tcl

proc Read {chan} {
    set len [gets $chan line]
    if {[eof $chan]} {
        puts stderr "eof received"
        set ::forever quit
        fileevent $pipe readable {}
    }
    puts stderr "RECV: $len '$line'"
}
proc main {} {
    set pipe [open |[list tclsh server.tcl] r+]
    fconfigure $pipe -blocking 0 -buffering line -translation auto
    fileevent $pipe readable [list Read $pipe]
    after 500 [list puts $pipe begin]
    after 1000 [list puts $pipe quit]
    after 2000 [list set ::forever timeout]
    vwait ::forever
    puts "exit with status '$::forever'"
    return 0
}
main

预期产出

c:\src>tclsh client.tcl
RECV: 10 'ECHO begin'
eof received
exit quit

答案 3 :(得分:1)

TCL实际上是从公开呼叫返回一个频道,而不是pid。你可以做几件事:

  1. 使用exec命令而不是打开管道,因为您显然不需要异步I / O.
  2. 使用close命令关闭我相信通过wait()系统调用等待进程关闭的管道。

答案 4 :(得分:1)

我通过在Tcl中定义一个虚拟的sentinal proc来解决这个从Python自动化Modelsim的问题。使用I / O通道的管道运行vsim。在我想要运行的每个命令之后发送sentinel命令。然后我等着看" sentinel"文本出现在输出流中,以保证上一个命令完成。

# Define a dummy sentinel proc
self.p.stdin.write('proc sentinel {} {}\n')
self.p.stdin.write(cmd + '\n')
self.p.stdin.write('sentinel\n')
self.p.stdin.flush()
while True:
  if self.process_done(): break  # The process died

  out.append(get_output(self.outq))
  if '> sentinel' in out[-1]: break # Stop when we see the prompt with the sentinel

您可以看到完整的自动化代码here。当从单独的Tcl解释器控制Modelsim时,可以使用类似的方法。