自从8048/8051微处理器进入市场以来,已经过去了三十年。它的出现改变全世界对嵌入式微控制器应当是什么样的观点。这么多年来,每种新的微控制器都采用它们的基本结构,每种新产品都作了一些改进,目的是满足应用系统越来越高的要求。最早的结构仍然很重要,而且没有改变,现在是迎接新的多处理器核结构的时候了。这是最新设计的结构,用于二十一世纪的应用系统。在本文中,我们将讨论在结构设计方面的根本变化──由于需要更高的运作速度同时要省电,推动这种结构的出现。

二十世纪的应用系统

在二十世纪,一般的应用系统使用8位微控制器,它能够读取传感器的信号。这类微控制器能够进行少量的数据处理,有一些I/O,大约是并行的,以便把字符送往显示器,或者把一个字节数据送到磁带或者其他的数据记录设备上记录下来。有一些I/O能够对简单的键盘或者一组开关进行扫瞄,全部工作可以用芯片上的时实时时钟信号在要求的时间内完成。利用芯片上的时钟提供的精确时间信号,同步地传送数据,执行其他按时间进行的任务。

这些应用系统使用的存储器并不多,也许只是64到256字节的RAM存储器,大多数是集成在芯片上。有一些微控制器也能够访问外部存储器,最初的接口只不过是地址和数据总线,它们通过处理器读取数据,在软件的控制下把数据送往外面的存储器或者取出来。

所以,人们着眼于在要求的时间之内控制I/O,处理器进行的实际数据处理工作是很少的。这是因为处理器处理数据的能力非常有限,而且时钟的频率很低,只有几兆赫兹。尽管这些芯片处理数据的能力有限,对于大量简单的应用,从室内温度控制器到简单的家庭自动化系统,是绰绰有余的了。事实上,我是用最近推出的手持计算机撰写这篇文章的。这台计算机使用从最早的8048芯片衍生出来的微控制器专门读取我在键盘上的动作。随着时间的推移,出现了更小、功能更少的处理器,它的价钱较低。同时,出现了比较先进的,字长为16位和32位的其他微控制器,它们包含速度快得多、复杂得多的外部存储器接口,它们使用DMA控制器电路。然而,基本的想法仍然没有变。在一块芯片上有一两个处理器,从输入线上读取数据,把数据送到输出线上,按照需要改变I/O控制引脚。这些都是使用外面的实时时钟基准信号。

消费类电子产品推动二十一世纪应用系统的发展

但是,现在应用系统有了很大变化。除了用传统的位触发(bit banging)方式,增加新的处理功能──算法的处理。今天,大量的应用系统是消费类多媒体系统,包括小小的MP3音乐播放器到具有视像功能的移动电话。而且期待已久的高分辨率电视也开始蜂拥而来,由于高分辨率电视的出现,突然之间,消费者们认识到他们需要家庭网络,在房间之间传送视频节目和音乐。

多媒体的功能

所有新型消费类应用系统的核心部分都有数字量数据,这就是说显示和播放这些数据的器件中需要进行大量的数字信号处理。在设计用于多媒体的各种文件格式时,已经考虑到使用数学算法进行数字处理──快速富利叶变换(FFT),离散余弦变换(DCT)等等。在多媒体应用系统中需要宽频带,它要求二十一世纪的处理器有专门的电路来处理这些算法。但是仍然需要早期使用的通用I/O和实时时钟。新的芯片两者都需要!

面向位流

因此早期的处理器把外部存储器看成是应用系统的数据源,也是应用系统中数据的去向。现代处理器要能够操作来自互联网、USB和1394以及电缆和人造卫星电视服务系统传过来的高速位流数据。消费类产品,例如相机、MP3播放器,甚至是移动电话,都普遍使用USB 2.0接口,要求速度达到480 Mb/s。视像应用系统通常使用1394接口,速度为200/400/800 Mb/s。现在千兆位的以太网甚至已经开始在家庭中出现,它的数据传送速度还更高。今天的处理器要处理这么高的数据速度,按照二十世纪的标准,速度之快不可思议。

