第一章 基础知识
汇编语言的三类指令
1. 汇编指令
汇编指令是直接被CPU执行的指令,它们在汇编时被转换为对应的机器码。主要包括:
-
数据传送指令:如
MOV
,用于在寄存器、内存和I/O端口之间传送数据。MOV AX, BX ; 将BX中的数据传送到AX
-
算术与逻辑指令:如
ADD
、SUB
,用于进行数学计算和逻辑操作。ADD AX, BX ; 将BX中的数据加到AX中
-
控制转移指令:如
JMP
、CALL
,用于改变程序执行流程。JMP LABEL ; 无条件跳转到LABEL标签
2. 伪指令
伪指令是指导汇编器工作的指令,它们在汇编过程中被处理,但不生成机器码。主要包括:
-
段定义指令:如
SEGMENT
、ENDS
,用于定义和结束一个段。DATA SEGMENT
-
数据定义指令:如
DB
、DW
,用于定义字节或字数据。DB 0x55 ; 定义一个字节数据0x55
-
常量定义指令:如
EQU
,用于定义常量。MAXLEN EQU 255 ; 定义常量MAXLEN为255
3. 符号指令
符号指令用于标识变量、常量、代码段等,在汇编过程中被替换为具体的地址或值。它们没有对应的机器码。
-
标签:用于标识代码中的位置。
LABEL: ; 定义一个标签LABEL
-
宏定义:如
MACRO
,用于定义宏,简化代码编写。MYMACRO MACRO ; 宏定义内容 ENDM
CPU对存储器的读写
CPU对存储器的读写操作是计算机系统中最基本和最重要的功能之一。以下是详细说明CPU如何与存储器交互进行读写操作的过程,包括存储单元的介绍。
存储器结构与存储单元
存储器(Memory)由多个存储单元(Memory Cell)组成,每个存储单元都有唯一的地址(Address),用于存储数据(Data)。存储器可以分为两大类:
- 随机存取存储器(RAM):可读可写,用于存储临时数据。RAM是易失性存储器,断电后数据会丢失。
- 只读存储器(ROM):只能读取,用于存储固件和不可变数据。ROM是非易失性存储器,断电后数据仍然保存。
每个存储单元通常存储一个字节(8位)或一个字(16位)的数据,存储单元按照地址从零开始顺序编号。CPU通过地址访问这些存储单元中的数据。
总线系统
CPU通过总线(Bus)与存储器进行通信。总线系统包括:
地址总线
数据总线
数据总线是一组用于在CPU、内存和外设设备之间传输数据的信号线。数据总线的宽度决定了每次传输的数据量。例如,32位数据总线一次可以传输32位(4字节)的数据。
控制总线
控制总线是一组用于传输控制信号的信号线,这些信号用于协调和管理系统各部分之间的操作。控制信号包括读/写命令、时钟信号、中断请求等。
-
地址总线是一组用于传输存储单元地址的信号线。它的主要作用是指定内存或外设设备中的位置,以便CPU可以读写数据。地址总线的宽度决定了CPU可以访问的最大内存空间。例如,16位地址总线可以访问2^16 = 65,536个存储单元。
- 功能:传输内存地址。
- 影响:地址总线的宽度决定了CPU可以寻址的内存空间范围。例如,32位地址总线可以寻址4GB的内存空间。
- 方向:地址总线一般是单向的(寻址信息通常是从CPU发出)
- 功能:传输数据,包括指令和数据字。
- 影响:数据总线的宽度影响了系统的数据传输速率和性能。例如,64位数据总线相比于32位数据总线,可以一次传输更多的数据,从而提高系统性能。
- 方向:数据总线是双向的,因为数据既可以从CPU发送到内存或I/O设备,也可以从内存或I/O设备发送到CPU。
- 功能:传输控制信号以管理和协调系统操作。
- 影响:控制总线的效率和设计直接影响系统的整体性能和稳定性。它们确保数据和地址的传输按照正确的时序进行。
- 方向:控制总线是双向的,因为控制信号既可以从CPU发送到其他组件,也可以从其他组件发送到CPU。
读操作
读取存储器的过程可以分为以下几个步骤:
-
地址传输:
- CPU将要读取的数据地址放入地址总线。地址总线的宽度决定了CPU能够访问的最大内存地址范围。
MOV AX, [1234H] ; 读取内存地址1234H的数据到AX寄存器
- CPU将要读取的数据地址放入地址总线。地址总线的宽度决定了CPU能够访问的最大内存地址范围。
-
控制信号发送:
- CPU通过控制总线发送读命令(Read Command)到存储器。控制信号通知存储器准备好数据。
; 控制总线发送读信号
- CPU通过控制总线发送读命令(Read Command)到存储器。控制信号通知存储器准备好数据。
-
数据传输:
- 存储器接收到读命令后,将指定地址的数据放入数据总线。数据总线的宽度决定了一次能够传输的数据量。
; 数据总线传输数据
- 存储器接收到读命令后,将指定地址的数据放入数据总线。数据总线的宽度决定了一次能够传输的数据量。
-
数据接收:
- CPU从数据总线读取数据,并将其存入指定的寄存器或内存位置。
; CPU从数据总线接收数据并存入AX
- CPU从数据总线读取数据,并将其存入指定的寄存器或内存位置。
写操作
写入存储器的过程可以分为以下几个步骤:
-
地址传输:
- CPU将要写入数据的地址放入地址总线。
MOV [1234H], AX ; 将AX寄存器的数据写入内存地址1234H
- CPU将要写入数据的地址放入地址总线。
-
数据传输:
- CPU将要写入的数据放入数据总线。
; 数据总线传输要写入的数据
- CPU将要写入的数据放入数据总线。
-
控制信号发送:
- CPU通过控制总线发送写命令(Write Command)到存储器。控制信号通知存储器接收数据。
; 控制总线发送写信号
- CPU通过控制总线发送写命令(Write Command)到存储器。控制信号通知存储器接收数据。
-
数据存储:
- 存储器接收到写命令后,将数据总线上的数据写入指定地址的存储单元。
; 存储器将数据写入指定地址
- 存储器接收到写命令后,将数据总线上的数据写入指定地址的存储单元。
内存地址空间的分配
在计算机体系结构中,地址总线是单向的,即CPU向内存或I/O设备发送地址信息。CPU通过逻辑地址空间访问物理存储器,当CPU在某个地址空间中执行读写操作时,实际上是在相应的物理存储器单元中进行这些操作(对ROM写无效,ROM是只读)
8086PC内存地址空间的分配
-
主存储器地址空间 (RAM)
- 地址范围:00000h 到 9FFFFh
- 描述:这是系统的主内存区域,用于存放运行中的程序和数据。
-
显示地址空间
- 地址范围:A0000h 到 BFFFFh
- 描述:这是显示卡的显存地址空间。当向这个区域的内存单元中写数据时,实际上是向显示存储器中写入数据,这些数据会被显示卡输出到显示器上。
- 详细说明:在这个区域内,A0000h 到 AFFFFh 通常用于EGA/VGA显卡的显存,B0000h 到 B7FFFh 用于单色显示器(MDA),B8000h 到 BFFFFh 用于彩色显示器(CGA)。
-
各类ROM地址空间
- 地址范围:C0000h 到 FFFFFh
- 描述:这部分内存用于存储只读存储器(ROM)中的数据,包括BIOS程序和扩展卡的固件等。
- 详细说明:C0000h 到 C7FFFh 一般用于显示适配器的BIOS,E0000h 到 FFFFFh 则是系统BIOS区域。
CPU 与不同类型设备交互
“CPU 与所有设备(包括内存和外设)的交互,其主要区别在于访问的地址空间不同。CPU 通过不同的地址空间(内存地址空间、I/O 地址空间或内存映射 I/O 地址空间)与这些设备进行数据传输和控制操作。
示例一:CPU 与 RAM 交互
-
读操作:
- 发送地址:CPU 将要读取的内存地址(例如 0x0000)放在地址总线上。
- 控制信号:CPU 通过控制总线发送读命令。
- 数据传输:RAM 控制器读取地址 0x0000 处的数据,并通过数据总线传送给 CPU。假设返回的数据是 0x1234。
CPU -> 地址总线 -> 0x0000 CPU -> 控制总线 -> 读命令 RAM -> 数据总线 -> 0x1234
-
写操作:
- 发送地址和数据:CPU 将要写入的内存地址(例如 0x0000)和数据(例如 0x5678)放在地址总线和数据总线上。
- 控制信号:CPU 通过控制总线发送写命令。
- 数据写入:RAM 控制器将数据 0x5678 写入地址 0x0000。
CPU -> 地址总线 -> 0x0000 CPU -> 数据总线 -> 0x5678 CPU -> 控制总线 -> 写命令 RAM <- 数据总线 <- 0x5678
示例二:CPU 与显卡显存交互(内存映射 I/O)
-
写操作:
- 发送地址和数据:CPU 将要写入的显存地址(例如 0xA0000)和数据(例如图像数据)放在地址总线和数据总线上。
- 控制信号:CPU 通过控制总线发送写命令。
- 数据写入:显卡控制器将数据写入显存的指定地址 0xA0000。这些数据将被显示在屏幕上。
CPU -> 地址总线 -> 0xA0000 CPU -> 数据总线 -> 图像数据 CPU -> 控制总线 -> 写命令 显存 <- 数据总线 <- 图像数据
示例三:CPU 与键盘交互(I/O 端口映射)
-
读操作:
- 发送 I/O 端口地址:CPU 将要读取的 I/O 端口地址(例如 0x60)放在地址总线上。
- 控制信号:CPU 通过控制总线发送读命令。
- 数据传输:键盘控制器读取按键数据,并通过数据总线传送给 CPU。假设返回的按键数据是 0x1E(代表某个按键)。
CPU -> 地址总线 -> 0x60 CPU -> 控制总线 -> 读命令 键盘控制器 -> 数据总线 -> 0x1E
第2章寄存器
0. 典型的CPU结构
典型的CPU由运算器、控制器、寄存器等器件构成,这些器件通过片内总线相连。
- 运算器:进行信息处理
- 控制器:控制各种器件进行工作
- 寄存器:进行信息存储
1. 8086 CPU的寄存器
8086 CPU有14个16位寄存器:
- 通用寄存器:AX、BX、CX、DX
- 索引寄存器:SI、DI
- 指针寄存器:SP、BP、IP
- 段寄存器:CS、SS、DS、ES
- 状态寄存器:PSW
16位结构CPU的特性
- 运算器一次最多可以处理16位的数据
- 寄存器的最大宽度为16位
- 寄存器和运算器之间的通路为16位
数据处理
- 字节 (byte):8位,可以存在8位寄存器中
- 字 (word):16位,由两个字节组成,可以存在一个16位寄存器中
存储模式
8086采用小端模式:高地址存放高位字节,低地址存放低位字节。
2. 通用寄存器
通常用于存放一般性的数据,有AX、BX、CX、DX,它们可分为两个可独立使用的8位寄存器:
- AX = AH(高8位) + AL(低8位)
- BX = BH(高8位) + BL(低8位)
- CX = CH(高8位) + CL(低8位)
- DX = DH(高8位) + DL(低8位)
一个8位寄存器所能存储的数据范围是0 ~ 255(0x00 ~ 0xFF)。
3. 物理地址生成
8086 CPU有20位地址总线,可以传送20位地址,达到1MB寻址能力。然而,内部一次性处理、传输、暂时存储的地址为16位。8086 CPU通过在内部用两个16位地址合成的方法来形成一个20位的物理地址:
- 物理地址 = 段地址 × 16 + 偏移地址
例如,8086 CPU要访问地址为123C8H的内存单元:
1230H左移一位(空出4位)加上00C8H合成123C8H。
4. 段寄存器
通过将内存划分为段,用段地址指示段,用偏移地址访问段内的单元,可以用分段的方式来管理内存。段寄存器有4个:CS、DS、SS、ES,提供内存单元的段地址。
段的定义
- 数据段:用来存放数据
- 代码段:用来存放代码
- 栈段:用来存放栈
段的起始地址
一个段的起始地址一定是16的倍数,偏移地址为16位,变化范围为0-FFFFH,所以一个段的长度最大为64KB。
5. 指令执行
CS和IP
CS为代码段寄存器,IP为指令指针寄存器。CPU将CS、IP中的内容当作指令的段地址和偏移地址,用它们合成指令的物理地址,然后执行指令。8086 CPU的工作过程简要描述如下:
- 从CS指向的内存单元读取指令,读取的指令进入指令缓冲器
- IP = IP + 读取指令的长度,从而指向下一条指令
- 执行指令
- 重复上述过程
JMP指令
能够改变CS、IP内容的指令被统称为转移指令,例如:
jmp 段地址:偏移地址
:用指令中给出的段地址修改CS,偏移地址修改IPjmp 某一合法寄存器
:仅修改IP的内容,如jmp ax
实验:
DEBUG 指令 (实验)
A: 以汇编指令的格式在内存中写入一条机器指令
功能:允许用户以汇编语言的格式输入指令,DEBUG 程序会将这些汇编指令转化为机器码并存入内存。
语法:A 段地址:偏移地址
示例:
A 1000:0100
MOV AX, 4C00
INT 21
解释:在内存地址 1000:0100
处输入 MOV AX, 4C00
和 INT 21
两条指令。
D: 查看内存
功能:显示内存中的内容。
语法:D 段地址:起始偏移地址 [结束偏移地址]
示例:
D 1000:0100
解释:查看从内存地址 1000:0100
开始的内容。
E: 向内存中写入机器码
功能:向内存中写入数据,允许用户直接以机器码的形式向内存中写入数据。
语法:E 段地址:偏移地址 数据 [数据 [...]]
示例:
E 1000:0100 4C 00 21
解释:在内存地址 1000:0100
处写入数据 4C 00 21
。
G: 程序直接运行到指定地址位置
功能:将程序运行到指定的内存地址。
语法:G 偏移地址
示例:
G 0100
解释:从偏移地址 0100
处开始运行程序。
R: 查看, 改变寄存器
功能:显示或修改寄存器的内容。
语法:R [寄存器]
示例:
R AX
AX 0000
:1234
解释:查看 AX
寄存器的值,并将其修改为 1234
。
T: 执行一条机器指令
功能:单步执行一条机器指令。
语法:T
示例:
T
解释:执行当前内存位置的一条机器指令。
U: 查看内存指令翻译的汇编指令
功能:反汇编内存中的机器指令。
语法:U 段地址:偏移地址
示例:
U 1000:0100
解释:反汇编从内存地址 1000:0100
开始的指令。
P: 当遇到 int 21H 正常结束指令时使用P指令
功能:遇到 int 21H
结束指令或 loop
指令时执行到下一个非循环指令。
语法:P
示例:
P
解释:执行到 int 21H
或下一个非循环指令。
实验思考
(1)2000:0为什么不写为2000:0000
在DOS DEBUG工具中,段地址和偏移地址的表示法通常是简洁的,只需要指定实际有意义的部分。例如,2000:0
和2000:0000
确实表示的是同一个物理内存地址,但通常在写入时,只需要写出有意义的部分即可。
(2)2000H的H是?
在汇编语言和低级编程中,地址或数值后缀H
表示该数值是以十六进制(hexadecimal)表示的。
H
表示这是一个十六进制数。
(3)ROM无法修改
只读存储器(ROM),因此无法通过DEBUG工具直接修改它。这解释了为什么你的修改没有生效。ROM的内容在生产时已经固定,通常无法在运行时改变
实验内容
步骤3生产日期
步骤4