微计算机原理及应用
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.2 8086微处理器

2.2.1 8086的内部结构

8086 CPU内部由两个独立的工作部件,即执行部件(EU,Execution Unit)和总线接口部件(BIU,Bus Interface Unit)构成,其内部结构框图如图2-1所示,左半部为EU,右半部为BIU。

图2-1 8086 CPU内部结构框图

1.执行部件(EU)

EU只负责执行指令,而不与外部总线打交道。EU执行的指令从BIU的指令队列缓冲器取得,执行指令所得结果或执行指令所需的数据由EU向BIU发出请求,由BIU向存储器或外部设备存入或读取。EU包含下列三大部分。

(1)运算器

运算器由下列部分组成,负责所有运算。除此之外,通用寄存器也将协助其工作。

① 16位算术逻辑单元ALU(Arithmetic Logic Unit),其核心是一个二进制加法器,完成两方面的任务:

  • 进行所有的算术/逻辑运算。
  • 按指令寻址方式计算寻址单元16位的偏移地址EA(Effect Address),并将此EA送到BIU中形成一个20位的实际地址PA(Physical Address),以对1MB的存储空间寻址。

② 16位的状态标志寄存器F(Flag),用来存放反映ALU运算结果的特征状态,或存放一些控制标志。

③ 暂存寄存器,协助ALU完成各种运算,对参加运算的数据进行暂存。

(2)通用寄存器组

通用寄存器组包括8个16位的寄存器,其中AX,BX,CX,DX为数据寄存器,既可以寄存16位数据,也可分成两半,分别寄存8位数据;SP(Stack Pointer)为堆栈指针,用于堆栈操作时,确定堆栈在内存中的位置,给出栈顶的偏移量(Offset);BP(Base Pointer)为基址指针,用来存放位于堆栈段中的一个数据区基址的偏移量;SI(Source Index)和DI(Destination Index)为变址寄存器,SI用来存放源操作数地址的偏移量,DI用来存放目的操作数地址的偏移量。所谓偏移量是相对于段起始地址(或称为段首址)的距离。

(3)EU控制单元

EU控制单元接收从BIU指令队列(Instruction Stream Queue)中送来的指令码,并经过译码,形成完成该指令所需的各种控制信号,控制EU的各个部件在规定时间完成规定的操作。EU中所有的寄存器和数据通路(Q总线除外)都是16位的,可实现16位数据的快速传送和处理。

2.总线接口部件(BIU)

BIU是和总线打交道的接口部件,根据EU的请求,执行8086 CPU对存储器或I/O接口的总线操作,完成其数据传送。BIU由下列几部分组成。

(1)指令队列缓冲器

该缓冲器是用来暂存指令的一组暂存单元,由6个8位的寄存器组成,最多可存入6字节的指令码,采用“先进先出”原则,按顺序存放,顺序被取到EU中去执行。其工作将遵循以下原则。

① 取指时,将取来的指令存入指令队列缓冲器,当缓冲器中存入一条指令时,EU就开始执行。

② 指令队列缓冲器中只要有1字节为空,BIU便自动执行取指操作,直到填满为止。

③ 在EU执行指令过程中,若需要对存储器或I/O接口进行数据存取,则BIU将在执行完现行取指的总线周期后的下一个总线周期,对指定的存储单元或I/O接口进行存取操作,交换的数据经BIU交EU进行处理。

④ 当EU执行转移、调用和返回指令完毕时,将清除指令队列缓冲器,并要求BIU从新的地址重新开始取指令,新取的第一条指令将直接送EU执行,随后取来的指令填入指令队列。

由于执行部件EU和总线接口部件BIU是两个独立的工作部件,它们可按并行方式重叠操作,在EU执行指令的同时,BIU也在进行取指令、读操作数或存入结果的操作。这样,提高了整个系统的执行速度,充分利用总线实现最大限度的信息传输。与8位微处理器相比,这是一个很大的改进。

(2)16位指令指针寄存器IP(Instruction Pointer)

其功能与8位微处理器的程序计数器PC功能相似。但由于8086取指令和执行指令同时进行,因此Intel公司改用指令指针IP这一名称代替8位机的程序计数器PC的称法。IP中总是保存着EU要执行的下一条指令的偏移地址,而不像8位机的PC总是保存下一条取指令的地址。IP不能直接由程序进行存取,但可以进行修改,其修改发生在下列情况下:

① 程序运行中自动修正,使之指向要执行的下条指令的偏移地址。

② 转移、调用、中断和返回指令能改变IP的值,并将原IP值入栈保存,或由堆栈恢复原值。

(3)地址产生器和段寄存器

由于存放地址信号的IP和通用寄存器都只有16位,其编址范围只能达到64K,只为8086访存空间1M范围中的一个段,因此必须设置产生20位实际地址PA的机构,8086采用了地址产生器∑。

段寄存器是用来存放每种段的首地址的。8086有4个段寄存器:代码段CS(Code Segment)寄存器,数据段DS(Data Segment)寄存器,堆栈段SS(Stack Segment)寄存器和附加段ES(Extra Segment)寄存器,分别用来存放代码段首址、数据段首址、堆栈段首址和附加段首址。图2-2示出实际地址PA产生的过程。例如,要产生执行指令的PA,就将IP中的16位指令指针与代码段寄存器CS左移4位后的内容在地址产生器∑中相加。又例如,要产生某一操作数的PA,则应该首先由ALU计算出该操作数的16位偏移地址EA,然后在∑中与数据段寄存器DS左移4位后的内容相加。其余两个段————堆栈段和附加段中数据的PA也由同样的方法产生。概括起来,PA的计算公式为

PA=(段首址*16)+偏移地址

其中的偏移地址和段首址又都称为逻辑地址。

图2-2 实际地址PA的产生过程

(4)总线控制逻辑

8086的引脚线比较紧张,只分配20条总线用来传送16位数据信号D0~D15、20位地址信号A0~A19和4位状态信号S3~S6,这就必须采用分时传送。总线控制逻辑的功能,就是根据指令进行操作,用逻辑控制的方法实现上述信号的分时共用总线。分时传送的情况可参见本章2.2.7节总线操作时序。

2.2.2 8086的寄存器结构

在了解8086 CPU的内部结构以后,可以仿照第1章的典型微处理器来分析8086执行指令的过程。但是,对从事微计算机应用来说,在了解内部结构的基础上,更应掌握从中提取出的一种更简化的结构。这种结构中只包含信息寄存的空间,即程序中出现的寄存器。这种简化结构又称为可编程的寄存器结构,或程序设计的概念模型。

图2-3 8086的寄存器结构

图2-3为8086 CPU的寄存器结构,包括13个16位的寄存器和1个16位的状态标志寄存器。这里,着重指出每个寄存器的用途,以便在指令中更恰当地使用它们。

寄存器按功能可分为以下几组。

1.通用寄存器组