更严重的是,高分辨率音像网络联合会(HANA)用于家用网络的新标准认为FOUR 1394的位流速度会高达800 Mb/s。MP4格式的数据假定音频和视频有多个位流,以及供选用的其他数据流,用于传送标题和静止图像。在很多情况下,同一个处理器在对缓冲存储器送过来的MP4位流进行解码时,也要处理进来的位流,所以,必须立刻同时处理四个或者五个这样的高速度位流。

外接高速存储器接口

由于需要把数据高速度地送往外接存储器,处理器只需要处理几百个字节数据的时代早已成为过去。今天,用于视频应用系统的一些专用处理器一定要能够对128兆字节的DDR SRAM存储器进行存取。在一块处理器芯片上实现比较大的寻址范围是比较容易的,但是这些存储器接口的速度现在极为重要。寻址空间大意味着处理器上有很多引脚用作外接存储器的接口。在很多这类应用系统中有多个位流,这表示必须有一个简单的方法能够迅速地切换存储器接口上的地址位。在大多数现代处理器中,这个接口(一般有三个)使用成熟的DMA(直接存储器寻址)控制器。有一些控制器甚至更进一步,它们可以进行变址寻址。这样很方便。例如,当控制器从存储器中取出多字节矢量时,就很方便。

低功耗

许多现代消费类设备是用电池供电。它的处理工作量大,加上显示器,有时甚至还有一个磁盘驱动器,因此这些设备的电池负荷很大。所以功率是一个大问题,而处理器本身必须能够工作在低功率状态,以便延长电池寿命。当然,低功耗与高速处理不可兼得,所以在设计时要认真地权衡。

二十一世纪的多核处理器结构

应用系统在本质上的变化明确地要求对处理器芯片的结构作出相应的改变。例如,由于需要多媒体的功能,需要处理高速算法的专门电路。由于需要进行高速处理,芯片设计人员把处理器核加到芯片上,这样,需要进行实时处理的任务就可以在一个处理器芯核中运行,同时其他任务可在第二个处理器核上运行。

多处理器核

把任务分成两组──实时的任务和非实时的任务──的做法失败了,原因很简单,在现代的应用系统中,大多数任务都有一部分是实时进行的。简单地说,推动多媒体应用系统发展的动力是高速计算部件,它们竞相在很短的时间里,在下一批多媒体数据到来之前完成他们的算法。这个办法没有成功,就是说播于音乐时会出现停顿,或者视像中会有尖脉冲噪音。

近来的发展趋势是把一个甚两个DSP核和高速乘法器/累加器电路结合起来,跟上多媒体位流的速度。但是,由于增加速度更高位流的要求看来是无止境的,这个方法看来达到了它的极限。一个更好的方法是把几个处理器核集成到芯片上,每一个都比复杂的DSP核简单,但是每一个处理器核都有一个高速乘法器/累加器。这些处理器核如果妥善设计,就可以把计算任务分配给各个处理器核共同进行,从而能够执行复杂的算法。当然这需要重新写入算法,以便把计算任务分解,由多个处理器核分担,结果可能令人难以置信地提高了处理能力。

用这个办法安排计算任务还有另外一个优点。由于使用DSP核的芯片灵活性小,而用若干处理器核的芯片可以编程,可以把处理器核的数量设计成是最优的,来解决这个问题。需要更高的速度吗?只要用更多的处理器核来进行处理就可以了。这个办法利用了处理器核的强大处理能力,所以,和 DSP不一样。DSP主要是由高速算法电路组成,处理器核增加了高速条件转移的功能,它还有其他传统计算电路部件的功能。因此,使用多处理器核的办法十分灵活,它解决问题的能力很强,不只是能够完成高速算法。

