8086内部结构分析

1978年,intel推出了8086处理器,这是第一代16位微处理器,直接寻址能力1MB,14个程序员可见的寄存器,24种操作数寻址方式。

8086处理器功能特性

  • 1978年,8086第一代16位微处理器,第一次将流水线思想引进微处理器
  • 1979年推出80888位外部数据总线,兼容当时丰富的8位配套器件, 其内部结构与8086基本相同
  • 直接主存寻址能力1MB,20条地址线
  • 14 个 16 位程序员可见寄存器,也就是段内偏移最多64K
  • 支持多种寻址方式,支持8、16位无符号和带符号二进制或十进制运算,包括乘除法,但不支持浮点数运算
  • 指令的操作数可以是16位,也可以是8位
  • 输出输出的方式是独立编址
  • 内存地址空间分段,可寻址1MB,接口地址空间不分段,可寻址64KB
  • 24 种操作数寻址方式
  • 操作数类型:位、字节、字和块

8086处理器体系结构

BIU:总线接口单元

​ 负责与存储器、IO接口传递数据:

  • 从内存取指令,送到指令队列
  • 配合EU从指定的内存单元或IO端口取数据
  • 将EU的操作结果送到指定的内存单元或IO端口

EU:执行单元

​ 负责指令的执行(算术、逻辑、移位运算,有效地址计算,控制命令、……)

工作原理

BIU取指令,EU执行指令,两者相互配合

  • 指令队列有2+空字节,BIU自动取指 → 指令队列
  • EU总是从指令队列前部取指令去执行
  • 如果指令需要访问M或I/O,EU会请求BIU去完成
  • 由于存在指令队列,BIU和EU可以并行工作

寄存器结构

一共24个16位寄存器,其中4个数据寄存器和标志寄存器都分为两部分,高八位和低八位。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
graph TD

subgraph 寄存器
subgraph 通用寄存器
数据寄存器[数据寄存器]
数据寄存器 --> AX
数据寄存器 --> BX
数据寄存器 --> CX
数据寄存器 --> DX
AX[AX]
BX[BX]
CX[CX]
DX[DX]
指针寄存器[指针寄存器]
指针寄存器 --> 堆栈指针
指针寄存器 --> 基数指针
堆栈指针[SP]
基数指针[BP]
变址寄存器[变址寄存器]
变址寄存器 --> 源地址
变址寄存器 --> 目的地址
源地址[SI]
目的地址[DI]
end

控制寄存器[控制寄存器]
控制寄存器 --> 指令指针
控制寄存器 --> 标志寄存器
指令指针[IP]
标志寄存器[PSW]

端寄存器[端寄存器]
端寄存器 --> 代码段
端寄存器 --> 数据段
端寄存器 --> 堆栈段
端寄存器 --> 附加段
代码段[CS]
数据段[DS]
堆栈段[SS]
附加段[ES]
end

  • 能够放置操作数,能够随便引用的寄存器只有上面8个,并且指针寄存器只能当做16位寄存器使用,不能拆成两个8位使用

  • 下面这个表就是规定16位和8位数据,寄存器的编号(使用三位二进制即可),段寄存器是单独编号的,寄存器是通过操作码特定部分得知操作数是多少位

  • 注意这里四个数据寄存器的顺序是 ACDB

  • 寄存器的英文全称主要是对应的是该寄存器的用途

  • BX寄存器只是存了一个16位的地址偏移量,实际上默认的起始地址是\(DS\),于是形成地址是这样形成的:

    • 段寄存器\(DS\)存的是,起始地址的高16位,低4位默认是0
    • 然后\(BX\)里面存放的是16位的地址偏移量
    • 然后两个相加,得到内存地址,从这个内存地址读取数据到AX
    1
    2
    MOV AX, [BX]; B寄存器数据寄存器中唯一一个可以当做指针来用,进行间接寻址的寄存器

    • 若不使用\(BX\),可以使用SI或者\(DI\),也就是8086里面能够当指针来使用的就只有\(BX,SI,DI\)三个寄存器
  • \(CX\)是用来计数的,可以实现循环

    • \(Loop\)指令,会先将\(CX\)减一,若\(CX=0\),则不跳转,大于零则跳转到\(L1\)开始
    • 后面还有移位指令,若移位大于1,用低八位\(CL\)寄存器,进行计数
    • 串操作指令,使用CX寄存器记录数组的长度
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    MOV CX, 100 ; 设置 CX 寄存器为 100

    L1:
    ; 这里是循环的主体
    ; 可以在这里添加想要执行的代码

    LOOP L1 ; 循环,CX 减一,如果 CX 不为零,跳转到标签 L1

    ; 循环结束后的代码可以在这里继续

  • \(DX\)就是拿来记录数据的

    • 比如除法指令,得到的商在\(AX\)寄存器,余数就默认在\(DX\)寄存器里面
  • 除开以上的特殊情况,ABCD四个寄存器是可以随便使用的,存储一些临时的数据

  • \(SP\)\(BP\)是用来访问堆栈的,存放的是16位栈内偏移

  • \(SI\)\(DI\)是用来给串操作使用的,当然也可以用来当指针使用

  • 状态字寄存器无法独立的将低八位和高八位拿出来使用,所以图上画法有误

  • 附加段用途:

    • 比如两个数组的拷贝,两个数组在内存中的距离超过64K,超过一个段的最大距离了,于是一个数组可以放在\(DS\),另一个放在\(ES\)

    • MOV AX, ES:[BX]  ; 使用 ES 寄存器引用内存中 BX 寄存器指定的地址
      MOV AX, ES:[SI]  ; 使用 ES 寄存器引用内存中 SI 寄存器指定的地址
      MOV AX, ES:[DI]  ; 使用 ES 寄存器引用内存中 DI 寄存器指定的地址
  • 取指令:首地址放在\(CS\)里面,末尾填上4个0,段内偏移放在\(IP\)里面,两者相加的结果作为内存地址,从而取得下一条指令。

  • 管理堆栈:对于一个栈,大地址应该在堆栈底部,然后通过\(SS\)\(SP\)两个指针同时指向栈顶元素

  • 访问堆栈:不加中括号,使用\(BP\)作为指针的时候,默认的段起始地址是存在\(SS\)里面,可以拿来直接访问堆栈的某个位置的元素,而不破坏其原有的结构。MOV AX,[BP]也可以访问堆栈具体某个数。

  • 关于标志位寄存器

    • 先将\(OB5H\)放到\(AL\)寄存器,随后将\(8FH\)\(AL\)寄存器的值相加,值放在\(AL\)寄存器中

主存结构

  • 8086的主存和IO都是16位,支持16位读写,也支持8位读写(8088主存和IO都是8位,只支持8位读写)。

  • 分段结构

    • 代码、数据量不大 → 使其处于同一段内(64KB范围内)→ 可减少指令长度、提高运行速度

    • 内存分段为程序的浮动分配创造了条件

    • 形式地址6832H:1280H → 物理地址?68320H + 1280H = 695A0H

    • 各个分段之间可以重叠

    • 段寄存器的使用

    • 特殊的主存区域

      • 中断向量区:00000H~003FFH(1KB)每个中断向量占4个字节,256×4=1K
      • 显示缓冲区:单色 B0000H~B0FFFH(25×80×2=4000字节, 4KB)彩色 B8000H~BFFFFH(32KB)
      • 启动区:FFFF0H~FFFFFH(16个字节)无条件转移指令

例题