OpenGL程序设计笔记 #1

Posted in Uncategorized | No Comments »

#include <windows.h> // Standard Header For Most Programs

#include <gl/gl.h> // The GL Header File

#include <gl/glut.h> // The GL Utility Toolkit (Glut) Header

float rquad; // Angle For The Quad

int main ( int argc, char** argv )

{

glutInit ( &argc, argv );

//这是用来初始化glut的部分,所以一定要写在所有glut函数的前面。

glutInitDisplayMode ( GLUT_RGBA | GLUT_DOUBLE );

glutInitDisplayMode()用来设置显示方式,上面列出的显示方式为GLUT_RGBAGLUT_DOUBLE,分别意味着使用的是RGBA[Red, Green, Blue, Alpha]和双缓冲。此函数可以选择的参数有以下几类:

1. 颜色显示方式,包括GLUT_INDEXGLUT_RGBA,后者为默认,使用前者会覆盖后者。如果使用GLUT_INDEX,那么后面选择颜色就要使用glIndexs()来指定调色盘中的颜色,而前者则使用glColor*()函数来指定颜色

2. 缓冲区选择,包括GLUT_ACCUMGLUT_ALPHAGLUT_DEPTHGLUT_STENCIL四种不同的缓冲区。在开始的时候并不一定会用到它们,但是还是在这里说明一下。OpenGL中有四种重要的缓冲器,分别是Accumulation buffer, Alpha buffer, Depth bufferstencil buffer

Accumulation Buffer是一种数据结构,它包含了需要绘制的像素的RGBA信息。Accumulation Buffer提供了由Accum函数支持的5种操作,分别是ACCUMLOADRETURNMULTADD。用这五种操作将一个新的值累加至这个缓冲器当中。关于Accumulation buffer的具体内容可以参考
http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node106.html
http://www.cs.uiuc.edu/class/sp05/cs419/accum/accum.html

Alpha Buffer其实是Color Buffer中的一部分,里面保存了每个像素的Alpha值,也就是透明度

Depth Buffer保存了每个像素点的深度信息。比如两个空间中的三角形,前面的对后面的构成了遮挡,那么后面那个三角形中被遮挡的部分的depth就会和前面的不一样,这部分的像素就不会被画出来。

Stencil Buffer顾名思义代表一张“蜡纸”。在应用此模式绘图时,首次绘图可以指定那些位置被刻下来那些位置不刻,那么在接下来绘图的时候就可以只绘制被刻的部分。

3. 指定缓冲方式,包括GLUT_SINGLEGLUT_DOUBLE,前者为单缓冲,默认,后者为双缓冲,使用时会覆盖掉SINGLE选项。双缓冲的原理有点类似电影院里两台放映机。

glutInitWindowSize ( 500, 500 );

初始化窗口大小

glutCreateWindow ( "NeHe's OpenGL Framework" );

创建窗口

glutFullScreen ( );

全屏

InitGL ();

初始化GL设置。注意和前面的glutInit是不一样地。

glutDisplayFunc ( display );

回调函数,调用你自己写的display函数。所谓回调的意思就是你调用一个库函数,这个库函数又反过来调用你写的函数。你所要绘制的一帧图像的全部内容都需要在display中体现出来。

glutReshapeFunc (reshape);

也是一个回调函数,reshape函数指的是当窗口大小经过调整后会出现什么情况。

glutKeyboardFunc ( keyboard );

回调函数,响应键盘动作。

glutSpecialFunc ( arrow_keys );

回调函数,响应任何其他动作。

glutIdleFunc ( display );

回调函数,指明什么都不做的时候干什么。

glutMainLoop ( ); // Initialize The Main Loop

初始化主循环,回到首次使用DisplayFunc的地方。

上面几个函数的顺序是固定的。

}

void InitGL ( GLvoid ) // Create Some Everyday Functions

