购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

1.3 计算机体系结构

前面介绍了计算机历史上的一些重要体系结构和术语,本节将介绍用于构建现代处理器和相关计算机子系统的基本模块。

1.3.1 使用电压电平表示数据值

现代计算机的一个普遍特征是使用电压电平来表示数据值。通常,只使用高、低两个电压电平值,低电平表示0,高电平表示1。

电路中任何点(数字或其他)的电压本质上是模拟的,可以是其工作范围内的任何电压。当从低电平变为高电平或从高电平变为低电平时,电压必须经历介于两者之间的所有电压。在数字电路中,低电平和高电平之间的转换发生得很快,并且电路被设计成不对高电平和低电平之间的电压变化做出响应。

1.3.2 二进制数和十六进制数

无论如何,处理器中的电路都不能直接处理数字。处理器电路元件遵守电学和电子学定律,并只对提供给它们的输入做出响应。驱动这些响应的输入来自程序员开发的代码和输入的数据。例如,将程序的输出解释为电子表格中的数字或字处理程序中的字符,是对处理器内电信号交互的结果赋予意义的纯人工解释。决定将0分配给低电压、将1分配给高电压是解释过程的第一步。

数字计算机中的最小信息单位称为比特(bit,简称位),表示离散值0或1。将多个位组合在一起可以表示更大范围的值。一个字节(byte)由8个位组成。字节是大多数现代处理器可以从内存读取或写入的最小信息单位。直到现在,虽然还有一些计算机使用其他位宽作为可寻址数据项的最小单位,但是8位宽的字节却是大多数计算机的选择。

一个位可以取两个值:0和1。两个位可以取四个值:00、01、10和11。三个位可以取八个值:000、001、010、011、100、101、110和111。事实上,任何 n 位数都可以取2 n 个值,其中2 n 表示将 n 个2相乘。因此,一个8位的字节可以表示2 8 (256)个不同的值。

当执行计算任务时,二进制数格式并不是大多数人的首选,使用诸如11101010之类的数字可能会令人困惑且容易出错,尤其是在处理32位和64位数据时更是如此。为了更容易地使用这些数字,通常采用十六进制数,术语十六进制(hexadecimal)通常缩写为hex。

表1.1 二进制数、十六进制数和十进制数

在十六进制数字系统中,二进制数被分成四位一组。由于每组中有4个位,因此可能的数值个数是2 4 (16)。这16个数字中的前10个数字分配数字0~9,最后6个分配字母A~F。表1.1显示了从0开始的前16个二进制数,以及相应的十六进制数和十进制数。

二进制数11101010可以通过先将其分成两个4位组(1110和1010),然后写成十六进制数字EA来更紧凑地进行表示。4位组有时称为半字节(nibble)。因为二进制数只能取两个值,所以二进制数是以2为基数的数制。每位十六进制数字可以取16个值,因此十六进制数以16为基数。每位十进制数字可以有10种取值,因此十进制数是以10为基数的。

当使用这些不同的数制时,情况可能会变得复杂。形式为100的数字是二进制数、十六进制数还是十进制数?如果没有额外的信息,你就无法进行判断。各种编程语言和教科书都采取了不同的方法来消除这种歧义。在大多数情况下,十进制数字是默认的,因此数字100通常是十进制数。在编程语言(如C和C++)中,十六进制数使用前缀0x,因此数字0x100是十六进制数。在汇编语言中,可以使用前缀字符$或后缀字符h来表示十六进制数。编程中使用二进制值的情况较少,主要是因为十六进制的紧凑性更好。某些编译器支持将0b用作二进制数的前缀。

十六进制数表示法

本书使用前缀$或后缀h来表示十六进制数,具体取决于上下文。使用后缀b表示二进制数,没有前缀或后缀的数字表示十进制数。

位在二进制数内单独编号,位0是最右边的最低有效位。位编号从右向左递增。例如,在表1.1中,二进制值0001b(十进制数1)的位0被置位(set),其余三位被清除(cleared)。在0010b(十进制数2)中,位1被置位,其余位被清除。在0100b(十进制数4)中,位2被置位,其余位被清除。

置位与清除

置位的位其值为1,清除的位其值为0。

一个8位字节可能是从$00到$FF之间的值,相当于十进制范围0~255。当执行字节加法时,结果可能会超过8位。例如,将$01与$FF相加得到$100。使用8位寄存器时,这表示产生了向第9位的进位,必须使用处理器硬件和软件进行适当的处理。

在无符号算术中,从$00减去$01得到$FF,这构成了回绕。根据正在执行的计算,得到的可能是期望的结果,也可能不是期望的结果。在这种情况下,依然需要处理器硬件和软件相互配合进行处理。

如果需要,负值可以用二进制数表示。现代处理器中最常见的有符号数据格式是二进制补码。在二进制补码中,8位有符号数字的范围是-128~127。二进制补码数的最高有效位是符号位:0表示正值,1表示负值。通过对所有位取反、加1并忽略任何向最高位的进位,可以求得任意数字的二进制补码(参见表1.2)。对位取反意味着将0变为1,将1变为0。

表1.2 取反运算示例

