EDA/IC设计
IP验证增量仿真技术的运用
验证涉及每个阶段的迭代循环:仿真、检查结果,改变激励或设计或调试设置,重新仿真并不断重复。在系统调试过程中,软硬件在多次运行之间可能会有改变,因此系统调试也变得更为复杂。
某些验证可以被分解成多个可以并行运行的小型仿真。这种方法对许多旨在确认硬件本身的测试来说是非常有效的,但并不是所有测试都适合。像视频流处理这类测试就很难被分解成多个较小的测试,因为这种处理的对象是整个数据流,而且每个帧都依赖于它前面的帧。
对系统硬件或软件所做的修改可能并不会立即影响系统行为,对不是马上要执行的软件所做的代码修改在它运行之前不会改变系统行为。例如,虽然对一个1,000个周期后才被调用的软件例程做了修改,但系统行为在前面1,000个周期内是不变的。
设计师需要能够从代码或设计修改开始起作用的那点开始恢复仿真。在上述例子中,这意味着设计师应该在第1,000个周期时作出代码修改并重新启动仿真,不用再次运行前面1,000个周期。
当设计已经改变、新的块可能已经增加到系统模型中时,问题就比较难解决了。设计师没有这个新块过去保存的数据用于恢复。另外,设计师可能有许多IP块由于各种理由(如编译的,受保护的IP块)而表现为黑盒子,这些块将无法参与保存/恢复操作。
假如设计师可以对设计作出修改,相信寄存器值没有变化,并能重新启动修改后的仿真,那么设计师如何能根据硬件或软件变化而知道系统行为将要改变的确切点呢?不知道这点的话,设计师将要么重新启动得太早而浪费不需要的仿真周期,要么重新启动得太晚而错过一些变化了的行为。
另外,如果系统行为很早就改变了,但只是发生在设计的很小部分又会怎样呢?即使系统的小部分受到影响,系统的绝大部分模块在上千个周期内也不会受到改变的影响。
理想的解决方案是只在系统行为即将从上一次运行基础上发生改变时的那个点重新启动系统中的每个主要模块。然而这样做显然行不通,因为只要任何一个模块开始执行,它就要求与其他模块发生交互,就需要来自这些模块的信号,并发送信号给这些模块。
图:在少量修改后运行的仿真经常会完全重复前次仿真过程已经完成的工作。
解决这个问题的方法之一是考虑在I/O边界处保存每个块的行为,使得捕捉到的I/O信号可用于复用,而不用实际计算每个模块的仿真行为。复用保存在I/O边界的信号可以节省重新计算该模块行为所需的计算工作,减少工作量,进而提升系统性能。
当设计运行到修改开始影响特定模块的仿真时,设计师可以再次开始仿真,并停止使用保存的信号值。
设计师如何知道仿真何时已经改变了呢?除了复用保存的模块输出值外,设计师还保存了输入信号。在每个周期内,设计师可以将实际的输入信号值与保存的输入信号值进行比较。当保存值与实际值匹配时,设计师就能知道输出结果与上次运行结果是相同的。
这种方法的效果取决于假设执行信号和检查点读取所需的时间小于执行实际仿真所需时间,从而加速仿真的能力。显然,具有内部活动和少量I/O引脚的大模块的速度提升幅度要比具有许多I/O信号的小模块显著得多。在前一种情况下,保存和恢复I/O信号的成本要低于仿真模块行为所需付出的代价。在后一种情况中,在某些点保存和恢复信号数据的成本将超过仿真模块的代价。
有助于减少必须保存的数据量的一种方法是只在时钟周期上采样I/O信号。通用使用周期级(cycle-level)接口,设计师可以确保他或她只需要一个周期采样或分析信号值一次,而不是每个周期内以随机次数进行采样。因为大多数总线接口是周期精确型接口,因此这种方法通常没有什么问题。
实现这种系统所需要的功能要求设计师:
. 监视和捕捉特定模块的输入和输出。
. 将接口转换成在周期边界上工作。
. 以指定间隔查明所有寄存器值。
. 从保存文件中恢复出信号用作输出值。
. 将保存的输入值与实际值进行比较。
. 发现失配时,加载最近的检查值,只允许该模块仿真到当前时间,然后从该点开始继续正常的仿真。
Carbon设计系统公司在周期级模型编译器的“重放”特性中实现了上述功能。该模型编译器接收寄存器传输级代码,创建周期级编译后的模型,并提供周期级模块接口。其余功能则在编译期间于基本的I/O模型边界创建的部分包装器(wrapper)中实现。
全部0条评论
快来发表一下你的评论吧 !