{

glShadeModel(GL_SMOOTH); // Enable Smooth Shading

指定Shade方式,OpenGL官方意思是SMOOTH其实是对primitive图形进行了插值处理。

glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background

背景画成黑的

glClearDepth(1.0f); // Depth Buffer Setup

深度缓存器也清零

glEnable(GL_DEPTH_TEST); // Enables Depth Testing

开启深度测试

glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do

深度测试检验函数,里面的参数用来指明传入的像素的深度和已经在缓存区中函数的关系,只有当这个关系的逻辑表达式值为真时才画出来。

glEnable ( GL_COLOR_MATERIAL );

这个还不清楚

glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

一系列的额外选项,参考

http://www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/hint.html

}

void display ( void ) // Create The Display Function

{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer

// glLoadIdentity(); // Reset The Current Modelview Matrix

glPushMatrix();

glLoadIdentity(); // Reset The Current Modelview Matrix

glTranslatef(0.0f,0.0f,-6.0f); // Move Right 1.5 Units And Into The Screen 6.0

glRotatef(rquad,1.0f,0.0f,0.0f); // Rotate The Quad On The X axis

glColor3f(0.5f,0.5f,1.0f); // Set The Color To Blue One Time Only

glutWireCube(1.0f);

glPopMatrix();

rquad-=0.15f; // Decrease The Rotation Variable For The Quad ( NEW )

glutSwapBuffers ( );

// Swap The Buffers To Not Be Left With A Clear Screen

}

void reshape ( int width , int height ) // Create The Reshape Function (the viewport)

{

if (height==0) // Prevent A Divide By Zero By

{

height=1; // Making Height Equal One

}

glViewport(0,0,width,height); // Reset The Current Viewport

glMatrixMode(GL_PROJECTION); // Select The Projection Matrix

glLoadIdentity(); // Reset The Projection Matrix

// Calculate The Aspect Ratio Of The Window

gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);

glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix

// glLoadIdentity();

}

void keyboard ( unsigned char key, int x, int y ) // Create Keyboard Function

{

switch ( key ) {

case 27: // When Escape Is Pressed...

exit ( 0 ); // Exit The Program

break; // Ready For Next Case

default: // Now Wrap It Up

break;

}

}

void arrow_keys ( int a_keys, int x, int y ) // Create Special Function (required for arrow keys)

{

switch ( a_keys ) {

case GLUT_KEY_UP: // When Up Arrow Is Pressed...

glutFullScreen ( ); // Go Into Full Screen Mode

break;

case GLUT_KEY_DOWN: // When Down Arrow Is Pressed...

glutReshapeWindow ( 500, 500 ); // Go Into A 500 By 500 Window

break;

default:

break;

}

}

装饰

Posted in Uncategorized | No Comments »

人永远不会停止装饰。无论是装饰圣诞树,还是打扮自己。装饰其实是一种将灵魂与肉体分割开来的行为,它表现了生物天生的对物的占有欲。当然,如果装饰的对象是自己,那或多或少会有些性的暗示在里面。

之前提到的那篇科幻小说里其实有这样一个情节,就是当时的人工智能以及传感器和材料技术已经足够发达,能够做出通过恐怖谷实验的机器人,那个庞大的宿舍楼里面有一间很大并且很隐蔽的屋子,屋子里面全都是机器人,这些机器人的用途是进行心理治疗,至少这是官方的解释。机器人的面部使用具有重复热塑功能的硅胶,这样用户便可以定制机器人的面部特征。有一台很庞大的服务器用来记录与客户的沟通信息,从而提供更好的服务,当然这些信息也作为政府的重要资料予以保留。后来我也写过很多关于女性外貌机器人的故事,但是当时限于种种原因感觉这是件挺罪恶而且无聊的事情。不过现在回想那时的心理也许会有些新发现。我没能逃出那种对物的驾驭的欲望,并且很少有人能,尽管程度不同。

为什么为美女拍写真的时候,需要把本来光亮的皮肤处理成亚光效果?为什么整齐的齐眉刘海以及干练的BOBO头要比自然垂落的碎发看起来更性感?为什么要穿 ** 把腿包起来,以及穿上情趣内衣要比赤裸着身体看起来更诱惑?道理很简单,有了这些装饰,人就变成了物。灵性的平等的并且捉摸不透的人就变成了可驾驭的物,于是你可以打破一切与人交往的顾虑和禁忌,像对待财产一样去占有,去使用。这个装饰的过程让你摆脱了施加在你身上的道德约束。