需要注意的是,与数学中定义的一致,负零也是零。

二进制补码运算

二进制补码的位运算与无符号数的位运算相同,无论输入值是有符号的还是无符号的,加法和减法所涉及的操作都是相同的。将结果解释为有符号或无符号运算完全取决于用户的意图。

表1.3给出了二进制数00000000b到11111111b对应的有符号数(-128~127)和无符号数(0~255)。

表1.3 有符号和无符号的8位数字

(续)

二进制数的有符号和无符号表示形式可以扩展到更大的整数数据类型。16位二进制数可以表示0~65535的无符号整数和-32768~32767的有符号整数。在现代编程语言中通常使用32位、64位甚至更大的整数数据类型。

1.3.3 6502微处理器

本节将介绍一个处理器体系结构,与功能强大的现代处理器相比,该处理器的设计相对简单。本节的目的是快速普及不同复杂度的处理器所共有的一些基本概念。

MOS Technology公司于1975年推出了6502处理器,该处理器早年广泛用于雅达利(Atari)和任天堂(Nintendo)的视频游戏机,以及Commodore和苹果公司销售的计算机。直到今天,该处理器还在嵌入式系统中广泛使用,据估计,截至2018年,该处理器的产量在50亿至100亿之间。在流行文化中,根据屏幕中所展现的画面,“未来之城”中的机器人Bender和“终结者”中的T-800机器人似乎都使用了6502。

与许多早期的微处理器相同,6502由5V的恒定电压供电。在这些电路中,低信号电平是0~0.8V之间的任何电压。高信号电平是2~5V之间的任何电压。低信号电平定义为逻辑0,高信号电平定义为逻辑1。第2章将进一步深入探究数字电子技术。

处理器的字长定义了操作的基本数据元素的大小。6502的字长为8位,意味着6502一次可读写存储器中的8位数据,也可将数据存放在处理器内部8位宽的寄存器中。

6502的程序存储器内存和数据内存共享同一个地址空间,并通过单总线访问其内存。与Intel 8088相同,6502实现了冯·诺伊曼体系结构。6502具有16位地址总线,可访问64KB的内存。

1KB定义为2 10 B或1024B。16条地址线的二进制组合数目是2 16 ,可以访问64×1024=65536个空间。需要注意的是,设备可以寻址64KB,并不意味着所有这些空间都必须是内存空间。基于6502处理器的Commodore VIC-20计算机中只包含5KB的RAM和20KB的ROM。

6502具有称为寄存器的内部存储区域。寄存器是逻辑设备中的一个存储子设备,可以在其中存储信息字并在计算期间对其进行操作。典型的处理器包含少量寄存器,用于临时存储数据和执行加法或地址计算等操作。

图1.1显示了6502寄存器结构,包含5个8位寄存器(A、X、Y、P和S)和1个16位寄存器(PC)。每个寄存器上方的数字表示寄存器两端的位号。

图1.1 6502寄存器结构

A、X和Y寄存器中的任何一个都可以用作通用存储空间。只要指令没有修改寄存器内容,程序指令就可以将数值加载到其中一个寄存器中,并且稍后的一些指令会出于某种目的使用其中保存的值。A寄存器是唯一能够执行算术运算的寄存器。在计算内存地址时,可以使用X和Y寄存器作为索引寄存器,但不能使用A寄存器。

P寄存器保存处理器标志。除标记为1的位外,该寄存器中的其他位都有专门的用途。标记为1的位未定义,可以忽略。该寄存器中剩余的每一位称为标志,表示已发生了特定条件或表示设置了某种配置。6502的标志定义如下:

● N:负号标志。当算术运算的结果的位7为1时,该标志位设为1。该标志在有符号算术中使用。

● V:溢出标志。当有符号加法或减法导致上溢或下溢,即超出-128至127范围时,该标志位设为1。

● B:中断标志。该标志表示已执行了中断(BRK)指令。通常情况下,该位没有定义。只有在通过BRK指令将P寄存器的内容存储到栈时,才需要检查相关的B标志。在中断处理期间,B标志置位(即为1)表明是由BRK指令引起的软件中断,而不是硬件引起的中断。

● D:十进制模式标志。该标志表示处理器算术运算将在 二进制编码的十进制 (Binary-Coded Decimal,BCD)模式下运行。由于BCD模式很少使用,因此这里不再讨论,只需注意这种以10为基数的计算模式与分析机和ENIAC的体系结构具有一定的相似性。

● I:中断禁用标志。该标志表示不会处理中断请求(但非可屏蔽中断除外)。

● Z:零标志。当操作结果为零时该标志设为1。

● C:进位标志。当算术运算产生进位时该标志设为1。

在涉及循环、计数和算术运算等通用计算时,N、V、Z和C是最重要的标志。

S寄存器是栈指针。在6502中,栈是从地址$100到$1FF的内存区域。这256字节的空间用于临时存储子程序内的参数,并在调用子程序时保存返回地址。系统启动时,S寄存器将指向此范围的顶部作为初始状态。使用PHA等指令将数据“压”入栈(PHA指令会将A寄存器的内容压入栈)。