8086 CPU中设置了较多的通用寄存器,是一种面向寄存器的体系结构,操作数据可以直接存放在这些寄存器中,因而可减少访问存储器的次数,使用寄存器的指令长度也较短。这样,既提高了数据处理速度,也减小指令存放的内存空间。

8086的通用寄存器分为以下两组。

(1)数据寄存器

数据寄存器是指EU中的4个16位寄存器:AX,BX,CX和DX,一般用来存放16位的数据,又可分成高字节H和低字节L,即AH,BH,CH,DH和AL,BL,CL,DL两组,用于存放8位的数据。它们均可独立寻址,独立地出现在指令中。数据寄存器主要用来存放操作数或中间结果,以减少访问存储器的次数。

多数情况下,数据寄存器被用在算术或逻辑运算指令中进行算术逻辑运算。在有些指令中,则有特定的隐含用途,如AX作为累加器(Accumulator);BX作为基址(Base)寄存器,在查表转换指令XLAT中存放表的首址;CX作为计数(Count)寄存器,控制循环;DX作为数据(Data)寄存器,如在字除法运算指令DIV中存放余数。这些寄存器在指令中的隐含使用归纳如表2-2所示。

表2-2 数据寄存器的隐含使用

(2)指针和变址寄存器

8086有SP、BP两个指针寄存器和SI、DI两个变址寄存器。一般用来存放地址的偏移量,且被送到BIU的地址产生器Σ中与段寄存器内容的16倍数相加,产生20位的实际地址PA。

SP和BP都用来指示位于当前堆栈段中数据的偏移地址,但它们在使用上又有区别。SP指示入栈指令(PUSH)和出栈指令(POP)操作时栈顶的偏移地址,故称为堆栈指针寄存器;BP指示存放于堆栈段中的一个数据区基址的偏移地址,故称为基址指针寄存器。

SI和DI用来存放当前数据段中数据的偏移地址。SI中存放源操作数地址的偏移量,故称为源变址寄存器;DI中存放目的操作数地址的偏移量,故称为目的变址寄存器。例如,用于数据串操作指令中,被处理的源数据串的偏移地址放入SI,而处理后得到的结果数据串的偏移地址则放入DI。

2.段寄存器

段寄存器用来存放段首地址,因而可把8086的1MB存储空间分成若干个逻辑段。8086 CPU运行一汇编语言程序,通常需要用到4个现行段:代码段是存放程序的代码的,数据段是存放程序当前使用的数据的,堆栈段是为入栈、出栈数据提供存放空间的,附加段通常也是用来存放数据的,其典型用法是存放处理后的结果数据。这4个段的首址分别由4个段寄存器CS,DS,SS和ES来存放。它们都是16位的寄存器。

3.状态标志寄存器F

8086 CPU的状态标志寄存器F是一个16位寄存器,用了其中的9个位作为标志位(状态标志位为6个,控制标志位为3个),如图2-4所示。

图2-4 8086的状态标志寄存器

(1)状态标志位

状态标志位用来反映EU执行算术或逻辑运算后其结果的状态,共6个状态标志。

① 进位标志CF(Carry Flag):若CF=1,则表示结果的最高位上产生了一个进位或借位;若CF=0,则无进位或借位产生。

② 辅助进位标志AF(Auxiliary Carry Flag):当AF=1,表示结果的低4位产生了一个进位或借位;若AF=0,则无此进位或借位。

③ 溢出标志OF(Overflow Flag):当OF=1,表示带符号数在算术运算后产生了算术溢出;若OF=0,则无溢出。

④ 零标志ZF(Zero Flag):当ZF=1,表示运算结果为零;若ZF=0,则结果不为零。

⑤ 符号标志SF(Sign Flag):当SF=1,表示带符号数的运算结果为负数,即结果的最高位为1;若SF=0,则结果为正数,最高位为0。

⑥ 奇偶标志PF(Parity Flag):当PF=1,表示运算结果中有偶数个1;若PF=0,则结果中有奇数个1。

(2)控制标志位

控制标志位是用来控制CPU操作的,由指令设置或清除,有以下3个控制标志。

① 方向标志DF(Direction Flag):用来控制数据串操作指令的步进方向。用STD指令将DF置1后,数据串指令将以地址的递减顺序对数据串进行处理;若用CLD指令清除DF,则数据串指令将以地址的递增顺序对数据串进行处理。

② 中断允许标志IF(Interrupt Enable Flag):若用指令STI将IF置1,则8086 CPU开启中断,即允许接受外部从INTR引脚发来的中断请求;若用指令CLI将IF清除,则表示关中断,不能接受经INTR发来的中断请求。必须注意,IF的设置不影响非屏蔽中断NMI请求,也不影响CPU响应内部产生的中断请求。

③ 陷阱标志TF(Trap Flag):8086为使程序调试方便设置了TP。若置TP为1,则8086进入单步工作状态。在这种方式下,每执行完一条指令,就自动地产生一个内部中断,转去执行一个中断服务程序,将每条指令执行后CPU内部寄存器的情况显示出来,以便检查程序;反之,当TF被清除,8086仍正常地执行程序。

标志位的状态可用调试程序DEBUG将它们显示出来,所表示的符号如表2-3所示。

表2-3 FLAGS中标志位的状态表示符号

4.指令指针寄存器IP

IP是一个16位的寄存器,存放EU要执行的下一条指令的偏移地址。当BIU从代码段取出指令字节后,IP自动加1,又指向下一条指令的偏移地址,以实现对代码段指令的跟踪。IP的内容仅当执行转移类指令时才会由转移地址改变。

2.2.3 8086的引脚特性

8086 CPU的外壳仍采用8位微处理器所用的40条引脚的双列直插(DIP)封装,如图2-5所示。由于16位的CPU的数据总线增加到16条,地址总线增加到20条,因此必须分时复用一些引脚,表示为AD0~AD15。还有一些引脚将根据8086工作的方式不同,体现不同的功能,功能的转换由33号引脚进行控制。当(高电平)时,8086工作于最小方式MN,24~31号引脚直接提供8086的控制总线信号,如图中括号外的信号;当时,24~31号引脚提供的信号如图中括号内所示,这些信号还需经外接的8228总线控制器转换,才能提供给系统作为控制总线信号使用。

8086的引脚按其特性分为以下5类。

图2-5 8086 CPU芯片引脚特性

1.地址/数据总线(AD15~AD0双向、三态)

这是地址和数据信号复用的一类总线。每当访问存储器或I/O接口时,首先用来发地址信号,然后用来传输数据。因此,先发的地址信号应由外接的地址锁存器锁存下来,才能保证使用的需要。当进行存储器直接存取(DMA)时,这类总线处于浮空状态。

2.地址/状态总线(A19/S6,A18/S5,A17/S4,A16/S3输出、三态)