那么对于自己的装饰呢?一部分是出于对其他人的性暗示,另一部分则是将自己的肉体转化为物的过程。我想这也许是支撑着时尚界发展下去的一个重要原因。首先,任何人对穿什么好看穿什么不好看都没有概念。我母亲曾经告诉过我,在二三十年前那个对工人阶半夜凉初透级无限崇拜的时代,最流行的就是一身牛仔工装,男人一定要捋起袖子露出坚实的小臂,最好在胸口上溅些油污,绝对会引起姑娘们的侧目。但是到了现在这样的行头却代表了受到社会歧视的一个群体。人们其实并不知道自己穿什么好看,在对着镜子换衣服的时候,人所体验到的快感其实是源自于将自己的身体像一个物件一样用来摆弄。在摆弄之后获得了操纵物欲的高峰体验,嗯看来我有一个我可以接纳的身体,于是兴高采烈地出门了。

再仔细想想,这其实就是QQ秀等其他需要付费的Avatar服务成功的原因。你只要在物理世界中相当小的代价,便可在虚拟世界中获得无法比拟的强大力量。你可以决定你的身高,五官,衣物,也可以决定那些作为装饰品站在你身边的人的身高五官衣物。还有在网络游戏中需要你花钱才能获得的装备,需要你升级才能获得的Avatar衣物。大量通过生产劳动获得的社会财富便消耗到了这无休止的装饰当中,人们却依然乐此不疲。似乎在物理世界中的我们才是臭皮囊,而网络世界的形象才是真身。当然,你看到我小心地回避了“现实世界”这个词,因为没准儿若干年之后网络世界会成为真正的现实世界。

没错,人只要无法摆脱对物的占有,人就永远不会停止装饰。

交互设计闲扯淡(2)

Posted in Uncategorized | No Comments »

The next thing we talk about is the relationship between experience and interaction. Before the discussion, we need to clarify that all human’s experience cannot reflect what the real world is. For instance, we may feel hot when eating chili, and feel cool when chewing mint flavor gum. However, the absolute temperature of our tongue is not changed at that time. Another example, most of us may have dreamt about falling, but your actual movement on your bed may be merely one inch.

We can share the result of our observation to the environment we live, and naturally think the things we see is just the things what we see, the things we touch is just the thing what we touch. We cannot get rid of the limitation of sense because we born so.

So what does the matter with interaction? Okay, here’s the reason. Our experience is different. Some are happy while others are tough. For the sake of metabolism, we need to always keep some food in our digest system. Hence you will have a euphoric experience when eating, drinking (but not too much) and defecating. For the sake of next generation, you will also have a euphoric experience when performing piston movement. That’s the summary from your body to your decision-making system that you are doing “right thing” for your body and your species. We can treat it as a bonus. However, such a bonus some times can be independent from the action of doing “right things”. Because such a bonus can be fabricated! A typical example is masturbation.

That’s the reason why interactive design exists. And, unfortunately, interactive design is just like masturbation somehow. The mission of interactive design is just for bringing human euphoric experience which not able to get in real world.

Okay, next we will concentrate on what euphoric experience people eager.

交互设计闲扯淡

Posted in Uncategorized | No Comments »

现在大型的工业正在逐渐淡出我们的社会,原因是在工业层次上所能满足的供需已经几近于平衡,因此市场上没有更多的机会留给工业继续发展。事实上市场留给工业的机会越来越少,源自于人们对产品不正确的认识。

The huge conventional industries are fading out from our society, because the balance of the supply and demand is almost achieved, and no more chances are left for newer industry in the market. Actually the industries are experiencing a sort of change, and our definition on industry and product are also changed.

