开发半导体集成电路测试程序的方法和结构的制作方法

文档序号:6655860阅读:1714来源:国知局

专利名称::开发半导体集成电路测试程序的方法和结构的制作方法
技术领域
:本申请是在2004年2月6日提交的共同未决的美国申请No.10/772,434,“MethodandStructuretoDevelopaTestProgramforSemiconductorIntegratedCircuits”的部分继续申请,并要求该申请的权益。该申请No.10/772,434要求2003年2月14日提交的申请No.60/447,839,“MethodandStructuretoDevelopaTestProgramforSemiconductorIntegratedCircuits”的权益。本申请还要求2004年5月22日提交的美国临时申请No.60/573,577,“SoftwareDevelopmentinanOpenArchitectureTestSystem”的权益。所有上述申请都转让给了Advantest公司,并且其全部内容在此引作参考。本发明涉及用于半导体测试的自动测试设备(ATE)领域。更具体地,本发明涉及用于在模块测试系统中管理模式目标文件的方法和系统。
背景技术
:在传统的ATE系统中,模式目标文件的内容与设备提供商专有属性的硬件密切相关。没有将模式目标文件集成在测试系统中以便适应各种设备提供商专有属性的硬件的标准。此外,模块设备提供商不愿与公众分享他们的专有格式,因此,很难开发一种通用的模式目标格式。此外,实行一种公用的格式可能产生额外的开销,这可能导致牺牲模式应用的效率。因此,没有一种模式数据公用的目标文件格式能应用于各种模块设备提供商。模块设备提供商不得不提供他们自己的模式编译器来将模式源文件编译为模式目标文件。这导致了每当一个设备提供商选择使用一个不同设备提供商的测试设备时,都要翻译模式文件的烦人的轮回。大家都希望克服这些缺陷。因此,需要一种开放体系的模块测试系统。更具体地,需要一种在模块测试系统中管理模式目标文件的机制。
发明内容本申请描述使用面向对象的构造(如C++对象和类)的测试程序开发。更具体地,该方法适合开发用于开放体系测试器的程序,如转让给本发明受让人的美国申请No.60/449,622、No.10/404,002以及No.10/403,817中描述的测试器。本发明的一个实施例提供一种方法,用于通过以通用的面向对象的构造(如C/C++)描述测试系统资源、测试系统配置、模块配置、测试顺序、测试计划、测试条件、测试模式、以及定时信息来在半导体测试系统(如自动测试装置(ATE))上开发测试被测试设备的测试程序。包含这些描述的文件存储在测试系统可访问的或使用这些文件的有关设备的存储器,即计算机可读介质中。描述测试系统资源可以包括指定资源类型,其中资源类型与对IC施加测试的至少一个测试模块关联,指定与资源类型关联的参数类型及指定参数类型的参数。描述测试系统配置可以包括指定用于控制至少一个测试模块的站点控制器,其中每个测试模块对IC施加测试,及指定模块连接使能器的输入端口。测试系统在指定的输入端口将站点控制器耦合到模块连接使能器,而模块连接使能器将站点控制器耦合到测试模块。模块连接使能器可以实现为开关阵列。描述模块配置可以包括指定用于指定模块类型的模块标识符,指定用于控制由模块标识符所指定模块类型的测试模块的可执行代码及指定与测试模块关联的资源类型。可执行代码可以采取动态链接库的形式。描述模块配置还可以涉及用户指定用于指定模块连接使能器输出端口的槽标识符,其中测试系统在输出端口将测试模块耦合到模块连接使能器,而模块连接使能器将测试模块耦合到对应的站点控制器。用户还可以指定用于识别测试模块提供商的厂家标识符及结合资源类型可用的最大数量资源单元的标识符。资源类型可以是例如数字测试器引脚和资源单元测试器通道。可选地,测试器通道资源单元还可以对应于资源类型,例如模拟测试器引脚、RF测试器引脚、电源引脚、数字转换器引脚和任意波形生成引脚。还可以提供关于禁用哪个资源单元的指示符。指示为禁用的资源单元可以表示测试模块不完善的资源单元。描述测试条件可以包括指定至少一个测试条件组、指定包括至少一个变量的规范集合;及指定用于选择要绑定到变量的表达式的选择器。测试条件组与用于规范集合的选择器定义了测试条件。描述测试序列可以包括指定其中各种测试可以施加的次序(或流)。描述测试模式可以包括指定测试模式、相关联的电压与电流电平、对应于上升与下降时间和相关联定时的信号值的过渡。本发明的一个实施方式还包括Preheader文件的使用。Preheader文件被编译,以创建用于与测试实体关联的类的头文件。Preheader文件包括用于指定用于设置测试实体的至少一个属性的参数的参数块及用于指定由编译器插入到测试实体类的头文件中的源代码的模板块。所述头文件可以是C++头文件。测试实体可以是测试,而测试实体可以是例如测试类。参数可以涉及例如模式列表和测试条件。在一种实施方式中,用于管理模块测试系统中模式目标文件的方法包括提供模块测试系统,其中该模块测试系统包括用于控制至少一个站点控制器的系统控制器,而且至少一个站点控制器控制至少一个测试模块及其进行测试的对应设备(DUT)。该方法还包括创建用于在创建提供的模式编译器与模块测试系统之间建立标准接口的目标文件管理框架、在站点控制器接收模式源文件、基于模式源文件利用目标文件管理框架创建模式目标元文件及通过测试模块利用模式目标元文件测试被测试设备。当联系附图参考本发明实施方式的具体描述时,以上提到的本发明特征与优点及其另外的特征与优点将在下文中更清楚地理解。图1说明了传统的测试器体系。图2说明了根据本发明实施方式的测试器体系。图3说明了根据本发明实施方式的测试器软件体系。图4说明了根据本发明实施方式的测试程序编译器。图5说明了根据本发明实施方式有多少不同的测试实例可以从单个测试类导出。图6说明了根据本发明实施方式的模式编译器。图7说明了根据本发明实施方式排序的模式树例子。图8说明了根据本发明实施方式的另一排序的模式树例子。图9说明了根据本发明实施方式测试程序所需的文件之间的关系。图10说明了根据本发明实施方式的波形生成。图11说明了根据本发明实施方式用于定时的映射。图12说明了根据本发明实施方式用于定时的另一映射。图13说明了根据本发明实施方式用于管理模块测试系统中模式目标文件的OFM框架。图14说明了模式目标元文件与其支持类之间的相互作用。具体实施例方式提供了用于管理模块测试系统中模式目标文件的方法与系统。以下描述的提出是为了使本领域任何技术人员能够制造并使用本发明。特定实施方式与应用的描述仅仅是作为例子提供的。在此所描述的例子的各种修改与组合对本领域技术人员是显而易见的,而且在不背离本发明主旨与范围的情况下在此所定义的通用原理适用于其它例子与应用。因此,本发明不是要限定到所描述和示出的例子,而是要符合与在此所公开的原理与特征一致的最广泛范围。本发明总的来说是根据如本受让人的美国申请No.60/449,622、10/404,002和10/403,817中所描述的开放体系来描述的。但是,本领域技术人员将认识到本发明不仅适用于开放测试器体系,而且也适用于固定测试器体系。开放体系测试系统的描述可以在要求本受让人的美国申请No.60/449,622的权益的美国申请No.10/772,372“MethodandApparatusforTestingIntegratedCircuits”中找到。图1说明了显示信号如何生成并施加到被测试设备(DUT)的传统测试器的通用结构。每个DUT输入引脚都连接到施加测试数据的驱动器2,而每个DUT输出引脚都连接到比较器4。在大多数情况下,使用三态驱动器比较器,使得每个测试器引脚(通道)都可以既充当输入引脚,又充当输出引脚。专用于单个DUT的测试器引脚共同形成与相关定时发生器6、波形发生器8、模式存储器10、定时数据存储器12、波形存储器数据14及定义数据率的块16一起工作的测试站点。图2说明了根据本发明实施方式的系统体系100。系统控制器(SysC)102耦合到多个站点控制器(SiteC)104。系统控制器还可以耦合到网络,以便访问文件。通过模块连接使能器106,每个站点控制器都耦合成控制位于测试站点110的一个或多个测试模块108。模块连接使能器106允许所连接硬件模块108的重新配置,还充当数据传输的总线(用于加载模式数据、收集响应数据、提供控制,等等)。可能的硬件实现包括专用连接、开关连接、总线连接、环形连接及星形连接。模块连接使能器106可以由例如开关阵列实现。每个测试站点110都与一个DUT112关联,DUT112通过加载板114连接到对应站点的模块。在一种实施方式中,单个站点控制器可以连接到多个DUT站点。系统控制器102充当全局系统管理器。它协调站点控制器的动作、管理系统级的并行测试策略并附加地提供操纵器/探测器控制及系统级数据登录与错误处理支持。依赖于操作设置,系统控制器102可以部署到独立于站点控制器104运行的CPU上。可选地,系统控制器102和站点控制器104可共享一个CPU。类似地,每个站点控制器104可以部署到其自己的专用CPU(中央处理单元),或者作为相同CPU中的独立处理器或线程。通过理解单独的系统组件也可以看作集成、单块集成电路系统的逻辑组件而不一定是分布式系统的物理组件,上述系统体系可以从概念上设想为图2所示的分布式系统。·在另一实施方式中,系统控制器与站点控制器可以利用一个或多个计算设备实现。每个计算设备可以包括·包括用于处理各种基本系统服务并用于执行依赖于硬件的任务的过程的操作系统;·用于在操作系统和例如用于管理模式目标文件的应用程序的测试系统的其它应用程序之间交互的应用层;·用于执行来自操作系统和应用程序的指令的处理器单元;及·用于存储测试系统数据的存储器单元,该存储器单元可以包括随机存取存储器、非易失存储器或大容量存储设备。应用程序可以包括可执行过程、子模块、表格及其它数据结构。在其它实施方式中,附加的或不同的模块及数据结构也可以使用,而且以上列出的一些模块和/或数据结构可以不使用。应用程序可以在软件和/或硬件中实现。当在硬件中实现时,他们可以在专用集成电路(ASIC)或现场可编程门阵列(FPGA)中实现。图3说明了根据本发明实施方式的软件体系200。软件体系200代表了分布式操作系统,具有对应于相关硬件系统元素102、104、108的系统控制器220、至少一个站点控制器240和至少一个模块260元素。除了模块260,体系200还包括用于软件模块仿真280的对应元件。作为示例选择,用于这种平台的开发环境可以基于微软的Windows。这种体系的使用在还有程序与支持的便携性方面的好处(例如,站点服务引擎可以连接运行测试器操作系统的膝上型电脑,以便执行事先的诊断)。但是,对于大的计算密集操作(例如测试模式编译),可以使相关软件作为能够独立运行以便允许在整个分布式平台上进行任务调度的独立实体。因此,用于批任务的相关软件工具能够运行在多个平台类型上。作为示例选择,ANSI/ISO标准C++可以作为软件的本机语言使用。当然,有多种允许带其自己的可选语言的第三方集成到系统中的选择(提供标准C++接口上的层)。图3说明了通过标准的源,根据各个元件的组织对其进行阴影表示(或者作为子系统集中开发),包括测试操作系统、用户组件292(例如,由用户为测试目的提供的)、系统组件294(例如,为基本连接性和通信作为软件基础结构提供的)、模块开发组件296(例如,由模块开发器提供的)及外部组件298(例如,由除模块开发器之外的外部源提供的)。从基于源的组织的观点看,测试操作系统(TOS)接口290包括用于站点控制器接口的系统控制器222、框架类224、用于模块接口的站点控制器245、框架类246、预定义的模块级接口、底板通信库249、底盘槽IF(接口)262、加载板硬件IF264、底板模拟IF293、加载板模拟IF285、DUT模拟IF287、用于DUT的Verilog模型的VerilogPLI(编程语言接口)288及用于DUT的C/C++模型的C/C++语言支持289。用户组件292包括用户测试计划242、用户测试类243、硬件加载板265及DUT266、DUTVerilog模型293和DUTC/C++模型291。系统组件294包括系统工具226、通信库230、测试类244、加载板驱动器250、HW底板261、模拟框架281、底板仿真282及加载板模拟286。模块开发组件296包括模块命令实现248、模块硬件263及模块仿真284。外部组件298包括外部工具225。系统控制器220包括用于站点控制器的接口222、框架类224、系统工具226、外部工具225及通信库230。系统控制器软件是用户的主要交互点。它提供到本发明的站点控制器的网关及多站点/DUT环境中站点控制器的同步,如在本受让人的美国申请No.60/449,622中所描述的。基于图形用户接口(GUI)或其它的用户应用与工具运行在系统控制器上。系统控制器还可充当用于所有测试计划相关信息的仓库,包括测试计划、测试模式和测试参数文件。存储这些文件的存储器可以对系统控制器是本地的或者离线的,例如通过网络连接到系统控制器。测试参数文件包含在本发明实施方式中面向对象的环境中用于测试类的参数化数据。除标准系统工具226之外(或者代替之),第三方开发人员也可提供工具。系统控制器220上的标准接口222包括工具用来访问测试器和测试对象的接口。工具(应用)225/226允许测试和测试器对象的交互性与批控制。工具包括用于(通过例如SECS/TSEM等的使用)提供自动化能力的应用。驻留在系统控制器220上的通信库230提供以对用户应用和测试程序透明的方式与站点控制器240通信的机制。驻留在与系统控制器220关联的存储器中的接口222提供与在系统控制器上执行的框架对象的开放式接口。包括允许基于站点控制器的模块软件访问并检索模式数据的接口。还包括应用与工具用于访问测试器和测试对象的接口及提供通过脚本引擎访问并控制测试器与测试组件的能力的脚本接口。这使得用于交互的机制、批与远程应用能够执行它们的功能。与系统控制器220关联的框架类224提供与上面提到的这些对象交互的机制,提供标准接口的引用实现。例如,本发明的站点控制器240提供功能性测试对象。系统控制器框架类可提供对应的功能性测试代理作为功能性测试对象基于远程系统控制器的代理。因此,使系统控制器220上的工具可具有标准功能性测试接口。框架类有效地提供与主系统控制器关联的操作系统。它们还构成提供到站点控制器的网关并在多站点/DUT环境中提供站点控制器同步的软件元素。因此,这一层在本发明的实施方式中提供了适于控制和访问站点控制器而不需要直接处理通信层的对象模型。站点控制器240是用户测试计划242、用户测试类243、标准测试类244、标准接口245、站点控制器框架类246、模块高级命令接口(即,预定义的模块级接口247)、模块命令实现248、底板通信库249和底板驱动器250的主机。优选地,大部分测试功能是由站点控制器104/204处理的,从而允许测试站点110的独立运行。测试计划242是用户写的。计划可以直接由采用面向对象结构的标准计算机语言,如C++,来写,或者在高级测试编程语言中描述,来产生C++代码,然后C++代码可以编译成可执行测试程序。对于测试程序开发,本发明的一种实施方式采用受让人的创造性测试程序语言(TPL)编译器。参考图4,测试程序编译器400部分地充当代码生成器,包括将描述测试与相关参数的测试程序开发人员的源文件404翻译成例如C++代码的面向对象结构的翻译器部分402。编译器部分406又将代码编译并链接成可执行文件,例如DLL,以便创建可以由测试器系统执行的测试程序。尽管将TPL代码生成器/翻译器的应用于测试系统是新颖的,但请注意,代码生成器是本领域已知的。而且,编译器部分可以是本领域已知的标准C++编译器。测试计划通过使用框架类246和/或标准或与站点控制器关联的用户提供的测试类244创建测试对象、利用标准接口245配置硬件并定义测试计划流。它还提供测试计划执行过程中所需的任何附加逻辑。测试计划支持一些基本服务并提供与例如调试服务(例如,断点)的底层对象的服务的接口,及对底层框架与标准类的访问。输入到测试程序编译器400的源代码包括指定测试计划中所使用对象及其彼此关系的测试计划描述文件。这个文件被翻译成在站点控制器上执行的形式为标准接口实现的C++代码,这可以指示为ItestPlan。这个代码被打包成可以加载到站点控制器上的Windows动态链接库(DLL)。生成具有标准已知输入点的测试程序DLL,使得站点控制器软件可以使用该输入点生成并返回它所包含的TestPlan对象。站点控制器软件将测试程序DLL加载到其处理空间中并使用一个输入点来创建测试计划对象的实例。一旦测试计划对象已经创建,站点控制器软件就可以执行测试计划。与站点控制器关联的框架类246是实现公共的测试相关操作的一组类与方法。站点控制器级框架包括例如用于电源和引脚电子排序、设置电平与定时条件的类、获得测量值的类及控制测试流的类。框架还提供用于运行时间服务与调试的方法。框架对象可以通过实现标准接口工作。例如,TesterPin框架类的实现标准化成实现测试类可以与硬件模块引脚交互的通用测试器引脚接口。特定的框架对象可以实现成利用模块级接口247的帮助工作,与模块通信。站点控制器框架类实际上充当支持每个站点控制器的本地操作系统。大体上,多于90%的程序代码是用于设备测试的数据,而剩余的10%代码实现测试方法。设备测试数据是依赖于DUT的(例如,电源条件、信号电压条件、定时条件等)。测试代码包括将特定的设备条件加载到ATE硬件上的方法,还有那些实现特定于用户的目标(例如,数据登录)所需的方法。本发明一种实施方式的框架提供独立于硬件的允许用户执行DUT测试编程任务的测试与测试器对象模型。为了增加测试代码的可重用性,可以使这种代码独立于任何特定于设备的数据(例如,引脚名、模拟数据,等等)或特定于设备测试的数据(例如,用于DC单元的条件、测试引脚、目标引脚数、模式文件名、模式程序地址)。如果测试代码利用这些类型的数据编译,则测试代码的可重用性降低。因此,根据本发明的实施方式,可以使任何特定于设备的数据或者特定于设备测试的数据在外部对测试代码可用,作为代码执行时的输入。在本发明的实施方式中,在此表示为Itest的一个测试类(它是标准测试接口的实现)实现测试数据的与用于特定类型测试的代码(及因此代码的可重用性)的分离。这种测试类可以看作是用于其自己的独立实例的“模板”,彼此只根据特定于设备和/或特定于设备测试的数据不同。测试类在测试计划文件中指定。每个测试类一般实现特定类型的设备测试或用于设备测试的设置。例如,本发明的实施方式可以提供Itest接口的特定实现,例如FunctionalTest,作为所有DUT功能性测试的基础。它提供设置测试条件、执行模式和基于失败的选通脉冲的存在确定测试状态的基本功能性。其它类型的实现可以包括AC和DC测试类,在此表示为ACParametricTests和DCParametricTests。所有的测试类型都可以提供某些虚拟方法(例如,init()、preExec()和postExec())的缺省实现。这些方法变成测试工程师覆盖缺省特征并设置任何特定于测试的进入点。但是,定制的测试类也可以在测试计划中实现。测试类允许用户通过提供用于指定该测试特定实例的选项的参数来配置类特征。例如,FunctionalTest可以取参数Plist和TestConditionS,来分别指定要执行的模式列表和测试的电平与定时条件。指定这些参数的不同值(通过使用测试计划描述文件中不同的“测试”块)允许用户创建函数Test的不同实例。图5说明了不同的测试实例可以如何从单个测试类中导出。这些类可以直接以面向对象的结构,例如C++代码,编程,或者设计成允许测试程序编译器从测试计划文件取该测试及其参数的描述并生成对应的C++代码,C++代码可以编译并链接以便生成测试程序。可以采用模板库作为一般算法与数据结构的通用库。这个库可以对测试器用户是可见的,使得用户可以例如修改测试类的实现,以便创建用户定义的测试类。关于用户开发的测试类,系统的实施方式支持这种测试类集成到框架中,因为所有测试类都从例如ITest的单个测试接口导出,因此框架可以与标准系统测试类集合相同的方式控制它们。在理解它们必须在其测试程序中使用定制代码以便利用这些附加功能的情况下,用户可以自由地将附加功能结合到它们的测试类中。每个测试站点110都专用于测试一个或多个DUT106,并通过可配置的测试模块集合112起作用。每个测试模块112都是执行特定测试任务的实体。例如,测试模块112可以是DUT电源、引脚卡、模拟卡,等等。这种模块方法提供了高度的灵活性和可配置性。模块命令实现类248可以由模块硬件厂家提供,并依赖于厂家所选的命令实现方法,实现用于硬件模块的模块级接口或者提供标准接口的特定于模块的实现。这些类的外部接口是由预定义的模块级接口需求和底板通信库需求定义的。这一层还提供标准测试命令集合的扩展,以便允许方法(函数)与数据元素的添加。底板通信库249提供跨底板的标准通信的接口,从而提供与连接到测试站点的模块通信所必需的功能。这使得特定于厂家的模块软件可以使用底板驱动器250与对应的硬件模块通信。底板通信协议可以使用基于包的格式。测试引脚对象表示物理测试器通道,并从测试器引脚接口导出,在此表示为ITesterPin。本发明实施方式的软件开发包(SDK)提供也可以称为TesterPin的ItesterPin的缺省实现,这是根据预定义的模块级接口IChannel实现的。如果他们可以根据Ichannel实现他们的模块功能性,则厂家可以自由地使用TesterPin,否则,他们必须提供与他们的模块一起工作的ItesterPin的实现。在此表示为Imodule的由本发明测试器系统提供的标准模块接口一般地表示厂家的硬件模块。不同的厂家可以提供不同的模块。而且,一个厂家可以提供多个不同的模块。厂家支持的特定于模块的系统软件可以例如动态链接库(DLL)的可执行代码的形式提供。用于来自一个厂家的每种模块类型的软件可以封装到单个DLL中。每个这种软件模块都负责提供用于模块接口命令的特定于厂家的实现,这包括用于模块软件开发的API。有两方面的模块接口命令第一,它们充当用户与系统中特定硬件模块(间接)通信的接口,第二,它们提供第三方开发人员可以用于将他们自己的模块集成到站点控制器级框架中的接口。因此,由框架提供的模块接口模块分成两种类型[71]第一种且最显著的类型是通过框架接口暴露给用户的那些“命令”。因此,例如,测试器引脚接口(ITesterPin)提供获得和设置电平与定时值的方法,而电源接口(IPowerSupply)提供用于上电和下电的方法。此外,框架提供预定义模块级接口的特定类,这可以用于与模块通信。这些是由框架类(即,框架接口的“标准”实现)用于与厂家模块通信的接口。但是,第二方面的使用,模块级接口,是可选的。这样做的好处是厂家可以利用如ITesterPin和IPowerSupply等的类的实现,同时集中到通过实现模块级接口发送到其硬件的特定消息的内容。但是,如果这些接口对厂家不合适,则他们可以选择提供他们框架接口的定制实现(例如,ITesterPin、IpowerSupply等的厂家实现)。然后这些将提供对他们硬件合适的定制功能。以这种开放体系作为背景,以下进一步描述本发明的测试程序开发系统。以下的部分A描述用于描述其中测试程序将使用的测试环境的规则;部分B描述用于测试程序开发的方法与规则;部分C指定开发测试计划及如何定义测试程序主结构的方法与规则;部分D描述如何在开放体系的测试系统上运行测试程序;部分E描述用于测试模式的方法;部分F描述用于描述测试模式定时的规则;而部分G描述用于整体测试器操作的规则。A.组件[75]测试环境包括指定提供测试器并用于使之准备运行一组测试所必需条件的一组文件。测试环境优选地包括用于以下功能的文件1.测试器资源定义用于在开放体系测试系统中可用的测试器资源类型及这种资源支持的参数的说明。2.测试器配置用于站点控制器、站点及对应映射的说明。3.模块配置用于每个站点中硬件模块的说明。4.引脚描述用于DUT引脚的命名,例如信号引脚、电源,并描述引脚组,5.套接字用于DUT引脚到测试器引脚分配的说明。6.引脚选项用于引脚特定选项或模式的说明。7.模式列表用于测试模式及其序列的说明。8.模式用于测试向量的说明。以上所述1-3项是由ICF(安装与配置文件)利用来自CMD(配置管理数据库)的信息创建,并使得可以在众所周知的位置获得,而4-8项是特定于用户的。这部分提供了以上1-6项的描述;7-8项在部分E中更具体地描述。这些组件中的每一个优选地使用特定的方法与规则开发;这些方法与规则将在这部分中通过例子描述。A1.资源定义[77]每个硬件模块提供测试系统所使用的一种或多种类型的硬件资源(简单地说是资源)。测试器资源定义优选地用于声明一组用于可用资源类型的资源名及一组参数名和与每种特定资源类型关联的类型。例如,资源名dpin用于指数字测试器引脚。这些资源具有例如VIL(用于输入低电压)、VIH(用于输入高电压)、VOL(用于输出低电压)、VOH(用于输出高电压)等的参数。资源定义文件将具有“.rsc”的后缀。以下所示是例子资源定义,包含一些测试器资源##FileResources.rsc#Version0.1.2;ResourceDefs{#digitalpinsdpin{#LowandHighvoltagesforinputpinsVeltageVIL,VIH;#LowandHighvoltagesforoutputpinsVoltageVOL,VOH;}#powersuppliesdps{##PRE_WAITspecifiesthetimetowaitaftervoltage#reacheditsfinalvaluetostartpattern#generation.Theactualtimethatthesystem#willwaitisasmallsystemspecifiedrange:#PRE_WAIT-delta<=actual<=PRE_WAIT+delta##PRE_WAIT_MINisaminimumamounttowaitaftervoltage#reacheditsfinalvaluetostartpatterngeneration.#Itisasystemspecifiedrange:#PRE_WAIT_MIN<=actual<=PRE_WAIT_MIN+delta##POST_WAITspecifiesthetimetowaitafterpattern#generationendstoshutdownthepower.Theactual#timethatthesystemwillwaitisasmallsystem#definedrange:#POST_WAIT-delta<=actual<=POST_WAIT+delta##POST_WAIT_MINspecifiesthetimetowaitafterpattern#generationendstoshutdownthepower.Theactual#timethatthesystemwillwaitisasmallsystem#definedrange:#POST_WAIT_MIN<=actual<=POST_WAIT_MIN+delta#TimePRE_WAIT;TimePRE_WAIT_MIN;TimePOST_WAIT;TimePOST_WAIT_MIN;#Thevoltage.VoltageVCC;}}[78]应当指出,资源参数的类型(例如,电压或时间)优选地是标准工程单位。厂家提供的推荐不同参数说明的特定用途资源应当提供他们自己的资源定义文件。资源定义的结构[79]以下给出根据本发明优选实施方式的资源定义的结构resource-file:version-inforesource-defsversion-info:Versionversion-identifer;resource-defs:ResourceDefs{resource-def-list}resource-def-list:resource-defresource-def-listresource-defresource-def:resource-name{resource-params-decl-list}resource-params-decl-list:resource-params-declresource-params-decl-listresource-parans-declresource-params-decl:elementary-type-nameresource-param-name-list;resource-param-name-list:resource-param-nameresource-param-name-list,resource-param-name[80]以下指定以上未定义的非终结符号1.versionidentifier从的一个或多个字符的序列。它表示版本号。2.resource-name从[a-zA-Z0-9]的一个或多个字符的序列,不能以数字开头。它表示资源名,例如dpin或dps。3.elementary-type-name从[a-zA-Z0-9]的一个或多个字符的序列,不能以数字开头。它表示基本类型名,例如Voltage(cf.)。4.resource-param-name从[a-zA-Z0-9]的一个或多个字符的序列,不能以数字开头。它表示资源参数名,例如VIL。A2.测试器配置[81]测试器配置是一组优选地用于列出特定系统配置中站点控制器及站点控制器与开关阵列输入端口连接的规则。在本发明一个实施方式的体系中,单个站点控制器可以连接到单个开关阵列输入端口。因此,在这种环境下,开关阵列连接充当系统中站点控制器的隐含标识符(其它配置也是可能的)。以下是典型测试器配置的例子##TesterConfiguration,Sys.cfg#Version1.2.5;SysConfig{##ThefirstfieldisthehostnameoftheSiteControllermachine;#itcanbespecifiedaseitheradotted-decimalIPaddressora#domain-qualifiedhostname.##Thesecondfieldistheswitchmatrixinputportnumber,which#implicitlyservesastheidentifierfortheSiteController#connectedtoit.#zeus.olympus.deities.org2;127.0.0.24;127.0.0.0.1;#SITEC-1127.0.0.33;}[82]用于特定测试层系统的系统配置是系统简介的一部分,而且使得可以作为系统配置文件Sys.cfg访问。应当指出,在一种实施方式中,连接到端口1(在以上例子中是“127.0.0.0”)的站点控制器可以享受特定状态,其中它独自配置开关阵列。该“特定”站点控制器将称为SITEC-1。还应当指出,因为站点控制器可以通过内部网连接到系统控制器,所以在这个例子中指出的站点控制器是IP地址。相反,系统控制器可以连接到外部网,以访问文件,如模式数据。测试器配置的结构[83]以下给出根据本发明实施方式系统配置文件的结构system-config-file:version-infosystem-configversion-info:Versionversion-identifer;system-config:SysConfig{site-controller-connection-list}site-controller-connection-list:site-controller-connectionsite-controller-connection-listsite-controller-connectionsite-controller-connection:site-controller-hostnameinput-port;site-controller-hostname:ip-addressdomain-qualified-hostnameip-address:octet.octet.octet.octetdomain-qualified-hostname:namedomain-qualified-hostname.name[84]以下指定以上未定义的非终结符号1.versionidentifier从的一个或多个字符的序列。它表示版本号。2.octet从0到255的非负整数(十进制标记)。3.name从[a-zA-Z0-9]的一个或多个字符的序列,不能以数字开头。它表示有域名资格的主机名中的名字片断。4.input-port非负整数,十进制标记A3.模块配置[85]模块配置允许测试器物理配置的说明,例如系统底盘中每个模块的物理位置与类型。测试器总线配置的动态属性使之称为必需,其中测试器总线配置的动态属性允许测试器总线地址到物理槽位置的映射。这种信息允许在系统引导时发生的硬件发现处理,以便使系统配置有效。开关阵列的每个输出端口定义优选地由单个硬件模块占有的物理槽。以下所示是在根据本发明实施方式的文件Modules.cfg中指定的模块配置的例子##ModuleConfigurationFile,Modules.cfg#Version0.0.1;ModuleConfig{##Aconfigurationdefinitionwhichprovidesinformationabout#themoduletypethatisattachedtoslots1-12and32-48.#Notethatamodulemightprovidemorethan#asingletypeofresource.#Slot1-12,32-48#Switchmatrixoutputports#whichusetheconfiguration#definedbelow.{VendorID1;#definedvendorcode.ModuleID1;#Vendor-definedidcode.ModuleDrivermodl.dll;#Modulesoftware.##Resourcenameddpinspecifieschannels#fordigitaldata.Thenamedpinisnot#akeyword.Itissimplythenameofahardware#resource,andisobtainedfromtheresource#definitionfile.#Resourcedpin{MaxAvailable32;#Resourceunits1..32.}Resourceanalog{MaxAvailable16;#Resourceunits1..16.Disabled1-8;#Disabledresources1..8.#So,enabledonesare9..16.}}##Aconfigurationdefinitionwhichprovidesinformationabout#themoduletypethatisattachedtoslots16-30,50,and61-64.#Slot16-30,50,61-64{Resourcedpin{MaxAvailable32;#Maxavailableresourceunits.Disabled3,30-32;#Disabledresources.}ModuleDriver″moduletwo.dll″;VendorID2;ModuleID2;}##Aconfigurationdefinition,whichprovidesinformationabout#themoduletypethatisattachedtoslots65-66.#Slot65-66{ModuleID4;#DPSmodulewith8supplies.ModuleDrivermod4.dll;VendorID1;##Resourcetypedpsspecifyingresourceunitsfora#DevicePowerSupply#Resourcedps{MaxAvailable4;Disabled1;}}}[86]如前面所提到的,在一种实施方式中,槽指硬件模块可以通过其连接的连接器,如开关阵列的输出端口。每种配置定义提供关于可以连接到一个或多个槽的模块的信息。在配置定义中指定的VendorID是与厂家关联的唯一ID。ModuleID指由该厂家提供的模块的类型。在测试器配置中,可以有相同ModuleID的几个实例。ModuleDriver指为模块提供服务的厂家提供的DLL。最后,Resource指由这个模块提供服务的单元,并提供资源类型的名字;资源名是从资源定义文件获得的。以上例子描述了模块配置文件中的三个配置模块。在一种实现中,第一个配置块,槽1-12和32-48,是由厂家1生产的模块提供服务的。该厂家提供模块,标识符“1”指这个模块的类型,还提供控制模块的模块驱动器库。这个模块可以提供两种类型的资源单元,一种由资源名“dpin”指示,优选地是总共32个资源单元(即,“通道”),所有这些通道都是可用的,而另一种由资源名“analog”指示,总共16个资源单元,其中只有9至16是可用的。第二和第三个配置块以与第一个配置类似的方式指定。应当指出,允许通道标记为“disabled”使得可以识别仍然工作的模块上损坏的资源单元。还应当指出,配置块可以具有一个或多个槽标识符。当一个块具有多于一个槽标识符时,所标识的槽被称为是克隆的。模块配置文件,Modules.cfg,是作为系统简介的一部分由ICM(安装配置管理系统)(具有用户提供的特定于测试层的信息)创建的,而且使得在众所周知的位置可用。ICM可以是测试系统本地的实体,例如在系统控制器上,或者也可以驻留在系统控制器连接的网络上的某个其它位置。ICM管理CMD(配置管理数据库),并且一般随着系统配置的硬件变化而更新。ICM允许用户配置系统,例如站点控制器和模块。CMD是存储配置的数据库。对于实际的测试器配置/操作,ICM生成例如模块配置的配置文件和其它文件,并将它们和例如特定模块DLL的相关文件拷贝到测试器上。模块配置的结构[90]以下是根据以上优选实施方式的模块配置结构file-contents:version-infomodule-config-defversion-info:Versionversion-identifier;module-config-def:ModuleConfig{slot-entry-list}slot-entry-list:slot-entryslot-entry-listslot-entryslot-entry:Slotpositive-integer-list{slot-info}slot-info:required-config-listrequired-config-list:required-configrequired-config-listrequired-configrequired-config:VendorIDid-code;ModuleIDid-code;ModuleDriverfile-name;Resourceresource-name{max-specdisabled-specopt}max-spec:MaxAvailablepositive-integer;disabled-spec:Disabledpositive-integer-list;positive-integer-list:positive-integer-list-entrypositive-integer-list,positive-integer-list-entrypositive-integer-list-entry:positive-integerpositive-integer-number-rangepositive-integer-number-range:positive-integer-pos-integer[91]以下指定以上未定义的非终结符号1.version-identifier从的一个或多个字符的序列,其中第一个字符必须是从。2.positive-integer从的一个或多个字符的序列,不能以0开头。3.id-code从[a-zA-Z0-9]的一个或多个字符的序列。4.resource-name从[a-zA-Z0-9]的一个或多个字符的序列,其中第一个字符必须是从[a-zA-Z]。支持注释;注释以“#”字符开头,而且可以延伸到一行的结束。A4.引脚描述[93]DUT引脚描述利用引脚描述文件描述。用户使得DUT的描述在引脚描述文件中可用,该文件具有后缀.pin。这个纯文本文件至少包含以下内容DUT引脚名的列表;及命名引脚组的初始定义,该定义使用所定义DUT引脚名(说“初始”是因为它们以后可以编程性地修改或添加等)。数据说明与测试计划描述的分离允许DUT引脚定义一般的重用,并允许描述编译器从引脚描述文件导出(分解在向量说明中所使用的引脚名引用所需的)引脚名,而不需要将处理绑定到特定的测试计划。以下示出的是引脚描述文件的例子#Pindescriptionfile,myDUT.pin.##Notethatthisimplicitlyimportstheresource#configurationfile,Resources.rsc.#Version1.1.3a;PinDescription{Resourcedpin{A0;A1;A2;A3;A4;#Thissyntaxexpandstothenames″ABUS[1]″and“ABUS[2]”ABUS[1:2];A5;BBUS[1:8];DIR;CLK;GroupGrp1{DIR,CLK,A0,A1,A2,A3,A4,BBUS[1:4]}GroupGrp2{A5,##Thefollowinglinewillexpandto#″DIR,A1,A2,A4,A5,BBUS[2]″:#Grp1-CLK-A0-A3-BBUS[1]-BBUS[3:4]+A5,BBUS[5:8]}}Resourcedps{vcc1;vcc2;vcc3;GroupPSG{vcc1,vcc2}}}[96]应当指出,DUT引脚与引脚组定义封装在资源类型块中,以便允许编译器关联引脚和引脚组与电平所允许的参数设置等。应当指出以下关于引脚描述的点1.引脚组与引脚共享相同的命名空间并具有全局(即,测试计划)范围。这些名字的全局范围的一个结果是即使当在不同的资源块中声明时,引脚和引脚组也不能使用复制的名字。2.在引脚描述文件中需要至少一个资源定义。3.在每个资源中至少应当定义一个引脚名。4.在资源边界中引脚和组名需要唯一。5.相同的引脚或组名可以对两个或更多资源定义。但是,相同资源中的复制被忽略。6.出现在组定义中的所有引脚名与组名应当已经在该资源中定义。7.如果给出了,则组定义应当具有至少一个引脚名或组名(即,组定义不能为空)。8.引脚组定义可以包括对已经定义的引脚组的引用。9.引脚组定义可以包括例如已经定义的引脚和/或引脚组的加减的集合运算。引脚描述的结构[98]以下给出的是根据本发明优选实施方式的引脚描述的结构pin-description-file:version-infopin-descriptionversion-info:Versionversion-identifer;pin-description:PinDescription{resource-pins-def-list}resource-pins-def-list:resource-pins-defresource-pins-def-listresource-pins-defresource-pins-def:Resourceresource-name{pin-or-pin-group-def-list}pin-or-pin-group-def-list:pin-or-pin-group-defpin-or-pin-group-def-listpin-or-pin-group-defpindef-or-pin-groupdef:pin-def;pin-group-defpin-def:pin-namepin-name[index:index]pin-group-def:Grouppin-group-name{pin-group-def-item-list}pin-group-def-item-list:pin-defpin-group-def-item-list,pin-def[99]以下指定以上未定义的非终结符号1.version-identifier从的一个或多个字符的序列。它表示版本号。2.resource-name从[a-zA-Z0-9]的一个或多个字符的序列,不能以数字开头。它表示资源名,如dpin或dps。3.pin-name从[a-zA-Z0-9]的一个或多个字符的序列,不能以数字开头。它表示引脚A0的名字。4.pin-group-name从[a-zA-Z0-9]的一个或多个字符的序列,不能以数字开头。它表示引脚组ABUS的名字。5.index非负整数。它表示相关引脚组的下界或上界。A5.套接字[100]套接字指定DUT引脚名与物理测试器引脚(通道)指定(物理测试器通道号在模块配置文件中定义)之间的映射。应当指出,套接字可以用于支持不同的DUT包和不同的加载板配置等。对于多DUT系统,用于DUT/通道指定的套接字定义可以支持基本套接字到多个站点的“克隆”。但是,不同的套接字(即,用于相同逻辑引脚的不同物理映射)应当考虑站点模块分区。因此,除了提供DUT引脚到测试器通道指定,套接字还可以有效地定义站点分区。因此,套接字文件可以包含用于几个独立站点套接字的定义。以下所示是定义三个DUT站点的样本套接字文件Version1.1.3SocketDef{DUTTypeCHIP3{PinDescriptiondutP3.pin;#ThepindescriptionfileforCHIP3DUT2#Usesthefull-specificationsyntax{SiteController1;#SwitchMatrixinputportResourcedpin{##TheCLKpinisassignedtoresourcedpin,#slot2,resourceunit(channel)13.#CLK2.13;##TheDIRpinisassigncdtoresourcedpin.#slot5,resourceunit15.DIR5.15;##Thefollowingstatementwillbeexpandedto#BBUS[7]5.4#BBUS[6]5.5#BBUS[5]5.6##Soforexample,thepinsequenceBBUS[7],BBUS[6],#BBUS[5]isassignedtothesameslot5,andto#resourceunits4,5and6respectively.#BBUS[7:5]5.[4:6];BBUS[1:4]7.[21:18];BBUS[8]9.16;}Resourcedps{##TheV1pinisassignedtoresourcedps,#slot1,resourceunit(channel)1.#VCC11.1;##TheVCC2pinisassignedtoresourcedps,#slot1,resourceunit(channel)2.#VCC21.2;}}#EndDUT2DUT1#Thisis″cloned″fromDUT2above{SiteController1;#SameSiteControllerasforDUT2Resourcedpin{SlotOffset1;#Offsetvalueforslots}Resourcedps{SlotOffset10;#Offsetvalueforslots}##Theoffsetsyntaxaboveindicalesthattheslot/resDurce#unitassignmentsare″cloned″fromthefirstDUTdefined#forthisDUTType,i.e.,DUT2,withtheslotsofgfsetby#theSlotOffsetvalues.##Lookingatthedefinitionofdpinresourceunitsfor#DUT2,CLKisboundtoslot2.Hencc,forthepresent#DUT,CLKisboundtoslot2+1=3.##Someofthenewbindingsineffectduetotheoffset#assignmentsareshowninthetablebelow:##---------------------------------------------------#PinResourceRUnitSlot#---------------------------------------------------#CLKdpin132+1=3#DIRdpin155+1=6#BBUS[8]dpin169+1=10#VCC1dps11+10=11#VCC2dps21+10=11#}#EndDUT1}#EndDUTypeCHIP3DUTType74LS245{PinDescriptiondutLS.pin;DUT3disabled#ThisDUTsiteisdisabled,andwillbeignored{…}}#EndDUTType74LS245}#EndSocketDef[101]以下关于套接字的点应当注意1.套接字文件使用来自模块配置文件和用于给定DUT类型的用户引脚描述文件(见上例中PinDescription的说明)。使模块配置信息对套接字文件编译器隐含可用。套接字文件编译器是模式编译器的子部分,它读取并分析套接字DUT名到测试器通道映射,读取并分析模块配置与引脚描述文件来设置模式编译器所使用的测试器引脚到DUT引脚的映射。2.每种DUT类型至少需要一个DUT站点定义,而且与SlotOffset语法相反,它必须使用完全说明语法。如果对同一DUT类型提供多于一个DUT站点定义,则第一个必须使用完全说明语法。3.每个后续的DUT站点定义(对于同一DUT类型)可用使用完全说明语法或者SlotOffset语法,但不能两者都使用。这使得单个站点可能(由于,例如,不起作用的通道)偏离标准模式。4.偏离SlotOffset语法的绑定是关于为该DUT类型定义的第一个站点(该站点使用完全说明语法)定义的。5.DUT站点不需要以实际的物理次序声明。这允许第一(物理)站点偏离模式的情况。6.DUT站点ID需要在整个套接字(即,所有在其中定义的DUT类型)上是唯一的。7.对每个DUT站点定义需要至少一个资源定义。8.站点定义必须与模块配置一起使用,以确定测试配置是单站点/单DUT还是单站点/多DUT。9.在所有情况下,套接字文件都应当指定一组与引脚模式文件和模块配置文件一致的DUT通道映射。10.在有些情况下,期望允许套接字定义指定一个或多个DUT通道从测试器断开(例如,通过指定所分配物理通道为具有特定ID“0.0”的通道)。在这种情况下,这些DUT通道可在测试环境下使用和参考。这种通道上的操作将导致系统警告(但不是错误)。在加载时,将丢弃断开通道的模式数据。套接字的结构[102]以下是根据本发明优选实施方式的模块配置的结构socket-file:version-infosocket-defversion-info:Versionversion-identifer;socket-def:SocketDef{device-specific-socket-def-list}device-specific-socket-def-list:device-specific-socket-defdevice-specific-socket-def-listdevice-specific-socket-defdevice-specific-socket-def:DUTTypeDUT-type-name{pin-description-filedut-info-list}pin-description-file:PinDescpin-description-file-name;dut-info-list:dut-infodut-info-listdut-infodut-info:DUTdut-id{site-controller-input-portresource-info-list}sile-controller-input-port:SiteControllerswitch-matrix-input-port-number;resource-info-list:resource-inforesource-info-listresource-inforesource-info:Resourceresource-name{resource-item-unit-assignment-list}resource-item-unit-assignment-list:resource-item-utnit-assignmentresource-item-unit-assignment-listresource-item-unit-assignmentresource-item-unit-assigmnent:resouree-item-nameslot-number.resource-unit;resource-item-name[resource-item-index]slot-number.resource-unit-index;resource-item-nane[resource-item-index-range]slot-number.[resource-unit-index-range];resource-item-index-range:resource-item-index:resource-item-indexresource-unit-index-range:resource-unit-index:resource-unit-index[103]以下指定以上未定义的非终结符号1.version-identifier选自集合的一个或多个字符的序列。它不是版本号2.DUT-type-name选自集合的一个或多个字符的序列,其中第一个字符不能是选自集合。它不是DUT的类型,如CHIP3。3.pin-description-file-name简单的文件名,不包括其目录名,但包括所有后缀。文件名具有由主机操作系统识别的语法,并且如果包含在引号中,则允许空格和其它字符。4.switch-matrix-input-port-number十进制标记的非负整数,表示连接到站点控制器的输入端口的端口号。5.dut-id十进制标记的非负整数,识别DUT的实例。6.resource-name选自集合的一个或多个字符的序列,其中第一个字符不能选自集合。它表示资源文件中所定义的资源的名字。7.resource-item-name选自集合的一个或多个字符的序列,其中第一个字符不能选自集合。它表示资源单元的名字,例如pin或pin组。8.resource-item-index十进制标记的非负整数,表示一组资源项的特定成员。当在resource-item-index-range的环境下时,它表示连续资源项组序列的下或上界。9.resource-unit-index十进制标记的非负整数,表示一组资源单元(通道)的特定成员。当在resource-unit-index-range的环境下时,它表示连续资源单元组序列的下或上界。A6.PinS[104]应当指出,除了物理通道映射的逻辑引脚名(如由套接字所提供的),几种属性可以用于指定测试器资源。例如,选项可以用于定义通道的特定硬件配置,这可以是特定于测试的、特定于厂家的和/或特定于测试系统的。这些将利用引脚模式选项进行描述,并使得可以通过引脚模式选项文件获得。引脚模式选项定义将支持测试通道的特定选项或模式的配置。例如,这可以用于选择并配置通道复用。由于它可能需要重要的通道配置,因此优选地引脚模式选项只用作测试集合初始化流的一部分。引脚选项语法支持厂家定义的选项。一个例子在下面示出PinModeOptions{clockINdouble;a0OUTsingle;…};测试环境配置[106]如前面所指出的资源定义文件(Resources.rsc)、系统配置文件(Sys.cfg)与模块配置文件(Modules.cfg)都优选地在“众所周知的”位置可以获得。这种“众所周知的”位置是由系统环境变量TesterACTIVECONFIGS的值指定的目录。例如,如果TesterACTIVECONFIGS的值是目录F:\TesterSYS\configs,则系统将期望以下文件存在·F:\TesterSYS\configs\Resources.rs·F:\TesterSYS\configs\Sys.cfg·F:\TesterSYS\configs\Modules.cfg[107]在安装过程中,驻留在主计算机上的安装与配置管理系统(ICM)将优选地设置TesterACTIVECONFIGS的值。每次当ICM创建以上文件之一的新版本时,它就将新版本放置到由TesterACTIVECONFIGS指向的位置。应当指出,除了以上三个文件,例如模拟配置文件的其它系统配置文件也放置在由TesterACTIVECONFIGS指向的位置。B.用于测试程序开发的规则[108]测试器系统的两个主要面向终端用户的组件中的一个是测试环境。另一组件是测试器使之对终端用户(即,测试工程师和测试类开发人员)可用的编程工具。编程环境的主要组件是测试计划。测试计划使用测试类(这是由Test标记的测试接口的不同实现),该类实现用于特定类型测试的测试数据与代码的分离。计划可以直接写为C++测试程序,或者在测试计划描述文件中描述,该文件可以由测试程序生成器(翻译器402)处理,以便产生例如C++代码的面向对象代码。然后,所生成的C++代码可以编译成可执行测试程序。构成测试类实例所需的数据,例如电平、定时等,由用户在测试计划描述文件中指定。测试程序包括一组指定在设备上运行测试的细节的用户书写文件。本发明的实施方式包括允许用户利用C++结构写这些文件的规则集合。根据本发明实施方式的一个需求是遵循开发体系结构测试系统的模块化。模块化开发允许用户写处理测试不同方面的独立组件,然后允许这些组件以多种方式混合与匹配,以输出完整的测试程序。根据本发明优选实施方式的测试程序包括如下一组文件·用于用户变量和常量的文件*.usrv;·用于说明组的文件*.spec;·用于电平的文件*.lvl;·用于定时的文件*.tim;·用于测试条件组的文件*.tcg;·用于bin定义的文件*.bdefs;·用于定制功能和测试类的文件,用于pre-header的文件*.ph;·用于定制类型的文件*.ctyp;·用于定制变量的文件*.cvar;及·用于测试计划的文件*.tpl。以上的文件后缀是传统推荐的方便的文件分类。单个测试程序将优选地包括单个测试计划文件及其导入的文件。“导入”指具有或者直接由导入者引用的数据(指定导入的文件)或者由导入者直接引用的某个其它文件导入的数据的其它文件。测试计划文件可以在其中定义全局符、流及其它这种对象,或者它可以从其它文件导入这种信息。这些规则允许任何以上组件或者在其自己的独立文件中,或者直接内联到测试计划文件。应当指出,测试计划在概念上与C语言的main()函数类似。测试计划特征·用户变量与常量,·说明组,·电平,·定时,·测试条件,·bin定义,·pre-header,·定制类型,·定制变量,·测试计划,·[114]测试程序标识符优选地以大写或小写字母字符开始,后面可以是任何数量的字母、数字或下划线(_)字符。它具有在以下给出的描述中提供的几个关键词。这些关键字在该文档中利用如Version的粗体可视识别。关键字是保留的,而且优选地不用作标识符。有几个以下描述的特定符合,例如{,}、(,),及其它。测试对象的确立[115]测试描述文件的导入使导入文件能够引用由被导入文件使其可用的对象的名字。这允许导入文件引用被导入文件命名的对象。考虑导入引脚描述文件xxx.pin的套接字文件aaa.soc。可以有也导入xxx.pin的另一bbb.soc文件。但是,这些文件中任何一个都不会使由xxx.pin所描述的对象形成。它们仅仅是引用已经假设存在的对象。问题就提出来了这些对象什么时候形成?这就是测试计划文件根本不同的地方。与C类似,它是其中具有main()例程的文件。测试计划文件中的“Import”语句将形成这些对象,即,使这些对象形成。以下所示的测试计划mickey.tpl使得xxx.pin和aaa.soc中的对象形成#FileforMickey’sTestPlanVersion3.4.5;##Theseimportstatementswillactuallycausethe#objectstocomeintoexistence:#Importxxx.pin;#Elaboratespinandpin-groupobjectsImportaaa.soc;#Elaboratessitesocketmapobjects#Otherimportsasnecessary...FlowFlow1{...}[117]测试计划中xxx.pin的导入使得所有在xxx.pin中声明的引脚和引脚组对象形成。这如下描述“文件xxx.pin形成”。对于测试计划来说,直接导入需要形成的所有文件不是必需的。如果以下两个语句中的任何一个为真,则文件x由文件y导入1.y有命名x的导入语句;或2.x由z导入,而y有命名z的导入语句。当编译测试计划时,它将在文件中形成由测试计划导入的所有对象。由测试计划导入的文件集合按拓扑结构排序,以便产生文件形成的次序。由测试计划导入的文件集合称为测试计划的导入闭包。如果测试计划的导入闭包不能按拓扑结构排序,则必须有导入循环。这种状态是不正确的,而且将被编译器拒绝。用户变量与常量[119]全局变量与常量将利用用户变量与常量定义。常量是其值在编译时绑定而且不能改变的对象。例如,最大整数值将是常量。另一方面,绑定到变量的表达式可以通过API在运行时改变。·整数,·无符号整数,·双精度型,·字符串,·单位为伏特的电压(V),·单位为伏特每秒的电压回转(VPS),·单位为安培的电流(A),·单位为瓦特的功率(W),·单位为秒的时间(S),·单位为米的长度(M),·单位为赫兹的频率(Hz),·单位为欧姆的电阻(欧姆),及·单位为法拉的电容(F)。类型整数、无符号整数、浮点数与字符串称为基本类型。基本类型没有测试单位。不是基本类型的基础类型是双精度型,它具有相关联的测试单位与比例。比例符号是通用的工程比例符号·p(pico)是10-12,例如以pF(皮法)为单位·n(nano)是10-9,例如以nS(纳秒)为单位·u(micro)是10-6,例如以uS(微秒)为单位·m(milli)是10-3,例如以mV(毫伏)为单位·k(kilo)是10+3,例如以kOhm(千欧)为单位·M(mega)是10+6,例如以MHz(兆赫)为单位·G(giga)是10+9,例如以GHz(千兆赫)为单位[121]具有用户变量与常量的独立文件具有后缀.usrv。以下是具有一些全局常量的文件的例子。具有一些变量的文件的例子稍后给出。#-------------------------------------------------#Filelimits.usrv#-------------------------------------------------Version1.0.0;##ThisUserVarscollectiondeclarationdeclaresasetof#globallyavailablevariablesandconstants.#UserVars{#SomeconstantIntegerglobalsusedinvariousplaces.ConstIntegerMaxInteger=2147483647;ConstIntegerMinInteger=-2147483648;#Smallestvaluesuchthat1.0+Epsilon!=1.0ConstDoubleEpsilon=2.2204460492503131e-016;#SomeimportantconstantsrelatedtoDoubleConstDoubleMaxDouble=1.7976931348623158e+308;ConstDoubleMinDouble=-MaxDouble;ConstDoubleZeroPlus=2.2250738585072014e-308;ConstDoubleZeroMinus=-ZeroPlus;}[122]以上声明的UserVars的集合被看作是‘=’左边变量的定义。因此,最好是变量或常量的定义仅出现一次,而且应当初始化。如前面所提到的,常量一旦定义就不应当改变。绑定到常量的表达式可以涉及前面定义的常量和文字值。另一方面,变量可以通过API改变。绑定到变量的表达式可以涉及前面定义的变量、常量和文字值。每个变量都绑定到在运行时维护的表达式对象。这提供了在运行时改变与变量关联的表达式然后重新求所有变量的值的能力。表达式对象是变量或常量定义右侧的解析形式。在一种实施方式中,没有提供在运行时改变常量的工具。它们的值优选地是在编译时固定的。具有全局符的任何数量的这种文件可以存在于测试计划的导入闭包中。以上全局文件是一组数字限制,而这里是一组利用工程测量单位的工程全局符及一些随机用户变量#---------------------------------------------------#Filemyvars.usrv#---------------------------------------------------------Version0.1;##ThisdeclaresaUserVarscollectionofsomeengineering#globals.#UserVarsMyVars{#Engineeringquantities.ConstVoltageVInLow=0.0;#0VoltsConstVoltagcVInHigh=5.0;#5VoltsConstVoltageVOutLow=400.0mV;#400milliVoltsConstVoltageVOutHigh=5.1;#5.1VoltsConstTimeDeltaT=2.0E-9;#2nanosecondsConstTimeClkTick=1.0ns;#1nanosecondConstResistanceR10=10.0kOhms;#10kiloOhms#Somevariablesaredeclaredbelow.CurrentILow=1.0mA;#1milliAmpCurrentIHigh=2.0mA;#2milliAmpPowerPLow=ILow*VInLow;#LowpowervaluePowerPHigh=IHigh*VInHigh;#Highpowervalue##AnarrayoflowvaluesforallAbuspins.#ThevilforA0willbeinABusVil,forA1#inABusVil[1],andsoon.#VoltageABusVil[8]={1.0,1.2,Others=1.5};}[126]编译器优选地检查单位与类型匹配。应当指出,由于电压乘以电流得出功率,因此以上用于PLow和PHigh的等式将编译。但是,如以下的语句一般不编译##DoesnotcompilebecauseaCurrentandaVoltagecannotbeaddedtoyielda#power#PowerPxxx=IHigh+VInHigh[127]编译器将允许特定的自动类型转换PowerPxxx=2;#Setthepowerto2.0wattsIntegerY=3.6;#Ygetassigned3PowerPyyy=y;#Pyyygetassigned3.0wattsDoubleZ=Pyyy;#PyyygetsconvertedtounitlessDouble[128]到双精度型、无符号整数和整数的显式类型转换也是允许的PowerPxxx=3.5;#Explicittypeconversionisallowed,butnotrequired.#Xbecomes3.5DoubleX=Double(Pxxx);#Xbecomes3.5IntegerY=Integer(Pxxx);[129]通过转换成中间基本类型,不相关类型之间的转换也是可能的PowerPxxx=3.5;#Explicittypeconversionisrequired.LengthL=Double(Pxxx);#Lbecomes3.5metersVoltageV=Integer(Pxxx);#Vbecomes3.0Volts[130]TestPlan对象提供了UserVars类,该类是包含名字及其关联的表达式、值与类型的集合。用户变量可以进入缺省用户变量集合,或者进入命名用户变量集合。以上例子中没有指定名字的UserVars声明进入缺省集合。但是,有可能显式地如下命名集合#DeclareXandYintheMyVarsUserVarscollection.UserVarsMyVars{IntegerX=2.0;##ReferstotheaboveX,andtotheglobally#availableMaxIntegerfromthedefault#UserVarscollection.#IntegerY=MaxImeger-X;}#DeciareX,Y1andY2intheYourVarsUserVarscollection.UserVarsYourVars{IntegerX=3.0;#ReferstotheXfromMyVars.IntegerY1=MaxInteger-MyVars.X;#ReferstotheXdeclaredabove.IntegerY2=MaxInteger-X;}#MorevariablesbeingaddedtotheMyVarscollectionUserVarsMyVars{##ReferstoXandYfromtheearlierdeclaration#ofMyVars.#IntegerZ=X+Y;}[131]UserVars集合中的名字分解如下进行如果名字是合格的一即,名字包括被点分开的两段一则变量来自由点前面的段命名的命名用户变量集合。因此,上面的MyVars.X指MyVars集合中的X。名字“UserVars”可以用于显式地表示缺省用户变量集合。如果名字不合格,且当前集合中有同一名字的常量或变量,则名字分解成常量或变量。否则,名字分解成缺省用户变量集合中的常量或变量。UserVars集合中定义块的估计可以看作在顺序发生的,从第一个定义到最后一个定义。这可能需要每个变量在其使用之前定义。此外,对于一个UserVars集合,可以有几个定义块,每个定义块定义几个变量。所有这些定义块都可以看作是按照测试计划中的声明次序进行估计,然后,每个块的变量也以声明次序检查。最后,可以有几个UserVars集合,每个集合定义几个定义块上的变量。所有变量同样可以看作是以声明次序初始化。因此,在上例中,估计次序将是MyVars.X、MyVars.Y、YourVars.X、YourVars.Y1、YourVars.Y2、MyVars.Z。当UserVars集合使用来自另一集合的变量时,它优选地使用该变量的原始值。在集合之间不维护从属信息。因此,基于从属关系的重新估计可以限定到单个集合。每个用户变量集合都指C++UserVars类的一个实例。C++UserVars类的缺省对象命名为“UserVars”。UserVars声明中未命名的变量是来自缺省用户变量集合,并添加到这个缺省对象。命名用户变量集合中的变量添加到具有该名字的C++UserVars类对象中。在上例中,“MyVars”C++对象将以变量X、Y和Z结束。用于用户变量的C++[139]用户变量实现为n元组的集合,每个n元组具有name串、const/var布尔值、作为枚举值的type和作为表达式树的expression。名字的表达式可以由以下调用设置enumElemenaryType{UnsignedIntegerT,IntegerT,DoubleT,VoltageT,...};StatussetExpression(constString&name,constboolisConst,constelemenaryType,constExpression&expression);[140]类型表达式是对应于赋值右侧的文本的解析形式的类型。有UserVars全局可用的实例。例如,limits.usrv(cf.page)中用户变量的集合由以下所示的调用集合实现_UserVars.setExpression(“MaxInteget”,true,IntegerT,Expression(2147483647));_UserVars.setExpression(“MinInteger”,true,IntegerT,Expression(-2147483648));_UserVars.setExpression(“Epsilon”,true,DoubleT,Expression(2.2204460492503131e-016));_UserVars.setExpression(“MaxDouble”,true,DoubleT,Expression(1.7976931348623158e+308));_UserVars.setExpression(“MinDoubte”,true,DoubleT,Expression(“-MaxDouble”));_UserVars.setExpression(“ZeroPlus”,true,DoubleT,Expression(2.2250738585072014e-308));_UserVars.setExpression(“ZeroMinus”,true,DoubleT,Expression(“-ZeroPlus”));[141]以下是对myvars.usrv中声明的变量所执行的C++语句myVars.setExpression(“VInLow”,true,VoltageT,Expression(0.0));myVars.setExpression(“VInHigh”,true,VoltageT,Expression(5.0));myVars.setExpression(“DeltaT”,true,TimeT,Expression(2.0E-9));myVars.setExpression(“ClkTick”,true,TimeT,Expression(1.0E-9));myVars.setExpression(“R10”,true,ResistanceT,Expression(10.0E+3));myVars.setExpression(“ILow”,false,CurrentT,Expression(1.0E-3));myVars.setExpression(“IHigh”,false,CurrentT,Expression(2.0E-3));myVars.setExpression(“PLow”,false,PowerT,Expression(“ILow*VInLow”));myVars.setExpression(“PHigh”,false,PowerT,Expression(“IHigh*VInHigh”));myVars.setExpression(“ABusVil”,false,VoltageT,Expression(1.0));myVars.setExpression(“ABusVil[1]”,false,VoltageT,Expression(1.2));myVars.setExpression(“ABusVil[2]”,false,VoltageT,Expression(1.5));myVars.setExpression(“ABusVil[3]”,false,VoltageT,Expresmon(1.5));myVars.setExpressision(“ABusVil[4]”,false,VoltageT,Expression(1.5));myVars.setExpression(“ABusVil[5]”,false,VoltageT,Expression(1.5));myVars.setExpression(“ABusVil[6]”,false,VoltageT,Expression(1.5));myVars.setExpression(“ABusVil[7]”,false,VoltageT,Expression(1.5));在以上代码中,Expression类优选地具有表示表达式解析形式的构造函数。Expression有几个构造函数,包括一个取字符串字面量并解析的,还有一个取字符串字面量并只是作为字符串字面量使用的。这是通过为了可读性在以上未指定的附加参数区分的。缺省用户变量集合中的用户变量将由类UserVars的UserVars对象管理。命名用户变量集合Xxx中的用户变量将由名字为Xxx的UserVars对象管理。用于UserVars的运行时API[144]包含这些名字与表达式的C++UserVars类导出在运行时估计并修改这些值的应用编程接口(API)。与UserVars关联的表达式的修改也解决什么时候UserVars将重新估计和估计有什么影响的问题。首先考虑作为改变的结果,UserVars的重新估计什么时候应当被触发的问题。如果在对表达式进行改变后立即触发,则用户将不能够在触发重新估计之前进行一系列的相关改变。因此,重新触发是由用户的显式调用触发的。接下来考虑重新估计的影响。根据优选上述发送,有三种类型可用的重新估计[147]UserVars集合重新估计是限定到单个UserVars集合的重新估计。这种操作的语义是再次重新估计这个集合中的所有变量。UserVars目标重新估计是限定到对绑定到单个名字的表达式改变的重新估计。这将使用户能够改变单个名字的表达式,并使得集合的重新估计只考虑这个特定改变的发生。UserVars全局重新估计是所有UserVars集合的重新估计。这基本上以声明次序触发所有UserVars集合的重新估计,而且代价相当高。所有以上重新估计都将在重新估计UserVars之后重新估计例如Level、Timings等的从属对象。从属对象将具有表示它需要重新估计的dirty位。在任何时候UserVars集合编程性改变时,它都将设置所有从属对象的dirty位。这将触发从属对象的重新估计。总的来说,命名UserVars集合帮助包含重新估计影响问题。重新估计通常限定到单个集合。使用UserVars的一种简单方式将是仅使用缺省UserVars集合。以这种方式,进行改变的连锁反应可以对所有UserVars发生。这种连锁反应可以限定到几个命名的UserVars集合。多个集合可以引用彼此的变量,但绑定到变量的值是在使用时绑定的。在UserVars集合之间不维护从属关系。对于每种基本类型Xxx(无符号整数、电流、电压等),获得值的方法是StatusgetXxxValue(constString&name,Xxx&value)const;应当指出,没有直接设置值的方法,它是通过在reevaluateCollection()的调用之后设置表达式的调用完成的。获得和设置表达式的方法。setExpression()调用还可以用于定义到目前为止还没有定义的新变量。enumelementaryType{UnsignedIntegerT,IntegerT,DoubleT,VoltageT,...};StatusgetExpression(constString&name,Expression&expression)const;StatussetExpression(constString&name,constboolisConst,constelementaryType,constExpression&expression);[155]setExpression()定义可能在表达式导致循环从属关系的情况下失败。例如,如果进行以下两个调用,则第二个调用将以循环从属错误而失败setExpression(“X”,true,IntegerT,Expression(“Y+1”));setExpression(“Y”,true,IntegerT,Expression(“X+1”));这是因为绑定到名字的值是等式而不是赋值。当变量的值改变时,提供重新估计所有直接和间接从属名字的方法。例如以上成对调用的等式导致循环从属关系,这是不允许的。应当指出,这个API一般不支持自发的重新估计。对setExpression()的调用不会使变量及依赖它的所有其它变量重新估计。绑定到所有变量的值将保持不变,直到发生对(以下)reevaluateCollection()的调用。确定特定名字是否为常量的方法是StatusgetIsConst(constString&name,bool&isConst);[158]获得类型的方法是enumElementaryType{UnsignedIntegerT,IntegerT,DoubleT,VoltageT,...};StatusgetType(constString&name,ElementaryType&elementaryType)const;[159]UserVars集合重新估计方法是StatusreevaluateCollection();[160]该类将维护关于所有变量的等式及其从属关系。当这个方法被调用时,所有变量都将重新估计。UserVars目标重新估计方法是StatusreevaluateTargeted(constString&var);[162]该类将维护关于所有变量的等式及其从属关系。当这个方法被调用时,命名变量及所有依赖它的对象都将重新估计。·UserVars全局重新估计方法是staticStatusreevaluateAllCollections();[163]该类将维护关于所有变量的等式及其从属关系。当这个方法被调用时,以未指定的次序对所有UserVars集合调用reevaluateCollection()。确定是否定义了特定名字的方法StatusgetIsDefined(constString&name,bool&isDefined)const;[165]确定是否所有用户变量当前都定义了的方法StatusgetNames(StringList&names)const;删除目前定义的变量的方法StatusdeleteName(constString&name);[167]如果名字用在涉及其它变量的表达式中,则这个操作将失败。·获得依赖于给定变量或常量的变量和常量列表的方法StatusgetDependents(constString&name,StringList&dependents);说明集[168]说明集用于提供可以基于选择器取值的变量集合。例如,考虑以下使用选择器Minnie、Mickey、Goofy和Daisy的说明集。#---------------------------------------------------------#FileAaa.spec#---------------------------------------------------------Version1.0;InportLimits.usrv;SpecificationSetAaa(Minnie,Mickey,Goofy,Daisy){Doublexxx=1.0,2.0,3.0,4.0;Integeryyy=10,20,30,40;Integerzzz=MaxInteger-xxx,MaxInteger-xxx-1,MaxInteger-xxx-2,MaxInteger-xxx;#Thefollowingdeclarationassociatesasingle#value,whichwillbechosenregardlessofthe#selector.Itisequivalentto:#Integerwww=yyy+zzz,yyy+zzz,yyy+zzz,yyy+zzzIntegerwww=yyy+zzz;}[169]以上利用选择器Goofy的说明集将进行以下关联xxx=3.0;yyy=30;zzz=MaxInteger-xxx-2;www=yyy+zzz;[170]在说明集上设置选择器的操作将在以后描述测试时讨论。按照句法,说明集是选择器(上例中的Minnie、Mickey、Goofy和Daisy)的列表及变量定义列表(上例中的xxx、yyy、zzz和www)。变量的定义涉及或者与选择器列表一样长或者只包括单个表达式的表达式列表。从概念上讲,说明集可以看作是表达式阵列,其列是选择器,行是变量,项是表达式。特定的选择器(列)将每个变量(行)绑定到特定的表达式(项)。如果列表具有单个表达式,则表示具有该表达式的行复制与选择器个数一样多的次数。说明集可以出现在两者独立的环境中。它们可以独立地在.spec文件中说明,在这种情况下它们如上所示出现。这是命名说明集。否则,本地说明集可以在测试条件组中声明。在这种声明中,说明集将没有名字。它将是本地说明集,只对所包含的测试条件组起作用。命名说明集可以在模仿命名用户变量集合。以上说明集可以建模为命名为Aaa的UserVars集合,该集合将具有用于xxx[Mickey]、xxx[Goofy]、xxx[Daisy]、yyy[Minnie]等的表达式。当在测试环境中选择特定的选择器(例如Mickey)时,xxx、yyy和zzz的值从变量名及说明集名获得。测试条件组可以有最多一个说明集,或者是本地说明集,或者是对命名说明集的引用。本地说明集只出现在测试条件组的环境下,而且没有显式指定的名字。这种说明集具有由所包含的测试条件组的名字定义的隐含名字。为了在几个说明集和几个UserVars集合可见的时候在测试条件组中分解名字,应用以下规则1.如果名字是合格的,则它必须在命名用户变量集合中分解。2.如果名字不合格,则如果它在测试条件组中声明,则名字在本地说明集中分解,而如果是在测试条件组中引用,则名字在命名说明集中分解。3.如果名字没有被以上规则分解,则在缺省用户变量集合中分解。为了说明这些规则,考虑以下利用(后述)测试条件组的例子。Version1.2.3;Importlimits.usrv;#PicksupthelimitsUsetVarsfileabove.Importaaa.spec;#PicksuptheSpecificationSetAAAabove.TestConditionGroupTCG1{SpecificationSet(Min,Max,Typ){vcc=4.9,5.1,5.0;}#Rule1:Resolutioninanameduservariablescollection.#AreferencetoMyVars.VInLowreferstoVInLowfromMyVars.#Rule2:Resolutioninalocalspecificationset.#Areferenceto“vcc”herewillresolveinthecontext#ofthelocalspecificationsetabove.#Rule3:Resolutionindefaultuservariablescollection.#Areferenceto“MaxInteger”herewillresolvetolimits.usrv.#Error:Resolutionofxxx#Areferencetoxxxdoesnotresolvebecauseitisneitherin#thelocalspecificationset,norinlimits.usrv.#Error:ResolutionofAaa.xxx#LooksforananmedUserVarscolleotionnamedAaa.Thenamed#specificationsetdoesnotqualify.}TestConditionGroupTCG2{SpecificationSetAaa;#Referencestheimportedspecificationset#Rule1:Resolutioninanameduservariablescollection.#AreferencetoMyVars.VInLowreferstoVInLowfromMyVars.#Rule2:Resolutioninanamedspecificationset.#Areferenceto“xxx”herewillresolveinthecontext#ofthelocalspecificationsetAaaabove.#Rule3:Resolutionindefaultuservariablescollection.#Areferenceto“MaxInteger”herewillresolvetolimits.usrv.#Error:Resolutionofvcc#Areferehcetovccdoesnotresolvebecauseitisneitherin#thenamedspecificationsetAaa,norinlimits.usrv.#Error:ResolutionofAaa.xxx#LooksforanamedUserVarscollectionnamedAaa.Thenamed#specificationsetdoesnotqualify.}[177]说明集中名字的分解(以上规则)需要设置的选择器在需要名字分解时使能。这是通过测试条件组将通过指定选择器在测试中被引用的事实实现的。用于说明集的C++[178]利用以上规则,说明集可以由C++SpecificationSet类实现。SpecificationSet类具有基本上与UserVars类相同的API,除了用于选择器的额外字符串参数。因此,这个API不具体描述。所有命名说明集都优选地与该名字的C++对象关联。测试条件组环境中的本地说明集将具有对于该测试条件组唯一的名字。引用一个本地说明集的变量,而该变量处于它在其中定义的测试条件组环境之外,是非法的。电平[180]电平用于指定引脚和引脚组的参数。它是以下形式的声明集合<pin-or-pin-group-name>{<pin-param-1>=xxx;<pin-param-2>=yyy;}[181]这种声明指定命名引脚或引脚组的各种参数的设置。例如,如在以下例子中所示的,这种语句可以用于设置InputPins组中所有引脚的VIL值#----------------------------------------------------------#FileCHIPlevels.lvl#---------------------------------------------------------Version1.0;ImportCHIP3resources.rsc;ImportCHIP3pins.pin;LevelsCHIP3Levels{##Specifiespin-parametersforvariouspinsand#pingroupsusingglobalsandvaluesfrom#thespecificationset##Theorderofspecificationissignincant.#Pinparameterswillbesetinorderfrom#firsttolastinthisLevelssection,and#fromfirsttolastforeachpinorpin-group#subsection.##FromtheimportedpindescriptionfileCHIP3pins.pin,#theInPinsgroupisinthe“dpin”resource.Fromthe#importedresourcedefinitionfileCHIP3resources.rsc,#the“dps”resourcehasparametersnamedVILandVIH.#InPins{VILv_il;VIH=v_ih+1.0;}#Thefollowingstatementrequiresadelayof10uSafter#thecalltosettheInPinslevels.Actualdelaywillbe#asmallsystemdefinedrangearound10.0E-6:#10.0E-6-delta<=actual<=10.0E-6+deltaDelay10.0E-6;##FortheOutPins,thelevelsfortheparameters#VOLandVOHarespecified.#OutPins{VOL=v_ol/2.0;VOH=v_oh;}#Theclockpinwillhavespecialvalues.Clock{VOL=0.0;VOH=v_ih/2.0;}#ADelayof10uSafterthecalltosetClocklevels.#Thisisaminimumdelay,thatisguaranteedtobefor#atleast10.0uS,thoughitmaybealittlemore:#10.0E-6<=actual<=10.0E-6+deltaMinDelay10.0uS;##ThePowerPinsgroupisinthe“dps”resource.Pinsofthis#pingrouphavespecialparameters:#PRE_WAITspecifiesthetimetowaitaftervoltage#reacheditsfinalvaluetostartpattern#generation.Actualwaittimewillbeasmall#systemdefinedrangearoundPRE_WAIT(see)#POST_WAITspecifiesthetimetowaitafterpartern#generationendstoshutdownthepower.Actual#waittimewillbeasmallsystemdefinedrange#aroundPRE_WAIT(see).#PowerPins{PRE_WAIT=10.0ms;POST_WAIT=10.0ms;#VCCreachesitsfinalvalueof2.0Vfromits#presentvalueinarampwithaVoltageSlewRate#of±.01VoltsperSecond.VCC=Slew(0.01,2.0V);}}LevelsCHIP4Levels{#...}[182]如上面所看到的,每个Level块都优选地由多个level项构成,每个level项指定一个引脚或引脚组的参数。每个level项可以指定多个资源参数。用于设置这些level值的运行时语义如下[183]Level块的level项是以声明次序处理的。在多于一个Level项中出现的任何引脚都将被处理多次。用于单个参数的多个值说明应当以说明次序维护并应用。Level项中的资源参数以它们被指定的次序处理。在设置下一组电平时,Delay语句使设置电平的处理暂停大约所指示的持续时间。实际的等待时间可以在大约所指定延迟的小系统定义范围之内。因此,如果延迟t秒,则实际的延迟将满足t-Δt<=实际等待<=t+Δt[186]Delay语句将Level说明分成多个子序列,每个子序列将需要独立测试条件存储器设置来处理。MinDelay语句使设置电平的处理在设置下一电平组之前暂停至少所指定的持续时间。实际的等待时间可以在具有所指定最小延迟的最小值的小的系统定义范围之内。因此,如果最小延迟是t秒,则实际的延迟将满足t<=实际等待<=t+Δt[188]MinDelay语句将Level说明分成多个子序列,每个子序列将需要独立测试条件存储器设置来处理。每个引脚或引脚组名字精确地在引脚描述文件(suffix.pin)中的一个资源中指定,因此具有在资源文件(suffix.rsc)中指定的特定的可行资源参数集合。所有命名的参数必须来自这个可行的资源参数集合中,而且必须具有与用于设置其值的表达式相同的基本类型。关于资源参数的名字与类型的信息来自资源文件。资源文件Resources.rsc隐含导入,向测试器提供如dpin和dps的标准资源的参数的名字与类型。资源参数是可以使用UserVars及来自命名说明集或当前可视本地说明集的值的所分配表达式。Dps引脚资源具有特定的参数PRE_WAIT和POST_WAIT。PRE_WAIT参数指定从电源引脚达到其目的电压的时间到模式生成可以开始的时间所需要经过的时间段。POST_WAIT参数指定从模式生成停止的时间到电源引脚切断所需要经过的时间段。Dps引脚还指定电压参数如何到达其最终的值。它们可以简单地提供等式指定它,就象所有其它的引脚参数。在那种情况下,所述值将到达硬件所允许的值。它们还可以利用回转语句指定它。回转语句指定电源电压以具有指定绝对电压回转速度的斜率从初始值达到其最终值。用于Levels的C++[194]利用以上规则,C++Levels对象可以写成支持以下操作·有一种操作StatussetParameter(constString&pinOrPinGroupName,constString&parameterName,ElementaryTypeelementaryType,constExpression&Expression);[195]这个操作将表达式绑定到引脚或引脚组的参数。例如,dpin.InPinsVIH值由以下操作设置setParameter(”InPins”,”VIH”,VoltageT,Expression(”v_ih+1.0”));[196]对于Level对象中的所有声明,这个操作将调用几次。·有一种操作StatusassignLevels(constString&selector);如前面所描述的,该操作将通过并产生所有预定义的模块级接口以说明次序分配所有的参数电平。选择器参数用于根据前面所指定的规则分解表达式中的名字。测试条件组[197]测试条件组子语言将说明、定时与电平的描述包装在一起。定时对象常常利用参数指定。参数可以在定时中用于指定各种脉冲的上升边缘和下降边缘。同样,电平可以通过指定各种电压电平的最大、最小和一般值来参数化。测试条件组(TCG)对象根据这些说明将定时与电平的说明与实例化汇总到一起。TestConditionGroup声明包含可选的SpecificationSet。SpecificationSet声明可以是内联的(及未命名的)本地SpecificationSet,或者它也可以是对在其它地方声明的命名SpecificationSet的引用。TCG声明中可选的SpecificationSet声明后面跟着至少一个Level或Timing声明。它可以以任何次序既有Level又有Timing。但是,不允许有多于一个Level和Timing声明。这些约束是通过句法实施的。除了没有名字,TCG中的说明集声明与独立声明的声明设置完全一样。它的名字隐含地是包含它的TCG的名字。Timing声明包括来自指定定时文件的Timing对象的单个声明。这里是具有测试条件组的文件的例子#---------------------------------------------------------#FilemyTestConditionGroups.tcg#---------------------------------------------------------Version0.1;ImportCHIPlevels.lvl;Importedges.spec;Importtiming1.tim;Importtiming2.tim;TestConditionGroupTCG1{#ThisLocalSpecificationSetusesuser-definedselectors#“min”,“max”and“typ”.Anynumberofselectorswithany#userdefinednamesisallowed.##Thespecificationsetspecifiesatablegivingvaluesfor#variablesthatcanbeusedinexpressionstoinitialize#timingsandlevels.Thespecificationsetbelowdefines#valuesforvariablesasperthefollowingtable:#minmaxtyp#v_cc2.93.13.0#v_ihvInHigh+0.0vInHigh+0.2vInHigh+0.1#v_ilvInLow+0.0vInLow+0.2vInLow+0.1#...#Areferencesuchas“vInHigh”mustbepreviouslydefined#inablockofUserVars.##Thus,ifthe“max”selectorwasselectedinafunctional#test,thenthe“max”columnofvalueswouldbeboundto#thevariables,settingv_ccto3.1,v_ihtovInHigh+2.0#andsoon.##Notethatthisisalocalspecificationset,andhasno#name.SpecificationSet(min,max,typ){#Minimum,MaximumandTypicalspecificationsfor#voltages.Voltagev_cc=2.9,3.1,3.0;Voltagev_ih=vInHigh+0.0,vInHigh+0.2,vInHigh+0.1;Voltagev_il=vInLow+0.0,vInLow+0.2,vInLow+0.1;#Minimum,MaximumandTypicalspecificationsfor#leadingandtrailingtimingedges.Thebase#valueof1.0E-6uScorrespondsto1picosecond,#andisgivenasanexarnpleofusingscientific#notationfornumbersalongwithunits.Timet_le=1.0E-6uS,1.0E-6uS+4.0*DeltaT,1.0E-6uS+2.0*DcltaT;Timet_te=30ns,30ns+4.0*DeltaT,30ns+2.0*DeltaT;}#ReferstotheCHIP3Levelsimportedearlier.It#isoneofpossiblymanylevelsobjectsthathavebeen#importedfromtheabovefile.LevelsCHIP3Levels;—#Referstofiletiming1.timcontainingthesingle#timingTiming1.Thefilenameshouldbequotedif#ithaswhitespacecharactersinit.TimingsTiming1;}#AnothertestconditiongroupTestConditionGroupTCG2{#ClockAndDataEdgesSpecsisaspecificationsetwhich#isavailableintheedges.specsfile.Assumeithas#thefollowingdeclaration:#SpecificationSetClockAndDataEdgesSpecs(min,max,typ)#{#Timeclock_le=10.00uS,10.02uS,10.01uS;#Timeclock_te=20.00uS,20.02uS,20.01uS;#Timedata_le=10.0uS,10.2uS,10.1uS;#Timedata_e=30.0uS,30.2uS,30.1uS;#}#ASpecificationSetreferencetothisnamedsetisbelow:SpecificationSetClockAndDataEdgesSpecs;#Aninlinedlevelsdeclaration.Sincetheassociated#specificationset(above)doesnothavevariablessuch#asVInLow,VInHigh,VOutLowandVOutHigh,theymust#resolveinthedefaultUserVarscollection.Levels{InPins{VIL=VInLow;VIH=VInHigh+1.0;}OutPins{VOL=VOutLow/2.0;VOH=VOutHigh;}}#ThisTimingisfromthefile“timing2.tim”.Thetimings#willneedtheleadingandtrailingedgetimingsforclock#anddaraasspecifiedintheabovespecificationset.TimingsTiming2;}[200]在以上例子中,测试条件组TCG1描述了具有名字为“min”、“typ”和“max”的三个选择器的说明集。可以有任何数量不同的选择器。在说明集的主体中,对应于选择器,变量v_il、v_ih、t_le和t_te以值的三元组初始化。因此,在以上例子中,TCG1具有选择器“min”的实例将绑定变量v_il具有第一数字值(vlnputLow+0.0)。它支持用于说明集的选择器是用户定义的重复,而且允许任何次数的重复。唯一的要求是[201]说明集的选择器是唯一的标识符。在说明集中指定的每个值与精确地是与选择器集合元素个数相同的值数组关联。挑选第i个选择器将使每个值绑定到其关联的值向量的第i个值。在TCG中的说明集之后,可以有Level声明或Timing声明或两者都有。Level声明用于设置各种引脚参数的电平。在说明集中识别的变量将用于设置这些电平,以便允许用于引脚参数的不同实际值基于用于初始化TCG的选择器的动态绑定。为了示例说明,考虑启用选择器“min”的测试。参考页面上给出的说明集CHIP3Level,用于InPins组中引脚的引脚参数“VIH”将通过以下声明被初始化成表达式(v_ih+1.0)InPins{VIL=v_i1;VIH=v_ih+1.0;}[205]当选择器“min”启用时,这分解成(VinHigh+0.0+1.0)。同样,Timing对象可以基于说明集变量所选的值初始化。没有必要同时具有Timing和Level声明。如由以下例子所说明的,每个都可以自己出现,或者以任何次序同时出现。#---------------------------------------------------------#FileLevelsOnlyAndTimingsOnly.tcg#---------------------------------------------------------Version0.1;#ALevels-onlyTestConditionGroup.TestConditionGroupLevelsOnlyTCG{specificationSet(Min,Max,Typ){Voltagcv_il=0.0,0.2,0.1;Voltagev_ih=3.9,4.1,4.0;}#Aninlinedlevelsdeclaration.Sincetheassociated#specificationset(above)doesnothavevariablessuch#asVInLow,VInHigh,VOutLowandVOutHigh,theymust#resolveinthedefaultUserVarscollection.Levels{InPins{VIL=v_il;VIH=v_ih+1.0;}OutPins{VOL=v_l/2.0;VOH=v_ih;}}}#ATimings-onlyTestConditionGroupTestConditionGroupTimingsOnlyTCG{SpecificationSet(Min,Max,Typ){Timet_le=0.9E-3,1.1E-3,1.0E-3;}TimingsTiming2;}[206]但是,应当指出,在一个TCG中不应当有多于一个Timing和多于一个Level。因此,总的来说,应当有至少一个Timing或Level,且每个至多有一个。测试条件[207]TestCondition对象将TCG绑定到特定的选择器。一旦TCG已经如上所示进行了声明,则有可能如下所示声明TestCondition对象TestConditionTCMin{TestConditionGroup=TCG1;Selector=min;}TestConditionTCTyp{TestConditionGroup=TCG1;Selector=typ;}TestConditionTCMax{TestConditionGroup=TCG1;Selcctor=max;}[208]这些测试条件将在测试计划中如下实例化##DeclareaFunctionalTest“MyFunctionalTest”thatreferstothree#TestConditionGroupinstances.#TestFunctionalTestMyFunctionalTest{#SpecifythePatternListPList=patlAlist;#AnynumberofTestConditionscanbespecified:TestCondition=TCMin;TestCondition=TCMax;TestCondition=TCTyp;}在TCG(测试条件组)中命名资源。测试条件组中名字的分解在前面已经讨论过了。但是,这些规则可以重复,而且以下再次给出1.如果名字是合格的(cf.page),则它必须在命名用户变量集合中分解。2.如果名字不合格,则如果它在测试条件组中声明,则名字在本地说明集中分解,而如果是在测试条件组中引用,则名字在命名说明集中分解。3.如果名字没有被以上规则分解,则在缺省用户变量集合中分解。TCG运行时[210]测试条件组具有以下运行时语义[211]利用实例化的TestCondition,测试(如FunctionalTest)将引用具有来自其SpecificationSet的特定选择器的TCG。这种选择器将SpecificationSet中的每个变量绑定到其与所选选择器关联的值。然后,变量与其值的绑定将用于确定Levels和Timings。TestConditionGroup中的参数Level优选地以Level块中出现的次序顺序设置。因此,在CHIP3Level块中,参数电平设置的次序如下(符号<resource-name>.<resource-parameter>)·InputPins.VIL,·InputPins.VIH,·OutputPins.VIL,·OutputPins.VIH,·Clock.VOL,·Clock.VOH.这种顺序的次序使测试写程序看着电源的形式供点顺序。此外,如果电平项出现两次,即为一个引脚命名相同的引脚参数,则该引脚参数被设置两次。这也可以编程发生。如果参数由Slew语句设置,如VCC=Slew(0.01,2.0V);则意味着VCC将从其当前值以具有每秒±0.01伏特的电压回转速度的斜率达到其2.0伏特的最终值。说明集变量也可以传递到TCG中的Timings对象。然后,Timings对象将基于所选的变量初始化。例如,通过指定波形的上升边缘和下降边缘,这种机制可以用于定制Timings对象。用于TCG的C++[216]利用以上规则,测试条件组可以在C++TestConditionGroup类中声明并如下初始化[217]进行对TestConditionGroup成员函数的调用StatussetSpecificationSet(SpecificationSet*pSpecificationSet);该函数将设置TestConditionGroup的说明集。这可以是本地说明集,或者命名说明集,或者为空(如果都没有)。进行对TestConditionGroup成员函数的调用StatussetLevels(Levels*pLevels);该函数将设置TestConditionGroup的Level对象。这可以是局部声明的Level对象,或者是外部声明的Level对象,或者为空(如果都没有)。进行对TestConditionGroup成员函数的调用StatussetTimings(Timings*pTimings);该函数将设置TestConditionGroup的Timings对象。这可以是局部声明的Timings对象,或者为空(如果都没有)。Bin定义[220]Bin定义类定义Bin,即概括测试许多DUT的结果的计数器的集合。在测试DUT的过程中,DUT可以设置成任何bin,例如,指示特定测试的结果。在测试进行中,DUT可以设置成其它bin。DUT最终设置成的bin是在测试结束时所设置的最后一个。这种最终bin的计数器在这个DUT的测试结束时递增。具有bin定义的独立文件应当具有后缀.bdefs。Bin定义优选地是分层的。例如,在最外面的一层,可以有具有名字为Pass和Fail的两个bin的PassFailBins。然后,可以有几个HardBins,其中一些映射到Passbin,其它则映射到Failbin。HardBins被认为是PassFailBins的求精。最后,可以有大量的SoftBins,它们是HardBins的求精,其中很多映射到相同的HardBin。以下是说明bin层次的例子。#---------------------------------------------------------#FileCHlPbins.bdefs#---------------------------------------------------------Version1.2.3;BinDefs{#TheHardBinsareanoutermostlevelof#bins.Theyarenotarefinementofanyother#bins.BinGroupHardBins{“3GHzPass”:“DUTspassing3GHz”;“2.8GHzPass”:“DUTspassing2.8GHz”;“3GHzFail”:“DUTsfailing3GHz”;“2.8GHzFail”:“DUTsfailing2.8GHz”;LeakageFail:“DUTsfailingleakage”;}#TheSoftBinsareanextlevelofrefinement.#SoftBinsarearefinementofHardBins.BinGroupSoftBins:HardBins{“3GHzAllPass”:“GoodDUTsat3GHz”,“3GHzPass”;“3GHzCacheFail”:“CacheFailsat3GHz”,“3GHzFail”;“3GHzSBFTFail”:“SBFTFailsat3GHz”,“3GHzFail”;“3GHzLeakage”:“Leakagesat3GHz”,LeakageFail;“2.8GHzAllPass”:“GoodDUTsat2.8GHz”,“2.8GHzPass”;“2.8GHzCacheFail”:“CacheFailsat2.8GHz”,“2.8GHzFail”;“2.8GHzSBFTFail”:“SBFTFailsat2.8GHz”,“2.8GHzFail”;“2.8GHzLeakage”:“Leakagesat2.8GHz”,LeakageFail;}}[222]在以上例子中,最基本的bin是BinGroupHardBins。如果某个其它BinGroup是X的求精,则BinGroupX被看作是一组基本bin。因此,由于BinGroupSoftBins是HardBins的求精,所以BinGroupHardBins是一组基本bin。如果没有其它BinGroup是Y的求精,则BinGroupY被看作是一组leafbin。其中具有单个BinGroupZ的BinDefs块的退化情况将使Z为一组最基本的bin及一组leafbin。BinGroup名字是全局范围的。可以有任何数量的BinDefs块,但所声明的BinDefs必须是独特的。来自一个BinDefs块的BinGroup允许来自另一BinDefs块的BinGroup的求精。因此,在以上例子中,SoftBins可以在与HardBins独立的BinDefs块中。但是,为了可读性,强烈推荐定义所有BinGroup的单个BinDefs块。现在,通过添加另一BinGroup,以上层次可以扩展成计算有多少DUT通过和失败。#---------------------------------------------------------#FileCHIPbins.bdefs#---------------------------------------------------------Version1.2.3;BinDefs{#ThePassFailBinsareanoutermostlevelof#bins.Theyarenotarefinementofanyother#bins.BinGroupPassFailBins{Pass:“CountofpassingDUTS.”;Fail:“CountoffailingDUTS.”;}#TheHardBinsareanextlevelofrefinement.#HardBinsarearefinementofthePassFailBins,#asindicatedby“HardBins:PassFailBins”.BinGroupHardBins:PassFailBins{“3GHzPass”:“DUTspassing3GHz”,Pass;“2.8GHzPass”:“DUTspassing2.8GHz”,Pass;“3GHzFail”:“DUTsfailing3GHz”,Fail;“2.8GHzFail”:“DUTsfailing2.8GHz”,Fail;LeakageFail:“DUTsfailingleakage”,Fail;}#TheSoftBinsareanextlevelofrefinement.#SoftBinsarearefinementofHardBins.BinGroupSoftBins:HardBins{“3GHzAllPass”:“GoodDUTsat3GHz”,“3GHzPass”;“3GHzCacheFail”:“CacheFailsat3GHz”,“3GHzFail”;“3GHzSBFTFail”:“SBFTFailsat3GHz”,“3GHzFail”;“3GHzLeakage”:“Leakagesat3GHz”,LeakageFail;“2.8GHzAllPass”:“GoodDUTsat2.8GHz”,“2.8GHzPass”;“2.8GHzCacheFail”:“CacheFailsat2.8GHz”,“2.8GHzFail”;“2.8GHzSBFTFail”:“SBFTFailsat2.8GHz”,“2.8GHzFail”;“2.8GHzLeakage”:“Leakagesat2.8GHz”,LeakageFail;}}[225]这次,最基本的bin是BinGroupPassFailBins。它们一般不是任何bin的求精。BinGroupHardBins是PassFailBins的求精,而且也是基本bin。SoftBins是HardBins的求精,而且是一组leafbin。以上例子的层次中只有三个BinGroup。以下是更复杂的层次。BinDefs{#AgroupofmostbasebinsBinGroupA{...}#AgroupofbasebinsthatisarefinementofABinGroupAx:A{...}#AgroupofleafbinsthatisarefinementofAxBinGroupAxx:Ax{...}#AgroupofbasebinsthatisarefinementofABinGroupAy:A{...}#AgroupofleafbinsthatisarefinementofAyBinGroupAyy:Ay{...}#AgroupofmostbasebinsBinGroupB{...}#AgroupofleafbinsthatisarefinementofBBinGroupBx:B{...}}[226]在这个例子中,Ax和Ay是A的求精,Axx是Ax的求精,而Ayy是Ay的求精。这个例子还提供了BinGroupB和Bx,其中Bx是B的求精。以上具有名字为PassFailBins、HardBins和SoftBins的BinGroup的BinDefs声明将在这部分中继续用作例子。BinGroup中的每个bin具有1.或者是标识符或者是字符串文字的名字2.描述这个bin概括什么的说明3.如果这个bin是在求精的BinGroup中,则它求精的bin的名字也称为基本bin。PassFailBins中的两个bin名字为“Pass”和“Fail”。HardBins中的五个bin名字为“3GHzPass”、“2.8GHzPass”、“3GhzFail”、“2.8GhzFail”、“LeakageFail”。Bin名字可以是文字字符串,或者是标识符。Bin名字在BinGroup中必须唯一,但不同BinGroup之间可以重复。但是,BinGroup名字是全局范围的,而且必须在整个测试计划中唯一。在五个HardBins中,“3GHzPass”和“2.8GHzPass”都映射到PassFailBins的“Pass”bin。剩余的HardBins映射到PassFailBins的“Fail”bin。最后,有八个SoftBins。用于SBFT(softbin功能测试)和高速缓冲存储器在3GHz的两个失败映射到“3GhzFail”HardBin。同样,用于SBFT和高速缓冲存储器在2.8GHz的两个失败映射到“2.8GhzFail”HardBin。由于泄漏造成的两个失败都映射到相同的“LeakageFail”HardBin,而不管它们发生的速度。例如,最粗的测试(在最外面的级)是DUT通过还是未通过测试。例如,求精是DUT以特定频率,例如3Hz等,通过还是未通过测试。如下面所描述的,bin分配给测试计划流项(TestPlanFlowItem)中的DUT。测试计划流项具有结果子句,其中测试计划描述作为从执行测试而获得特定结果的结果所发生的动作与变化。在这个时候,SetBin语句可以发生#AFlowltemResultclause.Itisdescribedlater.Result0{#Actiontobetakenongettinga0backfrom#executingatest.#SetthebintoSoftBin.“3GHZPass”expressingthatthe#DUTwasexcellent.SetBinSoftBins.“3GHzPass”;}[232]许多SetBin语句可以在对DUT运行测试的过程中执行。当测试最终完成时,运行时将递增用于为该DUT和为所有其求精设置的finalbin的计数器。考虑具有在其测试过程中执行的以下SetBin语句的DUTSetBinSoftBins.”3GHzSBFTFail”;SetBinSoftBins.”2.8GHzAllPass”;[233]这个DUT通过3GHz的高速缓冲存储器与泄漏测试,但没有通过SBFT测试,因此分配给”3GHzSBFTFail”bin。然后,在2.8GHz进行测试,所有测试都通过。因此,最终bin分配是SoftBins集合中的”2.8GHzAllPass”。这个最终分配将递增以下bin的计数器1.SoftBins.”2.8GHzAllPass”2.HardBins.”2.8GHzPass”的求精3.PassFailBins.”Pass”的求精[234]当测试完成时,运行时将递增该DUT的最终bin分配和所有其求精的其它bin的计数器。SetBin只允许对leafbin进行。设置基本bin是非法的。以上计数器递增语义假设1.如果bin是leafbin,则是测试DUT结束时对该bin执行的SetBin语句的次数。2.如果bin是基本bin,则是其求精的bin的计数器之和。因此,在以上例子中,在SetBin语句中只允许SoftBins。用于HardBins.”LeakageFail”的计数器是用于SoftBins.”3GHzLeakageFail”与SoftBins.”2.8GHzLeakageFail”的计数器之和。以下是关于bin定义的一些规则1.BinDefinitions声明包括几个BinGroup声明。2.每个BinGroup声明都有名字及作为其求精的可选BinGroup名,后面是bin声明的一个块。3.bin声明包括名字,后面是描述,可选地还跟着该bin是其求精的基本bin的名字。4.bin名可以是字符串文字,或者是ID。空字符串不应当是有效的bin名。bin名应当在BinGroup声明的名字中唯一,但相同的名字可以在其它BinGroup声明中使用。5.如果BinGroup声明Xxx是另一BinGroup声明Yyy的求精,则Xxx中的所有bin声明必须声明来自Yyy的基本bin的名字。因此,因为SoftBins声明为HardBins的求精,所以SoftBins中每个bin声明都是HardBins的bin的求精。6.不是其它BinGroup声明的求精的BinGroup声明,例如PassFailBins,将优选地具有不声明基本bin的bin声明。binBbb具有一组Bbb是其求精的整个bin集合的base。它在形式上如下定义1.如果Aaa是Bbb的基本bin,则Aaa在Bbb的base集合中。2.Aaa的任何base都在Bbb的base集合中。BinGroup名字在TestPlan中是全局的。bin名字对BinGroup是局部的。SetBin语句只允许对leafbin进行。用于bin定义的C++[241]利用以上规则,可以为BinDefs声明中的每个BinGroup声明构造对象类型BinGroup。类BinGroup将具有子类LeafBinGroup。除了BinGroup∷incrementBin是C++受保护操作,而LeafBinGroup∷incrementBin是C++公有操作,这两个类的其它操作是相同的。以下是建立BinGroup或不是任何其它BinGroup求精的LeafBinGroup的缺省构造函数。构造函数BinGroup(BinGroup&baseBinGroup);LeafBinGroup(BinGroup&baseBinGroup);建立作为给定baseBinGroup的求精的baseBinGroup。一种方法StatusaddBin(constString&binName,constString&description,constString&baseBinName);定义bin及其描述。如果它是最基本的bin,则baseBinName参数必须是空字符串。递增bin计数器的方法StatusincrementBin(cosntString&binName);这个操作将递增用于这个bin和用于作为该binbase的所有bin的计数器。这个操作在类BinGroup中是受保护的,而在类LeafBinGroup是公有的。复位bin计数器的方法StatusresetBin(constString&binName);这个操作将复位用于该bin和用于作为该binbase的所有bin的计数器。获得关于bin的信息的方法StatusgetBinDescription(constString&binName,String&description);StatusgetBaseBin(constString&binName,BinGroup*pBaseBinGroup,String&baseBinName);StatusgetBinValue(constString&binName,unsignedint&value);[248]提供迭代器来获得所有当前定义的bin名字。TestPlan声明将包括BinGroup成员的个数,每个BinGroup声明一个。用于以上BinDefinitions的C++将如下//TestPlanconstructorTestPlan∷TestPlan():m_PassFailBins(),//DefaultConstructorm_HardBins(&m_PassFailBins),m_SoftBins(&m_HardBins){}//Bininitializationsm_PassFailBins.addBin(“Pass”,“CountofpassingDUTS.”,“”);m_passFailBins.addBin(“Fail”,“CountoffailingDUTS.”,“”);m_HardBins.addBin(“3GHzPass”,“Dutspassing3GHz”,“Pass”);...TestPlan的声明包括初始化为未定义BinGroup(NULL)的m_pCurrentBinGroup和初始化为未定义bin名(空字符串)的m_currentBin。每次当执行SetBin语句时,通过调用,将m_pCurrentBinGroup改变成指示BinGroup的名字,而mcurrentBin改变成指示组中的命名bin//Translationof:SetBinSoftBins.”3GHzAllPass”;pTestPlan->setBin(“SoftBins”,“3GHzAllPass”);[251]当测试计划完成执行时,它将调用m_pCurrentBinGroup->incrementBin(m_currentBin);使得这个bin和所有其基本bin都递增它们的计数器。当设计好测试计划时,测试计划BinGroup计数器复位,但不会在每次运行测试时重新初始化。计数器可以通过对BinGroup∷resetBin的显式调用复位。C.测试计划[253]测试计划可以看作是测试程序的主要结构。测试计划可以导入文件及定义类似的构造内联函数。因此,有可能导入给出一些全局符定义及声明附加全局符内联函数的文件。C1.测试计划流程与FlowItem[254]测试计划的一个关键元素是流。流封装了有限状态机。它包括运行IFlowable对象然后转换到另一FlowItem的几个FlowItem。运行IFlowable涉及运行实现IFlowable接口的对象。实现IFlowable接口的典型对象是Test与Flow本身。因此,流程具有运行Test与其它流程,然后转换成另一FlowItem的FlowItem。它还提供对从运行IFlowable返回的各种结果调用用户定制例程的机会。一般来说,Flow具有以下形式##FlowTestlimplementsafinitestatemachineforthe#Min,TypandMaxflavorsofMyFunctionalTest1.On#successittestsTest1Min,Test1Typ,Test1Max#andthenreturnstoitscallerwithOasasuccessful#status.Onfailure,itreturns1asafailingstatus.##AssumethatthetestsMyFunctionalTest1Min,...all#returnaResultofO(Pass),1and2(foracouple#oflevelsoffailure).#Result0Result1Result2#Test1MinTest1Typreturn1return1#Test1TypTest1Maxreturn1return1#Test1Maxreturn0return1return1#FlowFlowTest1{FlowItemFlowTest1_MinMyFunctionalTest1Min{Result0{PropertyPassFail=“Pass”;IncrementCountersPassCount;GoToFlowTest1_Typ;}Result1{PropertyPassFail=“Fail”;InerementCountersFailCount;Return1;}#Thisresultblockwillbeexecutedif#MyFunctionalTest1Minreturnsanyof#2,5,6,7,-6,-5or-4Result2,5:7,-6:-4{PropertyPassFail=“Fail;IncrementCountersFailCount;Return1;}}FlowItemFlowTest1_Typ{...}FlowItemFlowTest1_Max{...}}[256]流FlowTest1的操作如下1.以执行FlowItemFlowTest1_Min开始。2.FlowTest1_Min运行功能性测试,MyFunctionTest1Min。这种测试的细节在以下给出完整的测试计划时提供。3.期望从运行这个测试得到九种结果,0、1、2、5、6、7、-6、-5或-4。前两个Result子句分别处理0和1,第三个处理所有剩余的结果值。4.如果结果“0”(通过)出现,则FlowTest1_Min将递增计数器PassCounter。然后,将转换到新的FlowItemFlowTest1_Typ。5.如果结果“1”或结果“2”出现,则FlowTest1_Min将递增计数器FailCounter,然后从该流程返回。6.FlowTest1_Typ将以相同的方式操作,后续调用FlowTest1_Max。7.FlowTest1)_Max将将以相同的方式操作,然后当结果成功时,从该流程返回(“0”)。因此,对于成功的运行,FlowTest1将通过Test1的最小化、典型和最大化版本运行设备,然后返回。FlowTest2将以类似的方式运行。如上所述的流程基本上描述了有限状态机的状态与转换。FlowItem基本上是状态,它将做以下动作1.执行IFlowable(它可以是前面定义的Flow或Test或可以利用以上规则在C++中实现的用户定义的流程)。2.IFlowable的执行返回数字结果。基于该结果,特定的动作发生(更新一些计数器),然后发生以下两件事情中的一个1.流程返回到具有该数字结果的调用者。2.流程通过转换到另一状态(FlowItem)继续。因此,FlowItem具有以下成分·FlowItem有名字。·FlowItem有要执行的IFlowable。·FlowItem有数字或Result子句。·FlowItem的每个Result子句提供动作并以transition结束并与一个或多个结果值关联。这些项在FlowItem中的句法如下。FlowItem<name><IFIowabletobeexecuted>{Result<oneormoreresultvalues>{<actionsfortheseresultvalues><transitionfortheseresultvalues>}Result<oneormoreotherresultvalues>{...}...}要执行的IFlowable可以是Test或者用户定义的IFlowable,或者是Flow。用于结果的动作可以是以下任何一个·将由GUI工具使用的字符串值实体设置成属性结果的属性动作。这可以在以上FlowTest1例子中看到PropertyPassFail=”Pass”;[262]属性基本上是与结果语句关联的命名字符串或整数值实体。属性的数量可以是任意的,并且其优选由诸如GUI这样由用户用来显示与该结果关联的信息的工具使用。它们对实际测试结果或测试流程没有影响。一个计数行为将计数器的某些数字递增。这可以从上例中的语句IncrementCountersPassCount;看出。·一个例程调用程序调用一个任意的或用户的例程。这在下面讨论。最后,FlowItem具有一个Transition,其可以是将控制转移给另一FlowItem的GoTo语句,或者将控制返回给调用者(可以是调用流程,也可以是发起该测试计划的系统例程)的Return语句。预定义的流程(Flow)[265]Flow对象的典型应用是定义测试顺序。然后,该顺序作为测试计划服务器(TPS)中所发生事件,即执行测试计划事件,的结果执行。每个站点控制器上的测试计划服务器执行用户的测试计划。但是,Flow对象也响应其它事件执行。圆括号中的名字是用于将Flow分配给这些事件的名字。1.系统加载流程(SysLoadFlow)。当测试计划加载到一个或多个站点控制器上时,这个流程在系统控制器上执行。它是在测试计划实际加载到任何站点控制器上之前执行的。这个流程允许测试计划开发人员定义应当源自系统控制器的动作。这种动作包括模式文件的广播加载、校准动作,等等。2.站点加载流程(SiteLoadFlow)。这个流程在测试计划已经加载到站点上并初始化以后在站点控制器上执行。这允许任何特定于站点的初始化发生。3.批(lot)启动/结束流程(LotStartFlow/LotEndFlow)。当通知测试计划服务器新批的启动时,这些流程在站点控制器上执行。这典型地用于生产环境中注释具有特定于批的信息的数据登录流程。4.DUT改变流程(DutChangeFlow)。当其DUT信息改变时,这个流程在站点控制器上执行。同样,这也典型地用于生产环境中更新数据登录流程。5.测试计划启动/结束流程(TestPlanStartFlow/TestPlanEndFlow)。当通知测试计划服务器开始执行当前测试流程时和当该流程结束执行时,这些流程在站点控制器上执行。6.测试启动/结束流程(TestStartFlow/TestEndFlow)。当测试流程开始运行新测试和当该测试结束执行时,这些流程在站点控制器上执行。7.测试流程(TestFlow)。这个流程是当测试计划服务器接收到“执行测试计划”消息时执行的主要流程对象。应当指出,如果用户在用户的测试计划中定义了不是TestFlow或其它预定义流程中一种的流程,则执行它的优选方式是将其包括在这些预定义流程中一个的转移状态中。测试计划举例[267]在以下例子中,一起给出流程与描述该流程实现的有限状态机的注释。有限状态机是作为转移矩阵给出的。矩阵的行对应于FlowItem,列对应于结果。矩阵行的项指示当返回结果是列中所指定值时从该行的FlowItem转移到的FlowItem。以下示出具有三个流程,FlowTest1、FlowTest2和FlowMain,的测试计划。FlowTest1如上所述操作。它将在“min”、“typ”与“max”中的每一个中运行名字为MyFunctionalTest1的测试。同样,FlowTest2将在这些配置的每个中运行MyFunctionalTest2。最后,FlowMain将运行FlowTest1和FlowTest2。有限状态机转移矩阵在这些流程中的每个开始部分的注释中提供。#-------------------------------------------------------#FilemySimpleTestPlan.tpl#--------------------------------------------------------Version0.1;Importxxx.pin;#Pins#Constantsandvariablesgivinglimitingvalues.Importlimits.usrv;#ImporttestconditiongroupsImportmyTestConditionGroups.tcg;#Importsomebindefinitions.Importbins.bdefs;#----------------------------------------------------------#Startofthetestplan#----------------------------------------------------------TestPlanSample;#ThisblockdefinesPatternListsfile-qualifiednamesand#PatternListvariablesthatareusedinTestdeclarations.#Patternlistvariablesaredeferredtillcustomizationis#examined.PListDcfs{#Filequalifiedpatternlistnamesp11A.plist:pat1Alist,p12A.plist:pat2AList}#Thesocketforthetestsinthistestplan(thisisnotimported,#butresolvedatactivationtime):SocketDef=mytest.soc;#DeclaresomeuservariablesinlineUserVars{#StringnameforcurrenttestStringCurrentTest=″MyTest″;}TestConditionTC1Min{TestConditionGroup=TCG1;Selector=min;}TestConditionTC1Typ{TestConditionGroup=TCG1;Seleetor=typ;}TestConditionTC1Max{TestConditionGroup=TCG1;Selector=max;}#LikewiseforTC2Min,TC2Typ,TC2Max...##DeclareaFunctionalTest.″FunctionalTest″referstoaC++#testclasstbatrunsthetest,andreturnsa0,1or2as#aResuIt.TheTestConditionGroupTCG1isselectedwith#the″min″selectorbyreferringtotheTC1MinTestCondition.#TestFunctionalTestMyFunctionalTest1Min{PListParam=pat1AList;TestConditionParam=TC1Min;}#AnotherFunctionalTestselectingTCG1with″typ″TestFunctionalTestMyFunctionalTest1Typ{PListParam=pat1AList;TestConditionParam=TC1Typ;}#AnotherFunctionalTestselcctingTCG1with″max″TestFunctionalTestMyFunctionalTest1Max{PListParam=pat1AList;TestConditionParam=TC1Max;}#NowselectTCG2with″min″TestFunctionalTestMyFunctionalTest2Min{PListParam=pat2AList;TestConditionParam=TC2Min;}#LikewiseforTCG2with″typ″andTCG2with″max″TestFunctionalTestMyFunctionalTest2Typ{PListParam=pat1AList;TestConditionParam=TC2Typ;}TestFunctionalTestMyFunctionalTest2Max{PListParam=pat1AList;TestConditionParam=TC2Max;}##AtthistimethefollowingTestobjectshavebeendefined#MyFunotionalTest1Min#MyFunctionalTest1Typ#MyFunctionalTest1Max#MyFunctionalTest2Min#MyFunctionalTest2Typ#MyFunctionalTest2Max###Countersarevariablesthatareincrementedduringthe#executionofatest.TheyareUnsignedIntegersthatare#initializedtozero.#Counters{PassCount,FailCount}##Flowscannowbepresented.AFlowisanobjectthat#essentiallyrepresentsafinitestatemachinewhich#canexecute“Flowables”,andtransitiontootherflowablesbased#ontheResultreturnedfromexecutingaFlowable.AFlowcanalso#callanotherflow.##AFlowcoinsistsofanumberofFlowItemsandtransitions#betweenthem.FlowItemshavenameswhichareuniquein#theenclosingFlow,executea“Flowable”object,andthen#transitiontoanotherFlowIteminthesameenclosingFlow.##FlowableobjectsincludeTestsandotherFlows.When#aFlowableobjectexecutes,itreturnsanumericResult#whichisusedbytheFlowItemtotransitiontoanother#FlowItem.Asaresultofthis,bothTestsandFlows#terminatebyretuminganutmericResultvalue.##FlowTest1implementsafinitestatemachineforthe#Min,TypandMaxflavorsofMyFunctionalTest1.On#successittestsTest1Min,Test1Typ,Test1Max#andthenreturnstoitscallerwith0asasuccessful#Result.Onfailure,itreturns1asafailingResult.##AssumethatthetestsMyFunctionalTest1Min,...all#returnaResultof0(Pass),1and2(foracouple#oflevelsoffailure).TheTransitionMatrixofthe#finitestatemachineimplementedbyFlowTest1is;#-----------------------------------------------------------#Result0Result1Result2#-----------------------------------------------------------#FlowTest1_MinFlowTest1Typretum1return1#FlowTest1_TypFlowTest1Maxreturn1return1#FlowTest1_Maxreturn0return1retum1##wheretheIFlowablesrunbyeachFlowItemare:#FlowItemIFlowablethatisrun#FlowTest1_MinMyFunctionalTest1Min#FlowTest1_TypMyFunctionalTest1Typ#FlowTest1_MaxMyFunctionalTest1Max#FlowFlowTest1{FlowItemFlowTest1_MinMyFunctionalTest1Min{Result0{PropertyPassFail=″Pass″;IncrementCountersPassCount;GoToFlowTest1_Typ;}Result1,2{PropertyPassFail=″Fail″;IncrementCountersFailCount;Return1;}}FlowItemFlowTest1_TypMyFunctionalTest1Typ{Result0{PropertyPassFail=″Pass″;IncrementCountersPassCount;GoToFlowTest1_Max;}Result1,2{PropertyPassFail=″Fail″;IncrementConntersFailCount;Return1;}}#LikewiseforFlowTest1_MaxFlowItemFlowTest1_MaxMyFunctionalTest1Max{Result0{PropertyPassFail=″Pass″;IncrementCountersPassCount;Return0;}Result1,2{PropertyPassFail=″Fail″;IncrementCountersFailCount;Return1;}}}##FlowTest2issimilartoFlowTest1.Itimplementsa#finitestatemachinefortheMin,TypandMaxflavors#ofMyFunctionalTest2.OnsuccessittestsTest2Min,#Test2Typ,Test2Maxandthenreturnstoitscallerwith#0asasuccessfulResult.Onfailure,itreturns1as#afailingResult.##AssumethatthetestsMyFunctionalTest2Min,...all#retumaResultof0(Pass),1and2(foracouple#oflevelsoffailure).TheTransitionMatrixofthe#finitestatemachineimplementedbyFlowTest2is:#-----------------------------------------------------------#Result0Result1Result2#-----------------------------------------------------------#FlowTest2_MinFlowTest2_Typreturn1return1#FlowTest2_TypFlowTest2Maxreturn1return1#FlowTest2_Maxreturn0return1return1##WheretheIFlowablesrunbyeachFlowItemare:#FlowItemIFlowablethatisrun#FlowTest2_MinMyFunctionalTest2Min#FlowTest2_TypMyFunctionalTest2Typ#FlowTest2_MaxMyFunctionalTest2Max#FlowFlowTest2{#...}##NowtheFlowMain,themaintestflow,canbepresented.It#implementsafinitestatemachinethatcallsFlowTest1#andFlowTest2asbelow:#------------------------------------#Result0Result1#------------------------------------#FlowMain_1FlowMain_2return1#FlowMain_2return0return1##WheretheIFlowablesrunbyeachFlowItemare:#FlowItemIFlowablethatisrun#FlowMain_1FlowTest1#FlowMain_2FlowTest2FlowFlowMain{#Thefirstdeclaredflowistheinitialflowtobe#executed.ItgoestoFlowMain_2onsuccess,and#returns1onfailure.FlowItemFlowMain_lFlowTest1{Result0{PropertyPassFail=″Pass″;IncrementCountersPassCount;GoToFlowMain_2;}Result1{#Sorry...FlowTest1failedPropertyPassFail=″Fail″;IncrementCountersFailCount;#AddtotherightsoftbinSetBinSoftBins.“3GHzSBFTFail”;Return1;}}FlowItemFlowMain_2FlowTest2{Result0{#Allpassed!PropertyPassFail=″Pass″;IncrementCountersPassCount;#AddtotherightsonbinSetBinSoftBins.“3GHzAllPass”;Return0;}Result1{#FlowTest1passed,butFlowTest2failedPropertyPassFail=″Fail″;IncrementCountersFailCount;#AddtotherightsoftbinSetBinSoftBins.“3GHzCacheFail”;Return1;}}}TestFlow=FlowMain;[269]以上测试计划是以优选次序如下构造的1.首先,提供版本号。这个号用于确保与编译器版本的兼容性。2.然后,声明多个导入。这些是具有分解测试计划中所使用名字所需的声明的各种文件。3.接下来,声明测试计划名字,其后是测试计划的内联声明。4.然后声明一组PlistDefs。这些包括指定来自所指定文件的GlobalPLists的文件限定名字。它们还包括模式列表变量。模式列表变量是可以在执行时的定制flowable中初始化的变量。它们提供了将测试与实际模式列表的绑定延迟到运行时的方式。5.接下来,声明一组用户变量。这些包括字符串。6.然后,声明一些计数器,以便确定通过和未通过的测试的个数。计数器是初始化为0并在IncrementCounter语句递增的简单变量。它们与前面描述的bin不同,bin的语义是只有当前设置的bin在DUT测试结束时递增。7.接下来声明一系列测试条件。这些条件中的每个指定一个测试条件组和选择器。在这个例子中,测试条件组来自mytestconditionsgroups.tcg。但是,它们也可以内联在测试计划中。8.接下来,声明一系列Flowables或测试。它们每一个都是选择模式列表与测试条件的已知测试功能测试。因此,例如,MyFunctionalTest1Max选择测试条件TClMax与模式列表。9.然后,声明三个流程,FlowTest1、FlowTest2和FlowMain。流程运行Flowables。Flowables包括测试(例如MyFunctionalTestlMax)和其它流程(例如FlowTestl和FlowTest2)。FlowTest1和FlowTest2中的每一个都分别运行通过Test1和Test2的最小、典型与最大版本。流程FlowMain调用前面声明的流程,先是FlowTest1,然后是FlowTest2。10.最后,TestFlow事件分配给FlowMain流程。因此,流程FlowMain是当用户选择执行这个计划时由这个测试计划执行的流程。用于流程的C++[270]利用以上规则,大部分元素可以用C++实现,除了流程本身。用于FlowItem的C++[271]表示FlowItem的C++类可以具有以下接口·一种操作StatussetFlowable(IFlowable*pIFlowable);该操作将设置对这个FlowItem要执行的IFlowable。一旦FlowItem从需要执行这个IFlowable的调用集合返回,它就将需要递增依赖于结果值的计数器列表。为此,FlowItem需要有要递增的计数器向量。这通过以下调用初始化StatussetCounterRefs(unsignedintresult,CounterRefListcounterRefs);这个调用将对计数器的引用向量设置到FlowItem中,使得一旦IFlowable完成执行它就可以递增它们。例如,语句IncrementCountersA,B,C;将优选地如下使用以上调用//SomewhereearlierCounterRefListcounters;...//CodeforResultclause//Result2,3{...}//offlowObject.counters.reset();counters.add(&A);counters.add(&B);counters.add(&C);flowObject.setCounterRefs(2,counters);flowObiect.setCounterRefs(3,counters);使用临时的CounterRefList对象指定计数器。最开始调用counters.reset(),然后是设置计数器列表的多个counters.add()调用。然后,这可以用于设置针对结果值2和3要更新的计数器向量。然后,FlowItem可能需要转移到关于特定结果的另一FlowItemStatussetTransition(unsignedintresult,FlowItem*pFlowItem);在特定Result语句处理许多结果值的情况下,自然需要几个这样的调用。FlowItem可能需要返回结果。这可以通过以下进行StatussetReturnResult(unsignedintresult,unsignedintreturnResult);[276]例如,对于前面例子中的FlowItemFirstFlowItem,以上调用中“result”的值是“2”,而“returnResult”的值是“1”。·最后,FlowItem需要执行操作Statusexecute(unsignedint&result,FlowItem*pNextFlowItem);[277]这个操作将执行IFlowable,然后更新所指示的计数器,然后或者返回结果,或者返回指向下一FlowItem的指针。如果这个指针为NULL,则结果是返回值。为FlowItemFlowMain_1生成的代码如下FlowItemFlowMain_1;FlowItemFlowMain_2;CounterRefListcounters;FlowMain_1.setFlowable(FlowTest1);//Result0counters.reset();counters.add(&PassCount);FlowMain_1.setCounterRefs(0,counters);FlowMain_1.setTransition(0,&FlowMain_2);//Result1counters.reset();counters.add(&FailCount);FlowMain_1.setCounterRefs(1,counters);//TbefollowingcallfromITestPlanwillsetthe//currentbingroupandbinname.pTestPlan->setBin(“SoftBins”,“3GHzSBFTFail”);FlowMain_1.setReturnResult(1,1);以上生成的代码设置FlowMain_1运行IFlowable“FlowTest1”,然后设置它递增用于每个结果的合适计数器列表,最后采取必需的动作。在结果“0”的情况下必需的动作是转移到FlowMain_1,而在结果“1”的情况下是返回。C2.测试计划中的计数器支持[280]计数器是初始化为0并且可以在测试运行中的各个点由IncrementCounter语句递增的变量。它们与只在测试结束时递增的Bin不同。此外,bin是层次性的,而计数器是简单变量。因此,计数器比bin具有更简单更有限的功能。计数器可以通过维护一组作为无符号整数的指定计数器的Counter类在TestPlan中支持。对象将通过Counter声明在这个类中定义。计数器不能在测试开始时自动复位,从而允许TestPlan在测试许多DUT的过程中收集计数。需要提供对一个计数器的值进行复位、递增和查询的方法。这使得可以有bining的替代,以便确定作为运行测试结果的计数。TestPlan优选地包含成员变量,m_modifiedCounters,这是通过在DUT上运行测试修改的计数器的集合。这个集合在测试的开始初始化成空集合。在进行IncrementCounters调用的每个地方,将生成向m_modifiedCounters成员添加指定计数器的代码。因此,这个成员收集在DUT上测试执行过程中修改的所有计数器。用于Flow对象的C++[283]一旦所有的FlowItem都创建了,则Flow对象就可以如下所示作为C++对象创建·添加FlowItem的操作StatusaddFlowItem(FlowItem*pFlowItem,boolisInitalFlowItem);该操作向Flow添加所指示的FlowItem。如果这是Flow的初始FlowItem,则布尔值设置成True。·执行流程的操作StatusexecuteFlow(unsignedint&result);[284]这优选地在Flow返回时返回,结果是执行流程。其动作是利用初始FlowItem开始执行流程。只有当前FlowItem返回下一个要执行的FlowItem,它就将持续执行FlowItem。因此,为Flow生成的C++具有几个对addFlowItem()的重复调用,以便将FlowItem添加到Flow。当选择测试计划中的这个流程执行时,executeFlow()操作将发生。C3.测试类[286]总的来说,大部分程序代码是用于设备测试的数据,剩余的是实现测试方法的测试程序代码。数据是依赖DUT的(例如,电源条件、信号电压条件、定时条件等)。测试条件包括将指定的设备条件加载到ATE硬件上的方法,还有那些实现用户指定目标(如数据登录等)所需的方法。如上面所解释的,为了提高测试代码的重用性,这种代码一旦独立于任何特定于设备的数据(例如,引脚名、模拟数据等)或特定于设备测试的数据(例如,用于DC单元的条件、测量引脚、目标引脚的个数、模式文件的名字、模式程序的地址等)。如果测试代码利用这些类型的数据编译,则测试代码的重用性将降低。因此,应当使任何特定于设备的数据或特定于设备测试的数据对测试代码在外部可用,作为代码执行时的输入。在开放体系结构测试系统中,作为Itest接口实现的Test类实现对于特定类型的测试测试数据与代码的分离(从而实现代码的重用性)。这种测试类可以看作是其独立实例的“模板”,独立实例彼此的区别只有特定于设备或特定于设备测试的数据。测试类在测试计划文件中指定。每个测试类典型地实现特定类型的设备测试或者设备测试的安装。例如,Functional、AC和DC参数化测试优选地是由独立的Test类实现的。但是,定制的测试类也可以用在测试计划中。测试类允许用户通过提供用于指定该测试的特定实例的选项的参数来配置类行为。例如,FunctionalTest将分别取参数Plist和TestConditions来指定要执行的模式列表和该测试的Level和Timing条件。(通过测试计划描述文件中不同“Test”块的使用)指定这些参数的不同值允许用户创建FunctionalTest的不同实例。图5示出了不同的测试实例502将如何从单个测试类504导出。这些类应当设计成允许编译器400从测试计划文件取测试的描述及其参数并生成正确的C++代码,该代码可以编译链接以生成测试程序。测试类实例可以添加到描述测试流程的对象,其中测试流程创建设备测试的复杂执行序列。C4.从ITest和IFlowable的导出[291]如上面所提到的,Test类从ITest导出。利用以上规则,这些可以在实现ITest接口的C++类中实现。除了为ITest接口指定的方法,这些类提供执行指定的设备测试类所需的特定于测试的智能与逻辑。Test类还实现IFlowable接口。因此,Test类的实例可以用在运行测试的FlowItem中。定制[292]提供定制机制来允许用户调用C函数并开发他们自己实现ITest与IFlowable接口的类。自我测量能力[293]如果Test类的对象可以被询问关于其方法与签名,则可以验证合适的参数可以包括在所生成的源代码中。这种特征对于转移阶段中的错误检查与确认是非常有用的。如果测试工程师在参数的名字中或对这些参数的变元个数(或者可能是类型)中犯了错误,则转移阶段可以捕捉到它并在翻译时提供有意义的错误消息,而不是等待来自C++编译器的编译时错误消息。这对测试工程师更加有用。自检(Introspection)指要求对象在其自身当中查找并返回关于其属性与方法的能力。例如Java的有些语言将这种能力作为语言的一部分提供。诸如VisualBasic的其它语言将这种需求强加到要与其一起使用的对象上。C++不提供这种特征。这种方法还很好地适于提供缺省参数值,及可选参数的指示。此外,如果这种能力作为所有Test类实现的一部分提供,则GUI应用还可以使用这种信息动态建立对话框及其它用户接口元素来帮助工程师有效地使用这些类。这些复杂性在本发明的实施方式中是通过代替完全自我测量而提供允许测试类开发人员在单个基于文本的源文件(每个Test类)中完全指定Test类的公有方法/属性的方法的机制抵消的,其中开发人员已经指定该Test类为参数化类所需的Test类。单个源是优选的任何人都不想在一个文件中有Test类的参数化接口的描述,而在另一独立的(头)文件中有C++接口描述,然后麻烦地需要使这两个源保持同步。为此,“基于文本的”描述嵌入到用于Test类的Preheader文件中,该Preheader文件由编译器用于有限的自我测量及用于生成Test类的C++头。所生成的C++头文件是用于最终编译Test类C++代码的头文件。Preheader[298]C++中头的使用是众所周知的。因此,因为C++难以解析和阅读,所以本发明的实施方式定义允许编译器创造可以由测试类开发人员用作头的C++输出。根据这种实施方式,测试类开发人员写Preheader,该Preheader由编译器400作为头文件输出,从而允许到对应测试类或其它测试实体的可见性。以下例子说明了根据本发明优选实施方式用于Test类的Preheader文件的概念。考虑以下从源文件的节选,对于测试FuncTest1...TestConditionTC1{TestConditionGroup=TCG1;#PreviouslydefinedTCGforLevelsSelector=min;}TestConditionTC2{TestConditionGroup=TCG2;#PreviouslydefinedTCGforTimingSelector=min;}...TestFunctionalTestFuncTest1{PLisfParam=patList1;#PreviouslydefinedpatternlistTestConditionParam=TC1;TestConditionParam=TC2;}[300]编译器需要知道哪个FunctionalTest是确定以上FuncTest1的说明是否合法所必需的。哪个FunctionalTest必需的定义可以在Preheader中定义,而不是在知道FunctionalTest的情况下建立到编译器中。假定C++类中的FunctionalTest具有基类Test1和Test2,并具有是Plist和TestConditions阵列的成员。编译器需要知道FunctionalTest成员的类型,以便识别以上FuncTest1的声明是否合法。此外,为了生成FunTest1的C++对象声明,需要构建类FunctionalTest的C++头文件。这需要编译器也知道FunctionalTest类的基本类、其成员名、以及其它这样的信息。本发明一个实施例的Pre-header子语言为编译器提供其识别声明的合法性和生成对应于声明的C++头文件和对象声明所需的信息。注意,FunctionalTest是简单的类型(如果考虑参数化),因此,将使用非常简单的描述来参数化。因此可以按照以下所示来写支持上述参数化的Pre-header,FunctionalTest.ph(假设Pre-header对于基本测试类Test1和Test2)1Version1.0;2#3#Parameterizationspecificationpre-headerforFunctionalTest4#5ImportTest1.ph;#ForbaseclassTest16ImportTest2.ph;#ForbaseclassTest27TestClass=FunctionalTest;#Thenameofthistestclass8PublicBases=Test1,Test2;#Listofpublicbaseclasses9#Thcparameterslistor“parameterblock”:10Parameters11{12#ThefollowingdeclarationspecifiesthataFunctionalTesthas13#-aparameteroftypePList14#-[representedbyC++typeTester∷PatternTree]15#-storedinamcmbernamedm_pPatList16#-afunctiontosetitnamedsetPatternTree.17#-aparameterdescriptionfortheGUItouseasatooltip18PListPListParam19{20Cardinality=1;21Attribute=m_pPatList;22SctFunction=setPatternTree;23Description=“ThePListparameterforaFunctionalTest”;24}25#26#ThefollowingdeclarationspecifiesthataFunctionalTesthas27#-lormoreparametersoftypeTestCondition28#-[representedbyC++typeTester∷TestCondition]29#-storedinamembernamedm_testCondnsArray30#-afunctiontosetitnamedaddTestCondtion.31#-aparameterdescriptionfortheGUItouseasatooltip32#The[implement]clausecausesthetranslationphaseofto33#generateadefaultimplementationofthisfunction.34#35TestConditionTestConditionParam36{37Cardinality=1-n;38Attribute=m_testCondnsArray;39SetFunction=addTestCondition[Implement];4ODeseription=“TheTestConditionparamteterforaFutnctionalTest”;41}42}43#44#ThesectionbelowispartofthePre-Headerwhichisanescape45#intoC++code.Thiswillbereferedtoasa“templateblock.”46#47#Everythinginthissectionwillbereproducedverbatiminthe48#generatedheaderfile,exceptfor“$Class”,“$Inc”,49#“$ParamAryTypes”,“$ParamAttrs”,“$ParamFns”and“$Paramlmpls”.50#51#Notethatnocommentsbeginningwiththe‘#’characteraresupported52#withinthefollowingsection.53#54CPlusPlusBegin55$Inc56namespace57{58class$Class59{60//Arraytypesforparametersstorage:61$ParamAryTypes62public:63virtualvoidpreExec();64virtualvoidexec();65virtualvoidpostExec();66$ParamFns67...68private:69doublem_someVar;70$ParamAttrs71...72};73...74$ParamImpls75}//Endnamespace76CPlusPlusEnd用于参数化的测试类的C++[305]当编译器处理Pre-Header文件时,它建立编译器变量的值,如$Inc,$Class、$ParamAryTypes及其它。这使得它能够通过逐字逐句地生成以上C++代码并在所指示的位置在编译器变量$Inc、$Class等的值中扩展来创建以下C++头文件。对于FunctionalTest.ph,它为FunctionalTest类创建以下C++头文件FunctionalTest.h。1#line7″./FunctionalTest.ph″2#include<ITest.h>3#line5″./FunctionalTest.ph″4#include<Test1.h>5#line6″./FunctionalTest.ph″6#include<Test2.h>7#line55″./FunctionalTest.ph″8#include<vectop>9#line55″./FunctionalTest.ph″10#include<Levels.h>11#line55″./FunctionalTest.ph″12#include<TestCondnGrp.h>13...14#line56″./FunctionalTest.ph″15namespace16{17#line7″./FunctionalTest.ph″18classFunctionalTest:publicITest,19#line8″./FunctionalTest.ph″20publicTest1,21#line8″./FunclionalTest.ph″22publicTest223#line59″./FunctionalTest.ph″24{25//Arraytypesforparametersstorage:26#line61″./FunctionalTest.ph″27public:28#line37″./FunctionalTest.ph″29typedefstd∷vector<Tester∷TestCondition*>TestConditionPtrsAry_t;3O#line62″./FunctionalTest.ph″31public:32virtualvoidpreExec();33virtualvoidexec();34virtualvoidpostExec();35public:36#line7″./FunctionalTest.ph″37voidsetName(OFCString&name);#Automaticforalltests38#line22″./FunctionalTest.ph″39voidsetPatternTree(PatternTree*);40#line23″./FunctionalTest.ph″41StringgetPListParamDescription()const;42#line39″./FunctionalTest.ph″43voidaddTestCondnion(TestCondition*);44#line40″./FunctionalTest.ph″45voidgetTestConditionParamDescription()const;46#line67″JFunctionalTest.ph″47...48private:49doublem_someVar;50#line70″./FunctionaLtesLph″51private:52#line7″./FunctionalTest.ph″530FCStringm_name;#Automaticforalltests54#line21″./FunctionalTest.ph″55Tester∷PatternTree*m_pPatList;56#line38″./FunctionalTest.ph″57TestConditionPtrsAry_tm_testCondnsArray;58#ine71″./FunctionalTest.ph″59...60};61...62#line7″./FunctionalTest.ph″63inlinevoid64#line7″./FunctionalTest.ph″65FunctionalTest∷setName(OFCString&name)66#line74″./FunctionalTest.h″67{68m_name=name;69return;70}71#line39″/FuoctionalTest.ph″72inlinevoid73#line39″./FunctionalTest.ph″74FunctionalTest∷addTestCondition(TestCondition*arg)75#line74″./FunctionalTest.ph″76{77m_testCondnsArray.push_back(arg);78return;79}80#line23″./FunctionalTest.ph″81inlinevoid82Tester∷StringFunctionalTest∷getPListParamDeacription()83{84return“ThePListparameterforaFunctionalTest”;85}86#line40″./FunctionalTest.ph″87inlinevoid88Tester∷StringFunctioualTest∷getTestConditionParamDeseription()89{90return“TheTestConditi0nparameterforaFunctionalTest”;91}92#line75″./FunctionalTest.ph″93}//Endnamespace如前面所描述的,这个Pre-Header使得编译器能够检查FunctionalTest声明的有效性,来为其生成代码并生成它所需的C++头文件。作为例子,考虑前面给出的FunctionalTest声明,为了方便,以下进行了复制TestFunctionalTestFuncTest1{PlistParam=patList1;#PreviouslydefinedpattemlistTestConditionParam=TC1;TestConditionParam=TC2;}[308]以上给出编译器将为此生成的C++头文件。编译器将为以上FunctionalTest构造函数生成以下代码FunctionalTestFuncTest1;FuncTest1.setName(″FuncTest1″);FuncTest1.setPatternTree(&patList1);FuncTest1.addTestCondition(&TC1);FuncTest1.addTestCondition(&TC2);[309]还应当注意为Description函数生成的名字。名字为Xxx的每个参数都与以下成员函数关联StatusgetXxxDescription()const;该函数返回具有GUI可以使用的工具提示描述的字符串。其它Pre-Header特征[310]Pre-Header支持一些其它用户定义的枚举类型作为附加类型。这允许GUI提供可以用于设置特定参数值的可能选择的下拉列表。此外,Pre-Header提供关联可以看作表的多个参数的特征。例如,将“属性”阵列实现为关联的名字字符串阵列与值的整数阵列的集合可能是方便的。实现这种特征的一种容易的方式是使用(后面讨论的)定制类型阵列。但是,那需要用户写要使用的定制类型Pre-Header。这些特征都在以下例子中说明#---------------------------------------------------------#FileFooBarTest.ph##Parameterizationspecificationpre-headerfor#customtestclassFoobarTest#---------------------------------------------------------Version1.0;ImportTest1.ph;#ForbaseclassTest1TestClass=FoobarTest;#ThenameofthistestclassPublicBases=Test1;#Listofpublicbaseclasses#Theparatneterslist:Parameters{#AnenumneratedtypeEnumWishyWashy=Yes,Perhaps,Possibly,Maybe,MaybeNot,No;#DefineaWishyWashyparameter.WishyWashyWW{Cardiality=1;Attribute=m_ww;SetFunction=setWw;Description=“TheWWparameterforaFoobarTest”;}#Thisclasshasanarrayofname-numberpairsthatis#interpretedintheclass.ParamGroup{Cardinality=0-n#TheNamefieldinthisarrayis:#-oftypeString#-[representedbyC++typeTester∷String]#-storedinamembernamedm_NameArray#-afunctiontosetitnamedaddName.#-aparameterdescriptionfortheGUItouseasatooltipStringName{Attribute=m_NameArray;SetFunction=addName;Description=“ANamewithaValue”;}#TheNumberfieldinthisarrayis:#-oftypeInteger#-[representedbyC++typeint]#-storedinamembernamedm_NumberArray#-afunctiontosetitnamedaddNumber.#-aparameterdescriptionfortheGUItouseasatooltipIntegerNumber{Attribute=m_NumberArray;SetFunction=addNumber;Description=“ThevalueoftheName”;}}#ThefollowingdeclarationspecifiesthataFunctionalTesthas#-aparameteroftypePList#-[representedbyC++typeTester∷PatternTree]#-storedinamembernamedm_pPatList#-afunctiontosetitnamedsetPatternTree.#-aparameterdescriptionfortheGUItouseasatooltipPListPListParam{Cardinality=1;Attribute=m_pPatList;SetFunction=setPatternTree;Description=“ThePListparameterforaFunctionalTest”;}##ThefollowingdeclarationspecifiesthataFunctionalTesthas#-1ormoreparametersoftypeTestCondition#-[representedbyC++typeTester∷TestCondition]#-storedinamembernamedm_testCondnsArray#-afunctiontosetitnamedaddTestCondition.#The[implement]causecausesthetranslationphaseofto#generateadefaultimplementationofthisfunction.#TestConditionTestConditionParam{Cardinality=1-n;Attribute=m_testCondnsArray;SetFunction=addTestCondition[Implement];Description=“TheTestConditionparamcterforaFunctionalTest”;}}CPlusPlusBegin$Iacnamespace{class$Class{//Arraytypesforparametersstorage:$ParamAryTypespublic:virtualvoidpreExec();virtualvoidexec();virtualvoidpostExec();$ParamFns//...private:doublem_someVar;$ParamAttrs//...};//...$ParamImpls}//EndnamespaceCplusPlusEnd[311]必须指出,定制类型的名字-数字对可以是已经声明的,而且该定制类型的单个阵列参数可以是已经用于具有与以上参数ParamGroup相同的作用。以上提出的技术是避免声明定制类型的必要性的方便措施。C5.定制函数声明[312]这允许用户在流程转移发生时调用定制函数。定制函数是通过Pre-Header如下声明的#---------------------------------------------------------#FileMyFunctions.ph##Parameterizationspecificationpre-headerforMyFunctions#---------------------------------------------------------Version1.0;Functions=MyFunctions;#Thenameofthisgroupoffunctions#DeclarethefollowingC++functioninthe#MyFunctionsnamespacetodeterminetheminimun#oftwovalues.#//Returntheminimumofx,y#doubleMyRoutines∷Min#(ITestPlan*pITestPlan,int&x,int&y);IntegerMin(Integerx,Integery);#DeclarethefollowingC++functioninthe#UserRoutinesnamespacetoreturntheaverageof#anarray.#//Returntheaverageofthearray#doubleMyRoutines∷Avg#(ITestPlan*plTestPlan,double*a,constinta_size);#TheC++functionwillbecalledwithaanda’LengthDoubleAvg(Doublea[]);#DeclarethefollowingC++functioninthe#UserRoutinesnamespacetoprintthedutid#andamessage#//Returntheaverageofthearray#doubleMyRoutines∷Print#(ITestPlan*plTestPlan,String*msg,unsignedint&dutId);#TheC++functionwillbecalledwithaanda’LengthVoidPrint(Stringmsg,UnsignedlntegerdutId);[313]一般来说,由于编译器将以标准方式扩展这些声明,因此需要为以上声明提供C++部分。用户当然要负责这些函数的C++实现。应当指出,所有的以上函数都将可能取ITestPlan指针作为隐含的第一个参数。这个指针向函数书写者提供对TestPlan中stateS的访问。例如,函数书写者可以使用ItestPlan接口来访问当前的Flow,流程中的当前FlowItem,当前的Result子句,UserVars的值,及其它这种信息。特定的测试器定义函数可以在文件Functions.ph中使用Version1.2.3;##FileFunctions.ph#Functions=Functions;#Thenameofthisgroupoffunctions#DeclarethefollowingC++functioninthe#Functionsnamespace#ReturnstheIDofthecurrentDUTbeingtestedbythe#caller.UnsignedIntegerGetDUTID();用于定制函数声明的C++[314]由编译器为以上MyFunctions生成的C++代码是要简单地声明MyFunctions命名空间中的一些函数namespaceMyFunctions{doubleMin(ITestPlan*pITestPlan,int&x,int&y);doubleAvg(ITestPlan*pITestPlan,double*a,constinta_size);voidPrint(ITestPlan*pITestPlan,char*Msg,unsignedintdutID);}[315]这些函数将可以从流程调用。定制Flowble[316]也有可能利用Pre-Header创建实现C++IFlowable接口的Pre-Header。这使得用户能够定义可以在FlowItem中运行的定制flowable。以下所示是用于用户定义的FlowableMyFlowable的Pre-Header#---------------------------------------------------------#FileMyFlowable.ph##Parameterizationspecificationpre-headerforMyFlowable#---------------------------------------------------------Version1.2.4;FlowableClass=MyFlowable;#Thenameofthiscustomclass#Theparameterslist:Parameters{#ThefollowingdeclarationspecifiesthataMyFlowahlehas#-1optionalparameterInt1oftypeInteger#-[representedbyC++typeint]#-storedinamembernamedm_int1Val#-afunctiontosetitnanmedsetlnt1Val.IntegerInt1{Cardinality=0-1;Attribute=m_int1Val;SetFunction=setInt1Val;}#ThefollowingdeclarationspecifiesthataMyFlowablehas#-1mandatoryparameterInt2oftypeInteger#-[representedbyC++typeint]#-storedinamembernamedm_int2Val#-afunctiontosetitnamedsetInt2Va.IntegerInt2{Cardinality=1;Attribate=m_int2Val;SetFunction=setInt2Val;}#ThefollowingdeclarationspecifiesthataMyFlowablehas#-oneormoreparametersoftypeString#-[representedbyC++typeTester∷String]#-storedinamembernamedm_stringArrVal#-afunctiontosetitnamedaddStringVal.StringStringItem{Cardinality=1-n;Attributt=m_stringArrVal;SetFunction=addStringVal;}#ThefollowingdeclarationspecitiliesthataMyFlowablehas#-AsinglePListparameter#-[representcdbytheC++typeTester∷PList]#-storedinamembernamedm_plist#-afunctiontosetitnamedsetPListParamPListPListParam{Cardinality=1;Attribute=m_plist;SetFunction=setPListParam;}}##ThesectionbelowispartofthePre-Headerwhichisanescape#intoC++code.##Everythinginthissectionwillbereproducedverbatiminthe#gerneratedheaderfile,exceptfor“$Class”,“$Inc”,#“$ParamAryTypes”,“$ParamAttrs”,“$ParamFns”and“$ParamImpls”.##Notethatnocommentsbeginningwiththe‘#’characteraresupported#withinthefollowingsection.#CPlusPlusBegin$Incnamespace{class$Class{//Arraytypesfbrparamctersstorage:$ParamAryTypespublic:virtualvoidpreExec();virtualvoidexec();virtualvoidpostExec();$ParamFns//...private:doubiem_someVar;$ParamAttrs//...};//...SParamImpls}//EndnamespaceCplusPlusEnd有几个实现IFlowable接口的类。这些类包括1.用于程序加载的流程,它检查测试计划是否可以在当前测试器配置中执行。2.用于模式加载的流程,它将加载特定的模式与模式列表。3.用于初始化的流程,它将硬件与软件放到已知的状态,加载全局变量,并进行其它初始化与确认功能。4.其它通常有用的测试流程。C7.定制类型[318]前面关于Test类的讨论只允许测试类参数为已知类型,即,基本类型和测试器定义类型,例如PList和TestConditions。为了用户的灵活性,提供类型可扩展性是很重要的,由此可以创建和使用(对编译器是未知先验的)类型。Customtype(CT)将在定制类型中定义。这些可以用于定义对应于C语言struct(也称为PlainoldData类型或者POD,这与它们在C++中的同名物差别很大)的类型及对应于C语言函数签名typedefs的类型。具有用户类型的独立文件将有扩展名.ctyp。这里是根据本发明优选实施方式的用户类型声明的例子#---------------------------------------------------------#FileMyCustomTypes.etyp#--------------------------------------------------------Version1.0.0;CustomTypes{#AstructuredPlain-Old-DatatypePodFoo{StringS1;#StringisastandardtypeIntegerI1;#...andsoisIntegerStringS2;}#AnotherstructuredtypeusingFooPodBar{FooFoo1;StringS1;FooFoo2;}##Apointertoafunction.#Retumtype:Integer#Parameters:Integer,Integer#RoutineBinaryOp(Integer,Integer)ReturnsInteger;##Anotherpointertoafunction.#Returntype:Void#Parametcr:Integer#RoutineUnaryOp(Integer)ReturnsVoid;##Apointertoafunctionthattakes#noparametersanddoesnotreturnavalue.#RoutineNullaryOp()ReturnsVoid;}用于定制类型的C++[319]以上提出的定制类型声明将由编译器翻译成以下C++代码namespaceCustomTypes{structFoo{Tcster∷StringS1;intI1;Tester∷StringS2};structBar{FooFoo1;Tester∷StringS1;FooFoo2;};typedefint(*BinaryOp)(int&,int&);typedefvoid(*UnaryOp)(int);typedefvoid(*NullaryOp)();}如以下所示出的,这些类型的对象可以作为参数传递到Test类。作为Test类参数使用定制类型[321]考虑用户具有对测试的扩展的情况,除了模式列表和测试条件,这需要初始化其它类对象及在包含定制类型的文件(即,.ctyp文件)中定义的任意(即,用户定义)对象。例如,假定用户想使用在文件MyTestCTs.ctyp中定义的CT#FileMyTesctCTrs.ctypVersion1.0;CustomTypes{PodFoo{Stringname;PListpatternList;}PodBar{FoosomeFoo;DoubledVal;}RoutineBinaryOp(Integer,Integer)returnInteger;}[322]用户使用以上类型所需要做的就是在他的测试类pre-header中导入以上文件。由于编译器解释如此定义的CT,由此当其处理测试类pre-header时,用于Foo和Bar的定义可用。此外,编译器定义两个C语言strcut,分别对应于以上类型Foo和Bar的structFoo和structBar,其定义放在文件myTestCTs.h中。myTestCTs.ctt的导入语句使文件myTestCTs.h包括在所生成的测试类C++头中。以下例子说明了这个处理。首先,考虑测试计划中对测试的声明(为了清楚,忽略了对模式列表和测试条件的声明)...ImportMyFunctions.ph;ImportMyCustomTypes.ctyp;...#TheCustomVarsblockdefinesvariablesoftheCustom#typesdefinedearlier.CustomVars{...Barbar1={{″ThisisaFoo″,somePatList},#someFoo3.14159#dVal}##Afunctionobjectthatisabinaryoperator.#Thenameontherighthandsideoftheassingnment#isaroutinedeclaredinMyFunctions,forwhich,#ofcourse,theuserhastoprovideanimplementation.#BinaryOpbop1=MyFunetions.Min;}...TestMyFancyTestMyTest1{…BarParam=bar1;BinaryOpParam=bop1;}...在以上例子中,CustomVars块包括在测试计划中。具有定制变量的独立文件将具有扩展名.cvar。用户将如下写用于支持以上参数化的pre_header(为了清楚,忽略用于模式列表和测试条件的参数化声明)#---------------------------------------------------------#FileMyFancyTest.ph##Parameterizationspecificationpre-headerforMyFancyTest#---------------------------------------------------------Version1.0.2;ImportMyCustomTypes.cryp;#ForCTsusedinMyFancyTestImportFunctionalTest.ph;#Forbasec1assFunctionalTestTestClass=MyFancyTest;#ThenameofthistestclassPublicBascs=FunctionalTest;#Listofpublicbaseclasses#Theparameterslist:Parameters{#ThefollowingdeclarationspecifiesthataMyFancyTesthas#-anoptionalarrayofparametersofcustomtypeBar#-[representcdbyC++typeCustomTypes∷Bar]#-storedinamembernamedm_barsArray#-afunctiontosetitnamedaddBarParam.#AnimplementationwillbegeneratedforaddBarParam.BarBarParam{Cardinality=0-n;Attribute=m_arsArray;SetFunction=addBarParam[Implement];}#ThefollowingdeclarationspecifiesthataMyFancyTesthas#-anoptionalparameterofcustomtypeBinaryOp#-[representedbyC++typeCustomTypes∷BinaryOp]#-storedinamembernamedm_binaryOp#-afunctiontosetitnamedsetBinaryOpParam.#AnimplemcntationwillbegeneratedforsetBinaryOpParam.BinaryOpBinaryOpParam{Cardinality=0-1;Attribute=m_binaryOp;SetFunetion=setBinaryOpPararm[Implement];}}CPIusPlusBegin$Incnamespace{class$Class{$ParamAryTypespublic:virtualvoidpreExec();virtualvoidexec();virtualvoidpostExec();$ParamFns//...private:doublem_someVar;$ParamAttrs//...};//...$ParamImpls}//EndnamespaceCPlusPlusEnd用于利用定制类型的定制测试类的C++[324]最后,一旦编译器处理完这个pre-header文件,它就将创建以下用于MyFancyTest类的C++头文件,MyFancyTest.h:#include<MyCustomTypes.h>#include<ITest.h>#include<FunctionalTesth>...namespace{classMyPancyTest:publicITest,publicFunctionalTest{public:typedefstd∷vector<CustomTypes∷Bar*>BarAry_t;public:virtualvoidpreExec();virtualvoidexec();virtualvoidpostExec();public:voidsetName(OFCString&name);#AutomaticforalltestsvoidsetPatternTree(PattemTree*);voidaddTestCondition(TestCondition*);voidaddBarParam(CustomTypes∷Bar*);voidsetBinaryOpParam(CustomTypes∷BinaryOp*);...private:doublem_someVar;private:OFCStringm_name;#AutomaticforalltestsPatternTree*m_pPatList;TestConditionPtrsAry_tm_testCondnsArray;BarAry_tm_barsArray;BinaryOp*m_binaryOp;...};//EndclassMyFancyTest...inlinevoidMyFancyTest∷addBarParam(CustomTypes∷Bar*arg){m_barsArray.push_back(arg);return;}inlinevoidMyFancyTest∷setBinaryOpParam(CustomTypes∷BinaryOp*arg){m_binaryOp=arg;return;}}//Endnamespace参数化[325]如上面所看到的,用于Test类、定制Flowable类或定制函数定义的pre-header通过参数化说明部分提供了对类/函数有限的自我测量。编译器使用这个部分生成用于类/函数的参数化接口(并生成类/函数头本身)。对于Test类和Flowable类,它还使用这部分随后在测试计划代码中生成初始化该类实例的调用。应当注意以下关于pre-header和对应声明的点1.每个Test或定制Flowable类定义都优选地在pre-header中指定。pre-header中的Parameter块优选地是可以指定用于这种类的参数列表的唯一地方。(因此,作为必然的结果,用于Test的“标准”参数,例如模式列表和测试条件说明,也需要包括在Parameter块的pre-header中;这允许标准和CT的所有测试统一处理)。2.在用于Test或Flowable的pre-header中定义为非可选(即,具有非零基数)的所有参数都应当在用于该类实例的Test块或Flowable块声明中初始化。3.用于Test/Flowable块中参数初始化的对象应当在前面已经定义了。4.替换指示符$Class、$Inc、$ParamAryTypes、$ParamFns、$ParamAttrs与$ParamImpls必须出现在pre-header的用户代码部分中用户想将对应的所生成代码插入所生成类头文件中的确切位置。由于为每个都生成特定的代码,因此这些应当确切地只出现一次。5.pre-header的Parameter块中参数说明的名字(例如以上例子中的PListParam、TestConditionParam或BarParam)是要用于该类实例的声明中的参数名字。6.以下是用于参数说明中的描述的语义a)Cardinality这指出将支持的这种类型参数的个数。以下是一种实施方式中的可能值i1这个参数是强制的,而且应当确切地只指定一次。这个参数将作为对该类型参数对象的指针维护。ii0-1这个参数是可选的;如果指定,则必须只指定一次。这个参数将作为指向该参数类型对象的指针保持。iii1-n这个参数是强制的。而且,可以对这个参数指定多个值。值以指定的次序存储。iv0-n这个参数是可选的。可以对这个参数指定多个值。值以指定的次序存储。应当注意,对于以上的()和(),所有指定的值都存储在STL向量<>中,根据指向参数类型的指针建立模板。这个向量的类型将被定义并插入到由$ParamAryTypes指示的点。对这些类型定义的访问级总是公有的。b)Attribute作为这种类型参数值的存储使用的C++变量的名字。该名字将作为C++类的私有数据成员逐字被复制,并且必须遵循C++标识符的需求。应当注意,这种属性的类型是i如果只允许单个值,则是指向参数类型的指针;ii如果允许多个值(见以上()),则是关于指向参数类型的指针建立模板的STL向量<>。应当注意,属性保持对由测试计划创建和构成的对象的引用,但不拥有这些对象。对象的寿命总是由测试计划本身管理的。c)SetFunction用于设置这个参数值所使用的函数名。以下要点应当注意i名字应当是逐字复制的,因此必须遵循C++语言需求。ii函数的访问级总是公有的。iii返回类型总是void。iv函数总是只带单个变元,类型是指向参数类型的指针。应当注意,值总是单独设置的,即,对于允许指定多个值的参数,测试计划中所生成的代码将重复调用这个函数,对每个指定的值调用一次,每个值都将添加到STL向量(如上所述)。函数名之后的可选关键字“[implement]”指示这个函数的通常实现将作为内联方法在类头中可用(在由$ParamImpls指示的点插入)。否则,用户负责提供该函数的实现。a)Description作为工具提示的字符串文字,将由GUI工具用于在这个参数的运行时修改中提供帮助。在用于名字为Xxx的参数的定制类中所生成的C++成员函数将是StringgetXxxDescription()const;该函数将返回指定的字符串。定制的测试计划例子[328]以下所示是利用某种定制修饰的测试计划例子#---------------------------------------------------------#FileMyCustomizedTestPlan.tpl#---------------------------------------------------------Version0.1;##Importsasbefore...#Thefollowingimportisimplicit,butcanbeexplicitly#provided.ImportFunctionalTest.ph;#ImportforMyFlowables,MyFunctionsandFunctionsImportMyFlowables.ph;ImportMyFunctions.ph;ImportFunctions.ph;#----------------------------------------------------------#Startofthetestplan#---------------------------------------------------------TestPlanSample;#ThisblockdefinesPatternListsfile-qualifiednamesand#PatternListvariablesthatareusedinTestdeclarations.#Thefile-qualifiednamesrefertopatternlistsinthenamed#files.ThevariablesrefertoStringvariableswhichwill#holdthepatternlistnamesatruntime.UserdefinedFlowable#objectscouldsetthevaluesofthesevariablesthroughan#API.PListDefs{#Filequalifiedpatternlistnamesp11A.plist:pat1Alistp12A.plist:pat2AList,#PatternlistvariablesplistXxx,plistYyy,plistZzz}#SocketDef,UserVarsdeclarationasbefore...#DeclarationsofTestConditionsTC1Min,TC1Typ,TC1Max,#TC2Min,TC2Typ,TC2Maxasbetore...##DeclareaFunctionalTest.“FunctionalTest”referstoaC++#testclassthatrunsthetest,andreturnsa0,1or2as#aResult.TheTestConditionGroupTCG1issclectedwith#the″min″selectorbyreferringtotheTC1MinTestCondition.##Notethatcompilercancompilethisbecauseoftheimported#FunctionalTest.phfile.#TestFunctionalTestMyFunctionalTest1Min{PListParam=pat1AList;TestConditionParam=TC1Min;}##AdditionalFunctionalTestdeclarationsforthefollowing,asbefore#MyFunctionalTest1Typ#MyFunctionalTest1Max#MyFunctionalTest2Min#MyFunctionalTest2Typ#MyFunctionalTest2Max##HereisadeclarationofMyFlowable.ItusesaPatternListvariable#plistXxxwhichisinitializedbytbeflowablepriortousehere.##CompilercancompilethisbecauseoftheimportedMyFlowables.phfile:FlowableMyFlowableMyFlowable1{Int1=10;Int2=20;StringItem=“HelloWorld”;PListParam=plistXxx;}#CountersforPassCountandFailCountasbefore...#Flowsasbefore.FlowsFlowTest1andFlowTest2are#unchangedfromthepreviousexample.FlowFlowTest1{#...}FlowFlowTest2{#...}##NowFlowMain,amainflow,canbepresented.It#implementsafinitestatemachinethatcallsFlowTest1#andFlowTest2asbelow:#------------------------------------#Result0Result1#------------------------------------#FlowMain_1FlowMain_2return1#FlowMain_2FlowMain_3return1#FlowMain_3FlowMain_4return1#FlowMain_4FlowMain_5return1#FlowMain_5return0return1##WheretheIFlowablesrunbyeachFlowItemare:#------------------------------------------#FlowItemIFlowablethatisrun#------------------------------------------#FlowMain_1MyFlowable1#FlowMain_2DatalogStartFlow#FlowMain_3FlowTest1#FlowMain_4FlowTest2#FlowMain_5DatalogStopFlow#FlowFlowMain{##Thefirstdeclaredflowistheinitialflowtobe#executed.ItgoestoFlowMain_InitializationFlow#onsuccess,andreturns1onfailure.#FlowItemFlowMain_1MyFlowable1{Result0{PropertyPassFail=″Pass″;IncrementCountersPassCount;#AuserfunctioncallMyFunetions.Print(“PassedMyFlowable1”,Functions.GetDUTID());GoToFlowMain_2;}Result1{PropertyPassFail=″Fail″;IncrementCountersFailCount;#AuserfunctioncallMyFunctions.Print(“FailedMyFlowablel”,Functions.GetDUTID());SetBinSoftBins.“3GH2Leakage”;Return1;}}##GoestoFlowMain_3onsuccess#andreturns1onfailure.#FlowItemFlowMain_2DatalogStartFlow{Result0{PropertyPassFail=″Pass″;IncrementCountersPassCount;#AuserfunctioncallMyFunctions.Print(“PassedDatalogStartFlow”,Functions.GetDUTID());GoToFlowMain_3;}Result1{PropertyPassFail=″Fail″;IncrementCountersFai1Count;MyFunctions.Print(“FailedDatalogStanFlow”,Fuinctions.GetDUTID());Return1;}}#ThisFlowItemcallsthepreviouslydefinedFlowTest1FlowItemFlowMain_3FlowTest1{Result0{PropertyPassFail=″Pass″;IncrementCountersPassCount;#AuserfunctioncallMyFunctions.Print(“PassedFlowTest1”,Functions.GetDUTID());GoToFlowMain_4;}Result1{PropertyPassFail=″Fail″;IncrementCountersFailCount;#AuserfunctioncallMyFunctions.Print(“FailedFlowTest1”、Functions.GetDUTID());SetBinSoftBins.“3GHzCacheFail”;Return1;}}#ThisFlowItemcallsthepreviouslydefinedFlowTest2FlowItemFlowMain_4FlowTest2{Result0{PropertyPassFail=″Pass″;IncrementCountersPassCount;#AuserfunctioncallMyFunctions.Print(“PassedFlowTest2”,Functions.GetDUTID());GoToFlowMain_5;}Result1{#FlowTest1passed,butFlowTest2failedPropcrtyPassFail=″Fail″;IncrementCountersFailCount;#AuserfunctioncallMyFunctions.Print(“FailedFlowTest2”,Functions.GetDUTID());SetBinSoftBins.“3GHzSBFTFail”;Return1;}}FlowItemFlowMain_5DatalogStopFlow{Result0{#AllPassed!PropertyPassFail=″Pass″;IncrementCountersPassCount;#AuserfunctioncallMyFunctions.Print(“Passedall!”,Functions.GetDUTID());SetBinSoftBins.“3GHzAllPass”;Return0;}Result1{#FlowTest1andFlowTest2passed,#butDatalogStopFlowfailedPropertyPassFail=″Fail″;IncrementCountersFailCount;#AuserfunctioncallMyFunctions.Print(“FailedDatalogStopFlow”,Functions.GetDUTID());Return1;}}}[329]关于以上代码,需要指出以下要点1.这里的PListDefs部分有一些PList名字还有一些PList变量。PList名字是可以在测试中直接使用的名字。PList变量是可以在测试中使用的变量,其值在运行时由定制Flowable中的代码绑定到实际的PList。2.PListDefs部分是可选的。如果不存在,则其内容可以由编译器从各测试声明中推断。如果存在,则必须声明测试所使用的所有PList参数,当然也可以声明更多个。3.运行时API可用于向PList变量指定值。TestPlan类将具有函数StatusSetPListVariable(constTester∷String&varName,constTester∷String&fileQualifiedPListName);Flowable将能够使用以上函数将PListVariable绑定到特定的PList。4.用户函数可以在FlowItems中刚要转移之前调用,其中转移或者是将控制转移到其它FlowItem,或者是返回。用于用户函数调用的C++[330]除了在流中调用定制函数,由编译器生成的C++代码已经对前面给出的各种定制技术示出了。FlowItem中的用户函数调用优选地是由每个流的IUserCalls成员处理的。每个流优选地具有导出单个虚拟成员函数的接口IUserCalls的成员,如下所示classIuserCalls{public:virtualvoidexec(constString&flowItemName,unsignedintresult)=0;}[331]当遇到具有用户函数调用的流时,流以实现以上接口的类的实例构成。例如,在流例子中的FlowMain中将以以下类的实例构成classFlowMain_UserCalls:publicIUserCalls{public:virtualvoidexec(constString&flowItemName,unsignedintresult){if(flowItcmName==“FlowMain_1”){//...}elseif(flowItemName==“FlowMain_2”){//...}elseif(flowItemName==“FlowMain_3”){switch(result){case0:MyFunctions∷Print(“PassedFlowTest1”,Functions∷GetDUTID());retun;case1:MyFunctions∷Print(“FailedFlowTest1”,Functions∷GetDUTID());return;default:return;}}elseif(flowItermName==“FlowMain_4”){//...}elseif(flowItemName==“FlowMain_5”){//...}}};FlowItem∷execute()操作知道流项的名字。在返回指向下一流的指针之前,它将对所包含的流调用IuserCalls∷exec(),传递其自己的流项名字和当前结果的值。这将使以上代码执行,调用所需的用户定义函数。C9.测试程序编译[333]如上面所解释的,测试计划描述文件指定测试计划中所使用的对象及其彼此的关系。在一种实施方式中,这个文件翻译成将在站点控制器上执行的形式为标准接口ITestPlan实现的C++代码。这种代码将包装到可以加载到站点控制器上的Windows动态链接库(DLL)中。生成的测试程序DLL具有站点控制器软件可以用于生成并返回它所包含的TestPlan对象的标准已知输入点。从测试计划描述构造[334]从测试计划描述到ITestPlan实现的转换处理是由测试程序编译器400实现的。这个处理发生在两个阶段翻译与编译。在翻译阶段402,编译器400处理测试计划文件(及它导入的各种其它文件)及测试计划中所使用的所有测试类型的pre-header。在这个阶段,它创建测试计划对象的C++代码和所遇到的测试类型的C++头,及所有其它支持的文件,例如MSVC++(微软的VisualC++)工作区和项目文件、DLL“boilerplate”代码等。编译器400将文件和行伪指令插入到所生成的代码中,以确保编译时错误消息指回描述文件中适当的位置,而不是指向所生成的代码。在发生在编译器创建必需文件之后的编译阶段,调用例如MSVC++编译器的标准编译器404来编译文件并将它们链接到DLL中。编译器取有效测试计划文件(和所有相关的文件)作为输入并根据需要生成TestPlan文件和由测试计划文件中“Import”伪指令表示的所有其它文件。此外,它生成MSVC++“解决方案”来建立测试计划DLL。例如,如果主文件(MyTestPlan.tpl)包括要结合定时信息的Timingl.tim,则除了别的以外,编译器还将创建以下文件MyTestPlan.hMyTestPlan.cppTiming1.cppMyTestPlan.sln(MSVC++“解决方案”文件)MyTestPlan.vcprpj(MSVC++“项目”文件)[338]在所有文件都创建(或更新)之后,编译器调用MSVC++“解决方案”应用,指定它所创建的“解决方案”并创建DLL。任何错误和/或警告都将显示给用户。在建立测试计划后,如果用户对Timing1.tim进行修改,则用户将调用编译器,向其传递MyTestPlan.tpl。编译器将(通过时间戳信息)识别出主测试计划未改变,因此MyTestPlan.h/.cpp将不再重新创建。但是,在处理主测试计划文件的同时,将看到Timing1.tim改变了。因此,将重新创建Timing1.cpp文件,并调用MSVC++应用重新建立DLL。这避免了重新编译MyTestPlan.cpp,而只编译Timing1.cpp并重新链接DLL。对于需要相当大量的时间进行编译的大测试计划,这种方法对于缩减重新编译和重新链接时间是非常有用的。D.运行测试程序[340]站点控制器软件将测试程序DLL加载到其处理空间中并调用DLL中的“工厂”函数来创建测试计划对象的实例。一旦测试计划对象已经创建,站点控制器软件就可以执行测试计划或者以任何其它必要的方式与其交互。非交互式建立[341]对于Windows环境中的大部分C++软件开发人员,建立应用(或DLL,或库,等等)意味着提供开发环境(微软VisualC++、BorlandC++,或类似的其它环境)、编辑代码及(常常是)按下按钮来建立产品。本发明实施方式的测试环境将具有类似的动作集合。测试计划开发人员将需要编辑代码并建立他们的测试计划。但是,测试器不需要测试计划开发人员为了生产结果测试计划DLL而提出C++开发环境。为了实现这个目的,本发明采用非交互式建立的概念。非交互式建立定义为以非交互模式使用MSVisualC++的建立。应当注意,这仍然允许其它工具交互式地用于管理这种建立。唯一的含意是VisualC++是非交互式使用的。假设的环境[344]关于用户环境,进行特定的假设。这些假设是1.测试计划开发人员将根据以上方法与规则开发他的测试计划。2.测试计划开发人员可能不具有对C++的专家级知识。3.测试计划开发人员将能够访问将文件转换成测试计划DLL的命令行工具或GUI工具。不用按钮建立应用[345]利用MSVisualStudio非交互式地工作需要两种方法中的一种。第一种(最简单的一种)是使用命令行接口。第二种(更灵活的一种)是使用自动化接口。这部分描述这两种方法。创建项目[346]为了非交互式地使用MSVisualStudio,应当以包含一个或多个有效项目的工作解决方案开始。不幸的是,这是一个不能从命令行或自动化方法实现的任务。任何一种方法都不能提供用于项目创建的机制。但是,用于VisualStudio的项目与解决方案可以从模板创建。因此,给定开始的项目名和模板,我们就可以为VisualStudio创建解决方案/项目。构造项目[347]由于命令行不支持,因此向产生的项目添加新文件使用VisualStudio自动化模型。我们提供两种VisualStudio宏来向项目添加新的和现有文件。类似的代码可以由使用ActiveScript引擎的外部脚本(例如VBScript、JScript、ActivePerl、ActivePython等)用于执行相同的任务。因此,我们的代码生成工具可以创建新的文件并利用自动化模型将它们添加到现有的VisualStudio项目中。在文件创建之后,它们可以由工具根据需要更新。建立项目[348]一旦我们在适当的位置有了解决方案和项目,就有了利用VisualStudio非交互式地建立测试计划的几种选项。最简单的选项是从命令行调用它。这种命令行看起来象devenvsolutionFile/buildsolutionCfg其中solutionFile是VisualStudio文件而solutionCfg是可用于解决方案中的项目的特定配置。另一解决方案是使用自动化的VisualStudio对象模型。这允许对建立与配置处理的更细粒度的控制。如上面所提到的,它包含从命令行建立项目的Perl脚本列表。这个程序读取指定要建立的项目与配置的配置文件(及其它关于项目的信息)并利用自动化模型建立它们。看这个脚本中$msdev对象的使用,作为脚本中如何使用自动化对象的例子。调试器支持[349]为了让Test类的开发人员验证并调试他们的工作,他们需要访问允许他们进入站点控制器并单步调试他们的代码的调试器。由于编译器生成的代码是由MSVC++编译的C++,因此我们使用MSVC++调试器来调试Test类的实现。应当注意,这个特征只对Test类开发人员或其它直接在C++中工作的人员有意义。其它机制将提供给希望调试或单步调试Test程序运行而不直接参考所生成的C++代码的测试工程师。系统软件环境[350]这部分描述用于测试器的通用软件环境用户测试计划所需文件的位置,指定这种文件可选位置的机制及用于指定测试计划和模块控制软件位置的方法。测试计划所需的环境[351]系统标准位置及测试计划所需的用于1.模式列表,2.模式,3.定时数据,及4.测试类DLL的搜索路径的运行时配置可以由“environment”变量配置并由环境配置文件指定。这些是文本文件,具有如下的简单语法TesterPATOBJPATH=“patterrns\data;D:\projects\SC23\patterns\data”[352]在文本文件中定义这种“environment”变量而不是通过本地OS支持的环境变量定义的优点是实现不受OS支持环境变量所具有的共同约束的限制,例如最大字符串长度等。以下“environment”(设置)变量将用于以上列出的实体·模式列表Tester_PATLIST_PATH.·模式目标文件Tester_PATOBJ_PATH.·模式源文件Tester_PATSRC_PATH(这是可选的;请看).·定时数据文件Tester_TIMING_PATH.·测试类DLLTester_TEST_CLASS_LIBPATH.为了支持特定的情况,在维持有用缺省特性的同时,我们提供三级配置。这以递增的优先次序描述首先,系统环境设置文件,$Tester_INSTALLATION_ROOT\cfgsetups\Setup.env,将指定“environment”变量的缺省值。如果没有其它的配置机制可用,则将需要这个文件。总的来说,它对运行在系统上的所有测试计划可用。这个文件是由安装与配置管理(ICM)系统在安装过程中创建的,其中自安装程序的输入指定上面提到的三个变量缺省值。(应当注意,如在以下子部分中所描述的,除了用于以上三个变量的系统缺省值,这个文件还将包含用于特定的其它测试器“environment”变量的系统缺省值)。其次,环境设置文件可以由用户作为对测试计划的运行时参数指定。这个运行时配置中的变量将比缺省定义优先。最后,测试计划可以使用特定的块来指定其执行中要使用的环境变量。在测试计划中定义的变量比系统文件或用户定义文件中的那些变量优先。总的来说,所有必需的变量都应当通过上述一种机制定义。如果变量没有定义,则会发生运行时错误。其它环境设置[358]除了用户测试计划所需的“environment”变量,以下两个“environment”变量也是测试环境所需的1.TesterTESTPLANLIBPATH这指定系统控制器用于查找应当加载的测试计划DLL的搜索路径。应当注意,相同的搜索路径也将用于查找用户引脚描述和套接字文件。在安装时指定给ICM的这个变量的缺省值由ICM存储在文件$Tester_INSTALLATION_ROOT\cfgsetups\Setup.env中。2.Tester_MODULE_LIBPATH这指定系统将用于加载厂家提供的硬件模块控制软件DLL的搜索路径。从配置管理数据库(CMD)提取的这个信息也由ICM存储在文件$TesterINSTALLATION_ROOT\cfgsetups\Setup.env中。应当注意,尽管用户可以覆盖Setup.env文件中对Tester_TEST_PLAN_LIBPATH变量给出的值,但Setup.env文件中对Tester_TEST_PLAN_LIBPATH变量给出的值不应当由用户改变,除非用户想显式改变用于厂家提供的硬件模块控制软件DLL的搜索路径。搜索路径说明语义[360]关于指定搜索路径的“environment”变量,应当注意以下要点1.每个都应当是系统将要搜索的由分号(“;”)隔开的目录名列表,以便找到特定类型的引用文件。2.在最初系统查找这种“environment”变量的值以后,由用户对其值进行的任何改变(例如,通过编辑环境配置文件)都将只在用户显式“通知”系统需要这么做的时候由系统注册。3.当关于“当前工作目录”(CWD)的路径可能导致不确定结果时,由于分布式环境中CWD的概念-例如其中测试器工作的环境-可能不是用户直观期望的概念,因此搜索路径中的相对路径名将解释为相关环境变量(提供定义根的功能性)的特定设置。指定搜索路径中所有相关路径名都将被假设与之相关的根的这个相关环境变量是“Tester_INSTALLATION_ROOT”变量,该变量给出用户系统上测试器安装的顶级(即,“根”)目录的位置。4.目录条目不能包含集合[V:*?<>|;]中的字符,应当注意除了分号(“;”)例外,这个集合中所有其它字符在Windows文件名中都是非法的。因为分号(“;”)用于区分搜索路径中的条目,所以它不应当用在搜索路径条目中。应当注意,路径名可以具有嵌入的空格,但紧挨着路径名前后出现(即,在路径名的第一个非空格字符之前和最后一个非空格字符之后)的所有空格都不看作是路径名的一部分并将被忽略。5.搜索路径目录将以它们在定义中所遇到的次序搜索。文件的第一次出现将是被选择的那个。E.测试模式[361]有效的管理、处理、和加载非常大的测试模式集合是本发明一个实施方式框架的重要体系结构方面。层次模式列表的思想被看作是向终端用户提供易处理概念及容易使用的系统的有效工具。通过测试向量使对DUT的刺激对测试系统可用。向量通常可以分类为顺序的(或线性的)、扫描或算法模式生成器(APG)导出的。在本发明一个实施方式的系统中,测试向量根据在测试时应用到DUT的模式组织。模式是由用户测试程序中的Pattern对象表示的。在该系统中,模式组织为模式列表,由模式列表对象以程序方式表示。模式列表对象表示模式的有序列表或其它模式列表。排序隐含在列表组件的声明次序中。应当注意,如果需要单个模式,则需要由它自己封装在列表中。用户测试程序中的模式列表对象与磁盘上的模式列表文件关联,该文件包含模式列表的实际定义。因此,模式列表的内容是由相关磁盘文件的内容动态确定的(关于这个,随后将描述)。模式列表的定义提供了模式列表的显式名称并通过文件名关联来识别模式的有序列表和/或其它模式列表。它还提供执行选项的说明,由于选项可以应用到模式列表和模式,因此这将在描述模式对象后具体描述。模式列表应当遵循以下规则file-contents:version-infoglobal-pattern-list-definitionsversion-info:Versionversion-identifier;global-pattern-list-definitions:global-pattern-list-definitionglobal-pattern-list-definitionsglobal-pattern-list-definitionglobal-pattern-list-definition:global-pattern-list-declaration{list-block}global-pattern-list-declaration:GlobaIPListpattern-list-nameoptionsoptlist-block:list-entrylist-blocklist-entrylist-entry:pattern-entry;pattern-list-entry;global-pattern-list-definition;local-pattern-list-definition;pattern-entry:Patpattern-nameoptionsoptpattern-list-entry:PListpattern-list-referenceoptionsoptpattern-list-reference:pattern-list-qualified-namefile-name’:’pattern-list-qualified-namepattern-list-qualified-name:pattern-list-namepattern-list-qualified-name′.′pattern-list-namelocal-pattern-list-definition:local-pattern-list-declaration{list-block]local-pattern-list-declaration:LocalPListpattern-list-nameoptionsoptoptions:optionoptionsoptionoption:option-definition:option-nameoption-parametersoptoption-parameters:option-parameteroption-parameters‘,’option-parameter[365]以下是以上所使用未定义非终止符的描述1.version-identifier选自集合的一个或多个字符的序列,其中第一个字符必须是数字。2.name选自集合[a-zA-Z_0-9]的一个或多个字符的序列,其中第一个字符必须选自集合[a-zA-Z_]。3.pattern-list-name选自集合[a-zA-Z_0-9]的一个或多个字符的序列,其中第一个字符必须选自集合[a-zA-Z]。4.file-name有效Windows文件名(如果文件名中包含任何空格,则必须包含在双引号中)。应当注意,这应当是简单的文件名,即,它不应当有目录成分。pattern-list-reference可以是内部的,指向相同文件中的模式列表,或者外部的,指向其它文件。外部引用需要由file-name限定。5.option-name选自集合[a-zA-Z_0-9]的一个或多个字符的序列,其中第一个字符必须选自集合[a-zA-Z]。6.option-parameter选自集合[a-zA-Z0-9]的一个或多个字符的序列。模式列表文件支持注释,这意味着可以由模式列表文件解析器忽略。注释以“#”字符开始,并延伸到一行的结束。E1.模式列表的规则[367]用于模式列表的静态或编译时规则管理名字的声明与分解。模式列表语言中的名字由global-pattern-list-definition和local-pattern-list-definition声明。它们由pattern-list-reference引用。以下是管理这些声明与引用的一些规则。1.global-pattern-list-definition和local-pattern-list-definition声明模式列表的名字。pattern-list-reference引用所声明模式列表的名字。全局模式列表的名字是全局已知的。局部模式列表的名字只在它们被声明的列表块中已知。它们可以无需限定地在该列表块中直接引用。在更深的嵌套声明中,局部模式列表将需要由限定的名字引用。2.局部模式列表名在所包含的模式列表范围内已知,而全局模式列表在系统范围内已知。例如GlobalPListG1{LocalPListL1{LocalPListL2{}...GlobalPListG2{}...PListL2;#OK.NameL2isknowninthisscopePListG2#OK.NameG2isglobal}PListL2;#Error.NameL2isnotknownhere.PListL1.L2;#OK.NameL1isknownhere.L2isknownby#qualification.PListG1.L1.L2;#OK.QualificationbyG1isnotneededbut#isallowed.PListG2;#OK.NameG2isglobal}3.全局模式列表可以是模式列表文件的最外面一级定义,或者在所包含的模式列表中嵌套定义。但嵌套仅仅是为了方便。它们在概念上定义为文件最外面一级的全局模式列表。嵌套的全局模式列表在语义上等于相同名字的最外面(非嵌套)全局模式列表。因此,例如GlobalPListG1{GlobalPListG2...}在语义上等同于GlobalPListG1{PListG2;#ReferencesG2}GlobalPListG2...4.所有全局模式列表都是唯一命名的。GlobalPListG1{#Notethatthisisasifdeclaredattheoutermostlevel#withareferencetoitrighhthere.GlobalPListG2{...}}#Thisdeclarationwillbeanerrorinthisoranyotherfile,#asthenameG2isalreadytaken.GlobalPListG2#Error.GlobalnameG2istaken.{…}5.局部模式列表总是在还定义局部模式列表名字范围的包含模式列表中嵌套定义。局部模式列表在其被包含的模式列表中唯一命名。局部模式列表在语义上不允许出现在模式列表文件的最外面一级。GlobalPListG1{LocalPListL1{}LocalPListL2{LocalPListL1#OK.NolocalnameL1isdeclareddirectly#intheenclosingscopedefinedbyL2.{}PListL1;#OK.ReferstoL1declaredinL2PListG1.L1;#OK.ReferstoL1declaredinG1.}#Error.RedeclaringnameL1whentheenclosingscope#definedbyG1alreadyhasanL1declaredinit.LocalPListL1;{}6.每个模式列表文件都包含用于一个或多个全局模式列表的定义。这直接遵循语法。最外面一级是global-pattern-list-definition,而且必须至少有一个。7.pattern-name是对模式的引用,在Pat关键字之后。它引用其名字通过将后缀.pat连接到模式名而获得的模式文件中的模式。该文件指示将与为模式定义的搜索路径一起获得的文件。8.pattern-list-reference是对PList关键字之后的模式列表的引用。该引用包括可选文件名,后面跟着只是由点隔开的名字列表的限定模式列表名。因此,例如,以下可以是pattern-list-referencePlistfoo.plist:G1.L1.L2.L3;其引用文件foo.plist中的全局模式列表G1中所嵌套的L1中所嵌套的L2中所嵌套的局部模式列表L3。以上名字中最左边的名字段是G1。最左边的名字段必须分解成全局模式列表或者可以从引用点看到的局部模式列表。pattern-list-reference的名字分解如下进行1.每个名字段都分解成在其前面的前缀上下文中声明的名字。2.如果有文件限定,则最左边的名字段分解成在所命名文件中声明的全局模式列表。3.如果没有文件限定,则最左边的名字可以分解成所包含范围内的局部模式,而且如果失败,则利用下一包含的范围,等等,直到所包含的全局范围。4.为了保持全局范围的语义,就象它们在模式列表文件的最外面一级声明的一样,需要将范围的搜索限定到最靠近的包含全局范围。如果嵌套的全局范围是在最外面一级(等效)文本声明的,则名字分解搜索将在检查其范围后终止。5.如果引用未能由前面的步骤分解,则最左边的名字段可以分解成该相同文件中的全局模式列表。6.如果引用未能由前面的步骤分解,则最左边的名字段可以分解成通过将.plist后缀添加到最左边名字段所获得的文件中指定的全局模式列表。7.如果引用未能由前面的步骤分解,则引用是错误的。如前面所提到的,以上规则指示最左边的名字段分解成可以从引用点看到的局部模式列表或者分解成全局模式列表。以下例子说明了这些思想中的一些。GlobalPlistG1{PListG3;#OK.Referstoapattemlistlaterinthisfile.PListG4;#OK.Referstoapatternlistinfile“G4.plist”#OK.ReferstoG1inthefile“my_plists.plist”.PListmy_plists.plist:G1;#OK.Referstoapatternlistinfile“my_plists.plist”.The#qualifiednamereferstoalocalpatternlistnamedL2declared#inthescopcofalocalpatternlistnamedL1declaredinthe#scopeofaglobalpatternlistnamedG1.PListmyplists.plist:G1.L1.L2;LocalPListL1{LocalPListL2{}}PListL1;#OK.ReferstoL1declaredinthe#enclosingscopeofG1}GlobalPlistG2{LocalPListL2{}GlobalPListG3{LocalPListL3{}PListL1;#Error.NoL1declarcdinthisoranyerclosing#scope;#Error.ThenameL2isnotdeclaredinthisscope.Also#thoughL2isdeclaredintheenclosingscope,thisscope#isglobal,andsonofurtherenclosingscopeisexamined.##ContrastwithreferencetonameL2inLocalPListL3below.PListL2;PListG1.L1;#OK.ReferstoL1inG1.#Error.G3isnotreallynestedinsidcG1.SinceG3#isglobal,itisreallydeclaredatanoutermostlevel,#andsoG1.G3ismeaningless.PListG2.G3.L3;}LocalPListL3{#OK.ReferstoG2.L2.TheetclosingglobalscopeisG2#andthenameL2isdeclaredinG2.PListL2;}}所有模式列表文件名与模式文件名都要求在利用它们的整个测试计划中是唯一的。模式列表引用可以指在相同文件中在引用前或引用后定义的模式列表。递归与互相递归的模式列表定义是不允许的。尽管在模式列表文件语法中没有什么可以防止用户创建这种定义,但解析器在检测到这种状况时会标记错误。应当注意,有一些成本与这种状态的检测关联。如果用户可以承担保证输入空间没有互相递归定义的责任,则他/她将可以关掉该检查。GlobalPListG1{LocalPListL2{LocalPListL3{#Error.L2runsL3whichrunsL2.#ThisisarecursivereferencetoL2PListL2;PListG2;}}}GlobalPListG2{#Error.G1.L2runsL3whichrunsG2whichrunsG1.L2.#ThisisamutuallyrecursivereferencetoG1.L2.PListG1.L2;}[375]模式与模式列表的语法描述允许对其指定选项。通常,选项是厂家特定的。该语法允许任何模式或模式列表具有多个指定的选项,每个选项具有多个参数。我们描述由大部分厂家识别的一些支持选项。模式树的动态(即,执行)语义是在定义模式执行序列之后描述的。E2.模式[377]图6说明了根据本发明实施方式的模式编译器602和模式加载器604。模式的用户定义内容在纯文本文件的模式源文件606中可以获得。模式编译器将负责将源文件编译成适用加载到测试器硬件上的特定于模块的格式;该后一种文件称为模式目标文件。以下是通用的属性1.模式对象是不可以由用户创建的;而用户总是处理模式列表,模式列表是其它模式列表和/或模式的集合。模式列表对象创建、拥有并维护包含在其中的模式对象,同时如果必要则使它们可以由用户访问。2.模式是在测试计划中唯一命名的,即,测试计划中没有两个模式有相同的名字。模式的名字不同于包含它的文件名。模式文件名是用在模式列表文件中用于指示模式的名字,而模式的实际名字在模式文件中定义。总的来说,在本发明的一个实施方式中,单个DUT(被测试的设备)可以连接到来自不同厂家的测试器模块。这包括整个模式编译-加载-执行链。主要部分在这部分描述。E3.模式编译[379]因此,模式编译器602需要瞄准特定的站点配置(关于所使用的特定于厂家的数字模块)。对于剩余的这部分讨论,作为例子,术语“模块”将用于指数字模块。为了允许将来自不同厂家的模块608集成到系统中,以下过程是优选的1.每个模块厂家将负责以动态加载库或独立可执行程序的形式,提供其自己的特定于模块的模式编译器610。这种编译器库/可执行程序将至少提供compile()方法。2.模式源文件将对其所包含的每种类型的模式块提供两种不同类型的部分a)将包含所有编译器都可访问(但不一定使用)的信息的“公共”部分,及b)一个或多个可选的特定于厂家的部分,每个部分由唯一的厂家代码识别,用于可以由特定厂家的编译器所使用的信息。3.厂家的编译器将不直接创建模式目标文件。相反,测试器将提供由目标文件管理器(OFM)614管理的模式目标“元文件”612,其中OFM614是模式编译器的一部分。模式编译器可以位于充当系统控制器的计算机上,或者是离线的,例如在系统控制器连接到的网络上。到目前为止以抽象术语指的“模式目标文件”实际是这个目标元文件。目标元文件将与模式源文件的名字相同,源文件的扩展名由目标文件扩展名代替。OFM将提供读写这个文件的应用编程接口(API)。目标元文件将具有用于存储以下内容的条款a)公共的头信息,b)特定于模块的头信息,包括识别对应的模块和用于该模块的模式数据的位置,c)特定于模块的模式数据,根据需要由模块厂家组织并能够由模块厂家解释。OFMAPI将允许模块厂家的编译器将特定于模块的头信息和数据写到目标元文件中。应当注意,即使在目标站点中两个或多个模块完全相同的情况下,目标元文件的这种布局也允许模式数据以每个模块为基础组织。应当注意,模式编译器也可能需要其它的厂家支持的配置信息来方便特定于模块的硬件加载信息的生成,其中该生成可以利用如直接存储器存取(DMA)的有效数据通信。E4.目标文件管理器(OFM)框架[382]开放体系结构的测试系统提供可缩放与灵活的解决方案。在本发明的一种实施方式的开放体系结构的测试系统中,单个被测试的设备(DUT)可以连接到来自不同厂家的测试器模块。这种环境下的测试模块指该开放体系结构的测试系统中的功能性单元,而且可以包括硬件和软件组件。这种实施方式的分布式、可重新配置的模块化开放体系结构的测试系统在此也称为测试系统或系统。测试系统的用户写用于测试DUT的模式,可能不需要知道这种模式将利用由不同硬件厂家开发的多种测试器模块进行编译。这假定这些模块中的每一个都能够提供该模式中特定的特征,而且特定于厂家的模式格式可以包括在该模式文件中。通过测试向量使对DUT的刺激对测试系统可用。测试系统框架中的测试向量根据测试过程中施加到DUT的模式组织。模式由用户测试程序中的模式对象表示。以下段落引入测试系统的OFM框架的一些关键术语。模式块对象表示给定类型的(循环或非循环)模式数据的集合,该给定类型对于模式块中模式数据的描述共享公共的语法。在一种实施方式中,所支持模式块的类型是循环模式块(例如,MainPattern、SubPattern、算法模式生成器模式(ALPGPattern))和由模式源中的类型(例如,pattern[type])所识别的非循环模式类型。SubPattern和ALPGPattern块是辅助模式目标元文件的示例块。模式块可以提供两种不同类型的部分1)包含所有编译器都可以访问(但不一定必须使用)的信息的公共部分,及2)一个或多个可选的特定于厂家的部分,每个特定于厂家的部分由唯一的厂家代码识别,用于存储由厂家编译器可以使用的信息。模式对象表示模式块的集合,但具有这样的限制条件模式对象中没有两个块是相同类型。循环模式块表示用在顺序循环数字测试器中的测试向量的集合,其中测试器提供厂家要遵循的标准语法。模式源文件可以容纳一个或多个模式块。图13说明了根据本发明一种实施方式用于管理模块化测试系统中的模式目标文件的OFM框架。该OFM框架包括厂家编译器接口(IVendorCompiler)1302、厂家模式编译器接口(IVendorPatCompiler)1303及厂家循环模式编译器接口(IVendorCyclizedPatCompiler)1304。模块厂家负责提供他们自己的模式编译器,其中这些模式编译器实现IvendorPatCompiler接口1303或IvendorCyclizedPatCompiler接口1304或两者都实现。该OFM框架还包括OFM模块代理(OFMModuleAgent)类1306、OFM循环模式模块代理(POFCyclizedModuleAgent)类1308、OFM标签读取器(OFMLabelReader)类1310、目标文件管理器(OFMManager)类1312及模式目标元文件(PattemObjMetaFile)类1314。用于处理非循环模式块的第一厂家模式编译器(ATRFPatCom)类1316和用于处理循环模式块的第二厂家模式编译器(ATDM250PatCom)类1318是分别实现IvendorPatCompiler1303和IvendorCyclizedPatCompiler1304的厂家提供的类的例子。以下提供接口和类的描述。IvendorPatCompiler接口[387]IvendorPatCompiler接口1303支持两组功能。第一组功能支持模式源文件中非循环模式块的编译和利用模块数据对模式目标元文件的更新。第二组功能支持模式目标元文件的公共块部分的更新。如果厂家编译器匹配模块配置文件中的模块类型ID集合并支持块类型,则OFM调用一组模式编译方法。模式编译方法是被调用来使得厂家编译器将编译过的模式对象数据存储到用于对应模块模式加载器的元文件中。以下描述第一组模式编译方法。·compile():compile()方法是由OFM调用的,以便编译模式源文件。OFM向厂家编译器传递POFCyclizedModuleAgent对象。这个对象提供了保护/访问控制,使得厂家编译器有权对模式源文件公共部分和特定于模块的部分的读访问及对特定于厂家模块的部分的写访问。OFMResourcePinMapper实例也作为参数传递到厂家编译器,以便提供关于引脚与资源之间映射的信息。·needsPinNames():needsPinNames()方法由OFM调用,以便查询模块编译器当调用compile()方法时是否需求提供引脚名列表。·getSupportedResources():getSupportedResources()方法由OFM调用,以便查询模块编译器所支持的资源的名字。这在厂家编译器需要一个引脚列表以便在“每个资源”的级别进行模式编译处理时,用于创建引脚列表。·release():release()方法由OFM调用,以便允许厂家模式编译器在删除导出的IvendorPatCompiler对象之前执行清除操作。·getErrorList():getErrorList()方法由OFM调用,以便检索OFCStatus对象的阵列。这个阵列包含在模式源编译过程中模式编译器可能遇到的错误及警告。OFCStatus是包含关于错误的信息的实体。它可以是整数值的简单形式,表示特定的错误代码。当错误发生时,使OFCStatus成为带包括错误代码的信息及关于错误的特定实例的某种特定数据的对象是有用的。OFM使用IvendorPatCompiler接口1303的“getter”方法来查询厂家编译器以获得公共部分的各种设置。厂家编译器的责任是从所编译的模式源文件提供关于公共部分设置的细节。以下描述用于编译模式源文件的公共部分方法。·getPinRef())如果目标文件管理器需要厂家模式编译器解析模式源文件并向OFM提供引脚引用设置文件的名字,则调用getPinRef()。·getSubReference()如果目标文件管理器需要厂家模式编译器解析模式源文件并向OFM提供由这个模式源文件引用的子例程的阵列,则调用getSubReference()。·getSynchronizedNameArray()如果目标文件管理器需要厂家模式编译器解析模式源文件并向OFM提供存在于这个模式源文件中的同步块的阵列,则它调用getSynchronizedNameArray()。OFM框架使用这些(在引脚描述文件中声明的)名字配合这些块的执行。IVendorCyclizedPatCompiler接口[390]IVendorCyclizedPatCompiler接口1304继承自IVendorCompiler接口1302。它也需要模块厂家支持两组功能。第一组功能支持模式源文件中循环模式块的编译并更新模式目标元文件。第二组功能支持模式目标元文件的公共块部分的更新。如果厂家编译器匹配模块配置文件中的模块类型ID集合并支持该块类型,则OFM调用模式编译方法。该方法的调用使厂家编译器将编译过的模式对象数据存储到用于对应模块模式加载器的元文件中。以下描述第一组模式编译方法。compile()方法由OFM调用,以便编译模式源块。OFM向厂家编译器传递POFCyclizedModuleAgent对象。这个对象提供了保护/访问控制,使得厂家编译器有权对公共部分和模块部分读访问及对模块部分写访问。OFMResourcePinMapper实例也作为参数传递到厂家编译器,以便提供关于引脚与资源之间映射的信息。OFM使用IVendorCyclizedPatCompiler接口1304的“getter”方法来查询厂家编译器以获得公共部分的各种(特定于循环测试器的)设置。厂家编译器负责提供所编译的模式源文件的细节。以下描述用于编译模式源文件的公共部分方法。·getALPGReference()如果OFM需要厂家模式编译器解析模式源文件并向OFM提供在模式源文件中引用的ALPG模式列表,则它调用getALPGReference()方法。·getDomainList()如果OFM需要厂家模式编译器解析模式源文件并向OFM提供由该模式所使用的域列表,则它调用getDomainList()方法。应当注意,由于模式可能不用于设备的所有域,因此这个域列表可以是在引脚描述文件中指定的域列表的子集。·getLabelList()如果OFM需要厂家模式编译器解析模式源文件并向OFM提供模式源中用于给定域的标记列表,则它调用getLableList()方法。应当注意,标记具有域中的访问,并且相同的标记可以用在多个域中。·getLabelOpcodeOffset()如果OFM需要厂家模式编译器解析模式源文件并向OFM提供用于给定域中的标记的Opcode偏移,则OFM调用getLableOpcodeOffset()方法。·getLabelOperandOffet()如果OFM需要厂家模式编译器解析模式源文件并向OFM提供用于给定域中标记的Operand偏移,则OFM调用getLabelOperandOffet()方法。·getPXRSetupFileRef()如果OFM需要厂家模式编译器解析模式源文件并向OFM提供所导入的模式交叉引用设置文件的名字,则OFM调用getPXRSetupFileRef()方法。·getCyclizedPatternType()如果OFM需要厂家模式编译器解析模式源文件并向OFM提供所指定的循环模式块的类型(SQPG、ALPG、SUBR、SCAN、ESCAN),则OFM调用getCyclizedPatternType()方法。·getAMAX()如果OFM需要厂家模式编译器解析模式源文件并向OFM提供属于公共部分的最大地址大小,则OFM调用getAMAX()方法。OFMModuleAgent[394]OFMModuleAgent1306是可以由POFCyclizedModuleAgent类扩展的基类。这个类提供访问每个模块的二进制不透明数据所需的方法组的实现。OFMModuleAgent类1306包括以下方法。·flush()如果缓冲的二进制数据需要转储(flush),则厂家编译器调用flush()方法。·position()厂家编译器调用position()方法来确定模式块中二进制数据的当前位置。·preAllocate()如果厂家编译器需要OFM给模式目标元文件中的块预先分配给定大小以提高效率,则厂家编译器调用preAllocate()。为二进制块分配的缺省大小是0×4000。·getSize()如果厂家编译器需要OFM查询元文件以确定模块的二进制数据的大小,则厂家编译器调用getSize()。POFCyclizedModuleAgent[395]POFCyclizedModuleAgent类1308是对当OFM开始编译模式时由OFM打开的PatternObjMetaFile类1314的浅句柄。它利用特定于循环测试器模块的附加方法来扩展OFMModuleAgent。通过允许它们既从公共部分又从模块部分读取,它向厂家模式编译器提供对模式目标元文件的有限访问。它还提供对厂家编译器模块部分的写访问。这个接口是由厂家模式编译器在OFM调用compile()方法时编译模式的过程中所使用的。POFCyclizedModuleAgent类1308包括以下方法。·getALPGRefList()如果厂家编译器需要OFM提供在这个模式源中引用的ALPG模式的阵列,则它调用getALPGRefList()方法。·getDomainList()如果厂家编译器需要OFM提供由模式使用的域阵列,则它调用getDomainList()方法。应当注意,由于模式可能不会用于设备的所有域,因此域阵列可以是在引脚描述文件中指定的域阵列的子集。·getLabelList()如果厂家编译器需要OFM提供在给定域的模式源中所使用的标签阵列,则它调用getLabelList()方法。应当注意,标签具有域中的范围并且相同的标签可以用在多个域中。·getLabelOpcodeOffset()如果厂家编译器需要OFM提供给定域中标签的Opcode偏移,则它调用getLabelOpcodeOffset()方法。·getLabelOperandOffset()如果厂家编译器需要OFM提供给定域中标签的Operand偏移,则它调用getLabelOperandOffset()方法。·getPXRSetupFileRef()如果厂家编译器需要OFM提供所导入的模式交叉引用设置文件的名字,则它调用getPXRSetupFileRef()方法。·getTimingRef()如果厂家编译器需要OFM提供实现ITimFile接口的对象,则它调用getTimingRef()方法。这个类向编译器提供对系统测试程序语言定时文件的设置的访问,而不需要解析这个文件。·getTimingMapRef()如果厂家编译器需要OFM提供实现ITMapFile接口的对象,则它调用getTimingMapRef()方法。这个类向编译器提供对测试系统定时映射文件的设置的访问,而不需要解析这个文件。·getCyclizedPatternType()如果厂家编译器需要OFM提供指定模式的类型(SQPG、ALPG、SUBR、SCAN、ESCAN),则它调用getCyclizedPatternType()方法。·getTMapResolutionChecksFlag()厂家编译器调用getTMapResolutionChecksFlag()方法查询测试系统变量TMAP_RESOLUTION_CHECKSS是否在系统环境配置文件中设置了。OFMLabelReader[396]当编译循环模式块时,厂家模式编译器需要访问子例程模式目标元文件和ALPG模式目标元文件的标记与偏移量。这种访问是由OFMLabelReader类13lO提供的。这个类以与POFCyclizedModuleAgent类类似的方式工作并提供逐个域对子例程和元文件的ALPG标签/偏移量的只读访问。厂家编译器可以对所引用的每个子例程/ALPG模式实例化这个对象并在任务完成后删除该对象。在这种实施方式中,这是特定于循环数字模块模式编译器的。OFMLabelReader类1310包括以下方法。·OFMLabelReader()厂家编译器调用OFMLabelReader()方法为特定的子例程或ALPG模式目标元文件构造OFMLabelReader对象。·open()厂家编译器调用open()方法来使OFMLabelReader对象打开文件。·close()厂家编译器调用close()方法来使OFMLabelReader对象关闭文件。·getLabelList()如果厂家编译器需要OFM得到用于OFMLabelReader实例的给定域的标签阵列,则它调用getLabelList()方法。·getLabelOpcodeOffset()如果厂家编译器需要OFM读出OFMLabelReader实例的给定域中标签的Opcode偏移量,则它调用getLabelOpcodeOffset()方法。·getLabelOperandOffset()如果厂家编译器需要OFM读出OFMLabelReader实例的给定域中标签的Operand偏移量,则它调用getLabelOperandOffset()方法。·getSourceVersion()如果厂家编译器需要OFM读出用于生成由该OFMLabelReader实例表示的子例程模式目标文件的源文件的版本,则它调用getSourceVersion()方法。在一种实施方式中,模式块是封装PatternBlock类型的最高级对象。在模式源文件中可以存在一个或多个模式块。每个模式块包含单个CommonSection和零或多个VendorSection(也称为模块部分)。OFM框架支持以下类型的模式块MainPattern、SubrPattern、ALPGPattern和Pattern。MainPattern、SubrPattern和ALPGPattern是用于处理循环模式的特定块。而通用的Pattern类型是可扩展的,以便允许OFM框架以透明方式启用其它的测试器模式语言。以下是模式源文件的例子。它包括用于循环数字模块的MainPattern及假定的通用模式(类型FOO)。应当注意,将循环和FOO类型的模式放到相同的源文件中的原因是循环的MainPattern块和FOO模式块有足够的接近相关性,因此它们可以作为单个实体一起使用。在这个例子中,假定模式FOO的CommonSection部分中的语法是已经对测试系统中所有FOO类型模式标准化的语法。在不存在标准的情况下,CommonSection可以为空。##Filenane:main1.pat(producesobjectfilemain1.pobj)#Vertion1.0;#----------------------------------------------------------------------#MainPattcrndefinition:#----------------------------------------------------------------------MainPattern{CommonSection{SdefineALL_H(H*}SdefineALL_L(L*}SdefineALL_0(0*}SdefineALL_1(1*}#------------------------------------------------------#TimingSpecifications#------------------------------------------------------Timing″productionTiming.tim:ProductionTiming″;#------------------------------------------------------#FinDescriptionfileSpecifications#------------------------------------------------------PinDescription″Pin.pin″;#------------------------------------------------------#SetupfileSpecifications#------------------------------------------------------Pxr″setup.pxr″;#------------------------------------------------------#DafaultDomainCycles#------------------------------------------------------Domaindefault{#----------------------------------------------#label:instruction{Vector/WaveformData}#----------------------------------------------NOP{V{DIR=1;APins=S{ALL_1};BPins-S{ALL_H};OE_=0;}1W{AllPins-wfs1;}}NOP{V{APins=S{ALL_0};BPins={ALL_L};}}NOP{V{APins=10000000;BPins=HLLLLLLL;}}NOP{V{APins=S{ALL_1};BPins=S(ALL_H};}}EXIT{V[APins=S{ALL_0};BPins=S{ALL_L};}}}}}#----------------------------------------------------------------------#FOOPatterndefinition:#----------------------------------------------------------------------PatternFOOCommonSection{NumberOfData=192;DataFormat{float;int;}Data{0.0E+00,1;5.21E+00,0;....;}}VendorSection1{Compression=ENABLED;}相同类型的多个实例是不允许的。这意味这只有MainPattern、SubrPattern和ALPGPattern块中的一个被看作相同的循环模式类型。由于它包括相同类型的两个模式块(循环),因此以下例子产生错误#--------------------------------------------------------#FiletwoCyclizedTypes.pat#--------------------------------------------------------Version1.0;##Thisisthemaincyclizedpatternblock#MainPattern{CommonSeotion{...}}##Thisisthesubroutinecyclizedpatternblock#SubrPattern{CommonSection(...}}[400]在Pattern的情况下,允许所声明类型的单个实例。对于其它不同的所声明类型,可以允许Pattern的多个实例。以下例子包括PatternFOO1和FOO2的两个实例和类型MainPattern的Pattern块实例。#--------------------------------------------------------#FilethreeTypes.pat#--------------------------------------------------------Version1.0;##Thisisthemaincyclizedpatternblock#MainPattern{CommonSection{...}}##ThisisapatternblockofgenerictypeFOO1#PatternFOO1(CommonSection{...}}##ThisisapatternblockofgenerictypeFOO2#PatternFOO2{CommonSection{...}}[401]CommonSection块包括针对测试系统标准化的模式类型的描述。这部分的内容遵循这种标准语法并以相似的方式由各种编译器解释。一种这样的标准的例子是对循环数字模块的MainPattern定义的语法。在测试系统中不存在用于这种类型的标准的情况下,定义空CommonSection。OFM框架允许每个模块编译器确定每个Pattern块中对应模块部分的内容。其它厂家编译器不具有访问在特定于厂家的Pattern块中建立的内容的许可。模式目标元文件[403]概述信息和其它公共的配置信息存储在模式目标元文件的主要公共头中。概述包括访问模式对象中各个模式块所需的信息。以下信息存储在主公共头中1.模式源文件名。2.来自源文件的版本信息。3.对在模式编译过程中要使用的套接字文件、实用配置文件和模块配置文件的引用。4.包含在模式目标元文件中的模式块类型的集合。每个模式块都有头部分,该头部分包括用于处理地址的预加载分解等或处理数据登录所需的信息。由于每个模式块的公共部分的语义对于特定的块类型基本上是相同的,因此每种编译器都能够提供相同的概述信息。因此,写元文件的第一编译器存储这种信息。以下信息存储在非循环块的公共部分头中1.在源文件中声明的模式类型。2.在模式源文件的公共部分中子例程引用的映射。3.如果对这种类型的模式块是需要的,则有对引脚设置文件的引用。4.在这种模式中定义的同步块的映射。这对应于利用系统引脚描述文件中的关键字Synchronized所定义的名字。以下信息存储在循环块的公共部分头中1.在源文件中声明的模式类型。2.在模式源文件的公共部分中子例程引用的映射。3.在该模式中定义的域块的映射。这对应于利用系统引脚描述文件中的关键字Domain所定义的名字。这些名字由OFM框架以与非循环模式的同步块相同的方式对待。4.用在模式源文件的公共部分中的波形和定时列表。5.对模式源文件公共部分中的向量opcode和operand地址的标签引用的映射。6.对模式源文件中指定的引脚、定时、定时映射和其它设置的引用。图14说明了模式目标元文件(PatternObjMetaFile)及其支持类之间的交互。PatternObjMetaFile类1402包括循环模式对象块(POFCyclizedCommonSection)类1416的实例及非循环模式对象块(POFCommonSection)类1408的零个或多个实例。模式目标元文件(PatternObjMetaFile)类1402封装了模式目标元文件的功能性并向OFM框架提供用于与元文件交互的API。POFCommonSection类1408封装了元文件中非循环模式对象的功能性。该类实现POF公共部分接口(IPOFCommonSection)141O。ObjMetaFile类1405向客户提供模式目标元文件的专有厂家部分。专有厂家模块部分封装在POFModule对象1412及其对应的POFBLOB对象1414中。每个POFModule对象与特定的厂家模块关联。单个厂家可以提供多于一个模块,因此在模式目标元文件中具有多于一个模块部分。POFCyclizedCommonSection类1416封装了基于循环的数字模式对象块的功能性。该类实现POF循环公共部分接口(IPOFCyclizedCommonSection)1418。因为它提供对为所有模式块类型提供的基于循环的公共部分数据和不基于循环的公共数据的访问,因此它与POFCommonSection类不同。OFM框架与厂家模块编译器之间的交互[409]在一种实施方式中,测试系统模式编译器瞄准特定的站点配置(关于所使用的特定于厂家的数字模块)。为了支持将来自不同厂家的模块集成到测试系统中,实现以下方法。1.厂家编译器不直接创建模式目标文件。相反,测试系统提供由OFM管理的模式目标元文件。术语模式目标元文件还指目标元文件。OFM框架管理公共模式数据到元文件中的存储,但依赖来自不同模块的插件调用特定于厂家的数据的编译。用于模式编译处理的模型可以如图6所示可视化。模式目标元文件具有与模式源文件相同的名字,其中源文件的扩展名被模式目标文件扩展名代替。OFM提供对这些文件进行读写的应用编程接口(API)。模式目标元文件具有用于存储以下内容的条款a)公共头信息,b)特定于模块的头信息,及c)特定于模块的模式数据,由模块厂家组织并能够由模块厂家解释。2.每个模块厂家都负责以可动态加载库的形式提供其自己的模式编译器。这个库提供检索由OFM框架定义的标准接口的完全实现的能力,例如IVendorPatComplier和IVendorCyclizedPatComplier或两者都有。提供IVendorPatComplier接口的功能是由以下库实现的OFCStatuscreateVendorPatCompiler(IvendorPatCompiler*&pCompiler,ConstOFCString&type);此外,提供IVendorCyclizedPatComplier接口的功能是由以下库实现的OFCStatuscreateVendorCyclizedPatCompiler(IvendorCyclizedPatCompiler*&pCompiler);在厂家不支持用于循环数字模式或用于特定通用模式类型的编译器的情况下,以上函数返回通知OFM框架不支持所请求编译器类型的预定义OFCStatus。3.OFM框架包括一组用于向厂家编译器提供对公共数据的访问的接口,这些数据是支持模式编译的任务所需要的。这包括对封装DUT引脚描述、DUT套接字与DUT定时的运行时对象的访问。它还包括用于访问例如模式子例程的其它所引用模式元文件的能力。4.OFM框架还包括一组用于使模块厂家编译器能将特定于模块的头信息和数据写到模式目标元文件的接口。应当注意,即使当目标站点中的两个或更多模块完全相同的时候,目标元文件的这种布局也使模式数据以每个模块为基础进行组织。上述方法使多个厂家可以继续使用他们专有的格式并使来自多个厂家的模块共同存在于开发体系结构的测试系统中。元文件特定于厂家的部分被看作“黑匣子”,OFM框架不需要具有关于它的特定知识,而且其它厂家也不需要访问它。在另一实施方式中,模式编译过程中厂家模块编译器与OFM框架的交互是以下述步骤的顺序说明的1.OFM框架实例化OFMManager的实例,来管理在SYSTEM模式编译器的命令行上指定的一个或多个模式的编译。2.OFMManager被实例化。这包括(以每个厂家和每个模块为基础)利用系统实用配置文件来注册所指定的所有模式编译器动态链接库(DLL)。系统实用配置文件指定特定系统配置的实用设置。这个文件包括为每个厂家的模块注册的模式编译DLL及共享库的名字。这种信息由OFM框架用于调用各种厂家编译器来编译模式源文件的对应部分。作为注册的一部分,查询每个DLL来找出所支持的模式块的类型。3.然后,OFMManager使用PatternObjectMetaFile类来保存整个模式源文件公用的数据。作为这个步骤的一部分,框架读取模式源文件来检索包括这个模式源文件的模式块的类型。所找到的模式块的各种类型存储在公共部分中。应当注意,框架区分两种类型的模式块-循环的和常规的(非循环的)。常规的模式块可以具有定义其类型的任何名字。不需要事先通知OFM框架这些名字,因此使系统具有开发的体系结构。4.对于包含在所编译模式源中的每种类型的模式块,OFMManager查询厂家模式编译器DLL来实例化实现IVendorPatCompiler接口的对象。在编译循环模式块的情况下,OFMManager查询DLL来实例化实现ICyclizedVendorPatCompiler接口(这是IVendorPatCompiler接口的子类型)的对象。5.对于在以上步骤4中获得的每个IVendorCompiler导出的对象,OFMManager调用getSupportedResource()方法来获得由这个模块支持的系统资源列表。该系统资源列表(与套接字文件和系统模块配置文件(MCF)一起)用于创建需要编译的资源集合。在厂家编译器为模式编译目的而需要具有这种列表的情况下,该系统资源列表还用于创建用于被测试设备(DUT)的引脚列表。应当注意,OFM框架不使其成为强制的,因为可能有所编译模式不以面向引脚的方式描述因而编译器不需要引脚列表的情况。在那种情况下,IVendorPatCompiler接口支持needsPinNames()方法来允许OFMManager找出特定的厂家编译器是否需要DUT引脚列表。6.OFMManager调用支持所编译模式块类型的每个IVendorPatCompiler接口的compile()方法。它对这个方法提供以下参数。a)在模式源中引用的资源类型列表,具有(可选地)用于每个这种资源类型的引脚名列表。在不需要引脚的情况下,该引脚列表为空。b)OFMModuleAgent(或用于循环模式的POFCyclizedModuleAgent)导出对象的实例,以便向厂家模式编译器提供对模式目标元文件特定的读写访问。7.在编译每个模式源块之后,OFMManager查询第一使用的编译器的公共部分数据,然后该数据用于更新模式目标元文件。8.然后,OFMManager向每个厂家模式编译器查询所遇到的错误/警告列表。这个错误/警告列表合并并提供给用户。9.步骤3和8对每个编译的模式源文件重复,并生成对应的模式目标元文件。10.最后,OFMManager释放在这个步骤序列的步骤2中注册的所有厂家模式编译器。这允许各种厂家编译器在编译处理退出之前进行清理。加载模式数据[412]在本发明一个实施方式的测试系统中,每个模块厂家负责提供其自己的特定模式加载机制。如上面所讨论的,模式目标元文件在不同的部分中存储特定于模块的数据。厂家实现利用系统应用编程接口(API)来访问来自模式目标元文件的相关部分。OFM框架又负责调用每个模块的加载模式方法来将来自元文件适当部分的特定于模块的数据加载到模块中。以下描述说明OFM框架与用于模式加载的厂家模块之间的交互的步骤序列。1.PatternMgr对象负责包括模式执行序列的模式集合的加载。这个对象实例化用于每个所加载的模式的PatternLoader实例。2.PatternLoader实例化用于所加载模式的PatternObjMeteFile类并向其查询模式目标元文件中模式块的类型列表。PatternLoader还向PatternObjMeteFile查询包含在每个模式块类型中的模块类型。3.然后,PatternLoader调用由厂家提供的对应导出IModule类的loadPattern()方法来加载用于每种类型的块与模块的模式数据。4.对应[Module接口的loadPattern()方法使用对PatternLoader类的传递引用。然后,它使用PatternLoader类的load()方法来访问PatternObjMeteFile类并从其读取特定于模块的数据,从而完成模式的加载。E5.模式文件[414]有可能使每个编译器厂家为模式指定完全不同的纯文本格式,实际上这在大多数情况下是真正需要的。但是,总的来说,对应基于循环的测试环境,在对每个向量需要跨模块的相关并完全相同语义的情况下,用于模式文件的共享、通用的语法不仅是期望的,而且是必需的。这种共享的语法是对模式源文件中的“公共”部分指定的。实际上,对于大多数情况,设想“公共”部分是(除头信息以外)在模式文件中需要的唯一部分,而且每个厂家的编译器将只利用该部分工作。这部分给出了所有编译器都应当能够解释的用于模式文件的规则。模式文件应当如下组织file_contents:version_infopattern_definitionsversion_info:Versionversion-identifier′;′pattern_definitions:pattern_definitionpattern_definitionspattern_definitionpattern_definition:main_header′{′main_section′}′main_header′{′main_sectionvendor_sections′}′subr_header′{′subr_section′}′subr_header′{′subr_ectionvendor_sections′}′main_header:MainPatternidentifiermain_section:CommonSection′{′common_contentsmain_section_domains′}′common_contents:timing_referencetiming_map_referencetiming_reference:Timingfile-name′;′timing_map_reference:TimingMapfile-name′;′main_section_domains:main_section_domainsmain_section_domainmain_section_domainmain_section_domain:Domaindomain_name′{′main_section_contents′}′domain_name:identifiermain_section_contents:main_section_contentsmain_section_contentmain_section_contentmain_section_content:label_specmain_pattern_secmain_pattern_speclabel_spec:label′:′label:identifiermain_pattern_spec:main_operationcapture_mask_flag′{′vectors_and_waveforms′}′main_operation:/*empty*/common_operationjal_opjsr_opjsrc_opjsc_opexit_opcommon_operation:idxi_opidxin_opjec_opjech_opiff_opiffi_opjni_opldin_opnop_oppause_opsndc_opsndt_opstfi_opsti_opstps_opwait_op/**InstructionsspecifictotheMAINPatterns*/jsr_op:JSRidentifierjsrc_op:JSRCidentifierjsc_op:JSCidentifierjal_op:JALidentifierexit_op:EXIT/**InstructionscommontobothMAINandSUBRPatterns*/idxi_op:IDXI24-bitnumberidxin_op:IDXInindex-registerjec_op:JECidentifierjech_op:JECHidentifierjff_op:JFFidentifierjffi_op:JFFIidentifierjni_op:JNIidentifierldin_op:LDINindex-registernop_op:NOPpase_op:PAUSEsndc_op:SNDC8-bitnumbersndt_op:SNDT8-bitnumberstfi_op:STFI24-bitnumbersti_op:STI24-bitnunberstps_op:STPSwait_op:WAITcapture_mask_flag:/*empty*/capture_mask_flagCTVcapture_mask_flagMTVcapture_mask_flagMATCHvectors_and_wavfeforms:/*empty*/vectors_and_waveformsvectorvectors_and_waveformswaveformvector:vector_declaration′{′vector_data′}′vector_declaration:VectorVvector_data:vector_datumvector_datavector_datumvector_datum:pin_name′=′vector-value′;′pin_name′=′identifier′;′waveform:waveform_declaration′{′waveform_data′}′waveform_declaration:WaveformWwaveform_data:waveform_datumwaveform_datawaveform_datumwaveform_datum:waveform-table-pin-group-name′=′identifier′;′pin_name:identifiervendor_sections:vendor_sectionsvendor_section{}vendor_section{}vendor_section:VendorSection′{′vendor_section_contents′}′subr_header:SubrPatternsubr_section:CommonSection′{′common_contentssource_selection_tablesubr_ection_domains′}′CommonSection′{′common_contentssubr_section_domains′}′subr_section_domains:subr_section_domainssubr_section_domainsubr_section_domainsubr_section_domain:Domaindomain_name′{′subr_section_contents′}′source_selection_table:SourceSelectionTable′{′source_selector_definitions′}′source_selector_definitions:source_selector_definitionssource_selector_definitionsource_selector_definitionsource_selector_definiton:SourceSelectorsource_selector_name′{′source_mappings′}′source_selecior_name:identifiersource_mappings:source_mappingssource_mappingsource_mappingsource_mapping:pin_name′=′source′;′source:MAININVERT_MAINSUBRINVERT_SUBRsubr_section_contents:subr_section_contentssubr_section_contentsubr_section_contentsubr_section_content:label_specsubr_pattern_specsubr_pattern_specsubr_pattern_spec:subr_operationcapture_mask_flag′{′vectors_and_waveforms′}′subr_operation:/*empty*/common_operationrtn_opstss_op/**InstructionsspecifictotheSUBRPatterns*/rtn_op:RTNstss_op:STSSidentifier[415]以下是以上所使用的未定义非终止符的描述1.version-identifier选自集合的一个或多个字符的序列,其中第一个字符必须是数字。2.identifier选自集合[a-zA-Z0-9]的一个或多个字符的序列,其中第一个字符必须选自集合[a-zA-Z]。3.vender-section-contents只对特定于厂家的编译器有意义的任意文本。4.file-name有效的Windows文件名(如果在文件名中包含任何空格,则必须包含在双引号中)。应当注意,这应当是简单文件名,即,不应当具有目录成分。5.waveform-table-pin-group-name选自集合[a-zA-Z_0-9]的一个或多个字符的序列,其中第一个字符必须选自集合[a-zA-Z]。这个变量是在其它某个地方声明的,并保留对引脚组公用的波形表的名字。6.24-bitnumber最大为16777215的有限十进制数。7.8-bitnumber最大为256的有限十进制数。8.index-register有效十进制数。在模块的一种实施方式中,这可以是值[1-8]。9.vecor这类似于STIL中的Vector语句。应当注意,这指的是信号名与信号组名,使得对于编译器有必要能够访问引脚描述文件。10.waveform-time-reference选自集合[a-zA-Z_0-9]的一个或多个字符的序列,其中第一个字符必须选自集合[a-zA-Z]。模式文件将支持注释,注释的意思是将被模式文件编译器忽略。注释以“#”字符开始,延伸到一行的结束。关于模式文件头和“公共”部分中的结构,应当注意以下要点1.pattern-name项指定将与模式文件包含用于其的数据的模式对象关联的名字。这在对应的模式目标元文件中转移到头。2.waveform-time-reference是用于在模式文件外部,在Timing文件中定义的特定waveform-and-timing定义的名字。模式文件中waveform-time-reference的说明将(用于waveform-and-timing的)特定名字绑定到所有后续的向量,直到遇到另一waveform-time-reference。3.用于子例程(例如,JSR与JSRC)调用的操作数是应当是在相同模式文件中先前遇到的pattern-speclabel或者外部定义的子例程模式中的pattern-speclabel。这种操作数最终为加载/处理而分解。用于子例程调用的操作数的标签需要在整个系统中唯一。应当注意,尽管waveform-time-reference名字可以是句法上正确的任何名字,但由于特定的硬件暗示waveform-time-reference名字可能需要限制到先前已知的、很好定义的集合(为了更多的可读性,这可以由用户可选地映射到用户选择的名字,映射在可选文件中给出)。还应当注意,模式与waveform-time-reference源文件应当提供用于连接到物理测试器通道的所有DUT通道的初始配置。如果后续数据对任何DUT通道忽略,则模式编译器将“插入”模式数据,保留来自初始级的输出。模式文件例子[420]MAIN模式源文件的简单例子将帮助说明该使用。##Filename:good1.pat#Version1.0;#--------------------------------------------------------------------#MainPatterndefinition:#--------------------------------------------------------------------MainPatterngood1{CommonSection{MacroDefdefaultDataVal(XXXXXXXX)MacroDefnopInstr(NOP)MacroDeflabel1(Label1:)MaeroDefjniInst(JNI)#-----------------------------------------------------------------#TimingSpecifications#-----------------------------------------------------------------Timing″productionTiming.tim″;TimingMap″productionTimingOpenSTARMap.tmap″;#-----------------------------------------------------------------#DefaultDomainCycles#-----------------------------------------------------------------Domaindefault{#----------------------------------------------------------------#label:instruction{Vector/WaveformData}#----------------------------------------------------------------NOP{V{DATA=$dcfaultDataVal;CLK=1;}W{DATA=wfsl;CLK=wfsl;}}JALmyAPG{V{DATA=00000000;}}JSCmySCAN{V{DATA=10101010;}}JSRCmySubroutine{V{DATA=01010101;}}JSRmyAPG{V{DATA=00110011;}}STI100{}labZero:NOP{V{DATA=00000011;}}JNIlabZero{V{DATA=11111100;}}IDXI3000{V{DATA=10101010;}}IDXXIn3{V{DATA=01010101;}}Slabel1NOP{V{DATA=$defaultDataVal;}}IDXI2000{V{DATA=10101010;}}NOP{}EXIT{V{DATA=LLHHLLHH;}}}}}以下说明用于说明SUBROUTINE模式源文件的另一例子。#--------------------------------------------------------------------#SubroutinePatternmySubrPat1definition:#--------------------------------------------------------------------SubrPatternmySubrPat1{CommonSection{#-----------------------------------------------------------------#TimingSpecifications#-----------------------------------------------------------------Timing″productionTiming.tim″;TimingMap″productionTimingOpenSTARMap.tmap″;#-----------------------------------------------------------------#SourceSelectionSpecifications#-----------------------------------------------------------------SourceSelectionTable{SourceSelectorSreSelDef{DATA=SUBR;CLK=SUBR;DATA=SUBR;}SourceSelectorSrcSelOne{DATA=MAIN;CLK=MAIN;}}#----------------------------------------------------------------#DefaultDomainCycles#----------------------------------------------------------------Domaindefault{#----------------------------------------------------------------#label:instruction{VectorandWavedformDatasetups}#----------------------------------------------------------------STI100{Vector{DATA=00000000;}}IDXI3000{Vector{DATA=00001111;}}IDXIn3{Vector{DATA=00110011;}}$label1NOP{Vector{DATA=LLHHLLHH;}}NOP{Vector{DATA=LLXXXXXX;}}NOP{Vector{DATA=LLHHXXXX;}}JNILabel1{Vector{DATA=LLHHLLHH;}}STSSSrcSelOne{Vector{DATA=LHLHLHLH;}}RTN{Vector{DATA=LLXXXXXX;}}}}[422]来自模式源文件的主头和公共部分的概述信息存储在目标元文件的主头中。概述包括用于快速提取一般所需的信息,用于帮助地址等的预加载分解或用于帮助数据登录。由于公共部分的语义对于所有编译器都是完全相同的,因此每个编译器都就能够提供相同的概述信息,而且写元文件的第一编译器将存储这种信息。以下是将要存储的信息1.模式源文件名。2.在源文件中所声明的模式类型。3.来自源文件的版本信息。4.用在模式源文件的公共部分中的所有waveform-and-timing名字列表。5.引用模式源文件中公共部分的(相对)向量地址的所有子例程的映射。6.引用模式源文件中公共部分的(相对)向量地址的所有标签的映射。7.通用的簿记信息向量计数、指令计数,等等。开放体系结构的测试系统需要模式与模式列表文件都具有显式和不同的扩展名。对于模式文件,这适用于纯文本源与编译后的目标文件。这被看作是方便用户快速识别目录列表中可见的文件类型等并允许以扩展名为基础进行关联。模式列表文件解析器将期望具有以下扩展名的文件名纯文本模式源文件.pat编译后的模式目标元文件.pobj模式列表文件.plst[424]用户可以重写这些缺省值,例如通过测试器环境变量或者设置选项。测试器将需要在至少一个环境配置文件中定义用于文件搜索路径的以下“环境”变量Tester_PATLIST_PATH用于模式列表文件。Tester_PATSRC_PATH用于模式源文件(可选的)。Tester_PATOBJ_PATH用于模式目标元文件。应当注意,如果可选的环境/设置变量Tester_PATSRC_PATH没有定义,则将假定与Tester_PATOBJ_PATH相同。总的来说,不定义Tester_PATSRC_PATH比用与Tester_PATOBJ_PATH相同的值来定义更有效。E6.软件表示[427]模式对象不是由用户创建的;相反,用户总是处理模式列表对象,其中模式列表对象是其它模式列表和/或模式的集合。模式列表对象创建、拥有并维护包含在其中的模式对象,同时使用户可以访问它们。用户测试程序中的模式列表对象与磁盘上包含模式列表实际定义的模式列表文件关联。模式列表的定义提供模式列表的显式名字并通过文件名关联识别模式和/或其它模式列表的有序列表。这部分描述模式列表和列表的软件表示,作为理解它们如何在测试器框架中操作的开头。模式列表关联[428]测试环境中的单个测试站点(及通过扩展还有其中的测试计划)可以与多个顶级模式列表关联。但是,在任何给定时间,对于测试计划都只有一个执行环境。由于高级模式列表为其(分层)引用的模式定义了执行序列,因此活动执行环境是对应于当前所选的顶级模式列表的环境。应当注意,这并不暗示一次只有包含在单个模式列表中的模式可以加载到硬件上;相反,为了使执行序列可行而需要加载到硬件上的模式集合必须总是所有当前加载模式的子集。模式树直观上可以感到表示高级模式列表的一种方式是通过树数据结构的某种排序。图7说明了本发明有序模式树的一种实施方式,假定模式列表A是高级模式列表。模式树信息内容[430]以下信息将存储在模式树的每个节点上1.与该节点关联的实体(模式列表或模式)的名字。2.定义源的类型。对于叶子(模式节点),这总是模式文件;对于中间(模式列表)节点,这可以是“顶级文件”(对于顶级模式列表定义)或者“嵌入在文件中”(对于嵌套的模式列表定义)。3.磁盘上节点关联的文件的最后修改时间戳。以下附加信息将只存储在中间节点(模式列表)上1.(如果有的话)关于由该节点表示的模式列表对象设置的执行选项-即,其对象选项。2.(如果有的话)关于由该节点表示的模式列表定义内的每个孩子引用的执行选项-即,对于其每个孩子的引用选项。因此,在从根到中间节点的唯一路径上遇到的节点集合和其中遇到它们的序列包含确定由该节点表示的组合、有效的执行选项所必需的所有信息。模式的执行选项是由其中间父亲的有效执行选项结合其中间父亲可能有的用于其的引用选项确定的。在这里,应当注意尽管模式列表解析器是在创建模式树的过程中,但由于它们的使用环境要到稍后才能分解,因此特定的执行选项可能需要简单地作为字符串的值的初始存储。这种选项的例子是“掩码”选项,它指定引脚掩码信息模式列表不与套接字信息关联,因此引脚掩码信息(引脚与组名)存储为字符串,在加载之前分解。以下附加信息将只存储在叶子(模式)节点中1.对由该模式调用的子例程的所有(可能是传递的)引用,作为执行树,既有外部的又有内部的。当然,所有模式节点都将附加地具有对目标元文件公共头中可用的所有模式文件概述信息的访问并可以选择对其高速缓冲。处理模式列表修改[436]对模式列表内容进行的改变从概念上影响对该模式列表的所有引用。适当地应用到模式对象及模式列表对象的以下规则将用于管理这种改变1.对磁盘上模式列表文件的内容所进行的改变将通过测试系统只在关于该模式列表(或关于引用其的任何其它模式列表)执行的load()命令上传播。换句话说,软件中的模式列表层次将总是反映当前加载到硬件上的模式列表。2.用户将能够设置使加载过程中所进行的同步模式列表与其磁盘文件源的测试失败的模式;这将允许生产模式中更快/更安全的操作。模式树导航[437]与测试站点(及通过扩展还与该站点的测试计划)关联的顶级模式列表具有公有(全局)范围。系统提供导航表示顶级模式列表的模式树的API,使得用户可以获得对单独节点和子树的访问。E7.模式列表动态特征[438]前面描述了模式列表的静态规则。现在给出模式列表动态(执行)规则的描述。模式树对于总的模式管理是基本的。例如,模式加载序列的起始点是对当前与站点或测试计划关联的模式树调用load()方法。但是,模式树不能孤立地操作。完全初始化的模式树将引用创建以下两个框架对象1.顶级模式列表定义模式的模式执行序列。它描述这种执行序列可以如何从对应于该顶级模式列表的模式树导出。例如,图7所示对应于模式树A的模式执行序列是{q,s,t,q,r,q,u,u,v}。模式执行序列是从概念上反映通过模式树描述的执行序列的有序列表。框架建立并维护模式执行序列中模式树节点与对应输入之间的任何必要的导航链接。2.模式集合,它简单地是模式树中所有唯一模式(包括子例程)的列表。因此,该列表是将用于确定应当加载到硬件上的单独模式列表。框架建立并维护模式集合中模式树节点与对应输入之间的任何必要的导航链接。图7模式树的模式集合是(q,s,t,r,u,v)(假定模式列表A中没有模式包含任何子例程调用)。应当注意,模式执行序列和模式集合总是可以从模式树导出;但是,只要是可行的,在初始构造之后对它们进行告诉缓冲常常是有意义的。模式列表执行选项[441]如上所示,(定义之前的)每个模式列表声明或模式列表/模式引用输入可以后面跟着多个执行选项。模式列表执行选项修改模式列表的运行时执行。为了允许进一步的扩展,用于这些选项的名字(和可选值)将简单地被模式编译器的模式列表文件解析器看作字符串,适当地由特定版本解释。测试器规定以下所述的一组选项及其解释。但是,厂家可以扩展选项集合。为了允许选项语法的解析时确认,模式列表文件解析器可以读取特定版本的信息文件。这种信息文件还可以用于执行特定版本是否从根本上支持执行选项的说明。对于支持一组执行选项的版本,以下通用规则将管理它们的使用。为了理解这些规则,将模式列表/模式的层次集合可视化为有序的树是有用的。1.关于模式列表定义设置的固有选项(即,在文件中的“local-pattern-list-declaration,global-pattern-list-declaration”结果中)有效地指导用户测试程序中关于对应模式列表对象设置的选项设置。因此,它们适用于该模式列表对象的所有引用并称为对象选项。2.关于对模式列表/模式的引用设置的引用选项(即,在文件中的“pattern-entry”和“pattern-list-entry”结果中)限制层次中对特定路径选项的范围-从树的根到所考虑引用的(由模式列表/模式的声明次序建立的)路径。因此,这些是关于特定对象引用(而不是对对象本身)的选项,并称为引用选项。3.用于层次集合中任何列表/模式的(由模式列表/模式的声明次序建立的)有效选项设置是沿从树的根到该列表/模式的路径遇到的对象与引用选项的组合。特定的组合机制(例如,设置联合、设置交集或任何其它冲突解决算法)是选项本身的属性。应当注意,以上规则的结果-及没有设置关于模式文件中模式定义的执行选项的工具的事实-是没有设置应用到对模式的所有引用的选项的直接规则。用于实现这个目的的机制是使用单模式模式列表。测试器指定修改其burst特性并修改其执行序列的模式列表执行选项的特定集合。当用于模式列表的执行序列提交给硬件时,硬件产生burst。burst是直接由硬件执行模式序列,而不需要软件的任何介入。burst中断是执行序列中前一burst终止而新burst开始的位置。模式管理软件的一个目标是向硬件提供需要产生burst的执行序列。缺省地,一个模式树生成一个执行序列,该序列如果提交给硬件,就将会导致单个burst。但是,这种特性可以提供使用关于模式列表的选项修改。因此,选项结果的使用会导致burst中断。此外,用户有时候将需要在每个模式或每个burst之前或其后运行的序言或结尾模式。这修改将要提交给硬件的执行序列。在创建或修改模式执行序列对象的过程中,框架具有确定(如果需要的话还报告)模式burst中的中断所需要的所有信息,该burst是由所指定执行选项与由模式树体现的特定执行序列的组合而产生的。这么做时,可能需要调查系统中模块的硬件能力。例如,一种硬件实现允许引脚掩码的四种存储配置,其中两种(0和3)用于缺省掩码(以支持MarksThisVector,MTV)和非掩码操作。因此,允许用户的两种不同的全局引脚掩码配置,而不需要中断burst模式。应当注意,如果模块厂家不支持硬件中的模式列表实现,则厂家对模式执行序列的处理将导致执行序列中所有模式的单独执行。在站点兼容和站点异类系统中,站点的burst能力将受“最低公分母”的限制。测试器提供特定的缺省选项集合,以下描述其参数。每个选项都是通过声明以下开始的·它是是固有的(即,与Global或Local关键字的定义关联)还是引用的(即,与Pat或PList关键字的引用关联)。固有选项在定义点和每个引用应用,而引用选项只在其关联的引用时应用。·此外,如果选项假定为递归应用到所有静态(句法上)或动态(通过引用语义上)嵌套的模式或模式列表,则选项称为是被孩子继承的。以下是选项列表。每个兼容的厂家都将根据指定解释这些选项。1.Mask<pin/pingroup>当应用到GlobalPList、LocalPList时是固有的,当应用到PList、Pat时是引用的。被孩子继承。这个模式列表将总是具有由禁用的所指示引脚或引脚组引用的引脚比较电路。有时候,硬件限制可能导致burst中断。2.BurstOff当应用到GlobalPList、LocalPList时是固有的,当应用到PList、Pat时是引用的。不被孩子继承。这个模式列表将总是在非burst模式执行。这个选项不被孩子继承,但BurstOffDeep选项(下面)是由孩子继承的。3.BurstOffDeep当应用到GlobalPList、LocalPList时是固有的,当应用到PList、Pat时是引用的。被孩子继承。这个模式列表将总是在非burst模式执行。这个选项被孩子继承,但BurstOff选项(上面)是不由孩子继承的。应当注意,BurstOffDeep选项不能被孩子关闭。4.PreBurst<pattern>当应用到GlobalPList、LocalPList时是固有的,只被不具有所指定burst选项的孩子节点继承。所指示的模式放到这个模式列表的所有burst之前。PreBurst模式就在每次burst由于这个模式列表节点而开始之前发生。当已经在具有是相同模式的PreBurst选项的burst中时,这个选项不应用。5.PostBurst<pattern>当应用到GlobalPList、LocalPList时是固有的,只被不具有所指定burst选项的孩子节点继承。所指示的模式放到这个模式列表的所有burst之后。PostBurst模式就在每次burst由于这个模式列表节点而开始之后发生。当已经在具有是相同模式的PostBurst选项的burst中时,这个选项不应用。6.PrePattern<pattern>当应用到GlobalPList、LocalPList时是固有的,不被孩子节点继承。所指示的模式放到这个模式列表的所有模式之前。7.PostPattern<pattern>当应用到GlobalPList、LocalPList时是固有的,不被孩子节点继承。所指示的模式放到这个模式列表的所有模式之后。8.Alpg<alpgobjectname>当应用到GlobalPList、LocalPList时是固有的,不被孩子节点继承。所指定的ALPG对象存储例如低速APG寄存器设置、读取等待时间、中间数据寄存器、地址数据求逆、数据生成等的相关信息。9.StartPattern<pattern>当应用到GlobalPList、LocalPList时是固有的,不被孩子节点继承。模式列表将在其执行序列中StartPattern第一次出现时开始执行。10.StopPattern<pattern>当应用到GlobalPList、LocalPList时是固有的,不被孩子节点继承。模式列表将在其执行序列中StopPattern第一次出现时开始停止执行。11.StartAddr<vectoroffsetorlabel>当应用到GlobalPList、LocalPList时是固有的,不被孩子节点继承。这必须与StartPattern选项同时出现。模式列表将在其执行序列中StartPattern第一次出现时在StartAddr开始执行。12.StopAddr<vectoroffsetorlabel>当应用到GlobalPList、LocalPList时是固有的,不被孩子节点继承。这必须与StopPattern选项同时出现。模式列表将在其执行序列中StopPattern第一次出现时在StopAddr停止执行。13.EnableCompare_StartPattern<pattern>当应用到GlobalPList、LocalPList时是固有的,不被孩子节点继承。模式比较将在所指示模式第一次出现时开始。14.EnableCompare_StartAddr,EnableCompare_StartCycle当应用到GlobalPList、LocalPList时是固有的,不被孩子节点继承。这必须与EnableCompare_StartPattern同时出现。指示模式中模式比较要开始的地址或循环。15.EnableCompare_StopPattern<pattern>当应用到GlobalPList、LocalPList时是固有的,不被孩子节点继承。模式比较将在所指示模式第一次出现时完成。l6.EnableCompare_StopAdr,EnableCompare_StopCycle当应用到GlobalPList、LocalPList时是固有的,不被孩子节点继承。这必须与EnableCompare_StopPattern同时出现。指示模式中模式比较要完成的地址或循环。17.Skip当应用到PList、Pat时是引用的。不被孩子节点继承。使得跳过由模式列表支配的模式或整个序列。这还使得跳过在这个模式列表子树根的所有选项。就象这个模式子树对于执行目的来说不存在一样。模式列表burst控制[451]如前面所描述的,当用于模式列表的执行序列提交给硬件时,硬件产生模式序列的burst,而不需要软件的任何介入。burst中断是执行序列中前一burst终止而新burst开始的位置。如在以上选项列表中所描述的,PreBurst、PostBurst、BurstOff和BurstOftDeep选项控制burst中断在哪里发生。PreBurst和PostBurst选项确定服从下述特定附加规则的burst中断1.当父亲列表具有PreBurst和PostBurst选项且嵌套列表具有相同的对应选项时,没有burst中断,且嵌套列表的PreBurst和PostBurst选项不应用。只有单个burst应用父亲列表的PreBurst和PostBurst。2.注意,当嵌套列表不具有burst选项时,等效于具有通过这些选项的描述与父亲列表相同的PreBurst和PostBurst选项。因此,不具有burst选项的嵌套列表不会导致burst中断。3.如果以上规则1不应用且对从父亲列表开始到嵌套列表开始的模式执行序列有影响,则在嵌套列表的开始有burst中断。在这种情况下,父亲列表的PreBurst和PostBurst应用到从父亲列表开始的模式执行序列的这种影响。嵌套列表的PreBurst和PostBurst应用到嵌套列表。4.如果以上规则1不应用且对从嵌套列表结束到父亲列表结束的模式执行序列有影响,则在嵌套列表的结束有burst中断。在这种情况下,父亲列表的PreBurst和PostBurst应用到对从父亲列表开始的模式执行序列的这种影响。嵌套列表的PreBurst和PostBurst应用到嵌套列表。5.如果规则1不应用且对从除嵌套列表以外的父亲列表开始的模式执行序列没有影响,则父亲列表的PreBurst和PostBurst不应用。只有单个burst应用嵌套列表的PreBurst和PostBurst。以下是说明选项对执行序列作用的一些例子。为了简化,假定所有模式列表都在单个文件中指定。例子1BurstOff的使用[453]这个例子说明BurstOff和PreBurst。特别要强调的是BurstOff使模式单独运行在一个模式长的burst中。因此PreBurst选项仍然应用。输入模式列表如下GlobalA[BurstOff][PreBurstpat_z]{Patq;PListB;Patr;Pats;GlobalC{Patt;PListD;};PListD;PListE;};GlobalB{Pata;Patb;};GlobalD[BurstOff]{Patc;Patd;};GlobalE{Pate;};根在A的树可以在图8中表示。以下是用于这个模式的执行序列。字符|指示burst中断。这个模式列表在10个burst中执行,第一个具有模式z和q,最后一个具有模式ezq|ab|zr|zs|t|c|d|c|d|e[455]应当注意以下关于这个执行序列的要点1.由于关于A的BurstOff选项没有被B继承,因此B中的模式a和b作为burst操作。2.由于关于A的PreBurst选项没有被B继承,因此B的burst中的a和b前面没有加上z。3.前面加z只对由于作为a的直接孩子,即模式q、r和s,而执行的模式发生。由于A具有BurstOff选项,因此这些模式是单独执行的,就象在只有一个模式长的burst中。BurstOff需要模式在一个模式长的burst中单独运行。因此,PreBurst和PostBurst选项仍然应用。4.模式列表D具有使其孩子c和d单独执行的固有burstoff选项。它们不从A继承PreBurstz。例子2BurstOffDeep的使用[456]这个例子说明了BurstOffDeep选项。模式列表定义过程中的BurstOffDeep影响嵌套定义与引用列表。但是,PreBurst和PostBurst选项不被嵌套和引用列表继承。该例子使用与例子1中相同的模式A、B、C、D、E,但选项是不同的5.关于A定义的选项[BurstOffDeep]、[PreBurstz]、[PostBursty]6.对任何其它节点都没有其它选项。执行序列如下。就象前面,|字符指示burst中断。zqy|a|b|zry|zsy|t|c|d|c|d|e注意,以下关于这个执行序列的要点1.PreBurst和PostBurst选项不被B、C、D、E继承。2.BurstOffDeep被B、C、D和E继承。例子3PreBurst和PostBurst继承[458]现在假定考虑例子1的模式列表树,其中选项是1.关于A定义的选项[PreBurstx]、[PostBursty]2.关于A定义的选项[PreBurstx]、[PostBurstz]3.对任何其它节点都没有其它选项。执行序列将是xqabrstcdcdey[460]“tcd”子序列不是“xtcdz”的原因如下1.第一个x是禁止的,因为它等于与有效的当前burst关联的pre-burst选项。2.最后一个z是禁止的,因为PostBurstz没有继承到D,而且没有从C生成的z可以附加到其上面的模式。例子4Skip的使用[461]这个例子说明了关于嵌套定义和引用列表的Skip选项的作用。该例子使用与例子1中相同的模式A、B、C、D、E,但选项是不同的1.关于A定义的选项[Skip]、[PreBurstz]、[PostBursty]2.关于对r引用的选项[Skip]3.关于C定义的选项[Skip][462]执行序列是如下没有中断的单个burstzqabscdey[463]注意以下关于这个执行序列的要点1.用于r和C的节点被跳过。2.根本没有burst中断。例子5Mask的使用[464]这个例子说明了Mask的作用及其对模式和模式列表定义与引用的作用。该例子使用与例子1中相同的模式A、B、C、D、E,但选项是不同的1.关于A定义的选项[maskpin1_pin2]、[PreBurstz]2.关于对B引用的选项[maskpin3]3.关于B定义的选项[maskpin4]4.关于对e引用的选项[maskpin5]5.对任何节点都没有其它选项。名字“pin1_pin2”指定掩码Pin1和Pin2的组。名字“pin3”、“pin4”和“pin5”分别指定掩码Pin3、Pin4和Pin5。以下提供该执行序列,|指示burst中断。每个模式下的数字指示在该模式执行过程中被掩码的引脚。zqabzrzstcdcd|e1111111111111222222222222233544[466]注意以下关于这个执行序列的要点1.厂家的硬件如果没burst中断的话只可以容纳两个掩码块。在e执行之前,这两个掩码块是引脚{1,2}和引脚{1,2,3,4}。当模式e以引脚{1,2,5}的不同掩码块到达时,硬件需要burst中断。例子6继承选项与引用的使用[467]这个例子说明了当定义被引用时,在定义处的继承选项不应用。考虑以下例子GlobalA{GlobalB[BurstOffDeep]{GlobalC{...};...};...PListC;};GlobalD{PListC;};[468]BurstOffDeep选项是由C在其定义的点继承的。但是,它不是固有选项,因此在其两个引用点不会应用到C。例子7对于嵌套列表的PreBurst和PostBurst[469]考虑以下例子GlobalPListA[PreBurstx][PostBursty]{Patp1;LocalPListB[PreBurstx][PostBursty]{Patp2;}LocalPListC{Patp3;}LocalPListD[PreBurstx][PostBurstz]{Patp4;}LocalPListE[PreBurstw][PostBursty]{Patp5;}Patp6;}..该执行序列是xp1p2p3y|xp4z|wp5y|xp6y1.因为嵌套列表的PreBurst和PostBurst选项指定为与父亲的相同,所以模式p2在与p1相同的burst中。因为这些选项继承为与父亲的相同,所以模式p3也在相同的burst中。这些选项在剩余的嵌套列表中有至少一个不同的成员,从而造成burst中断。定时用户主要通过利用模式文件定义测试设置来与系统交互。定时文件用于描述这些模式的定时。这个文件需要分解用于底层定义的其它系统文件(例如,Pin、SpecSelector)。此外,用在定时定义中分解各种变量的Spec-Selectors和Global定义封装在合成的TestConditionGroup对象中。例如测试计划文件的较高级文件又使用这个TestConditionGroup实例。测试计划文件包含对TestConditionGroup对象的引用。模式源文件对TimingMap对象中的WaveformSelector进行引用。Timing对象本身引用Pin对象。可选地,Timing对象还可以引用由SpecSelector对象调制的变量。这些关系在图9中说明。Pattern-List中的Pattern对象指定用于一组模式特征的WaveformSelector对象的名字。还要注意,TimingMap文件在模式中指定。如果这个映射未改变,则模式不需要编译。[474]TestConditionGroupFile对象导入要使用的Timing对象和要使用的TimingMap对象。每个测试都使用从用于该实例的TestConditionGroup对象导出的TimingCondition实例。因此,支持相同波形表的集合的多个Timing对象可以存储在测试器框架中并可以根据需要交换。类似地,多个测试计划文件可以共享公共的TestConditionGroup对象。以下测试计划描述文件的例子说明了Timing对象的使用。{TestConditionGroup=tim2_prod;Selector=max;}TestFunctionalTestMyFunctionalTestSlow{PListParam=patlist1;TestConditionParam=tim1_prod_typ;}TestFunctionalTestMyFunctionalTestFast{PListParam=patList1;TestConditionParam=tim2_prod_max;[476]Timing对象以每个引脚为基础定义了各种波形。用在Timing文件和TimingMap文件中的引脚需要在引脚定义文件中适当地定义。Timing对象可以使用SpecificationSet对象来定义waveform对象中的值。尽管Timing对象可以包括用于各种属性的硬编码值,但情况通常是用户利用变量指定各个值。这些变量又可以依赖SpecificationSet对象。以下说明这种使用的例子。[478]SpecSelector如下说明地定义。SpecificationSetprodTmgSpec(min,max,typ){t_le=10ns,14ns,12ns;t_te=30ns,34ns,32ns;}[479]通过改变spec而使用的timing的改变在以下例子中说明。F2.映射到测试器的定时组件[480]测试器模块的两个组件直接涉及波形的生成及其关联的定时。这两个模块是模式生成器(PG)和框架处理器(FP)。说明开放体系结构测试系统体系结构中框架处理器的波形格式化与定时生成的简化框图在图10中说明。以下给出波形生成的简单描述。模式生成器1002生成模块中所有引脚公共的定时集合。该定时集合称为全局定时集合(GTS)。有三种其中模式生成器可以设置的模式。这三种模式影响可以用于描述GTS的位数。此外,这些设置还影响用于选择簇及CaptureThisVector(CTV)和MaskThisVector(MTV)位是否设置的位数。为了通知测试器捕捉这个向量的结果,用户在模式文件中使用CTV标志。类似地,用户在模式中使用MTV标志来通知测试器掩蔽当前向量的结果。这在下面的表1中说明。模式生成器1002还负责波形特征(WFC)的生成。WFC以每个引脚为基础生成。测试器模块使用固定位数来描述WFC。表1[482]测试器模块为每个引脚提供框架处理器1004。每个框架处理器都包含定时设置扰频器(TSS)1006,在这个例子中该定时设置扰频器具有高达1024的总深度。依赖于前面所述和在图10中说明的模式生成器的模式,其中使用每个簇64输入的16个簇,TSS1006可以分成多个簇1008。提供TSS,从而允许为每个引脚定义波形表的能力中更大的灵活性。在“FP”模式,TSS使用2比特输出一个定时设置。因此,TSS将生成每个引脚总共四种不同的物理定时设置。这些定时设置称为局部定时设置(LTS)。框架处理器1004组合LTS和WFC并创建到波形存储器1012和定时存储器1014的索引1010。在“FP”模式中,5位值分成由LTS生成的2位和由WFC生成的3位。因此,尽管可以使用最大4种物理定时设置,但物理波形存储器和定时存储器的深度是每引脚32深。波形存储器保护形成波形的使能定时边缘。用于使能边缘的定时值是从定时存储器获得的。因此,框架处理器格式化波形。映射方法[484]该方法是以每引脚为基础将WaveformTable块映射到测试器中的LTS中。如果测试器硬件支持4个LTS,则用户可以定义最大4个WaveformTable块。每个WaveformTable块可以具有最大n个用于测试器数字模块的波形定义。Timing-Map文件提供开放体系结构的测试系统中在Timing-Map块中定义的逻辑WaveformSelector到模块的WaveformTable的映射。在该情况下,测试器支持高达256个逻辑WaveformSelector。在开放体系结构的测试系统中,这些逻辑WaveformSelector直接映射到GTS。模式编译器依赖于Timing-Map和Timing块,才能够编译模式文件。但是,如果Timing块的WaveformTable中的波形特征未改变或者映射到Timing-Map块中的WaveformSelector未改变,则不需要重新编译模式。使用映射方法的例子[486]为了说明到测试器数字模块的映射,进行以下假设框架处理器设置成FP模式;CTV和MTV位设置成使GTS位的总数是6,而定时簇选择器位的总数是4。Timing块中定义的每个WaveformTable都映射到Timing文件中不同的LTS。这是以每个引脚为基础完成的。因此,WaveformTableseql映射到LTS1。在“SIG”引脚的情况下,所有8个可能的波形输入都用完了。但是,“CLK”引脚需要单个波形输入,从而用完波形存储器(WFT)和波形定时存储器(WTM)中的单个行。“SIG”引脚的前两个物理波形的映射在图11中说明。由于这个WaveformTable映射需要边缘独立配置的两个波形特征,因此我们结束分配波形存储器(WFT)1112和波形定时存储器(WTM)1114中的两个输入。该模块的一种实施方式具有总共6个定时边缘,T1、T2、T3、T4、T5和T6。这些直接映射到在Timing块的EdgeResource部分中的波形中定义的事件E1、E2、……。如果在Timing块中定义了多于6个事件且与以上模块一起使用,则将会导致错误。在图11的例子中,第一个波形特征“0”使用TimingEdgeT1来编程“ForceDown”或“D”事件,该事件发生在循环开始10ns的时间。TimingEdgeT2也用于在30ns的时间生成“ForceDown”或“D”事件。最后,TimingEdgeT3用于在45ns的时间生成“ForceOff”或“Z”事件。第二个波形特征“1”使用TimingEdgeT1来编程“ForceUp”或“U”事件,该事件发生在循环开始10ns的时间。TimingEdgeT2也用于在30ns的时间生成“ForceDown”或“D”事件。最后,TimingEdgeT3用于在45ns的时间生成“ForceOff”或“Z”事件。以这种方式,WFC映射到框架处理器的WFM存储器和WTM存储器中。用于引脚“SIG”的LTS1的波形存储器WFM的最终设置在以下表2中说明。表2[492]用于引脚“SIG”的LTS1的波形定时存储器WTM的最终设置在以下表3中说明。表3[493]“CLK”引脚用完了单个波形,因此用于这个引脚的WFM和WFT是非常简单的。用于“CLK”引脚的LTS1的波形存储器WFM的最终设置在以下表4中说明。表4LTS2的波形定时存储器WTM的最终设置在以下表5中说明。表5[495]TimingMap块显式地将WaveformSelector映射到Timing块的Waveformtable。对于测试器系统,这简化为设置定时设置扰频器(TSS)存储器。TSS基本上包含从GTS到保留所述设置的LTS的映射。用于我们例子的引脚SIG的TSS设置看起来象以下的表6。表6[496]最后,在TSS和LTS设置映射分解后,模式编译器可以使用这种信息来利用要使用的正确波形表(LTS)和正确波形特征来编程模式。因此,只考虑引脚“SIG”的我们的例子伪码模式在图11中说明。应当注意,这种编译不依赖于Timing块,而只依赖于Timing-Map块。G测试器操作[497]这部分描述测试器操作系统(TOS)的基本操作。在这部分中考虑的动作是·系统初始化·测试计划加载·模式加载·运行测试计划·运行单独的测试系统初始化[498]在一种实施方式中,为了初始化系统,必须满足特定的假设且必须满足特定的条件。以下子部分列出这些假设和条件。前提[499]相关系统软件组件的拷贝具有中心存储器,其位置是系统控制器已知的。这可以是在系统控制器上,或者在具有网络安装目录的其它系统上(或者通过其它机制对SYSC已知)-不管使用什么机制,在系统可以工作之前,所有软件都必须对系统控制器可用。这种软件包括厂家硬件控制(即,模块软件)DLL;标准的或用户测试类DLL;及用户测试计划DLL。系统模块配置文件在系统控制器上可用。回想这个文件使用户可以指定测试器的物理配置,例如系统底盘中每个模块的物理位置和类型,及模块软件DLL的名字。系统配置文件在系统控制器上可用。回想这个文件包含系统中站点控制器的列表及站点控制器主机名到开关矩阵输入端口地址的映射。站点控制器具有称为站点配置管理器(SCM)运行的服务。这种服务负责通过称为“硬件发现”的处理确定在每个槽中安装了什么硬件。它还负责参与系统控制器的系统初始化处理。应当注意,在一种实施方式中,开关矩阵操作协议指示单个站点控制器上的SCM应当总是利用开关矩阵输入端口连接地址1配置与模块的开关矩阵连接。回想这个“特定”站点标记为SITEC-1。系统控制器负责向每个站点控制器的SCM提供其开关矩阵连接地址。每个站点控制器的SCM都能够开始称为测试计划服务器(TPS)的处理。每个站点控制器上的测试计划服务器从根本上负责包含并执行用户的测试计划(或在单个站点控制器在多个DUT上运行测试的情况下是测试计划)。初始化阶段I系统确认[505]一旦以上假设和前提都已经满足,系统初始化首先进行如下的系统确认步骤1.系统控制器读取系统与模块配置文件,来初始化系统的特定于用户的视图。2.利用所指定的系统配置信息,系统控制器验证所指定的站点控制器是否活动、可到达并已经准备好(即,有SCM在运行)。这个验证步骤中的任何错误都将造成发生系统错误,并且初始化将异常中断。3.然后,系统控制器通知在SITEC-1的SCM服务配置开关矩阵具有对所有硬件模块的访问,并请求它执行硬件发现。4.在SITEC-1的SCM服务向所有可用的模块槽(已知的硬件位置)轮询{厂家,硬件}元组并生成{厂家,硬件}元组到槽的映射。结果是这种轮询识别出完整系统中存在的{厂家,硬件,槽}绑定的整个集合。这种轮询的结果发送到系统控制器。5.系统控制器验证以上硬件发现步骤的结果匹配模块配置文件中特定于用户的配置。这个验证步骤中的任何错误都将造成发生系统错误并且初始化将异常中断。6.然后,系统控制器从已知位置的环境设置文件加载缺省环境(例如模块DLL的搜索路径、模式列表、模式、测试计划DLL、测试类DLL等)。7.系统控制器确保所有识别出的模块软件DLL都存在。如果有在系统控制器上不可用的,则如果可能的话就从中心存储器检索;否则将发生系统错误并且初始化将异常中断。初始化阶段II站点配置(可选的)站点配置,或站点分区,涉及可用系统硬件模块到不同站点的软件级指定(即,为多个DUT提供服务)。回想站点分区信息是在套接字文件中提供的。测试器系统允许站点(重新)分区既可用作为测试计划加载的一部分(由于每个测试计划都与特定的套接字关联)也可以作为独立的用户调用步骤执行。在后一种情况下,用户通过提供单独用于分区系统的套接字文件启动站点分区。在每个站点测试不同DUT类型的多DUT测试情况下,这在系统初始化过程中是特别有用的。但是,这个步骤在初始化阶段是可选的,并且用户可以选择不执行它,而是选择允许测试计划加载来适当地分区系统。不管选择来实现站点分区的方式是什么(通过独立调用或者隐含地通过测试计划加载),机制都是相同的。以下描述这种机制。1.给定套接字,系统控制器首先确定当前现有的系统分区是否与套接字兼容,或者是否需要重新分区。初始化过程中的缺省分区是所有可用模块都连接到SITEC-1的分区。以下剩余步骤只有在需要重新分区时才执行。2.系9统控制器向每个站点控制器的SCM发送配置信息,以利用在新套接字下已经使能的DUT站点个数和标识符重新配置。应当注意,这个是通用过程并处理由站点控制器控制的DUT站点个数为一的情况。新套接字信息也传送到SCM。3.如果有的话,则每个SCM都停止运行的TPS并启动新的TPS,利用新的套接字和在新套接字下已经使能的DUT站点个数和标识符初始化它。4.系统控制器确定哪个站点需要所需系统模块的什么子集。在这么做的同时,它还为该站点准备硬件槽信息。对于每个站点,净结果是指定给该站点的槽对站点模块DLL的一个列表。特定于站点的列表将标记为站点模块DLL槽列表(SITE-MDSL)。5.站点控制器向每个SCM提供合适的SITE-MDSL及必要的模块DLL。每个SCM又使这种信息对新启动的TPS可用。6.然后,系统控制器请求SITEC-1为合适的站点到槽连接(即为站点分区操作)配置开关矩阵。7.站点1至n上的TPS加载在其SITE-MDSL中指定的DLL。这些DLL中的每一个都具有名字为initialize()的函数,该函数取槽编号的阵列。在这个时候如果有任何误动作,将发生系统错误并且初始化将异常中断。initialize()方法进行以下动作a)创建基于标准接口IXXXModule的具体类。例如,与数字模块关联的DLL将创建单个基于IPinModule的对象来为与其关联的每个槽服务。b)创建基于接口IResource的具体类,对模块中的每个“资源单元”创建一个。同样,对于数字模块,每个基于IPinModule的对象将为由该数字模块专用的槽集合中的所有引脚创建基于ITesterPin的对象。8.然后,站点1至n上的TPS对每个加载模块DLL调用getXXXModule()来检索模块内容信息。9.对getXXXModule()的每次调用都返回作为IModule指针的<VendorHWType>Module类(例如,AdvantestPinModule)。每个这样的IModule指针都被TPS高速缓冲,这使得这些对于框架/用户代码可用。应当注意,IModule、IResource等的集合是永久性的(至少对于TPS的生命周期)。10.一旦以上步骤都完成了,TPS就在其指定的(众所周知的)端口上开始listen()。这向系统控制器发出TPS已经“准备好”开始正常(即,站点分区)操作的信号。测试计划加载[509]这部分描述用户测试计划DLL加载到站点控制器上的步骤(对于单个或多个DUT测试)。一旦系统初始化(及可选地还有启动站点分区)已经完成,用户测试计划就可以加载。用户测试计划在站点控制器上的加载如下进行1.系统控制器首先将测试计划DLL加载到其自己的处理空间中,查询其关联的套接字文件及其DUT类型标识符。这种信息用于识别运行这个测试计划的站点,由此识别这个测试计划将加载到的站点控制器。2.然后,系统控制器使用与测试计划关联的套接字信息启动如上概述的重新分区处理。3.系统控制器从测试计划DLL提取由测试计划所使用的测试类DLL,并且一旦系统控制器验证TPS已经准备好开始正常(即,站点分区)操作,就向适当的TPS发送测试类DLL并最终发送测试计划DLL本身。4.TPS调用LoadLibray()将其加载到其处理空间中。它对DLL调用众所周知的函数来创建与其服务的站点(即,DUT)个数一样多的TestPlan对象。5.TPS利用必要的测试器框架对象初始化TestPlan对象。在初始化过程中,TPS将由TestPlan对象所使用的测试类的适当DLL加载到处理空间中并创建测试类实例。6.TPS设置系统控制器到TestPlan对象的通信通道。7.系统控制器与TPS通信并建立其用于TestPlan对象的代理服务器。这决定了用户测试计划在站点控制器上的成功加载。运行测试计划[512]根据预定义流逻辑执行测试计划中所有测试的方法如下1.用户的应用程序将RunTestPlan消息发送到TPS。TPS向所连接的所有应用程序发送ExecutingTestPlan消息。然后,TPS对测试计划调用execute()。2.利用单个站点控制器测试多个DUT是利用该站点控制器上的多个线程执行的,每个DUT一个线程。每个线程运行相同TestPlan对象的不同、独立的实例。在这种情况下,由于模块控制软件DLL可能跨DUT共享,因此需要用于硬件通信的模块命令取DUT标识符参数。3.TestPlan对象对其集合中的每个测试迭代(可选地,告诉其流对象根据流逻辑处理每个测试),调用preExec()、execute()和postExec()。4.在每个测试执行时,状态消息发送回所连接的所有应用程序。执行单个测试[513]用户可能希望在一个测试计划中执行单个测试而不是所有测试。对于单个测试的执行,方法如下。1.用户应用程序向TPS发送RunTest消息;TPS向所连接的所有应用程序发送ExecutingTest消息。然后,TPS对测试计划调用executeTest(),指定要运行的测试。2.测试计划对象通过对该测试对象调用preExec()、execute()和postExec()来执行所指定的测试。3.当测试执行时,它将状态消息发送回所连接的所有应用程序。尽管本发明已经联系特定的实施方式进行了描述,但应当理解在不背离本发明主旨与范围的情况下,本领域技术人员可以进行各种修改与变更。本发明不限于前面的说明性细节,而是可以根据权利要求的范围解释。权利要求1.一种用于管理模块化测试系统中模式目标文件的方法,包括提供模块化测试系统,其中该模块化测试系统包括用于控制至少一个站点控制器的系统控制器,而且其中该至少一个站点控制器控制至少一个测试模块及其对应的被测试设备(DUT);创建用于在厂家提供的模式编译器和模块化测试系统之间建立标准接口的目标文件管理(OFM)框架;接收模式源文件;基于该模式源文件利用OFM框架创建模式目标元文件;及利用模式目标元文件通过测试模块测试所述DUT。2.如权利要求1所述的方法,其中所述OFM框架提供用于支持将厂家提供的模式数据集成到模块化测试系统中的标准接口类。3.如权利要求1所述的方法,其中所述OFM框架还配置成将来自不同厂家的特定于模块的模式数据传输到模式目标元文件。4.如权利要求1所述的方法,其中创建OFM框架包括创建用于对接厂家提供的模式编译器和测试模块的厂家模式编译器类;创建用于访问模式目标元文件类的OFM框架模块代理类,其中模式目标元文件类封装了被编译的模式目标元文件;及创建用于访问在模式编译过程中使用的其它辅助模式目标元文件的特定部分的OFM标签读取器类。5.如权利要求4所述的方法,其中创建厂家模式编译器类包括支持模式源文件的模式编译;更新模式目标元文件的特定于模块的部分;更新模式目标元文件的公共部分;及合并编译错误。6.如权利要求4所述的方法,其中创建OFM模块代理类包括支持从公共部分对厂家提供的模式编译器的读操作;支持从特定于厂家的部分对厂家提供的模式编译器的读操作;及支持从厂家提供的模式编译器到模式目标元文件的特定于模块的部分的写操作。7.如权利要求4所述的方法,其中创建OFM标签读取器类包括访问辅助模式目标元文件的标签;及访问辅助模式目标元文件的标签偏移。8.如权利要求1所述的方法,其中所述模式目标元文件包括用于表示模式源文件中基于非循环的模式块的一个或多个模式块;及用于表示模式源文件中基于循环的模式块的至多一个循环模式块。9.如权利要求1所述的方法,其中创建模式目标元文件包括初始化用于控制模式编译的OFM管理器;利用模式目标元文件类存储模式源文件的公共部分数据,其中该公共部分数据包括厂家提供的模式编译器可用的信息;为由模式目标元文件使用的每个厂家模块实例化厂家模式编译器接口,其中厂家模式编译器接口对象支持多种类型的模式块;根据厂家模式编译器接口对象获得由测试模块支持的系统资源列表;利用模式编译器编译模式源文件中的资源类型列表,以便生成公共部分数据;利用公共部分数据更新模式目标元文件;及生成编译错误与警告列表。10.如权利要求9所述的方法,其中所述模式编译器包括至少一个特定于模块的模式编译器;及目标文件管理器,用于指导每个特定于模块的编译器编译对应模式源文件的特定于模块的部分和公共部分。11.如权利要求9所述的方法,其中厂家模式编译器接口对象包括基于循环的模式编译器接口对象。12.如权利要求9所述的方法,其中厂家模式编译器接口对象包括基于非循环的模式编译器接口对象。13.如权利要求9所述的方法,其中多种类型的模式块包括选自基于循环的模式和基于非循环的模式的一个或多个项。14.一种模块化测试系统,包括系统控制器;耦合到该系统控制器的至少一个站点控制器;至少一个测试模块及其对应的被测试设备(DUT),其中测试模块是由站点控制器控制的;目标文件管理(OFM)框架,用于建立厂家提供的模式编译器与模块化测试系统之间的标准接口;用于接收模式源文件的装置;用于利用OFM框架基于模式源文件创建模式目标元文件的装置;及用于利用模式目标元文件通过测试模块测试DUT的装置。15.如权利要求14所述的系统,其中OFM框架提供用于支持将厂家提供的模式数据集成到模块化测试系统中的标准接口类。16.如权利要求14所述的系统,其中OFM框架配置成将来自不同厂家的特定于模块的模式数据传输到模式目标元文件。17.如权利要求14所述的系统,其中OFM框架还包括用于创建用于对接厂家提供的模式编译器和测试模块的厂家模式编译器类的装置;用于创建访问模式目标元文件类的OFM框架模块代理类的装置,其中模式目标元文件类封装了被编译的模式目标元文件;及用于创建访问在模式编译过程中使用的其它辅助模式目标元文件的特定部分的OFM标签读取器类的装置。18.如权利要求17所述的系统,其中用于创建厂家模式编译器类的装置包括用于支持模式源文件的模式编译的装置;用于更新模式目标元文件的特定于模块的部分的装置;用于更新模式目标元文件的公共部分的装置;及用于合并编译错误的装置。19.如权利要求17所述的系统,其中用于创建OFM模块代理类的装置包括用于支持从公共部分对厂家提供的模式编译器的读操作的装置;用于支持从特定于厂家的部分对厂家提供的模式编译器的读操作的装置;及用于支持从厂家提供的模式编译器到模式目标元文件的特定于模块的部分的写操作的装置。20.如权利要求17所述的系统,其中用于创建OFM标签读取器类的装置包括用于访问辅助模式目标元文件的标签的装置;及用于访问辅助模式目标元文件的标签偏移的装置。21.如权利要求14所述的系统,其中模式目标元文件包括用于表示模式源文件中基于非循环的模式块的一个或多个模式块;及用于表示模式源文件中基于循环的模式块的至多一个循环模式块。22.如权利要求14所述的系统,其中用于创建模式目标元文件的装置包括用于初始化控制模式编译的OFM管理器的装置;用于利用模式目标元文件类存储模式源文件的公共部分数据的装置,其中该公共部分数据包括厂家提供的模式编译器可用的信息;用于为由模式目标元文件使用的每个厂家模块实例化厂家模式编译器接口的装置,其中厂家模式编译器接口对象支持多种类型的模式块;用于根据厂家模式编译器接口对象获得由测试模块支持的系统资源列表的装置;用于利用模式编译器编译模式源文件中的资源类型列表,以便生成公共部分数据的装置;用于利用公共部分数据更新模式目标元文件的装置;及用于生成编译错误与警告列表的装置。23.如权利要求22所述的系统,其中模式编译器包括至少一个特定于模块的模式编译器;及目标文件管理器,用于指导每个特定于模块的编译器编译对应模式源文件的特定于模块的部分和公共部分。24.如权利要求22所述的系统,其中厂家模式编译器接口对象包括基于循环的模式编译器接口对象。25.如权利要求22所述的系统,其中厂家模式编译器接口对象包括基于非循环的模式编译器接口对象。26.如权利要求22所述的系统,其中多种类型的模式块包括选自基于循环的模式和基于非循环的模式的一个或多个项。27.一种模式编译器,包括至少一个特定于模块的模式编译器;目标文件管理器,用于指导每个特定于模块的编译器编译对应模式源文件的特定于模块的部分和公共部分;及模式目标元文件,其中模式目标元文件包括公共头部分和至少一个特定于模块的模式数据部分。28.如权利要求27所述的模式编译器,其中公共部分包括所有特定于模块的编译器可以访问的信息。29.如权利要求27所述的模式编译器,还包括至少一个特定于模块的模式加载器,用于将特定于模块的模式数据加载到对应的测试模块中执行。30.如权利要求27所述的模式编译器,其中模式目标元文件还包括用于表示模式源文件中基于非循环的模式块的一个或多个模式块;及用于表示模式源文件中基于循环的模式块的至多一个循环模式块。全文摘要公开了一种用于在模块测试系统中管理模式目标文件的方法。该方法包括提供一个模块测试系统,其中该模块测试系统包括一个系统控制器,用于控制至少一个站点控制器,且其中所述至少一个站点控制器控制至少一个测试模块和其对应的被测试设备(DUT)。该方法还包括创建一个目标文件管理框架,用于在设备提供商提供的模式编译器和模块测试系统之间建立一个标准接口;接收模式源文件;根据该模式源文件,使用该目标文件管理框架创建一个模式目标图元文件;以及使用该模式目标图元文件,通过测试模块测试被测试的设备。文档编号G06F11/26GK1989417SQ20058001639公开日2007年6月27日申请日期2005年5月23日优先权日2004年5月22日发明者哈森吉特·辛格,安康·普拉马尼克,马克·埃尔斯顿,田原善文,足立敏明申请人:株式会社爱德万测试
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1