A19~A16是地址信号的高4位,和A15~A0一样,也是应该首先发出的;S6~S3是状态信号,可在输出地址信号之后输出,因此,这4条总线也可采取分时复用。A19~A16在访问存储器时才有用,也需由外接地址锁存器进行锁存后,向系统提供20位地址信号,而访问I/O接口时,则不使用,即A19~A16=0。4位状态信号有不同的用途:① S4,S3用来指示当前使用哪一个段寄存器:00指示在使用ES,01指示在使用SS;10指示在使用CS;11指示在使用DS。② S5用来指示中断允许标志IF的状态。③ S6始终保持低电平。

当进行DMA时,这类总线进入浮空状态。

3.控制总线

以下8条控制线不论8086工作在最大或是最小方式下,都是存在的。

(1)

高8位数据总线允许/状态线(输出,三态)。这是分时复用线。在访问存储器或I/O接口的总线周期中,首先输出控制信号,用以对以字节组织的存储器或I/O接口实现高位或低位字节的选择;然后输出状态信号S7。S7为备用状态信号,其内容不固定。

(2)

读控制信号(输出,三态,低电平有效)。当时,表示8086 CPU执行存储器读操作或I/O读操作;DMA时,浮空。

(3)READY

准备就绪信号(输入,高电平有效)。该信号是由所访问的存储器或I/O接口发来的响应信号。当READY为高电平时,表示内存或I/O设备准备就绪,马上可进行一次数据传输。在每个总线周期中CPU都要对READY信号进行采样,若检测到为无效的低电平时,将自动插入等待状态TW,直到READY变为高电平后才进行数据传输,结束该次总线周期。

(4)

测试信号(输入,低电平有效)。该信号和等待指令WAIT结合起来使用。在CPU执行WAIT指令时,进入空转的等待状态;每隔5个时钟周期对引脚进行一次测试。当8086的信号为有效电平时,等待状态结束,继续往下执行WAIT后面的指令。等待期中允许外部中断,中断返回后到WAIT指令的下一条命令。

(5)INTR

可屏蔽中断请求信号(输入,高电平有效)。当INTR引脚出现高电平时,表示外设提出了中断请求,8086在每一个指令周期的最后一个状态去采样此信号。若已发来此信号,而且CPU的中断允许标志IF=1(开中断),则CPU就会在结束当前指令后,响应此中断请求,转去执行一个中断服务程序;相反,虽已发来此请求,但IF=0(关中断),则CPU不会响应中断,表示外设中断请求被屏蔽掉了。

(6)NMI

非屏蔽中断请求信号(输入,上升沿有效)与INTR有两点不同:

① 该请求信号是一个上升沿触发信号,而不是高电平信号。

② 只要此请求信号来到,不管IF是否为1,CPU都会在执行完当前指令后,进入规定中断类型号的非屏蔽中断处理程序。

(7)RESET

复位信号(输入,高电平有效)用来对CPU进行复位操作。8086 CPU要求复位信号至少维持4个时钟周期的高电平才有效。复位信号有效后,CPU结束当前操作,并将CPU内部寄存器F,IP,DS,SS,ES及指令队列缓冲器清零,而将CS设置为FFFFH。当复位信号变为低电平时,CPU便从FFFF0H开始执行程序,执行系统的启动操作。

(8)CLK

时钟脉冲(输入)。8086 CPU要求时钟脉冲的占空比为1/3,即1/3周期为高电平,2/3周期为低电平。通常,8086的时钟信号由外接的时钟发生器8284A提供。

4.电源和地址

电源线VCC接入的电压为+5V±10%;8086有两条地线GND,均应接地。

5.其他控制线

8086 CPU的24~31号引脚也是一些控制信号线,但它们的定义将根据8086的工作方式(最小工作模式或最大工作模式)来确定,将在本章2.2.5节介绍。

2.2.4 8086的时钟和总线周期概念

8086 CPU由外接的一片时钟发生器8284A提供主频为5MHz的时钟信号。在时钟控制下,一步步顺序地执行指令,因此时钟周期是CPU执行指令的时间刻度。在执行指令过程中,凡需访问存储器或访问I/O接口的操作都统一交给BIU的外部总线完成,每次访问称为一个总线周期。若执行数据输出,则称为“写”总线周期;若执行数据输入,则称为“读”总线周期。

前面2.2.1节和2.2.2节涉及的是信息流通途径和存放的空间概念,本节涉及的则是信息处理的时间概念。

1.8284A时钟信号发生器

8284A是Intel公司专为8086设计的时钟发生器,产生8086所需的系统时钟信号(即主频),用石英晶体或某一TTL脉冲发生器作为振荡源,除提供频率恒定的时钟信号外,还要对外界输入的“准备就绪”信号RDY和复位信号RES进行同步。8284A的引脚特性及其与8086/8088 CPU的连接如图2-6所示。外界的RDY输入8284A,经时钟的下降沿同步后,输出READY信号作为8086的“准备就绪”信号;同样,外界的复位信号输入8284A,经整形并由时钟的下降沿同步后,输出RESET信号作为8086的复位信号(其宽度不得小于4个时钟周期)。外界的RDY和可以在任何时候发出,但送到CPU去的都是经过时钟同步了的信号。

8284A根据使用振荡源的不同,有两种不同的连接方法。

(1)用脉冲发生器做振荡源时,只要将该发生器的输出端与8284A的EFI端相连即可。

(2)更常用的方法是采用晶体振荡器作为振荡源,这时需将晶体振荡器的两端接到8284A的X1和X2上。

图2-6 8284A及其与8086/8088的连接

如果用前一种方法,则必须将接高电平,而用后一种方法,则必须将接地。不管用哪种方法,8284A输出的时钟CLK的频率均为振荡源频率的1/3,而振荡源本身的频率经8284A驱动后,由OSC端输出,可供系统使用。

2.总线周期

CPU访问(读或写)一次存储器或I/O接口所花的时间,称为一个总线周期。8086的一个最基本的总线周期由4个时钟周期组成。时钟周期是CPU的基本时间计量单位,由主频决定。例如,8086的主频为5MHz,一个时钟周期就是200ns。一个时钟周期又称为一个状态T,因此一个基本总线周期就由T1,T2,T3,T4组成。图2-7为典型的BIU总线周期波形图。在T1状态,CPU首先将应访问的存储单元或I/O端口的地址送到总线上;在T2~T4状态,若是“写”总线周期,则CPU把输出数据送到总线上;若是“读”总线周期,则CPU在T3到T4期间从总线上输入数据,T2状态时总线浮空,以便CPU有个缓冲时间把输出地址的写方式转换为输入数据的读方式。这就是总线AD0~AD15和A16/S3~A19/S6在总线周期的不同状态下传送不同信号用的分时复用总线的方法。在表示CPU总线周期波形图时,对于由两条或两条以上的线组成的一组总线的波形(如地址总线、数据总线等),使用交叉变化的双线表示,这是因为在每个状态下,有的线可能为低电平,有的线则可能为高电平。这里还需要指出两点:

图2-7 典型的BIU总线周期波形图