我们都知道按照一般的说法,产品必须得具有使用价值才能被用来交换,或者更具体地说产品具备满足消费者某些方面的需求的能力才能被用来交换,为生产者带来利润从而养活自己并且继续投入生产。但事实上人们忽略了一个很严重的问题,就是消费者从购买产品起,到他的需求真正被满足的这个过程,有相当长的时间 [甚至长于产品制造的时间],是由消费者自助地满足其需求的。这就是关键所在,消费者的需求得到满足是一个过程,这个过程不仅包括依赖的物质材料,也需要一个动作的发起者来执行这个过程。按照这种划分,一般提供满足需求的是工业,而执行这个过程的行业叫做服务业。但遗憾的是,直到本世纪初,普遍的舆佳节又重阳论观点仍然认为工业是首要的而服务业是从属的。

It’s known that product must be associated with some certain value of use, or it cannot be bartered, so that to make the producer live and go on producing. The value of use is considered as the ability of satisfying some certain requirements. However, a serious issue was ignored for long time. There is a long period from the goods are produced until the demand of consumer is satisfied, is the execution of the consumer themselves.

仔细一想我们现在的世界其实很混乱,因为根本没人关心别人需要什么。我们 [大部分人] 拿着辛苦劳动赚来的钞票面对着琳琅满目的产品却无所适从,原因是没有人告诉我们它会为我们带来什么 [当然我们手里的钞票也是通过我们生产让别人无所适从的商品中得来的]。这就是你为什么会感到当你面对着各种选项时却会感觉这根本不是所谓的选择,因为你并不了解这些选项到底对你有怎样的不同,然而对于你别无选择的是,你不得不拿钱去把它们其中的一些买下来。

For a more cautious inspection, our world is just experiencing a sort of chaos, because no one really cares about other’s need. Most of us, holding the money earned from hard work, just feel confused when looking at various commodities, because no one tells us what they will bring us. That is why you think such choice can hardly to be “choice”, because all options are same unknown, and you have to buy them with your money.

我的想法是,如果人们都乐意支付服务的话,那么也许“商品”的概念就会淡出我们的视线了。高中的时候我曾经写过一个没写完的科幻小说,那是看了一集Discovery后的感觉。由于人口的增多以及环境的恶化等诸多因素,导致政府最终不得不停止商品房的销售,而所有的非农业用地 [当然农业用地也已经很少] 则兴起了名叫“垂直街区(Vertical street)”的计划,盖起了高达一百多层,占地面积为二至三公顷的建筑物。当然这种建筑物是经过精心设计的,包括采光和其他智能化设施。不过为了降低环保成本,每户居室都禁止使用炊具,街区内有公共食堂提供全世界各国风味的饭菜。居室也禁止自己洗衣服,街区内提供了一套洗衣设备可以确保你的衣服干净无菌,并且你还可以定制洗完衣服后散发出来的香味。规格可以参考现在医院或者宾馆所使用的洗衣设备。你也没有私人浴室,街区提供了刷卡服务的公共浴室。你如果要喝水,那么就得用楼宇特别配发的饮水瓶到饮水机那里接水,如果用别的瓶子你接不到水;如果你不用嘴对着瓶子喝,瓶子的水也不会倒出来。因为你购买的是饮用水。确切地说,你购买的不是水,而是饮水的服务。在那个故事里面没有商品,只有服务。你的一切生活需求都被最大化地以集约式服务的形式满足,而你的居住也是服务,你的12平米的房间为你提供了休息以及保护隐私的服务。

From my aspect, if everyone would like to purchase for service, then the concept of “Commodity” will soon be fade out from our sight. I have an unfinished sci-fi, which can be a summary of an episode of Discovery. In that story, the government had to stop the house business because of the continuous growth of population and environmental deterioration. At the same time, the government also carried out the plan called “Vertical Street”, skyscraped huge concrete totem as high as one hundred floors, and as wide area as 2 or 3 hectors. Of course these buildings are carefully designed, including lighting and other intelligent facilities. However, for the sake of the cost of environmental protection, kitchenware is banned. The public cafeteria provides food with worldwide flavor. Home washing machines are also forbidden because of same reason, and the public laundry can keep your clothes clean and away from microbes. You can even customize the aroma of your clothes after washed. You are not allowed to own your private bathroom, public bathroom are also provided. If you want to drink water, you need to use special intelligent bottle to get water from the water dispenser. You won’t get water if you use other bottle, and you won’t get the water from the bottle unless your mouth touches it. Because you purchased for drinkable water, or more exactly, you purchased for the service of drinking water. In the story, there is no commodity, but all with service instead. Your demand can be satisfied by these services, while you don’t have any possession.