多处理器核芯片的灵活性表现在,可以简单地指定各个处理器核完成需要执行的不同任务,解决范围广泛的各种问题。可以让一个处理器核去管理外接存储器,让八个处理器核负责快速富利叶变换,完成多媒体算法,再用几个处理器核带动应用系统中的各种I/O子系统。这与使用单个处理器处理多任务的传统方法完全不一样。大家知道,这个方法是让处理器在某一段时间做一个任务,然后切换到另一项任务,等等,因而人们觉得它是执行多任务的处理器。如果有一些任务是关于I/O的,需要相当时间等着接收数据,这个感觉是没错的。但是,对于不需要等待数据的任务,这个感觉就完全破灭了──这个处理器只是由不同的任务共用资源,它的负担显然是很重的。在转换任务时,由于处理器把数据存放到寄存器和存放应用数据,需要上下文切换时间,这个问题就加重了。处理器越大、越复杂,上下文切换时间越长,这种多任务处理器的感觉就破灭得越严重。在多处理器核的方法中,每一个任务是用一个或者更多处理器核来完成,情况完全变了。上下文切换时间是零,道理很简单,每个处理器不会改变它的任务。多处理器的想法变成了现实。

本地RAM/ROM存储器

当设计中使用了多个处理器时,存储器存取的问题就出来了。大多数多核芯片设计把几个处理器核和一个共用存储器放在一起。这样做简化了设计,因为每一个核只是处理器本身,问题转到多个处理器核如何共同使用一个存储器,以及存储器存取的仲裁,这是一个难题。通常用到某种仲裁网络或者交叉点切换开关。在只有三个到四个处理器核时,这个方法是可行的。但是,在芯片上需要几十个处理器核时,共用存储器的问题变得很复杂,令人望而却步。此外,由于越来越多处理器核需要对存储器进行存取,共用存储器的效率变得越来越低,很快就成为致命的瓶颈,把多核结构在处理方面的优点都淹没了。

解决这个问题的办法是用本地存储器取代普通的共用存储器。本地存储器是属于各个处理器核的存储器。用这个办法,就不需要存储器仲裁,也不需要交叉切换开关,因为每个处理器核只是对自己的RMA/ROM存储器进行存取。

用共用存储器来存放数据有一个大优点,这就是,只要为分配给每个处理器核它所需要的存储容量,就可以对存储器的大小进行优化。在每个处理器核都有它自己的本地存储器时,存储器的容量就需要权衡折衷。如果存储器容量太小,处理器核就不能充分发挥作用,如果存储器容量太大,又造成浪费,芯片就会很大,代价是效率。

好在本地存储器的大小很容易确定。只要编写芯片必须处理的典型算法的源代码,并且试一下,很快就知道,需要的存储器容量有两种,一种是1000字节或者少一些,一种是容量很大,几兆字节,甚至几百兆字节。当使用很大的缓冲器来处理多媒体数据时,就会出现上面所说的第二种情况。但是只不过是芯片上的几个处理器核需要容量很大的本地存储器。很清楚,每个处理器核增加几兆字节的本地存储器,既使这样做是实际可行的,也是很浪费的。第一种存储器容量,也就是1000 字节,用今天的主流半导体工艺是很实际的,作为处理器核的本地存储器,的确是绰绰有余的。

最后一个办法就是每一个处理器核都用小一些的本地存储器,1000字节的数量级,用于存放程序源代码和数据,再用一个大得多的外接存储器,作为缓冲存储器,满足多媒体的需要。只有少数处理器核需要用它。

处理器核之间的通讯

很清楚的一点是,多核芯片的想法并不是用一组处理器核岛,每个岛有一组它自己的I/O脚,这些I/O脚是相互独立的。我们已经讲过,计算量很大的算法可以由几个处理器核分担进行。很明显,各个处理器核之间需要交换数据和合作。