(1)当与CPU相连的存储器或外设速度跟不上CPU的访问速度时,就会由存储器或外设通过READY控制线,在T3状态开始之前向CPU发一个READY无效信号,表示传送的数据未准备就绪,于是CPU将在T3之后插入一个或多个附加的时钟周期TW(即等待状态)。在TW状态,总线上的信息情况维持T3状态的信息情况。当存储器或外设准备就绪时,就向READY线上发出有效信号,CPU接到此信号,自动脱离TW而进入T4状态。

(2)总线周期只用于CPU和存储器或I/O接口之间传送数据和供取指令填充指令队列。如果在一个总线周期之后,不立即执行下一个总线周期,那么系统总线就处于空闲状态,即执行空闲(Idle)周期TI。在TI中,可以包含1个时钟周期或多个时钟周期。这期间,在总线的高4位上CPU仍然保持前一个总线周期的状态信息;而在总线低16位上,则视前一个总线周期是写周期还是读周期来确定。若是写周期,则总线低16位上继续保持数据信息;若是读周期,则CPU将使低16位处于浮空状态。

2.2.5 8086的工作模式

8086 CPU有两种工作模式:最小工作模式和最大工作模式,以尽可能适应各种应用场合的需要。

1.最小工作模式及8282、8286的应用

(1)最小工作模式

当把8086的33脚接向+5V时,就处于最小工作模式。所谓最小工作模式,就是系统中只有一个微处理器8086,所有的总线控制信号都直接由8086产生,系统中总线控制逻辑电路被减到最少。最小工作模式适合于较小规模的应用,其系统结构如图2-8所示,这与8位微处理器系统类似,总线上的芯片可根据用户需要接入。图中的8284A为时钟发生器,外接晶体的基本振荡频率为15MHz,经三分频后,作为CPU的系统时钟CLK。

图2-8 8086最小工作模式典型系统结构

(2)8282/8283的应用

8282/8283是Intel公司的8位带锁存器的单向三态不反相/反相的缓冲器,用来锁存8086访问存储器和I/O接口时于T1状态发出的地址信号。经8282锁存后的地址信号可以在整个周期保持不变,为外部提供稳定的地址信号。

8282/8283均采用20条引脚的DIP封装,其内部逻辑结构和引脚特性如图2-9所示。为三态控制信号,低电平有效。STB为锁存选通信号,高电平有效。接入系统时,以8086的ALE(地址锁存允许信号)作为STB。ALE信号在每个总线周期一开始就有效,使8086的地址信号被锁存下来,并传至输出端,作为系统地址总线,供存储器芯片和I/O接口芯片连接。在不带DMA控制器的8086单处理器系统中,可将接地,保持常有效,而当为高电平时,8282的输出端则处于高阻状态。

图2-9 8282及8283的内部逻辑及引脚特性

(3)8286/8287的应用

8286/8287是Intel公司的8位双向三态不反相/反相的缓冲器,均采用20条引脚的DIP封装,其内部逻辑结构和引脚特性如图2-10所示。每一位双向三态缓冲器由两个单向三态缓冲器构成,起双向电子开关作用,可对数据总线进行功率放大,并当收/发器使用。8286/8287可作为选件,用于需要增加数据总线驱动能力的系统。

图2-10 8286及8287的内部逻辑及引脚特性

和T是该缓冲器的三态控制信号,经过两个或非门产生对正向及反向缓冲器的门控信号。为允许输出控制信号,低电平有效;T为传送方向控制信号,高电平有效。当无效时,不管T是否有效,数据在两个方向上都不能传输;只有当时,若T=1,则数据从A流向B,若T=0,数据则由B流向A。8286/8287接入系统时,用8086的DEN(数据有效)信号作为,用(数据发/收)信号作为T。

(4)最小工作模式下24~31号引脚功能的定义

(Memory/Input and Output)存储器/输入和输出控制信号(输出,三态):此信号被接至存储器芯片和接口芯片的片选端,用于区分CPU当前是访问存储器还是访问接口。若为高电平,则表示CPU和存储器进行数据交换;若为低电平,则表示CPU和输入/输出设备进行数据交换;当DMA时,此线被置为浮空。

写控制信号(输出,低电平有效,三态):当CPU执行对存储器或对I/O的写操作时,此信号有效。有效时间为写周期中的T2,T3和TW,在DMA时,此线被置为浮空。

③ HOLD(HOLD Request)总线保持请求信号(输入,高电平有效):是由系统中的其他总线主控部件(如DMA控制器)向CPU发来的请求占用总线的控制信号。当CPU收到此信号时,若CPU允许让出总线,就在当前总线周期完成时,于T4状态或空闲状态TI的下一状态从HLDA线上发出一个应答信号作为HOLD请求的响应,同时,CPU使具有三态功能的所有地址/数据总线和控制总线处于浮空,其时序如图2-11所示。当总线请求部件收到HLDA后,获得对总线的控制权。从这时开始,HOLD和HLDA都保持高电平(有效)。当请求部件完成对总线的占用后(如DMA完成),将把HOLD信号变为低电平(无效),CPU收到后,也将HLDA变为低电平(无效),至此,CPU又恢复对地址/数据总线和控制总线的控制权。

④ HLDA(HOLD Acknowledge)总线保持应答信号(输出,高电平有效):这是与HOLD配合使用的,由CPU向总线请求部件发回的一种响应联络信号。

(Interrupt Acknowledge)中断响应信号(输出,低电平有效):是和中断请求信号INTR配合使用的一对信号。此信号是在CPU收到外部中断源发来的INTR后,且当中断允许标志IF=1,则会在一条指令执行完毕的当前总线周期和下一个总线周期中,从引脚上往外设接口各发一个负脉冲,以作为对外设中断请求发回的响应。这两个负脉冲都将从每个总线周期的T2维持到T4状态的开始。如图2-12所示,第1个负脉冲通知外设接口(如中断控制器),它发出的中断请求已经得到允许;第2个负脉冲期间,由外设接口往数据总线上送中断类型码n,使CPU能获得有关中断响应的有关信息。

图2-11 总线保持请求/保持响应时序(最小模式)

图2-12 8086的中断响应信号及时序

⑥ ALE(Address Latch Enable)地址锁存允许信号(输出,高电平有效):在任何一个总线周期的T1状态,ALE输出有效电平,以表示当前在地址/数据复用总线上输出的是地址信号。该信号提供给地址锁存器8282/8283作为地址锁存信号,对地址进行锁存。要注意,此信号线不能被浮空。

(Data Enable)数据允许信号(输出,低电平有效,三态):这是8086提供给数据总线收发器8286/8287的三态控制信号,接至其端。此信号在每个访问存储器或I/O的周期或中断响应周期有效;在DMA时,被置为浮空。

(Data Transmit/Receive)数据收/发控制信号(输出,三态):在使用8286/8287作为数据总线收发器时,该信号用来控制8286/8287的数据传送方向。若为高电平,则进行数据发送,否则进行数据接收。在DMA时,被置为浮空。