当然这不是物质匮乏的共人比黄花瘦产主义社会,同样有很奢侈的服务可以供你享受,你可以肆意挥霍水,当然前提是你有足够的可以肆意挥霍的钱,当然还有另外一些更有情趣的服务,不过那是另外一个故事里的内容。你用来挥霍的水和你引用的水完全一样,为什么价格的差别那么大?因为后者带给了你完全不同的体验。

Windows下Eclipse编程环境设置

Posted in Uncategorized | No Comments »

昨天设置好了Eclipse + CDT + MinGW以及相关的设置,写了一个OpenGL程序,并且参照Processing的源代码把它修改的更加复杂。如果仅是绘图部分,OpenGL和Processing以及OpenFrameworks的BeginShape部分基本是一样的。但如果要引入更多的功能,显然仅靠OpenGL所提供的API是远远不够的,所以需要设计更复杂的抽象数据结构。

在Eclipse下设置OpenFrameworks的方法首先参考官方文档:

http://www.openframeworks.cc/files/ofeclipse_tut/openframeworkseclipsewrksp.html

如果要在Eclipse中直接应用OpenGL的API进行编程,使用了MinGW所提供的C/C++编译器,所以要使用MinGW所对应的GLUT库。注意,不同编译器对应的GLUT库也是有区别的,具体可以参考

http://www.transmissionzero.co.uk/computing/using-glut-with-mingw/

我参阅了若干个配置Eclipse+ MinGW + GLUT的文章,但是只有上面这个可以正常运行。有些所提供的库的头文件和编译器是有冲突的。

另外需要说明的是,OpenGL并没有提供像Processing以及OpenFrameworks中的基本图形 (primitive graphics),所以需要自己写对应的函数。这个可以参考Processing或者OpenFrameworks的源代码来写。OpenFrameworks可以确定是使用了OpenGL,但是Processing的图像引擎从源代码来看是Ben Fry自己写的PGraphics3D,我想效果会比OpenGL差一些。

关于计算

Posted in Uncategorized | No Comments »

接下来就要讨论计算的过程。我们不直接讨论什么才是计算,因为这个以我的水平实在说不清楚。但是既然我们能够放心地把一些计算任务交给计算机去做,那么从计算机的角度来看或多或少能够触及计算的本质内容。从上一篇对CPU的讨论,我们便能够知道,计算机做的事情,就是按照特定的次序,对状态载体按照一定的规则进行改变状态的操作。指令指针,寄存器以及在算术逻辑单元中固化的硬件电路恰好能够对应这三个要素。

在前一段时间,我终于接触到了实质上的编译器构造工作。设计一种新的语言,包括建立对应的Lexer和Parser,对于某些模式的匹配,对应到target language,也就是实际能够产生动作的语言中去。然而对于Terence Parr而言,ANTLR不过是个工具,他真正推崇的其实是StringTemplate,也就是字符串模板。利用字符串模板以及一些用户定义的代换规则,即可实现计算的过程。这个过程是图灵完备的,因为它恰恰就是在做图灵机做的事情。后来我想,如果应用类似的机制实现一种BinaryTemplate,那么它不仅能够实现完备的计算,并且还能够真正控制计算机的动作,同时还能够完全地解析一切存储于计算机中的信息。它的框架大概是这样:

1.文法规则:

这部分基本上和正则表达式的内容一致,在这里我用了类似Mathematica的记法,所以就不需要使用圆括号了。

BinaryPattern: (0|1)* 所谓的二进制模式就是一串0和1,在BinaryTemplate中一切都是BinaryPattern。

Optional[BinaryPattern] 代表有没有都可以

Duplicated[BinaryPattern] 代表至少有一个重复的BinaryPattern

DuplicatedZero[BinaryPattern] 代表既可以没有,也可以有一个或多个

Alternate[BinaryPattern1, BinaryPattern2, ...] 代表若干个BinaryPattern中的一个

2.运算规则:

运算规则基本同汇编指令的算术逻辑指令相同(这就是为什么我要去做底层的原因)

算数指令包括Plus, Subtract, Multiply, Quotient和Divide

逻辑指令包括And, Not, Or和ExclusiveOr

位移指令包括ShiftLeft, ShiftRight, RotateLeft, RotateRight

3. 替换规则:

替换规则并不是描述数据的,而是描述代换过程的。

ReplaceAll对整个BinaryStream检索一次,匹配BinarPattern并进行替换

ReplaceRepeated对整个BinaryStream检索若干次,直到没有任何可用的规则为止

CPU

Posted in Hardware | No Comments »

最近看了很多关于处理器方面的知识,包括来自Atmel的AVR系列8位单片机,还有ARM的Cortex M-3。当然不可避免地重新温习了一下CPU内部结构以及指令集相关的内容。驱使我由很抽象的语言层次重新转回和我专业紧密相关的嵌入式系统的原因是,原来由general purpose计算机所完成的任务正在不断分化,比如音频视频以及通信等都有了实现单独功能的可移动设备。人们已经越来越意识到多功能的综合系统并不方便使用,并且设计和维护都十分困难,并且技术上的简约主义已经得到了世界范围内的认可,因此可以预计计算机最终的功能一定会回归到真正的计算。在我看来,每一个拥有计算机的人都应当弄明白计算机为什么能够计算,这样才能真正控制计算机,否则人就会被计算机控制。接下来我们先讨论一个一般的 (也就是抽象的) CPU的组成和工作方式,然后再讨论它为什么这样设计,最后再讨论到底什么是计算以及为什么计算机能够计算。

我们大家似乎都听说过计算机的内部是以“0”和“1”来表示数据的。当然不管是以什么来表示,这些抽象的符号必须得具有一个具象的载体,就好像我们写字总是需要一个写字的地方,比如纸,沙地以及旅游景点的柱子上。计算机当然不能用纸来记录数据 (尽管最开始的名为图灵机的抽象计算机确实是这么设计的) 因为频繁的改写会对纸张造成不可修复的损耗,它所使用的载体叫做触发器,至于触发器是什么东西你并不需要了解,你只要知道它就像纸一样在上面写字字就会留在上面并且如果想擦也能擦得掉可以了。计算机的内存储器就是由触发器构成的庞大阵列。在CPU中所使用的存储器非常快速,叫做寄存器。CPU内所有的运算过程都是围绕着寄存器实现的。

首先是最简单的栈寄存器,栈寄存器的操作和我们在数据结构中所见到的描述是一样的,只有压栈和出栈两种操作。描述栈的时候一般喜欢使用类似弹匣或是纸杯架这样的实物进行描述,但是在CPU中所有的状态都是电位而不是实物,因此压栈和出栈并不是通过移动实物,而是通过状态的覆盖实现的。栈寄存器有一个小的计数器用来记录最近加入的数据存在了哪个位置,如果有新的数据压入那么就让这个小的计数器指向这个新数据的位置,如果是弹出数据并不像你想象中的先把这个位置清零再让小计数器记录它前面数据的位置,而是仅有后面的步骤。因为这个计数器指向前一个位置,就在声明后面的东西不是栈里面的内容别的指令可以随便修改。这样的结果是,即使你使用了出栈操作,在压入新的数据之前,访问那个位置你仍然会获得同样的内容。对于栈寄存器的操作只有压栈和出栈两种,压栈和出栈的内容分别可以是通用寄存器中的内容,或者是状态寄存器的内容。