当数据被压入栈时,6502将S寄存器所指示的地址,加上固定的$100偏移量,所得的结果作为该数据的内存地址,然后对S寄存器做递减操作。通过执行更多的压栈指令,可以将其他数据放入栈。当存入更多的数据时,栈在内存中的位置向下移动。在将数据存入栈中时,程序必须注意不要超过固定的256字节栈大小。

必须用与压入顺序相反的顺序检索存储在栈中的数据。栈是 后进先出 (Last-In,First-Out,LIFO)数据结构,这意味着当从栈“弹出”(pop)一个数据时,它是最近压入的字节。PHA指令将S寄存器加1,然后将S寄存器(加上$100偏移量)指示的地址处的数值复制到A寄存器中。

PC寄存器是程序计数器,其中存放着要执行的下一条指令所在的内存地址。与其他寄存器不同,PC的长度为16位,允许访问6502的整个地址空间。

每条指令由1字节操作码(operationcode,简写为opcode)组成,根据指令的不同,操作码后面可以跟0~2个操作数字节。执行完每条指令后,PC会更新以指向刚刚执行完成指令之后的下一条指令。除了在顺序指令执行期间的自动更新之外,PC还可以通过跳转指令、分支指令以及子程序调用和返回指令来修改。

1.3.4 6502指令集

接下来研究6502指令集。不同的处理器有不同的指令,程序员将指令按照不同的顺序组织在一起,就能执行不同的算法。每条指令包含一个操作码,用来告诉处理器在执行该指令时完成什么操作。

如果程序员愿意,他们可以直接使用处理器指令编写代码。在本节后面可以看到一些例子。程序员也可以使用高级语言编程,然后,使用一种名为编译器的软件工具,将高级代码转换为处理器指令序列(通常要比高级语言代码序列长得多)。

本节使用的是处理器指令序列的代码,这种形式的源代码称为汇编语言。

6502指令集中的每条指令都有一个由三个字符组成的助记符。在汇编语言源文件中,每行代码包含一条指令助记符,后面跟着该指令的操作数。助记符和操作数的组合定义了寻址模式。6502支持多种寻址模式,为访问寄存器和存储器中的数据提供了极大的灵活性。在这里将只使用立即数寻址模式,在该模式中,操作数本身就是一个数值,而不是指示包含数值的寄存器或内存位置。立即数前面有一个#字符。

在6502汇编中,十进制数字没有前缀,而十六进制数字前面有一个$字符,例如,48是十进制数,而$30是十六进制数。

下面将用一些汇编代码示例来演示6502的算术功能。下面的示例中使用了5条6502指令:

● LDA向寄存器A加载一个数值。

● ADC将进位(P寄存器中的C标志)作为加法运算的额外输入和输出,即带进位的加法。

● SBC将进位标志作为减法运算的额外输入和输出。

● SEC将进位标志直接设为1。

● CLC将进位标志直接清0。

由于进位标志是加法和减法指令的输入,因此在执行ADC或SBC指令之前确保该值是正确的。在启动加法操作之前,C标志必须清零,以指示没有来自先前加法的进位。进行多字节加法(例如,使用16位、32位或64位数字)时,在进行高位字节的加法运算时,需要将相邻的低字节加法运算产生的进位作为输入参与运算。如果在ADC指令执行时C标志为1,则效果是将结果加1。ADC完成后,C标志用作结果的第9位:C标志结果为0表示没有进位,结果为1表示有来自8位寄存器的进位。

对于使用6502汇编语言的新手程序员来说,使用SBC指令进行减法运算往往会更感到困惑。小学生在学习减法时,如果要从一个较小的数中减去一个较大的数,则需要使用借位技术。在6502中,C标志代表借位的反逻辑。如果C为1,则借位为0,如果C为0,则借位为1。因此,在没有借位的情况下执行减法时,需要在执行SBC命令之前将C标志设为1。

表1.4中的示例将6502作为计算器使用,使用代码中定义为立即值的输入,并将结果存储在A寄存器中。“结果”列显示A寄存器以及N、V、Z和C标志的最终值。

表1.4 6502算术指令序列

如果你没有一台具有汇编器和调试器的6502计算机,可以在Web浏览器中在线运行免费的6502模拟器。访问https://skilldrick.github.io/easy6502/可以获得一个优秀的模拟器,访问该网站并向下滚动,直到找到带有用于汇编和运行6502代码按钮的默认代码列表。用表1.4中的一组三条指令替换默认代码清单,然后对代码进行汇编。

如果要检查序列中每条指令的效果,可以使用调试器控制指令单步执行,并观察处理器寄存器的结果。

本节非常简要地介绍了6502处理器及其部分功能。此处的一个要点是展示执行简单加法时的进位问题和执行减法时的借位问题所面临的挑战。从查尔斯·巴贝奇到6502的设计者,计算机体系结构设计师已经设计出了计算问题的解决方案,并使用可用的最好技术来实现这些解决方案。 1ozRbdAB4NggXdZNVkr/j28/KhbwFAmyC0edc27UJ5ONW6A5rIKFW2hTN1i/SplQ

点击中间区域
呼出菜单
上一章
目录
下一章
×