2.最大工作模式及8288的应用

(1)最大工作模式

当把8086的33脚接地时,系统就处于最大工作模式。用于中型或大型规模的8086系统中。最大工作模式系统的显著特点是可包含两个或两个以上的处理器,其中必有一个为主处理器8086,其他的称为协处理器,用来协助主处理器承担某方面的工作,使主处理器的性能得到横向提升。8086系列的协处理器常用的有两种:一种是专用于数值运算的处理器8087,它能实现多种类型的数值操作,如高精度整数和浮点运算、超越函数(如三角函数、对数函数等)的运算。用硬件完成运算比通常用软件方法完成运算将大幅提高系统数值的运算速度;另一种是专用于输入/输出处理的协处理器8089,有一套专用于输入/输出操作的指令系统,直接供输入/输出设备使用,使8086从这类繁杂的工作中解脱出来,明显地提高主处理器的效率。

8086最大工作模式的典型系统结构如图2-13所示,与最小工作模式比较,一是增加了总线控制器8288,使总线控制功能和驱动能力得到增强,二是8286收发器为必选件,以适应系统组件增加对数据总线提出的功率要求。如果典型系统中加入总线仲裁器8289,就可构成一个多处理器系统,如图2-14所示。

图2-13 8086最大工作模式典型系统结构

最大工作模式下,许多总线控制信号是通过总线控制器8288产生的,而不是由8086 CPU直接提供。这样,8086在最小工作模式下对24~31号引脚定义的控制功能就需重新定义,改为支持多处理器系统所用。

(2)最大工作模式下24~31号引脚功能的定义

最大工作模式下,对24~31号引脚定义的功能已示于图2-5的括号中,包括下述控制信号:

图2-14 多处理器系统

(Bus Cycle Status)总线周期的状态信号(输出,三态):用来指示CPU总线周期的操作类型,并送到8288总线控制器,产生对应于各种总线周期的控制命令如表2-4所示。

② QS1,QS0(Instruction Queue Status)指令队列状态信号(输出,高电平有效):这两个信号组合起来提供了前一个时钟周期(指总线周期的前一个状态)中指令队列的状态,以便于外部对8086 BIU中的指令队列的动作跟踪。QS1,QS0的代码组合分别为00,01,10和11,所对应的指令队列为:无操作、从队列缓冲器取出指令的第一字节、队列为空和从队列缓冲器中取出第二字节以后部分。

表2-4 与总线周期,8288的控制命令

(Request/Grant)总线请求输入/总线请求允许输出信号(双向,低电平有效):在图2-14的多处理器系统中,当8086使用总线,其为高电平;这时,若协处理器8087或8089要使用总线,就由它们的线输出低电平(请求);经8086检测,且当总线处于允许状态,则8086的输出低电平作为允许信号(允许),再经8087或8089检测出此信号,对总线进行使用;待使用完毕,将线变为低电平(释放),8086在检测到该信号时,又恢复对总线的使用。

总线封锁信号(输出,三态,低电平有效):当此信号线上输出有效电平时,表示CPU独占总线,封锁其他总线主部件占用总线。信号由指令前缀LOCK产生,LOCK前缀后面的一条指令执行完后,便撤销了信号(为避免多个处理器使用共有资源产生冲突而设置的)。此外,在8086的2个中断响应脉冲之间,LOCK信号也自动有效,以防其他总线主部件在中断响应过程中占有总线而使一个完整的中断响应过程被间断。在DMA下,LOCK引脚处于浮空。

(3)总线控制器8288

8288是20条引脚的DIP芯片,采用TTL工艺,其内部原理框图及外部引脚如图2-15所示。

图2-15 8288的内部原理框图和外部引脚

8288的引脚信号分为3组:输入信号(含状态和控制信号)、命令输出信号、输出的总线控制信号。

8288与系统的连接如图2-16所示。从图中可以看到,8288接收8086执行指令时产生的状态信号,在时钟发生器8284A的时钟CLK信号控制下,译码产生时序性的各种总线控制信号和命令信号,同时,也增强这些信号对总线的驱动能力。尽管最大方式一般用于多处理器系统,然而,在一些单处理器系统中,由于此优点,也使用了8288。

图2-16 8288总线控制器与系统的连接

8288的IOB(I/O总线工作方式)信号是用来决定其本身工作方式的,即:

① 当IOB接地时,8288工作在适合于单处理器工作的方式。这时IBM PC/XT微机为一般情况下设置的状态。此时,要求(Address Enable)接地(有效),CEN(Command Enable)接+5V(有效),这种方式下的输出端(Master Cascade Enable/Peripheral Data Enable)输出为MCE(主模块允许)信号。

② 当IOB接+5V时,且CEN也接+5V(有效),8288将适合工作于多处理器的系统中。这种方式下,引脚输出的是(外部设备数据允许)信号,此信号用做8286收/发器的开启信号,使局部总线和系统总线接通。

8288根据状态信号译码后,产生以下控制信号和命令:

〈1〉ALE地址锁存信号:和最小模式下的ALE含义相同,也是送给地址锁存器8282作为选通信号STB。

〈2〉DEN数据允许信号和数据收/发信号:送到8286总线收/发器分别控制总线收/发器的开启和控制数据的传输方向。这两个信号和最小模式下的含义相同,但是,这里的DEN和最小方式的电平相反。

〈3〉中断响应信号,与最小模式下的含义相同。

〈4〉(Memory ReaD Command),(Memory WriTe Command)和(I/O Read Command),(I/O Write Command)存储器和I/O接口读/写控制信号:分别用来控制存储器和I/O接口的读/写,均为低电平有效,都在相应总线周期的中间部分输出。显然,在任何一种总线周期内,只要这4个命令信号中有一个输出,就可控制一个部件的读/写操作。这些信号相当于最小模式下,由8086直接产生的配合作用的效果。

〈5〉(Advanced I/O Write Command)和(Advanced Memory Write Command),超前写I/O命令和超前写内存命令:其功能与相同,只是将超前一个时钟周期发出,用来控制速度较慢的外设或存储器芯片时,将得到一个额外的时钟周期去执行写操作。

2.2.6 8086的总线操作时序

8086 CPU执行访问存储器或访问I/O接口的指令,或装填指令队列,都需要执行一个总线周期,进行总线操作。从前面已知,一个基本总线周期包含4个状态T1,T2,T3,T4。当存储器或I/O设备的速度较慢时,要通过8284A时钟发生器发出READY=0(未准备就绪)信号,CPU则在T3开始时对READY进行采样。当采到“未准备就绪”信号时,就会在T3之后插入1个或多个等待状态TW

CPU在每个状态中都安排了具体的操作,如由总线发地址、状态或控制信号,由总线收/发数据信号等。总线操作按数据信号传输方向可分为总线读操作和总线写操作。前者指CPU从存储器或I/O接口读取数据,后者指CPU把数据写入到存储器或I/O接口。读/写操作又与8086 CPU工作模式有关。现以8086的最小模式为例,分析总线读/写的操作时序。