接下来是通用寄存器。在通用寄存器上实现的操作很简单,只有两种。一种是 1) 找到特定的位置,然后以这个位置中的内容作为数据,然后按一定规则改写。另一种是 2) 找到特定的位置,然后以这个位置中的内容作为内存中的另一个位置,然后再在内存中找到这个位置,然后按一定规则改写。需要注意的是,CPU是不能直接读取内存中的内容并进行改写。2) 中内存中的数据必须得先读到寄存器中,这个过程实际上当然就是以内存中的数据覆盖寄存器中某个位置的数据了,然后再按照1)的方式进行操作。尽管原理很简单,但是这些操作可能会有很多种变化。变化可能来自寻找特定位置的方式,这个特定的位置既可以由程序员直接确定,也可以通过已经保存在寄存器或内存中(呃已经说了内存中的还是必须移动到寄存器中)的数据确定,同时寻找位置既可以直接确定位置,也可以先确定一个地区,然后再在这个地区中确定一个位置。当然更为复杂的变化则来自于改写的规则。这些规则太过复杂以至于必须得有一个专门的机构实现,这就是“算术逻辑单元”。可以应用在通用寄存器上的操作有两组,一组是传送指令,就是用存放在某一个给定位置的数据,覆盖掉另外一个给定位置的数据;另外一组就是算术逻辑指令,通常读取特定位置的数据,然后将运算的结果覆盖原来存放数据的位置。

状态寄存器顾名思义是用来记录状态的。这些状态包括做加减法时有没有进位或者借位,两个数字相减的结果是正是负还是零,以及栈有没有溢出等等。状态寄存器一般是不能由程序员直接修改的,而是由其他指令执行的过程中对它进行修改 (最主要的就是算术逻辑指令)。而还有一系列叫做控制流的指令会用到状态寄存器,它们会依据状态寄存器所记录的状态来确定下一步要用哪些指令。

最后的寄存器是指令寄存器和指令指针寄存器。指令寄存器的内容是按照指令指针寄存器中所记录的存放指令的地址所获取的指令,获取指令这个动作是自动进行的 (否则计算机就运转不起来了)。指令指针寄存器的内容则是可以修改的,修改它的便是上面提到的控制流指令。

以上便是CPU最重要的部分。接下来就是计算机执行指令的过程。程序解释成指令之后,也是存放在某一个地方然后一条一条往出取的。一条指令从指令序列取出后,就被放到了指令寄存器中。然后一个译码器将这个指令翻译成机器代码,发送给对应的执行机构去执行。执行过程如图所示:

11

CPU工作流 (lovelycharts.com是一个蛮不错的在线diagram软件)

在多条指令的存取过程中便大有文章可做了。最早的处理器,第二条指令的取指令过程,必须得等到第一条指令执行完才能够完成,于是接下来产生了两种技术来对这个过程进行优化。第一个叫做流水线优化,在第一条指令被译码的过程中,取指令的器件已经开始取第二条指令了,在第一条指令被执行的过程中,译码机构已经在翻译第二条指令了,而取指令的器件已经在取第三条指令了。这样的话能够大大缩短整个指令序列的执行时间,但是能够进行流水线优化有两个必要的前提,就是对于一条指令取指令、译码、和执行所花的时间都一样,并且不同指令的这三个过程都一样。第二个叫做超标量优化 (这个主要是用在Intel处理器中,首次出现在Pentium处理器) ,原理很简单,就是一次取两条指令,分别进行取指令、译码和执行,在取指令的时候超标量器件会判断两个指令如果没有共享资源,那么就可以放进两个流水线里面同时执行。[之所以叫做超标量只是因为它名字听起来比较酷,其实所谓的标量处理器就是在一个单位时间内只对一两个数据进行操作,而很早就已经出现了一个单位时间内对若干个数据进行操作的模型,就是传说中的超长指令字(Very long instrction word, VLIW),它是矢量处理器,因此超标量就是把它们略为混合了一下]。

最后就是它为什么要这样设计。其实这就是我们做事的过程。今天你有很多任务,需要给客户打电话,需要查阅询问邮件并且回复,然后去写关于反馈的报告并在下班前交给老板等等。事情得一件一件做,当你看到“给客户打电话”时(预取),你知道你要去拿起电话然后翻开通讯录(指派),然后你要去挨个打电话(执行),最后把谈话的内容写到你的工作日志里面去(写回)。一件事情就是这样完成的,你要知道它,知道怎么实现它,然后去实现,最后留下有意义的结果。如果最后没有把结果留下来,你会忘掉,然后这件事就相当于没做。

由于所有的事情都是这样完成的,因此你会发现CPU的结构和操作几乎是类似的,而且汇编代码的样子也几乎是一样的。