处理器核之间进行通讯的方式有两种:传送状态信号和传送数据块。从概念上讲,这两者之间并无区别,然而在通讯速度方面则有很大的不同。例如,状态信号可以送给相邻的核,说明数据已经就绪,等待传送,然后在它们之间传送数块。这两种通讯方式都要求效率很高,而实现高效率的办法可能完全不一样。我们在后面再来谈这个问题。

对于存储器共用的情形,处理器之间的通讯可以用几个办法进行。如果只牵涉到两个处理器核,可以提供通讯电路,每一个处理器通过电路和其他处理器进行通讯,这是实际可行的。但是当处理器核的数量增加到几十个,芯片的面积和通讯电路的复杂程度会变得令人望而生畏。实现处理器核之间通讯的另一个办法是只限于在一组很少的处理器核之间进行通讯,典型的情形是在最靠近的两个处理器核之间进行通讯。这个方法简单得多,而且非常实际。

实现处理器核之间的通讯电路是许多处理器面临的问题。如何实现通讯路径和进行处理?作为计算机的使用人员,对于我们运行的应用程序,我们习惯于让计算机去作出决定。例如,随着我们的文件增多,文字处理处理应用软件需要更多存储器,我们依靠计算机找到存储空间,指定那个存储空间供文字处理程序使用,一项文字处理也许需要重新指定存储块,并把一部分数据移到磁盘上。这个处理过程我们是完全看不见的,是计算机按需要进行的。

在设计存储器分配系统时,甚至在磁盘操作系统时,考虑到要以很高的效率来运行软件,这时就是文字处理程序,这点并不是大家都清楚的。设计系统时,一开始就考虑到计算机自主地运作,指定存储块,把其他存储块的数据移到硬盘,而不是由使用者来做这件事。

对于多核芯片,究竟如何指定这些处理器核去执行应用软件中的各个任务呢?这不是由应用程序自己来做,甚致不是一些操作系统。指定处理器核完成一项任务的过程是由设计人员/程序员来做的,设计人员和程序员把应用软件送到芯片上,而不由开发系统程序来做。把应用软件送到芯片的过程是设计课题中最基本的问题。为此,设计人员一定要了解哪一项任务需要交换最多的数据。然后指定邻定的处理器核完成这项任务,将处理器核的通讯优化。如果指定处理器核的过程是由开发系统以某种方式自动进行的,那么可以设计一个在处理器核之间进行通讯的系统,针对自动指定处理器核的过程进行优化。但是,由于这是由设计人员做的,最好是使用最简单、效率最高的通讯电路,它只在这个处理器核与邻近处理器核之间交换数据。当然,可以让处理器核把数据和状态信号用接力的方法传给较远的处理器核,但是,规定处理器核只与最近的处理器核直接交换数据,芯片设计就简单得多,应用软件设计人员反正需要指定处理器核的任务,对他们来讲,并无任何损失。

针对具体的应用系统进行自动设计和手工设计,两者之间往往会有冲突。既然计算机起的作用有时候是文字处理器,有时候是电影播放器,或金融电子数据计算器,不论是哪一种功能,与嵌入式处理器起的作用是完全不同的。在嵌入式处理器芯片中,不在相机和温度控制器这些功能之间来回切换。因此,不要用不论什么事、不论在那捚,不论什么时候都做的结构,不要像大型交叉点开关那样可以在芯片上任何两个处理器核之间交换数据,因而对设计进行折衷。

如果我们决定只在最靠近的相邻处理器核之间交换数据的话,通讯电路就变得很简单,效率也有可能很高。处理器核之间交换数据是通过共用寄存器进行,不需要解决冲突的电路,不需要优先权网络。但是有可能把某些状态信号和数据交换结合起来。传统的做法是,两个处理器通过一个共用寄存器传送数据,检测某个地方的状态位,它决定传送数据的状态。处理器A把数据送往寄存器,并把状态位设置为“高电平”,表示数据已经到位,等待读取。处理器B是通过软件检测状态位,看它是否变成“高电平”,状态位为“高电平”表示新的数据已经放在寄存器中。在读取数据之后,处理器 B将状态位复位,成为“低电平”,表示已经读取数据,寄存器已经准备好等待下一次传送数据。在这方面有很多不同的做法。不过,可惜的是,比起实际传送数据所用的时间,两个处理器读取状态位、检测状态位、写入状态位所用的时间更长。