1.8086最小模式下的总线读操作时序

图2-17为8086 CPU从存储器或I/O接口读取数据的操作时序。

(1)T1状态

① CPU根据执行的是访问存储器还是访问I/O接口的指令,首先在线上发有效电平。若为高电平,则表示从存储器读;若为低电平,则表示从I/O端口读。此信号将持续整个总线周期。

② 从地址/数据复用线AD15~AD0和地址/状态复用线A19/S6~A16/S3发存储器单元地址(20位)或发I/O端口地址(16位)信号。这类信号只持续T1状态,因此必须进行锁存,以供整个总线周期使用。

③ 为了锁存地址信号,CPU于T1状态,从ALE引脚上输出一个正脉冲作为8282地址锁存器的地址锁存信号。在ALE的下降沿到来之前,和地址信号均已有效。因此,8282可用ALE信号的下降沿对地址进行锁存。

图2-17 8086总线读操作时序(最小模式)

④ 为了实现对存储体的高位字节库(即奇地址库)的寻址,CPU在T1状态通过引脚发有效信号(低电平)。和地址信号A0分别用来对奇、偶地址库进行寻址(详见本章2.2.7节存储器组织)。

⑤ 为了控制数据总线的传输方向,发信号,以控制数据总线收/发器8286处于接收数据状态。

(2)T2状态

① 总线上输出的地址信号消失,此时,AD15~AD0进入浮空状态,作为一个缓冲期以便将总线传输方向由输出地址转为读入数据。

② A19/S6~A16/S3线开始输出状态信号S7~S3,并持续到T4状态。其中的S7未赋实际意义。

信号变为低电平(有效),用来开放总线收/发器8286。这样,就可以使8286提前于T3状态(即数据总线上出现输入数据前)获得开放,有效信号维持到T4的中期结束。

信号变为低电平(有效)。此信号被接到系统中所有存储器和I/O接口芯片,用来开放数据输出缓冲器,以便将数据送上数据总线。

继续保持低电平,维持8286为接收数据状态。

(3)T3状态

经过T1,T2后,存储器单元或I/O接口把数据送上数据总线AD15~AD0,供CPU读取。

(4)TW等待状态

当系统中所用的存储器或外设的工作速度较慢,不能在基本总线周期规定的4个状态完成读操作时,它们将通过8284时钟发生器给CPU发一个READY为无效的信号。CPU在T3的前沿(下降沿)采样READY。当采到的READY=0(未准备就绪)时,就会在T3和T4之间插入等待状态TW。TW可以为1个或多个状态。以后,CPU在每个TW的前沿(下降沿)去采样READY,直至采到READY=1(表示“已准备就绪”)时,才在本TW结束时,脱离TW而进入T4状态。在最后一个TW,数据已出现在数据总线上,因此,这时的总线操作和基本总线周期中T3状态下的一样。而在这之前的TW状态,虽然所有CPU控制信号状态已和T3状态下的一样,但终因READY沿未有效,仍不能使数据信号送上数据总线。

(5)T4状态

在T4状态和前一状态交界的下降沿处,CPU对数据总线上的数据进行采样,完成读取数据的操作。

归结起来:在总线读操作周期中,8086于T1从分时复用的地址/数据线AD和地址/状态线上输出地址;T2时使AD线浮空,并输出;在T3,T4时,外界将欲读入的数据送至AD线上;在T4的前沿,将此数据读入CPU。

2.8086最小模式下的总线写操作时序

图2-18示出8086 CPU对存储器或I/O接口写入数据的写操作时序。与读操作一样,基本写操作周期也包含4个状态:T1,T2,T3和T4。当存储器芯片或外设速度较慢时,在T3和T4之间插入1个或多个TW

图2-18 8086总线写操作时序(最小工作模式)

在总线写操作周期中,8086于T1将地址信号送至地址/数据复用总线AD上,并于T2开始直到T4,将数据信号输出到AD线上,等到存储器或I/O接口芯片上的输入数据缓冲器被打开,便将AD线上输出的数据写入到存储器单元或I/O端口。存储器或I/O端口的输入数据缓冲器是利用在T2状态由CPU发出的写控制信号打开的。

总线的写周期和读周期比较,有以下不同:

① 写周期下,AD线上因输出的地址和输出的数据为同一方向,因此T2时不再需要像读周期时要维持一个状态的浮空以作为缓冲。

② 对存储器或I/O接口芯片发的控制信号是,而不是(但它们出现的时间类似,都从T2开始)。

③ 在引脚上发出的是高电平的数据发送控制信号DT,而不是;DT被送到8286总线收/发器控制数据输出方向。

2.2.7 存储器组织

1.存储器的标准结构

存储器通常按字节组织排列成一个个单元,每个单元用一个唯一的地址码表示,这就是存储器的标准结构。若存放的数据为8位的字节数据,则将它们按顺序进行存放;若存放的数据为16位的字数据,则将字的高位字节存于高地址单元,低位字节存于低地址单元;若存放的数据为32位的双字(这通常是指地址指针数据),则将地址指针的偏移量(字)存于低地址的字单元中,将地址指针的段基址(字)存于高地址的字单元中,其存放的示意图如图2-19所示。还要注意:存放字时,其低位字节可从奇数地址开始,也可从偶数地址开始;前一种存储方式称为非规则存放(这样存放的字为非规则字),后一种方式为规则存放(这样存放的字为规则字)。对规则字的存取可在一个总线周期完成,对非规则字的存取则需两个总线周期才能完成。

8086 CPU在组织1MB的存储器时,其空间实际上被分成两个512KB的存储体,或称存储库,分别叫做高位库和低位库。高位库与8086数据总线中的D15~D8相连,库中每个单元的地址均为奇数;低位库与数据总线中的D7~D0相连,库中每个单元的地址均为偶数。地址线A0和控制线用于库的选择,分别接到每个库的选择端。地址线A19~A1同时接到两个库的存储芯片上,以寻址每个存储单元。存储器高位库、低位库与总线的连接如图2-20所示。当时,选中奇数地址的高位库;当A0=0时,选中偶数地址的低位库。可见,当执行对各种数据寻址的指令时发出的和A0信号就可控制对两个库的“读”或“写”操作;当和A0分别为00,01,10和11时,实现的“读”或“写”分别为16位数据(双库),奇地址高位库,偶地址低位库,不传送。

图2-19 各种数据在存储器中的存放

图2-20 8086存储器高、低位库与总线的连接

2.存储器分段

8086用20位地址信号,寻址1MB的内存空间,每个单元的实际地址PA需用5位十六进制数表示。但CPU内部存放地址信息的一些寄存器,如指令指针IP、堆栈指针SP、基址指针BP、变址寄存器SI,DI和段寄存器CS,DS,ES,SS等都只有16位,显然不能存放PA而直接寻址1MB空间。为此,在16位或16位以上的微处理器中引入存储器分段的概念。

