CN1382280A - 用于设计可配置的处理器的自动处理器产生系统及其方法 - Google Patents

用于设计可配置的处理器的自动处理器产生系统及其方法 Download PDF

Info

Publication number
CN1382280A
CN1382280A CN00812731A CN00812731A CN1382280A CN 1382280 A CN1382280 A CN 1382280A CN 00812731 A CN00812731 A CN 00812731A CN 00812731 A CN00812731 A CN 00812731A CN 1382280 A CN1382280 A CN 1382280A
Authority
CN
China
Prior art keywords
instruction
user
processor
module
program
Prior art date
Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
Granted
Application number
CN00812731A
Other languages
English (en)
Other versions
CN1382280B (zh
Inventor
厄尔利·A·基利安
理查多·E·冈萨雷兹
阿西什·B·迪克斯特
蒙妮卡·莱姆
沃尔特·D·里奇坦斯坦
克里斯托弗·劳恩
约翰·拉坦伯格
罗伯特·P·威尔森
阿伯特·R-R·王
多尔·E·麦丹
文·K·蒋
理查德·鲁戴尔
Current Assignee (The listed assignees may be inaccurate. Google has not performed a legal analysis and makes no representation or warranty as to the accuracy of the list.)
Tensilica Inc
Original Assignee
Tensilica Inc
Priority date (The priority date is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the date listed.)
Filing date
Publication date
Priority claimed from US09/246,047 external-priority patent/US6477683B1/en
Priority claimed from US09/323,161 external-priority patent/US6701515B1/en
Priority claimed from US09/322,735 external-priority patent/US6477697B1/en
Application filed by Tensilica Inc filed Critical Tensilica Inc
Publication of CN1382280A publication Critical patent/CN1382280A/zh
Application granted granted Critical
Publication of CN1382280B publication Critical patent/CN1382280B/zh
Anticipated expiration legal-status Critical
Expired - Lifetime legal-status Critical Current

Links

Images

Classifications

    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F30/00Computer-aided design [CAD]
    • G06F30/30Circuit design
    • G06F30/32Circuit design at the digital level
    • G06F30/33Design verification, e.g. functional simulation or model checking
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F11/00Error detection; Error correction; Monitoring
    • G06F11/28Error detection; Error correction; Monitoring by checking the correct order of processing
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F11/00Error detection; Error correction; Monitoring
    • G06F11/30Monitoring
    • G06F11/3003Monitoring arrangements specially adapted to the computing system or computing system component being monitored
    • G06F11/3006Monitoring arrangements specially adapted to the computing system or computing system component being monitored where the computing system is distributed, e.g. networked systems, clusters, multiprocessor systems
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F11/00Error detection; Error correction; Monitoring
    • G06F11/36Preventing errors by testing or debugging software
    • G06F11/362Software debugging
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F13/00Interconnection of, or transfer of information or other signals between, memories, input/output devices or central processing units
    • G06F13/10Program control for peripheral devices
    • G06F13/12Program control for peripheral devices using hardware independent of the central processor, e.g. channel or peripheral processor
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F30/00Computer-aided design [CAD]
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F30/00Computer-aided design [CAD]
    • G06F30/30Circuit design
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F30/00Computer-aided design [CAD]
    • G06F30/30Circuit design
    • G06F30/32Circuit design at the digital level
    • G06F30/33Design verification, e.g. functional simulation or model checking
    • G06F30/3308Design verification, e.g. functional simulation or model checking using simulation
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F8/00Arrangements for software engineering
    • G06F8/20Software design
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F8/00Arrangements for software engineering
    • G06F8/30Creation or generation of source code
    • G06F8/37Compiler construction; Parser generation
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F8/00Arrangements for software engineering
    • G06F8/40Transformation of program code
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F9/00Arrangements for program control, e.g. control units
    • G06F9/06Arrangements for program control, e.g. control units using stored programs, i.e. using an internal store of processing equipment to receive or retain programs
    • G06F9/44Arrangements for executing specific programs
    • G06F9/455Emulation; Interpretation; Software simulation, e.g. virtualisation or emulation of application or operating system execution engines

Abstract

一种可配置的RISC处理器用高性能的固定和可变长度的编码来实现用户定义的指令集。定义新指令集的过程受到各种工具的支持,这些工具允许用户添加新指令并且对它们进行快速评估,以保持多种指令集并在它们之间进行切换。一种标准化的语言被用来开发目标指令集的可配置的各项定义以及为实现该指令集所需的硬件的HDL描述,以及用于验证和应用程序开发的各种开发工具,由此在设计过程中实现高度的自动化。

Description

用于设计可配置的处理器的自动处理器产生系统及其方法
                    发明背景
1.发明领域
本发明涉及微处理器系统,更具体地说,本发明涉及含有一个或多个处理器的一种应用程序解决方案的设计,在这里,系统中的各处理器在它们的设计过程中被这样配置和加强,以改进它们对一种特定应用程序的适用性。本发明还面向这样一个系统,在其中,应用程序开发者可以在现有指令集体系结构的基础上,快速地开发指令扩展,例如新的指令,包括控制用户定义的处理器状态的新指令,并且立即测量这样的扩展对应用程序运行时间以及对处理器周期时间的影响。
2.相关技术的说明
传统上,对处理器进行设计和修改曾经是很困难的。由于这个原因,大多数含有处理器的系统都使用为通用用途而一次设计和验证的那些(方案),然后被多种应用程序一直沿用下来。这样一来,它们对特定应用程序的适用性并不经常都是理想的。修改处理器以便较好地执行特定应用程序的代码通常是适宜的(例如,运行更快些,功耗降低些,或者成本降低些)。然而,即使修改现有处理器的设计,其困难,因而其时间、成本和风险,都是很高的,所以典型地不这样做。
为了更好地理解使现有技术的处理器变为可配置的处理器所遇到的困难,让我们考虑它的开发过程。首先,要开发其指令集体系结构(ISA)。实质上,这个步骤进行一次之后,就要被许多系统用上几十年。例如,Intel PentiumTM处理器所用的指令集可能是继承了早在1970年代中期引入的8008和8080微处理器的遗产。在这个过程中,基于预定的ISA设计规范,各ISA指令,句法等被开发出来,并且用于ISA的软件开发工具,诸如汇编程序,调试程序,编译程序等也被开发出来。随后,开发出针对特定ISA的仿真程序,各种基准测试程序被运行,以评估ISA的有效性,并且根据评估的结果,对ISA进行修改。在某几点上,ISA将被认为是满意的,并且随着一份充分开发的ISA说明书,一段ISA仿真程序,一份ISA验证程序组以及一种开发程序组,包括例如汇编程序,调试程序,编译程序等的完成,ISA过程就宣告终结了。然后,开始进行处理器设计。由于处理器可能有许多年的使用寿命,所以这个过程的执行是不频繁的—典型地,一种处理器一次设计出来后,总要被许多系统用上许多年。只要给出ISA,它的验证程序组,仿真程序以及不同处理器的各种开发目标,就能对该处理器的微体系结构进行设计、仿真和修改。一旦微体系结构被定型,它就被纳入一种硬件描述语言(HDL)之中,并且开发出一种微体系结构验证程序组,用以验证该HDL实施方案(多数在以后进行)。接着,与针对这一点而描述的手工处理相对照,自动设计工具可以基于HDL描述来合成一个电路,并对它的各元件进行布局和布线。随后可以对布局进行修改,以优化芯片面积的使用和定时。可供选择地,可以使用附加的手工处理来生成基于HDL描述的平面布置图,将HDL转换为电路,然后人工地和自动地对电路进行验证并进行布局设计。最后,使用一种自动化工具对布局进行验证,以证实它与电路相匹配,并且根据各项布局参数对各电路进行验证。
在完成处理器开发之后,对系统进行总体设计。不同于ISA和处理器的设计,系统设计(它可以包括芯片设计,现在的芯片包括处理器)是十分普通的,并且典型地对系统进行连续设计。每一种系统都被一种特定应用程序使用一段相当短的时间周期(1或2年)。基于预定的系统目标,例如成本、性能、功率和功能,事先存在的处理器说明书,芯片版型说明书(通常跟处理器经销商紧密联系),对整个系统的体系结构进行设计,选择一种处理器使之与设计目标相匹配,并选定处理器的版型(这跟处理器选择紧密联系)。
随后,给出选定的处理器、ISA、版型以及事先开发的仿真程序、验证和开发工具(还有用于所选定的版型的标准单元库),来设计该系统的实施方案,为该系统的HDL实施方案开发出一种验证程序组,并使该实施方案得以验证。其次,合成该系统的电路,在电路板上进行布局和布线,并对布局和定时进行再优化。最后,对这些板进行设计和布局,制作出各芯片,并组装各电路板。
现有技术处理器设计的另一项困难就是,由于任何给定的应用程序仅需要各项特征的一个特定的组合,以及让一个处理器拥有该项应用程序所不需要的特征将是过分昂贵的,消耗更多功率,并且更加难以制造,所以简单地设计具有更多特征的传统的处理器以覆盖所有的应用程序是不适当的。此外,当开始设计一种处理器时,还不可能知道所有的应用目标。若处理器的修改过程可以实现自动化并且很可靠,则系统设计者产生应用解决方案的能力将会显著地增强。
作为一个实例,考虑这样一种器件,它被设计用于在一条使用复杂协议的信道上发送和接收数据。由于该协议是复杂的,所以不可能全部使用硬接线(例如组合逻辑)来合理地完成处理过程,取而代之的是,将可编程处理器引入该系统用于协议处理。可编程性还允许差错固定,并且通过将新的软件装入指令存储器,就能完成日后的协议更新。然而,传统的处理器或许不是为这种特定应用程序而设计的(当设计此种处理器时,甚至该项应用程序可能尚未出现),并且它需要执行这样一些操作,这些操作需要几条指令去完成,而只要在附加的处理器逻辑中,用一条或几条指令就能完成这些操作。
由于处理器不能轻易地改进,使得许多系统设计者不打算这样做,并且改为在一种可得到的处理器上,选择执行一种低效率的纯软件解决方案。这种低效率导致一种解决方案可能更慢,或者需要更多的功率,或者成本较高(例如,它可能需要一块较大的、功能更强的处理器,以足够的速度来执行该程序)。其他设计者选择在他们为该项应用程序而设计的专用硬件中提供某些处理要求,例如一个协处理器,然后让程序员在程序的不同点上通过编码来访问该专用硬件。然而,由于只有相当大的工作单元才被足够地加速,使得通过使用专用硬件而节省的时间大于(译者注:应为小于)往返于向专用硬件传送数据所需的附加时间,所以,在处理器和专用硬件之间传送数据的时间限制了这种方案在系统优化中的使用。
在通信信道应用的实例中,该协议可能需要加密、纠错,或者压缩/解压缩处理。这样的处理通常在个别的比特上进行操作,而不是在处理器的较大的字上进行操作。用于一项计算的电路可能是适中的,但是让处理器去抽取每一个比特,顺序地对它进行处理,然后重新装入各比特,将增加可观的开销。
作为一个非常特殊的例子,考虑使用表1所示规则的哈夫曼解码(类似的编码用于MPEG压缩标准)。
    Pattern     Value     Length
    0 0 X X X X X X     0     2
    0 1 X X X X X X     1     2
    1 0 X X X X X X     2     2
    1 1 0 X X X X X     3     3
    1 1 1 0 X X X X     4     4
    1 1 1 1 0 X X X     5     5
    1 1 1 1 1 0 X X     6     6
    1 1 1 1 1 1 0 X     7     7
    1 1 1 1 1 1 1 0     8     8
    1 1 1 1 1 1 1 1     9     8
数值和长度二者都要进行计算,因此,在码流中,各length比特可以被消除,以便找到待解码的下一个元素的起点。
对一个常规的指令集来说,对此进行编码有多种方法,但是由于有很多测试需要做,并且跟组合逻辑的单门延时相对比,每一种软件实施方案都需要多个处理器周期,所以它们全都需要许多条指令。例如,一种使用MIPS指令集的有效的现有技术的实施方案可能需要6项逻辑运算,6项条件分支,1项算术运算,以及相关的寄存器装载。使用一种优化设计的指令集可使编码好一些,但是在时间方面仍然开销很大:1项逻辑运算,6项条件分支,1项算术运算,以及相关的寄存器装载。
在处理器资源方面,开销是如此之大,使得典型地要使用一份256行的对照表,来代替作为逐位比较的序列的处理过程的编码。然而,一份256行的对照表要占用大量的空间,并且访问该表可能还需要许多个周期。对于较长的哈夫曼编码来说,表的大小将变得无法使用,它将导致更加复杂和比较慢的代码。
在处理器中,迎合特殊应用要求的可能的问题解决方案就是使用可配置的处理器,它具有易于修改和扩展的指令集和体系结构,以便改进处理器的功能并实现功能的定制。可配置性允许设计者在其产品中指定是否需要或需要多少附加的功能。可配置性的最简单的一种是二进制选择:一种特征是有还是没有。例如,可以提供一种有或没有浮点硬件的处理器。
通过采用比较精细的渐进方法的配置选择,使灵活性得以改进。例如,处理器可以允许系统设计者在寄存器文件中指定寄存器的数目,存储器的宽度,高速缓冲存储器的大小,高速缓冲存储器的关联性等。然而,这些选项仍然没有达到由系统设计者按照自己的想法加以定制的水平。例如,在上面的哈夫曼解码的例子中,虽然在现有技术中,不知道系统设计者可能喜欢纳入一条专门的指令来进行解码,例如,
huff8  t1,t0在这里,结果的最高8位是解码后的数值,同时,低8位是长度。跟前面所描述的软件实施方案相对照,哈夫曼解码的直接硬件实施方案是十分简单的一除了指令解码等以外,用于组合逻辑功能的指令的解码逻辑大致上有30个门,或者是一个典型的处理器的门的数目的不到0.1%,并且可以由一个专用处理器在一个单周期中进行计算,因此,跟仅使用通用指令相比,其改进因子为4-20。
现有技术在可配置处理器产生方面的努力通常分为两类:配合参数化硬件描述而使用的逻辑合成;以及来自抽象机器描述的编译程序和汇编程序的重定目标。属于第1类的可合成的处理器硬件设计,例如Synopsys DW 8051处理器,ARM/Synopsys ARM7-S,Lexra LX-4080,ARC可配置的RISC核心;并且在某种程度上还包括Synopsys可合成的/可配置的PCI总线接口。
在上述例子中,Synopsys DW 8051包括一种现有处理器体系结构的二进制兼容的实施方案;以及小量的合成参数,例如内部RAM的128或256字节,由参数rom addr size确定的ROM地址范围,一个可选的间隔定时器,一个可变数目(0-2)的串行端口,以及一个支持6或13个源的中断单元。虽然对DW 8051的体系结构可以作出一些改变,但是在其指令集体系结构中不可能作出改变。
ARM/Synopsys ARM7-S处理器包括现有体系结构和微体系结构的二进制兼容的实施方案。它具有两个可配置的参数:高性能或低性能乘法器的选择,以及纳入调试程序和在线仿真逻辑。虽然有可能使ARM7-S的指令集体系结构发生改变,但是它们是现有的不可配置的处理器实施方案的子集,所以不需要新的软件。
LX-4080处理器具有标准的MIPS体系结构的可配置的变体,并且对指令集扩展不提供软件支持。它的选项包括一个定制引擎接口,它允许用专用操作对MIPS算术逻辑单元ALU的操作码进行扩展;一个内部硬件接口,它包括一个寄存器源和一个寄存器或16位宽的立即数源,以及目标和挂起信号;一个简单的存储器管理单元选项;3个MIPS协处理器接口;一个通往高速缓冲存储器、便笺式RAM或ROM的灵活的本地存储器接口;一个总线控制器,它将外部功能和存储器连接到该处理器自身的局部总线;以及一个可配置深度的写缓冲器。
ARC可配置的RISC核心与飞速获取数据的门计数估计之间具有一个用户接口,上述估计基于目标技术和时钟速度,指令高速缓冲存储器配置,指令集扩展,一个定时器选项,一个便笺式存储器器选项,以及存储器控制器选项;一个具有可选择的选项的指令集,例如具有送往存储器的数据块的局部便笺式RAM,专用寄存器,多达16种额外状态代码选择,一个32×32比特计分牌乘法块,一个单周期32位barrel-shifter/旋转块,一条规格化(寻找第1位)指令,直接将结果写到命令缓冲存储器(不是写到寄存器文件),一个16位MUL/MAC块以及36位累加器,以及使用线性算术的用以访问本地SRAM的滑动指针;以及通过手工编辑VHDL源代码来定义的用户指令。ARC设计没有用于实现一种指令集描述语言的装置,也不产生可配置处理器专用的软件工具。
Synopsys可配置的PCI接口包括用于安装、配置和合成活动的GUI或命令行接口;在每一个步骤中检查是否采取必要的用户动作;已选定的、基于配置(例如Verilog对VHDL)的设计文件的安装;可选择的配置,例如参数设置,并且用组合有效性的检查来向用户提示各项配置的数值,用用户更新的HDL源代码来产生HDL而不去编辑HDL源文件;以及合成功能,例如一个用户接口,它对技术库进行分析,以选择I/O缓冲器,与技术无关的约束条件以及合成稿本,缓冲器插入和针对特定技术的缓冲器的提示,并将与技术无关的公式转换为依赖于技术的稿本。由于可配置的PCI总线接口实现了各项参数的一致性检查,基于配置的安装,以及HDL文件的自动修改,所以这样的总线接口是值得注意的。
此外,现有技术的合成技术基于用户目标说明而选择不同的映射关系,允许这种映射关系对速度、功率、面积或目标部件进行优化。在这一点上,在现有技术中,在不通过整个映射过程来进行设计的前提下,不可能获得以这种方式重新配置处理器的效果的反馈。这样的反馈可以被用来引导处理器进一步的重新配置,直至达到系统设计目标为止。
在可配置处理器产生的领域中,第2类现有技术(即,编译程序和汇编程序的自动重定目标)涉及大范围的学术研究,参见例如Hanono等人所写的《在AVIV可重定目标代码发生器中的指令选择,资源配置和调度》(用于代码发生器的自动生成的机器指令的表示);Fauth等人所写的《使用nML来描述指令集处理器》;Ramsey等人所写的《在嵌入式系统中用于建立工具的机器描述》;Aho等人所写的《使用树匹配和动态编程的代码产生》(用以匹配与每一条机器指令有关的各种变换的算法,例如,相加、装载、存储、分支等,具有一系列的被表示为某些与机器无关的中间形式的程序操作,使用诸如模式匹配的各种方法);以及Cattell所写的《代码发生器的形式化和自动导出》(用于编译程序研究的机器体系结构的抽象描述)。
一旦处理器已经被设计出来,就应当对它的运作进行验证。这就是说,处理器通常使用一条流水线(其每一级都适应于指令执行的一个阶段),从一条存储的指令中来执行各项指令。因此,改变或增加一条指令或者改变配置可能需要在处理器的逻辑中作出普遍的改变,因此,多个流水线级中的每一个都可以在每一条这样的指令上来执行适当的动作。一种处理器的配置要求对它进行重新验证,并且这种验证适用于各项改变和添加。这不是一项简单的任务。各种处理器都是具有扩展的内部数据和控制状态的复杂的逻辑器件,并且控制、数据与程序的组合使得处理器验证成为一种需要的技术。处理器验证所增加的困难就是在开发适当的验证工具中的困难。由于在现有技术中,验证不是自动进行的,所以它的灵活性、速度和可靠性都低于最佳值。
此外,一旦处理器被设计出来并且经过验证,若不能容易地对它进行编程,那就不是特别有用的。通常在扩展软件工具的帮助下对处理器进行编程,上述工具包括编译程序、汇编程序、连接程序、调试程序、仿真程序和跟踪程序。当处理器发生改变时,软件工具也必须随之改变。若一条指令不能被编译、汇编、仿真或调试,则添加一条这样的指令是无益的。在现有技术中,与处理器修改和改进相关的软件改变曾经是促进处理器设计的一个主要的障碍。
因此,可以看出,由于通常典型地不是针对一种特殊应用来设计和修改各种处理器,所以现有技术的处理器设计处于一定程度的困难之中。同样,可以看出,若能够针对特殊应用来配置和扩展各种处理器,则在系统效率上就有可能取得可观的改进。还有,若能在实施方案特性(例如功耗、速度等)上使用反馈来改善处理器的设计,就能增进设计过程的效率和有效性。而且,在现有技术中,一个处理器一旦被修改,就需要进行大量的努力,来验证修改后的处理器的正确运作。最后,虽然现有技术提供有限的处理器可配置性,但是它们不能为软件开发工具的产生提供用于已配置的处理器的修整。
符合上述规范的一个系统一定是业界中的一项改进,可以作出改进—例如,需要有这样一种处理器系统,它具有对存储在专用寄存器里面的信息(即,处理器状态)进行访问或修改的各项指令,它显著地限制了可获得各项指令的范围,并因此限制了可获得的性能改进的数量。
同样,发明新的专用指令涉及在减少周期计数、添加硬件资源以及CPU周期时间影响之间作出复杂的折衷。另一个挑战就是在高性能微处理器实施方案的通常是错综复杂的细节中,在不涉及应用程序开发者的前提下,为新指令获得有效的硬件实施方案。
上述系统向用户给出设计一种跟她的应用很好地配套的处理器的灵活性。但是对于硬件和软件的交互式开发来说,仍然是很麻烦的。为了更充分地理解这个问题,考虑这样一种典型方案,该方案被许多软件设计者用来对其软件应用程序的性能进行调整。他们将典型地想到一种可能的改进,修改他们的软件以便使用这种可能的改进,重新编译他们的软件源,以便产生含有那种可能的改进的可运行的应用程序,并且随后对可能的改进进行评估。根据评估的结果,他们可以保留或抛弃这些可能的改进。典型地,整个过程可能仅在几分钟内完成。这就使用户能够自由地进行实验,快速地进行尝试并决定保留或抛弃一些想法。在某些情况下,恰当地评估一种可能的想法是很复杂的。用户可能需要在多种情况下对这种想法进行测试。在这样的情况下,用户通常保留已编译的应用程序的多种版本:一种原始版本以及含有可能的改进的另一种版本。在某些情况下,可能的改进可以是交互式的,并且用户可以保留该应用程序的两个以上的拷贝,其中的每一个都使用可能的改进的一个不同的子集。通过保留多种版本,用户就能在不同情况下,容易地重复测试不同的版本。
可配置处理器的用户喜欢以类似于软件开发者在传统的处理器上开发软件的方式来交互式地联合开发硬件和软件。考虑用户将定制的指令添加到可配置处理器中去这样的情形。用户喜欢交互式地将各种可能的指令添加到他们的处理器中去,并且在他们的特定的应用程序中测试和评估那些指令。在现有技术系统中,由于3种原因,使得这成为困难。
首先,在提出一条可能的指令之后,在获得能得益于这条指令的编译程序和仿真程序之前,用户必须等待一个小时以上。
其次,当用户希望用许多可能的指令进行实验时,用户必须为每一条指令生成和保留一个软件开发系统。软件开发系统可能十分庞大。保留许多版本可能变得无法管理。
最后,软件开发系统是为整个处理器配置的。这使得在不同工程师当中分解开发过程变得很困难。考虑两个开发者同时在一项特定的应用中进行工作这样一个实例。一个开发者可能负责决定处理器的高速缓冲存储器的特性,而另一个则负责添加定制的指令。当这两个开发者的工作联系在一起时,每一片都是充分地可分离的,使得每一个开发者都能彼此隔离地进行她的任务。高速缓冲存储器的开发者可能一开始就提出一种特殊的配置。另一个开发者开始于该项配置,并且尝试几种指令,为每一条可能的指令建立一个软件开发系统。现在,高速缓冲存储器的开发者修改已提出的高速缓冲存储器的配置。由于她的配置中的每一种都采用原来的高速缓冲存储器的配置,所以另一个开发者现在必须重建她的配置中的每一种。如果有许多开发者同时在一个项目上进行工作,要将不同的配置组织到一起可能很快就变为无法管理。
                          本发明的简述
本发明克服了现有技术的这些问题,并且它的一个目标就是提供一个这样的系统。它通过产生处理器的硬件实施方案的描述以及一组用于从相同的配置说明对处理器进行编程的软件开发工具,来自动地配置一种处理器。
本发明的另一个目标就是提供这样一个系统,它能针对不同的性能规范,对硬件实施方案和软件开发工具进行优化。
本发明的又一个目标就是提供这样一个系统,它为处理器给出不同类型的可配置性,包括可扩展性,二进制选择和参数修改。
本发明的再一个目标就是提供这样一个系统,它以一种能够容易地植入硬件的语言来描述处理器的指令集体系结构。
本发明的还一个目标就是提供这样一个系统和方法,用以开发和实现能修改处理器状态的指令集扩展。
本发明的另一个目标就是提供这样一个系统和方法,用以开发和实现能修改可配置的处理器的各寄存器的指令集扩展。
本发明的又一个目标就是允许用户通过添加新的指令来定制一种处理器配置,并且能在几分钟内评估该项特征。
通过提供一个自动处理器产生系统,能够达到上述目标,上述系统使用以标准化语言编写的定制的处理器指令集选项和扩展来开发一种目标指令集的配置定义,为实现该指令集所需的电路的硬件描述语言说明,以及各种开发工具,例如编译程序,汇编程序,调试程序和仿真程序,它们都可以被用来为该处理器生成软件以及对该处理器进行验证。可以针对不同的规范,例如面积、功耗和速度,来优化处理器电路的实施方案。一种处理器配置一旦被开发出来,它就能被测试,并且被输入到待修改的系统,以便反复地优化处理器的实施方案。
为了开发根据本发明的一个自动处理器产生系统,需要定义一种指令集体系结构描述语言,以及研制各种开发工具,诸如汇编程序,连接程序,编译程序和调试程序。这是开发过程的一部分,因为虽然大部分工具都是标准的,但是它们应当被修改为能够根据ISA描述而自动地被配置。这一部分设计过程典型地是由自动处理器设计工具本身的设计者或生产者来完成的。
一个根据本发明的自动处理器产生系统的运作如下。一个用户,例如一个系统设计者,开发一种可配置的指令集体系结构。这就是说,使用ISA定义和先前开发的工具,开发出遵循某种ISA设计目标的一种可配置的指令集体系结构。然后,为这种可配置的指令集体系结构配置开发工具和仿真程序。使用可配置的仿真器,运行基准测试,以评估可配置的指令集体系结构的有效性,并且根据评估结果来修改其核心。一旦可配置的指令集体系结构处于一种满意状态,就为它开发一种验证程序组。
在关注这个过程的软件方面的同时,该系统还通过开发一种可配置的处理器来关注硬件方面。接着,使用诸如成本、性能、功率、功能等系统目标以及关于可用的处理器生产厂家的信息,该系统设计整体的系统体系结构,它考虑到可配置的ISA选项、扩展和处理器特征。使用整体的系统体系结构、开发软件、仿真程序、可配置的指令集体系结构以及处理器的HDL实施方案,由该系统来配置处理器ISA,HDL实施方案,软件和仿真程序,并且系统的HDL被设计用于系统在一个芯片上的设计。同样,基于系统体系结构和芯片版型的说明,基于相对于系统HDL的版型能力的评估来选择芯片的版型(不像在现有技术中涉及处理器选择那样)。最后,使用该版型的标准单元库,该配置系统合成电路,对它进行布局和布线,并提供对布局和定时进行重新优化的能力。随后,若该设计不属于单片类型,则对电路板布局进行设计,制造各芯片,并组装各电路板。
如同上面所看到的那样,使用了几种技术以便于实现处理器设计过程的范围广泛的自动化。用以解决这些问题的第1项技术就是设计和实现专用的机制,它不像随意修改或扩展那样灵活,但是它仍然允许重大的功能改进。通过限制更改的随意性,与此相关的各种问题也受到约束。
第2项技术就是对各项更改提供一项单独的说明,并自动地对所有受影响的部件产生修改或扩展。由于把某件事情用手工做一次,跟编写一种工具去自动地做这件事情并使用该工具一次相比,前者通常是更廉价的,所以用现有技术设计的处理器做不到这一点。当该项任务被多次重复执行时,就能看出自动化的优点。
所使用的第3项技术就是建立一个数据库,以便为后续的用户评估的估计和自动配置提供帮助。
最后,第4项技术就是以一种适合于配置的形式来提供硬件和软件。在本发明的一个实施例中,某些硬件和软件不是直接地用标准的硬件和软件语言来编写,而是用这样一种语言来编写:通过添加一个预处理器,它允许查询配置数据库,以及具有置换、条件、复制和其他修改功能的标准硬件和软件语言的产生。然后用能够将各项改进连接进来的钩子来完成处理器的设计。
为了说明这些技术,考虑添加各项专用指令。通过将该方法限制于具有寄存器和常数操作数并产生一个寄存器结果的各种指令,就能仅用组合(无状态,无反馈)逻辑来说明各种指令的运作。这个输入指定操作码的分配、指令名、汇编程序句法,以及用于该指令的组合逻辑(各种工具由此产生):
—该处理器的指令解码逻辑,用以识别新的操作码;
—添加一个功能单元,以便在寄存器操作数上面执行组合逻辑功能;
—送往处理器的指令调度逻辑的输入,以确认仅当其操作数为有效时,才发出指令;
—汇编程序的修改,以接受新的操作码及其操作数,并产生正确的机器代码;
—编译程序的修改,增加新的内部函数,以便访问新的指令;
—反汇编程序/调试程序的修改,以便将机器代码翻译为新指令;
—仿真程序的修改,以便接受新的操作码并执行所指定的逻辑功能;以及
—诊断程序发生器,它产生直接的和随机的代码序列,用以包含和检查所增加的各项指令的结果。
以上的所有技术都被用来添加各种专用指令。输入被限制为输入和输出各操作数和逻辑以便对他们进行评估。在一处对各项更改进行描述,并且所有硬件和软件的修改都从该描述中导出。这种设置表示一个单独的输入如何能够被用来改进多个部件。
这个处理过程的结果是一个这样的系统,由于在设计过程中的更晚一些时候,在处理器和系统逻辑的其余部分之间可以作出各种折衷,所以该系统在满足应用需求方面优于现有技术。由于它的配置可以应用于更多的表示形式,所以它优于上面所讨论的多种现有技术方案。一个单独的源可以用于所有的ISA编码,软件工具和高级仿真可以纳入一个配置包,并且流程可以被设计成迭代式的以便找出各项配置数值的最佳组合。还有,前面所述的各种方法仅单独地集中于硬件配置或软件配置,而没有用于控制的单独的用户接口,或者一个用于用户引导的重新定义的测量系统,而本发明则将全部流量分配给处理器硬件和软件的配置,包括来自硬件设计和软件性能的结果,以帮助选择最佳的配置。
根据本发明的一个方面,通过提供一种自动化的处理器设计工具就能达到这些目标,上述设计工具使用以标准化语言编写的定制的处理器指令集扩展的描述,来开发目标指令集的可配置的定义,为实现该指令集所需的电路的硬件描述语言说明,以及各种开发工具,诸如编译程序、汇编程序、调试程序和仿真程序,它们可以被用来为该处理器开发各种应用,以及对它进行验证。标准化语言能够处理指令集扩展,后者修改处理器状态或使用可配置的处理器。通过提供一种受到限制的扩展和优化的领域,就能在更高的程度上实现过程的自动化,从而促进快速和可靠的开发。
根据本发明的另一个方面,通过提供一个这样的系统也能进一步地达到上述目标,在该系统中,用户能够保存多组可能的指令或状态(在下文中,可能的可配置的指令或状态的组合将被统称为“处理器改进”),并在评估它们的应用时,容易在它们之间进行切换。
用户使用在这里所描述的方法来选择和建立一个基本处理器。用户生成新的一组用户定义的处理器改进并将它们放进一个文件目录之中。然后,用户启用一种用以处理用户改进的工具,并将它们转换为基本的软件开发工具可以使用的形式。由于它仅涉及用户定义的改进并且不建立一个完整的软件系统,所以这种转换是很快的。然后用户启用基本的软件开发工具,告诉该工具动态地使用在新目录中生成的各项处理器改进。最好是,经由一个命令行选项或者经由一个环境变量,向各工具给出该目录的位置。为了进一步地简化这个过程,用户可以使用标准的软件makefiles。这些使用户能够修改它们的处理器指令,并且随后经由一条单独的make命令,来处理各项改进,并使用基本的软件开发工具,在新的处理器改进的名义下重建和评估他们的应用。
本发明克服了现有技术方案中的3种限制。给出了一组新的可能的改进,用户可以在几分钟时间内评估各项新的改进。通过为每一组生成新的目录,用户就能保存可能的各项改进的多种版本。由于该目录仅包括各项新改进的描述,而不是整个的软件系统的描述,所以所需的存储空间是最小的。最后,各项新的改进跟配置的其余部分解除连接。一旦用户已经生成了具有各项新改进的一个可能的集合的目录,她就能将该目录跟任何基本配置配合使用。
                  附图的简要说明
当结合诸附图来阅读下列详细说明时,本发明的上述和其他目标将变得更加明显,在诸附图中:
图1是一份方框图,表示在执行根据本发明的一个优选实施例的指令集的一个处理器;
图2是一份方框图,表示根据本该实施例的处理器中所使用的一条流水线的方框图;
图3表示在根据本实施例的图形用户接口(GUI)中的一种配置管理程序;
图4表示在根据本实施例的图形用户接口(GUI)中的一个配置编辑程序;
图5表示在根据本实施例的可配置性的不同类型;
图6是一份方框图,表示在该实施例的处理器配置的流程;
图7是一份方框图,表示根据本实施例的一个指令集;
图8是一份方框图,表示用于根据本发明而配置的一个处理器的一块仿真板;
图9是一份方框图,表示根据本实施例的可配置处理器的逻辑结构;
图10是一份方框图,表示将一个乘法器添加到图9的结构之中;
图11是一份方框图,表示将一个乘法累加单元添加到图9的结构之中;
图12和13这两份图表示在本实施例中的存储器的配置;以及
图14和15这两份图表示在图8的结构中的用户定义功能单元的添加;
图16是一份方框图,表示在另一个优选实施例中,介于各系统部件之间的信息流;
图17是一份方框图,表示在本实施例中,用于各种软件开发工具的定制代码是如何产生的;
图18是一份方框图,表示在本发明的另一个优选实施例中,所使用的各种软件模块的产生;
图19是一份方框图,表示在根据本实施例的一个可配置的处理器中的流水线的结构;
图20是根据本实施例的状态寄存器的实施方案;
图21是一份图,表示在本实施例中,为实现状态寄存器所需的附加逻辑;
图22是一份图,表示来自几个语义块的一种状态的下一种状态输出的组合,以及选择其中一个输入到根据本实施例的一个状态寄存器之中;
图23表示对应于根据本实施例的语义逻辑的逻辑;
图24表示在本实施例中,当被映射到用户寄存器的一个比特时,针对状态的一个比特的逻辑。
                各优选实施例的详细说明
一般来说,自动处理器产生过程开始于可配置的处理器定义以及用户指定的对它的修改,还有有待于为其配置处理器的用户指定的应用程序。此项信息被用来产生一个考虑到用户修改的可配置的处理器,以及产生软件开发工具,例如,针对它的编译程序、仿真程序、汇编程序和反汇编程序,等等。同样,使用各种新的软件开发工具对应用程序进行再编译。使用仿真程序对经过再编译的应用程序进行仿真,来产生一个软件特征文件,用以描述运行该应用程序的已配置的处理器的性能,并且就硅芯片面积利用、功耗、速度等方面对已配置的处理器进行评估,以便产生一个表征处理器电路实施方案的硬件特征文件。软件和硬件特征文件被反馈并提供给用户,以便进行进一步的迭代配置,使地处理器针对该项特定应用程序被优化。
根据本发明的一个优选实施例的自动处理器产生系统10具有4个主要部件,如图1所示:一个用户配置接口20,希望通过它来设计处理器的用户输入其可配置性和可扩展性选项以及其他设计约束条件;一套软件开发工具30,它可以被定制,以便按照用户所选择的标准来设计处理器;对处理器40的硬件实施方案的参数化的、可扩展的描述;以及一个建立系统50,它从用户接口那里接收输入数据,产生所要求处理器的定制的、可合成的硬件描述,以及修改各种软件开发工具以适应所选定的设计。最好是,建立系统50附带地产生诊断工具,用以验证硬件和软件设计,还产生一个评估器,用以评估硬件和软件的各项特性。
在本文中以及在所附的权利要求书中所使用的“硬件实施方案描述”指的是,用以描述处理器设计的物理的实施方案的各个方面的一项或多项描述,并且,单独使用或结合一项或多项其他描述,以便于根据该设计的各芯片的生产。因此,硬件实施方案描述的各部分可以处于不同层次的抽象,从诸如硬件描述语言那样的相当高级,通过网表和微代码到各项屏蔽描述。在本实施例中,硬件实施方案描述的主要部分被写入HDL、网表和稿本之中。
而且,在本文中以及在所附的权利要求书中所使用的HDL指的是一般级别的硬件描述语言,它被用来描述微结构之类,并且不打算用它来表示这种语言的任何特例。
在本实施例中,处理器配置的基础就是图2所示的体系结构60。该结构的许多元素是用户不能直接地进行修改的基本特性。这些包括处理器控制段62,调整和解码段64(虽然此段的某些部分基于用户指定的配置),ALU和地址产生段66,分支逻辑和取指令段68,以及处理器接口70。其他各单元都是基本处理器的一部分,但是可以由用户进行配置。这些包括中断控制段72,数据与指令地址监视段74和76,窗口寄存器文件78,数据与指令高速缓冲存储与标记段80,写缓冲器82和定时器84。图2所示的剩下的各段可以由用户可选地加以纳入。
处理器配置系统10的中央部件是用户配置接口20。这是一个模块,它最好是能向用户提供图形用户接口(GUI),借助于这个接口,用户有可能去选择包括编译程序重新配置以及汇编程序、反汇编程序和指令集仿真程序(ISS)在内的处理器功能;并准备用于整个处理器合成、布局和布线的的输入。它还让用户得益于处理器面积、功耗、循环时间、应用性能以及代码长度的快速评估,以便进一步地迭代和改善处理器的配置。最好是,GUI还能访问一个配置数据库,以便根据用户输入来取得默认值,并进行差错检测。
为了使用根据本实施例的自动处理器生成系统10来设计一个处理器60,用户将设计参数输入到用户配置接口20之中。自动处理器生成系统10可以是在用户控制下运行于计算机系统之上的一个孤立系统;然而,它最好是主要地运行于自动处理器生成系统10的生产厂家的控制下的一个系统之上。这样一来,就可以在一个通信网络上来提供用户访问。例如,可以使用一个具有用HTML和Java语言编写的数据输入屏幕的网络浏览器来提供GUI。这有几方面的好处,例如保持任何专有的后端软件的保密性,简化后端软件的维护和更新,等等。在这种情况下,为了访问GUI,用户首先要在系统10中进行登录,以便证明其身份。
一旦用户获准访问,系统将显示一个配置管理员屏幕86,如图3所示。配置管理员屏幕86是一份目录,其上列出了用户可访问的所有配置。图3中的配置管理员屏幕86表示用户有两种配置,“just intr”和“high pri0”,前者已经被建立,即,已被定型用于生产,而后者尚有待建立。从这个屏幕86用户可以建立一种选定的配置,对它进行删除、编辑,生成一份报告,说明已经为该种配置选择那一种配置和扩展选项,或者生成一种新的配置。对那些已经建立的配置来说,例如“just intr”,可以下载为它定制的一套软件开发工具30。
图4示出了生成一种新的配置或者对一种现有的配置进行编辑要用到图4所示的配置编辑程序88。配置编辑程序88在左边有一个“选项”选择菜单,表示可配置和可扩展的处理器60的各个大概的方面。当一个选项部分被选定时,在右边就出现针对该部分的具有各配置选项的屏幕,并且可以如业界所熟知的那样,用下拉式菜单、便笺框、检查框、收音机旋钮等来设置这些选项。虽然用户可以随机地选择各选项并输入数据,但是,由于在各部分之间存在逻辑上的依赖性,所以最好还是按照顺序逐项输入数据;例如,为了适当地显示在“中断”部分的各选项,中断的号码应当是在“ISA选项”部分中已经被选定的那些。
在本实施例中,对每一部分来说,下列的配置选项都是可用的:目标
用于评估的技术
    目标ASIC技术:.18,.25,.35微米
    目标运行条件:典型的,最坏情况
实施方案目标
    目标速度:任意
    门计数:任意
    目标功能:任意
    目标优先顺序:速度,面积功能;速度,功能,面积ISA选项
数位选项
    具有40位累加器的MAC16:是,否
    16位乘法器:是,否
除外选项
    中断的数目:0-32
    高优先级中断等级:0-14
    激活调试程序:是,否
    定时器数目:0-3
其他
    字节顺序:低位在先,高位在先
    可用于调用窗口的寄存器数目:32,64处理器高速缓冲存储器与存储器
    处理器接口读出宽度(比特):32,64,128
    写缓冲器行(地址/数值对):4,8,16,32
处理器高速缓冲存储器
    指令/数据高速缓冲存储器大小(kB):1,2,4,8,16
    指令/数据高速缓冲存储器行大小(kB):16,32,64外围部件
定时器
    定时器中断数目
    定时器中断等级调试支持
    指令地址断点寄存器数目:0-2
    数据地址断点寄存器数目:0-2
    调试中断等级
    跟踪端口:是,否
    芯片上的调试模块:是,否
    全扫描:是,否中断
    源:外部,软件
    优先等级系统存储器地址
    矢量与地址计算方法:XTOS,手工
配置参数
    RAM大小,起始地址:任意
    ROM大小,起始地址:任意
    XTOS:任意
配置专用地址
    用户除外矢量:任意
    核除外矢量:任意
    寄存器窗口溢出/下溢矢量基地址:任意
    复位矢量:任意
    XTOS起始地址:任意
    应用程序起始地址:任意TIE指令
    (定义各项ISA扩展)目标CAD环境
仿真
    VerilogTM:是,否
合成
    Design CompilerTM:是,否
布局和布线
    ApolloTM:是,否此外,系统10还提供添加其他功能单元的选项,例如32位整数乘/除单元或浮点算术运算单元;存储器管理单元;芯片上的RAM和ROM选项;高速缓冲存储器的关联性;增强的DSP及协处理器指令集;回写的高速缓冲存储器;多处理器同步;编译程序引导的推论;以及对附加的CAD封装的支持。可用于一个给定的可配置处理器的那些配置选项,最好是在一份定义文件(例如附录A所示的那一种)中将它们列出,以便一旦用户选定适当的选项时,系统10将其用于句法检查等。
从以上所述可以看出,自动处理器配置系统10向用户提供两种宽广类型的可配置性300,如图5所示:可扩展性302,它允许用户从搜索中定义任意的功能和结构,以及可修改性304,它允许用户从预定的、受约束的选项集里面进行选择。在可修改性的范围内,系统允许某些特性的二进制选择306,例如,应当将一个MAC16还是一个DSP添加到处理器60以及其他处理器特性的参数说明308,后者例如中断的数目和高速缓冲存储器的大小。
在上述配置选项中,许多都是专业人士熟悉的;然而,还有另外一些值得关注。例如,RAM和ROM选项允许设计者将便笺式存储器或固件纳入到处理器本身。处理器10可以从这些存储器中取指令或读写数据。存储器的大小和位置是可配置的。在本实施例中,这些存储器中的每一个都是作为在一个集合关联的高速缓冲存储器中的一个附加集而被访问的。通过跟一个单独的标记行进行比较,就能检出在存储器中的一次命中。
由于每一个高优先等级中断需要3个专用寄存器,开销较大,所以系统10为中断(实现各种1级中断)以及高优先等级中断选项(实现2-15级中断以及各种不可屏蔽中断)提供独立的配置选项。
具有40位累加器选项的MAC16(示于图2的90)添加了一种16位的乘法器/加法器功能,后者具有一个40位的累加器、8个16位操作数寄存器以及一组复合指令,它将乘法、累加、操作数装载以及地址更新指令组合在一起。可以在与乘法/累加运算并行的条件下,从存储器中将成对的16位数装载到操作数寄存器。这个单元能够支持每个周期两次装载和1次乘法/累加运算的各种算法。
芯片上的调试模块(示于图2中的92)被用来通过JTAG端口94去访问处理器60内部的、软件可见的状态。模块92为除外情况的产生提供支持,使处理器60进入调试方式;访问所有的程序可见存储器或存储器位置,执行处理器60被配置去执行的任何指令;修改程序计数器PC使其跳到在代码中的所需位置;以及一段应用程序,它允许返回到正常运算方式,这种方式是从处理器60外部,经由JTAG端口94来触发的。
一旦处理器10进入调试方式,它就从外部世界等待关于一条有效的指令已经经由JTAG端口94被扫描进来的指示。一旦处理器10的硬件实现已经被生产出来,模块92就被用来调试该系统。可以经由运行于一部远方主机之上的调试程序来控制处理器10的执行。调试程序经由JTAG端口94跟处理器建立接口,并使用芯片上的调试模块92的能力来确定和控制处理器10的状态以及控制各指令的执行。
可以配置多达3个32位记数器/定时器84。这使得32位寄存器的使用令每一个时钟周期以及(对每一个已配置的定时器来说)比较寄存器都增加1,比较器将比较寄存器的内容跟当前时钟寄存器的计数加以比较,用于中断和类似的功能。记数器/定时器可以被配置为边沿触发,并能产生普通的和高优先等级的内部中断。
推断选项通过让装载随机应变地移动,以控制流量,使之流向它们不经常被执行的地方,来提供编译程序在调度上的更大的灵活性。由于装载可能导致除外情况,这样的装载移动可能会把除外情况引入到一段原先没有出现的有效程序之中。当装载被执行时,随机应变的装载能避免这些除外情况的出现,但当需要数据时,就提供一种除外情况。取代为一次装载差错而导致一种除外情况,随机应变的装载令目标寄存器的有效位复位(与该选项有关的新的处理器状态)。
虽然核心处理器60最好具有某些基本的流水线同步能力,但当一个系统使用多个处理器时,需要介于各处理器之间的某种通信或同步。在某些情况下,使用诸如输入和输出队列那样的自同步通信技术。在其他情况下,共享存储器模型被用于通信,并且由于共享存储器不提供所需的语义,所以有必要提供支持同步的指令集。例如,可以添加具有获得和释放语义(功能)的装载和存储指令。在那些不同的存储器位置可能被用于同步和数据,使得在各同步引用之间必须保持精确的顺序这样的多处理器系统中,这对于控制存储器引用的顺序是有用的。其他指令可以被用来生成业界所熟知的信号。
在某些情况下,共享存储器模型被用于通信,并且由于共享存储器不提供所需的语义,所以有必要提供支持同步的指令集。通过多处理器同步选项来完成这一点。
在各配置选项中,最重要的也许就是TIE指令的定义了,由此建立设计者定义的指令执行单元96。位于加州Santa Clara的Tensilica公司开发的TIETM(Tensilica指令集扩展)允许用户以扩展和新指令的形式为其应用程序描述定制的各项函数,以便扩充基本的ISA。此外,由于TIE的灵活性,它可以被用来描述用户不能改变的ISA部分;这样一来,整个ISA可以被用来一致地产生软件开发工具30以及硬件实施方案描述40。TIE说明使用多个积木块,对各新指令的属性描述如下:
—指令字段               —指令类
—指令操作码             —指令语义
—指令操作数             —常数表
指令字段语句field被用来改进TIE代码的可读性。各字段是集合在一起并且用一个名字来引用的其他各字段的子集或连锁。在一条指令中,各比特的全集就是最高级的超集字段inst,并且这个字段可以划分为几个较小的字段。例如,
field x             inst[11:8]
field y        inst[15:12]
field xy       {x,y}将两个4位字段,x和y,定义为最高级字段inst的子字段(分别是,比特8-11和12-15),并将一个8位字段xy定义为x和y两个字段的连锁。
语句opcode为各编码专用字段定义各操作码。打算用来指定各操作数(例如各寄存器或各立即常数)的各指令字段,若准备为这样定义的各操作码所使用,则首先必须用字段语句加以定义,然后用操作数语句加以定义。
例如,
opcode  acs    op2=4’b0000  CUST0
opcode  adse1  op2=4’b000 1  CUST0根据先前定义的操作码CUST0(4’b0000表示一组4位长的二进制常数0000)来定义两组新的操作码,acs和adse1。优选核心ISA的TIE说明具有下列语句
field op0    inst[3:0]
field op1    inst[19:16]
field op2    inst[23:20]
opcode       QRST  op0=4’b0000
opcode       CUST0 op1=4’b1000 QRST作为它的基本定义的一部分。因此,acs和adse1的定义使得TIE编译程序产生分别由下列语句表示的指令解码逻辑:
inst[23:0]=0000 0110 xxxx xxxx xxxx 0000
inst[23:0]=0001 0110 xxxx xxxx xxxx 0000
指令操作数语句operand标识各寄存器和立即常数。然而,在将一个字段定义为一个操作数之前,它应当事先已经被定义为一个如上所述的字段。若该操作数是一个立即常数,则可以从该操作数产生该常数的值,或者它可以从如下所述的一份事先定义的常数表中取值。例如,为了对一个立即操作数进行编码,TIE代码
    field          offset    inst[23:6]

    operand        offests4  offset{

         assign    offsets4={{14{offset[17]}},offset}<<2;

    } {

         wire    [31:0]t;

      assign  t=offsets4>>2;

      assign  offset=t[17:0];

    }
定义一个名为offset的18位的字段,它保存一个带符号的数以及一个操作数offsets4,它是存储在offset字段之中的数的4倍。Operand语句的最后部分实际上描述在VerilogTM HDL的一个子集中用以进行计算的电路,上述HDL是用来描述组合电路的,正如专业人士所熟知的那样。
这里,wire语句定义一组宽度为32位的名为t的逻辑接线。在wire语句之后的第1个assign语句指定驱动逻辑接线的逻辑信号是向右移位的常数offsets4,并且第2个assign语句指定t的低18位被放进offset字段。第1个assign语句直接地指定作为offset的一个连锁的操作数offsets4的值,并且其符号位(位17)的14个复制品被一个左移两位所跟随。
对一个常数表操作数来说,TIE代码
  table prime 16 {

        2,3,5,7,9,11,13,17,19,23,29,31,37,41,43,47,

  53

  }

  operand        prime_s    s {

       assign    prime_s=prime[s];

  } {

       assign s=prime_s==prime[0]  ?    4′b0000:

                 prime_s==prime[1]  ?    4′b0001:

                 prime_s==prime[2]  ?    4′b0010:

                 prime_s==prime[3]  ?    4′b0011:

                 prime_s==prime[4]  ?    4′b0100:

                 prime_s==prime[5]  ?    4′b0101:

                 prime_s==prime[6]  ?    4′b0110:

                 prime_s==prime[7]  ?    4′b0111:

                 prime_s==prime[8]  ?    4′b1000:
				
				<dp n="d25"/>
           prime_s==prime[9]     ?    4′b1001:
           prime_s==prime[10]    ?    4′b1010:
           prime_s==prime[11]    ?    4′b1011:
           prime_s==prime[12]    ?    4′b1100:
           prime_s==prime[13]    ?    4′b1101:
           prime_s==prime[14]    ?    4′b1110:

                                       4′b1111;
利用table语句来定义一个常数数组prime(跟随在表名字之后的数字是表中各元素的号码),并且使用操作数s作为进入该表prime的一个索引,用以为操作数prime_s编码一个数值(注意在定义索引时VerilogTM各语句的使用)。
指令类语句iclass在一种公共格式中将各操作码和各操作数联系在一起。在语句iclass中定义的所有指令都具有相同的格式和操作数用途。在定义一个指令类之前,它的各成分应当首先被定义为字段,然后被定义为操作码和操作数。例如,在前面定义操作数acs和adse1的实例中所使用的代码的基础上,建立附加的语句
operand art t  {assign art=AR[t];}  {}
operand ars s  {assign ars=AR[s];}  {}
operand arr r  {assign AR[r]=arr;}  {}使用operand语句来定义3个寄存器操作数art,ars和arr(再次注意在此项定义中VerilogTM各语句的使用)。随后,iclass语句iclass Viterbi{adse1,acs}{out arr,in art,in ars}指定操作数adse1和acs属于指令viterbi的共同类,上述指令viterbi取两个寄存器操作数art和ars作为输入,并且将输出写入到寄存器操作数arr之中。
指令语义语句semantic描述使用VerilogTM(用于对操作数进行编码)的相同子集的一条或多条指令的行为。通过在一条单独的语义语句中定义多条指令,可以共享某些共同的表达式,并且硬件实施方案可以变得更加有效。在语义语句中允许使用的变量是针对在语句的操作码列表中所定义的各操作码的各操作数,以及在操作码列表中为每一个操作码指定的一个单比特变量。这个变量具有与操作码相同的名字,并且当该操作码被检出时,它估值为1。它被用于计算部分(VerilogTM子集部分),用以指示相应指令的出现。
例如,TIE代码定义一条新指令ADD8_4,它将一个32位字中的4个8位操作数跟在另一个32位字中对应的4个8位操作数相加;还定义了另一条新指令MIN16_2,它在一个32位字中,进行两个16位操作数的最小值的选择,并且在另一个32位字中,可以读出各自的16位操作数:
  opcode ADD8_4  op2=4’b0000 CUST0

  opcode MIN16_2 op2=4’b0001 CUST0

  iclass add_min{ADD8_4,MIN16_2}{out arr,in ars,in art}

  semantic add_min{ADD8_4,MIN16_2}(

       wire[31:0]add,min;

       wire[7:0]add3,add2,addl,add0;

       wire[15:0]min1,min0;

       assign add3=art[31:24]+ars[31:24];

       assign add2=art[23:16]+ars[23:16];

       assign add1=art[15:8]+ars[15:8];

       assign add0=art[7:0]+ars[7:0];

       assign add={add3,add2,add1,add0};

       assign min1=art[31:16]<ars[31:16]?art[31:16]:

  ars[31:16];

       assign min0=art[15:0]<ars[15:0]?art[15:0]:

  ars[15:0];

       assign min={min1,min0};

       assign arr=(({32{{ADD8_4}}}) &amp; (add))|

  (({32{{MIN16_2}}}) &amp; (min));

  }
在这里,op2,CUST0,arr,art和ars是如上面所指出的预定义操作数,并且opeode和iclass语句起着如上所述的作用。
Semantic语句指定由新指令进行的计算。正如专业人士所熟知的那样,Semantic语句中的第2行指定由新的ADD8_4所进行的计算,其中的第3和第4行指定由新的MIN16_2进行的计算,并且该程序段的最后一行指定将结果写入arr寄存器。
回到用户输入接口20的讨论,一旦用户已经输入了她所需要的配置和扩展选项,建立系统50就接着往下进行。如图5所示,建立系统50接收由用户设置的各参数组成的配置说明以及由用户设计的可扩展的各项特征,并将它们跟定义核心处理器体系结构的各项附加参数(例如,用户不能修改的各项特征)组合在一起,以生成描述整个处理器的配置说明100。例如,除了用户选择的配置设置102之外,建立系统50还可以添加各项参数,用以为处理器的物理地址空间指定物理地址的位数,处理器60在复位之后待执行的第1条指令,等等。
为了说明在可配置的处理器中作为核心指令而实现的各项指令以及经由配置选项的选择成为可用的各项指令的实例,由Tensilica公司提供的《XtensaTM指令集体系结构(ISA)参考手册》(修订1.0版)已作为参考文献被收入本文。
配置说明100还包括一个ISA封装,其中包括指定基本ISA的TIE语言语句,用户已经选择任何附加的封装,例如协处理器封装98(见图2)或者一个DSP封装,以及由用户提供的任何TIE扩展。此外,配置说明100还可以具有多种语句设置标志,表示某些结构特征是否有待于纳入处理器60之中。例如
IsaUseDebug                    1
IsaUseInterrupt                1
IsaUseHighPriorityInterrupt    0
IsaUseException                1表示该处理器将包括芯片上的调试模块92,中断装置72以及除外情况管理,但不包括高优先等级中断装置。
使用配置说明100能自动地产生下列各项:
—处理器60的指令解码逻辑;
—用于处理器60的非法指令检测逻辑;
—汇编程序110的ISA专用部分;
—编译程序108的ISA专用支持程序;
—反汇编程序110的ISA专用部分(为调试程序所使用);以及
—仿真程序112的ISA专用部分。
由于一种重要的配置能力就是指定指令的封装的纳入,所以自动地产生这些项目是有价值的。对某些事情来说,若指令已经被配置,则在每一种工具中,有可能用条件代码来实现这一步,以管理该指令,但是这是不好用的;更重要的是,它不允许系统设计者容易地为他的系统添加指令。
除了将配置说明100作为来自设计者的输入以外,还有可能接受各项目标,并且让建立系统50自动地确定配置。设计者可以为处理器60指定各项目标。例如,时钟频率、面积、成本、典型功耗以及最大功耗等都可以成为目标。由于某些目标存在矛盾(例如,通常仅通过增加面积或功耗或二者同时增加来提高性能),随后,建立系统50向搜索引擎106进行咨询,以确定可用的配置选项的集合,并且确定如何从企图同时达到各项输入目标的一种算法那里设置每一个选项。
搜索引擎106包括一个数据库,它具有描述各种量度的影响的各行。各行可以指定一种特定的配置设置在一种量度上具有加法的、乘法的或限制的效果。各行还可以被标记为需要其他的配置选项作为先决条件,或者被标志为跟其他各选项不兼容。例如,简单的分支判断选项可以为每一条指令的周期数(CPI—性能的一种决定因素)指定乘法的或加法的效果、对时钟频率的限制,对面积的加法效果、以及对功率的加法效果等。它可以被标记为跟一种偏好的分支判断程序不兼容,并且依赖于将取指令队列的大小设置为至少两行。这些效果的数值可以是一项参数(例如分支判断表的大小)的一个函数。一般来说,用可以估值的各种函数来表示数据库的各行。
不同的算法可能用于寻找最接近于达到各项输入目标的配置设置。例如,一种简单的背包封装算法按照数值除以成本的排序来考虑每一个选项,并且接受任何能增加数值同时将成本限制在指定限值以下的选项说明。这样一来,例如,为了使性能最大化,同时保持功率低于一个指定数值,可以按照性能除以功率对各选项进行排序,并且接受能增加性能但不超出功率限值的每一个选项。更复杂的各种背包算法提供某种程度的回溯。
一种用于从目标和设计数据库来确定配置的很不同的算法种类基于模拟退火。各项参数的一个随机初始集被用来作为起始点,然后通过评估一个全局的应用程序函数来确定接受或拒绝个别参数的改变。当根据一个阈值(随着优化的进行,该阈值降低)概率地接受负的改变时,应用程序函数的改进通常被接受。在这个系统中,从各项输入目标来构建应用程序函数。例如,给定的各项目标为:性能>200,功率<100,面积<4,按照功率、面积,和性能的优先顺序,可以使用下列的应用程序函数:
      Max((1-Power/100) * 0.5,0)+(max((1-Area/4) * 0.3,0)*

  (if Power<100 then 1 else(1-Power/100)**2))+

  (max(Performance/200 * 0.2,0) * (if Power<100 then 1 else

  (1-Power/100)**2)) * (if Area<4 then 1 else (1 -

  area/4)**2))
它回报功耗的降低,直到它低于100,随后为中性,回报面积的减少直到它低于4,随后为中性,并且回报性能的提高,直到它高于200,随后为中性。还有这样的部件:当功率超出指定值时,减少面积的使用,当功率或面积超出指定值时,降低性能的使用。
这两种算法以及其他算法都可以被用来搜索满足指定目标的各种配置。重要的是可配置处理器的设计已经在一个设计数据库中加以说明,该数据库具有先决条件以及各项不兼容性选项的说明,以及各配置选项对不同量度的影响。
我们给出的实例已经使用各项硬件目标,这些目标是一般的,并且不依赖于运行于处理器60之上的特定算法。所描述的算法还可以被用来选择跟特定的用户程序相配套的配置。例如,用户程序可以运行于具有高速缓冲存储器的精确的仿真器之上,以测量不同类型的高速缓冲存储器的数目,这些高速缓冲存储器具有不同的特性,诸如不同的大小,不同的线宽以及不同的设置关联性。这些仿真的结果可以被添加到搜索算法106所使用的数据库中去,上述算法被描述用以帮助选择硬件实施方案说明40。
类似地,可以针对某些指令的出现来修饰用户算法,上述指令可以任选地被植入到硬件之中。例如,若用户算法花费大量时间来进行乘法运算,则搜索引擎106可以自动地建议纳入一个硬件乘法器。这样的算法不需要局限于考虑一种用户算法。用户可以将一组算法送入系统,并且搜索引擎106可以选择这样一种配置,平均来说,这样的配置对用户程序的集合是有用的。
除了选择处理器60的预配置特性以外,搜索算法还可以被用来自动地选择或向用户建议可能的TIE扩展。给出各项输入目标,并且给出可能用C编程语言编写的用户程序的实例,这些算法就会建议可能的TIE扩展。对于没有状态的TIE扩展来说,可以用模式匹配程序来嵌入类似于编译程序的各种工具。这些模式匹配程序按照自底向上方式在表达式节点中搜索能用一条单字接指令来代替的多字节指令模式。例如,用户C程序含有下列语句:
x=(y+z)<<2;
x2=(y2+z2)<<2;
模式匹配程序将发现该用户在两个不同位置上将两个数相加,并将结果左移两位。系统将产生一条TIE指令(两数相加并将结果左移两位)的可能性添加到数据库之中。
建立系统50跟踪许多条可能的TIE指令,连同它们出现多少次的一个计数。使用一种跟踪工具,系统50还跟踪在该算法的整个执行过程中,每一条指令被执行的频繁程度。使用一个硬件仿真器,系统50跟踪为了实现每一条可能的TIE指令,硬件的开销有多大。这些数字被送入搜索试探算法,以便选择一组能使各项输入目标最大化的可能的TIE指令;上述目标例如性能,代码大小,硬件复杂性等等。
类似的然而更强有力的算法被用来发现具有状态的可能的TIE指令。几种不同的算法被用来检出不同类型的机会。一种算法使用类似编译程序的工具来扫描用户程序,并且检测该用户程序是否需要比硬件所能提供的更多的寄存器。正如业界的许多从业者所熟知的那样,通过对寄存器溢出的计数,就能检出这种情况,并且以用户代码的编译后的样式加以恢复(取出)。类似于编译程序的工具向搜索引擎建议一个具有附加硬件寄存器98的协处理器,但是它仅支持用于用户代码的、具有多次溢出和恢复的部分的运算。该工具负责通知搜索引擎106所使用的数据库称:关于协处理器的硬件成本的估计以及关于用户算法性能如何的估计已经得到改进。如上所述,搜索引擎106对所建议的协处理器98是否能导致更好的配置这一点作出全局的判断。
可供选择地,或者与之相结合,类似于编译程序的工具检查用户程序是否使用位屏蔽操作,以保证某些变量永不大于某些限值。在这种情况下,该工具向搜索引擎106建议一个使用与用户限值(例如,12位或20位或任何其他大小的整数)相一致的数据类型的协处理器98。在另一个实施例中所使用的第3种算法,用于以C++语言编写的用户程序,类似于编译程序的工具发现很多时间都消耗在对用户定义的抽象数据类型的运算上。若所有运算都基于适用于TIE的数据类型,则该算法向搜索引擎提出在该种数据类型上,用一个TIE协处理器来实现所有的运算。
为了生成处理器60的指令解码逻辑,为在配置说明中所定义的每一组操作码产生一组信号。通过简单地将下列语句
opcode NAME FIELD=VALUE重写到HDL语句
assign NAME=FIELD=VALUE;以及将
opcode NAME FIELD=VALUE PARENTNAME[FIELD2=VALUE2]重写到
assign NAME=PARENTNAME & (FIELD==VALUE)就能产生该代码。
寄存器互锁以及流水线信号的产生也已经实现自动化。这种逻辑也基于配置说明中的信息而产生。基于包含在iclass语句中的寄存器使用信息以及该指令的潜在因素,当当前指令的源操作数依赖于尚未完成的一条先前的指令的目标操作数时,已产生的逻辑插入一个挂起(或气泡)。实现这种挂起功能的机制作为核心硬件的一部分而实现。
通过对个别的已产生的指令信号进行或非运算,并将其结果跟它们的字段约束条件进行与运算,来产生非法指令检测逻辑:
assign illegalinst=!(INST1|INST2…|INSTn);
各指令解码信号以及非法指令信号可用作解码模块的输出以及作为手写处理器逻辑的输入。
为了产生其他的处理器特征,本实施例使用可配置处理器60的VerilogTM描述,并且用一种基于Perl的预处理器语言加以强化。Perl是一种全特征语言,其中包括复杂的控制结构、子程序和I/O装置。在本发明的一个实施例中被称为TPP(如在附录B的源程序列表中所示,TPP本身是一段Perl程序)的预处理器,扫描它的输入,把某些行标识为用预处理器语言(Perl用于TPP)编写的预处理器代码(以分号为前缀的那些用于TPP),并且构建一段程序,其中包括已抽取的行和语句,以产生其他行的文本。非预处理器的行可以具有嵌入的表达式,在其位置上,作为TPP处理的结果而产生的表达式被置换。然后,执行所得到的程序以产生源代码,即,用以描述详细的处理器逻辑40的VerilogTM代码(正如在下面将要看到的那样,TPP也被用来配置软件开发工具30)。
当用于这种场合,由于它允许将诸如配置说明查询、条件表达式以及迭代结构那样的结构纳入到VerilogTM代码之中,以及如前面所指出的那样,允许根据在VerilogTM代码之中的配置说明100来实现嵌入的表达式,所以TPP是一种强有力的预处理语言。例如,基于数据库查询的的TPP分配类似于
;$endian=config_get_value(“IsaMemoryOrder”)
在这里,config_get_value是用以查询配置说明100的TPP函数,IsaMemoryOrder是在配置说明100中设置的一个标志,并且$endian是将在以后用来生成VerilogTM代码的一个TPP变量。
TPP条件表达式可以是
;if(config_get_value(“IsaMemoryOrder”)eq“LittleEndian”)
;{按照低位在先顺序执行VerilogTM代码}
;否则
;{按照高位在先顺序执行VerilogTM代码}可以用TPP结构来实现迭代循环,例如
;for($i=0;$i<$ninterrupts;$i++)
;{do VerilogTM code for each 0f 1...N interrupts}在这里,$i是一个TPP循环索引变量,$ninterrupts是为处理器60指定的中断的数目(使用config_get_value从配置说明100中获得)。
最后,可以将TPP代码嵌入到VerilogTM表达式,例如
wire[`$ninterrupts-1`:0]srInterruptEn;
xtscenflop #(`$ninterrupts`)srintrenreg(srInterruptEn,
srDataIn W[`$ninterrupts-1`:0],srIntrEnWEn,!cReset,CLK);在这里,$ninterrupts定义中断的数目并确定xtscenflop模块(一个触发器原始模块)的宽度(用比特来表示);
srInterruptEn是触发器的输出,被定义为一串适当数目的比特;
srDataIn_W是触发器的输入,但是根据中断的数目仅输入有关的比特;
srIntrEnWEn是触发器的写使能信号;
cReset是送往触发器的清除输入;以及
CLK是送往触发器的输入时钟。
例如,给出下列送往TPP的输入:
  ;              #                    Timer             Interrupt

  ;              if                   ($IsaUseTimer)            {

  wire                    [`$width-1`:0]                srCCount;

  wire                                                  ccountWEn;

  //--------------------------------------------------------------

  -

  //                      CCOUNT                          Register

  //--------------------------------------------------------------

  -

  assign ccountWEn=srWEn_W &amp;&amp; (srWrAdr_W==`SRCCOUNT);

  xtflop # (`$width`)srccntreg(srCCount,(ccountWEn?srDataIn_W:

  srCCount+1),CLK);

  ;      for       ($i=0;    $i<$TimerNumber;   $i++)       {

  //--------------------------------------------------------------

  -

  //                       CCOMPARE                       Register

  //--------------------------------------------------------------

  -

  wire                [`$width-1`:0]              srCCompare`$i`;

  wire                                               ccompWEn`$i`;

  assign ccompWEn`$i`=srWEn_W &amp;&amp; (srWrAdr_W==`SRCCOMPARE`$i`);

  xtenflop               #(`$width`)                 srccmp`$i`reg

  (srCCompare`$i`,srDataIn_W,ccompWEn`$i`,CLK);

  assign setCCompIntr`$i`=(srCCompare`$i`==srCCount);

  assign clrCCompIntr`$i`=ccompWEn`$i`;

  ;}

  ;} ## IsaUseTimer
and the declarations

      $IsaUseTimer=1

      $TimerNumber=2

      $width=32
TPP generates

  wire                       [31:0]                     srCCount;

  wire                                                  ccountWEn;

  //--------------------------------------------------------------

  -

  //                         CCOUNT                       Register

  //--------------------------------------------------------------

  -

  assign ccountWEn=srWEn_W &amp;&amp; (srWrAdr_W==`SRCCOUNT);

  xtflop #(32) srccntreg(srCCount,(ccountWEn ?srDataIn_W:

  srCCount+1),CLK);

  //--------------------------------------------------------------

  -

  //                         CCOMPARE                     Register

  //--------------------------------------------------------------

  -

  wire                       [31:0]                  srCCompare0;

  wire                                                  ccompWEn0;
				
				<dp n="d35"/>
  assign ccompWEn0=srWEn_W &amp;&amp; (srWrAdr_W==`SRCCOMPARE0);

  xtenflop #(32) srccmp0reg

  (srCCompare0,srDataIn_W,ccompWEn0,CLK);

  assign setCCompIntr0=(srCCompare0==srCCount);

  assign clrCCompIntr0=ccompWEn0;

  //-------------------------------------------------------------

  -

  //                        CCOMPARE                     Register

  //--------------------------------------------------------------

  -

  wire                      [31:0]                    srCCompare1;

  wire                                                   ccompWEn1;

  assign ccompWEn1=srWEn_W &amp;&amp; (srWrAdr_W==`SRCCOMPARE1);

  xtenflop                  #(32)                 srccmp1reg

  (srCCompare1,srDataIn_W,ccompWEn1,CLK);

  assign setCCompIntr1=(srCCompare1==srCCount);

  assign clrCCompIntr1=ccompWEn1;
这样产生的HDL描述114被用来合成用于实现处理器的硬件,例如在程序块122中使用由Synopsys公司制作的DesignCompilerTM。然后,在程序块128中使用例如由Cadence公司提供的Silicon EnsembleTM或者由Avent!公司提供的ApolloTM对结果进行布局和布线。一旦各部件已经被布线完毕,在程序块132中,使用例如由Synopsys公司提供的PrimeTimeTM,将其结果用于接线的反向注释和定时验证。这样处理的产物就是一个硬件特征文件134,它可以被用户用来向配置俘获程序20提供进一步的输入,以便进行进一步的配置迭代。
正如前面结合逻辑合成部分122所说明的那样,配置处理器60的结果之一就是一组定制的HDL文件,通过使用多种商业的合成工具中的任何一种,就能从中获得专用的门一级的实施方案。Synopsys公司提供的Design CompilerTM就是这样一种工具。为了保证正确的和高性能的门一级的实施方案,本实施例提供了在客户环境中为使合成过程自动化所需的稿本。在提供这样的稿本时,所面临的挑战就是支持多种合成方法学和不同用户的实施目标。为了迎接第1种挑战,本实施例将稿本切分为较小的和功能上完整的稿本。一个这样的实例就是提供一个读稿本,它能读出与特定的处理器配置60有关的所有HDL文件,并提供一个定时约束稿本来设置在处理器60中的唯一的定时要求,以及一个稿本,它以能够用于门一级网表的布局和布线的方式写出合成结果。为了迎接第2种挑战,本实施例为每一种实施目标提供一种稿本。一个这样的实例就是提供一种用以获得最快的循环时间的稿本,一种用以获得最小硅片面积的稿本,以及一种用以获得最低功耗的稿本。
在处理器配置的其他阶段也使用这些稿本。例如,处理器60的HDL模型一旦被写出,就可以用一段仿真程序来验证处理器60的正确运行,如同前面结合程序块132所说明的那样。通常,通过在被仿真的处理器60中运行多种测试程序或诊断程序来完成这一步。在被仿真的处理器60中运行一种测试程序可能需要许多步骤,例如产生测试程序的一个可执行的图像,产生可以被仿真程序112读出的可执行的图像的一种表示,生成一个暂时的布局以便收集仿真结果,供以后分析之用,分析仿真结果,等等。在现有技术中,使用多个丢弃的稿本来完成这一步。这些稿本具有关于仿真环境的内含知识,例如应当纳入哪一个HDL文件,在目录结构中何处能找到这些文件,在测试台中需要哪些文件,等等。在当前设计中,优选的机制就是编写一个由参数置换而配置出来的稿本样板。这种配置机制也使用TPP来产生在仿真中所需的文件的列表。
而且,在程序块132的验证过程中,通常需要编写其他的稿本,以便让设计者运行一系列的测试程序。通常被用来运行回归程序组,它使设计者相信在HDL模型中的给定的改变不会引入新的差错。由于回归稿本有许多内含的关于文件名、位置等的假设,所以它们也经常被丢弃。如上所述,针对一个单独的测试程序,为了生成一个运行稿本,将回归稿本写成一个样板。在配置时,通过将各项参数置换为实际数值来配置该样板。
将RTL描述转换为硬件实施方案的过程的最后一个步骤就是使用布局和布线(P&R)软件将抽象的网表转换为几何表示。P&R软件分析网表的连接性并且决定各单元的定位。然后它尝试去描画介于所有单元之间的连接。时钟网通常受到特殊的注意并且作为最后一个步骤进行布线。这个过程可能受助于向各工具提供某些信息,例如希望将哪些单元靠拢在一起(称为软件集群),各单元的相对位置,希望哪些网具有小的传播延时,等等。
为了使这个过程变得更容易以及保证符合所需的性能目标—循环时间,面积,功耗—配置机制为P&R软件产生一组稿本或输入文件。这些稿本还含有诸如需要多少根电源与接地连线,这些连线应当如何沿着边界分布,等等。通过查询一个数据库来产生这些稿本,在该数据库中,含有关于要生成多少软件集群,以及哪些单元应当纳入它们之中,哪些网在定时上是重要的,等等。这些参数根据已经选择哪些选项而发生改变。这些稿本必须是根据准备用来进行布局与布线的各种工具来加以配置的。
可选地,该配置机制可以从用户那里请求更多的信息,并将其送往P&R稿本。例如,接口可以向用户要求最终布局所需的纵横比,在时钟树中应当插入多少个缓冲级,输入和输出引脚应当设置在哪一面,这些引脚相对的或绝对的位置,电源和接地母线的宽度和位置,等等。然后这些参数将被送往P&R稿本,以产生所需的布局。
可以使用更加复杂的稿本,它支持例如更加复杂的时钟树。一种用以降低功耗的普通的优化方案就是对时钟信号进行门控。然而,由于要平衡所有分支的延时是比较困难的,所以这使得时钟树的合成成为一个更加困难的问题。配置接口会向用户要求正确的各单元用于时钟树,并进行部分或全部的时钟树合成。通过获知在该项设计中各门控时钟位于何处,以及评估从缓冲门(qualifying gate)到各触发器的时钟输入端之间的延时,就能做到这一步。然后,它将对时钟树合成工具给出一项约束条件,即时钟缓冲器的延时要跟各门控单元的延时相匹配。在当前的实施例中,由一个通用的Perl稿本来完成这一步。这个稿本读出由配置代理商根据哪些选项被选中而产生的门控时钟信息。一旦该设计已经被布局和布线完毕,并在最终的时钟树合成完成之前,就运行Perl稿本。
对上述的特殊处理过程还可以作出进一步的改进。特别是,我们将叙述一种过程,通过它,用户就能几乎瞬时地获得类似的硬件特征信息,而不必花费几个小时去运行那些CAD工具。这个过程有几个步骤。
这个过程中的第1个步骤就是将所有配置选项的集合划分为各正交选项的组,使得在一个组中的一个选项对硬件特征的影响跟在任何其他组中的各选项无关。例如,MAC16单元对硬件特征的影响跟任何其他选项无关。这样一来,就形成一个仅有MAC16选项的选项组。由于对硬件特征的影响取决于这些选项的特定组合,所以更复杂的实例就是含有各中断选项、各高级中断选项以及定时器选项的一个选项组。
第2个步骤就是表征每一个选项组对硬件特征的影响。通过获得在该组中,各选项的各种组合对硬件特征的影响,来实现这种表征。对每一种组合来说,使用一种事先描述的过程来获得此项特征,在上述过程中,导出一个实际的实施方案并测量其硬件特征。这样的信息被存储在一个评估数据库之中。
最后的步骤就是导出专门的公式,用曲线拟合和内插技术,来计算在各选项组中,各选项的特定组合对硬件特征的影响。根据各选项的性质,使用不同的公式。例如,由于每一个附加的中断矢量都向硬件添加大致相同的逻辑,我们使用线性函数来模拟它对硬件的影响。在另一个实例中,具有需要高级中断选项的定时器单元,因此,关于定时器选项对硬件的影响的公式是涉及几个选项的条件公式。
就体系结构的选择如何影响应用程序的运行时间性能以及代码的大小提供快速反馈是有用的。来自多个应用领域的几组基准测试程序被选中。对每一个领域来说,预先建立一个数据库,它对不同的体系结构设计决策如何影响在该领域中的各应用程序的运行时间性能和代码大小作出评估。随着用户改变体系结构的设计,针对用户感兴趣的应用领域或针对多个领域对数据库进行查询。评估结果被送给用户,使得她能在软件效益和硬件成本之间的折衷上获得一项估计。
可以容易地对快速评估系统进行扩展,以便就如何修改一种配置使处理器进一步地优化提出建议。一个这样的实例就是将每一种配置选项跟一组数字联系起来,上述数字表示该选项对各种成本度量诸如面积、延时和功率的增加的影响。使用快速评估系统使得计算一种给定的选项对增加成本的影响变得容易。它仅涉及对评估系统的两次调用,其中一次有选项,一次没有选项。这两次评估的成本差异表示该选项对增加成本的影响。例如,通过对两种配置(有和没有MAC16选项)的面积成本进行评估,来计算MAC16选项对增加面积的影响。随后在交互式配置系统中显示有MAC16选项时的差异。这样一个系统能引导用户通过一系列的单步改进到达一种优化的解决方案。
现在转到自动处理器配置过程的软件一边,本发明的这个实施例配置了软件开发工具30,使得它们为该处理器所专用。配置过程开始于软件开发工具30,这种工具可以推广应用于多种不同系统和指令集体系结构。这样的可重定目标的工具已经被广泛地研究并且为业界所熟知。这个实施例使用GNU族的工具,这是一种自由软件,包括例如GNU C编译程序,GNU汇编程序,GNU调试程序,GNU链接程序,GNU跟踪程序,以及各种实用程序。然后,通过直接从ISA描述产生软件的各部分,以及通过使用TPP对手写的软件的各部分进行修改,来自动地配置这些工具30。
可以按照几种不同方法来配置GNU C编译程序。给出核心ISA描述之后,在汇编程序中许多依赖于机器的逻辑都可以采用手写。在可配置处理器的指令集中,编译程序的这个部分是共同的,并且用手来重定目标允许为取得最佳结果而进行细调。然而,即使对编译程序的这个手写部分来说,某些代码仍然是自动地从ISA描述中产生的。特别是,ISA描述定义各常数数值的集合,它们可以用于各种指令的各立即字段。对每一个立即字段来说,都产生一个判断函数,用以检验一个特定的常数数值在该字段中是否能够被编码。当为处理器60生成代码时,编译程序就使用这些判断函数。对编译程序配置的这个方面进行自动化消除了基于ISA描述与编译程序之间出现不一致的机会,并且它使得只要用最小的努力就能改变ISA中的常数。
经过用TPP进行预处理,编译程序的若干部分就配置好了。对于通过参数选择来控制的各配置选项来说,在编译程序中对应的各项参数都经由TPP来设置。例如,编译程序具有一个标志变量,用以表示目标处理器60使用高位在先顺序还是低位在先顺序,并且使用一条TPP命令对这个变量进行自动地设置,上述命令从配置说明100中读出顺序参数。TPP也被用来根据在配置说明100中对应的封装是否被激活,有条件地使能或失能编译程序的手工编码部分,该部分产生用于可选的各ISA封装。例如,若配置说明仅包括MAC16的选项90,则在编译程序中仅包括用以产生各项乘法/累加指令的代码。
编译程序也被配置成支持经由TIE语言指定的设计者定义的各项指令。这种支持有两个层次。在最低层次,设计者定义的各项指令可用于宏,内部函数,或者在正在被编译的代码中的在线(外部的)函数。本发明的这个实施例产生一个C语言头文件,它将在线函数定义为“在线汇编”代码(GNU C编译程序的一个标准特征)。给出设计者定义的操作码及其各项操作数的TIE说明之后,生成头文件的过程也就是转换为GNU C编译程序的在线汇编句法的一种直截了当的过程。一种可供选择的实施方案生成含有C预处理器的各个宏(它们指定在线汇编的各项指令)的头文件。再一个可供选择的方案使用TPP直接地将内部函数添加到编译程序之中。
通过让编译程序自动地识别使用各项指令的机会,来提供对设计者定义的各项指令的第2层支持。可以由用户直接地定义这些TIE指令或者在配置过程中自动地生成。在编译用户应用程序之前,TIE代码被自动地察看,并且被转换为等效的C语言函数。这个步骤同样被用来对各项TIE指令进行快速仿真。等效的C语言函数被部分地编译为编译程序所使用的基于树状的中间表示。对每一条TIE指令来说,这种表示被存储在一个数据库之中。当用户应用程序被编译时,编译过程的一部分就是一段模式匹配程序。用户应用程序被编译为基于树状的中间表示。在用户程序中,模式匹配程序对每一棵树都从底部开始扫描。在扫描的每一个步骤中,模式匹配程序检查植根于当前点的立即表示是否匹配于在数据库中的任何TIE指令。若存在匹配,则该匹配被登记。在完成对每一棵树的扫描之后,最大程度的匹配集合被选中。在该树中,每一次最大匹配都被置换为等效的TIE指令。
上述算法将自动地识别使用无状态的各项TIE指令的机会。也可以使用各种附加的方案来自动地识别使用有状态的各项TIE指令的机会。一个先前的部分描述了用于自动地选择具有状态的可能的各项TIE指令的算法。相同的算法被用来自动地使用在C或C++应用程序中的各项TIE指令。当一个TIE协处理器被定义为具有更多的寄存器,但只有有限的运算集合时,就对各代码区域进行扫描,以察看它们是否会出现寄存器溢出,以及那些区域是否仅使用可得到的运算的集合。若这样的区域被找到,则在那些区域中的代码将自动地被改变为使用协处理器的各项指令以及各寄存器98。在区域的边界上产生转换操作,以便将数据送入或送出协处理器98。类似地,若一个TIE协处理器已经被定义为对不同大小的整数进行运算,则各代码区域被检查,以察看在该区域中的所有数据是否都被存取,因为它具有不同的大小。对于匹配的各区域来说,其代码被转换,并且glue代码被添加到边界上。类似地,若一个TIE协处理器已经被定义为实现一种C++语言的抽象数据类型,则在那种数据类型中的所有运算都被置换为TIE协处理器的各项指令。
要注意的是,自动地建议TIE指令以及自动地使用TIE指令二者都是独立地有用的。经由内在机制,用户可以人工地使用所建议的各项TIE指令,并且可以将所使用的算法应用于人工地设计的各项TIE指令或各协处理器98。
不管设计者定义的各项指令是如何产生的,或者经由各在线函数或者借助于自动识别,编译程序都需要知道设计者定义的各项指令的潜在的侧面效应,使得它能对这些指令进行优化和调度。为了改进性能,传统的编译程序优化用户代码,以便使所需的各项特性,诸如运行时间性能、代码大小或功耗,得以优化。如同一位精通的专业人士所熟知的那样,这样的优化包括诸如重新排列各指令,或者将某些指令置换为语义上等效的其他指令。为了很好地进行优化,编译程序应当知道每一条指令是如何影响机器的不同部分的。两条对机器状态的不同部分进行读和写的指令可以自由地被重新排序。两条对机器状态的同一部分进行访问的指令通常不能被重新排序。对传统的处理器来说,由不同的指令来进行状态的读和/或写通过硬件接线,有时通过表格,进入编译程序。在本发明的一个实施例中,各项TIE指令被保守地设定为对处理器60的所有状态进行读和写。这使编译程序能产生正确的代码,但是限制了编译程序在出现TIE指令时对代码进行优化的能力。在本发明的另一个实施例中,一种工具自动地读出TIE定义,并且为每一条TIE指令发现哪一种状态是被所述指令读或写的。然后,这个工具修改被编译程序的优化程序所使用的表格,以便精确地模拟每一条TIE指令的效果。
像编译程序那样,汇编程序110的依赖于机器的部分包括自动生成的部分以及用TPP配置的手工编码部分。手工编写的代码支持所有配置所共有的某些特征。然而,汇编程序110的主要任务是对机器指令进行编码,并且可以从ISA描述中自动地生成指令的编码与解码软件。
由于在几种不同的软件工具中,指令的编码和解码都是有用的,所以本发明的这个实施例将软件集中在一起,以便在一个独立的软件库中执行这些任务。使用在ISA描述中的信息自动地生成这个库。该库定义各操作码的一个枚举,一个函数,它将操作码助记符的字符串有效地映射为该枚举的成员(StringToOpcode),以及为每一组操作码指定指令长度的表格(InstructionLength),操作数的数目,(numberOfOperands),操作数字段,操作数类型(即,寄存器或立即数)(operandType),二进制编码(encodeOpcode),以及助记符串(opcodeName)。对每一个操作数字段来说,该库提供存取者函数,以便对指令字中对应的各比特进行编码(fieldSetFunction)和解码(fieldGetFunction)。ISA描述中所有这些信息都是现成可用的;产生库软件仅仅是将该信息转换为可执行的C语言代码。例如,各项指令的编码被记录在一个C数组变量之中,在其中,每一行都是针对一条特定指令的编码,通过将每一个操作码字段设置为在ISA描述中为该指令而指定的数值而产生上述编码;encodeOpcode函数仅为一组给定的操作码返回该数组的数值。
该库还提供一个函数,用以对二进制指令中的操作码进行解码(decodeInstruction)。这个函数被生成为嵌套的switch语句的一个序列,其中,最外层的开关对位于操作码层次结构的顶层的子操作码字段进行测试,并且,嵌套的switch语句对在操作码层次结构中层次逐渐降低的各子操作码字段进行测试。因此,为这个函数而生成的代码具有与操作码层次结构本身相同的结构。
给出用于编码和解码的这个库之后,汇编程序110的实现就变得很容易。例如,在汇编程序中的指令编码逻辑是十分简单的:
  AssembleInstruction(String mnemonic,int arguments[])

  begin

       opcode=stringToOpcode(mnemonic);

       if(opcode==UNDEFINED)

           Error(″Unknown opcode″);

       instruction=encodeOpcode(opcode);

       numArgs=numberOfOperands(opcode);

       for i=0,numArgs-1 do

       begin

           setFun=fieldSetFunction(opcode,i);

           setFun(instruction,arguments[i]);

       end

       return instruction;

  end
实现反汇编程序110(该程序将二进制指令转换为一种紧密地重新组合汇编代码的可读形式)也同样是直截了当的:
  DisassembleInstruction(BinaryInstruction instruction)

  begin

       opcode=decodeInstruction(instruction);

       instructionAddress +=instructionLength(opcode);

       print opcodeName(opcode);

       //Loop through the operands,disassembling each

       numArgs=numberOfOperands(opcode);

       for i=0,numArgs-1 do

       begin

            type=operandType(opcode,i);

       getFun=fieldGetFunction(opcode,i);

       value=getFun(opcode,i,instruction);

       if(i!=0)print″,″;//Comma separate operands

       //Print based on the type of the operand

       switch(type)

       case register:
				
				<dp n="d44"/>
                 print registerPrefix(type),value;

           case  immediate:

                 print value;

           case  pc_relative_label:

                 print instructionAddress+value;

           //etc.for more different operand types

      end   

  end
这个反汇编程序算法被用于一种卓越的反汇编程序工具,并且也用于调试程序130,以支持机器码的调试。
跟编译程序和汇编程序110相比,链接程序对配置是比较不敏感的。多数链接程序都是标准的,并且甚至依赖于机器的部分也主要是依赖于核心ISA描述,并且可以为一种特定的核心ISA进行手工编码。使用TPP从配置说明100对诸如顺序这样的参数进行设置。目标处理器60的存储器映射是链接程序所需的配置的一个其他方面。跟前面一样,用TPP将指定存储器映射的各项参数插入到链接程序之中。在本发明的这个实施例中,由一组链接程序稿本来驱动GNU链接程序,正是这些链接程序稿本含有存储器映射信息。这个方案的一个优点就是,若目标系统的存储器映射不同于处理器60在配置时所指定的存储器映射,则附加的链接程序稿本可以在以后生成,不用重新配置处理器60,也不用重建链接程序。因此,本实施例包括一种工具,它用不同的存储器映射参数来配置新的链接程序稿本。
调试程序130提供下列各种机制:在运行过程中观察程序的状态,在一段时间里单步执行一条指令,引入各断点,执行其他标准的调试任务。被调试的程序可以运行于已配置的处理器的硬件实施方案,或者运行于ISS126之上。在无论哪一种情况下,调试程序都向用户提供相同的接口。当在一个硬件实施方案上运行该程序时,一段小的监控程序被纳入到目标系统之中,用以控制用户程序的执行,并经由一个串行口跟调试程序进行通信。当在仿真程序126上运行该程序时,仿真程序126本身就执行那些功能。调试程序130以几种方式依赖于配置。它跟上述的指令编码/解码库链接,以支持从调试程序130对机器码进行反汇编。通过扫描ISA描述来找出哪一个寄存器存在于处理器60之中,来产生调试程序130中用于显示处理器的寄存器状态的部分,以及向调试程序130提供信息的监控程序部分和ISS126。
其他软件开发工具30都是标准的,并且不需要为每一种处理器配置而加以改变。特征观察程序和各种应用程序都归入这一类。一旦运行于为处理器60的所有配置所共享的二进制格式的文件之上时,这些工具就可能需要重定目标,但是它们既不依赖于ISA描述,也不依赖于在配置说明100中的其他参数。
配置说明也被用来配置示于图13的被称为ISS126的一段仿真程序。ISS126是一段软件应用程序,它模拟可配置处理器指令集的功能行为。不同于诸如Synopsys的VCS以及Cadence的Verilog XL和NC仿真程序那样的对置的处理器硬件模型,ISS HDL模型是CPU在执行指令时的一种抽象。由于它不需要模拟在整个处理器设计中每一个门和寄存器的每一次状态改变,所以ISS 126可以运行得比硬件仿真更快。
ISS 126允许为已配置的处理器60而生成的程序在一部宿主计算机上被执行。它精确地再现该处理器的复位和中断行为,这些行为允许对诸如设备驱动程序和初始化代码这样的低级程序进行开发。当把本地代码变换为嵌入式应用程序时,这是特别有用的。
ISS 126可以被用来识别潜在的问题,诸如体系结构假设,存储器排序考虑等,用不着将代码下载到实际的已嵌入的目标。
在本实施例中,使用一种类似于C的语言来教学式地表达ISS语义,以建立C操作员积木块,它将指令转换为函数。可以使用这种语言来模拟中断的基本功能,例如,中断寄存器,位设置,中断等级,矢量等。
可配置的ISS126被用于作为系统设计和验证过程的一部分的下列4种用途或目标:
—在硬件变为可用之前调试软件应用程序;
—调试系统软件(例如,编译程序和操作系统部件);
—跟用于硬件设计验证的HDL仿真进行比较。ISS用作ISA的引用实现—在处理器设计验证过程中,ISS和处理器HDL为诊断程序和应用程序而运行,并且来自二者的轨迹被比较;以及
—分析软件应用程序性能(这可能是配置过程的一部分,或者在已经选定处理器的配置之后,它可以被用于进一步的应用程序调整)。
所有的目标都要求ISS126能够对用可配置的汇编程序110和链接程序产生的程序进行装载和解码。它们还要求ISS对指令的执行在语义上等效于对应的硬件执行以及等效于编译程序的期望。因为这些原因,ISS126从用以定义硬件和系统软件的相同的ISA文件导出它的解码和执行行为。
针对上面所列的第1个和最后一个目标,对ISS126来说,重要的是尽可能快地达到所需的精度。因此,ISS126允许对仿真的详细程度进行动态控制。例如,除非被请求,对高速缓冲存储器的细节不进行仿真,并且高速缓冲存储器的模拟可以动态地关闭或接通。此外,在ISS126被编译之前,ISS126的各部件(例如,高速缓冲存储器和流水线模型)被配置,使得在运行时间中,ISS126很少作出依赖于配置的行为选择。这样一来,从涉及系统的其他各部分的定义好了的源导出所有ISS的可配置的行为。
针对上面所列的第1个和第3个目标,对ISS126来说,重要的是,当操作系统OS尚未为设计中的系统(目标)提供服务时,为应用程序提供操作系统服务。对这些服务来说,同样重要的是,当这是调试过程的一个相关部分时,由目标OS提供这些服务。这样一来,系统提供一种设计,用于在ISS主机和仿真目标之间灵活地传送这些服务。当前的设计依赖于ISS动态控制(陷阱SYSCALL指令可以被接通和关闭)以及使用专门的SIMCALL指令去请求主机操作系统服务这两者的组合。
最后一个目标要求ISS126去模拟处理器和系统行为的某些方面,这些方面低于ISA指定的层次。特别是,通过为来自Perl稿本(它从配置数据库100提取各项参数)的模型产生C语言代码,来构建ISS的高速缓冲存储器模型。此外,各项指令的流水线行为的细节(例如基于寄存器使用的互锁以及功能单元有效性要求)也从配置数据库100导出。在当前的实施方案中,一个专用的流水线描述文件按照类似于LISP语言的句法来指定这种信息。
第3个目标要求对中断行为进行精确的控制。为此目的,在ISS126中的一个专门的非体系结构寄存器被用来抑制各种中断使能。
ISS126提供提供几种接口来支持针对其使用的不同目标:
—一个批处理命令或命令行模式(通常结合第1个和最后一个目标使用);
—一个命令循环模式,它提供非符号的调试能力,例如,断点,监测点,步骤等—频繁地用于所有4个目标;以及
—一个插座接口,它允许ISS126被软件调试程序作为一个执行后端来使用(这应当被配置成能对所选定的特定配置的寄存器状态进行读和写)。
—一个可用稿本来描述的接口,它允许非常详细的调试和性能分析。特别是,这个接口可以被用来对不同配置的应用行为进行比较。例如,在任何断点上,来自一种配置的运行状态可以跟来自另一种配置的运行状态进行比较,或者转移到后一种状态。
仿真程序126也具有手工编码和自动生成这两部分。手工编码部分是常规的,除了指令解码和执行以外,这两者都是从ISA描述语言产生的表格中生成的。通过开始于从待执行的指令字中找到的基本操作码,这些表对指令进行解码,用字段的值索引到一份表格之中,继续进行下去,直到找到一个叶操作码(即,一个没有按照其他操作码的样式被定义的操作码)为止。然后该表格向从TIE代码转换过来的代码给出一个指针,上述TIE代码按照针对该指令的语义说明来指定。这组代码被执行,以便仿真该指令。
ISS126能够可选地跟踪被仿真的程序的执行。这种跟踪使用一种为业界所熟知的程序计数器(PC)采样技术。在规则的间隔上,仿真程序126对正在被仿真的处理器的程序计数器进行采样。它按照每一个代码区域的采样数来建立一个直方图。仿真程序126还对在调用图中的每一个边沿被执行的次数进行计数,其方法是,当一条调用指令被仿真时,令计数器加1。当仿真过程完成时,仿真程序126写一个输出文件,其中包括直方图以及调用图边沿计数,其格式是可以被一个标准的跟踪观察程序所读出。由于被仿真的程序118不需要用仪器方式(如同在一种标准的跟踪技术之中)来进行修改,所以跟踪开销不影响仿真结果,并且这种跟踪是完全无损伤的。
最好是,系统进行有效的硬件处理器仿真以及软件处理器仿真。为此目的,本实施例提供一块仿真板。如图6所示,仿真板200使用一个复合的可编程逻辑器件202。例如Altera Flex 10K200E从硬件上仿真处理器配置60。一旦用该系统产生的处理器网表来进行编程,该CPLD器件就从功能上等效于最后的ASIC产品。它提供这样的好处,即处理器60的物理实现是可行的,它比其他仿真方法(例如ISS或HDL)运行得更快,并且在周期上是精确的。然而,它不能达到最终ASIC所能达到的各项高频目标。
这块板使得设计者能够评估各种处理器配置选项,并且在设计周期的较早阶段就开始进行软件开发与调试。它还可以用于该种处理器配置的功能验证。
仿真板200在其上具有若干资源,使得软件的开发、调试和验证变得容易。这些包括CPLD器件202本身,EPROM204,SRAM206,同步SRAM208,闪烁存储器210以及两个RS232串行通道212。串行通道212提供一条通往UNIX或PC主机的通信链路,以便下载和调试用户程序。处理器60的配置,以CPLD网表的形式,通过一条通往该器件的配置端口214的专用的串行链路,或者通过专用的各配置ROM216被下载到CPLD202。
在板200上可用的资源同样是可配置到一定程度的。由于映射是通过一种可以容易地改变的可编程逻辑器件(PLD)217来完成的,所以在板上各种存储元件的存储器映射都可以容易地被改变。同样,通过使用较大(容量)的存储器器件以及适当地确定标记总线222和224(连接到高速缓冲存储器218和228)的大小,就能使处理器核心所使用的高速缓冲存储器218和228变为可扩展的。
使用该板来评估一种特定的处理器配置涉及几个步骤。第1个步骤是获得一组描述处理器的特定配置的RTL文件。下一个步骤是使用多种市售合成工具中的任何一种,从RTL描述中合成一个门级的网表。一个这样的实例就是来自Synopsys公司的FPGA EXPRESS。然后,用门级的网表来获得一种CPLD实施方案,该方案使用典型地由经销商提供的各种工具。一种这样的工具就是来自Altera公司的Maxplus2。最后一个步骤就是使用由CPLD经销商再次提供的编程器,将该实施方案下载到在仿真板上的CPLD芯片上。
由于仿真板的用途之一是支持用于调试目的的快速原型实施方案,所以重要的是,在前面的段落中所列举的CPLD实施过程是自动的。为了达到这个目标,通过将所有相关的文件集中到一个单独的目录之中,来定制提供给用户的各种文件。随后,提供一个完全定制的合成稿本,它能够将特定的处理器配置合成到顾客所选定的特定的FPGA器件中去。经销商的各种工具所使用的完全定制的实施方案稿本也同时生成。这样的合成和实施方案稿本从功能上保证具有最佳性能的正确的实施方案。通过将适当的命令纳入到稿本中去,以便读入跟特定的处理器配置有关的所有RTL文件,通过纳入适当的命令,以便基于在处理器配置中的I/O信号来分配芯片引脚位置,以及通过纳入各种命令,以便获得针对处理器逻辑的某些重要部分(例如门控时钟)的专门的逻辑实施方案,来达到功能上的正确性。该稿本还通过向所有的处理器I/O信号分配详细的定时约束条件,以及通过对某些重要信号的特殊处理,来改进该实施方案的性能。定时约束条件的一个实例就是,通过考虑在板上的该信号的延时,向一个信号分配特定的输入延时。重要信号处理的一个实例就是,向专用的全局接线分配时钟信号,以便在CPLD芯片上获得低的时钟延时差异。
最好是,系统还为已配置的处理器60配置一个验证程序组。大多数像微处理器那样的复合设计的验证包括如下的流程:
—建立一个测试台,用以仿真该设计,并对输出进行比较,比较可以在测试台内进行,也可以使用一个像ISS126那样的外部模型;
—写诊断程序,以产生刺激源;
—使用像有限状态机的行覆盖那样的方案来测量验证的覆盖,包括覆盖HDL、降低差错率、在该设计上所运行的矢量的数目等;以及
—若覆盖不充分—则写更多的诊断程序,以及使用各种工具,来产生各种诊断程序,以便进一步地实践该项设计。
本发明使用与此有些类似的流程,但考虑到本设计的可配置性,该流程的所有部件都被修改。这种方法学包括下列步骤:
—为一种特定的配置建立一个测试台。该测试台的配置使用类似于针对HDDL而描述的方案,并支持其中所支持的所有选项和扩展,即,高速缓冲存储器(容量)大小、总线接口、时钟、中断产生等;
—在HDL的一种特定配置上运行自检诊断程序。诊断程序本身是可配置的,以便针对硬件的一个特定片段而对它们进行剪裁。选择哪一段诊断程序来运行也依赖于配置;
—运行以伪随机方式产生的诊断程序,并且在执行每一条指令之后,将处理器状态跟ISS126进行比较;以及
—测量验证的覆盖—使用测量功能和行覆盖的覆盖工具。同样,监控程序和检查程序也跟诊断程序一起运行,以监视非法的各种状态和各种情况。所有这些对一种特定的配置说明来说,都是可配置的。
所有各验证部件都是可验证的。使用TPP来实现可配置性。
测试台是其中含有已配置的处理器60的系统的一个VerilogTM模型。在本发明的情况下,测试台包括:
—高速缓冲存储器,总线接口,外部存储器;
—外部中断和总线差错产生;以及
—时钟产生。
由于差不多所有的上述特性都是可配置的,所以测试台本身需要支持可配置性。这样一来,例如,根据配置自动地调整高速缓冲存储器的大小和宽度,以及外部中断的数目。
测试台向被测试的器件—处理器60提供刺激源。通过提供预装到存储器的汇编级指令来做到这一点。它还产生用以控制处理器60的行为—例如,各种中断—的各种信号。同样,这些信号的频率和定时都是受控于测试台的,并且由后者自动地产生。
诊断程序有两种类型的可配置性。首先,诊断程序用TPP来确定测试什么。例如,已经编写一种用以测试软件中断的诊断程序。这种诊断程序需要知道有多少种软件中断,以便产生正确的汇编代码。
其次,处理器配置系统10应当确定哪一种诊断程序适用于这种配置。例如,被编写用以测试MAC单元的诊断程序就不适用于不含有这种单元的处理器60。在本实施例中,通过使用一个含有关于每一种诊断程序的信息的数据库来完成这一步。该数据库可以包括针对每一种诊断程序的下列信息:
—使用该诊断程序,若某个选项已经被选中;
—若诊断程序不能带着各种中断去运行;
—若诊断程序在运行时,需要各种专门的库或各种句柄;以及
—若诊断程序不能在与ISS126协同仿真的情况下运行。
最好是,处理器硬件描述包括3种类型的测试工具:测试发生器工具,监控程序和覆盖工具(或检查程序),以及一种协同仿真机制。测试发生器工具是以智能方式生成一系列处理器指令的各种工具。它们是各种伪随机测试发生器的序列。本实施例内部使用两种类型—专门开发的一种称为RTPG,另一种基于外部工具的称为VERA(VSG)。二者都具有围绕它们而建立的可配置性。基于针对一种配置的有效指令,它们将产生一系列的指令。这些工具也将能够处理从TIE新定义的各种指令—使得这些新定义的指令为了测试而随机地被产生。本实施例包括监控程序和检查程序,用以测量设计验证的覆盖程度。
监控程序和覆盖工具伴随着一次回归运行而运行。覆盖工具监测诊断程序正在做什么,以及正在实践的HDL的功能和逻辑。在回归运行的整个过程中收集所有这些信息,并在以后进行分析,以便获得关于该逻辑的哪些部分需要进一步测试的提示。本实施例使用几种可配置的功能覆盖工具。例如,对一个特定的有限状态机来说,根据一种配置,它并不包括所有的状态。因此,对那种配置来说,功能覆盖工具并不需要尝试去检查那些状态或跳变。通过使该工具能够用TPP来进行配置,就能完成这一步。
类似地,还有各种监控程序,用以检查在HDL仿真过程中出现的各种非法状态。这些非法状态可以表示为各种差错。例如,在一组3态总线中,两个驱动器不应同时处于高电位。这些监控程序是可配置的—根据在该种配置下是否纳入一种特定的逻辑,来增加或取消一些检查项目。
协同仿真机制将HDL跟ISS126连接在一起。它被用来检查在指令结束时在HDL和ISS126中,处理器的状态是否相同。在它知道为每一种配置纳入了哪些特征以及需要对哪一种状态进行比较这个范围内,它也是可配置的。这样一来,例如,数据的断点特征(导致)增加一个专门的寄存器。这种机制需要知道如何对这个新的专用寄存器进行比较。
经由TIE说明的指令语义可以被转换为功能上等效的C语言函数,以便用于ISS126,以及让系统设计者用于测试和验证。在配置数据库106中,一条指令的语义被各种工具转换为C语言函数(该工具使用标准的语法分析工具来建立一棵语法树),然后顺着这棵语法树,检查是否符合语法规则,并且输出用C语言写成的对应的表达式。这种转换需要一次预通过,以便向所有表达式分配比特宽度并且重写语法树使某些转换得以简化。跟其他转换程序(例如HDL到C或者C到汇编语言编译程序)相比,这些转换程序是相对地简单的,并且可以由专业人士从TIE和C语言说明书开始进行编写。
使用由配置文件100配置的编译程序以及汇编/反汇编程序100,基准测试应用源代码118被编译和汇编,并且,使用样本数据集124,它被仿真以获得软件特征文件130,该文件也被送往用户配置俘获程序以便向用户反馈。
有能力获得针对任何配置参数选择的硬件和软件价格/效益特征的为任何配置选择开辟了由设计者进一步地优化系统的机会。特别是,这将使设计者选择最佳的配置参数,这些参数根据某些估价函数来优化整个系统。一种可能的处理过程是基于一种贪婪的策略,即,通过重复地选择或不选择一种配置参数。在每一个步骤,都选择对整个系统性能和价格具有最佳影响的那些参数。这个步骤一直重复进行,直至找不到还能改进系统的性能与价格的单独的参数为止。其他扩展包括同时注视一组配置参数,或者使用更复杂的搜索算法。
除了获得最佳的配置参数选择以外,这种处理过程还可以被用来构建最佳处理器的各种扩展。由于在处理器的各种扩展中存在大量的可能性,重要的是限制扩展候选者的数目。其中,一种技术就是去分析应用软件并且仅注视那些能改进系统性能或价格的指令扩展。
已经讲完了根据本实施例的一个自动处理器配置系统的操作之后,现在将给出处理器宏体系结构配置的实例。第1个实例表示将本发明应用于图像压缩时的优点。
运动评估是许多图像压缩算法(包括MPEG视频和263会议应用)的一个重要部分。视频图像压缩尝试使用从一帧到另一帧的相似性,以减少用于每一帧所需的存储容量。在最简单的情况下,每一块待压缩的图像都可以跟参考图像的对应块(相同的X,Y位置)进行比较(只有紧挨着的领先的或随后的图像被压缩)。介于各帧之间的图像差异的压缩与个别图像的压缩相比,前者通常具有较高的比特效率。在视频序列中,独特的图像特征通常在不同帧之间发生移动,所以在不同帧的各块之间的最接近的一致性通常不是准确地处于相同的X,Y位置上,而是有一些偏离。若图像的某些重要部分在不同帧之间发生移动,则有必要在对这些差异进行计算之前,识别和补偿这种运动。这个事实意味着通过对介于连续的图像之间的差异(包括对各种独特的特征,以及在用于已计算的差异的子图像中的X,Y偏离)进行编码,就能得到反差最强的表示。在用于计算图像差异的位置上的偏离被称为运动矢量。
在这一类图像压缩中,最繁重的计算任务就是为每一块确定最适当的运动矢量。选择运动矢量的常用方法就是在被压缩的每一块图像以及前一帧图像的各候选块的集合之间,找出在像素与像素之间具有最小的平均差异的矢量。各候选块是在围绕被压缩的块的位置上的所有的各邻近块的集合。图像的大小,块的大小,以及各邻近块的大小,都影响到运动估计算法的运行时间。
简单的基于块的运动估计将待压缩的图像的每一帧子图像跟一帧参考图像进行比较。在视频序列中,参考图像可以领先于或跟随于主题图像。在每一种情况下,在主题图像被解压缩之前,该参考图像应当被解压缩系统认为是有效的。一块待压缩的图像跟参考图像的各候选块之间的比较说明如下。
围绕在参考图像中的对应位置,为主题图像的每一块进行一次搜索。通常,对图像的每一种彩色分量(例如YUV)单独地进行分析。有时,仅对一种分量,例如亮度,进行分析。在主题块和参考图像的搜索区域的每一个可能的块之间,计算像素与像素之间的平均差异。这个差异就是像素数值的大小的差异的绝对值。平均值跟在各块的对子中N2个像素之和成正比(这里,N是该块的维数)。产生最小平均像素差异的参考图像的块定义主题图像的该块的运动矢量。
下面的实例表示运动估计算法的一种简单形式,然后使用TIE为一个小的专用功能单元优化其算法。此项优化产生10倍以上的加速效果,使得基于处理器的压缩适用于许多视频应用。它说明了一个将易于用高级语言进行编程跟专用硬件的效率结合在一起的处理器的功能。
这个实例使用两个矩阵OldB和NewB,分别表示老图像和新图像。图像的大小被确定为NX和NY。块大小被确定为BLOCKX和BLOCKY。因此,该图像由NX/BLOCKX乘以NY/BLOCKY个块组成。围绕一个块的搜索区域被确定为SEARCHX和SEARCHY。最佳运动矢量和数值被存储在VectX,VectY,和VectB之中。由基本(参考)实施方案计算出来的最佳运动矢量和数值被存储在BaseX,BaseY,和BaseB之中。这些数值被用来检查由该实施方案使用指令扩展计算出来的各矢量。在以下的C代码段中,可以获得这些基本定义:
  #define NX 64                               /* image width */

  #define NY 32                               /* image height */

  #define BLOCKX   16                         /* block width */

  #define BLOCKY   16                         /* block height */

  #de fine SEARCHX  4                         /* search region

                                              width */

  #define SEARCHY   4                         /* search region

                                              height */

  unsigned char OldB[NX][NY];                /* old image  */

  unsigned char NewB[NX][NY];                /* new image */

  unsigned short VectX[NX/BLOCKX][NY/BLOCKY];/* X motion vector
*/

  unsigned short VectY[NX/BLOCKX][NY/BLOCKY];/* Y motion vector*/

  unsigned short VectB[NX/BLOCKX][NY/BLOCKY];/*absolute

                                              difference */

  unsigned short BaseX[NX/BLOCKX][NY/BLOCKY];/* Base X motion

                                              vector */

  unsigned short BaseY[NX/BLOCKX][NY/BLOCKY];/* Base Y motion

                                              vector */

  unsigned short BaseB[NX/BLOCKX][NY/BLOCKY];/* Base absolute

                                              difference */

  #define ABS(x)       (((x)<0)?(-(x)):(x))

  #define MIN(x,y)    (((x)<(y))?(x):(y))

  #define MAX(x,y)    (((x)>(y))?(x):(y))

  #define ABSD(x,y)   (((x)>(y))?((x)-(y)):((y)-(x)))
运动评估算法包括3个嵌套的循环:
1.对老图像中的每一个源块。
2.对在环绕源块区域的新图像的每一个目标块。
3.计算介于每一对像素之间的绝对差值。
该算法的完整代码列举如下。
                 参考软件实施方案
  void

  motion_estimate_base()

  {    

     int bx,by,cx,cy,x,y;

     int startx,starty,endx,endy;

     unsigned diff,best,bestx,besty;

     for(bx=0;bx<NX/BLOCKX;bx++){

         for(by=0;by<NY/BLOCKY;by++){

             best=bestx=besty=UINT_MAX;

             startx=MAX(0,bx*BLOCKX-SEARCHX);

             starty=MAX(0,by*BLOCKY-SEARCHY);
				
				<dp n="d56"/>
               endx=MIN(NX-BLOCKX,bx*BLOCKX+SEARCHX);

               endy=MIN(NY-BLOCKY,by*BLOCKY+SEARCHY);

               for(cx=startx;cx<endx;cx++){

                   for(cy=starty;cy<endy;cy++)(

                       diff=0;

                       for(x=0;x<BLOCKX;x++){

                           for(y=0;y<BLOCKY;y++){

                               diff+=ABSD(OldB[cx+x][cy+y],
NewB[bx*BLOCKX+x][by*BLOCKY+y]);

                           }

                        }  

                        if(diff<best){

                          best=diff;

                          bestx=cx;

                          besty=cy;

                        }

                    }

                }

                BaseX[bx][by]=bestx;

                BaseY[bx][by]=besty;

                BaseB[bx][by]=best;

            }

        }
基本实施方案是简单的,它不能使用这种块与块之间的比较中的更多的内在平行性。可配置的处理器体系结构提供两种重要的工具,能显著地加速这种应用程序的执行。
首先,该指令集体系结构包括强有力的漏斗式移位基元,允许在存储器中快速抽取未对准的字段。这允许像素比较的内环有效地从存储器中取出相邻各像素的组。该环可以被重写,使之能同时运行于4个像素(字节)之上。特别是,为了达到这个实例的目的,人们希望定义一条新的指令,以便在同一时间内计算4个像素对的绝对差值。然而,在定义这条新指令之前,有必要再次实施该算法,以利用这样一条指令。
这条指令的出现允许在内环差值计算中得到这样的改进,即,环的打开变得同样引人注目。内环的C语言代码被重写,以便利用新的绝对差值求和指令以及有效的移位。参考图像的4个重叠的块的一部分就能在同一个环中进行比较。SAD(x,y)是对应于所添加的指令的新的内部函数。SRC(x,y)对x和y的连锁进行右移,其位移量存储在SAR寄存器之中。
        使用SAD指令的运动估计的快速方式
/

  void

  motion_estimate_tie()

  {

      int bx,by,cx,cy,x;

      int startx,starty,endx,endy;

      unsigned diff0,diff1,diff2,diff3,best,bestx,besty;

      unsigned *N,N1,N2,N3,N4,*O,A,B,C,D,E;

      for(bx=0;bx<NX/BLOCKX;bx++){

          for(by=0;by<NY/BLOCKY;by++){

              best=bestx=besty=UINT_MAX;

              startx=MAX(0,bx*BLOCKX-SEARCHX);

              starty=MAX(0,by*BLOCKY-SEARCHY);

              endx=MIN(NX-BLOCKX,bx*BLOCKX+SEARCHX);

              endy=MIN(NY-BLOCKY,by*BLOCKY+SEARCHY);

              for(cy=starty;cy<endy;cy+=sizeof(long)){

                  for(cx=startx;cx<endx;cx++){

                      diff0=diff1=diff2=diff3=0;

                      for(x=0;x<BLOCKX;x++){

                          N=(unsigned *) &amp; (NewB[bx*BLOCKX+x]

                             [by*BLOCKY]);

                          N1=N[0];

                          N2=N[1];

                          N3=N[2];
				
				<dp n="d58"/>
                   N4=N[3];

                   O(unsigned*) &amp; (OldB[cx+x][cy]);

                   A=O[0];

                   B=O[1];

                   C=O[2];

                   D=O[3];

                   E=O[4];

                   diff0+=SAD(A,N1)+SAD(B,N2)+

                                 SAD(C,N3)+SAD(D,N4);

                   SSAI(8);

                   diff1+=SAD(SRC(B,A),N1)+

                      SAD(SRC(C,B),N2)+SAD(SRC(D,C),

                      N3)+SAD(SRC(E,D),N4);

                 SSAI(16);

                   diff2+=SAD(SRC(B,A),N1)+

                       SAD(SRC(C,B),N2)+SAD(SRC(D,C),

                       N3)+SAD(SRC(E,D),N4);

                   SSAI(24);

                   diff3+=SAD(SRC(B,A),N1)+

                        SAD(SRC(C,B),N2)+SAD(SRC(D,C),

                        N3)+SAD(SRC(E,D),N4);

                      O+=NY/4;  

                      N+=NY/4;

                   }

                   if(diff0<best){

                      best=diff0;

                      bestx=cx;

                      besty=cy;

                   }

                   if(diff1<best){

                      best=diff1;

                      bestx=cx;

                      besty=cy+1;

                   }

                   if(diff2<best){

                      best=diff2;

                      bestx=cx;

                      besty=cy+2;

                   }

                   if(diff3<best){

                      best=diff3;

                      bestx=cx;

                      besty=cy+3;

                  }

              }

          }

          VectX[bx][by]=bestx;

          VectY[bx][by]=besty;

          VectB[bx][by]=best;

      }

  }
}

                               58a
本实施方案使用下列SAD函数来评估最终的新指令:
              4个字节的绝对差值求和
 /

      static inline unsigned

      SAD(unsigned ars,unsigned art)

      {

          return ABSD(ars>>24,art>>24)+

                 ABSD((ars>>16)  &amp;255,(art>>16) &amp; 255)+

                 ABSD((ars>>8)  &amp;255,(art>>8) &amp; 255)+

                 ABSD(ars &amp; 255,art &amp; 255);

      }
为了调试这个新的实施方案,使用下列的测试程序,将用新的实施方案以及用基本实施方案计算出来的两种运动矢量和数值加以比较:
                      主测试程序
  /

      int

      main(int argc,char **argv)

      {

          int passwd;

      #ifndef NOPRINTF

          printf(″Block=(%d,%d),Search=(%d,%d),size=(%d,%d)\n″,

              BLOCKX,BLOCKY,SEARCHX,SEARCHY,NX,NY);

      #endif

          init();

          motion_estimate_base();

          motion_estimate_tie();

          passwd=check();

      #ifndef NOPRINTF

          printf(passwd?″TIE version passed\n″:″** TIE version

  failed\n″);

      #endif

          return passwd;

      }
在整个开发过程中,都将使用这个简单的测试程序。这里,应当遵循的一条常规就是当检测到一个差错时,主程序应当返回0,否则,返回1。
使用TIE允许新指令的快速说明。可配置的处理器发生器能够在硬件实施方案以及软件开发工具这两方面充分地实现这些指令。硬件合成将新函数的最佳整合生成到硬件数据通路之中。可配置的处理器的软件环境完全支持在C和C++编译程序、汇编程序、符号调试程序、跟踪程序以及周期精确指令集仿真程序中的新指令。硬件和软件的快速再生使得专用指令成为一种用于应用程序加速的快速和可靠的工具。
这个实例使用TIE来实现一条简单指令,以便并行地执行4个像素的像素求差值、取绝对值和累加。这条单字节指令能进行11种基本运算(在常规的处理过程中,可能需要多条独立的指令),如同一种原子运算那样。下面是完整的描述:
  // define a new opcode for Sum of Absolute Difference (SAD)

  // from which instruction decoding logic is derived

  opcode SAD op2=4′b0000 CUST0

  // define a new instruction class

  // from which compiler,assembler,disassembler

  // routines are derived

  iclass sad {SAD} {out arr,in ars,in art}

  // semantic definition from which instruction-set

  // simulation and RTL descriptions are derived

  semantic sad_logic{SAD}{

      wire[8:0]diff01,diff11,diff21,diff31;

      wire[7:0]diff0r,diff1r,diff2r,diff3r;

      assign diff01=art[7:0]-ars[7:0];

      assign diff11=art[15:8]-ars[15:8];

      assign diff21=art[23:16]-ars[23:16];

      assign diff31=art[31:24]-ars[31:24];

      assign diff0r=ars[7:0]-art[7:0];

      assign diff1r=ars[15:8]-art[15:8];

      assign diff2r=ars[23:16]-art[23:16];

      assign diff3r=ars[31:24]-art[31:24];

      assign arr= 

          (diff01[8]?diff0r:diff01)+

          (diff11[8]?diff1r:diff11)+

          (diff21[8]?diff2r:diff21)+

          (diff31[8]?diff3r:diff31);

  }
这种描述表示为定义一条新指令所需的最少步骤。首先,有必要为这条新指令定义一组新的操作码。在这种情况下,新操作码SAD被定义为CUST0的子操作码。如上面所指出的那样,CUST0被预定义为:
opcode QRST op0=4’b0000
opcode CUST0 op1=4’b0100 QRST
很容易看出,QRST是顶层操作码。CUST0是QRST的子操作码,并且SAD又是CUST0的子操作码。操作码的这种层次结构组织允许操作码空间的逻辑分组和管理。要记住的一件重要事情就是CUST0(和CUST1)被定义为保留的操作码空间,以便用户添加新的指令。最好是,用户停留在所分配的操作码空间,以保证TIE描述的未来的可再用性。
在TIE描述中的第2个步骤是定义一个新的指令类,它含有新指令SAD。这就是SAD指令的各操作数被定义的地方。在这种情况下,SAD包括3个寄存器操作数,目标寄存器arr,源寄存器ars和art。如前面所指出的那样,arr被定义为用该指令的字段r索引的寄存器,ars和art被定义为用该指令的字段s和t索引的寄存器。
描述中的最后一块为SAD指令给出正式的语义定义。该描述使用Verilog HDL语言的一个子集,用以描述组合逻辑。正是这个块精确地规定ISS将如何对SAD指令进行仿真,以及如何合成一个附加电路并且被添加到可配置的处理器硬件中去以便支持新的指令。
其次,使用前面叙述的各种工具对TIE描述进行调试和验证。在验证TIE描述的正确性之后,下一个步骤就是评估新指令对硬件尺寸和性能的影响。如上所述,可以使用例如Design CompilerTM来完成这一步。当Design Compiler完成工作之后,用户可以注视其输出,以便得到详细的面积和速度报告。
在验证TIE描述为正确和有效之后,这就是配置和建造一个也支持新的SAD指令的可配置处理器的时间。如上所述,使用图形用户接口GUI来完成这一步。
再次,运动评估代码被编译为用于可配置处理器的代码,可配置处理器使用指令集仿真程序来验证程序的正确性,更重要的是测量其性能。用3个步骤来完成这一步:运行使用仿真程序的测试程序;运行基本实施方案以获得指令计数;以及运行新的实施方案以获得指令计数。
下面是第2个步骤的仿真输出:
   Block=(16,16),Search=(4,4),size=(32,32)
   TIE version passed
   Simulation Completed Successfully
   Time for Simulation=0.98 seconds
   Events                        Number Number

                                     per 100

                                      instrs
   Instructions                  226005(100.00)
   Unconditional taken branches       454(0.20)
   Conditional branches            37149(16.44)

      Taken                      26947(11.92)

      Not taken                   10202(4.51)
   Window Overflows                    20(0.01)
   Window Underflows                   19(0.01)
下面是最后一个步骤的仿真输出:
   Block=(16,16),Search=(4,4),size=(32,32)
   TIE version passed
   Simulation Completed Successfully
   Time for Simulation=0.36seconds
   Events                       Number Number

                                    per 100

                                     instrs
   Instructions                   51743(100.00)
   Unconditional taken branches       706(1.36)
   Conditional branches              3541(6.84)
   Taken                             2759(5.33)
   Not taken                          782(1.51)
   Window Overflows                    20(0.04)
   Window Underflows                   19(0.04)
从这两份报告可以看出,已经取得了大约4倍的加速。要注意的是,可配置处理器指令集仿真程序还能提供更多的其他有用信息。
在验证该程序的正确性和性能之后,下一个步骤就是使用如上所述的Verilog仿真程序来运行测试程序。专业人士可以从附录C的makefile中发现这个过程的细节(相关的各文件也在附录C中示出)。这种仿真的目的就是进一步地验证新的实施方案的正确性,并且,更重要的是,使得这段测试程序成为用于这个已配置的处理器的回归测试的一部分。
最后,可以使用例如Design CompilerTM来合成处理器逻辑,以及使用例如A polloTM来进行布局和布线。
为了说明的简明和简单起见,本实例对视频压缩和运动评估作了一次简化的观察。实际上,在标准压缩算法中,存在许多附加的细微差别。例如,MPEG2典型地用子像素分辨率来进行运动评估和补偿。各像素的两个相邻的行和列可以被平均,以生成一组像素,内插到介于两行或两列之间的想象中的一个理想位置上。在这里,由于仅用3或4行TIE代码就能容易地实现一组并行的像素平均算法。所以可配置处理器的用户定义指令再次成为有用的。在一行中的像素平均再次使用该处理器的标准指令集的有效的对准操作。
因此,纳入一条简单的差值的绝对值求和指令仅增加几百个门,然而对运动评估性能的改进超过10倍。这种加速表示在最终系统中在成本格和电源效率方面显著的改进。
而且,软件开发工具的无缝扩展(纳入新的运动评估指令)允许快速的原型研制、性能分析以及完整的软件应用程序解决方案的发表。本发明的解决方案使得专用处理器的配置简单、可靠和完整,并且在最终系统产品的成本、性能、功能和电源效率等方面提供引人注目的改进。
作为一个聚焦于添加一个硬件功能单元的实例,考虑图6所示的基本配置,其中包括处理器控制功能、程序计数器(PC)、分支选择、指令存储器或高速缓冲存储器和指令解码器,以及基本整数数据通路,其中包括主寄存器文件,旁路多路复用器,流水线寄存器,算术逻辑单元ALU,地址发生器以及用于高速缓冲存储器的数据存储器。
在有条件地出现乘法器逻辑(当设置”乘法器”参数时)的同时编写HDL,并且如图7所示,乘法器单元作为新的流水线级被添加(若需要支持精确的除外情况,则要求转换到除外情况处理)。当然,最好是伴随着新单元来添加使用乘法器的各种指令。
作为第2个实例,如图8所示,可以将一个全协处理器添加到基本配置,用作诸如乘法/累加单元那样的数字信号处理器。这就给处理器的控制带来一些改变,例如为乘法—累加运算添加各种解码控制信号,包括对来自扩展指令的源和目标寄存器的内容进行解码;为各控制信号添加适当的流水线延时;扩展寄存器目标逻辑;为一个寄存器旁路多路复用器添加控制,以便从累加寄存器送数,以及纳入一个乘法—累加单元,作为用于一条指令的执行结果的可能的源。此外,它还需要添加一个乘法—累加单元,后者带来了附加的各累加寄存器,用于主寄存器源的一个乘法—累加阵列和源选择多路复用器。同样,添加协处理器带来了来自累加寄存器的寄存器旁路多路复用器的扩展,它从累加寄存器取出一个源,并且扩展装载/对准多路复用器,以便从乘法器结果中取出一个源。再有,为了跟实际的硬件一起使用新的功能单元,本系统最好增添一些指令。
与数字信号处理器相结合显得特别有用的另一个选项就是一个浮点单元。这样一个实施例如IEEE 754单精度浮点运算标准的功能单元可以连同用于访问它的各项指令一起添加。浮点单元可以被用于例如数字信号处理的应用场合,诸如音频压缩和解压缩。
作为本系统的灵活性的又一个实例,考虑如图9所示的4KB存储器接口。使用本发明的可配置性,协处理器的各寄存器和各数据通路可以比主整数寄存器文件和数据通路宽些或窄些,并且本地存储器的宽度可以改变,使得存储器宽度等于最宽的处理器或协处理器的宽度(存储器在读和写时的寻址也相应地被调整)。例如,图10表示一个用于处理器的本地存储器系统,该处理器支持向一个处理器/协处理器组合的32位的装载和存储。上述组合在相同的阵列中寻址,但是该协处理器支持128位的装载和存储。这可以用TPP代码来实现
    function memory(Select,A1,A2,DI1,DI2,W1,W2,DO1,DO2)
    ;$B1=config_get_value(″width_of_port_1″);$B2=
    config_get_value(″width_of_port_2″);
    ;$Bytes=config_get_value(″size_of_memory″);
    ;$Max=max($B1,$B2);$Min=min($B1,$B2);
    ;$Banks=$Max/$Min;
    ;$Wide1=($Max==$B1);$Wide2=($Max==$B2);
    ;$Depth=$Bytes/(log2($Banks)*log2($Max));
    wire[`$Max`*8-1:0]Data1=`$Wide1`?DI1:{`$Banks`{DI1}};
    wire[`$Max`*8-1:0]Data2=`$Wide1`?DI2:{`$Banks`{DI2}));
    wire[`$Max`*8-1:0]D=Select?Data1:Data2;
    wire Wide=Select?Wide1:Wide2;
    wire[log2(`$Bytes`)-1:0]A=Select?A1:A2;
  wire[log2(`$Bytes`)-1:0]Address=A[log2(`SBytes`)-
  1:log2($Banks)]:
  wire[log2(`$Banks`)-1:0]Lane=A[log2($Banks`)-1:0];
  ;for($i=0;$i<$Banks;$i++){

    wire WrEnable{i}=Wide|(Lane=={i});

    wire[log2(`$Min`)-1:0]WrData`$i`=D[({i}+1)*`$Min`*8-
  1:{1}*$Min*8]

    ram(RdData`$i`,Depth,Address,WrData`$i`,WrEnable`$i`);
  ;}
  wire[`$Max`*8-1:0]RdData={
  ;for($i=0;$i<$Banks;$i++){
    RdData`$i`,
  ;}

    }
  wire[`$B1`*8-1:0] DO1=Widel?RdData:RdData[(Lane+1)*B1*8-
  1:Lane*B1*8];
  wire[`$B2`*8-1:0] DO2=Wide2?RdData:RdData[(Lane+1)*B2*8-
  1:Lane*B2*8];
在这里,$Bytes是总的存储器大小,在写信号W1的控制下,在数据总线D1的字节地址A1处,以宽度B1进行存取,或者使用对应的参数B2,A2,D2和W2。在一个给定的周期中,只有一组由Select定义的信号是活动的。TPP代码将存储器实现为存储器池的一个集合。每一个池的宽度由最小存取宽度以及池的数目乘以最大与最小存取宽度之比来给出。一个for循环被用来具体说明每一个存储器池及其相关的写信号,即,写使能和写数据。第2个for循环被用来收集从所有各池读出的数据,并将其送到一组单独的总线。
图11表示将用户定义的各项指令纳入到基本配置之中的一个实例。如图所示,可以用类似于算术逻辑单元ALU那样的定时和接口将简单指令添加到处理器流水线中去。以这种方式添加的各项指令应当不产生挂起或除外情况,不含有状态,仅使用两个普通的源寄存器数值以及指令字作为输入,并产生一个单独的输出数值。然而,若TIE语言具有指定处理器状态的规定,则这样的约束条件就是不必要的。
图12表示在这个系统中实现一个用户定义单元的另一个实例。图中所示的功能单元,ALU的一个8/16并行数据单元扩展,从下列ISA代码中产生:
      Instruction{

      Opcode    ADD8_4     CUSTOM      op2=0000

      Opcode    MIN16_2    CUSTOM      op2=0001

      Opcode    SHIFT16_2  CUSTOM      op2=0002

      iclass         MY    4ADD8,2MIN16,SHIFT16_2

          a<t,a<s,a>t

      }

      Implementation{

      input[31:0]art,ars;

      input[23:0]inst;

      input ADD8_4,MIN16_2,SHIFT16_2;

      output[31:0]arr;

  wire[31:0]add,min,shift;

  assign add={(art[31:24]+ars[31:24],art[23:16]+art[23:16],

  art[15:8]+art[15:8],art[7:0]+art[7:0]};

  assign min[31:16]=art[31:16]<ars[31:16]?Art[31:16]:

  ars[31:16];

  assign min[15:0]=art[15:0]<ars[15:0]?Art[15:0]:

  ars[15:0];

  assign shift[31:16]=art[31:16]<<ars[31:16];

  assign shift[15:0]=art[15:0]<<ars[15:0];

  assign arr={32{ADD8_4}} &amp; add|{32{MIN16_2}} &amp; min|

  {32{SHIFT16_2}} &amp; shift;

  }
在本发明的另一个方面,特别感兴趣的是,设计者定义指令执行单元96,TIE定义的各项指令,包括那些修改处理器状态的指令,就是在这个单元中被解码和执行。在本发明的这个方面,多个积木块已经被添加到语言之中,使之有可能说明能够被新指令读和写的附加的处理器状态。“状态”语句被用来说明附加的处理器状态。该说明开始于关键字state。状态语句的下一部分说明该状态的大小和各比特的号码,以及该状态的各比特是如何被索引的。其后的部分是状态名,用以标识在其他说明部分中的状态。状态语句的最后一部分是与该状态有关的属性的一份列表。例如,
state[63:0]DATA cpn=0 autopack
state[27:0]KEYC cpn=1 nopack
state[27:0]KEYD cpn=1定义3种新的处理器状态,DATA,KEYC和KEYD。状态DATA是64比特宽度,其各比特被索引为从63到0。KEYC和KEYD二者都是28比特的状态。DATA具有一种协处理器号码属性cpn,表示数据DATA属于哪一个协处理器。
属性“autopack”表示状态DATA将自动地被映射到用户寄存器文件中的某些寄存器,使得DATA的数值能够被各种软件工具读和写。
user_register部分被定义为表示将状态映射到在用户寄存器文件中的各寄存器。user_register部分开始于一个关键字user_register,其后跟随着一个表示寄存器号码的数字,并且以一个表示待映射到寄存器的各状态比特的表达式作为结尾。例如,
          user_register 0  DATA[31:0]
          user_register 1  DATA[63:32]
          user_register 2  KEYC
          user_register 3  KEYD
          user_register 4  {X,Y,Z}指定DATA的低位字被映射到第1用户寄存器文件,并且高位字被映射到第2用户寄存器文件。其后的两个用户寄存器文件行被用来保存KEYC和KEYD的数值。显而易见,在这一部分中所使用的状态信息应当跟state部分所使用的保持一致。这里,可以通过一段计算机程序来自动地检查此项一致性。
在本发明的另一个实施例中,使用箱式包装(bin-packing)算法自动地将各状态比特分配到用户寄存器文件的各行。在又一个实施例中,可以使用例如人工和自动分配的组合来保证向上的兼容性。
指令字段语句field被用来改进TIE代码的可读性。各字段是被集合在一起并且用名字来引用的其他字段的各连锁的各子集。在一条指令中各比特的完全集是最高级的超集字段inst,并且这个字段可以被划分为较小的各字段。例如,
field x    inst[11:8]
field y    inst[15:12]
field xy   [x,y]将两个4比特字段x和y,定义为一个最高级字段inst的子字段(分别是比特8-11和12-15),以及将一个8比特字段xy定义为x和y字段的连锁。
语句opcode为编码专用字段定义操作码。打算指定操作数的指令字段,例如,准备由这样定义的操作码使用的寄存器或立即常数,应当首先用field语句加以定义,然后用operand语句加以定义。
例如,
opcode    acs    op2=4’b0000  CUST0
opcode    adse1  op2=4’b0001  CUST0基于事先定义的操作码CUST0(4’b0000表示一个4比特长的二进制常数0000)来定义两组新的操作码acs和adse1。优选的核心ISA的TIE描述具有下列语句
    field op0  inst[3:0]
    field op1  inst[19:16]
    field op2  inst[23:20]
    opcode     QRST  op0=4′b0000
    opcode     CUST0 op1=4′b0100 QRST作为它的基本定义的一部分。因此,acs和adse1的定义使得TIE编译程序产生分别由下列语句表示的指令解码逻辑:
inst[23:0]=0000 0110 xxxx xxxx xxxx 0000
inst[23:0]=0001 0110 xxxx xxxx xxxx 0000
指令操作数语句operand标识各寄存器和立即常数。然而,在将一个字段定义为一个操作数之前,它应当事先已经被定义为一个如上所述的字段。若该操作数是一个立即常数,则可以从该操作数产生该常数的数值,或者可以从一个事先定义的常数表中将它取出,常数表的定义将在下面叙述。例如,为了对一个立即操作数进行编码,TIE代码
  field            offset       inst[23:6]
  operand          offests4    offset{

     assign      offsets4={{14(offset[17]}},offset}<<2;
  }{

     wire        [31:0]t;

  assign    t=offsets4>>2;

  assign    offset=t[17:0];
  }
定义一个18位的、名为offset的字段,它保存一个有符号数以及一个操作数offsets4,后者是存储在offset字段中的数的4倍。如同专业人士所懂得的那样,operand语句的最后一部分实际上描述在用于描述组合电路的VerilogTM HDL的一个子集中用以进行计算的电路。
这里,wire语句定义一组名为t的逻辑接线,其宽度为32位。在wire语句之后的第1 assign语句指定驱动逻辑接线的逻辑信号为offsets4,并且第2 assign语句指定t的低18位被放进offset字段。第1 assign语句直接地指定操作数offsets4的值为offset以及它的符号位(位17)以及跟随在其后的左移两位的14份拷贝的一个连锁。
对一个常数表操作数来说,TIE代码
  table prime 16{

        2,3,5,7,9,11,13,17,19,23,29,31,37,41,43,47,

  53

  }

  operand        prime_s s{

       assign    prime_s=prime[s];

  }{
				
				<dp n="d70"/>
  assign s=prime_s==prime[0]    ?   4′b0000:

          prime_s==prime[1]    ?   4′b0001:

          prime_s==prime[2]    ?   4′b0010:

          prime_s==prime[3]    ?   4′b0011:

          prime_s==prime[4]    ?   4′b0100:

          prime_s==prime[5]    ?   4′b0101:

          prime_s==prime[6]    ?   4′b0110:

          prime_s==prime[7]    ?   4′b0111:

          prime_s==prime[8]    ?   4′b1000:

          prime_s==prime[9]    ?   4′b1001:

          prime_s==prime[10]   ?   4′b1010:

          prime_s==prime[11]   ?   4′b1011:

          prime_s==prime[12]   ?   4′b1100:

          prime_s==prime[13]   ?   4′b1101:

          prime_s==prime[14]   ?   4′b1110:

                                      4′b1111;
利用table语句来定义一个常数数组prime(跟随在表名之后的数字是表中各元素的号码),并使用这些操作数作为进入该表prime的索引,以便为操作数prime_s编码一个数值(注意在定义索引时,VerilogTM语句的使用)。
指令类语句iclass在一种共同格式中将操作码和操作数联系在一起。在一个iclass语句中定义的所有指令都具有相同的格式和操作数用法。在定义一个指令类之前,它的各成员必须首先被定义为字段,然后被定义为操作码和操作数。例如,建立在前面的定义操作码acs和adse1的实例的基础上,附加语句
  operand    art    t    {assign art=AR[t];}  {}
  operand    ars    s    {assign ars=AR{s};}  {}
  operand    arr    r    {assign AR[r]=arr;)  {}使用operand语句来定义3个寄存器操作数art,ars和arr(再次注意在定义中VerilogTM语句的使用)。然后,iclass语句
iclass viterbi[adse1,acs][out arr,in art in ars]指定操作数adse1和acs属于指令viterbi的一个共同类,它取两个寄存器操作数art和ars作为输入,并将输出写入到一个寄存器操作数arr中去。
在本发明中,指令类语句iclass被修改,以便允许对各指令的状态访问信息进行说明。它开始于关键字“iclass”,其后跟随着该指令类的名字,属于该指令类的操作码的列表以及操作数访问信息的一份列表,并且结束于一份新定义的、用于状态访问信息的列表。例如,
iclass lddata {LDDATA} {out arr,in imm4} {in DATA}
iclass stdata {STDATA} {in ars,in art)   {out DATA}
iclass stkey  {STKEY}  {in ars,in art}   {out KEYC,out KEYD}
iclass des      {DES}    {out arr,in imm4}  {inout KEYC,inoutDATA,inout KEYD}定义几个指令类以及各种新指令如何访问各种状态。关键字“in”,“out”和“inout”被用来指示该状态被iclass中的各指令读出、写入或修改(读出和写入)。在本实例中,状态“DATA”被指令“LDDATA”读出,状态“KEYC”和“KEYD”被指令“STKEY”写入,“KEYC”,“KEYD”和“DATA”被指令“DES”修改。
指令语义语句semantic描述一条或多条指令的行为,这些指令使用用于对操作数进行编码的VerilogTM的相同子集。通过在一条单独的semantic语句中定义多条指令,某些共同的表达式可以共享,并且硬件实施方案可以变得更加有效。在semantic语句中允许使用的变量是在该语句的操作码列表中定义的用于各操作码的各操作数,以及在该操作码列表中为每一组操作码指定的一个单比特变量。该变量具有与操作码相同的名字,并且当该操作码被检出时,它被估值为1。它被用于计算部分(VerilogTM子集部分),用以指示相应的指令的出现。
  // define a new opcode for BYTESWAP based on

  // -a predefined instruction field op2

  // -a predefined opcode CUST0

  // refer to Xtensa ISA manual for descriptions of op2 and CUST0

  opcode BYTESWAP op2=4′b0000 CUST0

  //declare state SWAP and COUNT

  state COUNT    32
  state SWAP     1

  // map COUNT and SWAP to user register file entries

  user_register 0 COUNT

  user_register 1 SWAP

  // define a new instruction class that

  // -reads data from ars(predefined to be AR[s])

  // -uses and writes state COUNT

  // -uses state SWAP

  iclass bs  {BYTESWAP}    {out arr,in ars}  {inout COUNT,in
SWAP}

  // semantic definition of byteswap

  //    COUNT the number of byte-swapped words

  //    Return the swapped or un-swapped data depending on SWAP

  semantic bs {BYTESWAP}{

       wire          [31:0]        ars_swapped
{ars[7:0],ars[15:8],ars[23:16],ars[31:24]};

       assign arr=SWAP?ars_swapped:ars;

       assign COUNT=COUNT+SWAP;

  }
上述代码的第1部分为新指令定义一组操作码,称为BYTESWAP。
  // define a new opcode for BYTESWAP based on

  // -a predefined instruction field op2

  // -a predefined opcode CUST0

  // refer to xtensa IsA marnual for descriptions of op2 and CUST0

  opcode BYTESWAP op2=4′b0000 CUST0
这里,新操作码被定义为CUST0的一组子操作码。从下面详细叙述的《XtensaTM指令集体系结构参考手册》中,可以看出CUST0被定义为
opcode QRST op0=4’b0000
opcode CUST0 op1=4’b0100 QRST
在这里,op0和op1都是指令中的字段。典型地按照一种层次结构的样式来组织各操作码。这里,QRST是顶级操作码,CUST0是QRST的子操作码,并且BYTESWAP又是CUST0的子操作码。操作码的这种层次结构组织允许对操作码空间进行逻辑的集群和管理。
第2段说明表示BYTESWAP指令所需的附加的处理器状态:
//declare state SWAP and COUNT
state COUNT    32
state SWAP   1这里,COUNT被说明为一种32比特的状态,而SWAP为1个比特的状态。TIE语言指定在COUNT中的各比特从31到0进行索引,其中比特0为最低位。
XtensaTM ISA提供两条指令,RSR和WSR,用于(将数据)存入专用的系统寄存器以及从其中取出。类似地,它提供两条其他指令,RUR和WUR(下面将作详细说明),用于存储和恢复在TIE中被说明的各种状态。为了存储和恢复在TIE中被说明的各种状态,必须在RUR和WUR指令能够访问的用户寄存器文件中指定由各状态到各行的映射关系。上述代码的下列部分指定这种映射关系:
//map COUNT and SWAP to user register file entries
user_register 0 COUNT
user_register 1 SWAP使得下列各指令将COUNT的数值保存到a2,并将SWAP的数值保存到a5:
RUR a2,0;
RUR a5,1;
这种机制实际上被用于测试程序中,用以验证各状态的各项内燃机车。在C语言中,上述两条指令具有下列形式:
x=RUR(0);
y=RUR(1);
TIE描述的嵌套部分是含有新指令BYTESWAP的新指令类的定义:
  // define a new instruction class that

  // -reads data from ars(predefined to be AR[s])

  // -uses and writes state COUNT

  // -uses state SWAP

  iclass bs{BYTESWAP}{out arr,in ars}{inout COUNT,in
SWAP}
在这里,iclass是关键字,bs是iclass的名字。下一个子句列出在指令类(BYTESWAP)中的指令。其后的指令指定在这个类中的各指令所使用的操作数(在本例中为一个输入操作数ars和一个输出操作数arr)。在iclass定义中的最后一个子句指定在这个类中被该指令访问的各种状态(在本例中,该指令将对状态SWAP进行读出,对状态COUNT进行读和写)。
上述代码的最后一块为BYTESWAP指令给出正式的语义定义:
      // semantic definition of byteswap

      // COUNT the number of byte-swapped words

      // Return the swapped or un-swapped data depending on SWAP

      semantic bs{BYTESWAP}{

          wire            [31:0]         ars_swapped

  {ars[7:0],ars[15:8],ars[23:16],ars[31:24]};

              assign arr=SWAP?ars_swapped:ars;

              assign COUNT=COUNT+SWAP;

      }
该描述使用Verilog HDL的一个子集来描述组合逻辑。正是这个块精确地规定指令集仿真程序将如何仿真BYTESWAP指令,以及附加电路如何被合成并且被添加到XtensaTM处理器硬件之中,以支持新的指令。
在实现各种用户定义状态的本发明中,被说明的状态可以像其他变量那样被使用,以便访问存储在各种状态中的信息。出现在一个表达式右边的一个状态标识符指示从该状态读出。通过将一个数值或者一个表达式分配给状态标识符,就能完成写入到一种状态。例如,下面的语义代码段表示一条指令如何读出或写入各种状态:
assign KEYC=sr==8′d2?art[27:0]:KEYC;
assign KEYD=sr==8′d3?art[27:0]:KEYD;
assign DATA=sr==8′d0?{DATA[63:32],art}:{art,DATA[63:32]};
为了说明在可配置处理器中,可以作为核心指令而被执行的各种指令的实例,以及经由各配置选项的选择变为可用的各指令的目的,Tensilica公司出版的《XtensaTM指令集体系结构(ISA)参考手册》修订版1.0已作为参考文献被收入本文。还有,为了说明能够被用来执行这样的用户定义指令的TIE语言指令的各种实例,同样由Tensilica公司出版的《指令扩展语言(TIE)参考手册》修订版1.3也已作为参考文献被收入本文。
从TIE描述中,可以使用例如,类似于附录D所示的一段程序来产生执行这些指令的硬件实施方案。附录E表示为了如同内部函数那样支持新的指令所需的头文件而使用的代码。
使用配置说明,可以自动地生成下列各项:
—处理器60的指令解码逻辑;
—用于处理器60的非法指令检测逻辑;
—汇编程序的ISA专用部分;
—用于编译程序的ISA专用支持程序;
—反汇编程序的ISA专用部分(为调试程序所使用);以及
—仿真程序的ISA专用部分。
图16是一份图,表示这些软件工具的ISA专用部分是如何产生的。TIE语法分析程序410从用户生成的TIE描述文件400为几段程序生成C语言代码,上述程序中的每一段都产生一个文件,该文件可以被一种或多种软件开发工具所访问,以便得到关于用户定义指令和状态的信息。例如,程序tie2gcc 420生成一个称为xtensa_tie.h的C语言头文件470,其中包括针对新指令的内部函数。程序tie2isa 430生成一个动态连接库(DLL)480,其中含有关于用户定义指令格式的信息(在下面所讨论的Wilson等人的专利申请中,这是其中所讨论的编码与解码DLL的有效组合)。程序tie2iss 440生成性能模拟程序,并产生一个含有指令语义的DLL490,正如在Wilson等人的专利申请中所讨论的那样,该指令语义被主机编译程序用来产生为该仿真程序所使用的仿真程序DLL。程序tie2ver 450以一种适当的硬件描述语言为用户定义的各项指令产生必要的描述500。最后,程序tie2xtos 460产生为RUR和WUR指令所使用的保存与恢复代码510。
对各项指令的精细描述以及它们如何访问各种状态使得它有可能产生有效的逻辑,该逻辑可以插入到现有的高性能微处理器设计之中。结合本发明的这个实施例而叙述的各种方法专门处理那些从一个或多个状态寄存器读出或写入其中的各项新指令。特别是,本实施例表示在微处理器类的实现方式的意义上,如何导出用于各状态寄存器的硬件逻辑,上述微处理器的实现方式全都使用流水线,作为获得高性能的一种技术。
在例如图17所示的流水线实施方案中,一个状态寄存器被典型地复制若干次,每一项具体说明都表示处于一个特定流水线级之中的状态的数值。在本实施例中,一种状态被转换为与优先的核心处理器实施方案相一致的寄存器的多个拷贝。同时,再次以跟优先的核心处理器实施方案相一致的方式产生附加的旁路和前向逻辑。例如,为了瞄准一个含有3个执行阶段的核心处理器实施方案,本实施例将一种状态转换为3个寄存器,其连接方式如图18所示。在这个实施方案中,每一个寄存器610-630都表示在3个流水线级其中之一的状态in的数值。ctrl-1,ctrl-2,和ctrl-3都是控制信号,用以在相应的触发器610-630中激活数据锁存功能。
为了制作状态寄存器的多个拷贝而进行的跟优先的处理器实施方案相一致的工作要求附加的逻辑和控制信号。“一致”意味着状态应当表现出与在中断、除外情况和流水线挂起等情况下处理器的其余各种状态精确地相同。典型地,一种给定的处理器实施方案定义表示各种流水线条件的某些信号。要求这样的信号能使流水线状态寄存器正确地进行工作。
在一个典型的流水线实施方案中,执行单元包括多个流水线级。在这条流水线的多个级中进行一条指令的计算。指令流按照由控制逻辑所引导的序列从流水线中流过。在任何给定的时间,在流水线中都可能有多达n条指令被执行。这里n为级的数目。在一个超标量的处理器中,也可以使用本发明来实现,在流水线中的指令的数目可以是n×w,其中,w是处理器的出口宽度。
控制逻辑的作用是确认介于各指令之间的依赖性得到遵守,并且介于各指令之间的任何干扰都得以解决。若一条指令使用由一条先前的指令计算出来的数据,则需要专门的硬件在不阻塞流水线的情况下将数据送到后一条指令。若出现中断,则在流水线中的所有指令都需要被杀掉,然后再重新执行。当由于不具备它所需要的输入数据或计算硬件而使得指令无法执行时,该指令应当被挂起。挂起一条指令的廉价的方法是在它的第1执行阶段就把它杀掉,并在下一个周期中重新执行该指令。这种技术的结果就是在流水线中生成一个无效的级(气泡)。这个气泡连同其他指令一起,流过该流水线。在各指令被损坏的流水线的末端,这些气泡被抛弃。
使用上述3级流水线的实例,这样一种处理器状态的典型的实施方案所需的附加逻辑和连接示于图19。
在正常情况下,在一级中计算出来的数值将被立即送往下一条指令,而不必等待该数值到达流水线的末端,以便减少因数据依赖性而引入的流水线挂起的次数。通过直接地将第1触发器610的输出送往语义块,使得它能够立即被下一条指令所使用,就能完成这一步。为了处理诸如中断和除外等异常情况,本实施方案需要下列3种控制信号:Kill_1,Kill_all,和Valid_3。
信号Kill_1表示由于例如不具备它所需要的数据,所以当前处于第1流水线级110的指令应当被杀掉。信号Kill_all表示由于它们前面的一条指令已经产生一种除外情况或者已经出现一次中断,所以在流水线中的所有指令都应当被杀掉。信号Valid_3表示当前处于最后一级630之中的指令是否有效。这种情况通常是在第1流水线级610中杀掉一条指令以及在流水线中出现一个气泡(无效指令)的结果。“Valid_3”简单地表示在第3流水线级之中的指令是有效的还是一个气泡。显而易见,只有有效的指令应当被锁存。
图20表示为实现状态寄存器所需的附加逻辑和连接。它同时表示如何构建控制逻辑,以驱动各信号“ctrl-1”,“ctrl-2”和“ctrl-3”,使得状态寄存器的实施方案符合上述各项要求。下面是为了实现图19所示的状态寄存器而自动地生成的样本HDL代码。
    module tie_enflop(tie_out,tie_in,en,clk);

    parameter size=32;
  output[size-1:0]tie_out;
  input[size-1:0] tie_in;
  input            en;
  input            clk;
  reg[size-1:0]   tmp;
  assign tie_out=tmp;
  always @ (posedge clk)begin

  if(en)

     tmp<=#1 tie_in;
  end
  endmodule
  module tie athens state(ns,we,ke,kp,vw,clk,ps);
  parameter size=32;
  input[size-1:0]ns; //next state
  input we;      //write enable
  input ke;      // Kill E state
  input kp;      //Kill Pipeline
  input vw;      //Valid W state
  input clk;     //clock
  output[size-1:0]ps;//present state
  wire[size-1:0]se;  //state at E stage
  wire[size-1:0]sm;  //state at M stage
  wire[size-1:0]sw;  //state at W stage
  wire[size-1:0]sx;  //state at X stage
  wire ee;    //write enable for EM register
  wire ew;    // write enable for WX register
  assign se=kp?sx:ns;
  assign ee=kp|we &amp;~ke;
  assign ew=vw &amp; ~kp;
  assign ps=sm;
  tie_enflop #(size)state_EM(.tie_out(sm),.tie in(se),.en(ee),

      \.clk(clk));
  tie_enflop       #(size)    state_MW(.tie_out(sw), .tie_in(sm),

      .en(1′b1),\.clk(clk));
  tie_enflop #(size)state_WX(.tie_out(sx),.tie_in(sw),.en(ew),

     \.clk(clk));
  endmodule
若语义块指定该状态作为它的输入,则使用上述的流水线状态寄存器模型,将该状态的当前状态值作为一个输入变量送往语义块。若语义块具有为一种状态产生新数值的逻辑,则生成一组输出信号。这个输出信号被用来作为下一个状态,输入到流水线状态寄存器。
本实施例允许多个语义描述块,其中的每一个都描述多条指令的行为。在这种不受约束的描述方式下,有可能只有各语义块的一个子集为一种给定状态产生下一个状态的输出。而且,也可能一个给定的语义块有条件地依赖于在一段给定时间内,它执行什么指令而产生下一个状态的输出。因而,需要附加的硬件逻辑去从所有语义块中组合下一个状态输出,以形成送往流水线状态寄存器的输入。在本发明的这个实施例中,为每一个语义块自动地导出一组信号,以表示该块是否已经为该状态产生一个新的数值。在另一个实施例中,这样一组信号可以留给设计者去说明。
图20表示如何从几个语义块s1-sn组合一种状态的下一个状态输出,并且适当地选择其中的一个以便输入到状态寄存器。在这份图中,op1_1和op1_2是用于第1语义块的操作码信号,op2_1和op2_2是用于第2语义块的操作码信号,等等。语义块i的下一个状态输出是si(若有多个状态寄存器,则针对该块有多个下一个状态输出)。该信号表示该语义块i已经为该状态si_we产生一个新的数值。信号s_we表示是否有任何的语义块为该状态产生一个新的数值,并且被用来作为写使能信号输入到流水线状态寄存器。
即使多语义块的表达能力不大于单语义块的,它仍然典型地通过把相关的指令集中到一个单独的块,来提供更加结构化的描述。由于在更受限制的范围内来执行这些指令,所以多语义块还能够导致对指令效果的更简单的分析。另一方面,对一个单语义块来说,通常有理由去描述多条指令的行为。最常见的是,这是由于这些指令的硬件实施方案共亨公共的逻辑。在一个单语义块中描述多条指令通常会导致更有效的硬件设计。
由于中断和除外情况,对软件来说,有必要向数据存储器装入各种状态的数值,以及从其中恢复(取出)各种状态的数值。基于新状态和新指令的正式描述,有可能自动地产生这样的恢复与装载指令。在本发明的一个实施例中,用于恢复与装载的逻辑被自动地产生为两个语义块,后者可以被递归地转换为恰似任何其他块的实际的硬件。例如,从下列状态的说明中:
        state[63:0]DATA cpn=0 autopack

        state[27:0]KEYC cpn=1 nopack

        state[27:0]KEYD cpn=1

        user_register 0=DATA[31:0];

        user_register 1=DATA[63:32];

        user_register 2=KEYC;

        user register 3=KEYD;
可以产生下列语义块,以便将“DATA”,“KEYC”和“KEYD”的数值读入各通用寄存器:
iclass rur {RUR}{out arr,in st}{in DATA,in KEYC,in KEYD}
semantic rur (RUR){

  wire sel_0=(st==8′d0);

  wire sel_1=(st==8′d1);

  wire sel_2=(st==8′d2);

  wire sel_3=(st  ==8′d3);

  assign arr={32{sel_0}}&amp; DATA[31:0]   |

              {32{sel_1}}&amp; DATA[64:32]  |

              {32{sel_2}}&amp; KEYC          |

              {32{sel_3}}&amp; KEYD;
}
图21表示对应于这一类语义逻辑的逻辑的方框图。输入信号”st”跟各种常数进行比较,以形成各种选择信号,它们被用来以跟user_register说明相一致的方法,从各状态寄存器中选择某些位。使用先前的状态说明,DATA的位32映射到第2用户寄存器的位0。因此,在此图中MUX的第2输入应当被连接到DATA状态的第32位。
可以产生下列语义块,将来自各通用寄存器的数值写入状态“DATA”,“KEYC”和“KEYD”
  iclass wur{WUR}{in art,in sr}{out DATA.out KEYC,out KEYD}

  semantic wur (WUR){

      wire sel_0=(st==8′d0);

      wire sel_1=(st==8′d1);

      wire sel_2=(st==8′d2);

      wire sel_3=(st==8′d3);

      assign DATA={sel_1?art:DATA[63:32],sel_0?art:
  DATA[31:0]};

      assign KEYC=art;

      assign KEYD=art;

      assign DATA_we=WUR;

      assign KEYC_we=WUR &amp; sel_2;

      assign KEYD_we=WUR &amp; sel_3;

  }
图22表示当被映射到第i个用户寄存器的第k位时,状态S的第j位的逻辑。在一条WUR指令中,若user_register号码“st”为“i”,则“ars”的第k位被装载到S[j]寄存器;否则,S[j]的原始数值被再次循环。此外,若状态S的任何位被重新装载,则信号S_we被激活。
TIE user_register说明指定从由状态说明定义的附加处理器状态到由这些RUR和WUR指令所使用的一个标识符的映射关系,以便对独立于TIE指令之外的这种状态进行读和写。
附录F表示用于产生RUR和WUR指令的代码。
RUR和WUR指令的主要用途是用于任务切换,在一个多任务环境中,多任务软件共享根据某些调度算法来运行的处理器。当被激活时,该任务的状态驻留在处理器的寄存器之中。当调度算法决定切换到另一项任务时,被保存在处理器的各寄存器之中的状态被存入到存储器之中,并将另一项任务的状态从存储器装载到处理器的寄存器之中。XtensaTM指令集体系结构(ISA)包括RSR和WSR指令,用以对ISA所定义的状态进行读和写。例如,下列代码是任务“存入存储器”的一部分:
     //save special registers

     rsr  a0,SAR

     rsr  a1,LC0UNT

     s32i a0,a3,UEXCSAVE+0

     s32i a1,a3,UEXCSAVE+4

     rsr  a0,LBEG

     rsr  a1,LEND

     s32i a0,a3,UEXCSAVE+8

     s32i a1,a3,UEXCSAVE+12
  ;if(config_get_value(″IsaUseMAC16″)){

     rsr  a0,ACCLO

     rsr  a1,ACCHI

     s32i a0,a3,UEXCSAVE+16

     s32i a1,a3,UEXCSAVE+20

     rsr  a0,MR_0

     rsr  a1,MR_1

     s32i a0,a3,UEXCSAVE+24

     s32i a1,a3,UEXCSAVE+28

     rsr  a0,MR_2

     rsr  a1,MR_3

     s32i a0,a3,UEXCSAVE+32

     s32i a1,a3,UEXCSAVE+36
  ;}
以及下列代码是任务“从存储器恢复”的一部分:
     // restore special registers

     132i a2,a1,UEXCSAVE +   0

     132i a3,a1,UEXCSAVE +   4

     wsr  a2,SAR

     wsr  a3,LCOUNT

     132i a2,a1,UEXCSAVE +   8

     132i a3,a1,UEXCSAVE +  12

     wsr  a2,LBEG

     wsr  a3,LEND
 ;if(config_get_value(″IsaUseMAC16″)}{

     132i a2,a1,UEXCSAVE+16

     132i a3,a1,UEXCSAVE+20

     wsr  a2,ACCLO

     wsr  a3,ACCHI

     132i a2,a1,UEXCSAVE+24

     132i a3,a1,UEXCSAVE+28

     wsr  a2,MR_0

     wsr  a3,MR_1
				
				<dp n="d83"/>
      132i a2,a1,UEXCSAVE+32

      132i a3,a1,UEXCSAVE+36

      wsr  a2,MR_2

      wsr  a3,MR_3

  ;}
在这里,SAR,LCOUNT,LBEG,LEND都是核心XtensaTM ISA的处理器状态寄存器部分,并且ACCLO,ACCHI,MR_0,MR_1,MR_2和MR_3都是MAC 16 xtensaTMISA选项的一部分。(各寄存器都以成对方式被存储和恢复,以避免流水线互锁。)
当设计者用TIE来定义新的状态时,它也必须像以上的状态那样进行任务切换。对设计者来说,一种可能性就是,简单地编写任务切换代码(上面已经给出其中的一部分)以及添加类似于上述代码的指令RUR/S32I和L32I/WUR。然而,当软件被自动地产生并且在结构上是正确的时,可配置的处理器将是最有效的。因此,本发明包括一种装置,用以自动地增加任务切换代码。下列的各tpp行被添加到上述的存储任务中去:
      ;my $off=0;

      ;my $i;

      ;for($i=0;$i<$#user_registers;$i+=2){

          rur  a2,`$user_registers[$i+0]`

          rur  a3,`$user_registers[$i+1]`

          s32i a2,UEXCUREG+`$off+0`

          s32i a3,UEXCUREG+`$off+4`

      ;$off+=8;

      ;}

      ;if(@user_registers &amp; 1){

      ;# odd number of user registers

        rur  a2,`$user_registers[$#user_registers]`

        s32i a2,UEXCUREG+`$off+0`

      ;$off+=4;

      ;}
以及下列各行被添加到上述恢复任务中去:
      ;my $off=0;

      ;my $i;

      ;for($i=0;$i<$#user_registers;$i+=2){

          132i a2,UEXCUREG+`$off+0`

          132i a3,UEXCUREG+`$off+4`

          wur  a2,`$user_registers[$i+0]`

          wur  a3,`$user_registers[$i+1]`

      ;$off+=8;

      ;} 

      ;if(@user_registers &amp; 1){

      ;# odd number of user registers

          132i a2,UEXCUREG+`$off+0`

          wur  a2,`$user_registers[$#user_registers]`

      ;$off+=4;

      ;}
最后,在存储器中的任务状态区域应当具有分配给用户寄存器存储的附加的空间,并且这个空间从任务存储指针的基地址算起的偏移量被定义为汇编程序常数UEXCUREG。这个存储区域事先用下列代码加以定义
    #define UEXCREGSIZE(16*4)

    #define UEXCPARMSIZE(4*4)

    ;if(&amp;config_get_value(″IsaUseMAC16″)){

    #define UEXCSAVESIZE(10*4)

    ;}else{

    #define UEXCSAVESIZE(4*4)

    ;}

    #define UEXCMISCSIZE(2*4)

    #define UEXCPARM 0

    #define UEXCREG(UEXCPARM+UEXCPARMSIZE)

    #define UEXCSAVE(UEXCREG+UEXCREGSIZE)

    #define UEXCMISC(UEXCSAVE+UEXCSAVESIZE)

    #define UEXCWIN(UEXCMISC+0)

    #define                             UEXCFRAME
(UEXCREGSIZE+UEXCPARMSIZE+UEXCSAVESIZE+UEXCMISCSIZE)
which is changed to

  #define UEXCREGSIZE(16*4)

  #define UEXCPARMSIZE(4*4)

  ;if(&amp;config_get_value(″IsaUseMAC16″)){

  #define UEXCSAVESIZE(10*4)

  ;}else{

  #define UEXCSAVESIZE(4*4)

  ;}

  #define UEXCMISCSIZE(2*4)

  #define UEXCUREGSIZE `@user_registers * 4`

  #define UEXCPARM 0

  #define UEXCREG(UEXCPARM+UEXCPARMSIZE)

  #define UEXCSAVE(UEXCREG+UEXCREGSIZE)

  #define UEXCMISC(UEXCSAVE+UEXCSAVESIZE)

  #define UEXCUREG(UEXCMISC+UEXCMISCSIZE)

  #define UEXCWIN(UEXCUREG+0)

  #define UEXCFRAME\

  (UEXCREGSIZE+UEXCPARMSIZE+UEXCSAVESIZE+UEXCMISCSIZE+UEXCUREGSIZE

  )
这个代码依赖于存在一个tpp变量@user_register,它有一份用户寄存器号码的列表,这简单地是一份从每一个user_register语句的第1自变量生成的列表。
在某些更复杂的微处理器实施方案中,可以在不同的流水线状态中计算出一种状态,处理这一步需要对这里所描述的过程作出若干扩展(虽然是简单的扩展)。首先,描述语言需要扩展,使之能够将一个语义块跟一个流水线级联系在一起。可以用几种方法当中的一种来完成这一步。在一个实施例中,可以用每一个语义块明显地指定相关的流水线级。在另一个实施例中,可以为每一个语义块指定流水线级的一个范围。在又一个实施例中,根据所需的计算延时,可以为一个给定的语义块自动地导出流水线级。
在不同的流水线级中支持状态产生的第2项任务就是处理各种中断,各种除外情况和各种挂起。这通常涉及在流水线控制信号的控制下,增添适当的旁路和前向逻辑。在一个实施例中,可以产生一份通用图,用以指示该状态何时产生以及它何时被使用二者之间的关系。基于应用分析,可以实现适当的前向逻辑,以处理共同的情况,并且可以产生互锁逻辑,对于不由前向逻辑来处理的各种情况,将流水线挂起。
用于修改基本处理器的指令出口逻辑的方法依赖于该基本处理器所使用的算法。然而,一般来说,对大多数指令来说,不管是单出口还是超标量,也不管是用于单周期指令还是多周期指令,指令出口逻辑都仅依赖于被测试的指令,用于产生:
1.为每一种处理器状态元素指示该指令是否将各种状态用作一个源的各种信号;
2.为每一种处理器状态元素指示该指令是否将各种状态用作一个目标的各种信号;
3.为每一个功能单元指示该指令是否使用各功能单元的各种信号;
这些信号被用来执行发往流水线以及交叉出口检查,并且被用来在依赖于流水线的出口逻辑中更新流水线的状态。TIE含有所有必需的信息,以便为各项新指令增加各种信号以及它们的方程式。
首先,TIE状态说明导致为指令出口逻辑生成一组新的信号。在iclass说明的第3或第4自变量中所列出的in或inout操作数或状态为针对被指定的处理器状态元素的第1组方程式的第2自变量中所列出的各项指令增添指令解码信号。
其次,在iclass说明的第3或第4自变量中所列出的in或inout操作数或状态为针对被指定的处理器状态元素的第1组方程式的第2自变量所列出的各项指令增添指令解码信号。
第三,从每一个TIE语义块生成的逻辑都代表一个新的功能单元,这样就生成一组新的单元信号,并且,用于为该语义块指定的各项TIE指令的各解码信号通过逻辑“或”运算被组合在一起,以形成第3组方程式。
当一条指令被发出时,应当为未来的发出决定而更新流水线的状态。再有,用于修改基本处理器的指令发出逻辑的方法依赖于该基本处理器所使用的算法。然而,某些一般的观察是可能的。流水线状态应当向发出逻辑反向提供下列状态:
4.当该项结果可用于旁路时,为每一条已发出的指令指示目标的各种信号;
5.为每一个功能单元指示该功能单元已经为另一条指令作好准备的各种信号。
这里描述的实施例是一个单出口处理器,其中,设计者定义的各项指令被限制在逻辑计算的一个单周期以内。在这种情况下,上述问题得以可观地简化。不需要功能单元进行检查或者交叉出口检查,并且也没有一条单周期指令能使一个处理器状态元素不为下一条指令作好管道就绪的准备。因此,出口方程式恰好变为
issue=(~srcluse|srclpipeready)&(~src2use|src2pipeready)
&(~srcNuse|srcNpipeready);
并且其中src[i]管道就绪信号不受各附加指令的影响,并且src[i]use是按照以上所述进行说明和修改的第1方程组。在这个实施例中,不需要第4和第5组信号。对一个多出口和多周期的变通的实施例来说,将用一种潜在因素说明为每一条指令扩充其TIE描述,给出建立计算流水线所需的周期的数目。
通过对每一条指令的指令解码信号进行逻辑“或”运算,把它们集中在一起,从而在每一个语义块流水线级中产生第4组信号,根据说明,指令的执行在该级中完成。
通过默认已产生的逻辑都将被完全地送进流水线,以及因此由TIE产生的各功能单元在接受一条指令之后,通常都是单周期的。在这种情况下,针对TIE各语义块的第5组信号通常得以建立。当需要在多个周期上再次使用在各语义块中的逻辑时,一个进一步的说明将指定在多少个周期内,这些指令将使用该功能单元。在这种情况下,通过对每一条指令的指令解码信号进行逻辑“或”运算,把它们集中在一起,从而在每一个语义块流水线级中产生第5组信号,每一条指令的执行在该级所指定的周期计数中完成。
可供选择地,在一个不同的实施例中,它可以作为对TIE的扩展,让设计者指定结果就绪信号和功能单元就绪信号。
根据本实施例进行处理的代码的实例见各附录。为了简洁起见,对此将不作详细说明;然而,在参阅上述参考手册之后,专业人士对此都将有所理解。附录G是实现一条使用TIE语言的指令的例子;附录H表示TIE编译程序将为使用这样的代码的编译程序产生什么。类似地,附录I表示TIE编译程序将为仿真程序产生什么;附录J表示TIE编译程序将为在一段用户程序中扩展TIE指令的宏产生什么;附录K表示TIE编译程序将产生什么,用以仿真在本地方式中的各项TIE指令;附录L表示TIE编译程序将产生什么,作为对附加硬件的Verilog HDL描述;以及附录M表示TIE编译程序将产生什么,作为优化上述的Verilog HDL描述的Design Compiler稿本,用以评估TIE指令在面积和速度方面对CPU尺寸和性能的影响。
如上面所指出的那样,为了开始处理器配置过程,用户经由上述的GUI,通过选择一个基本处理器来开始。作为过程的一部分,如图1所示,软件开发工具30被建立并且被提供给用户。软件开发工具30含有涉及本发明的另一个方面的4个重要部件,详见图6:编译程序108,汇编程序110,指令集仿真程序112,以及调试程序130。
如同专业人士所熟知的那样,编译程序把用诸如C或C++那样的高级编程语言编写的用户应用程序转换为处理器专用的汇编语言。诸如C或C++那样的高级编程语言被设计为允许应用程序的作者以便于他们精细地描述的形式来描述他们的应用程序。这些都不是各种处理器所能理解的语言。应用程序的作者用不着为即将被使用的处理器的所有的专门的特性而操心。典型地,相同的C或C++程序可以不加修改或稍加修改就可以在许多不同类型的处理器中使用。
汇编程序将C或C++程序转换为汇编语言。汇编语言更接近于机器语言,处理器直接地支持机器语言。不同类型的处理器都有它们自身的汇编语言。每一条汇编指令通常直接地代表一条机器指令,但是二者不一定相同。汇编指令被设计为人可读的字符串。每一条指令或操作数都被给出一个有意义的名字或助记符,让人们能够读出汇编指令,同时易于理解机器将进行何种操作。汇编程序将汇编语言转换为机器语言。由汇编程序有效地将每一条汇编指令串编码为一条或多条机器指令,后者可以直接地和有效地被处理器执行。
机器码可以直接地在处理器上运行,但是各种物理的处理器并不是经常都是立即可用的。建立各种物理的处理器是费时费钱的过程。当选择可能的处理器配置时,用户不能为每一种选择都建立一个物理的处理器。取而代之的是,向用户提供一种称为仿真程序的软件程序。运行于普通的计算机之上的仿真程序能够仿真在用户配置的处理器之上的用户应用程序的效果。仿真程序能够模仿被仿真的处理器的语义,并且能够告诉用户实际的处理器在运行用户的应用程序时将有多快。
调试程序是一种工具,让用户用他们的软件交互式地查找各种问题。调试程序允许用户交互式地运行他们的程序。用户可以在任何时间停止程序的执行,同时注视其C语言源代码,所得到的汇编代码或机器代码。用户还可以在一个断点上察看或修改她的(任何或全部)各变量或硬件寄存器数值。然后用户可以继续执行—或许每次执行一个语句,或许每次执行一条机器指令,或许转到用户选择的一个新的断点。
所有4部分108,110,112和130都需要知道用户定义的指令750(见图3),并且仿真程序112和调试程序130还必须附带地知道用户定义的状态752。系统允许用户经由被添加到用户的C和C++应用程序的内部调用来访问用户定义的指令750。编译程序108应当针对用户定义的指令750,将内部调用转换为汇编语言指令738。汇编程序110应当取出新的汇编语言指令738,不管是由用户直接编写还是由编译程序108转换,并将它们编码为对应于用户定义的各指令750的各机器指令740。仿真程序112应当对用户定义的各机器指令740进行解码。它应当模拟各项指令的语义,并且它应当模拟在已配置的处理器上的各项指令的性能。仿真程序112还应当模拟用户定义状态所蕴涵的数值和性能。调试程序130应当允许用户去显示汇编语言指令738,其中包括用户定义指令750。它应当允许用户察看和修改用户定义状态的数值。
在本发明的这个方面,用户启用一种工具,即TIE编译程序702,来处理当前可能的用户定义的各项改进736。TIE编译程序702不同于编译程序708,后者将用户应用程序转换为汇编语言738。TIE编译程序702建立一些部件,它使得已经建立的基本软件系统30(编译程序708,汇编程序710,仿真程序712以及调试程序730)去使用新的、用户定义的各项改进736。软件系统30的每一个元素都使用各部件的稍为不同的集合。
图24是一份图,说明这些软件工具的TIE指定部分是如何产生的。TIE编译程序702从用户定义扩展文件736为若干程序生成C语言代码,其中的每一段都产生一个文件,一种或多种软件开发工具都可以访问这个文件,以便取得关于用户定义指令和状态的信息。例如,程序tie2gcc 800产生一个被称为xtensa-tie.h的C语言头文件842(下面将作详细说明),它含有针对新指令的内部函数定义。程序tie2isa 810产生一个动态连接库(DLL)844/848,它含有关于用户定义指令格式的信息(下面将详细说明编码DLL 844和解码DLL 848的组合)。程序tie2iss 840产生用于性能模拟和指令语义的C语言代码870,如下面将要讨论的那样,被一个主机编译程序846用来产生被仿真程序所使用的仿真程序DLL849,下面将对此作详细叙述。程序tie2ver 850以适当的硬件描述语言为用户定义指令产生必要的描述850。最后,程序tie2xtos 860保存和恢复代码810,为场景切换??保存和恢复用户定义状态。在上述Wang等人的应用程序中,可以找到关于用户定义状态的实现的附加信息。
编译程序708
在本实施例中,编译程序708将用户应用程序中的内部调用转换为汇编语言指令738,用于用户定义的改进736。编译程序708在宏的顶部实现这种机制以及在线汇编机制,这样的机制在诸如GNU编译程序那样的编译程序中可以看到。关于这些机制的更多的信息,可参见例如,《GNU和C++编译程序用户指导》,EGCS版本1.0.3。
考虑一个用户希望生成一条新指令foo,它运行于两个寄存器,并将一个结果返回第3寄存器。用户将指令描述放进用户定义指令文件750的一个特定的目录之中,并启用TIE编译程序702。TIE编译程序702生成具有诸如xtensa-tie.h那样的标准名字的文件742。该文件含有foo的下列定义。
#define foo(ars,art)\
     ({int arr;asm volatile(″foo %0,%1,%2″:″=a″(arr):\
″a″(ars),″a″(art));}}
当用户在她的应用程序中启用编译程序708时,她通过命令行选项或者环境变量,告诉编译程序708具有用户定义改进736的目录名。该目录也包含xtensa-tie.h文件742。编译程序708自动地将文件xtensa-tie.h纳入用户正在编译的C语言或C++语言应用程序,就像用户自己已经编写了foo的定义一样。用户在自己的应用程序中将内部调用纳入指令foo。由于已纳入的定义,所以编译程序708将那些内部调用看成是对已纳入的定义的调用。根据编译程序708提供的标准宏机制,编译程序708处理宏foo的调用时,就好像用户直接编写了汇编语言指令738,而不是宏调用。也就是说,根据标准的在线汇编机制,编译程序708将调用转换为单独的汇编指令foo。例如,用户也许有一个包含对内部的foo进行调用的函数。
int fred(int a,int b)
{
return foo(a,b);
}编译程序利用用户定义的指令foo,将函数转换为下列的汇编语言子程序。
  fred:

  .frame sp,32

  entry sp,32

  #APP

  foo a2,a2,a3

  #NO_APP

  retw.n
当用户创建一组新的用户定义的改进736时,并不需要编写新的编译程序。TIE编译程序702只是创建文件xtensa_tie.h 742,该文件由预先建立的编译程序自动地纳入用户的应用程序。
汇编程序710
在这个实施例中,汇编程序710使用编码库744对汇编指令750进行编码。  进入该库744的包括如下函数:
—将操作码助记符字符串转换为内部的操作码表示;
—针对在一条机器指令740中的操作码字段,为每组操作码提供待生成的位图;以及
—为每一条指令的操作数的操作数数值进行编码,并且将已编码的操作数的位图插入到机器指令740的操作数字段中去。
举例来说,设想我们上述的例子中调用内部foo的用户函数。汇编程序可能接受指令“foo a2,a2 a3”,然后将它转换成由十六进制数0x62230表示的机器指令,其中,高位6和低位0一起表示foo的操作码,2,2和3分别表示3个寄存器a2,a2和a3。
这些函数的内部实现是基于表格和内部函数的组合。表格可以由TIE编译程序702容易地生成,但是它们的表达能力却很有限。当需要更大的灵活性时,例如当表达操作数编码函数时,TIE编译程序702就可以生成随机的C语言代码,并被纳入库744之中。
再次设想“foo a2,a2,a3”的例子。每个寄存器字段都只是用寄存器的号码进行编码。TIE编译程序702创建下列函数,该函数检查合法的寄存器数值,如果数值是合法的,就返回寄存器的号码。
      xtensa_encode_result encode_r(valp)

      u_int32_t *valp;

      {

          u_int32_t val=*valp;

          if((val>>4)!=0)

          return xtensa_encode_result_too_high;

          *valp=val;

          return xtensa_encode_result_ok;

      }
如果全部的编码都这么简单,就不需要任何加密函数,只要一份表格就足够了。然而,用户可以选择更加复杂的编码。下列的编码用TIE语言编写,用操作数的值除以1024的商对每个操作数进行编码。这样的编码对于那些要求是1024的倍数的经常被编码的数值是非常有用的。
Operand tx10t{t<<10}{tx10>>10}
TIE编译程序将操作数编码描述转换为下列的C语言函数。
  xtensa_encode_result encode_tx10(valp)

  u_int32_*valp;

  {

      u_int32_t t,tx10;

      tx10=*valp;

      t=(tx10>>10) &amp; 0xf;

      tx10=decode_tx10(t);

      if(tx10!=*valp)(

      return xtensa_encode_result_not_ok;

  }else{

      *valp=t;

  }

  return xtensa_encode_result_ok;

  }
因为对操作数来说,可能的取值范围非常大,所以不能用一份表格来进行这样的编码。表格将不得不非常大。
在编码库744的一个实施例中,一份表格将操作码的助记符字符串映射为内部的操作码表示。为了提高效率,该表格可能被排序,或者它可能是一份散列表,或者允许进行有效检索的其他数据结构。另一份表格将每组操作码跟一条机器指令的样板建立映射关系,将操作码字段初始化为该操作码的适当的位图。具有相同的操作数字段和操作数编码的操作码被组合在一起。对于这些组中的每个操作数,库中包含一个函数将操作数值编码成位图,另一个函数将这些位图插入到机器指令的适当字段之中。一份独立的内部表将每个指令操作数映射为这些函数。设想一个例子,结果寄存器的号码被编码为指令的比特12…15。TIE编译程序702将生成下列函数,将指令的比特12…15设置为结果寄存器的值(号码):
  void set_r_field(insn,val)

  xtensa_insnbuf insn;

  u_int32_t val; 

  {

      insn[0]=(insn[0] &amp; 0xffff0fff)|((val<<12) &amp; 0xf000);

  }
为了在不用重新编写汇编程序710的情况下就能更改用户定义的指令,编码库744被实施为一个动态连接库(DLL)。DLLs是让程序动态地扩展其功能的标准方式。处理DLLs的细节在不同的主机操作系统中是不同的,但是基本概念是一样的。DLL作为程序代码的扩充,被动态地载入运行中的程序之中。运行时间连接程序解决了DLL和主程序之间以及DLL和其它已经加载的DLLs之间的符号引用。就编码库或DLL 744来说,代码的一小部分被静态地连接到汇编程序710。该代码负责加载DLL,将DLL中的信息和预先建立的指令系统746的现有编码信息(可能已经从一个独立的DLL进行加载)加以组合,使该信息可以通过如上所述的各接口函数进行访问。
当用户创建新的改进736时,她在改进736描述的描述的基础上启用TIE编译程序702。TIE编译程序702生成的C语言代码定义了实现编码DLL的内部表和函数。TIE编译程序702然后启用主机系统的本机编译程序746(它编译的代码在主机上运行,而不是在被配置的处理器上运行),以便为用户定义的指令750创建编码DLL 144。用户在其应用程序中,使用标志或环境变量来启用预先编写的汇编程序710,这些标志或环境变量指向含有用户定义的的各项改进736的目录。预先编写的汇编程序710在目录中动态地打开DLL 744。对于每一条汇编指令来说,预先编写的汇编程序710使用编码DLL 744来查找操作码助记符字符串,寻找操作码字段在机器指令中的位图,并对每一个指令操作数进行编码。
例如,当汇编程序710发现TIE指令“foo a2,a2,a3”时,汇编程序710通过一份表格发现,“foo”操作码转换为处于比特位置16到23的数字6。从表中,它为每一个寄存器找到编码函数。函数将a2编码为数字2,将另一个a2编码为数字2,将a3编码为数字3。从表中,它找到适当的设置函数。Set_r_field将结果数值2放入该指令的位单元12…15。类似的设置函数也将另外的2和3放入适当的地方。
仿真程序712
仿真程序712以几种方式与用户定义的各项改进736进行交互。对于机器指令740来说,仿真程序712必须对指令进行解码,也就是说,将指令分解为操作码和操作数单元。用户定义的各项改进736通过解码DLL 748的一个函数进行解码(编码DLL 744和解码DLL 748实际上可能是同一个DLL)。例如,假定用户定义了三个操作码:foo1,foo2和foo3,在指令的比特16到23的编码分别为0x6,0x16和0x26,以及在比特0到3为0,。TIE编译程序702生成下列的解码函数,它将操作码与所有用户定义的指令750进行比较:
      int decode_insn(const xtensa_insnbuf insn)

      {

          if((insn[0] &amp; 0xff000f)==0x60000)return xtensa_fool_op;

          if((insn[0] &amp; 0xff000f)==0x160000)return
xtensa_foo2_op;

          if((insn[0] &amp; 0xff000f)==0x260000)return
xtensa_foo3_op;

          return XTENSA_UNDEFINED;

      }
当用户定义的指令数量很多时,将操作码与所有可能的用户定义的指令750进行比较可能是费时的,所以TIE编译程序可以使用分开层次的开关语句组来代替。
  switch(get_op0_field(insn)){

    case 0x0:

      switch(get_op1_field(insn)){

        case 0x6:

          switch(get_op2_field(insn)){  

            case 0x0:return xtensa_fool_op;

            case 0x1:return xtensa_foo2_op;

            case 0x2:return xtensa_foo3_op;

            default:return XTENSA_UNDEFINED;

          }

        default:return XTENSA_UNDEFINED;

      }

    default:return XTENSA_UNDEFINED;

  }
除了对指令操作码进行解码之外,解码DLL 748还包括用于对指令操作数进行解码的函数。完成的方式同编码DLL 744中对操作数进行编码完全相同。首先,解码DLL 748的函数从机器指令中选取操作数字段。继续上述的例子,TIE编译程序702生成下列的函数,从一个指令的12到15比特选取一个数值:
  u_int32_t get_r_field(insn)

       xtensa_insnbuf insn;

  {

      return((insn[0] &amp; 0xf000)>>12);

  }
TIE对一个操作数的描述包括编码和解码的描述,所以鉴于编码DLL 744使用操作数编码描述,解码DLL 748使用操作数解码描述。例如,TIE操作数的描述是:
Operand tx10 t{t<<10}{tx10>>10}生成下列的操作数解码函数:
  u_int32_t decode_tx10(val)

      u_int32_t val;

  {

      u_int32_t t,tx10;

      t=val;

      tx10=t<<10;

      return tx10;

  }
当用户启用仿真程序712时,她告诉仿真程序712含有用户定义的各项改进736的解码DLL 748的目录。仿真程序712打开适当的DLL。每当仿真程序712对一条指令进行解码时,如果该指令没有通过预先编写的指令系统的解码函数成功地进行解码,那么仿真程序712就启用DLL 748中的解码函数。
给出一个已解码的指令750之后,仿真程序712必须对指令750的语义进行解释和模拟。这用函数方式完成。每条指令750都有对应的函数,让仿真程序712对该指令750的语义进行模拟。仿真程序712在内部对被模拟的处理器的全部状态保持跟踪。仿真程序712有固定的接口用于更新或查询处理器的状态。如上所述,用户定义的各项改进736是由TIE硬件描述语言写成的,该语言是Verilog的一个子集。TIE编译程序702将硬件描述语言转换为C语言函数,仿真程序712利用上述的C语言函数来模拟新的改进736。硬件描述语言运算符直接地转换为对应的C语言运算符。读状态或写状态的操作被转换为仿真程序的界面,用于对处理器状态进行更新或查询。
作为本实施例中的一个例子,假定有一个用户创建一条指令,用以增加两个寄存器。选择这个例子只是为了简便。用户可以用硬件描述语言对增加的语义做如下的描述:
Semantic add{add}{assign arr=ars+art;}
输出寄存器由内部的名字arr来表示,它被赋予了两个输入寄存器的和,这两个输入寄存器的内部名字分别是ars和art。TIE编译程序702采取这种描述,并生成仿真程序712使用的语义函数:
  void add_func(u32_OPND0_,u32_OPND1_,u32OPND2_,u32
_OPND3_)

  {
  set_ar(_OPND0_,ar(_OPND1_)+ar(_OPND2_));

  pc_incr(3);

  }
硬件运算符“+”直接地转换为对应的C语言运算符“+”。硬件寄存器ars和art的读取被转换为对仿真程序712的函数“ar”的调用。硬件寄存器arr的写入被转换为对仿真程序712的函数“set_ar”的调用。因为每条指令都隐含地将程序计数器pc的内容增加了该指令的大小,所以TIE编译程序702也生成对仿真程序712函数的调用,使被仿真的pc增加3,即加法指令大小。
当TIE编译程序702被启用时,为每个用户定义的指令都创建一个如上所述的语义函数,同时也创建一份表格,它将全部的操作码名字映射到相关的语义函数之中。使用标准的编译程序746将表格与函数编译到仿真程序DLL 749中去。当用户启用仿真程序712时,她告诉仿真程序712含有用户定义的各项改进736的目录。仿真程序712打开适当的DLL。每当启用仿真程序712时,它对程序中所有的指令进行解码,并创建一份表格,其中含有各项指令与相关的各语义函数的映射关系。建立映射关系时,仿真程序712打开DLL,检索适当的语义函数。当对用户定义的指令736的语义进行仿真时,仿真程序712直接地启用DLL中的函数。
为了告诉用户在被仿真的硬件上运行应用程序所需的时间有多长,仿真程序712需要仿真指令750的执行效果。仿真程序712为此使用了流水线模型。每条指令在几个周期上执行。在每一个周期,指令使用机器的不同资源。仿真程序712开始尝试并行地执行所有的指令。若多条指令在同一个周期中使用相同的资源,则后面的指令被挂起,以等待资源腾出来。若后面的指令读取前面的指令在后面的周期中所写入的状态,则后面的指令就被挂起,以等待该数值被写入。仿真程序712使用函数接口来模拟每一条指令的效果。为每一种类型的指令都创建一个函数。这些函数包括对仿真程序接口的调用,该接口模拟处理器的性能。
例如,假定有一个简单的3寄存器指令foo。TIE编译程序可能会创建下列的仿真程序函数:
  void foo_sched(u32 op0,u32 op1,u32 op2,u32 op3)

  {

           pipe_use_ifetch(3);

           pipe_use(REGF32_AR,op1,1);

           pipe_use(REGF32_AR,op2,1);

           pipe_def(REGF32_AR,op0,2);

           pipe_def_ifetch(-1);

       }
对pipe_use_ifetch的调用告诉仿真程序712称,该指令将需要取3个字节。对pipe_use的两次调用告诉仿真程序712称,两个输入寄存器将在周期1读入。对pipe_def的调用告诉仿真程序712称,输出寄存器将要在周期2被写入。对pipe_def_ifetch的调用告诉仿真程序712称,该指令不是一个分支,因此下一条指令可以在下一个周期被取出。
这些函数的指针跟各语义函数一起放在同一份表格中。函数本身就像语义函数一样被编译到DLL 749之中。当启用仿真程序712时,它创建了指令和运行函数的映射关系。当建立映射关系时,仿真程序712打开DLL 749,检索适当的性能函数。当对用户定义的指令736的执行情况进行仿真时,仿真程序712直接启用DLL 749中的函数。
调试程序730
调试程序以两种方式与用户定义的各项改进750进行交互。首先,用户能够显示针对用户定义的各项指令736的汇编语言指令738。为了做到这一点,调试程序730必须将机器语言指令740解码为汇编语言指令738。这与仿真程序712对指令进行解码时使用的原理是相同的,并且调试程序730使用的DLL最好跟仿真程序712解码时使用的DLL完全相同。除了对各项指令进行解码外,调试程序还必须将已解码的指令转换为字符串。为此,解码DLL 748包括一个函数,它将每个内部的操作码表示映射为相应的助记符字符串。这可以通过一份简单的表个来实现。
用户可以使用标志或环境变量来启用预先编写的调试程序,这些标志或环境变量指向含有用户定义的各项改进750的目录。预先建立的调试程序动态地打开适当的DLL 748。
调试程序730也跟用户定义的状态752进行交互。调试程序730必须能够读取和修改状态752。为此,调试程序730与仿真程序712进行通信。它向仿真程序712询问状态有多大,以及状态变量的名字是什么。每当调试程序730被要求显示用户状态的数值时,它就像询问预先定义的状态一样向仿真程序712询问该数值。类似地,为了修改用户的状态,调试程序730告诉仿真程序712将状态设置成一个给定值。
因此,可以看出,根据本发明对用户定义的指令集和状态加以支持的实施方案,可以使用定义用户函数的模块来完成,这些模块被嵌入到核心软件开发工具之中。因此,开发一个系统时,特定的用户定义的各项改进嵌入模块可以作为系统内部的一组来使用,以便于组织和操作。
此外,核心软件开发工具可能专用于特定的核心指令集以及处理器状态,并且用户定义的各项改进单一的嵌入模块的集合,可能跟驻留在系统中的许多核心软件开发工具结合在一起进行评价。
               附件A# Xtensa配置数据库说明# $ Id:Definition,v 1.65 1999/02/04 15:30:45 adixit Exp $.# 版权所有1998年Tensilica公司# 这些已编码的指令,语句,以及计算机程序均为Tensilica公司# 的保密的专有信息,在没有得到Tensilica公司事先的书面同意的情况下,不得向第三方公开,或者以任何形式进行全部的或部分的拷贝##这是配置参数定义文件。# —所有被支持的配置都必须在这个文件中加以说明# —所有分析配置的工具都应当检查这个文件的正确性# —对这个文件的更改应当保持最小,并且小心地进行处理## 命名惯例# 大多数参数的名字都以列表中的一个类名开头:# Addr      地址和转换参数# Build          ?# Cad       目标CAD环境# DV        各项设计验证参数# Data      下列各项中的一项:# DataCache     数据高速缓冲存储器参数# DataRAM       数据RAM参数# DataROM       数据ROM参数# Debug         调试程序选项参数# Impl          实施方案各项目标# Inst          下列各项中的一项:# InstCache       指令高速缓冲存储器参数# InstRAM           指令RAM参数# InstRoM           指令ROM参数# Interrupt         中断参数# Isa               指令集体系结构参数# Iss               指令集仿真程序参数# PIF               处理器接口参数# Sys               系统参数(例如存储器映射)# TIE               专用指令参数# Test              生产测试参数# Timer             周期计数/比较选项# Vector            复位/除外情况/中断矢量地址# 许多参数以一个后缀结尾,给出它们被测量时所用的单位:# Bits# Bytes             (即8位)# Count             用作一般的“的数目”后缀# Entries           类似于Count# Filename          文件的绝对路径名# Interrupt         中断标识(0…31)# Level             中断等级(1…15)# Max               最大值# Paddr             物理地址# Type              可能数值的一个枚举# Vaddr             虚拟地址
本文档的格式:
列1:配置参数名
列2:参数的默认值
列3:核对值的有效性的perl表示
# Xtensa Configuration Database Specification
□
# $Id:Definition,v 1.65 1999/02/04 15:30:45 adixit Exp $
□
□
# Copyright 1998 Tensilica Inc.
# These coded instructions,statements,and computer programs are
# Confidential Proprietary Information of Tensilica Inc. and may not
be
# disclosed to third parties or copied in any form,in whole or in
part,
# without the prior written consent of Tensilica  Inc.
#
# This is the configuration parameter definition file.
#  -All supported configurations must be declared in this file
#  -All tools parsing configurations must check against this file for
validity
#  -Changes to this file must be kept minimum and dealt with care
#
# Naming Conventions
#   Most parameter names begin with a category name from the following
#   list:
#     Addr         Addressing and translation parameters
#     Build             ?
#     Cad          Target CAD environment
#     DV           Design Verification parameters
#     Data         One of the  following:
#     DataCache      Data Cache parameters
#     DataRAM          Data RAM parameters
#     DataROM          Data ROM parameters
#     Debug            Debug option parameters
#     Impl         Implementation goals
#     Inst         One of the following:
#     InstCache      Instruction Cache parameters
#     InstRAM          Instruction RAM parameters
#     InstROM          Instruction ROM parameters
#     Interrupt        Interrupt parameters
#     Isa          Instruction Set Architecture parameters
#     Iss          Instruction Set  Simulator parameters
#     PIF          Processor Interface parameters
#     Sys          System parameters(e.g.memory map)
#     TIE          Application-specific instruction parameters
#     Test         Manufacturing Test parameters
#     Timer             Cycle count/compare option parameters
#     Vector            Reset/Exception/Interrupt vector addresses
#   Many parameters end in a suffix giving the units in which they
#   are measured:
#     Bits
#     Bytes             (i.e.8bits)
#     Count             used as a generic″number of″suffix
#     Entries           similar to Count
#     Filename          absoluate pathname of file
#     Interrupt         interrupt id(0..31)
				
				<dp n="d103"/>
######################################################################
#

          ISA选项
#
######################################################################
######
IsaUseClamps                0          0|1
IsaUseMAC16                 0          0|1
IsaUseMul16                 0          0|1
IsaUseException             1          1
IsaUseInterrupt             0          0|1
IsaUseHighLevelInterrupt    0          0|1
IsaUseDebug                 0          0|1
IsaUseTimer                 0          0|1
IsaUseWindowedRegisters           1          1
IsaMemoryOrder              LittleEndian    LittleEndian|BigEndian
IsaARRegisterCount          32         32|64
######################################################################
######
#    地址和转换
######################################################################
######
AddrPhysicalAddressBits    32    1[6-9]|2[0-9]|3[0-2]
AddrVirtualAddressBits     32    1[6-9]|2[0-9]|3[0-2]
######################################################################
######
#  数据高速缓冲存储器/RAM/ROM
######################################################################
######
DataCacheBytes           1k         0k|1k|2k|4k|8k|16k
DataCacheLineBytes       16         16|32|64
DataRAMBytes             0k         0k|1k|2k|4k|8k|16k
DataROMBytes             0k         0k|1k|2k|4k|8k|16k
DataWriteBufferEntries         4             4|8|16|32
DataCacheAccessBits      32         32|64|128
######################################################################
######
#             指令高速缓冲存储器/RAM/ROM
######################################################################
######
InstCacheBytes           1k             0k|1k|2k|4k|8k|16k
				
				<dp n="d104"/>
InstCacheLineBytes     16       16|32|64
InstRAMBytes           0k       0k|1k|2k|4k|8k|16k
InstROMBytes           0k       0k|1k|2k|4k|8k|16k
InstCacheAccessBits    32       32|64|128
######################################################################
######
#    处理器接口
######################################################################
######
PIFReadDataBits            32         32|64|128
PIFWriteDataBits       32        32|64|128
pIFTracePort               0          0|1
######################################################################
##
#    系统
######################################################################
######
SysAppStartVAddr    0x40001000 0x[0-9a-fA-F]+
SysDefaultCacheAttr       0xfff21122 0x[0-9a-fA-F]+
SysROMBytes               128k       [0-9]+(k|m)
SysROMPAddr               0x20000000 0x[0-9a-fA-F]+
SysRAMBytes               1m         [0-9]+(k|m)
SvsRAMPAddr               0x40000000 0x[0-9a-fA-F]+
SysStackBytes             16k        [0-9]+(k|m)
SysXMONBytes              0x0000fd00 0x[0-9a-fA-F]+
SysXMONVAddr              0x20000300 0x[0-9a-fA-F]+
SysXTOSBytes              0x00000c00 0x[0-9a-fA-F]+
SysXTOSVAddr              0x40000400 0x[0-9a-fA-F]+
######################################################################
######
#           矢量地址
######################################################################
######
VectorResetVAddr    0x20000020 0x[0-9a-fA-F]+
VectorUserExceptionVAddr    0x40000214 0x[0-9a-fA-F]+
VectorKernelExceptionVAddr  0x40000204 0x[0-9a-fA-F]+
VectorWindowBaseVAddr       0x40000000 0x[0-9a-fA-F]+
VectorLevel2InterruptVAddr  0x40000224 0x[0-9a-fA-F]+
VectorLevel3InterruptVAddr  0x40000234 0x[0-9a-fA-F]+
######################################################################
######
#           中断选项
######################################################################
######
InterruptCount        1           [1-9]|1[0-9]|2[0-9]|3[0-2]
InterruptLevelMax     1           [1-3]
Interrupt0Type        External    External|Internal|Software
Interrupt1Type        External    External|Internal|Software
Interrupt2Type        External    External|Internal|Software
Interrupt3Type        External    External|Internal|Software
Interrupt4Type        External    External|Internal|Software
Interrupt5Type        External    External|Internal|Software
				
				<dp n="d105"/>
Interrupt6Type          External    External|Internal|Software
Interrupt7Type          External    External|Internal|Software
Interrupt8Type          External    External|Internal|Software
Interrupt9Type          External    External|Internal|Software
Interrupt10Type         External    External|Internal|Software
Interrupt11Type         External    External|Internal|Software
Interrupt12Type         External    External|Internal|Software
Interrupt13Type         External    External|Internal|Software
Interrupt14Type         External    External|Internal|Software
Interrupt15Type         External    External|Internal|Software
Interrupt16Type         External    External|Internal|Software
Interrupt17Type         External    External|Internal|Software
Interrupt18Type         External    External|Internal|Software
Interrupt19Type         External    External|Internal|Software
Interrupt20Type         External    External|Internal|Software
Interrupt21Type         External    External|Internal|Software
Interrupt22Type         External    External|Internal|Software
Interrupt23Type         External    External|Internal|Software
Interrupt24Type         External    External|Internal|Software
Interrupt25Type         External    External|Internal|Software
Interrupt26Type         External    External|Internal|Software
Interrupt27Type         External    External|Internal|Software
Interrupt28Type         External    External|Internal|Software
Interrupt29Type         External    External|Internal|Software
Interrupt30Type         External    External|Internal|Software
Interrupt31Type         External    External|Internal|Software
Interrupt0Level         1           [1-3]
Interrupt1Level         1           [1-3]
Interrupt2Level         1           [1-3]
Interrupt3Level         1           [1-3]
Interrupt4Level         1           [1-3]
Interrupt5Level         1           [1-3]
Interrupt6Level         1           [1-3]
Interrupt7Level         1           [1-3]
Interrupt8Level         1           [1-3]
Interrupt9Level         1           [1-3]
Interrupt10Level    1         [1-3]
Interrupt11Level    1         [1-3]
Interrupt12Level    1         [1-3]
Interrupt13Level    1         [1-3]
Interrupt14Level    1         [1-3]
Interrupt15Level    1         [1-3]
Interrupt16Level    1         [1-3]
Interrupt17Level    1         [1-3]
Interrupt18Level    1         [1-3]
Interrupt19Level    1         [1-3]
Interrupt20Level    1         [1-3]
Interrupt21Level    1         [1-3]
Interrupt22Level    1         [1-3]
Interrupt23Level    1         [1-3]
Interrupt24Level    1         [1-3]
Interrupt25Level    1         [1-3]
Interrupt26Level    1         [1-3]
Interrupt27Level    1         [1-3]
Interrupt28Level    1         [1-3]
Interrupt29Level    1         [1-3]
				
				<dp n="d106"/>
Interrupt30Level      1          [1-3]
Interrupt31Level      1          [1-3]
#######################################################################

   其他处理器部件选项    处理器定时器选项
#
#
########################################################################
######
TimerCount            0        [0-3]
Timer0Interrupt           0          [0-9]|1[0-9]|2[0-9]|3[0-1]
Timer1Interrupt           0          [0-9]|1[0-9]|2[0-9]|3[0-1]
Timer2Interrupt           0          [0-9]|1[0-9]|2[0-9]|3[0-1]
######################################################################
######               
#    调试程序选项
######################################################################
######
DebugDataVAddrTrapCount         0          [0-2]
DebugInstVAddrTrapCount         0          [0-2]
DebugInterruptLevel        2          [2-3]
DebugUseOnChipDebug        0          0|1
######################################################################
######
#        指令集仿真程序
######################################################################
######
ISSArgcPAddr                0x00012000 0x[0-9a-fA-F]+
ISSArgvPAddr                0x00012004 0x[0-9a-fA-F]+
######################################################################
######
#        设计验证
######################################################################
######
DVMagicLocPAddr            0x00010000 0x[0-9a-fA-F]+
DVSerialRXADataPAddr       0x00011000 0x[0-9a-fA-F]+
DVSerialRXBDataPAddr       0x00011010 0x[0-9a-fA-F]+
DVSerialRXStatusPAddr      0x00011020 0x[0-9a-fA-F]+
DVSerialRXRequestPAddr          0x00011030 0x[0-9a-fA-F]+
DVCachedVAddr              0x60000000 0x[0-9a-fA-F]+
DVNonCachedVAddr      0x80000000 0x[0-9a-fA-F]+
######################################################################
######
#        测试选项
######################################################################
######
TestFullScan                0        01
TestLatchesTransparent           0         0|1
######################################################################
##
#        处理器实施方案配置
				
				<dp n="d107"/>
######################################################################
######
ImplTargetSpeed            250           [1-9][0-9]*
ImplTargetSize             20000         [1-9][0-9]*
ImplTargetPower            75            [1-9][0-9]*
ImplSpeedPriority          High          High|Medium|Low
ImplPowerPriority          Medium             High|Medium|Low
ImplSizePriority     Low          High|Medium|Low
ImplTargetTechnology       25m

    18m|25m|35m|cx3551|cx3301|acb25typ|acb25wst|t25typical|t25worst|
t35std|lss3g|ibm25typ|ibm25wc|vst_tsmc25typ
ImplOperatingCondition           Typical        Worst|Typical
######################################################################
######
#       CAD选项
######################################################################
######
CadParUseApollo                  1        0|1
CadParUseSiliconEnsemble         0        0|1
CadSimUseVCS                     1        0|1
CadSimUseVerilogXL               1        0|1
CadSimUseVerilogNC               1        0|1
CadSimUseVantage             0         0|1
CadSimUseMTI                     0        0|1
CadStvUseMotive                  0        0|1
CadStvUsePrimeTime               1        0|1
CadSynUseBuildGates              0        0|1
CadSynUseDesignCompiler             1          0|1
######################################################################
#         TIE指令文件。它必须是绝对路径名
#
######################################################################
######

     TIE文件名               \/.*|-
######################################################################
######
######################################################################
######
#

    下面的程序段仅用于内部。若要将任何内部参数往上送,请确认
#

     所有产品部件都能支持它。
#
######################################################################
######
######################################################################
######
# Constants for Athens implementation
IsaUseAthensCacheTest       1         0|1
IsaUseSpeculation           0         0
IsaUseCoprocessor           0         0
IsaUseFloatingPoint         0         0
IsaUseDSP             0          0
IsaUseDensityInstruction    1         1
				
				<dp n="d108"/>
IsaUse32bitMulDiv          0           0
IsaUseAbsdif               0           0
IsaUseCRC             0           0
IsaUsePopCount             0           0
IsaUseLeadingZeros         0           0
IsaUseMinMax               0           0
IsaUseSignExtend      0           0
IsaUseSynchronization      0           0
DataCacheIndexLock         0           0
DataCacheIndexType         physical    physical
DataCacheMaxMissCount      1           1
DataCacheMissStart         32          32
DataCacheParityBits        0           0
DataCacheSectorSize        16          16
DataCacheTagParityBits           0            0
DataCacheTagType     physical    physical
DataCacheWayLock     0           0
InstCacheIndexLock        0            0
InstCacheIndexType        physical     physical
InstCacheMaxMissCount     1            1
InstCacheMissStart        32           32
InstCacheParityBits       0            0
InstCacheSectorSize       16           16
InstCacheTagParityBits           0           0
InstCacheTagType     physical    physical
InstCacheWayLock     0           0
######################################################################
######
#  Build mode...for Web customers.They can run a limited number of
#  production builds,but as many eval builds as they like.
#  UserCID is used for fingerprinting
######################################################################
######
BuildMode            Evaluation Evaluation|Production
BuildUserCID              999        [0-9]+
######################################################################
######
######################################################################
######
# Values used by the GUI-basically persistent  state
######################################################################
######
######################################################################
######
SysAddressLayout     Xtos     Xtos|Manual
附件B
#  !/usr/xtensa/tools/bin/perl
#  Tensilica PreProcessor
#  $Id:tpp,V1.15 1998/12/17 19:36:03 earl Exp $
#  Modified:Kaushik Sheth
#  Copyright(C)1998 Tensilica.All rights reserved.
#  The original code was taken from Iain McClatchie.
#  perl preprocessor
#  Copyright(C)1998 Iain McClatchie.All rights reserved. No
warrantee implied.
#  Author:Iain McClatchie
#  You can redistribute and/or modify this software under the terms of
the
#  GNU General Public License as published by the Free Software
Foundation;
#  either version 2,or(at your option)any later version.
use lib″@xtools@/lib″;
package tpp;
# Standard perl modules
use strict;
use Exporter();
use  Getopt∷Long;
# Module stuff
@tpp∷ISA=qw(Exporter);
@tpp∷EXPORT=qw(

    include

    error

    );
@tpp∷EXPORT_OK=qw(
    include

    gen

    error

    );
%tpp∷EXPORT_TAGS=();
use vars qw(

   $debug

   $lines

   @incdir

   $config

   $output

   @global_file_stack

   );
# Main program
{

  $∷myname=′tpp′;    # for error messages

  # parse command line

  $debug=0;       # -debug command line option
				
				<dp n="d111"/>
  $lines=0 ;        # -lines command line option

  @incdir=();       # -I command line options

  $config=″;       # -c command line option

  $output=undef;    # -o command line option

  my @eval=();

  if(!GetOptions(

       ″debug!″=>\$debug,

       ″lines!″=>\$lines,

       ″I=s@″=>\@incdir,

       ″c=s″=>\$config,

       ″o=s″=>\$output,

       ″eval=s@″=>\@eval)

    || @ARGV<=0){

    # command line error

    print STDERR<<″END″;
tpp[args]file

  Applies a perl preprocessor to the indicated file,and any files

  included therein;the output of the preprocessor is written to

  stdout.Perl is embedded in the source text by one of two means.

  Whole lines of perl can be embedded by preceding them with a

  semicolon(you would typically do this for looping statments or

  subroutine calls).Alternatively,perl expressions can be embedded

  into the middle of other text by escaping them with backticks.

  -debug    Print perl code to STDERR,so you can figure out why your
embedded

            perl statements are looping forever.

  -lines    Embed\′#line 43\″foo.w\″\′directives in output,for
more

            comprehensible error and warning messages from later
tools.

  -I dir    search for include files in directory dir

  -o output_file  Redirect the output to a file rather than a stdout.

  -c config_file  Read the specified config file.

  -e eval   Eval eval before running program
NOTE:

     the lines with only″;″and″;//″will go unaltered.
END

     exit(1);

  }

  #  Initialize

  push(@INC,@incdir);

  @global_file_stack=();

  # Read configuration file

  tppcode∷init($config);

  # Open the output file

  if($output){

   open(STDOUT,″>$output″)

         ||die(″$∷myname:$!,opening′$output′\n″);

  }
				
				<dp n="d112"/>
  # Process evals

  foreach(@eval){

   tppcode∷execute($_);

  }

  # Process the input files

  foreach(@ARGV)(

   include($_);

  }

  # Done

  exit(0);
}
sub include {

  my($file)=@_;

  my($buf,$tempname,@chunks,$chunk,$state,$lasttype);

  if($file=~m|^/|){

   if(!open(INP,″<$file″)){

      error($file,″$!,opening $ file″);

   }

  }else{

   my$path;

   foreach $path(″.″,@incdir){

       if(open(INP,″<$path/$file″)){

        $file=″$path/$file″;

        last;

      }

    }

    error($file,″Couldn′t find $file in @INC″)

        if tell(INP)==-1;

  }

  $lasttype=″″;

  while(<INP>) 

    if(/^\s*;(.*)$/){

       my $1=$1;

       if($lasttype ne″perl″){

        $lasttype=″perl″;

       }

       if((/^\s*;\s*\/\//)||(/^\s*;\s*$/)){

        $buf.=″print STDOUT\″$_\″;\n″;

         }else{

        $buf.=$1.″\n″;

       }

   }else{

      if($lines and $lasttype ne″text″){

       $buf.=″print STDOUT\″\#line$.\\\″$file\\\″\\n\″;\n″;

       $lasttype=″text″;

     }

     chomp;

     if(m/^$/){

      $buf.=″print STDOUT \″\\n\″;\n″;
				
				<dp n="d113"/>
              next;

             }

             @chunks=split(″\`″);

             $state=0;

             $tempname=″00″;

             foreach $chunk(@chunks){

              if($state==0){

                 $chunk=quotemeta($chunk);

                 $state=1;

             }else{

                if($chunk=~m/^\W/){#Perl expression

                 $buf.= ″\$temp$tempname=$chunk;\n″;

                 $chunk= ″\$\{temp$tempname\}″;

                 $tempname++;

                 $state=0;

                }else{                    # Backquoted something

                 $chunk=″\\\`″.quotemeta($chunk);

                 $state=1;

                }

            }

          }

          # check if the line ends with a backquote

          if(m/\`$/){

           $state=1-$state;

          }

          error($file,″Unterminated embedded perl expression,line
$.″)

            if($state==0);

          $buf.=″print STDOUT\″″.join(″″,@chunks)
″\\n\″;\n″;

     }

  }

  close(INP);

  print STDERR $buf if($debug);

  push(@global_file_stack,$file);

  tppcode∷execute($buf);

  pop(@global_file_stack);

  if($@){

   chomp($@);

   error($file,$@);

  }
}
sub gen{

  print STDOUT(@_);
}
sub error{

  my($file,$err)=@_;

  print STDERR″$∷myname:Error($err)while preprocessing file
\″$file\″\n″;

  my $fn;

  foreach $fn(@global_file_stack){

    print STDERR″               included from\″$fn\″\n″;
				
				<dp n="d114"/>
  }

  exit(1);
}
# This package is used to execute the tpp code
package tppcode;
no strict;
use Xtensa∷Config;
sub ppp_require{

  print STDERR (″tpp:Warning:ppp_require used instead of
tpp∷include\n″);

  tpp∷include(@_);
}
sub init{

  my($cfile)=@_;

  config_set($cfile);
}
sub execute{

  my($code)=@_;

  eval($code);
}
#
#Local Variables:
#mode:perl
#perl-indent-level:4
#cperl-indent-level:4

        # End:
附件C
# Change XTENSA to point to your local installation
XTENSA=/usr/xtensa/awang/s8
#
# No need to change the rest
#
GCC=/usr/xtensa/stools/bin/gcc
XTCC=$(XTENSA)/bin/xt-gcc
XTRUN=$(XTENSA)/bin/xt-run
XTGO=$(XTENSA)/Hardware/scripts/xtgo
MFILE=$(XTENSA)/Hardware/diag/Makefile.common
all:run-base run-tie-cstub run-iss run-iss-old run-iss-new run-ver
#
# Rules to build various versions of me
#
me-base:me.c me_base.c me_tie.c src.c sad.c

       $(GCC) -o me-base -g -O2 -DNX=64 -DNY=64 me.c
me-tie-cstub:me.c me_base.c me tie.c src.c sad.c
       $(GCC) -o me-tie-cstub -g -O2 -DTIE -DNX=64 -DNY=64 me.c
me-xt:me.c me_base.c me_tie.c src.c sad.c

       $(XTCC) -o me-xt -g -O2 -DXTENSA -DNX=32 -DNY=32 me.c
me-xt-old:me.c me_base.c me_tie.c src.c sad.c

       $(XTCC) -o me-xt-old -g -O3 -DOLD -DXTENSA -DNX=32 -DNY=32
me.c
me-xt-new:me.c me_base.c me_tie.c src.c sad.c

       $(XTCC) -o me-xt-new -g -O3 -DNEW -DXTENSA -DNX=32 -DNY=32
me.c
me-xt.s:me.c me_base.c me_tie.c src.c sad.c

       $(XTCC) -o me-xt.s -S -O3 -DNOPRINTF -DXTENSA -DNX=16 -DNY=16
me.c
#
# Rules for various runs of me
#
run-base:me-base

      me-base;exit 0
run-tie-cstub:me-tie-cstub

      me-tie-cstub;exit 0
run-iss:me-xt

      $(XTRUN)me-xt
run-iss-old:me-xt-old

      $(XTRUN)--verbose me-xt-old
run-iss-new:me-xt-new

      $(XTRUN)--verbose me-xt-new
run-ver:me-xt.s testdir

      cp me-xt.s testdir/me-xt

      $(XTGO) -vcs -testdir `pwd`/testdir -test me-xt>run-ver.out
2>&amp;1

      grep Status run-ver.out
				
				<dp n="d117"/>
testdir:

      mkdir -p testdir/me-xt

      @echo ′all:me-xt.dat me-xt.bfd′>testdir/me-xt/Makefile

      @echo ″include $(MFILE)″>>testdir/me-xt/Makefile
clean:

      rm-rf me-* *.out testdir results
APPENDIX I:TEST PROGRAM
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#ifndef NX
#define NX 32                                 /* image width */
#endif
#ifndef NY
#define NY 32                                 /* image height */
#endif
#define BLOCKX 16                             /* block width */
#define BLOCKY 16                             /* block height */
#define SEARCHX 4                             /* search region width */
#define SEARCHY 4                             /* search region height */
unsigned char OldB [NX][NY];                 /* old image */
unsigned char NewB [NX][NY];                 /* new image */
unsigned short VectX[Nx/BLOCKX][NY/BLOCKY];  /* X motion vector */
unsigned short VectY[NX/BLOCKX][NY/BLOCKY];  /* Y motion vector */
unsigned short VectB[NX/BLOCKX][NY/BLOCKY];  /* absolute difference */
unsigned short BaseX[NX/BLOCKX][NY/BLOCKY];  /* Base X motion vector */
unsigned short BaseY[NX/BLOCKX][NY/BLOCKY];  /* Base Y motion vector */
unsigned short BaseB[NX/BLOCKX][NY/BLOCKY];  /* Base absolute
difference */
#define ABS(x)      (((x)<0) ?(-(x)):(x))
#define MIN(x,y)   (((x)<(y)) ?(x):(y))
#define MAX(x,y)   (((x)>(y)) ?(x):(y))
#define ABSD(x,y)  (((x)>(y)) ?((x)-(y)):((y)-(x)))
^L
/*********************************************************************

      为了测试目的对0ldB和NewB数组进行初始化
*********************************************************************/
void init()
{

  intx,y,x1,y1;
				
				<dp n="d118"/>
  for(x=0;x<NX;x++){

      for(y=0;y<NY;y++){

          OldB[x][y]=x^y;

      }

  }

  for(x=0;x<NX;x++){

      for(y=0;y<NY;y++){

          x1=(x+3)%NX;

          y1=(y+4)%NY;

          NewB[x][y]=OldB[x1][y1];

      }

  }
}
/*********************************************************************

             将各项结果对照全色数据进行检查 
*********************************************************************/
unsigned check()
{

  int bx,by;

  for(by=0;by<NY/BLOCKY;by++){

      for(bx=0;bx<NX/BLOCKX;bx++){

          if(VectX[bx][by]!=BaseX[bx][by])return 0;

          if(VectY[bx][by]!=BaseY[bx][by])return 0;

          if(VectB[bx][by]!=BaseB[bx][by])return 0;

      }

  }

  return 1;
}
/*********************************************************************

                运动评估的各种实施方案
*********************************************************************/
#include ″me_base.c″
#include ″me_tie.c″
/*********************************************************************

                      主测试程序
*********************************************************************/
int
main(int argc,char **argv)
{

  int passed;
#ifndef NOPRINTF

  printf(″Block=(%d,%d),Search=(%d,%d),size=(%d,%d)\n″,

      BLOCKX,BLOCKY,SEARCHX,SEARCHY,NX,NY);
#endif

  init();
				
				<dp n="d119"/>
#ifdef OLD

  motion estimate_base();

  passed=1;
#elif NEW

  motion estimate_tie();

  passed=1;
#else

  motion_estimate_base();

  motion_estimate_tie();

  passed=check();
#endif
#ifndef NOPRINTF

  printf(passed?″TIE version passed\n″:″** TIE version
failed\n″);
#endif

  return passed;
}
APPENDIX II:ME_BASE.C
/***********************************************************

             参考软件的实施方案
***********************************************************/
void
motion_estimate_base()
{

  int bx,by,cx,cy,x,y;

  int startx,starty,endx,endy;

  unsigned diff,best,bestx,besty;

  for(bx=0;bx<NX/BLOCKX;bx++){

      for(by=0;by<NY/BLOCKY;by++){

          best=bestx=besty=UINT_MAX;

          startx=MAX(0,bx*BLOCKX-SEARCHX);

          starty=MAX(0,by*BLOCKY-SEARCHY);

          endx=MIN(NX-BLOCKX,bx*BLOCKX+SEARCHX);

          endy=MIN(NY-BLOCKY,by*BLOCKY+SEARCHY);

          for(cx=startx;cx<endx;cx++){

              for(cy=starty;cy<endy;cy++){

                  diff=0;

                  for(x=0;x<BLOCKX;x++)(

                      for(y=0;y<BLOCKY;y++){

                          diff+=ABSD(OldB[cx+x][cy+y],
				
				<dp n="d120"/>
NewB[bx*BLOCKX+x][by*BLOCKY+y]);

                      }

                  }

                  if(diff<best){

                     best=diff;

                     bestx=cx;

                     besty=cy;

                 }

             }

         }

         BaseX[bx][by]=bestx;

         BaseY[bx][by]=besty;

         BaseB[bx][by]=best;

     }
   }
}
APPENDIX III:ME TIE.C
#include ″src.c″
#include ″sad.c″
/*********************************************************************

               使用SAD指令的运动评估的快速样式
*********************************************************************/
void
motion estimate tie()
{

  int bx,by,cx,cy,x;

  int startx,starty,endx,endy;

  unsigned diff0,diff1,diff2,diff3,best,bestx,besty;

  unsigned *N,N1,N2,N3,N4,*O,A,B,C,D,E;

  for(bx=0;bx<NX/BLOCKX;bx++){

      for(by=0;by<NY/BLOCKY;by++){

          best=bestx=besty=UINT_MAX;

          startx=MAX(0,bx*BLOCKX-SEARCHX);

          starty=MAX(0,by*BLOCKY-SEARCHY);

          endx=MIN(NX-BLOCKX,bx*BLOCKX+SEARCHX);

          endy=MIN(NY-BLOCKY,by*BLOCKY+SEARCHY);

          for(cy=starty;cy<endy;cy +=sizeof(long)){

              for(cx=startx;cx<endx;cx++){

                  diff0=diff1=diff2=diff3=0;

                  for(x=0;x<BLOCKX;x++){
				
				<dp n="d121"/>
                      N=(unsigned*)
&amp;(NewB[bx*BLOCKX+x][by*BLOCKY]);

                      N1=N[0];

                      N2=N[1];

                      N3=N[2];

                      N4=N[3];

                      O=(unsigned*) &amp; (OldB[cx+x][cy]);

                      A=O[0];

                      B=O[1];

                      C=O[2];

                      D=O[3];

                      E=O[4];

                      diff0+=SAD(A,N1)+SAD(B,N2)+

                                 SAD(C,N3)+SAD(D,N4);
#ifdef BIG ENDIAN

                      SSAI(24);

                      diff1+=SAD(SRC(A,B),N1)+SAD(SRC(B,C),N2)
+

                                 SAD(SRC(C,D),N3)+SAD(SRC(D,E),
N4);

                      SSAI(16);

                      diff2+=SAD(SRC(A,B),N1)+SAD(SRC(B,C),N2)
+

                                 SAD(SRC(C,D),N3)+SAD(SRC(D,E),
N4);

                      SSAI(8);

                      diff3+=SAD(SRC(A,B),N1)+SAD(SRC(B,C),N2)
+

                                 SAD(SRC(C,D),N3)+SAD(SRC(D,E),
N4);
#else

                      SSAI(8);

                      diff1+=SAD(SRC(B,A),N1)+SAD(SRC(C,B),N2)
+

                                 SAD(SRC(D,C),N3)+SAD(SRC(E,D),
N4);

                      SSAI(16);

                      diff2+=SAD(SRC(B,A),N1)+SAD(SRC(C,B),N2)
+

                                 SAD(SRC(D,C),N3)+SAD(SRC(E,D),
N4);

                      SSAI(24);

                      diff3+=SAD(SRC(B,A),N1)+SAD(SRC(C,B),N2)
+

                                 SAD(SRC(D,C),N3)+SAD(SRC(E,D),
N4);
#endif
				
				<dp n="d122"/>
                        O+=NY/4 ;

                        N+=NY/4;

                    }

                    if(diff0<best){

                      best=diff0;

                      bestx=cx;

                      besty=cy;

                    }

                    if(diff1<best){

                      best=diff1;

                      bestx=cx;

                      besty=cy+1;

                    }

                    if(diff2<best){

                      best=diff2;

                      bestx=cx;

                      besty=cy+2;

                    }

                    if(diff3<best){

                      best=diff3;

                      bestx=cx;

                      besty=cy+3;

                  }

              }

          }

          VectX[bx][by]=bestx;

          VectY[bx][by]=besty;

          VectB[bx][by]=best;

      }

  }
}
APPENDIX IV:SAD.C
#if defined(XTENSA)
#include <machine/Customer.h>
#elif defined(TIE)
#include ″../dk/me_cstub.c″
#else
/*********************************************************************

                4个字节的绝对差值之和
*********************************************************************/
static inline unsigned
SAD(unsigned ars,unsigned art)
{

  return ABSD(ars>>24,art>>24)+

         ABSD((ars>>16) &amp; 255,(art>>16) &amp; 255)+

         ABSD((ars>>8) &amp; 255,(art>>8) &amp; 255)+
				
				<dp n="d123"/>
      ABSD(ars &amp; 255,art &amp; 255);
}
#endif
APPENDIX V:SRC.C
/*********************************************************************

  若目标代码是原始代码,则使用一个全局变量来存储SSAI的位

  移量。
*********************************************************************/

  直接访问右移连锁指令。应当单独地用SSAI()来装载位移量

  寄存器
/*********************************************************************

  Direct access to the Shift Right Concatenate Instruction.

  The shift amount register must be loaded separately with SSAI().
*********************************************************************/
static inline unsigned
SRC(unsigned ars,unsigned art)
{

  unsigned arr;
#ifndef XTENSA

  arr=(ars<<(32-sar))|(art>>ar);
#else

  asm volatile(″src\t%0,%1,%2″:″=a″(arr):″a″(ars),″a″
(art));
#endif

  return arr;
}
/*********************************************************************

            设置位移量寄存器
*********************************************************************/
static inline void
SSAI(int count)
{
#ifndef XTENSA

  sar=count;
#else

  switch(count){

  case 8:

      asm volatile(″ssai\t8″);

      break;

  case 16:

      asm volatile(″ssai\t16″);

      break;

  case 24:

      asm volatile(″ssai\t24″);

      break;
				
				<dp n="d124"/>
  detault:

      exit(-1);

  }
#endif
}
APPENDIX VI:SOURCE CODE
/*
Block Motion  Estimation:
The purpose of motion estimation is to find the unaligned 8x8 block of
an existing (old) image that most closely resembles an aligned 8x8
block.The search here is at any byte offset in +/- 16 bytes in x and
+/-16 bytes in y.The search is a set of six nested loops.
OldB is pointer to a byte array of old block
NewB is pointer to a byte array of base block
*/
#define NY 480
#define NX 640
#define BLOCKX 16
#define BLOCKY 16
#define SEARCHX 16
#define SEARCHY 16
unsigned char OldB[Nx][NY];
unsigned char NewB[Nx][NY];
unsigned short VectX[NX/BLOCKX][NY/BLOCKY];
unsigned short VectY[NX/BLOCKX][NY/BLOCKY];
#define MIN(x,y)((x<y)?x:y)
#define MAX(x,y)((x>y)?x:y)
#define ABS(x)((x<0)?(-x):(x))
/* initialization with reference image data for test purposes */
void init()
{
int x,y;
for (x=0;x<NX;x++) for (y=0;y<NY;y++) {

  OldB[x][y]=x^y;

  NewB[x][y]=x+2*y+2;

  }
}
main()
				
				<dp n="d125"/>
{
int by,bx,cy,cx,yo,xo;
unsigned short best,bestx,besty,sumabsdiff0;
init();
for (by=0;by<NY/BLOCKY;by++){

  for(bx=0;bx<NX/BLOCKX;bx++){/* for each 8x8 block in the
image */

  best=0xffff;/* look for the minimum difference */

     for (cy=MAX(0,(by*BLOCKY)-SEARCHY);

         cy<MIN(NY-BLOCKY,(by*BLOCKY)+SEARCHY);

         cy++){/* for the old block at each line*/

       for(cx=MAX(0,(bx*BLOCKX)-SEARCHX);

        cx<MIN(NX-BLOCKX,(bx*BLOCKX)+SEARCHX);

          cx++){

      /*  test the NxN block at (bx,by)against NxN blocks */

      /*  at (cx,cy) */

          sumabsdiff0=0;

          for(yo=0;yo<BLOCKY;yo++)[/*for each of N rows in block
*/

           for(xo=0;xo<BLOCKX;xo++){/* for each of N pixels in
row */

            sumabsdiff0+=

              ABS(OldB[cx+xo][cy+yo]-

                NewB[bx*BLOCKX+xo][by*BLOCKY+yo]);

          }

       }

      if(sumabsdiff0<best){

        best=sumabsdiff0;bestx=cx;besty=cy;}

      }

  }

  VectX[bx][by]=bestx;

  VectY[bx][by]=besty;

  }
}
         附录VII:用TIE来优化C代码
         像素数值被包装为4个/每字
       OldW是指向旧块的一个字阵列的指针
       NewW是指向基块的一个字阵列的指针
#define NY 480
#define NX 640
#define BLOCKX 16
#define BLOCKY 16
#define SEARCHX 16
#define SEARCHY 16
				
				<dp n="d126"/>
#define MIN(x,y)((x<y)?x:y)
#define MAX(x,y)((x>y)?x:y)
unsigned long OldW[NY][NX/sizeof(long)];
unsigned long NewW[NY][NX/sizeof(long)];
unsigned short VectX[NY/BLOCKY][NX/BLOCKX];
unsigned short VectY[NY/BLOCKY][NX/BLOCKX];
void init()
{
int x,y;
for(x=0;x<NX/sizeof(long);x++)for(y=0;y<NY;y++){
  OldW[y][x]=((x<<2)^y)<<24|(((x<<2)+1)^y)<<16|(((x<<2)+2)^y)<<8
|((x<<2)+3)^y;

  NewW[y][x]=((x<<2)+2*y+2)<<24|(((x<<2)+1)+2*y+2)<<16|
(((x<<2)+2)+2*y+2)<<8|((x<<2)+3)+2*y+2;
  }
}
main()
{
register int by,bx,cy,cx,yo,xo;
register unsigned short
best,bestx,besty,sumabsdiff0,sumabsdiff1,sumabsdiff2,sumabsdiff3;
init();
for(by=0;by<NY/BLOCKY;by++){
  for(bx=0;bx<NX/BLOCKX;bx++){/* for each NxN block in the
image */

   best=0xffff;/* look for the minimum difference */

     for(cy=MAX(0,(by*BLOCKY)-SEARCHY);

        cy<MIN(NY-BLOCKY,(by*BLOCKY)+SEARCHY);

        cy++){/* for the old block at each line*/

      for(cx=MAX(0,(bx*BLOCKX-SEARCHX)/sizeof(long));

         cx<MIN((NX-BLOCKX-2)/sizeof(long),(bx*BLOCKX+SEARCHX)/
sizeof(long));

         cx++){/*and each word(4byte)offset in line*/

      /* test the NxN block at(bx,by)against four NxN blocks */

      /* at (cx,cy),(cx+1B,cy),(cx+2B,cy)(cx+3B,cy)     */

         sumabsdiff0=sumabsdiff1=sumabsdiff2=sumabsdiff3=0;

         for(yo=0;yo<BLOCKY;yo++){/* for each of the N lines in
the block */

           for(xo=0;xo<BLOCKX/8;xo+=2){

           register unsigned long *N,N1,N2*O,A,B,C,W,X;

           N=&amp;NewW [by+yo][bx*BLOCKX/sizeof(long)+xo];

           N1=*N;N2=*(N+1);/* 2 words of subject image*/

           O=&amp;OldW[cy+yo][cx+xo];

           A=*O;B=*(O+1);C=*(O+2);/*3 words of
reference*/

           sumabsdiff0+=sad(A,N1)+sad(B,N2);

           SHIFT(24)/* shift A,B,C left by one byte into W,X */
				
				<dp n="d127"/>
               sumabsdiff1 +=sad(W,N1)+sad(X,N2);

               SHIFT(16)/* shift A,B,C left by two bytes into W,X */

               sumabsdiff2 +=sad(W,N1)+sad(X,N2);

               SHIFT(8)/*shift A,B,C left by three bytes into W,X

               sumabsdiff3 += sad(W,N1)+sad(X,N2);

             }

           }

           if(sumabsdiff0<best){

               best=sumabsdiff0;bestx=cx;besty=cy;}

           if(sumabsdiff1<best){

               best=sumabsdiff1;bestx=cx+1;besty=cy;}

           if(sumabsdiff2<best){

               best=sumabsdiff2;bestx=cx+2;besty=cy;}

           if(sumabsdiff3<best){

               best=sumabsdiff3;bestx=cx+3;besty=cy;}

           }

        }

      VectX[bx][by]=bestx;

      VectY[bx][by]=besty;

  }
}
}
附件D
/*
 * TIE to Verilog  translation routines
 */
/* $Id:tie2ver_write.c,v1.27 1999/05/11 00:10:18 awang Exp $ */
/*
 * Copyright 1998-1999 Tensilica Inc.
 * These coded instructions,statements,and computer programs are
 * Confidential Proprietary Information of Tensilica Inc. and mav not
be
 * disclosed to third parties or copied in any form,in whole or in
part,
 * without the prior written consent of Tensilica Inc.
 */
#include<math.h>
#include″tie.h″
#include″st.h″
#define COMMENTS″//Do not modify this automatically generated file.″
static void tie2ver write expression(

          FILE *fp,tie_t *exp,int lhs,st_table *is,st_table *os);
#define tie2ver_program_foreach_instruction(_prog,_inst){    \

  tie_t *_iclass;                                          \

  tie_program_foreach_iclass(_prog,_iclass){               \

   if(tie_get_predefined(_iclass))continue;       \

     tie_iclass_foreach_instruction(_iclass,_inst){
#define end_tie2ver_program_foreach_instruction               \

     }end_tie_iclass_foreach_instruction;                  \

  }end_tie_program_foreach_iclass;                         \
}
#define TIE ENFLOP″\n\ 
module tie_enflop(tie_out,tie_in,en,clk);\n\
parameter size=32;\n\
output[size-1:0]tie_out;\n\
input[size-1:0] tie_in;\n\
input            en;\n\
input            clk;\n\
reg[size-1:0]   tmp;\n\
assign tie_out=tmp;\n\
always @(posedge clk)begin\n\
  if(en)\n\

  tmp<=#1 tie_in;\n\
end\n\
endmodule\n″
#define TIE_FLOP″\n\
module tie_flop(tie_out,tie_in,clk);\n\
parameter size=32;\n\
output [size-1:0]tie_out;\n\
input  [size-1:0]tie_in;\n\
input             clk;\n\
				
				<dp n="d130"/>
reg[size-1:0]   tmp;\n\
assign tie_out=tmp;\n\
always @(posedge clk) begin\n\
  tmp<=#1 tie_in;\n\
end\n\
endmodule\n″
#define TIE_ATHENS_STATE″\n\
module tie_athens_state(ns,we,ke,kp,vw,clk,ps);\n\
parameter size=32;\n\
input[size-1:0]ns;//next state\n\
input we;      //write enable\n\
input ke;      //Kill E state\n\
input kp;      //Kill Pipeline\n\
input vw;      //Valid W state\n\
input clk;     //clock\n\
output[size-1:0]ps;//present state\n\
\n\
wire[size-1:0]  se;//state at E stage\n\
wire[size-1:0]  sm;//state at M stage\n\
wire[size-1:0]  sw;//state at W stage\n\
wire[size-1:0]  sx;//state at X stage\n\
wire ee;        //write enable for EM register\n\
wire ew;        //write enable for WX register\n\
\n\
assign se=kp ?sx :ns;\n\
assign ee=kp | we &amp; ~ke;\n\
assign ew=vw &amp; ~kp;\n\
assign ps=sm;\n\
\n\
tie_enflop #(size)state_EM(.tie_out(sm),.tie_in(se),.en(ee),
.clk(clk));\n\
tie_flop   #(size)state_MW(.tie_out(sw),.tie_in(sm),.clk(clk));\n\
tie_enflop #(size)state_WX(.tie_out(sx),.tie_in(sw),.en(ew),
.clk(clk));\n\
\n\
endmodule\n″
/*********************************************************************

  建立和返回全局程序→用于用户定义的各项指令的操作数的操

  作数表格。返回的表格不含在预先定义的各项指令所使用的各操

  作数。
**********************************************************************
******/
static st_table*
tie2ver_program_get_operand_table(tie_t *prog)
{

  static st_table *tie2ver_Program_args=0;

  tie_t *inst;

  char *key,*value;

  st_table *operand_table;

  st_generator *gen;
				
				<dp n="d131"/>
  if(tie2ver_program_args==0){

    tie2ver_program_args=st_init_table(strcmp,st_strhash);

    tie2ver_program_foreach_instruction(prog,inst){

        operand_table=tie_instruction_get_operand_table(inst);

        st_foreach_item(operand_table,gen,&amp;key,&amp;value){

          st_insert(tie2ver_program_args,key,value);

        }

    }end_tie2ver_program_foreach_instruction;

  }

  return tie2ver_program_args;
}
/*********************************************************************
*******

               打印一个接线语句
**********************************************************************
******/
static void
tie2ver_write_wire(FILE *fp,tie_t *wire)
{

  int from,to,write_comma;

  tie_t *first,*second,*var;

  first=tie_get_first_child(wire);

  ASSERT(tie_get_type(first)==TIE_INT);

  from=tie_get_integer(first);

  second=tie_get_next_sibling(first);

  ASSERT(tie_get_type(second)==TIE_INT);

  to=tie_get_integer(second);

  fprintf(fp,″wire″);

  if(!(from==0 &amp;&amp; to==0)){

    fprintf(fp,″[%d:%d]″,from,to);

  }

  write_comma=0;

  var=tie_get_next_sibling(second);

  while(var!=0){

    if(write_comma){

       fprintf(fp,″,″);

    }else{

       write_comma=1;

    }

    fprintf(fp,″%s″,tie_get_identifier(var));

    var=tree_get_next_sibling(var);

  }

  fprintf(fp,″;\n″);
}
/*********************************************************************
*******

               打印一个unary表达式
				
				<dp n="d132"/>
**********************************************************************
******/
static void
tie2ver_write_unary(
FILE *fp,const char *op,tie_t *exp,int lhs,st_table *is,st_table
*os)
{

  fprintf(fp,″%s(″,op);

                     ession(fp,exp,lhs,is,os);
/*********************************************************************
*******

              打印一个二进制表达式
**********************************************************************
******/
static void
tie2ver_write_binary(
FILE *fp,const char *op,tie_t *exp1,tree_t *exp2,
int lhs,st_table *is,st_table *os)
{

  fprintf(fp,″(″);

  tie2ver_write_expression(fp,exp1,lhs,is,os);

  fprintf(fp,″)%s(″,op);

  tie2ver_write_expression(fp,exp2,lhs,is,os);

  fprintf(fp,″)″);
}
/*********************************************************************
*******

             打印一个标识符
**********************************************************************
******/
static void
tie2ver_write_identifier(
FILE *fp,tie_t *id,int lhs,st_table *is,st_table *os)
{

  tie_t *prog,*first,*second;

  char  *name,*dummy;

  name=tie_get_identifier(id);

  if((is!=0) &amp;&amp; st_lookup(is,name,&amp;dummy)){

    fprintf(fp,″%s_%s″,name,lhs?″ns″:″ps″);

  }else if((os!=0) &amp;&amp; st_lookup(os,name,&amp;dummy)){

    fprintf(fp,″%s_%s″,name,lhs?″ns″:″ps″);

  }else{

    fprintf(fp,″%s″,name);

  }

  first=tie_get_first_child(id);

  if(first==0){

     return;

  }

  /* detect whether this is a table access */
				
				<dp n="d133"/>
  prog=tie_get_program(id);

  if(tie_program_get_table_by_name(prog,name)!=0){

  switch(tie_get_type(first)){

  case TIE_ID:

      fprintf(fp,″(%s)″,tie_get_identifier(first));

      break;

  case TIE_INT:

      fprintf(fp,″(%d)″,tie_get_integer(first));

      break;

  default:

      DIE(″Error:expected type\n″);

  }

  return;

  }

  second=tie_get_next_sibling(first);

  if(second==0){

     fprintf(fp,″[%d]″,tie_get_integer(first));

  return;

  }

  fprintf(fp,″[%d:%d]″,tie_get_integer(first),
tie_get_integer(second));
}
/*********************************************************************
*******

                     打印连锁表达式
**********************************************************************
******/
static void
tie2ver_write_concatenation(
FILE *fp,tie_t *exp,int lhs,st_table *is,st_table *os)
{

  tie_t *comp;

  int write_comma;

  write_comma=0;

  fprintf(fp,″{″);

  tie_foreach_child(exp,comp){

   if(write_comma){

      fprintf(fp,″,″);

   }else{

      write comma=1;

   }

     tie2ver_write_expression(fp,comp,lhs,is,os);

   }end_tie_foreach_child;

   fprintf(fp,″}″);
}
/*********************************************************************
*******

                     打印条件语句
**********************************************************************
******/
static void
				
				<dp n="d134"/>
tie2ver_write_conditional(
FILE *fp,tie_t *exp,int lhs,st_table *is,st_table *os)
{

  tie_t *cond_exp,*then_exp,*else_exp;

  cond_exp=tie_get_first_child(exp);

  then_exp=tie_get_next_sibling(cond_exp);

  else_exp=tie_get_next_sibling(then_exp);

  ASSERT(tie_get_last_child(exp)==else_exp);

  fprintf(fp,″(″);

  tie2ver_write_expression(fp,cond_exp,lhs,is,os);

  fprintf(fp,″)?(″);

  tie2ver_write_expression(fp,then_exp,lhs,is,os);

  fprintf(fp,″):(″);

  tie2ver_write_expression(fp,else_exp,lhs,is,os);

  fprintf(fp,″)″);
}
/*********************************************************************
*******

                     打印复制语句
**********************************************************************
*******/
static void
tie2ver_write_replication(
FILE *fp,tie_t *exp,int lhs,st_table *is,st_table*os)
{

  tie_t *num,*comp;

  num=tie_get_first_child(exp);

  comp=tie_get_next_sibling(num);

  ASSERT(tie_get_last_child(exp)==comp);

  ASSERT(tie_get_type(num)==TIE_INT);

  fprintf(fp,″{%d{″,tie_get_integer(num));

  tie2ver_write_expression(fp,comp,lhs,is,os);

  fprintf(fp,″}}″);
}
/*********************************************************************
*******

                     打印一个表达式
**********************************************************************
******/
static void
tie2ver_write_expression(
FILE *fp,tie_t *exp,int lhs,st_table *is,st_table *os)
{

  tie_type_t type;

  tie_t *first,*second;

  first=tie_get_first_child(exp);

  second=first==0?0 :tie_get_next_sibling(first);
				
				<dp n="d135"/>
switch (type=tie_get_type(exp)){
case TIE_ID:
  tie2ver_write_identifier(fp,exp,lhs,is,os);
  break;
case TIE_INT:

   fprintf(fp,″%d″,tie_get_integer(exp));        break;
case TIE_CONST:

   fprintf(fp,″%s″,tie_get_constant(exp));       break;
case TIE_LOGICAL_NEGATION:
  tie2ver_write_unary(fp,″!″,first,lhs,is,os);  break;
case TIE_LOGICAL_AND:
  tie2ver_write_binary(fp,″&amp;&amp;″,first,second,lhs,is,os);
  break;
case TIE_LOGICAL_OR:
  tie2ver_write_binary(fp,″||″,first,second,lhs,is,os);
  break;
case TIE_BITWISE_NEGATION:
  tie2ver_write_unary(fp,″~″,first,lhs,is,os);break;
case TIE_BITWISE_AND:
  tie2ver_write_binary(fp,″&amp;″,first,second,lhs,is,os);
  break;
case TIE_BITWISE_OR:
  tie2ver_write_binary(fp,″|″,first,second,lhs,is,os);
  break;
case TIE_BITWISE_XOR:
  tie2ver_write_binary(fp,″^″,first,second,lhs,is,os);
  break;
case TIE_BITWISE_XNOR:
  tie2ver_write_binary(fp,″~^″,first,second,lhs,is,os);
  break;
case TIE_ADD:
  tie2ver_write_binary(fp,″+″,first,second,lhs,is,os);
  break;
case TIE_SUB:
  tie2ver_write_binary(fp,″-″,first,second,lhs,is,os);
  break;
case TIE_MULT:
  tie2ver_write_binary(fp,″*″,first,second,lhs,is,os);
  break;
case TIE_GT:
  tie2ver_write_binary(fp,″>″,first,second,lhs,is,os);
  break;
case TIE_GEQ:
  tie2ver_write_binary(fp,″>=″,first,second,lhs,is,os);
  break;
case TIE_LT:
  tie2ver_write_binary(fp,″<″,first,second,lhs,is,os);
  break;
case TIE_LEQ:
  tie2ver_write_binary(fp,″<=″,first,second,lhs,is,os);
  break;
case TIE_EQ:
  tie2ver_write_binary(fp,″==″,first,second,lhs,is,os);
  break;
case TIE_NEQ:
				
				<dp n="d136"/>
    tie2ver_write_binary(fp,″!=″,first,second,lhs,is,os);

    break;

  case TIE_REDUCTION_AND:

    tie2ver_write_unary(fp,″&amp;″,first,lhs,is,os);break;

  case TIE_REDUCTION_OR:

    tie2ver_write_unary(fp,″|″,first,lhs,is,os);break;

  case TIE_REDUCTION_XOR:

    tie2ver_write_unary(fp,_″^″,first,lhs,is,os);break;

  case TIE_SHIFT_LEFT:

    tie2ver_write_binary(fp,″<<″,first,second,lhs,is,os);

    break;

  case TIE_SHIFT_RIGHT:

    tie2ver_write_binary(fp,″>>″,first,second,lhs,is,os);

    break;

  case TIE_REPLICATION:

      tie2ver_write_replication(fp,exp,lhs,is,os);

    break;

  case TIE_CONCATENATION:

      tie2ver_write_concatenation(fp,exp,lhs,is,os);

    break;

  case TIE_CONDITIONAL:

      tie2ver_write_conditional(fp,exp,lhs,is,os);

    break;

  default:

    fprintf(stderr,″Wrong type:%d\n″,type);

      DIE(″Error:wrong expression type\n″);

  }
}
/*********************************************************************
*******

                   打印一个赋值语句
**********************************************************************
******/
static void
tie2ver_write_assignment(
FILE *fp,tie_t *assign,st_table *in_states,st_table *out_states)
{

  tie_t *lval,*rval;

  ASSERT(tie_get_type(assign)==TIE_ASSIGNMENT);

  lval=tie_get_first_child(assign);

  rval=tie_get_last_child(assign);

  ASSERT(tie_get_next_sibling(lval)==rval);

  ASSERT(tie_get_prev_sibling(rval)==lval);

  fprintf(fp,″assign″);

  tie2ver_write_expression(fp,lval,1,in_states,out_states);

  fprintf(fp,″=″);

  tie2ver_write_expression(fp,rval,0,in_states,out_states);

  fprintf(fp,″;\n″);
}
/*********************************************************************
*******
				
				<dp n="d137"/>
                     打印一份语句列表
**********************************************************************
******/
static void
tie2ver_write_statement(
FILE *fp,tie_t *statement,st_table *in_states,st_table *out_states)
{
  tie_t *child;

  ASSERT(tie_get_type(statement)==TIE_STATEMENT);

  tie_foreach_child(statement,child){

       switch (tie_get_type(child)){

    case TIE_WIRE:

        tie2ver_write_wire(fp,child);

        break;

    case TIE_ASSIGNMENT:

        tie2ver_write_assignment(fp,child,in_states,out_states);

        break;

    default:

        DIE(″Error:illegal program statement\n″);

    }

  }  end_tie_foreach_child;
}
/*********************************************************************
*******

                 为“iclass”编写模块定义
**********************************************************************
******/
static void
tie2ver_write_module_declaration(FILE *fp,tie_t *semantic)
{

  st_table *operand_table,*state_table;

  st_generator *gen;

  tie_t *ilist,*inst;

  char *c,*key,*value;

  fprintf(fp,″\n″);

  fprintf(fp,″module %s(″,tie_semantic_get_name(semantic)};

  c=″″;

  operand_table=tie_semantic_get_operand_table(semantic);

  st_foreach_item(operand_table,gen,&amp;key,&amp;value){

      fprintf(fp,″%s%s″,c,key);

    c=″,″;

  }

  state_table=tie_semantic_get_in_state_table(semantic);

  st_foreach_item(state_table,gen,&amp;key,&amp;value){

    fprintf(fp,″%s%s_ps″,c,key);

    c=″,″;

  }

  state_table=tie_semantic_get_out_state_table(semantic);

  st_foreach_item(state_table,gen ,&amp;key,&amp;value){
				
				<dp n="d138"/>
    fprintf(fp,″%s%s_ns″,c,key);

    fprintf(fp,″%s%s_we″,c,key);

    c=″,″;

  )

  ilist=tie_semantic_get_inst_list(semantic);

  tie_inst_list_foreach_instruction(ilist,inst){

      fprintf(fp,″,%s″,tie_instruction_get_name(inst));

  }end_tie_inst_list_foreach_instruction;

  fprintf(fp,″);\n″);

  st_foreach_item(operand_table,gen,&amp;key,&amp;value){

    switch((tie_type_t)value){

    case TIE_ARG_IN:

        fprintf(fp,″input[31:0]%s;\n″,key);break;

    case TIE_ARG_OUT:

        fprintf(fp,″output[31:0]%s;\n″,key);break;

    case TIE_ARG_INOUT:
        fprintf(fp,″inout[31:0]%s;\n″,key);break;

    default:

        DIE(″Error:unexpected arg type\n″);

    }

  }

  state_table=tie_semantic_get_in_state_table(semantic);

  st_foreach_item(state_table,gen,&amp;key,&amp;value){

   fprintf(fp,″input[%d:0]%s_ps;\n″,(int)value-1,key);

  }

  state_table=tie_semantic_get_out_state_table(semantic);

  st_foreach_item(state_table,gen,&amp;key,&amp;value){

   fprintf(fp,″output[%d:0]%s_ns;\n″,(int)value-1,key);

   fprintf(fp,″output %s_we;\n″,key);

  }

  tie_inst_list_foreach_instruction(ilist,inst){

      fprintf(fp,″input %s;\n″,tie_instruction_get_name(inst));

  }end_tie_inst_list_foreach_instruction;
}
/*********************************************************************
*******

            将“表格”打印到一个TIE文件
**********************************************************************
******/
static void
tie2ver_write_table(FILE *fp,tie_t *table)
{

  int i,width,size,bits,ivalue;

  char *oname,*iname,*cvalue;

  tie_t *value;

  oname=tie_table_get_name(table);

  iname=″index″;

  width=tie_table_get_width(table);
				
				<dp n="d139"/>
  size=tie_table_get_depth(table);

  bits=(int)ceil(log(size)/log(2));

  fprintf(fp,″\nfunction[%d:0]%s;\n″,width-1,oname);

  fprintf(fp,″input[%d:0]%s;\n″,bits-1,iname);

  fprintf(fp,″case(%s)\n″,iname);

  i=0;

  tie_table_foreach_value(table,value){

    fprintf(fp,″%d′d%d:%s=″,bits,i,oname);

    switch(tie_get_type(value)){

    case TIE_CONST:

        cvalue=tie_get_constant(value);

        fprintf(fp,″%d′b%s ;\n″,width,
tie_constant_get_binary_string(cvalue));

        break;

    case TIE_INT:

        ivalue=tie_get_integer(value);

        fprintf(fp,″%d′d%d;\n″,width,ivalue);

        break;

    default:

        DIE(″Internal Error:unexpected type\n″);

    }

    i++;

    }end_tie_table_foreach_value;

    fprintf(fp,″default:%s=%d′d0;\n″,oname,width);

    fprintf(fp,″endcase\n″);

    fprintf(fp,″endfunction\n″);
}
/*********************************************************************

       为被“语义”语句修改的每一种状态编写写使能逻辑
**********************************************************************
******/
static void
tie2ver_semantic_write_we(FILE *fp,tie_t *semantic)
{

  tie_t *inst;

  st_table *semantic_state_table,*inst_state_table;

  st_generator *gen;

  char *key,*value,*c,*iname;

  int found;

  semantic_state_table=tie_semantic_get_out_state_table(semantic);

  st_foreach_item(semantic_state_table,gen,&amp;key,&amp;value){

   fprintf(fp,″assign %s_we=″,key);

   c=″″;

   tie_semantic_foreach_instruction(semantic,inst){

       iname=tie_instruction_get_name(inst);

       inst_state_table=tie_instruction_get_state_table(inst);

       found=st_lookup(inst_state_table,key,&amp;value);

       if(found &amp;&amp;((tie_type_t)value!=TIE_ARG_IN)){

        fprintf(fp,″%s1′b1 &amp; %s″,c,iname);

       }else{
        fprintf(fp,″%s1′b0 &amp; %s″,c,iname);

       }
				
				<dp n="d140"/>
       c=″\n|″;

    }end_tie_semantic_foreach_instruction;

    fprintf(fp,″;\n″);

  }
}
/*********************************************************************
*******

                将“语义”语句写入TIE文件
**********************************************************************
******/
static void
tie2ver_write_semantic(FILE *fp,tie_t *semantic)
{

  tie_t *table,*statement;

  ls_t *tables;

  st_table *in_state_table,*out_state_table;

  ASSERT(tie_get_type(semantic)==TIE_SEMANTIC);

  tie2ver_write_module_declaration(fp,semantic);

  statement=tie_semantic_get_statement(semantic);

  in_state_table=tie_semantic_get_in_state_table(semantic);

  out_state_table=tie_semantic_get_out_state_table(semantic);

  tie2ver_write_statement(fp,statement,in_state_table,
out_state_table);

  tables=tie_expression_get_tables(statement,
tie_get_program(semantic));

  ls_foreach_data(tie_t*,tables,table){

    tie2ver_write_table(fp,table);

  }end_ls_foreach_data;

  ls_free(tables);

  tie2ver_semantic_write_we(fp,semantic);

  fprintf(fp,″endmodule\n″);
}
/*********************************************************************
*******

            为组合语义打印顶级模块说明
**********************************************************************
******/
static void
tie2ver_write_top_module(FILE *fp,tie_t *prog)
{

  st_generator  *gen;

  char *key,*value;

  st_table *operand_table;

  tie_t *inst,*iclass;

  fprintf(fp,″\n″);

  fprintf(fp,″module UserInstModule(clk,out_E,ars_E,art_E,
inst_R″);

  fprintf(fp,″,Kill_E,killPipe_W,valid_W″);

  tie_program_foreach_iclass(prog,iclass){
				
				<dp n="d141"/>
  if(tie_get_predefined(iclass))continue;

  tie_iclass_foreach_instruction(iclass,inst){

      fprintf(fp,″,%s_R″,tie_instruction_get_name(inst));

  }end_tie_iclass_foreach_instruction;

  }end_tie_program_foreach_iclass ;

  fprintf(fp,″,en_R);\n″);

  fprintf(fp,″input clk;\n″);

  fprintf(fp,″output [31:0] out_E;\n″);

  fprintf(fp,″input [31:0] ars_E;\n″);

  fprintf(fp,″input [31:0] art_E;\n″);

  fprintf(fp,″input [23:0] inst_R;\n″);

  fprintf(fp,″input en_R;\n″);

  fprintf(fp,″input Kill_E,killPipe_W,valid_W;\n″);

  tie2ver_program_foreach_instruction(prog,inst){

   fprintf(fp,″input %s_R;\n″,tie_instruction_get_name(inst));

  }end_tie2ver_program_foreach_instruction;

  tie2ver_program_foreach_instruction(prog,inst){

   fprintf(fp,″wire %s_E;\n″,tie_instruction_get_name(inst));

  }end_tie2ver_program_foreach_instruction;

  operand_table=tie2ver_program_get_operand_table(prog);

  st_foreach_item(operand_table,gen,&amp;key,&amp;value){

      if((tie_type_t)value!=TIE_ARG_IN){

       fprintf(fp,″wire[31:0] %s_E;\n″,key);

    }

  }
}
/*********************************************************************

        为每一个语义块和为每一个选择信号的每一个输出编写一

    段接线程序
**********************************************************************
******/
static void
tie2ver_write_wire_declaration(FILE *fp,tie_t *prog)
{

  tie_t *semantic, *state;

  st_table *operand_table, *global_operand_table;

  st_table *state_table;

  st_generator *gen;

  char *key,*value,*sname;

  int width;

  global_operand_table =tie2ver_program_get_operand_table(prog);

  st_foreach_item(global_operand_table,gen,&amp;key,&amp;value){

  if((tie_type_t)value==TIE_ARG_IN){

     if(strcmp(key,″art″)!=0 &amp;&amp; strcmp(key,″ars″)!=0){

      fprintf(fp,″wire[31:0] %s_R,%s_E;\n″,key,key);

     }

    }

  }
				
				<dp n="d142"/>
  tie_program_foreach_state(prog,state){

   if(tie_get_predefined(state))continue;

   sname=tie_state_get_name(state);

   width=tie_state_get_width(state);

   fprintf(fp,″wire[%d:0]%s_ps,%s_ns ;\n″,width-1,sname,
sname);

    fprintf(fp,″wire %s_we;\n″,sname);

  }end_tie_program_foreach_state;

  tie_program_foreach_semantic(prog,semantic){

  if(tie_get_predefined(semantic))continue;

  sname=tie_semantic_get_name(semantic);

  operand_table=tie_semantic_get_operand_table(semantic);

  st_foreach_item(operand_table,gen,&amp;key,&amp;value){

      if((tie_type_t)value !=TIE_ARG_IN){

         fprintf(fp,″wire[31:0]%s_%s;\n″,sname,key);

     }

  }

  state_table=tie_semantic_get_out_state_table(semantic);

  st_foreach_item(state_table,gen,&amp;key,&amp;value){

      fprintf(fp,″wire[%d:0]%s_%s_ns;\n″,(int)value-1,
sname,key);

        fprintf(fp,″wire %s_%s_we;\n″,sname,key);

  }

  fprintf(fp,″wire %s_select;\n″,sname);

  }end_tie_program_foreach_semantic;
}
/*********************************************************************
*******

                 写一个浮点运算说明语句
**********************************************************************
******/
static void
tie2ver_write_flop_instance(FILE *fp,char *name,int num)
{

  char *fmt;

  fmt=″tie_flop #(%d) f%s (.tie_out(%s_E),.tie_in(%s_R),
.clk(clk));\n″;

  fprintf(fp,fmt,num,name,name,name);
}
/*********************************************************************
*******

           锁存所有针对R级的指令信号
**********************************************************************
******/
static void
tie2ver_write_flop(FILE *fp,tie_t *prog)
{

  char *name;
				
				<dp n="d143"/>
  tie_t *inst;

  tie2ver_program_foreach_instruction(prog,inst){

   name=tie_instruction_get_name(inst);

   tie2ver_write_flop_instance(fp,name,1);

  }end_tie2ver_program_foreach_instruction;
}
/*********************************************************************

          为每一个语义块编写一个实例
**********************************************************************
******/
static void
tie2ver_write_semantic_instance(FILE *fp,tie_t *prog)
{

  tie_t *semantic,*ilist,*inst;

  const char *iname,*aname,*c;

  st_table *operand_table,*state_table;

  st_generator *gen;

  char *key,*value;

  tie_program_foreach_semantic(prog,semantic){

   if(tie_get_predefined(semantic))continue;

   iname=tie_semantic_get_name(semantic);

   fprintf(fp,″%s i%s(″,iname,iname);

   c=″″;

   operand_table=tie_semantic_get_operand_table(semantic);

   st_foreach_item(operand_table,gen,&amp;key,&amp;value){

       if((tie_type_t)value==TIE_ARG_IN){

        fprintf(fp,″%s\n   .%s(%s_E)″,c,key,key);

       }else{

          fprintf(fp,″%s\n   .%s(%s_%s)″,c,key,iname,key);

       }

       c=″,″;

   }

   state_table=tie_semantic_get_in_state_table(semantic);

   st_foreach_item(state_table,gen,&amp;key,&amp;value){

       fprintf(fp,″%s\n  .%s_ps(%s_ps)″,c,key,key);

       c=″,″;

   }

   state_table=tie_semantic_get_out_state_table(semantic);

   st_foreach_item(state_table,gen,&amp;key,&amp;value){

       fprintf(fp,″%s\n  .%s ns(=s_%s_ns)″,c,key,iname,key);

       fprintf(fp,″%s\n  .%s_we(%s_%s_we)″,c,key,iname,key);

       c=″,″;

   }

   ilist=tie_semantic_get_inst_list(semantic);

   tie_inst_list_foreach_instruction(ilist,inst){

       aname=tie_instruction_get_name(inst);

       fprintf(fp,″,\n  .%s(%s_E)″,aname,aname);
				
				<dp n="d144"/>
  }end_tie_inst_list_foreach_instruction;

  fprintf(fp,″);\n″);
   }end_tie_program_foreach_semantic;
}
/*********************************************************************
*******

          为每一种状态编写一个实例
**********************************************************************
******/
static void
tie2ver_write_state_instance(FILE *fp,tie_t *prog)
{

  tie_t *state;

  char *sname;

  int width;

  tie_program_foreach_state(prog,state){

  if(tie_get_predefined(state))continue;
  sname=tie_state_get_name(state);

  width=tie_state_get_width(state);

  fprintf(fp,″tie_athens_state#(%d)i%s(\n″,width,sname);

  fprintf(fp,″.ns(%s_ns),\n″,sname);

  fprintf(fp,″.we(%s_we),\n″,sname);

  fprintf(fp,″.ke(Kill_E),\n″);

  fprintf(fp,″.kp(killPipe_W),\n″);

  fprintf(fp,″.vw(valid_W),\n″);

  fprintf(fp,″.clk(clk),\n″);

  fprintf(fp,″.ps(%s_ps));\n″,sname);

  }end_tie_program_foreach_state;
}
/*********************************************************************
*******

              为一个输出编写操作数选择逻辑
**********************************************************************
******/
static void
tie2ver_write_opeTand_selection_logic_one(FILE *fp,tie_t *prog,char
*name)
{

  tie_t *semantic;

  char *c,*dummy;

  st_table *operand_table;

  fprintf(fp,″assign %s_E=″,name);

  c=″″;

  tie_program_foreach_semantic(prog,semantic){

   if(tie_get_predefined(semantic))continue;

   operand_table=tie_semantic_get_operand_table(semantic);

   fprintf(fp,″%s″,c);

   if(st_lookup(operand_table,name,&amp;dummy)){

     fprintf(fp,″%s_″,tie_semantic_get_name(semantic));

     fprintf(fp,″%s &amp;″,name);
				
				<dp n="d145"/>
   }else{

      fprintf(fp,″{32(l′b0}}&amp;″);

   }

   fprintf(fp,″{ 32{%s_select}}″,tie_semantic_get_name(semantic));

   c=″\n    |″;

  }end_tie_program_foreach_semantic;

  fprintf(fp,″;\n″);
}
/*********************************************************************
*******

             为一种状态编写状态选择逻辑
**********************************************************************
******/
static void
tie2ver_write_state_selection_logic_one(
FILE *fp,tie_t*prog,char*name,int width)
{

  tie_t *semantic;

  char *c,*value,*sname;

  st_table *state_table;

  fprintf(fp,″assign %s_ns=″,name);
  c=″″;

  tie_program_foreach_semantic(prog,semantic){

  if(tie_get_predefined(semantic))continue;

  sname=tie_semantic_get_name(semantic);

  state_table=tie_semantic_get_out_state_table(semantic);

  fprintf(fp,″%s″,c);

  if(st_lookup(state_table,name,&amp;value)){

     fprintf(fp,″%s_%s_ns &amp;″,sname,name);

  }else{

     fprintf(fp,″{%d{1′b0}}&amp;″,width);

  }

  fprintf(fp,″{%d{%s_select}}″,width,sname);

  c=″\n    |″;

  }end_tie_program_foreach_semantic;

  fprintf(fp,″;\n″);

  fprintf(fp,″assign %s_we=″,name);

  c=″″;

  tie_program_foreach_semantic(prog,semantic){

  if(tie_get_predefined(semantic))continue;

  sname=tie_semantic_get_name(semantic);

  state_table=tie_semantic_get_out_state_table(semantic);

  fprintf(fp,″%s″,c);

  if(st_lookup(state_table,name,&amp;value)){

     fprintf(fp,″%s_%s_we &amp; ″,sname,name);

  }else{

     fprintf(fp,″1′b0 &amp; ″);

  }

  fprintf(fp,″%s_select″,sname);

  c=″\n    |″;

  }end_tie_program_foreach_semantic;

  fprintf(fp,″;\n″);
}
				
				<dp n="d146"/>
/*********************************************************************
*******

                 为顶级模块编写选择逻辑
**********************************************************************
******/
static void
tie2ver_write_selection_logic(FILE *fp,tie_t *prog)
{

  tie_t *semantic,*ilist,*inst,*state;

  char *key, *value,*c,*sname;

  st_table *global_operand_table;

  st_generator *gen;

  int width;

  tie_program_foreach_semantic(prog,semantic){

   if(tie_get_predefined(semantic))continue;

    ilist=tie_semantic_get_inst_list(semantic);

   fprintf(fp,″assign %s_select=″,
tie_semantic_get_name(semantic));

  c=″″;

  tie_inst_list_foreach_instruction(ilist,inst){

      fprintf(fp,″%s%s_E″,c,tie_instruction_get_name(inst));

      c=″\n    |″;

  }end_tie_inst_list_foreach_instruction;

  fprintf(fp,″;\n″);
   }end_tie_program_foreach_semantic;

  global_operand_table=tie2ver_program_get_operand_table(prog);

  st_foreach_item(global_operand_table,gen,&amp;key,&amp;value){

   if((tie_type_t)value !=TIE_ARG_IN){

      tie2ver_write_operand_selection_logic_one(fp,prog,key);

      fprintf(fp,″assign out_E=%s_E;\n″,key);

  }
   }
   tie_program_foreach_state(prog,state){

   if(tie_get_predefined(state))continue;

   sname=tie_state_get_name(state);

   width=tie_state_get_width(state);

   tie2ver_write_state_selection_logic_one(fp,prog,sname,width);

  }end_tie_program_foreach_state;
}
/*********************************************************************
*******

        编写一系列的赋值语句,以便从指令中提取“字段”
**********************************************************************
******/
static void
tie2ver_write_field_recur(FILE *fp,tie_t *prog,tie_t *field,char
*suffix)
{

  tie_t *subfield,*newfield;

  char *c,*name;
				
				<dp n="d147"/>
  c=″;

  fprintf(fp,″{″);

  tie_field_foreach_subfield(field,subfield){

   fprintf(fp,″%s″,c);

     switch(tie_get_type(subfield)){

   case TIE_ID:

       name=tie_get_identifier(subfield);

       newfield=tie_program_get_field_by_name(prog,name);

       if(newfield==0){

        fprintf(fp,″inst_R″);

      }else{

        tie2ver_write_field_recur(fp,prog,newfield,suffix);

      }

      break;

  case TIE_SUBFIELD:

      name=tie_subfield_get_name(subfield);

      newfield=tie_program_get_field_by_name(prog,name);

      if(newfield==0){

       fprintf(fp,″inst_R″);

      }else{

       DIE(″Error:unexpected subfield name(expect ′inst′)\n″);

      }

      fprintf(fp,″[%d:″,tie_subfield_get_from_index(subfield));

      fprintf(fp,″%d]″,tie_subfield_get_to_index(subfield));

      break;

  default:

      DIE(″Error:unexpected subfield type\n″);

  }

  c=″,″;
   }end_tie_field_foreach_subfield;
   fprintf(fp,″}″);
}
/*********************************************************************
*******

           编写一系列的赋值语句,以便从指令中提取“字段”
**********************************************************************
******/
static void
tie2ver_write_field(FILE *fp,tie_t *prog,tie_t *field,char *suffix)
{

  fprintf(fp,″assign %s%s=″,tie_field_get_name(field),suffix);

  tie2ver_write_field_recur(fp,prog,field,suffix);

  fprintf(fp,″;\n″);
}
/*********************************************************************
*******

                 为“操作数”编写一个模块
**********************************************************************
******/
static void
tie2ver_write_one_immediate(FILE *fp,tie_t *prog,tie_t *operand)
{
				
				<dp n="d148"/>
  tie_t *decoding,*field,*table;

  char *oname,*fname;

  ls_t *tables;

  int width;

  ASSERT(tie_get_type(operand)==TIE_OPERAND);

  oname=tie_operand_get_name(operand);

  fname=tie_operand_get_field_name(operand);

  field=tie_program_get_field_by_name(prog,fname);

  width=tie_field_get_width(field);

  fprintf(fp,″\n″);

  fprintf(fp,″module %s(inst_R,%s);\n″,oname,oname);

  fprintf(fp,″input[23:0]inst_R;\n″);

  fprintf(fp,″output[31:0]%s;\n″,oname);

  fprintf(fp,″wire[%d:0]%s;\n″,tie_field_get_width(field)-1,
fname);

  tie2ver_write_field(fp,prog,field,″″);

  decoding=tie_operand_get_decoding_expression(operand);

  fprintf(fp,″assign %s=″,oname);

  tie2ver_write_expression(fp,decoding,0,0,0);

  fprintf(fp,″;\n″);

  tables=tie_expression_get_tables(decoding,prog);

  ls_foreach_ data(tie_t*,tables,table){

      tie2ver_write_table(fp,table);

  }end_ls_foreach_data;

  ls_free(tables);

  fprintf(fp,″endmodule\n″);
}    
/*********************************************************************
*******

           为每一种立即操作数解码逻辑编写一个模块
**********************************************************************
******/
static void
tie2ver_write_immediate(FILE *fp,tie_t *prog)
{

  st_table *operand_table;

  char *key,*value;

  st_generator *gen;

  tie_t *operand;

  tie_t *field;

  operand_table=tie2ver_program_get_operand_table(prog);

  st_foreach_item(operand_table,gen,&amp;key,&amp;value){

   if((tie_type_t)value==TIE_ARG_IN){

      if(strcmp(key,″art″)!=0 &amp;&amp; strcmp(key,″ars″)!=0){

         operand=tie_program_get_operand_by_name(prog,key);

       if(operand !=0){

          if(!tie_get_predefined(operand)){

           tie2ver_write_one_immediate(fp,prog,operand);

          }

       }else{

          field=tie_program_get_field_by_name(prog,key);
				
				<dp n="d149"/>
           if(field==0){

            fprintf(stderr,″Error:invalid operand %s\n″,key);

           }

        }

      }

    }

  }
}
/*********************************************************************
*******

                 为“操作数”编写一个模块
**********************************************************************
******/
static void
tie2ver_write_one_operand_instance(FILE *fp,tie_t *prog,tie_t
*operand)
{

  char *oname;

  ASSERT(tie_get_type(operand)==TIE_OPERAND);

  oname=tie_operand_get_name(operand);

  fprintf(fp,″%s i%s(.inst(inst_R),.%s(%s_R));\n″,oname,oname,
oname,oname);

  tie2ver_write_flop_instance(fp,oname,32);
}
/*********************************************************************
*******

          编写一个语句,以便从inst_R中提取“字段名”
**********************************************************************
******/
static void
tie2ver_write_one_field_instance(FILE *fp,tie_t *prog,tie_t *field)
{

  char *name;

  tie2ver_write_field(fp,prog,field,″_R″);

  name=tie_field_get_name(field);

  tie2ver_write_flop_instance(fp,name,32);
}
/*********************************************************************

           为每一种立即操作数解码逻辑编写一个实例
**********************************************************************
******/
static void
tie2ver_write_immediate_instance(FILE *fp,tie_t *prog)
{

  char *key,*value;

  st_table *operand_table;

  st_generator *gen;

  tie_t *operand,*field;
				
				<dp n="d150"/>
  operand_table=tie2ver_program_get_operand_table(prog);

  st_foreach_item(operand_table,gen,&amp;key,&amp;value){

   if((tie_type_t)value==TIE_ARG_IN){

     operand=tie_program_get_operand_by_name(prog,key);
     if(operand!=0 &amp;&amp; tie_operand_is_immediate(operand)){

      tie2ver write_one_operand_instance(fp,prog,operand);

     }else if(operand==0){ 

      field=tie_program_get_field_by_name(prog,key);

      if(field!=0){

         tie2ver_write_one_field_instance(fp,prog,field);

      }

     }

    }

  }
}
/********************************************************************* 

           将“prog”打印到TIE文件
**********************************************************************
******/
void
tie2ver_write_verilog(FILE *fp,tie_t *prog)
{

  tie_t *semantic;

  /* write tie primitives */

  fprintf(fp,COMMENTS);

  fprintf(fp,TIE_ENFLOP);

  fprintf(fp,TIE_FLOP);

  fprintf(fp,TIE_ATHENS_STATE);

  /* write each semantic block as a verilog module */

  ASSERT(tie_get_type(prog)==TIE_PROGRAM);

  tie_program_foreach_semantic(prog,semantic){

    if(tie_get_predefined(semantic))continue;

    tie2ver_write_semantic(fp,semantic);

   }end_tie_program_foreach_semantic;

  /* write each immediate operand as a verilog module */

  tie2ver_write_immediate(fp,prog);

  /* write the top-level Verilog module */

  tie2ver_write_top_module(fp,prog);

  tie2ver_write_wire_declaration(fp,prog);

  tie2ver_write_flop(fp,prog);

  tie2ver_write_immediate_instance(fp,prog);

  tie2ver_write_semantic_instance(fp,prog);

  tie2ver_write_state_instance(fp,prog);

  tie2ver_write selection_logic(fp,prog);

  fprintf(fp,″endmodule\n″);
}
/*********************************************************************
*******
				
				<dp n="d151"/>
              将“prog”打印到TIE文件
**********************************************************************
******/
void
tie2ver_write_instruction(FILE *fp,tie_t prog)
{

  tie_t *inst;

  int first=1;

  tie2ver_program_foreach_instruction(prog,inst){

   if (first){

       fprintf(fp,″%s″,tie_instruction_get_name(inst));

       first=0;

   }else{

       fprintf(fp,″%s″,tie_instruction_get_name(inst));

   }

  }end_tie2ver_program_foreach_instruction;
}
/*
 *  Local Variables:
 *  mode:c
 *  c-basic-offset:4
 *  End:
 */
附件E
#include ″tie.h″
#define COMMENTS″/* Do not modify. This is automatically
generated.*/″
#define tie2gcc_program_foreach_instruction(_prog,_inst){  \

  tie_t *_iclass;                                        \

  tie_program_foreach_iclass(_prog,_iclass){             \

      if(tie_get_predefined(_iclass))continue;           \

      tie_iclass_foreach_instruction(_iclass,_inst){
#define end_tie2gcc_program_foreach_instruction         \

      }end_tie_iclass_foreach_instruction;               \
   }end_tie_program_foreach_iclass;                        \
}
/*********************************************************************
*******

  建立并返回全局程序→用于用户定义的各项指令的自变量表格。

  返回的表格不含在预先定义的各项指令中所使用的各自变量。
**********************************************************************
******/
static st_table *
tie2gcc_program_get_operand_table(tie_t *prog)
{

  static st_table *tie2gcc_program_args=0;

  tie_t *inst;

  char *key,*value;

  st_table *arg_table;

  st_generator *gen;

  if(tie2gcc_progran_args==0){

     tie2gcc_program_args=st_init_table(strcmp,st_strhash);

     tie2gcc_program_foreach_instruction(prog,inst){

         arg_table=tie_instruction_get_operand_table(inst);

         st_foreach_item(arg_table,gen,&amp;key,&amp;value){

             st_insert(tie2gcc_program_args,key,value);

        }

         st_free_table(arg_table);

     }end_tie2gcc_program_foreach_instruction;

  }

  return tie2gcc_program_args;
}
/*********************************************************************
*******

                产生函数和自变量说明
**********************************************************************
******/
static void
tie2gcc_write_function(FILE *fp,tie_t *inst,tie_t *args)
{

  tie_t *arg;
				
				<dp n="d154"/>
   char *c;

   c=″″;

   fprintf(fp,″\n#define %s(″,tie_instruction_get_name(inst));

   tie_args_foreach_arg(args,arg){

      if(tie_get_type(arg)!=TIE_ARG_OUT){

        fprintf(fp,″%s%s″,c,tie_arg_get_name(arg));

        c=″,″;

    }

  }end_tie_args_foreach_arg;

  fprintf(fp,″)\\\n″);
}
/*********************************************************************

  返回在“args”中各自变量的列表,首先输出args。返回的列表

  应当被调用者释放。
**********************************************************************
*******/
ls_t *
tie2gcc_args_get_ordered(tie_t *args)
{

  tie_t *arg;

  ls_t *arglist;

  arglist=ls_alloc();

  tie_args_foreach_arg(args,arg){

   if(tie_get_type(arg)!=TIE_ARG_IN){

      ls_append(arglist,arg);

   }

  }end_tie_args_foreach_arg;

  tie_args_foreach_arg(args,arg){

   if(tie_get_type(arg)!=TIE_ARG_OUT){

      ls_append(arglist,arg);

   }

  }end_tie_args_foreach_arg;

  return arglist;
}
/*********************************************************************
*******

           写出一个ASM语句
**********************************************************************
******/
static void
tie2gcc_write_one_asm(
FILE *fp,tie_t *prog,tie_t *inst,tie_t *args,int value)
{

  tie_t *arg,*operand,*state;

  tie_type_t type,ptype;

  ls_t *arglist;
				
				<dp n="d155"/>
  char *t,s,c,*name,*n;

  int i;

  /* write the asm statement */

  fprintf(fp,″asm volatile(\″%s\t″,
tie_instruction_get_name(inst));

  i=0;

  tie_args_foreach_arg(args,arg){

      fprintf(fp,″%s%%%d″,i==0?″″:″,″,i);

   i++;

  }end_tie_args_foreach_arg;

  fprintf(fp,″\″″);

  ptype=TIE_UNKNOWN;

  arglist=tie2gcc_args_get_ordered(args);

  ls_foreach_data(tie_t *,arglist,arg){

    name=tie_arg_get_name(arg);

    operand=tie_program_get_operand_by_name(prog,name);

    if(operand !=0){

       state=tie_operand_get_state(operand);

       if(state!=0){

        n=tie_state_get_name(state);

        if(strcmp(n,″AR″)==0){

           c=′a′;

        }else if(strcmp(n,″FR″)==0){

           c=′f′;

        }else if(strcmp(n,″DR″)==0){

           c=′d′;

        }else if(strcmp(n,″BR″)==0){

           c=′b′;

        }else{

           DIE(″Internal Error:invalid state\n″);

        }

       }else{

        c=′i′;

       }

   }else{

       c=′i′;

   }

   type=tie_get_type(arg);

   if (ptype==TIE_UNKNOWN &amp;&amp; type==TIE_ARG_IN){

       fprintf(fp,″:″);

   }

   s=type==ptype ?′,′:′:′;

   t=type==TIE_ARG_IN?″″:″=″;

   fprintf(fp,″%c \″%s%c\″(%s)″,s,t,c,name);

   ptype=type;

  }end_ls_foreach_data;

  ls_free(arglist);

  fprintf(fp,″);″);
}
/********************************************************************
*******
				
				<dp n="d156"/>
              为“inst”产生在线函数
**********************************************************************
******/
static void
tie2gcc_write_asm(FILE *fp,tie_t *prog,tie_t *inst,tie_t *args)
{

  tie_t *arg, *out_arg;

  /* declear output variable and find the immediate operand */

  fprintf(fp,″   ({″);

  out_arg=0;

  tie_args_foreach_arg(args,arg){

      if(tie_get_type(arg)==TIE_ARG_OUT){

       fprintf(fp,″int %s ;″,tie_arg_get_name(arg));

       out_arg=arg;

    }

  }end_tie_args_foreach_arg;

  tie2gcc_write_one_asm(fp,prog,inst,args,-1);

  /* return the results */

  if(out_arg!=0){

    fprintf(fp,″%s;″,tie_arg_get_name(out_arg));

  }

  fprintf(fp,″})\n″);
}
/*********************************************************************
*******  

             为“inst”产生一个宏
/*********************************************************************
******/
static void
tie2gcc_write_inst(FILE *fp,tie_t *prog,tie_t *inst,tie_t *args)
{

  tie2gcc_write_function(fp,inst,args);

  tie2gcc_write_asm(fp,prog,inst,args);
}
/*********************************************************************
  产生gcc头文件,它将被纳入应用程序代码,以便使用用户定义
  的各项指令。
**********************************************************************
******/
void
tie2gcc_write_gcc(FILE *fp,tie_t *prog)
{

  tie_t *iclass,*ilist,*inst,*args;

  ASSERT(tie_get_type(prog)==TIE_PROGRAM);

  fprintf(fp,″%s\n″,COMMENTS);

  tie_program_foreach_iclass(prog,iclass){

    if(tie_get_predefined(iclass))continue;
				
				<dp n="d157"/>
    ilist=tie_iclass_get_inst_list(iclass);

  args=tie_iclass_get_io_args(iclass);

  tie_inst_list_foreach_instruction(ilist,inst){

      tie2gcc_write_inst(fp,prog,inst,args);

  }end_tie_inst_list_foreach_instruction;
  }end_tie_program_foreach_iclass;
}
/*********************************************************************
*******

           写出各函数以测试各立即数值的正确值
**********************************************************************
******/
static void
tie2gcc_write_operand_check_one(FILE *fp,char *name)
{

  fprintf(fp,″\nint\n″);

  fprintf(fp,″tensilica_%s(int v)\n″,name);

  fprintf(fp,″{\n″);

  fprintf(fp,″    tensilica_insnbuf_type insn;\n″);

  fprintf(fp,″    int new_v;\n″);

  fprintf(fp,″    if(!set_%s_field(insn,v))return 0;\n″,name);

  fprintf(fp,″    new_v=get_%s_field(insn);\n″,name);

  fprintf(fp,″    return new_v==v;\n″);

  fprintf(fp,″}\n″);
}
/*********************************************************************
*******

            写出各函数以测试各立即数值的正确值
**********************************************************************
******/
void
tie2gcc_write_operand_check(FILE *fp,tie_t *prog)
{

  st_table *arg_table;

  st_generator *gen;

  char *key,*value;

  arg_table=tie2gcc_program_get_operand_table(prog);

  st_foreach_item(arg_table,gen,&amp;key,&amp;value){

      if((tie_type_t),value==TIE_ARG_IN)( 

       if(strcmp(key,″art″)!=0 &amp;&amp; strcmp(key,″ars″)!=0

          tie2gcc_write_operand_check_one(fp,key);

       }

      }

  }
}
附件F
/*
 * TIE user_register routines
 */ 
/* $Id */
/*
 *  Copyright 1998-1999 Tensilica Inc.
 *  These coded instructions,statements,and computer programs are
 *  Confidential Proprietary Information of Tensilica Inc.and may not
be
 *  disclosed to third parties or copied in any form,in whole or in
part,
 *  without the prior written consent of Tensilica Inc.
 */
#include<math.h>
#include″tie.h″
#include″tie_int.h″
typedef struct ureg_struct{

    int statef;

  int statet;

  int uregf;

  int uregt;

  int ureg;

  char *name;
}ureg_t;
/*********************************************************************
*******

          返回“ureg”的索引
**********************************************************************
******/
int
tie_ureg_get_index(tie_t *ureg)
{

  ASSERT(tie_get_type(ureg)==TIE_UREG);

  return tie_get_integer(tie_get_first_child(ureg));
}
/*********************************************************************
           返回“ureg”的表达式
**********************************************************************
******/
tie_t *
tie_ureg_get_expression(tie_t *ureg)
{

  tie_t *index;

  ASSERT(tie_get_type(ureg)==TIE_UREG);

  index=tie_get_first_child(ureg);

  return tie_get_next_sibling(index);
}
				
				<dp n="d160"/>
/*********************************************************************
*******

              产生一个表示“ureg”的常数索引的字符串
**********************************************************************
******/
static char ureg_index[10];
char *tie_ureg_get_index_constant(tie_t *ureg)
{

  sprintf(ureg_index,″8′d%d″,tie_ureg_get_index(ureg));

  return ureg_index;
}
/*********************************************************************
*******

              产生针对RUR指令的st字段
**********************************************************************
******/
static void
tie_program_generate_st_field(tie_t  *program)
{

  tie_t *field;

  field=tie_alloc(TIE_FIELD);

  tie_append_child(field,tie_create_identifier(″st″));

  tie_append_child(field,tie_create_identifier(″s″));

  tie_append_child(field,tie_create_identifier(″t″));

  tie_program_add(program,field);
}
/*********************************************************************
*******

              产生RUR操作码
**********************************************************************
******/
static void
tie_program_generate_rur_opcode(tie_t *program)
{

  tie_t *opcode,*encode;

  opcode=tie_alloc(TIE_OPCODE);

  tie_append_child(opcode,tie_create_identifier(″RUR″));

  encode=tie_alloc(TIE_ENCODING);

  tie_append_child(opcode,encode);

  tie_append_child(encode,tie_create_identifier(″op2″));

  tie_append_child(encode,tie_create_constant(″4′b1110″));

  encode=tie_alloc(TIE_ENCODING);

  tie_append_child(opcode,encode);

  tie_append_child(encode,tie_create_identifier(″RST3″));

  tie_program_add(program,opcode);
}
				
				<dp n="d161"/>
/*********************************************************************
*******

                    产生WUR操作码
**********************************************************************
******/
static void
tie_program_generate_wur_opcode(tie_t *program)
{

  tie_t *opcode,*encode;

  opcode=tie_alloc(TIE_OPCODE);

  tie_append_child(opcode,tie_create_identifier(″WUR″));

  encode=tie_alloc(TIE_ENCODING);

  tie_append_child(opcode,encode);

  tie_append_child(encode,tie_create_identifier(″op2″));

  tie_append_child(encode,tie_create_constant(″4′b1111″));

  encode=tie_alloc(TIE_ENCODING);

  tie_append_child(opcode,encode);

  tie_append_child(encode,tie_create_identifier(″RST3″));

  tie_program_add(program,opcode);
}
/*********************************************************************
*******

                    产生RUR iclass
***********************************************************************
******/
static void
tie_program_generate_rur_iclass(tie_t *program)
{

  tie_t *iclass,*ilist,*args,*arg,*state;

  char *name;

  iclass=tie_alloc(TIE_ICLASS);

  tie_append_child(iclass,tie_create_identifier(″rur″));

  ilist=tie_alloc(TIE_INST_LIST);

  tie_append_child(iclass,ilist);

  tie_append_child(ilist,tie_create_identifier(″RUR″));

  args=tie_alloc(TIE_ARG_LIST);

  tie_append_child(iclass,args);

  arg=tie_alloc(TIE_ARG_OUT);

  tie_append_child(args,arg);

  tie_append_child(arg,tie_create_identifier(″arr″));

  arg=tie_alloc(TIE_ARG_IN);

  tie_append_child(args,arg);

  tie_append_child(arg,tie_create_identifier(″st″));

  args=tie_alloc(TIE_ARG_LIST);

  tie_append_child(iclass,args);
				
				<dp n="d162"/>
  tie_program_foreach_state(program,state){

  if(tie_get_predefined(state))continue;

  arg=tie_alloc(TIE_ARG_IN);

  tie_append_child(args,arg);

  name=tie_state_get_name(state);

  tie_append_child(arg,tie_create_identifier(name));
   }end_tie_program_foreach_state;

  tie_program_add(program,iclass);
}
/*********************************************************************
*******

                  产生WUR操作码
**********************************************************************
******/
static void
tie_program_generate_wur_iclass(tie_t *program)
{

  tie_t *iclass,*ilist, *args,*arg,*state;

  char *name;

  iclass=tie_alloc(TIE_ICLASS);

  tie_append_child(iclass,tie_create_identifier(″wur″));

  ilist=tie_alloc(TIE_INST_LIST);

  tie_append_child(iclass,ilist);

  tie_append_child(ilist,tie_create_identifier(″WUR″));

  args=tie_alloc(TIE_ARG_LIST);

  tie_append_child(iclass,args);

  arg=tie_alloc(TIE_RG_IN);

  tie_append_child(args,arg);

  tie_append_child(arg,tie_create_identifier(″art″));

  arg=tie_alloc(TIE_ARG_IN);

  tie_append_child(args,arg);

  tie_append_child(arg,tie_create_identifier(″sr″));

  args=tie_alloc(TIE_ARG_LIST);

  tie_append_child(iclass,args);

  tie_program_foreach_state(program,state){

  if(tie_get_predefined(state))continue;

  arg=tie_alloc(TIE_ARG_INOUT);

  tie_append_child(args,arg);

  name=tie_state_get_name(state);

  tie_append_child(arg,tie_create_identifier(name));
   }end_tie_program_foreach_state;
   tie_program_add(program,iclass);
}
				
				<dp n="d163"/>
/*********************************************************************
*******

               为每个ureg产生一组选择信号
**********************************************************************
******/
static void
tie_program_generate_selection_signals(tie_t *prog,tie_t *stmt,char
*fname)
{

  tie_t *ureg,*wire,*assign,*equal,*id;

  int index,max_index,width;

  char wname[80];

  max_index=0;

  tie_program_foreach_ureg(prog,ureg) {

   index=tie_ureg_get_index(ureg);

   max_index=MAX(max_index,index);

  } end_tie_program_foreach_ureg;

  width=(int)ceil(log(max_index+1)/log(2));

  tie_program_foreach_ureg(prog,ureg) {

   index=tie_ureg_get_index(ureg);

   wire=tie_alloc(TIE_WIRE);

   sprintf(wname,″ureg_sel_%d″,index);

   tie_append_child(wire,tie_create_integer(0));

   tie_append_child(wire,tie_create_integer(0));

   tie_append_child(wire,tie_create_identifier(wname));

   tie_append_child(stmt,wire);

   assign=tie_alloc(TIE_AssIGNMENT);

   tie_append_child(assign,tie_create_identifier(wname));

   tie_append_child(stmt,assign);

   equal=tie_alloc(TIE_EQ);

   sprintf(wname,″%d′d%d″,width,index);

   id=tie_create_identifier(fname);

   tie_append_child(id,tie_create_integer(width-1));

   tie_append_child(id,tie_create_integer(0));

   tie_append_child(equal,id);

   tie_append_child(equal,tie_create_constant(wname));

   tie_append_child(assign,equal);

  }end_tie_program_foreach_ureg;
}
/*********************************************************************
*******

           为“ureg”以及它前面的所有各ureg返回RUR选择逻辑
**********************************************************************
******/
static tie_t *
tie_program_rur_semantic_recur(ls_handle_t *ureg_handle)
{

  tie_t *and,*node,*or,*rep;
				
				<dp n="d164"/>
  node=tie_program_rur_semantic_recur(handle);

  tie_append_child(assign,node);

  ls_free(ureg_list);

  tie_program_add(program,semantic);
}
/*********************************************************************
*******

               将“ureg”的所有成员送进“列表”
**********************************************************************
*******/
static void
tie_ureg_exp_get_components(tie_t *exp,ls_t *list)
{

  tie_t *child;

  if(tie_get_type(exp)==TIE_ID){

    ls_prepend(list,exp);

  }

  tie_foreach_child(exp,child) {

    tie_ureg_exp_get_components(child,list);

  }end_tie_foreach_child;
}
/*********************************************************************
*******   

             取一份状态列表送往ur映射
**********************************************************************
******/
static void
tie_state_list_insert(ls_t *list,ureg_t *ur)
{

  ureg_t *item;

  ls_handle_t *handle;

  handle=0;

  ls_foreach_handle(list,handle) {

    item=(ureg_t *)ls_handle_get_data(handle);

    if(item->statef<ur->statet) {

       break;

    }

  }end_ls_foreach_handle;

  if (handle==0) {

    ls_append(list,ur);

  }else{

    ls_insert_before(handle,ur);

  }
}
/*********************************************************************
*******

                    取一份状态列表送往ur映射
				
				<dp n="d165"/>
  tie_t *ureg=(tie_t *) ls_handle_get_data(ureg_handle);

  ls_handle_t *ureg_next;

  char sname[80];

  and=tie_alloc{TIE_BITWISE_AND);
  rep=tie_alloc(TIE_REPLICATION);

  tie_append_child(and,rep);

  tie_append_child(rep,tie_create_integer(32));

  sprintf(sname,″ureg_sel_%d″,tie_ureg_get_index(ureg));

  tie_append_child(rep,tie_create_identifier(sname));

  tie_append_child(and,tie_dup(tie_ureg_get_expression(ureg)));

  ureg_next=ls_handle_get_next_handle(ureg_handle);

  if(ureg_next==0){

    return and;

  } else {

    node=tie_program_rur_semantic_recur(ureg_next);

    or=tie_alloc(TIE_BITWISE_OR);

    tie_append_child(or,and);

    tie_append_child(or,node);

    return or;

  }
}
/*********************************************************************
*******

               产生RUR语义块
**********************************************************************
******/
static void
tie_program_generate_rur_semantic(tie_t *program)
{

  tie_t *ureg,*semantic,*ilist,*statement,*assign,*node;

  ls_t *ureg_list;

  ls_handle_t *handle;

  semantic=tie_alloc(TIE_SEMANTIC);

  tie_append_child(semantic,tie_create_identifier(″rur″));

  ilist=tie_alloc(TIE_INST_LIST);

  tie_append_child(ilist,tie_create_identifier(″RUR″));

  tie_append_child(semantic,ilist);

  statement=tie_alloc(TIE_STATEMENT);

  tie_append_child(semantic,statement);

  tie_program_generate_selection_signals(program,statement,″st″);

  assign=tie_alloc(TIE_ASSIGNMENT);

  tie_append_child(statement,assign);

  tie_append_child(assign,tie_create_identifier(″arr″));

  ureg_list=ls_alloc();

  tie_program foreach_ureg(program,ureg){

   ls_append(ureg_list,ureg);

  } end_tie_program_foreach_ureg;

  handle=ls_get_first_handle(ureg_list);
				
				<dp n="d166"/>
**********************************************************************
******/
static void
tie_state_get_ur_mapping(tie_t *prog,tie_t *state,tie_t *ureg,ls_t
*list)
{

  tie_t *exp,*child,*s,*id;

  int num,uregf,uregt,statef,statet;

  ls_t *id_list;

  char *sname,*iname;

  ureg_t *ur;

  exp=tie_ureg_get_expression(ureg);

  num=tie_ureg_get_index(ureg);

  sname=tie_state_get_name(state);

  id_list=ls_alloc();

  tie_ureg_exp_get_components(exp,id_list);

  uregt=uregf=-1;

  ls_foreach_data(tie_t*,id_list,id){

    iname=tie_get_identifier(id);

    child=tie_get_first_child(id);

    /* compute the next uregf  and uregt */

    if(child==0){

       s=tie_program_get_state_by_name(prog,iname);

       ASSERT(s!=0);

       statet=0;

       statef=tie_state_get_width(s)-1;

   }else{

       statef=tie_get_integer(child);

       child=tie_get_next_sibling(child);

       if (child==0) {

        statet=statef;

      } else {

        statet=tie_get_integer(child);

     }

  }

  uregt=uregf+1;

  uregf=uregt+(statef-statet);

  if (strcmp(iname,sname)==0){

      ur=ALLOC(ureg_t,1);

      ur->statef=statef;

      ur->statet=statet;

      ur->uregf=uregf;

      ur->uregt=uregt;

      ur->ureg=num;

      ur->name=″art″;

      tie_state_list_insert(list,ur);

    }

  }end_ls_foreach_data;
}
				
				<dp n="d167"/>
/*********************************************************************
*******

               在state-to-ur映射表中填充空隙
**********************************************************************
******/
static void
tie_state_fill_gap(tie_t *state,ls_t *list)
{

  int width,statet,statef;

  ls_handle_t *handle;

  ureg_t *ur,*gap;

  char *name;
  width=tie_state_get_width(state);

  name=tie_state_get_name(state);

  statet=statef=width;

  ls_foreach_handle(list,handle){

    ur=(ureg_t *)ls_handle_get_data(handle);

    if(ur->statef<(statet-1)){

       gap=ALLOC(ureg_t,1);

       gap->statef=statet-1;

       gap->statet=ur->statef+1;

       gap->uregf=gap->uregt=gap->ureg=-1;

       gap->name=0;

       ls_insert_before(handle,gap);

   }

   statet=ur->statet;

   statef=ur->statef;

  }end_ls_foreach_handle;

  handle=ls_get_last_handle(list);

  ur=(ureg_t *)ls_handle_get_data(handle);

  if(ur->statet>0){

    gap=ALLOC(ureg_t,1);

    gap->statef=ur->statet-1;

    gap->statet=0;

    gap->uregf=gap->uregt=gap->ureg=-1;

    gap->name=0;

    ls_insert_after(handle,gap);

  }
}
/*********************************************************************
*******

               产生WUR语义块
**********************************************************************
******/
static void
tie_program_generate_wur_semantic(tie_t *program)
{    

  tie_t *ureg,*semantic,*ilist,*statement,*assign,*cond;

  tie_t *state,*concat,*id;

  ureg_t *ur;

  char *sname,selname[80];

  ls_t *list;
				
				<dp n="d168"/>
  semantic=tie_alloc(TIE_SEMANTIC);

  tie_append_child(program,semantic);

  tie_append_child(semantic,tie_create_identifier(″wur″));

  ilist=tie_alloc(TIE_INST_LIST);

  tie_append_child(ilist,tie_create_identifier(″WUR″));

  tie_append_child(semantic,ilist);

  statement=tie_alloc(TIE_STATEMENT);

  tie_append_child(semantic,statement);

  tie_program_generate_selection_signals(program,statement,″sr″);

  tie_program_foreach_state(program,state){

   if(tie_get_predefined(state))continue;

   sname=tie_state_get_name(state);

   list=ls_alloc();

   tie_program_foreach_ureg(program,ureg){

       tie_state_get_ur_mapping(program,state,ureg,list);

   }end_tie_program_foreach_ureg;

   tie_state_fill_gap(state,list);

   assign=tie_alloc(TIE_ASSIGNMENT);

   tie_append_child(statement,assign);

   tie_append_child(assign,tie_create_identifier(sname));

   concat=tie_alloc(TIE_CONCATENATION);

   tie_append_child(assign,concat);

   ls_foreach_data(ureg_t*,list,ur){

       if(ur->name!=0){

        cond=tie_alloc(TIE_CONDITIONAL);

        tie_append_child(concat,cond);

        sprintf(selname,″ureg_sel_%d″,ur->ureg);

        id=tie_create_identifier(selname);

        tie_append_child(cond,id);

        id=tie_create_identifier(ur->name);

        tie_append_child(id,tie_create_integer(ur->uregf));

        tie_append_child(id,tie_create_integer(ur->uregt));

        tie_append_child(cond,id);

        id=tie_create_identifier(sname);

        tie_append_child(id,tie_create_integer(ur->statef));

        tie_append_child(id,tie_create_integer(ur->statet));

        tie_append_child(cond,id);

       }else{

        id=tie_create_identifier(sname);

        tie_append_child(id,tie_create_integer(ur->statef));

        tie_append_child(id,tie_create_integer(ur->statet));

        tie_append_child(concat,id);

       }

    }end_ls_foreach_data;

    ls_free(list);

   }end_tie_program_foreach_state;
}
/*********************************************************************
*******

        产生WUR语义块
				
				<dp n="d169"/>
**********************************************************************
******/
void
tie_program_generate_rurwur(tie_t *program)
{

  tie_t *ureg ;

  int num=0;

  tie_program_foreach_ureg(program,ureg){

   num++;

  }end_tie_program_foreach_ureg;

  if(num==0){

   return;

  }

  tie_program_generate_st_field(program);

  tie_program_generate_rur_opcode(program);

  tie_program_generate_wur_opcode(program);

  tie_program_generate_rur_iclass(program);

  tie_program_generate_wur_iclass(program);

  tie_program_generate_rur_semantic(program);

  tie_program_generate_wur_semantic(program);
}
附件G
                                 150
// define a new opcode for BYTESWAP based on
//    -a predefined instruction field op2
//    -a predefined opcode CUST0
// refer to Xtensa ISA manual for descriptions of op2 and CUST0
opcode BYTESWAP op2=4′b0000 CUST0
// declare a state ACC used to accumulate byte-swapped data
state ACC  32
// declare a mode bit SWAP to control the swap
state SWAP 1
// use ″RUR ar,0″and″WUR ar,0″to move data between AR and ACC
user_register 0 ACC
// use″RUR ar,1″and″WUR ar,1″to move data between AR and SWAP
user_register 1 SWAP
// define a new instruction class that
//    -reads data from ars {predefined to be AR[s])
//    -uses and writes state ACC
//    -uses state SWAP
iclass bs {BYTESWAP}{in ars}{inout ACC,in SWAP}
// semantic definition of byteswap
//    Accumulates to ACC the byte-swapped ars (AR[s])or
//    ars depending on the SWAP bit
semantic bs {BYTESWAP}(

  wire [31:0] ars_swap={ars[7:0],ars[15:8],ars[23:16],ars[31:24]};

  assign ACC=ACC+(SWAP?ars_swap:ars);
}
附件H
#define PARAMS(_arg)_arg
typedef signed int int32_t;
typedef unsigned int u_int32_t;
typedef void* xtensa_isa;
typedef void* xtensa_operand;
typedef int xtensa_opcode;
#define XTENSA_UNDEFINED-1
typedef u_int32_t xtensa_insnbuf_word;
typedef xtensa_insnbuf_word *xtensa_insnbuf;
typedef enum(
  xtensa_encode_result_ok,
  xtensa_encode_result_align,
  xtensa_encode_result_not_in_table,
  xtensa_encode_result_too_low,
  xtensa_encode_result_too_high,
  xtensa_encode_result_not_ok
} xtensa_encode_result;
typedef u_int32_t(*xtensa_immed_decode_fn)PARAMS((u_int32_t val));
typedef xtensa_encode_result(*xtensa_immed_encode_fn)

   PARAMS((u_int32_t *valp));
typedef u_int32_t(*xtensa_get_field_fn)PARAMS((const xtensa_insnbuf
insn));
typedef void(*xtensa_set_field_fn)PARAMS((xtensa_insnbuf insn,

                              u_int32_t val));
typedef int(*xtensa_insn_decode_fn)PARAMS((const xtensa_insnbuf
insn));
typedef struct xtensa_operand_internal_struct{
  char operand_kind;
  char inout;
  xtensa_get_field_fn get_field;
  xtensa_set_field_fn set_field;
  xtensa_immed_encode_fn encode;
  xtensa_immed_decode_fn decode;
} xtensa_operand_internal;
typedef struct xtensa_iclass_internal_struct{
  int num_operands;
  xtensa_operand_internal **operands;
} xtensa_iclass_internal;
typedef struct xtensa_opcode_internal_struct{
  const char *name;
  int length;
  xtensa_insnbuf encoding_template;
				
				<dp n="d174"/>
 xtensa_iclass_internal *iclass;
}xtensa_opcode_internal;
typedef struct opname_lookup_entry_struct{
  const char *key;
  xtensa_opcode opcode;
}opname_lookup_entry;
typedef struct xtensa_isa_internal_struct{

  int insn_size;

  int insnbuf_size;

  int num_opcodes;

  xtensa_opcode_internal **opcode_table;

  int num_modules;

  int *module_opcode_base;

  xtensa_insn_decode_fn *module_decode_fn;

  opname_lookup_entry *opname_lookup_table;
}xtensa_isa_internal;
extern u_int32_t get_r_field(const xtensa_insnbuf insn);
extern void set_r_field(xtensa_insnbuf insn,u_int32_t val);
extern u_int32_t get_s_field(const xtensa_insnbuf insn);
extern void set_s_field(xtensa_insnbuf insn,u_int32_t val);
extern u_int32_t get_sr_field(const xtensa_insnbuf insn);
extern void set_sr_field(xtensa_insnbuf insn,u_int32_t val);
extern u_int32_t get_t_field(const xtensa_insnbuf insn);
extern void set_t_field(xtensa_insnbuf insn,u_int32_t val);
extern xtensa_encode_result encode_r(u_int32_t *valp);
extern u_int32_t decode_r(u_int32_t val);
extern xtensa_encode_result encode_s(u_int32_t *valp);
extern u_int32_t decode_s(u_int32_t val);
extern xtensa_encode_result encode_sr(u_int32_t *valp);
extern u_int32_t decode_sr(u_int32_t val);
extern xtensa_encode_result encode_t(u_int32_t *valp);
extern u_int32_t decode_t(u_int32_t val);
static u_int32_t get_st_field(insn)
const xtensa_insnbuf insn;
{
u_int32_t temp;
temp=0;
temp|=((insn[0] &amp; 0xf00)>>8)<<4;
temp|=((insn[0] &amp; 0xf0)>>4)<<0;
return temp;
}
static void set_st_field (insn,val)
xtensa_insnbuf insn;u_int32_t val;
{
insn[0]=(insn[0] &amp; 0xfffff0ff)|((val &amp; 0xf0)<<8);
insn[0]=(insn[0] &amp; 0xffffff0f)|((val &amp; 0xf)<<4);
}
static u_int32_t decode_st (u_int32_t val)
{
				
				<dp n="d175"/>
  return val;
}
static xtensa_encode_result encode_st(u_int32_t *valp)
{

  if((*valp>>8)!=0){

  return xtensa_encode_result_too_high;

  }else{

  return xtensa_encode_result_ok;

  }
}
static xtensa_operand_internal aor_operand={

  ′a′,

  ′>′,

  get_r_field,

  set_r_field,

  encode_r,

  decode_r
};
static xtensa_operand_internal ais_operand={

  ′a′,

  ′<′,

  get_s_field,

  set_s_field,

  encode_s,

  decode_s
};
static xtensa_operand_internal ait_operand={

  ′a′,

  ′<′,

  get_t_field,

  set_t_field,

  encode_t,

  decode_t
};
static xtensa_operand_internal iisr_operand={

  ′i′,

  ′<′,

  get_sr_field,

  set_sr_field,

  encode_sr,

  decode_sr
};
static xtensa_operand_internal iist_operand={

  ′i′,

  ′<′,

  get_st_field,

  set_st_field,

  encode_st,

  decode_st
};
				
				<dp n="d176"/>
static xtensa_operand_internal *bs_operand_list[]={

  &amp;ais_operand
};
static xtensa_iclass_internal bs_iclass={

  1,

  &amp;bs_operand_list[0]
};
static xtensa_operand_internal *rur_operand_list[]={

  &amp;aor_operand,

  &amp;iist_operand
};
static xtensa_iclass_internal rur_iclass={

  2,

  &amp;rur_operand_list[0]
};
static xtensa_operand_internal *wur_operand_list[]={

  &amp;ait_operand,

  &amp;iisr_operand
};
static xtensa_iclass_internal wur_iclass={

  2,

  &amp;wur_operand_list[0]
};
static xtensa_insnbuf_word BYTESWAP_template[]={0x60000};
static xtensa_opcode_internal BYTESWAP_opcode={

  ″byteswap″,

  3,

  &amp;BYTESWAP_template[0],

  &amp;bs_iclass
};
static xtensa_insnbuf_word RUR_template[]={0xe30000};
static xtensa_opcode_internal RUR_opcode={

  ″rur″,

  3,

  &amp;RUR_template[0],

  &amp;rur_iclass
};
static xtensa_insnbuf_word WUR_template[]={0xf30000};
static xtensa_opcode_internal WUR_opcode={

  ″wur″,

  3,

  &amp;WUR_template[0],

  &amp;wur_iclass
};
static xtensa_opcode_internal * opcodes[]={

  &amp;BYTESWAP_opcode,
				
				<dp n="d177"/>
  &amp;RUR_opcode,

  &amp;WUR_opcode
};
xtensa_opcode_internal ** get_opcodes(){return &amp;opcodes[0];}
const int get_num_opcodes(){return 3;}
#define xtensa_BYTESWAP_op 0
#define xtensa_RUR_op 1
#define xtensa_WUR_op 2
int decode_insn(const xtensa_insnbuf insn)
{
if((insn[0] &amp; 0xff000f)==0x60000)return xtensa_BYTESWAP_op;
if((insn[0] &amp; 0xff000f)==0xe30000)return xtensa_RUR_op;
if((insn[0] &amp; 0xff000f)==0xf30000)return xtensa_WUR_op;
return XTENSA_UNDEFINED;
}
附件I
typedef unsigned u32;
typedef struct u64str{unsigned int lo;unsigned int hi;}u64;
extern u32 state32(int i);
extern u64 state64(int i);
extern void    set_state32(int i,u32 v);
extern void    set_state64(int i,u64 v);
extern void    set_ar(int i,u32 v);
extern u32 ar(int i);
extern void    pc_incr(int i);
extern int aux32_fetchfirst(void);
extern void    pipe_use_ifetch(int n);
extern void    pipe_use_dcache(void);
extern void    pipe_def_ifetch(int n);
extern int arcode(void);
extern void    pipe_use(int n,int v,int i);
extern void    pipe_def(int n,int v,int i);
struct state_tbl_entry{

  const char *name;

  int numbits;
};
#define STATE_ACC     0
#define STATE_SWAP    1
#define NUM_STATES    2
struct state_tbl_entry local_state_tbl[NUM_STATES+1]={

  {″ACC″,32},

  {″SWAP″,1},

  {″″,0}
};
extern ″C″struct state_tbl_entry *get_state_tbl(void);
struct state_tpl_entry *get_state_tbl(void)
{

  return &amp;local_state_tbl[0];
}
/* constant table ai4const */
static const unsigned CONST_TBL_AI4CONST[]={

  0xffffffff,

  0x1,

  0x2,

  0x3,

  0x4,

  0x5,

  0x6,

  0x7,

  0x8,

  0x9,

  0xa,

  0xb,

  0xc,

  0xd,

  0xe,
				
				<dp n="d180"/>
  0xf
};
/* constant table b4const */
static const unsigned CONST_TBL_B4CONST[]={

  0xffffffff,

  0x1,

  0x2,

  0x3,

  0x4,

  0x5,

  0x6,

  0x7,

  0x8,

  0xa,

  0xc,

  0x10,

  0x20,

  0x40,

  0x80,

  0x100
};
/* constant table b4constu */
static const unsigned CONST_TBL_B4CONSTU[]={

  0x8000,

  0x10000,

  0x2,

  0x3,

  0x4,

  0x5,

  0x6,

  0x7,

  0x8,

  0xa,

  0xc,

  0x10,

  0x20,

  0x40,

  0x80,

  0x100
};
/* constant table d01tab */
static const unsigned CONST_TBL_D01TAB[]={

  0,

  0x1
};
/* constant table d23tab */
static const unsigned CONST_TBL_D23TAB[]={

  0x2,

  0x3
};
/* constant table i4plconst */
				
				<dp n="d181"/>
static const unsigned CONST_TBL_I4P1CONST[]={

  0x1,

  0x2,

  0x3,

  0x4,

  0x5,

  0x6,

  0x7,

  0x8,

  0x9,

  0xa,

  0xb,

  0xc,

  0xd,

  0xe,

  0xf,

  0x10
};
/* constant table mip32const */
static const unsigned CONST_TBL_MIP32CONST[]={

  0x20,

  0x1f,

  0x1e,

  0x1d,

  0x1c,

  0x1b,

  0x1a,

  0x19,

  0x18,

  0x17,

  0x16,

  0x15,

  0x14,

  0x13,

  0x12,

  0x11,

  0x10,

  0xf,

  0xe,

  0xd,

  0xc,

  0xb,

  0xa,

  0x9,

  0x8,

  0x7,

  0x6,

  0x5,

  0x4,

  0x3,

  0x2,

  0x1
};
void
				
				<dp n="d182"/>
BYTESWAP_func(u32_OPND0_,u32_OPND1_,u32_OPND2_,u32_OPND3_)
{
unsigned ars=ar(_OPND0_);
u32 ACC=state32(STATE_ACC);
u32 SWAP=state32(STATE_SWAP);
unsigned_tmp0;
unsigned SWAP_ps;
unsigned ACC_ps;
unsigned ACC_ns;
unsigned ars_swap;
SWAP_ps=SWAP;
ACC_ps=ACC;
ars_swap=(((ars &amp; 0xff))<<24)|((((ars>>8) &amp; 0xff))<<
16)|((((ars>>16) &amp; 0xff))<<8)|(((ars>>24) &amp; 0xff));
if(SWAP_ps){
_tmp0=ars_swap;
}else{
_tmp0=ars;
}
ACC_ns=ACC_ps+_tmp0;
ACC=ACC_ns;
set_state32(STATE_ACC,ACC);
pc_incr(3);
}
void
RUR_func(u32_OPND0_,u32_OPND1_,u32_OPND2_,u32_OPND3_)
{
unsigned arr;
unsigned st=_OPND1_;
u32 ACC=state32(STATE_ACC);
u32 SWAP=state32(STATE_SWAP);
unsigned_tmp1;
unsigned_tmp0;
unsigned SWAP_ps;
unsigned ACC_ps;
SWAP_ps=SWAP;
ACC_ps==ACC;
if(st==1){
_tmp0=SWAP_ps;
}else{
_tmp0=0;
}
if(st==0){
_tmp1=ACC_ps;
}else{
_tmp1=_tmp0;
}
arr=_tmp1;
set_ar(_OPND0_,arr);
pc_incr(3);
}
void
WUR_func(u32_OPND0_,u32_OPND1_,u32_OPND2_,u32_OPND3_)
{
				
				<dp n="d183"/>
unsigned art=ar(_OPND0_);
unsigned sr=_OPND1_;
u32 ACC=state32(STATE_ACC);
u32 SWAP=state32(STATE_SWAP);
unsigned_tmp1;
unsigned_tmp0;
unsigned SWAP_ps;
unsigned ACC_ps;
unsigned SWAP_ns;
unsigned ACC_ns;
unsigned ureg_sel_0;
unsigned ureg_sel_1;
SWAP_ps=SWAP;
ACC_ps=ACC;
ureg_sel_0=sr==0;
ureg_sel_1=sr==1;
if(ureg_sel_0){
_tmp0=art;
}else{
_tmp0=ACC_ps;
}
ACC_ns=_tmp0;
if(ureg_sel_1){
_tmp1=(art &amp; 0x1);
}else{
_tmp1=(SWAP_ps &amp; 0x1);
}
SWAP_ns=_tmp1;
ACC=ACC_ns;
SWAP=SWAP_ns;
set_state32(STATE_ACC,ACC);
set_state32(STATE_SWAP,SWAP);
pc_incr(3);
}
void BYTESWAP_sched (u32 op0,u32 op1,u32 op2,u32 op3)
{

    int ff;

  int cond;

  ff=aux32_fetchfirst();

  if (ff) {

    pipe_use_ifetch (3);
  }
  pipe_use(arcode(),op0,1);
  if(!ff){

    pipe_use_ifetch (3);
  }
  pipe_use_dcache ();
  pipe_def_ifetch (-1);
}
void RUR_sched(u32 op0,u32 op1,u32 op2,u32 op3)
{

  int ff;

  int cond;

  ff=aux32 fetchfirst();
				
				<dp n="d184"/>
  if(ff){

  pipe_use_ifetch (3);
  }
  if(!ff){

  pipe_use_ifetch (3);
  }
  pipe_use_dcache ();
  pipe_def (arcode(),op0,2);
  pipe_def_ifetch(-1);
}
void WUR_sched(u32 op0,u32 op1,u32 op2,u32 op3)
{
  int ff;
  int cond;
  ff=aux32 fetchfirst();
  if(ff){

  pipe_use_ifetch (3);
  }
  pipe_use(arcode(),op0,1);
  if(!ff){

  pipe_use_ifetch (3);
  }
  pipe_use_dcache ();
  pipe_def_ifetch (-1);
}
typedef void (SEMFUNC)(u32_OPND0_,u32_OPND1_,u32_OPND2,u32
_OPND3_);
struct isafunc_tbl_entry {

  const char *opname;

  SEMFUNC *semfn;

  SEMFUNC *schedfn;
};
static struct isafunc_tbl_entry local_fptr_tbl[]={

  {″byteswap″,BYTESWAP_func,BYTESWAP_sched},

  {″rur″,RUR_func,RUR_sched},

  {″wur″,WUR_func,WUR_sched},

  {″″,0,0}
};
extern″C″struct isafunc_tbl_entry  *get_isafunc_tbl (void);
struct isafunc_tbl_entry *get_isafunc_tbl (void)
{

  return &amp;local_fptr_tbl[0];
}
附件J
/*不要进行修改。这是自动产生的。
#define BYTESWA
				
				<dp n="d187"/>
P(ars)\

  ({asm volatile(″BYTESWAP %0″::″a″(ars));})
#define RUR(st) \

  ({int arr;asm volatile(″RUR %0,%1″:″=a″(arr):″i″(st));
arr;})
#define WUR(art,sr) \

           ({asm volatile(″WUR%0,%l″::″a″(art),″i″(sr))
附件K
#ifdef TIE_DEBUG
#define BYTESWAP TIE_BYTESWAP
#define RUR TIE_RUR
#define WUR TIE_WUR
#endif
typedef unsigned u32;
#define STATE32_ACC   0
#define STATE_ACC     STATE32_ACC
#define STATE32_SWAP  1
#define STATE_SWAP    STATE32_SWAP
#define NUM_STATE32   2
static u32 state32_table[NUM_STATE32];
static char *state32_name_table[NUM_STATE32]={

  ″ACC″,

  ″SWAP″
};
static u32 state32(int rn) {return state32_table{rn];}
static void     set_state32(int rn,u32 s) {state32_table[rn]=s;}
static int num_state32(void) {return NUM_STATE32;}
static char*  state32_name(int rn) {return state32_name_table[rn];)
void
BYTESWAP(unsigned ars)
{
u32 ACC=state32(STATE_ACC);
u32 SWAP=state32(STATE_SWAP);
unsigned _tmp0;
unsigned SWAP_ps;
unsigned ACC_ps;
unsigned ACC_ns;
unsigned ars_swap;
SWAP_ps=SWAP;
ACC_ps=ACC;
ars_swap=(((ars &amp; 0xff)) <<24)|((((ars>>8) &amp; 0xff)) <<
16)|((((ars>>16) &amp; 0xff)) <<8)|(((ars>>24) &amp; 0xff));
if(SWAP_ps){
_tmp0=ars_swap;
} else {
_tmp0=ars;
}
ACC_ns=ACC_ps+_tmp0;
ACC=ACC_ns;
set_state32(STATE_ACC,ACC);
}
unsigned
RUR(unsigned st)
{
unsigned arr;
u32 ACC=state32(STATE_ACC);
u32 SWAP=state32(STATE_SWAP);
unsigned_tmp1;
unsigned_tmp0;
				
				<dp n="d190"/>
unsigned SWAP_ps;
unsigned ACC_ps;
SWAP_ps=SWAP;
ACC_ps=ACC;
if (st==1) {
_tmp0=SWAP_ps;
}else{
_tmp0=0;
}
if(st==0){
_tmpl=ACC_ps;
}else{
_tmp1=_tmp0;
}
arr=tmp1;
return arr;
}
void
WUR(unsigned art,unsigned sr)
{
u32 ACC=state32(STATE ACC);
u32 SWAP=state32(STATE_SWAP);
unsigned _tmp1;
unsigned _tmp0;
unsigned SWAP_ps;
unsigned ACC_ps;
unsigned SWAP_ns;
unsigned ACC_ns;
unsigned ureg_sel_0;
unsigned ureg_sel_1;
SWAP_ps=SWAP;
ACC_ps=ACC;
ureg_sel_0=sr==0;
ureg_sel_1=sr==1;
if(ureg_sel_0){
_tmp0=art;
}else{
_tmp0=ACC_ps;
}
ACC_ns=_tmp0;
if(ureg_sel_1){
_tmp1=(art &amp; 0x1);
}else{
_tmp1=(SWAP_ps &amp; 0x1);
}
SWAP_ns=_tmp1;
ACC=ACC_ns;
SWAP=SWAP_ns;
set_state32(STATE_ACC,ACC);
set_state32(STATE_SWAP,SWAP);
}
#ifdef TIE_DEBUG
#undef BYTESWAP
#undef RUR
				
				<dp n="d191"/>
#undef WUR
#endif
附件L
// Do not modify this automatically generated file.
module tie_enflop(tie_out,tie_in,en,clk);
parameter size=32;
output[size-1:0]tie_out;
input[size-1:0]tie_in;
input           en;
input           clk;
reg[size-1:0]  tmp;
assign tie_out=tmp;
always @ (posedge clk)begin

  if (en)

    tmp<=#1 tie_in;
end
endmodule
module tie_flop(tie_out,tie_in,clk);
parameter size=32;
output[size-1:0]tie_out;
input[size-1:0]tie_in;
input           clk;
reg[size-1:0]  tmp;
assign tie_out=tmp;
always @ (posedge clk)begin
  tmp<=#1 tie_in;
end
endmodule
module tie_athens_state(ns,we,ke,kp,vw,clk,ps);
parameter size=32;
input [size-1:0] ns;//next state
input we;        //write enable
input ke;        //Kill E state
input kp;        //Kill Pipeline
input vw;        //Valid W state
input clk;       //clock
output [size-1:0] ps;//present state
wire   [size-1:0] se;//state at E stage
wire   [size-1:0] sm;//state at M stage
wire   [size-1:0] sw;//state at W stage
wire   [size-1:0] sx;//state at X stage
wire   ee;        //  write enable for EM register
wire   ew;        //  write enable for WX register
assign se=kp?sx :ns;
assign ee=kp|we &amp; ~ke;
assign ew=vw &amp;~kp;
assign ps=sm;
tie_enflop #(size)state_EM(.tie_out(sm),.tie_in(se),.en(ee),
.clk(clk));
tie_flop #(size)state_MW(.tie_out(sw),.tie_in(sm),.clk(clk));
tie_enflop #(size)state_WX(.tie_out(sx),.tie_in(sw),.en(ew),
.clk(clk));
endmodule
				
				<dp n="d194"/>
module bs (ars,ACC_ps,SWAP_ps,ACC_ns,ACC_we,BYTESWAP);
input[31:0]ars;
input[31:0]ACC_ps;
input[0:0]SWAP_ps;
output[31:0]ACC_ns;
output ACC_we;
input BYTESWAP;
wire[31:0]ars_swap;
assign ars_swap={ars[7:0],ars[15:8],ars[23:16],ars[31:24]};
assign ACC_ns=(ACC_ps)+((SWAP_ps)?(ars_swap):(ars));
assign ACC_we=1′b1 &amp; BYTESWAP;
endmodule
module rur(arr,st,ACC_ps,SWAP_ps,RUR);
output[31:0]arr;
input[31:0]st;
input[31:0]ACC_ps;
input[0:0]SWAP_ps;
input RUR;
assign arr=((st)==(8′d0))?(ACC_ps):(((st)==(8′d1))?
(SWAP_ps):(32 ′b0));
endmodule
module wur (art,sr,ACC_ps,SWAP_ps,ACC_ns,ACC_we,SWAP_ns,SWAP_we,WUR);
input[31:0]art;
input[31:0]sr;
input[31:0]ACC_ps;
input[0:0]SWAP_ps;
output[31:0]ACC_ns;
output ACC_we;
output[0:0]SWAP_ns;
output  SWAP_we;
input WUR;
wire ureg_sel_0;
assign ureg_sel_0=(sr)==(8′h0);
wire  ureg_sel_1;
assign ureg_sel_1=(sr)==(8′h1);
assign ACC_ns={(ureg_sel_0)?(art[31:0]):(ACC_ps[31:0])};
assign SWAP_ns={(ureg_sel_1)?(art[0:0]):(SWAP_ps[0:0])};
assign ACC_we=1′b1 &amp; WUR;
assign SWAP_we=1′b1 &amp; WUR;
endmodule
module UserInstModule(clk,out_E,ars_E,art_E,inst_R,Kill_E,
killPipe_W,valid_W,BYTESWAP_R,RUR_R,WUR_R,en_R);
input clk;
output[31:0]out_E;
input[31:0]ars_E;
input[31:0]art_E;
input[23:0]inst_R;
input en_R;
input Kill_E,killPipe_W,valid_W;
input BYTESWAP_R;
input RUR_R;
input WUR_R;
				
				<dp n="d195"/>
wire BYTESWAP_E;
wire RUR_E;
wire WUR_E;
wire [31:0]arr_E;
wire [31:0]sr_R,sr_E;
wire [31:0]st_R,st_E;
wire [31:0]ACC_ps,ACC_ns;
wire ACC_we;
wire [0:0]SWAP_ps,SWAP_ns;
wire SWAP_we;
wire [31:0]bs_ACC_ns;
wire bs_ACC_we;
wire bs_select;
wire [31:0]rur_arr;
wire rur_select;
wire [31:0]wur_ACC_ns ;
wire wur_ACC_we;
wire [0:0]wur_SWAP_ns;
wire wur_SWAP_we;
wire wur_select;
tie_enflop #(1) fBYTESWAP(.tie_out(BYTESWAP_E),.tie_in(BYTESWAP_R),
.en(en R),.clk(clk));
tie_enflop #(1) fRUR(.tie_out(RUR_E),.tie_in(RUR_R),.en(en_R),
.clk(clk));
tie_enflop #(1) fWUR(.tie_out(WUR_E),.tie_in(WUR_R),.en(en_R),
.clk(clk));
assign sr_R={{inst_R[11:8]},{inst_R[15:12]}};
tie_enflop #(32) fsr (.tie_out(sr_E),.tie_in(sr_R),.en(en_R),
.clk(clk));
assign st_R={{inst_R[11:8]},{inst_R[7:4]}};
tie_enflop #(32) fst(.tie_out(st_E),.tie_in(st_R),.en(en_R),
.clk(clk));
bs ibs(

  .ars(ars_E),

  .ACC_ps(ACC_ps),

  .SWAP_ps(SWAP_ps),

  .ACC_ns(bs_ACC_ns),

  .ACC_we(bs_ACC_we),

  .BYTESWAP(BYTESWAP_E));
rur irur(

  .arr(rur_arr),

  .st(st_E),

  .ACC_ps(ACC_ps),

  .SWAP_ps(SWAP_ps),

  .RUR(RUR_E));
wur iwur(

  .art(art_E),

  .sr(sr_E),

  .ACC_ps(ACC_ps),

  .SWAP_ps(SWAP_ps),

  .ACC_ns(wur_ACC_ns),

  .ACC_we(wur_ACC_we),

  .SWAP_ns(wur_SWAP_ns),

  .SWAP_we(wur_SWAP_we),

  .WUR(WUR_E));
tie athens state # (32) iACC(
				
				<dp n="d196"/>
  .ns(ACC_ns),

  .we(ACC_we),

  .ke(Kill_E),

  .kp(killPipe_W),

  .vw(valid_W),

  .clk(clk),
  .ps(ACC_ps));
tie_athens_state #(1) iSWAP(

  .ns(SWAP_ns),

  .we(SWAP_we),

  .ke(Kill_E),

  .kp(killPipe_W),

  .vw(valid_W),

  .clk(clk),

  .ps(SWAP_ps));
assign bs_select=BYTESWAP_E;
assign rur_select=RUR_E;
assign wur_select=WUR_E;
assign arr_E={32{1′b0}} &amp; {32{bs_select}}

  |rur_arr &amp; {32{rur_select}}

  |{32{1′b0}} &amp; {32{wur_select}};
assign out_E=arr_E;
assign ACC_ns=bs_ACC_ns &amp; {32{bs_select}}

  |{32{1′b0}} &amp; {32{rur_select}}

  |wur_ACC_ns  &amp; {32{wur_select}};
assign ACC_we=bs_ACC_we &amp; bs_select

  |1′b0 &amp; rur_select

  |wur_ACC_we &amp; wur_select;
assign SWAP_ns={1{1′b0}} &amp; {1{bs_select}}

  |{1{1′b0}} &amp; {1{rur_select}}

  |wur_SWAP_ns &amp; {1{wur_select}};
assign SWAP_we=1′b0 &amp; bs_select

  |1′b0 &amp; rur_select

  |wur_SWAP_we &amp; wur_select;
endmodule
附件M
/*********************************************************************
**

         您需要为这个部分填入必要的信息
**********************************************************************
*/
/* Set the search path to include the library directories */
SYNOPSYS=get_unix_variable(″SYNOPSYS″)
search_path=SYNOPSYS + /libraries/syn
/* Set the path and name of target library */
search_path=<...> + search_path
target_library=<name of the library>
/* Constraint information */
OPERATING_CONDITION=<name of the operating condition>
WIRE_LOAD=<name of the wire-load model>
BOUNDARY_LOAD=<library name>/<smallest inverter name>/<input pin
name>
DRIVE_CELL=<a large FF name>
DRIVE_PIN=<Q pin name of the FF>
DRIVE_PIN_FROM=<clock pin name of the FF>
/* target processor clock period */
CLOCK_PERIOD=<target clock period>
/*********************************************************************
**

               下面您不需要作出任何更改
**********************************************************************
*/
link_library={″*″}+target_library
symbol_library=generic.sdb
/* prepare workdir for hdl compiler */
hdlin_auto_save_templates=″TRUE″
define_design_lib WORK-path workdir
sh mkdir-p workdir
read -f verilog./prim.v
read -f verilog./ROOT.v
current_design UserInstModule
link
set_operating_conditions OPERATING_CONDITION
set_wire_load WIRE_LOAD
create_clock clk-period CLOCK_PERIOD
set_dont_touch_network clk
set_load{2 * load_of(BOUNDARY_LOAD)}all_outputs()
set_load{2 * load_of(BOUNDARY_LOAD)}all_inputs()
set_driving_cell-cell DRIVE_CELL -pin DRIVE_PIN -from_pin
DRIVE_PIN_FROM all_inputs()
				
				<dp n="d199"/>
set_max_delay 0.5 * CLOCK_PERIOD-from all_inputs()-to find(clock,
clk)
set_max_delay 0.5 * CLOCK_PERIOD-from find(clock,clk)-to
all_outputs()    
set_max_delay 0.5 * CLOCK_PERIOD-from all_inputs()-to all_outputs()
set_drive-rise 0 clk
set_drive-fall 0 clk
compile-ungroup_all
report_timing
report_constraint-all_viol
report_area

Claims (137)

1.一个用于设计可配置处理器的系统,该系统包括:
用于基于配置说明而产生处理器的硬件实施方案的描述的装置;以及
用于基于配置说明而产生该硬件实施方案专用的软件开发工具的装置。
2.根据权利要求1所述的系统,其中,用于产生软件开发工具的装置包括能产生运行于该处理器之上的代码的软件开发工具的装置。
3.根据权利要求1所述的系统,其中,软件开发工具包括一段编译程序,它适合于该配置说明,用于将一段应用程序编译为可以由处理器执行的代码。
4.根据权利要求1所述的系统,其中,软件开发工具包括一段汇编程序,它适应于配置说明,用于将一段应用程序汇编为可以由处理器执行的代码。
5.根据权利要求1所述的系统,其中,软件开发工具包括一段连接程序,它适应于配置说明,用于连接可以由处理器执行的代码。
6.根据权利要求1所述的系统,其中,软件开发工具包括一段反编译程序,它适应于配置说明,用于对可以由处理器执行的代码进行反汇编。
7.根据权利要求1所述的系统,其中,软件开发工具包括一段调试程序,它适应于配置说明,用于对可以由处理器执行的代码进行调试。
8.根据权利要求7所述的系统,其中,调试程序具有一个公共接口和配置,用于指令集仿真程序和硬件实施方案。
9.根据权利要求1所述的系统,其中,软件开发工具包括一段指令集仿真程序,它适应于配置说明,用于对可以由处理器执行的代码进行仿真。
10.根据权利要求9所述的系统,其中,指令集仿真程序能够模拟被仿真的代码的执行,用以测量包括执行的周期数在内的重要的性能规范。
11.根据权利要求10所述的系统,其中,性能规范基于特定的可配置的微体系结构的各项特征。
12.根据权利要求10所述的系统,其中,指令集仿真程序能够跟踪被仿真的程序的执行,以记录标准的跟踪统计特性,包括在每一种被仿真的函数中所执行的周期的数目。
13.根据权利要求1所述的系统,其中,硬件实施方案描述包括下列各项中的至少一项:详细的HDL硬件实施方案描述;合成稿本;布局和布线稿本;可编程逻辑器件稿本;测试台;用于验证的诊断测试;在一段仿真程序上运行诊断测试程序的稿本;以及各种测试工具。
14.根据权利要求1所述的系统,其中,用于产生硬件实施方案的装置包括:
用于从配置说明产生硬件实施方案描述的硬件描述语言说明的装置;
基于硬件描述语言说明,用于合成针对硬件实施方案的逻辑的装置;以及
基于已合成的逻辑,用于在一块芯片上对各元件进行布局与布线以形成一种电路的装置。
15.根据权利要求14所述的系统,其中,用于产生硬件实施方案描述的装置还包括:
用于验证电路的定时的装置;以及
用于确定电路的面积、周期时间和功耗的装置。
16.根据权利要求1所述的系统还包括用于产生配置说明的装置。
17.根据权利要求16所述的系统,其中,用于产生配置说明的装置对用户作出的各项配置参数的选择作出响应。
18.根据权利要求16所述的系统,其中,用于产生配置说明的装置用于产生基于处理器设计目标的说明。
19.根据权利要求1所述的系统,其中,配置说明包括处理器的一种可修改的特性的至少一项参数说明。
20.根据权利要求19所述的系统,其中,至少一项参数说明指定纳入一个功能单元,并且指定至少一条运行该功能单元的处理器指令。
21.根据权利要求19所述的系统,其中,至少一项参数说明指定影响处理器状态的一种结构的纳入、排除和特征这3者当中的一种。
22.根据权利要求21所述的系统,其中,结构是一个寄存器文件,并且参数说明指定在该寄存器文件中寄存器的数目。
23.根据权利要求21所述的系统,其中,结构是一个指令高速缓冲存储器。
24.根据权利要求21所述的系统,其中,结构是一个数据高速缓冲存储器。
25.根据权利要求21所述的系统,其中,结构是一个写入缓冲存储器。
26.根据权利要求21所述的系统,其中,结构是在芯片上的ROM和在芯片上的RAM二者当中的一种。
27.根据权利要求19所述的系统,其中,至少一项参数说明指定一种语义特性,它控制着在处理器中数据与指令二者当中至少一种的解释。
28.根据权利要求19所述的系统,其中,至少一项参数说明指定一种执行特性,它控制着在处理器中的各项指令的执行。
29.根据权利要求19所述的系统,其中,至少一项参数说明指定处理器的调试特性。
30.根据权利要求19所述的系统,其中,配置说明包括一项参数说明,它指定从预定特征;处理器元件的尺寸或数目;以及数值的赋予三者当中,至少选择其中一种。
31.根据权利要求1所述的系统还包括用于评估配置说明的适用性的装置。
32.根据权利要求31所述的系统,其中,用于评估的装置包括一种交互式评估工具。
33.根据权利要求31所述的系统,其中,用于评估的装置是用来评价由配置说明描述的处理器的硬件特性。
34.根据权利要求31所述的系统,其中,用于评估的装置是用来根据处理器的已评估的性能特性来评价配置说明的适用性。
35.根据权利要求34所述的系统还包括用于提供信息的装置,它根据已评估的性能特性来进行配置说明的修改。
36.根据权利要求34所述的系统,其中,性能特性包括为在一块芯片上实现该处理器所需的面积,处理器所消耗的功率以及处理器的时钟速度三者当中的至少一种。
37.根据权利要求31所述的系统,其中,用于评估的装置是用来根据处理器的已评估的软件特性来评价配置说明的适用性。
38.根据权利要求37所述的系统,其中,用于评估的装置通过在由配置说明所描述的处理器上执行一套基准测试程序,从中对所需的代码大小和周期数二者至少其中之一作出评估,从而交互式地向用户提供一种适用性评价。
39.根据权利要求31所述的系统,其中,用于评估的装置对由配置说明所描述的处理器的各项硬件特性和各项软件特性作出评价。
40.根据权利要求1所述的系统,其中,用于产生的装置还同时提供硬件的性能与成本以及软件应用性能的特性,以便对配置说明进行修改。
41.根据权利要求1所述的系统,其中,用于产生的装置还同时提供硬件的性能与成本以及软件应用性能的特性,以便对配置说明进行扩展。
42.根据权利要求1所述的系统,其中,用于产生的装置还同时提供硬件的性能与成本以及软件应用性能的特性,以便对配置说明进行修改,还同时提供硬件的性能与成本以及软件应用性能的特性,以便对配置说明的扩展进行描述。
43.根据权利要求1所述的系统还包括通过扩展,用于生成处理器的一种配置的装置。
44.根据权利要求1所述的系统,其中,配置说明包括处理器的一项可扩展特性的至少一项扩展说明。
45.根据权利要求44所述的系统,其中,扩展说明指定一条附加的指令。
46.根据权利要求44所述的系统,其中,扩展说明指定纳入一条用户定义的指令,以及针对该指令的一种实施方案。
47.根据权利要求46所述的系统,其中,用于产生软件开发工具的装置包括向用户建议适于至少一种应用的可能的用户定义指令的装置。
48.根据权利要求46所述的系统,其中,软件开发工具包括一段能产生用户定义指令的编译程序。
49.根据权利要求48所述的系统,其中,编译程序能够优化含有用户定义指令的代码。
50.根据权利要求46所述的系统,其中,软件开发工具包括下列3项中的至少一项:能产生用户定义指令的汇编程序;能够仿真使用用户定义指令的用户代码的执行情况的仿真程序;以及能够验证用户定义指令的用户实施方案的各种工具。
51.根据权利要求45所述的系统,其中,编译程序能够自动地产生各项附加的指令。
52.根据权利要求44所述的系统,其中:
扩展说明指定一种新的特征,该特征具有基本上由用户以抽象形式设计的功能;以及
用于产生硬件实施方案描述的装置还对新的特征进行重新定义,并将其整合到详细的硬件实施方案描述之中。
53.根据权利要求44所述的系统,其中,扩展说明是在指令集体系结构语言中的一个语句,它被用来指定一种操作码赋值以及一种指令语义。
54.根据权利要求53所述的系统,其中,用于产生硬件实施方案描述的装置包括从指令集体系结构语言定义中产生指令解码逻辑的装置。
55.根据权利要求54所述的系统,其中,用于产生硬件实施方案描述的装置还包括基于指令集体系结构语言定义,用于为指令互锁和挂起逻辑产生指定寄存器操作数用途的装置。
56.根据权利要求52所述的系统,其中,用于产生软件开发工具的装置包括用于产生指令解码方法的装置,上述解码方法用于适应于配置说明的指令集仿真程序之中。
57.根据权利要求52所述的系统,其中,用于产生软件开发工具的装置包括用于产生编码表的装置,上述编码表用于适应于配置说明的一段汇编程序之中。
58.根据权利要求52所述的系统,其中,用于产生硬件实施方案描述的装置还包括为新的特征生成数据路径的硬件描述的装置,上述数据路径的硬件与该处理器的特定的流水线体系结构相一致。
59.根据权利要求44所述的系统,其中,附加指令不为处理器增加新的状态。
60.根据权利要求44所述的系统,其中,附加指令为处理器增加状态。
61.根据权利要求1所述的系统,其中,配置说明包括由指令集体系结构描述语言说明所指定的至少一部分。
62.根据权利要求61所述的系统,其中,用于产生硬件实施方案描述的装置包括从指令集体系结构语言描述中自动地产生指令解码逻辑的装置。
63.根据权利要求61所述的系统,其中,用于产生软件开发工具的装置包括从指令集体系结构语言描述中自动地产生一段汇编程序核心的装置。
64.根据权利要求61所述的系统,其中,用于产生软件开发工具的装置包括从指令集体系结构语言描述中自动地产生一段编译程序的装置。
65.根据权利要求61所述的系统,其中,用于产生软件开发工具的装置包括从指令集体系结构语言描述中自动地产生一段反汇编程序的装置。
66.根据权利要求61所述的系统,其中,用于产生软件开发工具的装置包括从指令集体系结构语言描述中自动地产生一段指令集仿真程序的装置。
67.根据权利要求1所述的系统,其中,用于产生硬件实施方案描述的装置包括对硬件实施方案描述和软件开发工具的装置二者当中至少其中之一的一部分进行预处理,以便根据配置说明分别对硬件实施方案描述和软件开发工具进行修改的装置。
68.根据权利要求67所述的系统,其中,用于预处理的装置根据配置说明对硬件实施方案描述和软件开发工具二者其中之一的一项表达式进行评估,并且用一个数值来置换该表达式。
69.根据权利要求68所述的系统,其中,该表达式包括一种迭代结构,一种条件结构以及一种数据库查询三者当中至少其中之一。
70.根据权利要求1所述的系统,其中,配置说明包括至少一项参数说明,用以指定处理器的一种可修改的特性,以及至少一项扩展说明,用以指定处理器的一种可扩展的特性。
71.根据权利要求70所述的系统,其中,可修改的特性是对核心说明的一种修改,以及在核心说明中没有指定的一项可选的特征二者当中的一种。
72.根据权利要求1所述的系统,其中,配置说明包括至少一项参数说明,用以指定处理器的一种二进制的可选择的特性,至少一种可用参数方法指定的处理器特性,以及至少一种扩展说明,用以指定处理器的一种可扩展的特性。
73.用于设计可配置处理器的一种方法,该方法包括:
根据配置说明,产生处理器的硬件实施方案描述;以及
根据配置说明,产生专用于该硬件实施方案描述的各种软件开发工具。
74.用于设计可配置处理器的一种系统,该系统包括:
用于产生含有用户可定义部分的配置说明的装置,该配置说明的用户可定义部分包括:
关于用户定义的处理器状态的说明,以及
用户定义指令和与其相关的用户定义函数二者当中的至少一个,该函数包括从用户定义的处理器状态的读出和至用户定义的处理器状态的写入二者当中的至少一个;以及
用于基于配置说明而产生处理器的硬件实施方案描述的装置。
75.根据权利要求74所述的系统,其中,处理器的硬件实施方案的描述包括为执行用户定义指令以及为实现用户定义的处理器状态二者当中的至少一种所需的控制逻辑的说明。
76.根据权利要求75所述的系统,其中:
处理器的硬件实施方案描述一条指令执行的流水线;以及
控制逻辑包括跟指令执行的流水线的每一级有关的各部分。
77.根据权利要求76所述的系统,其中:
硬件实施方案描述包括用于中止指令执行的电路的描述;以及
控制逻辑包括用于防止由各项中止指令修改用户定义状态的电路。
78.根据权利要求77所述的系统,其中,控制逻辑包括针对至少一条用户定义指令,用于执行指令发出、操作数旁路以及操作数写使能三者当中至少一种的电路。
79.根据权利要求76所述的系统,其中,处理器的硬件实施方案的描述包括在指令执行的流水线的许多级中用于实现用户定义状态的各寄存器。
80.根据权利要求76所述的系统,其中:
处理器的硬件实施方案描述包括这样的状态寄存器,它们在不同于在其中产生各输出操作数的流水线级的流水线级中被写入。
硬件实施方案的描述指定绕过这样的写入而进入后继的指令,这些指令在被阻止写入到状态之前,引用用户定义处理器的状态。
81.根据权利要求74所述的系统,其中:
配置说明包括用户定义部分以外的一个预定部分;以及
说明的预定部分包括一条便于将用户定义状态存入存储器的指令,以及一条便于从存储器中取出用户定义状态的指令。
82.根据权利要求81所述的系统还包括使用该指令去产生一种软件,用于跟用户定义状态进行寄存器组转换。
83.根据权利要求74所述的系统还包括产生下列软件开发工具中至少一种的装置:一段汇编程序,用于对用户定义的处理器状态以及至少一条用户定义指令进行汇编;一段编译程序,用于对用户定义的处理器状态以及至少一条用户定义指令进行编译;一段仿真程序,用于对用户定义的处理器状态以及至少一条用户定义指令进行仿真;以及一段调试程序,用于对用户定义的处理器状态以及至少一条用户定义指令进行调试。
84.根据权利要求74所述的系统还包括产生下列软件开发工具的装置:一段汇编程序,用于对用户定义的处理器状态以及至少一条用户定义指令进行汇编;一段编译程序,用于对用户定义的处理器状态以及至少一条用户定义指令进行编译;一段仿真程序,用于对用户定义的处理器状态以及至少一条用户定义指令进行仿真;以及一段调试程序,用于对用户定义的处理器状态以及至少一条用户定义指令进行调试。
85.根据权利要求74所述的系统,其中,说明的用户定义部分包括指定用户定义状态的大小和索引的至少一个语句。
86.根据权利要求85所述的系统,其中,说明的用户定义部分包括与在一个处理器寄存器中的用户定义状态以及指定用户定义状态的封装有关的至少一种属性。
87.根据权利要求74所述的系统,其中,说明的用户定义部分包括指定用户定义状态与处理器寄存器的映射关系的至少一个语句。
88.根据权利要求74所述的系统,其中,用于产生处理器的硬件实施方案描述的装置包括将用户定义状态自动地映射到处理器的各寄存器的装置。
89.根据权利要求74所述的系统,其中,说明的用户定义部分包括用以说明一类用户定义指令及其对用户定义状态的影响的至少一个语句。
90.根据权利要求74所述的系统,其中,说明的用户定义部分包括用以向用户定义状态赋予一个数值的至少一个赋值语句。
91.一个用于设计可配置处理器的系统,该系统包括:
用于根据指令集体系结构说明而产生专用于该说明的软件开发工具的核心软件工具;以及
一个用户定义指令模块,用于根据用户定义的指令说明,产生至少一个模块,该模块供核心软件工具在实施各项用户定义指令的过程中使用。
92.根据权利要求91所述的系统,其中,核心软件工具包括能产生在处理器上运行的代码的各种软件工具。
93.根据权利要求91所述的系统,其中,至少一个模块被实现为一个动态连接库。
94.根据权利要求91所述的系统,其中,至少一个模块被实现为一张表。
95.根据权利要求91所述的系统,其中,核心软件工具包括一段编译程序,它使用用户定义的指令模块,用于将应用程序编译为使用用户定义的各项指令的、并且可以被处理器执行的代码。
96.根据权利要求95所述的系统,其中,至少一个模块包括由编译程序用于对用户定义的指令进行编译的模块。
97.根据权利要求91所述的系统,其中,核心软件工具包括一段汇编程序,它使用用户定义的指令模块,用于将应用程序汇编为使用用户定义的各项指令的、并且可以被处理器执行的代码。
98.根据权利要求97所述的系统,其中,至少一个模块包括由汇编程序用于将汇编语言指令映射为用户定义的指令的模块。
99.根据权利要求98所述的系统,其中:
该系统还包括核心指令集说明,用以说明各项非用户定义的指令;以及
核心指令集说明被汇编程序用来将应用程序汇编为可以被处理器执行的代码。
100.根据权利要求91所述的系统,其中,核心软件工具包括一段指令集仿真程序,用于仿真可以被处理器执行的代码。
101.根据权利要求100所述的系统,其中,至少一个模块包括一个被仿真程序用于对各项用户定义指令的执行情况进行仿真的模块。
102.根据权利要求101所述的系统,其中,被仿真程序使用的模块包括用于对各项用户定义指令进行解码的数据。
103.根据权利要求102所述的系统,其中,当各项指令不能被解码为预定义的指令时,该仿真程序就使用一个模块,对使用该仿真程序模块的各项指令进行解码。
104.根据权利要求91所述的系统,其中,核心软件工具包括一段调试程序,它使用用户定义的模块。对使用用户定义的各项指令的、并且可以被处理器执行的代码进行调试。
105.根据权利要求104所述的系统,其中,至少一个模块包括一个被调试程序用于将机器指令解码为汇编指令的模块。
106.根据权利要求104所述的系统,其中,至少一个模块包括一个被调试程序用于将汇编指令转换为字符串的模块。
107.根据权利要求104所述的系统,其中:
核心软件工具包括包括一段指令集仿真程序,用于仿真可以由处理器执行的代码;以及
调试程序跟仿真程序进行通信,以便获得用于调试的关于用户定义状态的信息。
108.根据权利要求91所述的系统,其中,根据不同的核心指令集说明,一条单独的用户定义指令可以不加修改地被多种核心软件工具所使用。
109.一种用于设计可配置的处理器的系统,该系统包括:
用于基于指令集体系结构的说明而产生专用于该项说明的软件开发工具的核心软件工具;
用于基于用户定义的指令说明而产生含有至少一个模块的组的用户定义的指令模块,该至少一个模块被核心软件工具用来实现各项用户定义的指令;以及
存储装置,用于同时地存储由用户定义的指令模块产生的组,其中每一组都对应于用户定义指令的一个不同的集合。
110.根据权利要求109所述的系统,其中,至少一个模块被实现为一个动态连接库。
111.根据权利要求109所述的系统,其中,至少一个模块被实现为一张表。
112.根据权利要求109所述的系统,其中,核心软件工具包括一段编译程序,它使用用户定义的指令模块,用于将应用程序编译为使用用户定义的各项指令的、并且可以被处理器执行的代码。
113.根据权利要求112所述的系统,其中,至少一个模块包括由编译程序用于对用户定义的各项指令进行编译的模块。
114.根据权利要求109所述的系统,其中,核心软件工具包括一段汇编程序,它使用用户定义的指令模块,用于将应用程序汇编为使用用户定义的各项指令的、并且可以被处理器执行的代码。
115.根据权利要求114所述的系统,其中,至少一个模块包括由汇编程序用于将汇编语言指令映射为用户定义的指令的模块。
116.根据权利要求109所述的系统,其中,核心软件工具包括一段指令集仿真程序,用于仿真可以被处理器执行的代码。
117.根据权利要求116所述的系统,其中,至少一个模块包括一个被仿真程序用于对各项用户定义指令的执行情况进行仿真的模块。
118.根据权利要求117所述的系统,其中,被仿真程序使用的模块包括用于对用户定义指令进行解码的数据。
119.根据权利要求118所述的系统,其中,当各项指令不能被解码为预定义的指令时,该仿真程序使用一个模块,对使用该仿真程序模块的各项指令进行解码。
120.根据权利要求109所述的系统,其中,核心软件工具包括一段调试程序,它使用用户定义的模块,对使用用户定义的各项指令的、并且可以被处理器执行的代码进行调试。
121.根据权利要求120所述的系统,其中,至少一个模块包括一个被调试程序用于将机器指令解码为汇编指令的模块。
122.根据权利要求120所述的系统,其中,至少一个模块包括一个被调试程序用于将汇编指令转换为字符串的模块。
123.一种用于设计可配置的处理器的系统,该系统包括:
基于指令集体系结构的说明,用于产生专用于该项说明的软件开发工具的多组核心软件工具;
基于用户定义的指令集说明,用于产生含有至少一个模块的用户定义的指令模块,它被一组核心软件工具用来实现各项用户定义的指令。
124.根据权利要求123所述的系统,其中,至少一个模块被实现为一个动态连接库。
125.根据权利要求123所述的系统,其中,至少一个模块被实现为一张表。
126.根据权利要求123所述的系统,其中,至少一组核心软件工具包括一段编译程序,它使用用户定义的指令模块,用于将应用程序编译为使用用户定义的各项指令的、并且可以被处理器执行的代码。
127.根据权利要求126所述的系统,其中,至少一个模块包括由编译程序用于对用户定义的各项指令进行编译的模块。
128.根据权利要求123所述的系统,其中,核心软件工具包括一段汇编程序,它使用用户定义的指令模块,用于将应用程序汇编为使用用户定义的各项指令的、并且可以被处理器执行的代码。
129.根据权利要求128所述的系统,其中,至少一个模块包括由汇编程序用于将汇编语言指令映射为用户定义指令的模块。
130.根据权利要求123所述的系统,其中,核心软件工具包括一段指令集仿真程序,用于仿真可以被处理器执行的代码。
131.根据权利要求130所述的系统,其中,至少一个模块包括一个被仿真程序用于对各项用户定义指令的执行情况进行仿真的模块。
132.根据权利要求131所述的系统,其中,被仿真程序使用的模块包括用于对用户定义指令进行解码的数据。
133.根据权利要求132所述的系统,其中,当各项指令不能被解码为预定义的指令时,该仿真程序使用一个模块,对使用该仿真程序模块的各项指令进行解码。
134.根据权利要求123所述的系统,其中,至少一组核心软件工具包括一段调试程序,它使用用户定义的模块,对使用用户定义的各项指令的、并且可以被处理器执行的代码进行调试。
135.根据权利要求134所述的系统,其中,至少一个模块包括一个被调试程序用于将机器指令解码为汇编指令的模块。
136.根据权利要求134所述的系统,其中,至少一个模块包括一个被调试程序用于将汇编指令转换为字符串的模块。
CN00812731.XA 2000-02-04 用于设计可配置的处理器的自动处理器产生系统及其方法 Expired - Lifetime CN1382280B (zh)

Applications Claiming Priority (6)

Application Number Priority Date Filing Date Title
US09/246,047 1999-02-05
US09/246,047 US6477683B1 (en) 1999-02-05 1999-02-05 Automated processor generation system for designing a configurable processor and method for the same
US09/323,161 US6701515B1 (en) 1999-05-27 1999-05-27 System and method for dynamically designing and evaluating configurable processor instructions
US09/323,161 1999-05-27
US09/322,735 US6477697B1 (en) 1999-02-05 1999-05-28 Adding complex instruction extensions defined in a standardized language to a microprocessor design to produce a configurable definition of a target instruction set, and hdl description of circuitry necessary to implement the instruction set, and development and verification tools for the instruction set
US09/322,735 1999-05-28

Publications (2)

Publication Number Publication Date
CN1382280A true CN1382280A (zh) 2002-11-27
CN1382280B CN1382280B (zh) 2016-11-30

Family

ID=

Cited By (23)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
CN100435154C (zh) * 2004-07-29 2008-11-19 国际商业机器公司 支持配置实体的选择性表示的配置说明语言的方法和系统
CN101236489B (zh) * 2008-02-26 2011-04-20 北京深思洛克软件技术股份有限公司 虚拟硬件系统及其指令执行方法、以及虚拟机
CN101483704B (zh) * 2008-01-10 2011-05-11 宝山钢铁股份有限公司 一种自动指令系统的仿真方法及装置
CN102110013A (zh) * 2009-12-23 2011-06-29 英特尔公司 用于有效生成处理器体系结构模型的方法和设备
CN102231180A (zh) * 2011-07-30 2011-11-02 张鹏 处理器指令编码可重定义的方法
CN103098058A (zh) * 2010-07-13 2013-05-08 艾尔葛托奇普股份有限公司 根据算法和规格的自动最佳集成电路生成器
CN103329097A (zh) * 2011-01-19 2013-09-25 艾尔葛托奇普股份有限公司 工具生成器
CN103827758A (zh) * 2011-09-30 2014-05-28 西门子公司 具有多功能显示器的管理系统
TWI450117B (zh) * 2009-09-17 2014-08-21 Emerson Network Power Embedded Computing Inc 客製化電路板的硬體描述語言產生系統及方法
CN104025034A (zh) * 2011-12-30 2014-09-03 英特尔公司 可配置精减指令集核
CN104737125A (zh) * 2012-10-23 2015-06-24 国际商业机器公司 维护代码生成器输出的完整性
CN106133626A (zh) * 2014-04-04 2016-11-16 西门子公司 用于运行自动化设备的方法,用于在方法的框架中使用的处理器和根据该方法工作的自动化设备
CN107024900A (zh) * 2015-10-21 2017-08-08 Ls 产电株式会社 最优编译plc命令的方法
CN107239829A (zh) * 2016-08-12 2017-10-10 北京深鉴科技有限公司 一种优化人工神经网络的方法
CN110007958A (zh) * 2018-01-05 2019-07-12 龙芯中科技术有限公司 指令验证方法、装置及存储介质
CN110188491A (zh) * 2019-06-03 2019-08-30 珠海格力电器股份有限公司 提高仿真计算过程中计算效率的处理方法及装置
CN110210046A (zh) * 2019-02-20 2019-09-06 芯易微电子(广州)有限公司 应用程序及专用指令集处理器一体化敏捷设计方法
CN110297703A (zh) * 2019-06-11 2019-10-01 国网江苏省电力有限公司 一种在实时仿真系统中模拟硬件任务调度的方法及装置
CN110825439A (zh) * 2018-08-10 2020-02-21 北京百度网讯科技有限公司 信息处理方法和处理器
CN110914813A (zh) * 2017-05-17 2020-03-24 德里克·约翰·哈姆林 数字处理连接性
CN113342649A (zh) * 2021-05-31 2021-09-03 上海创景信息科技有限公司 基于真实目标机实现单元测试的系统、方法、介质和设备
CN115480872A (zh) * 2022-09-14 2022-12-16 北京计算机技术及应用研究所 一种dsp c2812处理器指令集虚拟化仿真方法
CN115658455A (zh) * 2022-12-07 2023-01-31 北京开源芯片研究院 处理器性能评估方法、装置、电子设备及可读存储介质

Cited By (36)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
CN100435154C (zh) * 2004-07-29 2008-11-19 国际商业机器公司 支持配置实体的选择性表示的配置说明语言的方法和系统
CN101483704B (zh) * 2008-01-10 2011-05-11 宝山钢铁股份有限公司 一种自动指令系统的仿真方法及装置
CN101236489B (zh) * 2008-02-26 2011-04-20 北京深思洛克软件技术股份有限公司 虚拟硬件系统及其指令执行方法、以及虚拟机
TWI450117B (zh) * 2009-09-17 2014-08-21 Emerson Network Power Embedded Computing Inc 客製化電路板的硬體描述語言產生系統及方法
CN102110013A (zh) * 2009-12-23 2011-06-29 英特尔公司 用于有效生成处理器体系结构模型的方法和设备
CN102110013B (zh) * 2009-12-23 2015-08-19 英特尔公司 用于有效生成处理器体系结构模型的方法和设备
CN103098058A (zh) * 2010-07-13 2013-05-08 艾尔葛托奇普股份有限公司 根据算法和规格的自动最佳集成电路生成器
CN103329097A (zh) * 2011-01-19 2013-09-25 艾尔葛托奇普股份有限公司 工具生成器
CN102231180B (zh) * 2011-07-30 2014-05-28 张鹏 处理器指令编码可重定义的方法
CN102231180A (zh) * 2011-07-30 2011-11-02 张鹏 处理器指令编码可重定义的方法
CN103827758A (zh) * 2011-09-30 2014-05-28 西门子公司 具有多功能显示器的管理系统
CN104025034A (zh) * 2011-12-30 2014-09-03 英特尔公司 可配置精减指令集核
CN104025034B (zh) * 2011-12-30 2018-09-11 英特尔公司 可配置精减指令集核
CN104737125A (zh) * 2012-10-23 2015-06-24 国际商业机器公司 维护代码生成器输出的完整性
CN104737125B (zh) * 2012-10-23 2018-03-06 国际商业机器公司 用于维护代码生成器输出的完整性的方法和系统
CN106133626B (zh) * 2014-04-04 2019-05-07 西门子公司 用于运行自动化设备的方法,用于在方法的框架中使用的处理器和根据该方法工作的自动化设备
CN106133626A (zh) * 2014-04-04 2016-11-16 西门子公司 用于运行自动化设备的方法,用于在方法的框架中使用的处理器和根据该方法工作的自动化设备
US10295980B2 (en) 2014-04-04 2019-05-21 Siemens Aktiengesellschaft Automation device processor and method for operating the automation device
CN107024900A (zh) * 2015-10-21 2017-08-08 Ls 产电株式会社 最优编译plc命令的方法
US10445074B2 (en) 2015-10-21 2019-10-15 Lsis Co., Ltd. Method of optimally compiling PLC command
CN107239829A (zh) * 2016-08-12 2017-10-10 北京深鉴科技有限公司 一种优化人工神经网络的方法
CN107239829B (zh) * 2016-08-12 2020-12-11 赛灵思电子科技(北京)有限公司 一种优化人工神经网络的方法
CN110914813A (zh) * 2017-05-17 2020-03-24 德里克·约翰·哈姆林 数字处理连接性
CN110914813B (zh) * 2017-05-17 2023-10-31 德里克·约翰·哈姆林 数字处理连接性
CN110007958A (zh) * 2018-01-05 2019-07-12 龙芯中科技术有限公司 指令验证方法、装置及存储介质
CN110825439A (zh) * 2018-08-10 2020-02-21 北京百度网讯科技有限公司 信息处理方法和处理器
US11055100B2 (en) 2018-08-10 2021-07-06 Beijing Baidu Netcom Science And Technology Co., Ltd. Processor, and method for processing information applied to processor
CN110210046B (zh) * 2019-02-20 2023-04-07 芯易荟(上海)芯片科技有限公司 应用程序及专用指令集处理器一体化敏捷设计方法
CN110210046A (zh) * 2019-02-20 2019-09-06 芯易微电子(广州)有限公司 应用程序及专用指令集处理器一体化敏捷设计方法
CN110188491A (zh) * 2019-06-03 2019-08-30 珠海格力电器股份有限公司 提高仿真计算过程中计算效率的处理方法及装置
CN110297703A (zh) * 2019-06-11 2019-10-01 国网江苏省电力有限公司 一种在实时仿真系统中模拟硬件任务调度的方法及装置
CN113342649A (zh) * 2021-05-31 2021-09-03 上海创景信息科技有限公司 基于真实目标机实现单元测试的系统、方法、介质和设备
CN113342649B (zh) * 2021-05-31 2023-11-14 上海创景信息科技有限公司 基于真实目标机实现单元测试的方法、介质和设备
CN115480872A (zh) * 2022-09-14 2022-12-16 北京计算机技术及应用研究所 一种dsp c2812处理器指令集虚拟化仿真方法
CN115480872B (zh) * 2022-09-14 2023-04-28 北京计算机技术及应用研究所 一种dsp c2812处理器指令集虚拟化仿真方法
CN115658455A (zh) * 2022-12-07 2023-01-31 北京开源芯片研究院 处理器性能评估方法、装置、电子设备及可读存储介质

Also Published As

Publication number Publication date
WO2000046704A2 (en) 2000-08-10
KR20070088818A (ko) 2007-08-29
WO2000046704A3 (en) 2000-12-14
JP2003518280A (ja) 2003-06-03
KR100874738B1 (ko) 2008-12-22
AU3484100A (en) 2000-08-25
TW539965B (en) 2003-07-01
KR20020021081A (ko) 2002-03-18
JP2007250010A (ja) 2007-09-27
EP1159693A2 (en) 2001-12-05
KR100775547B1 (ko) 2007-11-09

Similar Documents

Publication Publication Date Title
CN1288585C (zh) 用于设计可配置处理器的自动处理器生成系统及方法
CN100338568C (zh) 开发片上系统用的开发环境的生成方法
CN1728153A (zh) 支持配置实体的选择性表示的配置说明语言的方法和系统
CN1666202A (zh) 管理集成电路设计的装置和方法
Hoffmann et al. Architecture exploration for embedded processors with LISA
Rowen Engineering the complex SOC: fast, flexible design with configurable processors
CN1308818C (zh) 用于结构仿真的系统
TW539965B (en) Automated processor generation system for designing a configurable processor and method for the same
CN1885295A (zh) 使用逻辑单元建置集成电路
CN1619490A (zh) 系统的集成设计,部署和管理阶段
CN1260055A (zh) 用于提高软件安全性的模糊技术
CN1505790A (zh) 带有可编程组件的基于块的设计方法
CN1625731A (zh) 具有多种长度指令集体系结构的可配置数据处理器
CN1664779A (zh) 软件开发基础架构
CN1570870A (zh) 终极管道和最优重排技术
CN1551006A (zh) 分布式计算系统架构及分布式应用的设计、部署和管理
US20130290693A1 (en) Method and Apparatus for the Automatic Generation of RTL from an Untimed C or C++ Description as a Fine-Grained Specialization of a Micro-processor Soft Core
CN1273893C (zh) 模块化计算机系统以及相关方法
CN1399737A (zh) 便于组件选择的软件开发系统
Hohenauer et al. A methodology and tool suite for C compiler generation from ADL processor models
Glökler et al. Design of energy-efficient application-specific instruction set processors
Karuri et al. Application analysis tools for ASIP design: application profiling and instruction-set customization
Mishra et al. Architecture description language (ADL)-driven software toolkit generation for architectural exploration of programmable SOCs
Trilla et al. Novia: A framework for discovering non-conventional inline accelerators
CN1957328A (zh) 展示方案组件的逻辑视图、便于其选择以及在编译之前的信号遗漏链接的软件开发系统

Legal Events

Date Code Title Description
C10 Entry into substantive examination
SE01 Entry into force of request for substantive examination
C06 Publication
PB01 Publication
C10 Entry into substantive examination
SE01 Entry into force of request for substantive examination
C10 Entry into substantive examination
SE01 Entry into force of request for substantive examination
C14 Grant of patent or utility model
GR01 Patent grant
CX01 Expiry of patent term
CX01 Expiry of patent term

Granted publication date: 20161130