多核芯片提供了一个简单得多的办法。处理器核A的源代码编写成这样:它总是认为寄存器是空着的,在等待数据。它的循环子程序没有检测和写入状态位的源代码,但是它变成是执行指令“送出数据(SendData)”-“送出数据”-“送出数据”,等等。同样处理器B的源代码认为一直有数据在等着它去读出,所以它的循环子程序现在只不过是执行指令“读取数据(ReadData)”-“读取数据”-“读取数据”,等等。在实际上这是如何实现的呢?处理器核A是送出数据的核,想把数据送到共用寄存器去,如果在寄存器中的数据还没读取,处理器核A 就停下来,一直到处理器核B读取了寄存器中的数据,在同一时刻,处理器核A回来执行原来要执行的哪条指令,也就“送出数据”。于是,从源代码的角度看,处理器核A总是认为寄存器总是空着的,在等待数据,没有必要读取和检测状态位。处理器核B做的事与之相似。处理器核B的源代码总是认为寄存器中一直存放着没有读出的数据。当它开始执行指令“读取数据”,从寄存器中取出数据时,如果寄存器中没有需要读取的数据,它也停下来。当新的数据在寄存器中出现时,处理器核B便执行“读取数据”指令,这条指令把数据从寄存器中取出来。同样,没有必要读取、检测状态位,没有必要将状态位置位。

大多数读者并不熟悉这项技术,对于处理器在不同芯片的系统,不是用这个办法。它之所以是那样地运作,是因为,当两个处理器核是在同一块芯片上时,有一个电路是用于将可以使用的处理器启动和让它停下来。关键在于,启动和停止的过程必须非常快──是执行一条指令所用的时间,这样才真正有效果。但是,这一点做得到的话,两个处理器核之间传送数据的速度将大幅度地加快,提高了几倍。事实上,有很多类型的数据交换,在处理器核之间完全不需要软件来发出信号。

如果处理器核是设计成使用与存储器对应的I/O(memory-mapped I/O),在处理器核之间会有各种更多令人感兴趣的通讯方式。在这个系统中,把I/O寄存器当作是存储器地址,这就是说,读写存储器的同样指令也对I/O进行操作。但是,对于多核芯片,这种I/O结构有不同的选择。处理器核不仅可以读取和执行本地ROM和RAM中的指令,它还能够读取和执行I/O口和寄存器送来的指令。

传送数据的循环子程序不需要读出、检测和写入状态位,难以置信地有效。用这个办法时,指令源源不断地送到处理器核的I/O口,并且直接执行。由于处理器核共用的寄存器实质上和I/O口是一样的,这表示,一个处理器核可以把源代码送到相邻的处理器核,这个处理器核可以直接从共用寄送器取出指令并且执行,不必把源代码实际地传送给另外一个处理器的本地存储器。源代码可以在各个处理器核之间传送,这些处理器核从寄存器上取出并执行这些指令。由于每一个处理器核实际上完全是在它自己的地址空间中进行,没有明显地把时间用在传送源代码指令上,传送源代码指令的速度非常快。

实时时钟

随着传统处理器的处理速度和复杂程度的提高,它们越来越不能实时地对任务进行处理,这表示处理源代码的时间是不确定的,每次都不一样。这大体上是由于使用了缓存,缓冲的容量越来越大,处理器用这些缓存来降低外接存储器的存取时间。 所以,在源代码的一个循环子程序中,指令是从外面取来的,但是在下一次,指令是在缓存中。同时,随着处理器变得更加复杂,CPU寄存器的数量也增加了。相应地,在进行中断处理时,把寄存器的内容存放起来的时间增长了。由于这一切,现代的处理器不适合嵌入式应用系统,更用不着说需要大量的存储器,芯片本身的成本了。