分段就是把1MB空间分为若干逻辑段,每段最多可含64KB的连续存储单元。每个段的首地址是一个能被16整除的数(即最后4位为0),首址是用软件设置的。

运行一个程序所用的具体存储空间可以为一个逻辑段,也可为多个逻辑段。段和段之间可以是连续的、断开的、部分重叠的或完全重叠的,如图2-21所示。

存储器采用分段编址方法进行组织,带来的好处如下。

① 指令中只涉及16位的地址(段首址或在段中的偏移量),缩短了指令长度,从而提高了执行程序的速度。

② 尽管存储空间多达1MB,但程序执行过程中不需要在1MB的大空间中去寻址,多数情况下只需在一个较小的段中运行。

③ 多数指令的运行都不涉及段寄存器的值,而只涉及16位的偏移量,为此,分段组织存储也为程序的浮动装配创造了条件。

④ 程序设计者不用为程序装配在何处而去修改指令,统一由操作系统去管理就行了。

3.实际地址和逻辑地址

实际地址,或称物理地址,是指CPU和存储器进行数据交换时使用的地址。对8086来说,是用20位二进制数或5位十六进制数表示的地址码,是唯一能代表存储空间每个单元的地址。

逻辑地址是指产生实际地址用到的两个地址分量:段首址和偏移量,它们都是用无符号的16位二进制数或4位十六进制数表示的地址代码。

指令中不能使用实际地址,只使用逻辑地址。由逻辑地址产生和计算实际地址的过程和公式已示于本章2.2.1节。注意:一个存储单元只有唯一编码的实际地址,而一个实际地址可对应多个逻辑地址,如图2-22所示。如图中某一实际地址11245H,可以从两部分重叠的段中得到:在段首址为1123H的段中,其偏移量为15H;在段首址为1124H的段中,其偏移地址为05H。这两组逻辑地址可表示为:1123H∶0015H和1124H∶0005H。

图2-21 实际存储器中段的位置

图2-22 一个实际地址可对应多个逻辑地址

段首址来源于4个段寄存器,偏移地址来源于SP,BP,SI,DI,IP和计算出的有效地址。寻址时到底使用哪个段寄存器与哪个偏移地址存放寄存器搭配(表2-5所示的逻辑地址源就示出了这种搭配关系),由8086的BIU部件根据执行操作的种类和应取得的数据类型确定。

表2-5 逻辑地址源

4.堆栈

一般的微机系统都需要设立堆栈来暂存一批数值数据或地址数据,为此,要在内存储器中特别划分出一段存储区。在该存储区中,存取数据按“后进先出”的原则进行。

8086由于采用了存储器分段,为了表示这特别划分出来的存储区,使用了一种称为堆栈段的段来表示。堆栈段中存取数据的地址由堆栈段寄存器SS和堆栈指针SP来规定。SS中存放堆栈段的首地址,SP中存放栈顶的地址,此地址表示栈顶离段首址的偏移量,存取数据都在栈顶进行。堆栈段的示意图如图2-23(a)所示。

图2-23 8086系统的堆栈及入栈、出栈操作

一个系统使用的堆栈数目不受限制,在有多个堆栈的情况下,各个堆栈用各自的段名来区分,但其中只有一个堆栈段是当前执行程序可直接寻址的,称此堆栈段为当前堆栈段。SS中存放的是当前堆栈段的首址,SP指出当前堆栈段中的栈顶位置。一个堆栈段最大的范围为64KB。用堆栈深度来表示堆栈段的容量大小。

堆栈的最典型应用是在调用子程序的程序中,为了实现程序正确的返回,需要将断点地址和主程序中的一些数据暂存起来。断点地址是指调用指令CALL的下条指令的地址,包括CS的值和IP的值。它们是在执行CALL时自动被存入堆栈的。主程序中的一些数据是指运行子程序时可能要被覆盖的一些CPU内部寄存器的数据,这些数据需要用专门的入栈操作指令PUSH推入堆栈暂存,而子程序执行完毕,又应该用出栈指令POP将它们弹回原来的地方,并按“先进后出”的原则编排出栈指令顺序(可参考第3章例3-2)。最后,子程序执行到返回指令RET时,自动将入栈的断点地址返送回IP和CS中,根据IP具备的程序跟踪功能,又回到主程序的断点地址继续执行后续程序。

