第五章LC-3在第四章中,我们讨论了计算机的基本组件:存储器,处理单元(包括相关的临时存储单元,通常是一组寄存器),输入和输出设备,以及控制所有单元(包括它本身)行为的控制单元。我们还介绍了指令周期的6个阶段:取指令,译码,计算地址,取操作数,执行和存储结果。下面,我们就准备研究一个“真实”的计算机——LC-3,确切的说,是介绍LC-3的指令集结构(ISA)。在第四章里,已经对其行为和其中的几条指令作了介绍,本章将深入研究LC-3的指令集结构。在第一章中我们曾经提到,指令集结构是软件命/指令和执行命令的硬件之间的接口,在本章以及第八章和第九章,我们将指出LC-3的指令集结构的重要特性。利用这些特性,就可以使用LC-3自己的语言编写程序,即LC-3机器语言。附录A包含了有关LC-3指令集结构的详细信息。5.1指令集结构:概要指令集结构(ISA)指明了在一台机器上编写软件时所要注意的全部信息。换句话说,ISA规定了程序员使用机器语言编程时的全部信息。对于那些将使用高级语言,如C、Pascal或Fortran、COBOL写的程序翻译成计算机机器语言的人,ISA也提供了关于该计算机的所有可用信息。ISA规定了存储器的组织,寄存器集和指令集,包括操作码,数据类型和寻址模式。5.1.1存储器组织LC-3的存储器有216(即65536)个地址空间的单元,16位的寻址能力。不是所有的65536个地址都用作存储单元,对此我们将在第八章作详细说明。既然LC-3通常处理的数据单元都是16比特大小,我们把16比特称作一个字,我们说LC-3是字可寻址的。5.1.2寄存器鉴于从存储器中读取数据花费的时间通常远长于一个机器周期,LC-3(像大多数计算机一样)提供了可以在一个机器周期内访问数据的附加的临时存储空间。最常用的一种附加临时存储空间就是LC-3所采用的是通用寄存器集。这个集合中的寄存器都被称作通用寄存器(GPR)。寄存器拥有和存储单元相同的性质――可以用来存储信息,这些信息不久后就会被读取。存储在每一个寄存器中的位数通常是一个字。在LC-3中,意味着是16位。寄存器必须是能够被唯一识别的。LC-3定义了8个通用寄存器,使用3位编码来识别,分别被标记为R0、R1……R7。图5.1显示了LC-3的寄存器集的一张瞬态图,有时被称为寄存器堆,在R0,R1……R7中分别存储1,3,4,7,-2,-4,-6和-8这8个值。回忆(第四章)把R0和R1中的数值相加得到的结果存入R2中的加法指令为:15141312111098765432100001010000000001ADDR2R0R1这个加法指令的两个加数用[8:6]位和[2:0]位表示,相加的结果存入的目标由[11:9]位表示。图5.2显示了在ADDR2,R1,R0指令执行之后的图5.1的寄存器堆的内容。5.1.3指令集一条指令由两部分组成,即它的操作码(指令让计算机做的事情)和操作数(计算机操作的对象)。ISA的指令集是由一组操作码、数据类型和寻址模式定义的。寻址模式决定了操作数位于什么地方。前面的例子就是一个操作码为ADD,寻址模式是寄存器模式的指令。该指令的操作是让计算机做二进制补码整数的加法,计算机寻找的操作数的位置是位于通用寄存器中的。5.1.4操作码有些ISA有一个非常大的操作码集,每一个操作码对应了一个程序中可能要执行的众多任务中的一个。有些ISA则拥有一个非常小的操作码集。有些ISA有专门的操作码来处理科学计算,例如,HP的PrecisionArchitecture中有一条指令是执行一个先乘后加的如(A*B)+C的三目运算。而有些ISA有用来处理从万维网获得的视频图像信息的指令,如Intelx86ISA加入了许多被称为MMX的指令,因为它们扩展(eXtend)了ISA指令集以帮助处理网络上的多媒体(MultiMedia)应用。还有其他的一些ISA加入了专门的操作码来帮助支持操作系统的任务,例如在二十世纪八十年代盛行的VAX体系,有一个专门的指令,用来在一个正在运行的程序切换到另一个程序之前,保存那个正在运行的程序的所有信息,而几乎所有的计算机都用一长串的指令使计算机实现保存那些信息的任务。当一个新的ISA被定义时,关于某条指令的去留问题,总是要有一番激烈的争论。LC-3ISA有15条指令,每一条指令由不同的操作码来区分。操作码是由指令的[15:12]位定义的。既然有4位用于操作码,其指令就有16种可能。然而,LC-3ISA只定义了15条指令,1101码未被定义,被保留下来,用于我们今天还不能预测到的将来的需要。有三种不同类型的指令,即三种不同类型的操作码,分别是:运算,数据传送,控制。运算指令处理信息,数据传送指令在存储器和寄存器之间或在寄存器/存储器和输入/输出设备之间传送数据。控制指令改变指令被执行的顺序。换言之,它们使某一条指令而不是位于存储器中下一个位置的指令被执行。图5.3列出了LC-3的15条指令,[15:12]位代表各操作码。每指令的使用将在随后的第5.2、5.3和5.4节来阐述。5.1.5数据类型数据类型是信息的表示方法。在计算机里有许多方法来表示相同的信息。在日常生活中,我们也使用许多不同的方法来表示相同的信息。例如,当我们问一个小孩,他有几岁时,他也许会伸出三个手指,代表三岁;他也许可以写下数字“3”;如果他是一个学计算机科学或计算机工程专业的大学生,他也许写下16位的二进制数0000000000000011来代替;如果他是化学专业的学生,可能使用3.0100来表示。这四种都是3的表示方法。如果ISA中有一个操作码能对某种数据类型表示的信息进行运算,我们就说该ISA支持这种数据类型。在第二章,我们介绍了LC-3的ISA支持的唯一一种数据类型:二进制补码整数。5.1.6寻址模式寻址模式是一种指示操作数位置的机制。一般地,可能在三个地方找到操作数:存储器,寄存器,或指令中的一部分。如果操作数位于指令中的一部分,我们称之为字面或立即数。“字面”源于指令的若干位字面上构成操作数的事实,“立即数”源于我们可以立即从指令中获得操作数的事实,也就是说,不用去别处寻找。LC-3支持五种寻址模式:立即数(或字面),寄存器和三种存储器寻址模式——PC相对,间接,基址+偏移量。我们将在5.2节中介绍使用了两种寻址模式的运算指令:寄存器和立即数。在5.3节中介绍使用了五种模式的数据传送指令。5.1.7条件码大多数ISA允许基于前一条指令产生的结果改变指令执行的顺序。LC-3有三个一位的寄存器,每当八个寄存器之一被改写时,它们可被设置为0或1。这三个一位的寄存器被称为N,Z,P。相应的意义:负数,零,正数。每当一个GPR(通用寄存器)被改写时,N,Z,P寄存器就会根据写到GPR的结果是否为负数,零,正数,分别设为0或1。也就是说,如果结果为负数,N为1,Z和P清0;如果结果为0,Z设为1,N、P为0;结果为正数,P为1,N、Z为0。这三个寄存器被称为条件码的原因是可用此位作条件,来控制指令的执行顺序。x86和SPARC是两种使用条件码的ISA的例子。我们将在5.4节中介绍LC-3如何使用条件码。5.2运算指令运算指令对数据进行处理。常见的例子包括算术运算(像加、减、乘、除)和逻辑运算(像与、或、非、异或)。LC-3有三个运算指令:加、与、非。NOT指令(操作码是1001)是唯一一个进行一元运算的指令,也就是说,这个指令要求有一个源操作数。这个指令对一个16位的源操作数按位取反后把结果存入一个目标中。NOT对源操作数和目标操作数都采用寄存器寻址模式。[8:6]位对应的是源寄存器,[11:9]位对应的是目标寄存器,[5:0]位必须全部包含1。如果R5一开始存储的是0101000011110000,执行下面的指令后:15141312111098765432101001011101111111NOTR3R5R3中将会包含1010111100001111。图5.4显示了用来执行NOT指令的数据通路的关键部分。既然NOT是一个一元运算,对于ALU,只有A输入是相关的。源操作数来自于R5,指挥ALU的控制信号是执行按位取反运算,ALU的输出(运算结果)被存储于R3中。ADD(操作码是0001)和AND(操作码是0101)指令都执行一个二元运算;它们需要两个16位的源操作数。ADD指令对两个源操作数执行一个二进制补码的加法运算。AND指令对它的两个16位源操作数执行一次按位与运算。像NOT一样,ADD和AND对其中一个源操作数和目标操作数采用寄存器寻址模式。[8:6]对应源寄存器,[11:9]对应目标寄存器(结果将被写入的地方)。ADD和AND的第二个源操作数可以通过寄存器寻址模式或立即数模式得到,由[5]位决定使用哪种方式。如果[5]位是0,那么第二个操作数要使用一个寄存器,[2:0]位对应着这个寄存器。这时,[4:3]位被全部设为0。例如,如果R4中存储数值6,R5中存储数值-18,执行下面的指令后:15141312111098765432100001001100000101ADDR1R4R5R1将会被写入数值-12。如果[5]位是1,第二个源操作数就被包含在指令当中。事实上,第二个源操作数是在执行ADD或AND操作之前,将[4:0]位执行符号扩展到16位得到的。图5.5显示了用来执行ADDR1,R4,#-2指令的数据通路的关键部分。既然ADD或AND指令的立即操作数必须位于指令的[4:0]位中,就不是所有的二进制补码整数都可以是立即数,那么,哪些整数可以用作立即数?例5.1下面的指令是做什么的?15141312111098765432100101010010100000答案:寄存器R2被清空。(也就是,被全部设为0)例5.2下面这条指令执行什么操作?15141312111098765432100001110110100001答案:寄存器R6加1(就是说,R6R6+1)注意:在同一条指令中一个寄存器既可以作为源操作数也可以作为目标操作数。这对LC-3的所有指令都是适用的。例5.3回想一下,取一个补码表示的数值的负数可以通过取反加1得到。因此,假设两个值A,B分别存在R0和R1中,如何执行A减B,再把结果存到R2中?答案:15141312111098765432101001001001111111NOTR1R1R1NOT(B)15141312111098765432100001010001100001ADDR2R11R2-B15141312111098765432100001010000000010ADDR2R0R2R2A+(-B)问题:这组指令还会产生什么不好的结果?怎样做就能避免出现这个结果?5.3数据传送指令数据传送指令可以在存储器和通用寄存器之间,存储器和输入/输出设备之间传送数据。现在我们将不研究怎样将数据从输入设备传送到寄存器和怎样将数据从寄存器传送到输出设备。这将是第八章的主题,同时它也是第九章的一个重要部分。在这一章,我们将集中精力去研究存储器和通用寄存器之间数据的传输。将数据从存储器移动到寄存器的过程叫加载(load)。而将数据从寄存器移动到存储器的过程叫存储(store)。在这两个过程中,源操作数所在位置的内容并没有改变。但目标操作数所在位置的内容被改写,原来的值便被破坏了。LC-3有7种数据传送指令:LD,LDR,LDI,LEA,ST,STR和STI。加载和存储指令的格式如下:1514131211109876543210操作码DR或SR地址生成位数据传送指令需要两个操作数:一个源操作数和一个目标操作数。源操作数是要传送的数据所在的位置,目标操作数是要传送到的位置。在两个操作数中,一个是寄存器,另一个是存储器单元或输入/输出设备。正如我们之前说过的,在本章,假设第二个操作数均位于存储器中。第二个操作数是输入/输出设备的情况我们留到第八章介绍。[11:9]位说明了第一个操作数,寄存器。如果指令是加载,DR指的就是目标寄存器,它将在从存储器读取数据之后,包含该数值(指