对于嵌入式处理器,一向强调处理实时应用软件的能力,强调在一定的时隙中处理源代码,要求在分配给它而且严格控制(或者说越来越短)的时间里处理事件以及显示。一个处理器芯片使用一个实时时钟来设置和控制这些任务,而这个时钟是由外面提供的。在多核芯片中什么是最理想的安排呢?

我们且把应用软件看作是一组相互有关的任务和子任务,指定处理器核去执行各个任务,这就是答案。现代应用系统,特别是多媒体密集型应用系统,它在一个时隙里要完成的不只是一两个任务。现在,如果说不是大多数任务,有很多任务都有一部分是实时的。于是,一个处理器核需要使用实时时钟信号,用它把状态信号以消息的方式送给其他处理器核,或者每一个处理器核都能够直接得到基准时钟信号。在这两种办法,后者好得多。

如果每个处理器核都能够得到实时时钟信号,因而可以取消状态信号,而且不需要使用状态信号在处理器核之间传送数据,在处理器核之间完全取消状态信号这种通讯方式还有很长一段路要走。要注意的是,我们并不是建议把系统时钟信号传到所有的处理器核去,这需要按照那个时钟信号同步地切换几百万个节点。为了让实时时钟有效地工作,每个处理器核中只有少数节点必须切换,对功耗的影响可以忽视。为了让每个节点能够充分地进行实时处理,在每个节点上用一个简单的计数器就绰绰有余了。

在设计上实现低功耗

随着越来越多嵌入式处理器芯片用在在移动应用系统中,对低功耗的要求越来越重要。在传统的设计中,绞尽脑汁在每一个细小问题上下功夫,细心地决定每个信号通路的速度,然后按照这个速度来选择晶体管的大小。只有速度最高的信号通路使用大功率晶体管。

但是,多核芯片能够按照数据是否出现来启动处理器核或者让它停下来,因此节电的办法要简单得多。不进行数据处理的处理器核不工作,它完全不消耗功率。处理器核只在需要时才工作,接通电源和切断电源完全是自动进行的,不需要由程序来干预。

把处理器核的电源完全切断,这对功耗的影响比起在信号通路上做文章大得多。事实上,这个方法还有一个优点。因为各个处理器核之间的数据通路是自动同步的,完全没有必要对处理器核本身进行同步。这就是说,不需要一个中央时钟为每个处理器核提供时钟信号。数据的传送总是尽量以最高速度进行──外部时钟不起任何作用,只不过是增加了复杂程度。每个处理器核各有一个时钟──一个简单的环形振荡器,它的速度和硅半导体的速度一样快,这些时钟取代了中央时钟。没有中央时钟,意味着不需要庞大的时钟树,而时钟树中的几百万个晶体管节点随着时钟信号的每一次嘀嗒一声而消耗功率。相反,每个处理器核都有小小的时钟振荡器,但是只在那个处理器核工作时,它的时钟才工作。如果一个处理器核由于在共用寄存器上没有数据可用,或者邻近的处理器核还没有读取,因而停了下来,环形振荡器也停止工作。只有处理器核工作时,它的时钟才消耗功率。即使在这时,它们相互之间完全不同步,所以功耗也不是集中在某个时间。

在这样的芯片中,有几十个处理器核,在任何一个给定的时间,这些处理器中只有一部分在运行。其中有一些处理器核有一段相当长的时间没有工作,因为芯片工作的状况是,这些任务在运行时,这些处理器核并没有参与。但是,即使在工作的处理器核在短时间内也是这样。先接通电源并且以硅半导体所能达到的速度执行程序,接着,它的数据用完了,就立即切断电源,或者等待邻近的处理器核读取数据后继续工作。在这种情况下,我们估计,在任一时刻,只有三分之一的处理器核在工作,过几个纳秒后,另外一组处理器核接通电源,但是仍然大约只有三分之一。这样就有效地降低了整个芯片的功耗,降低了三分之二,同时,每个处理器核以半导体可能达到的最大速度运行。