8086的堆栈操作有两种:入栈操作PUSH和出栈操作POP,均为16位的字操作,而且都在栈顶进行。栈顶是由堆栈指针SP所指的“实”栈顶。所谓“实”栈顶,是以最后推入堆栈信息所在的单元为栈顶,如图2-23(a)所示的10508H单元。图2-23(b)为入栈操作,在执行入栈指令PUSH AX时,先修改堆栈指针SP,完成(SP)-2→(SP)后,才能将AX的内容推入。推入时,先推高8位AH入栈,完成(AH→((SP+1))=(10507H),然后推低8位AL入栈,完成(AL)→((SP))=(10506H)。入栈完成后,因(SP)=10506H而指向新的栈顶。图2-23(c)示出出栈操作POP BX和POP AX。在执行第1条POP BX指令时,先将位于栈顶上的两个单元的内容弹出到BX,具体执行的操作可分为如下3步。

第1步:将栈顶内容,即((SP))=(10506H)→BL(低位)。

第2步:将((SP)+1)=(10507H)→BH(高位)。

第3步:修改指针,即(SP)+2→(SP),此时的(SP)=10508H也指向一个新的栈顶。

接着执行第2条出栈指令POP AX,其操作类同于POP BX,只是最后修改指针(SP)+2→(SP)的结果,使(SP)=1050AH,又指向一个新的栈顶。

5.专用的和保留的存储单元

Intel公司为保证与未来产品的兼容性,规定在存储区的最低地址区和最高地址区留出一些单元供CPU作为某些特殊功能专用,或为将来开发软件、硬件产品而保留。其中:

① 00000H~0007FH(共128B)用于中断,以存放中断向量表。

② FFFF0H~FFFFFH(共16B)用于系统复位启动。

IBM遵照这种规定,在IBM PC/XT这种最通用的8086系统中也做了相应规定:

① 00000H~003FFH(共1KB)用来存放中断向量表,该表上列出了每个中断处理子程序的入口地址。一个入口地址占4字节,前2字节中存放入口的偏移地址(IP值),后2字节中存放入口的段首址(CS值)。因此,1KB区域可以存放256个中断处理程序的入口地址。对一个具体的机器系统而言,256级中断是用不完的,空着的可供用户扩展功能时使用。当系统启动引导完成,这个区域的中断向量表就建立起来了。

② B0000H~B0FFFH(共4KB)是单色显示器的视频缓冲区,存放单色显示器当前屏幕显示字符所对应的ASCII码及其属性。

③ B8000H~BBFFFH(共16KB)是彩色显示器的视频缓冲区,存放彩色显示器当前屏幕像素点所对应的代码。

④ FFFF0H~FFFFFH(共16B)用于系统复位启动,一般存放一条无条件转移指令,使系统在上电或复位时,自动转到系统的初始化程序,这个区域被包含在系统的ROM范围内,在ROM中驻留着系统的基本I/O系统程序BIOS。

由于有了专用的和保留的存储单元的规定,使用Intel公司CPU的IBM PC/XT及各类兼容微机都具有较好的兼容性。

6.单模块程序的4个现行段

为了使存储器分段及其在汇编语言程序中的具体实现尽早结合,下面列举了一个具有4个现行段的单模块汇编语言程序框架的实例。

【例2-1】 程序功能:完成5+2=7的运算,将结果存入数据区中的SUM单元,并在屏幕上显示出来。此例的重点在于了解运行一个程序所需的4个现行段(代码段、数据段、堆栈段和附加段)在程序中如何表示出来。这里,设前3个段是相互分开的,而附加段与数据段完全重叠。每个段都标有段名,用伪指令SEGMENT/ENDS来定义,每个段不超过64KB,由DOS操作系统给它们分配存储地址。

源程序框架及其4个现行段编排如下。注:程序中每一行的编号是为进行下面的解释加入的,在实际输入程序时不应该输入。

1 ;SAMPLE    PROGRAM FOR ADD AND DISPLAYING SUM TO THE SCREEN
;
2 DATA        SEGMENT                       ;数据段
3 AUGEN       DDB 05H
4 ADDEN       DDB 02H
5 SUM         DB ?
6 DATA        ENDS
;
7 STACK       SEGMENT PARA STACK ′STACK′    ;堆栈段
8 DB 64       DUP(?)
9 STACK       ENDS
;
10 CODE       SEGMENT                       ;代码段
;
11            ASSUME CS:CODE,DS:DATA,SS:STACK,ES:DATA
12 START      PROC FAR
13            PUSH DS                       ;保存返回地址
14            MOV AX,0
15            PUSH AX
16            MOV AX,DATA ;初始化DS,ES
17            MOV DS,AX
18            MOV ES,AX
;
19            MOV AL,AUGEND                ;完成05H+02H的程序正文
20            ADD AL,ADDEND
21            MOV SUM,AL                   ;存结果
;
22            ADD AL,30H                   ;将结果变为ASCII码
23            MOV DL,AL                    ;显示结果
24            MOV AH,02H
25            INT 21H
;
26            RET                           ;返回DOS
27 START      ENDP
;
28 CODE       ENDS
;
29END         START                         ;汇编结束

第1行为程序的注释,用“;”开头,为非执行部分。2~6行为数据段,该段内设置有运行本程序所需的被加数AUGEND,加数ADDEND,还保留有一个存结果的单元SUM,它们均用伪操作指令DB进行定义。本段的段名为DATA,第2行和第6行是段定义语句,分别定义段的开始和终结。7~9行为堆栈段,段名为STACK,第7行和第9行分别定义该段的开始和终结,该段中用DB定义了一个深度为64字节的堆栈区。10~28行为代码段,该段段名为CODE,第10行和第28行分别定义该段的开始和终结。代码段中用“;”开始的汉字部分为注释(也可用英文注释),用它来说明一条或几条指令的作用;第12行为过程(Procedure)的说明语句PROC,过程有NEAR(近)过程和RAR(远)过程之分。这里为FAR过程,它是DOS下面的一个远过程。第12行和第27行分别表示过程的开始和结束,第26行的RET是返回语句,本例中应返回到DOS。第11行ASSUME也是一个说明语句,由它设定运行该程序时所需的4个现行段是什么段名,其中的ES和DS用相同段名,表示这两个段完全重叠。第19~21行是完成5+2运算并存储结果的部分,是本程序的正文部分。运算结果7是一位十进制数,可用第22行指令将其变为ASCII码后,由第23~第25行的一个中断调用INT 21H的02H功能交由屏幕显示出来。第19~25行是本模块的程序段,它随应完成的功能不同而不同。第13~18行对不同功能的程序段都是需要的,是不能改变的部分,通常称为程序的内务操作,这是保证程序能正确运行,并返回操作系统而不被死锁的必须部分。内务操作又包含两部分:第13~15行是保存返回地址(其原理将在第4章中讲述)所用的3条固定语句,第16~第18行是对数据段和附加段进行初始化,即把DOS给每个段分配的首地址(段名的地址)填入相应的段寄存器DS、ES中,对除CS以外的用到的现行段均需填入。第2~6行的数据段和第7~9行的堆栈段随程序段的功能不同,应用的情况也不同。最后指出,本例所示的单模块程序结构是汇编语言源程序结构框架之一,可供学习指令系统一章时仿照使用。

还要说明,这种程序结构,只要在程序段中没有调用指令或没有中断发生,堆栈段被默认也是可行的;这里的附加段也可以不设置。不设置的段就不在ASSUME语句中出现,也不对相应的段寄存器进行初始化装填。

2.2.8 8086 I/O端口组织

1.I/O端口

8086 CPU和外部设备之间是通过I/O接口芯片作为界面进行联系的,达到在其间传输信息的目的。每个I/O接口芯片上可有一个至几个端口。一个n位的端口实际上是存取数据的一个n位的寄存器。在系统设计时,要为每个端口分配一个地址,称为端口地址或端口号。每个端口号和存储器单元地址一样,应具有唯一性。

2.I/O端口编址方式

一般来说,I/O端口有存储器映象编址和独立编址两种方式。

(1)存储器映象编址的I/O

在这种编址方式下,将I/O端口地址置于存储器空间,和存储单元统一编址。因此,存储器的各种寻址方式都可用来寻址端口。这样,对端口的访问非常灵活,而且I/O接口与CPU的连接方法和存储器芯片与CPU的连接方法类似。但这种方法的缺点是端口占用了一部分存储器空间,而且端口地址的位数和存储器单元地址位数一样,比独立编址的I/O端口地址长,因而访问速度较慢。Motorola系列的CPU采用了这种I/O端口的编址方法。

(2)独立编址的I/O

凡是设有专门输入指令IN和输出指令OUT的CPU对I/O端口都进行独立编址。8086 CPU采用了这种编址方法。它使用20条地址总线中的A15~A0(16条)地址线对端口地址进行编址,因此,最多可访问的I/O端口可有64K个8位端口或32K个16位端口,任何两个相邻的8位端口可以组成一个16位端口。和访问存储器一样,对奇数地址的16位端口的访问,要进行两次才能完成。端口的寻址不分段,因而不用段寄存器。8086的端口地址仍为20位,高4位总是为0。

3.保留的I/O端口

在8086的64KB的I/O空间中,F8H~FFH这8个地址是Intel公司保留使用的,用户不能占用,否则将影响用户系统与Intel公司产品的兼容性。