CPU 是数字处理系统中的一个重要环节。在我看来,单片机、微处理器、dsp 都可以称作是 CPU,只是它们的侧重点有所不同罢了。具体来说,传统意义上的单片机更偏重于嵌入式的计算,比如说我们经常使用的 51、avr、arm 芯片中不仅仅含有了运算和控制功能,它还涵盖了定时器、串口、并口、usb、i2c 总线等外部资源。dsp 呢,CPU 一般只是作为 dsp 的一个核存在,它通常还会包含另外一个核,专门用于数字信号的处理工作。而微处理器,也就是我们经常说的 pc 上的处理器,它的工作比较单一,专注于计算和控制功能的处理,因此一般来说在这方面的性能上面,单片机和 dsp 都是不能和它相比的,有了南桥芯片和北桥芯片的帮助,pc 的微处理器就可以专注于自己的本职工作了,效率上面也会有一个很大的提高。

 

对于朋友们来说,生活中遇到的最多的 CPU 其实是 x86 的 CPU。当然,如果有哪位朋友喜欢 apple 之类的玩具,也会知道一些 arm 的相关事情。剩下的就是一些专用领域的 CPU 了,比如说在通信行业用到的比较多的 powerpc 芯片,在高性能服务器用的到的 sun sparc 芯片,在科学计算领域使用到的 mips 芯片。所以,无论遇到什么芯片,对于应用层开发的朋友都是一样的,只是在一些小地方需要还有一些注意的地方。比如说,

(1)数据的对齐方式

(2)数据的字节序问题

(3)函数参数的压栈问题

(4)CPU 的乱序执行问题

(5)CPU 中 cache 和内存一致性的问题

 

当然,如果我们所要思考只是简单的应用层设计,考虑到这些内容本身已经实属不易了。然而,我们考虑的是如何设计嵌入式操作系统的问题,所以接下来还要看看一般 CPU 下面都包含了那些内容。这样,只要熟练掌握了一款 CPU 的设计和实现,对其他 CPU 的知识也会触类旁通了。

 

任何一款 CPU,不管是完成的功能是什么样的,通常都会有这样一些基本设计:

 

(1)寄存器

    堆栈寄存器   

    pc 寄存器

    状态寄存器

    运算寄存器

 

    寄存器是 CPU 内部的基本资源。不管 CPU 的代码执行到什么时候,这些资源都是共享的,所以在 CPU 发生中断、函数调用、线程切换的时候,都需要对这些寄存器进行保护,常用的基本措施就是把把它们保存到临时堆栈当中去。堆栈寄存器记录了当前堆栈使用到了什么地方,pc 寄存器则记录当前代码跑到了什么地方,下一条指令在什么地方等。状态寄存器则保存了当前 CPU 的执行情况,包括计算有没有溢出、中断是关还是开、有没有 o 除数异常等等。至于运算寄存器就因 CPU 而异了,有的 CPU 寄存器比较少,比如说 x86 的寄存器;有的 CPU 寄存器就比较多,比如说 powerpc。运算寄存器的用途很多,比如说数据访问、计算、移位、返回计算结果等等。

 

(2)指令集

    寻址指令

    数学运算指令

    逻辑运算指令

    软中断指令

    跳转指令

    远程调用指令

    io 访问指令

    栈操作指令

 

指令集在某种程度上直接决定了某一种 CPU 的类型。就像 intel 和 amd 生产的 CPU 虽然有差别,但是它们的 CPU 使用的都是 x86 的指令集,而 marwell、samsung 和高通生产的 CPU 当然也不同,但是它们的指令集都是 arm 指令集。所以,如果软件在 marwell 上跑,一般来说也可以在 Samsung 上跑起来。指令集很复杂,内容很多。但是通常来说,上面这些内容都是 CPU 所必须要完成的几种指令。当然重中之重的还是中断和栈处理指令。

 

(3)中断、异常处理机制

不管是什么 CPU,中断部分的内容都是少不了的。试想一想,如果一颗 CPU 只知道不停地运行,那么它的执行效率实际上是很低的。拥有了中断的 CPU 不仅使得 CPU 可以和更多的外设 io 打交道,还能极大地提高自身运行的效率。不同的 CPU 处理中断的方法其实都差不多,在整个 CPU 的地址空间里面,通常在低地址区域会有一张中断向量表,表中每一项记录了每一个中断对应的处理函数。所以,只要中断发生时,CPU 就会首先将下一条 pc 地址压入堆栈,然后跳转到中断向量表中对应的中断地址处执行的相应的处理函数。这个过程是 CPU 自动完成的,不需要我们关心。这样对我们来说,它和 CPU 中的函数调用其实没有什么区别。等待中断处理结束后,我们使用 ret 指令返回到之前压入的那个 ip 地址处,继续下面的代码。整个过程就好像中断根本没有发生过一样。

 

所以,对于 CPU 的了解其实主要就是对寄存器、指令集和中断的了解。有了对中断和堆栈的深入理解,其实也就没有什么困难的了。在这里我们大家可以考虑一个问题,如何在 Windows 或者 linux 下仿真中断完成我们的操作系统开发呢?大家可以自己先思考一下,我们会在随后的博客中继续介绍。整篇文章,我们没有介绍编码的相关内容,其实只要把这里的基本概念弄清楚了,剩下来其实就是一些流程性的工作了。在软件开发中,设计其实是最难的,剩下的才是开发和调试。