指令集

指令集主要是决定于与处理器有关的那些寄存器。不过,对于多核芯片,处理器核经过精心设计,速度很高,但尺寸很小,复杂程度最低。换句话说就是,是RISC处理器。这种处理器用很简单、数量减少了的指令集运行。至今,处理器结构和处理器语言的最好搭配是,处理器执行的是用高水平RISC语言作为机器码编写的指令。这就做了两件事:第一是把大量功能放到最短的程序中,第二是,取消高级源代码与机器码之间的中间转换,从而把执行指令的速度提到最高。对于存储器容量受限制的芯片,上面讲的第一点极重要,在处理要求很高的多媒体应用算法时,第二点同样重要。

这就提出了一个问题:在这些处理器核中用什么高级语言作为机器码指令集?关于这个问题,没有多少可选择的。大多数现代高级语言是把大量数据传送给一组功能和子程序。程序员大体上是看不到这个过程的,因为它是稳藏在语言汇编器后面。但是,对于将来用于嵌入式芯片的处理器核,这个方法的效率很低。在这种情况下,处理器可以是RISC 处理器,但是像C和C++这些语言肯定不属于RISC之列。好在有一种语言是针对这类处理器进行了优化的──事实上它是针对设想中的多核芯片设计的。这种语言就是 Forth。

对于小的处理器核,Forth是很理想的。这有几个原因。但是首先是,它不使用大量的寄存器。实现Forth处理器的硬件很少。而且,因为 在编制Forth程序时,是定义新的字,然后用这些字来定义更高级的字,确定一组很少的核心字是很容易的,其余一切都是用这些核心字,然后把这些核心字装在处理器的专用电路中。最后的结果是处理器核非常小,速度很高。

用核心字实现的指令只有32条。有可能达到像理想的RISC那样,用数量最少的指令集直接处理大多数应用软件源代码,同时又可以使用那些包含很少用的指令的指令集──这种指令集会使电路变得复杂,最终降低执行速度。很清楚的是,只有32条指令的指令集只用5位就能实现,有一些指令只能用于某些场合,这样就有可能把几条指令都放在一个不长的指令字中,在一个18 位的指令字中最多可以放4条指令。

像这样安排的指令可以自动地达到缓存的效果,不需要设置L1和L2缓存。每取一个指令字时,一下子就把四条指令送到处理器核中。虽然这种内在的缓存很小,指令本身在使用它时,非常有效。例如,循环子程序的微指令可以全部放在一个18位指令字中。这种结构的指令字如果和自动状态信号一起,放到I/O寄存器中,是很理想的,因为这表示只要取一次指令字,就可以传送大数据块。用这种指令字时,要执行的指令是放在与邻近处理器核共用的I/O寄存器中,它的功能很强,因为寄存器中的每一个指令字有四条指令,而不是一条指令。这种软件和硬件结构,以及它们对多核芯片性能的巨大影响,用传统的语言是做不到的──只能用这种指令集,才能够把几条指令放在一个指令字中,用这个指令字就能够执行整个循环子程序。

不使用中央操作系统

在一块芯片上实现多个处理核并不是什么新点子,事实上,在市场上至少有几十种这样的芯片,或者即将推出这样的芯片。但是,实际上所有这些芯片包含两个或者四个处理器核,这些是大而复杂的处理器,用于 Windows台式计算机。有一个地方用了它,不是用在十分紧凑的嵌入式应用系统,而是用在大型服务器上。这种多核处理器都需要一个中央操作系统把应用程装到处理器核中并指挥它们工作。

在典型的对称式多核处理技术中,各个处理器核都是一样的。为了能够成功,假定要运行的软件已经用多线程的方式编写。操作系统可能在其中的一个处理器核中运行,它把源代码分成块,启动各个线程,用这个方式把源代码装到其他的处理核中。在装到处理器核时,以线程源代码块作为源代码的基本单位,让所有的处理器核的处理工作量保持均匀。如果应用程序已经是用这种多线程的方式编写的话,多核SMP的方法运作得相当不错。

当然,并不是所有软件是这样编写的,但是,即使不是这样编写的,中央操作系统也能够把整个程序装到各个处理器核中,于是,多核结构的优点便显示出来了。但是,对于嵌入式处理器,这些都不适用。由于没有磁盘驱动器,不能在在运行过程中在中央操作系统的控制下把程序装到处理器核中。简单地讲,在嵌入式处理器中没有中央操作系统。对于多核芯片,中央操作系统的作用为深思熟虑的程序员的作用所取代。

对于这类芯片,源代码是针对芯片上具体的处理器核编写的。它不是用于在给定的任何一个处理器核中运行,因为每个处理器核都是通过一组I/O和外面连接起来的。这个源代码是针对某个处理器核编写的,也只对这个处理器核是有意义的。这并不是这个方法的缺点,因为系统是确定的,例如是一个照相机,不是说现在是相机,下一次是面包烤炉。如果处理器核在各个时刻的任务是不同的,你会提出需要一个控制程序,例如中央操作系统。但是这和嵌入式处理器的概念是完全不一样的,是没有中央操作系统的。

这就提出了一个问题。例如,个人计算机不只是有一个操作系统,他们还有BIOS(基本输入输出系统),这是已经装在计算机中的操作系统。在系统中,BIOS执行最基本的I/O驱动程序。嵌入式多核处理器不需要中央操作系统,但是它仍然需要基本的输入输出驱动程序。如果我们要避免使用共用的中央存储器,我们就要接受这样的想法:每个处理器核要有它自已的BIOS。

既然每个处理器核有自己的ROM存储器,它就可以有它自己的BIOS。除了简单的输入和输出功能,处理器核的BIOS还有各种帮助你使用的子程序。这些BIOS子程序不是简单地考贝、复制芯片上每个核中ROM的内容。它们必须个别地处理处理器芯核的问题。虽然处理器核都是一样的,它们在芯片上的位置是不同的。有一些是连接到某种类型的I/O上,有一些是连接到其他处理器核上。在芯片中间的处理器核除了共用寄存器(用于处理器核之间交换数据),可能就没有外部I/O。

多个I/O接口

随着嵌入式处理器从原来的8048/8051发展到现代的处理器,I/O的性质也改变了。不论我们是讨论单个的处理器还是多核处理器,都是这样。因此,原先简单的并行I/O线加上串行接口是足够的了,今天的芯片必须和其他预先定下来的接口连接,例如USB、1394以及SPI(串行协议接口)。

现在,有数百种外设芯片使用SPI接口,也有处理器芯片提供SPI接口(或者多个SPI接口),于是出现了功能强大的而且便宜的外设功能,可以很容易地纳入到系统中。

可扩展的嵌入式处理器核阵列

我们上面在讨论多核芯片时没有讲到它的布置,没有讲这些处理器核是如何安排的。但是,如果这些处理器核是一样,且不讲它们的ROM内容,那么,阵列中的处理器核数量完全随意,是根据具体应用系统对处理能力的要求,由尺寸大小的经济性来决定的。

在布置芯片时,只要简单地复制处理器核,就可以将它扩展──如果完成一件工作,处理器核的数量不够,就增加一个或者增加几个。许多用于处理器核之间交换数据的电路也可以用于芯片与芯片之间交换数据。相应地,增加几块芯片,处理器核、存储器和I/O的数量便增加了,就可以扩展应用系统。

作者:David Guzeman, IntellaSys公司市场总监

美国加利褔尼亚州Cupertino市

Advertisements