汇编语言(以8086为例)
汇编语言(以8086为例)
01-序言
P3 由机器指令到汇编指令
机器语言: 是机器指令的集合。
机器指令: 是一台机器可以正确执行的命令。机器指令由一串二进制数表示,例如01010000。
由于机器指令的可读性极差,所以有了汇编语言与汇编指令。
汇编语言: 的主体是汇编指令。
汇编指令和机器指令表达的意思是相同的,他们的差别在于指令的表示方法上:汇编指令是机器指令便于记忆的书写形式;汇编指令是机器指令的助记符。
- 机器指令:1000100111011000
- 汇编指令:MOV AX BX
- 操作:将寄存器BX的内容送到AX中
工作过程: 汇编语言-> 编译器-> 机器码-> 计算机执行
汇编语言程序包含:
- 汇编指令——机器码的助记符
- 伪指令——由编译器执行
- 其他符号——由编译器识别
P4 计算机的组成
CPU想要工作,就必须向它提供指令和数据。而指令和数据在存储器(内存)中存放。
指令和数据的表示: 数据和指令存储在内存或磁盘上;数据和指令都是二进制信息。
存储单元: 存储器被划分为若干个存储单元,每个存储单元从0开始顺序编号;实际的内存空间很“大”。例如8086有20条数据线,寻址空间为1MB。
总线: 从物理上将,总线是一根根导线的集合;逻辑上则将总线分为地址总线、数据总线、控制总线三种总线。
CPU通过地址总线来指定存储单元,地址总线的宽度决定了可寻址的存储单元的大小,N根地址总线对应2N的寻址空间。
CPU与内存或其他器件之间的数据传输是通过数据总线来进行的,数据总线的宽度决定了CPU和外界的数据传送的速度。
CPU通过控制总线对外部器件进行控制,控制总线是一些不同控制线的集合,控制总线的宽度决定了CPU对外部器件的控制能力。
P5 内存的读写和地址空间
CPU想要进行数据的读写,必须和外部器件进行三类信息的交互:
- 存储单元的地址(地址信息)
- 器件的选择,读/写命令(控制信息)
- 读或写的数据(数据信息)
内存地址空间: 可用于存储数据和指令的内存地址的范围。由地址总线决定。
从CPU看地址空间:
- 将各类存储器看作一个逻辑存储器——统一编址
每个物理存储器在这个逻辑存储器中占有一个地址段,即一段地址空间(下图左侧为8086)
- 独立编址
P6 语言实践环境搭建
本课以8086CPU为例进行讲解。
因此实践方案为——DOS环境。具体软件为DOSBox
02-访问寄存器和内存
P7 本章导言
P8 寄存器及数据存储
寄存器: 是CPU内部的信息存储单元
8086CPU有14个寄存器: 8086CPU所有的寄存器都是16位的,可以存放两个字节,存放的最大值为 216-1
- 通用寄存器:AX、BX、CX、DX
- 变址寄存器:SI、DI
- 指针寄存器:SP、BP
- 指令指针寄存器:IP
- 段寄存器:CS、SS、DS、ES
- 标志寄存器:PSW
但是有个问题,8086上一代CPU中的寄存器都是8位的,如何保证程序的兼容性?
解决方案: 将通用寄存器均分为两个独立的8位寄存器使用。例如,AX可以分为AH(high)和AL(low)。
8086是16位CPU,所以8086的字长(word size) 为16bit
一个字(word) 可以存放在一个16位寄存器中,这个字的高位字节存放在这个寄存器的高8位寄存器,这个字的低位字节存放在这个寄存器的低8位寄存器。
P9 mov和add指令
在用中学
懂了吧!那么直接开始做题
例01:注意溢出哦,溢出直接舍掉
例02:注意溢出哦,溢出直接舍掉,不能进到AH中
P10 确定物理地址的方法
CPU访问内存单元时要给出内存单元的地址。
所有的内存单元构成的存储空间是一个一维的线性空间,每个内存单元在这个空间中都有唯一的地址,这个唯一的地址称为物理地址。
8086有20位地址总线,可传送20位地址,寻址能力为1M。
8086是16位结构的CPU,运算器一次最多可以处理16位的数据,寄存器的最大宽度为16位。
那么在8086内部处理、传输、暂存的地址也是16位,寻址能力也只有16位。可是它有20位地址总线,剩下的难道浪费了吗?
8086给出了一个解决方案:用两个16位地址(段地址、偏移地址)合成一个20位的物理地址。
地址加法器合成物理地址的方法:物理地址 = 段地址*16+偏移地址
对于一个物理地址,可以通过不同的段地址和偏移地址获得。
P11 内存的分段表示法
已知8086CPU用“物理地址 = 段地址*16+偏移地址”的方式给出内存单元的物理地址。
段地址,就是分段的方式管理内存。但是要注意,内存本身并没有分段,段的划分来自于CPU。
根据合成物理地址的方法,可以得出两个结论:
- 因为物理地址 = 段地址*16+偏移地址,段地址被*16了,所以一个段的起始地址一定是16的倍数(即最后一位一定为0,12340H这样)
- 偏移地址为16位,16位地址的寻址能力为64K,所以一个段的最大长度为64K
8086中存储单元地址的表示方法:
例如,数据在21F60H内存单元中,段地址是2000H,那么有两种表示方法:
- 数据存在内存 2000:1F60 单元中
- 数据存在内存的 2000H 段中的 1F60H 单元中
物理地址 = 段地址*16+偏移地址,那段地址和偏移地址分别怎么来呢?
段地址很重要!所以8086提供了4个段寄存器,专门用于存放段地址:
- CS——代码段寄存器
- DS——数据段寄存器
- SS——栈段寄存器
- ES——附加段寄存器
而偏移地址可以用多种方法提供——8086有丰富的取址方式
P12 Debug的使用
Debug是DOS系统中著名的调试程序,也可以运行在windows系统上
使用Debug程序,可以查看CPU各种寄存器中的内容、内存的情况,并且在机器指令级跟踪程序的运行
具体操作:
打开DOSBox,先进行挂载,选中工作目录
mount c d:\0105\MASM //将Dos里的c盘,绑定到本机上d:\0105\MASM这个目录
c: //切换到c盘
dir //ls,确定一下挂载是否成功
debug的使用
debug //启动程序,看到'-',说明启动成功
查看寄存器:R命令
r //查看寄存器内容
r [寄存器名] //改变指定寄存器内容,输入在冒号时输入改变值
r[寄存器名] //不加空格也可以
查看内存中的内容:D命令
d //列出预设地址内存处,128个字节的内容
d [段地址:偏移地址] //列出内存中指定地址处,128个字节的内容dd
d [段地址:偏移地址] [结尾偏移地址] //列出内存中指定地址处,指定范围的内容
改变内存中的内容:E命令
e [段地址:偏移地址] [数据1] [数据2] //默认是16进制,不需要加'H'
e [段地址:偏移地址] //逐个询问式修改。空格=接受,继续。回车=结束
将机器指令翻译成汇编指令:U命令
u [段地址:偏移地址]
以汇编指令的格式在内存中写入机器指令:A命令
a [段地址:偏移地址] //逐个询问式。空白内容时回车即可退出。
执行机器指令:T命令
t //执行 CS:IP 处的指令
退出debug:Q命令
q //quit
P13 CS、IP与代码段
CS: 代码段寄存器
IP: 指令指针寄存器
CS:IP: CPU将内存中 CS:IP 指向的内容当做指令执行
8086工作过程简要描述:
- 从CS:IP指向的内存单元读取指令,读取的指令进入指令缓冲器;
- IP = IP+所读取指令的长度,从而指向下一条指令;
- 执行指令。转到步骤(1),重复这个过程
P14 jmp指令
当我们需要修改下一条将要执行的指令时,本质上是需要修改CS、IP的值
那么该如何改变CS、IP的值呢?
使用debug直接修改——不靠谱;
用mov指令修改CS、IP寄存器——有些操作时不合法的
所以答案是,jmp指令: 修改CS、IP的指令
使用方法:
- 同时修改CS、IP的内容
jmp [段地址:偏移地址]
。例如:jmp 2000:3
功能:用指令中给出的段地址修改CS,偏移地址修改IP - 仅修改IP的内容
jmp [某一合法寄存器]
。例如:jmp ax
功能:类似于mov IP,ax
jmp指令实践:
P15 内存中字的存储
对于8086CPU,16位作为一个字。
16位的字存储在一个16位的寄存器中,高8位放高字节,低8位放低字节。
16位的字在内存中需要2个连续字节存储,低位字节存放在低地址单元,高位字节存放在高地址单元。
例如,存放4E20H 和 0012H
字单元: 由两个地址连续的内存单元组成,存放一个字型数据(16位)
原理: 8086一个字是16位,需要内存中两个连续的字节来存储。
P16 用DS和[address]实现字的传送
CPU要读取一个内存单元的时候,必须先给出这个内存单元的地址。而内存地址由段地址和偏移地址组成。怎样同时给出两个地址呢?
解决方案:DS和[address]配合
- 用DS寄存器存放要访问的数据的段地址
- 偏移地址用[...]的形式直接给出
- 注意:不能直接给DS赋值,只能通过通用寄存器给DS赋值
- 注意区分是,读写一个字还是一个字型
P17 DS与数据段
要求:实现对内存单元中数据的访问
处理方法:(DS):([address])
。用DS存放数据段的段地址;用相关指令访问数据段中的具体单元,单元地址由[address]指出
将123B0H~123BAH的内存单元定义为数据段:
练习:
总结(不一定完全)
用mov指令操作数据:
指令形式 | 示例 |
---|---|
mov 寄存器, 数据 | mov ax,8 |
mov 寄存器, 寄存器 | mov ax,bx |
mov 寄存器, 内存单元 | mov ax,[0] |
mov 内存单元, 寄存器 | mov [0],ax |
mov 段寄存器, 寄存器 | mov ds,ax |
mov 寄存器, 段寄存器 | mov ax,ds |
mov 内存单元, 段寄存器 | mov [0],ds |
mov 段寄存器, 内存单元 | mov ds,[0] |
add和sub指令:
指令形式 | 示例 |
---|---|
add 寄存器, 数据 | add ax,8 |
add 寄存器, 寄存器 | add ax,bx |
add 寄存器, 内存单元 | add ax,[0] |
add 内存单元, 寄存器 | add [0],ax |
用DS和[address]形式访问内存中数据段方法小结:
- 字在内存中存储时,要用两个地址连续的内存单元来存放。字的低位字节存放在低地址单元中,高位字节存放在高地址单元中
- 用mov指令访问内存单元时,可以在mov指令中只给出单元的偏移地址,此时段地址默认在DS寄存器中
- [address]表示一个偏移地址位address的内存单元
- 在内存和寄存器之间传送字型数据时,高地址单元和高8位寄存器对应,低地址单元和低8位寄存器对应
- mov 、add 、sub是具有两个操作对象的指令,访问内存中的数据段。
jmp是具有一个操作对象的指令,对应内存中的代码段
P18 栈及栈操作的实现
栈:先进后出。每次操作最顶上的元素。
栈有两个基本的操作:入栈和出栈
现在的CPU都有栈的设计,例如8086就提供相关的指令,支持用栈的方式访问内存空间。
主要有两个指令:
- push:入栈。
push ax
,将ax的数据送入栈中 - pop:出栈。
pop ax
,从栈顶取出数据送入ax
push ax:
- SP = SP-2
- 将ax中的内容送入SS:SP指向的内存单元处,SS:SP此时指向新栈顶
pop ax:
- 将SS:SP指向的内存单元处的数据送入ax中
- SP = SP+2,SS:SP指向当前栈顶下面的单元,以当前栈顶下面的单元为新的栈顶。
push、pop实质上就是一种内存传送指令,可以在寄存器和内存之间传送数据。与mov指令不同的是,Push和pop指令访问的内存单元的地址不是在指令中给出的,而是由SS:SP指出。
提问:
- CPU如何知道一段内存空间被当作栈使用?
- 执行push和pop的时候,如何知道哪个单元是栈顶单元?
回答:
在8086CPU中,由两个与栈相关的寄存器——SS和SP
栈段寄存器SS——存放栈顶的段地址,栈顶指针寄存器SP——存放栈顶的偏移地址
任何时刻,**SS:SP**
指向栈顶元素。
注意,栈空间是从高地址向低地址增加的。
如何避免栈顶超界问题?
8086CPU并不能保证栈不会超界。
P19 关于“段”的总结
物理地址 = 段地址*16+偏移地址
- 编程时,可以根据需要,将一组内存单元定义为一个段
- 起始地址为16的倍数,长度小于等于64K的一组地址连续的内存单元,定义为一个段
- 将一段内存定义为一个段,用一个段地址指示段,用偏移地址访问段内单元——在程序中可以完全由程序员安排。
目前为止已经学习了三种段:
- 数据段
将段地址放在DS中
用mov、add、sub等访问内存单元的指令时,CPU将我们定义的数据段中的内容当作数据段来访问 - 代码段
将段地址放在CS中,将段中第一条指令的偏移地址放在IP中。CS:IP指向即将执行的指令
CPU将执行我们定义的代码段中的指令 - 栈段
将段地址放在SS中,将栈顶单元的偏移地址放在SP中。SS:SP指向栈顶
CPU在需要进行栈操作(push、pop)时,将我们定义的栈段当作栈空间来使用。
03-汇编语言程序
P20 本章导学
P21 用汇编语言写的源程序
汇编程序结构
汇编程序: 包含汇编指令和伪指令的文本。
汇编程序的注释是;
,默认为10进制
汇编程序->编译器->机器码
汇编程序可以是:
- 在Debug中直接写入指令编写的汇编程序
适用于功能简单、短小精悍的程序
只需要包含汇编指令即可 - 单独编写成源文件后再编译为可执行文件的程序
适用于编写大程序
不只有汇编指令,还有指导编译器工作的伪指令
源程序由一些段构成,这些段存放代码、数据,或将某个段当作栈空间
伪指令
程序中的三种伪指令:
- 段定义
一个汇编程序是由多个段组成的,这些段被用来存放代码、数据或者当作栈空间来使用
一个有意义的汇编程序中至少要有一个段,这个段用来存放代码
定义程序中的段:每个段都需要有段名
格式:段名 segment
——段的开始;段名 ends
——段的结束 - end(不是ends)
汇编程序的结束标记。若程序结尾处不加end,编译器在编译程序时,不知道程序在何处结束。 - assume(假设)
含义是,假设某一段段寄存器和程序中的某个用segment...ends
定义的段相关联。
格式:assume 寄存器:段名
例如,assume cs:codesg
指cs寄存器与codesg这个段关联,将定义的codesg当作程序的代码段来使用
如何写出一个程序来
- 定义一个段
- 实现处理任务
- 指出程序在何处结束
- 段与段寄存器关联
- 加上程序返回的代码
以实现2*3的程序为例:
程序中可能的错误
- 语法错误
程序在编译时被编译器发现的错误,容易被发现 - 逻辑错误
在运行时发生的错误,不容易被发现
P22 由源程序到程序运行
由源程序到程序运行的过程
编写 -> 源程序文件.asm
-> 编译 -> 目标文件.obj
-> 连接 ->可执行文件.exe
编译
软件/指令:masm
连接
软件/指令:link
P23 用debug跟踪程序的执行
用debug装载程序:debug file.exe
有256(100H)字节的程序段前缀(PSP),作为数据区
用p命令/g命令执行:
p24 [...]
和(...)
-
[...]
:表示一个内存单元。是汇编语法规定的表示形式 -
(...)
:表示一个内存单元(只能用物理地址)或寄存器中的内容。是为学习方便大家约定的内容。
p25 Loop指令
功能:实现循环(计数型循环)
指令格式:loop 标号
CPU执行loop指令时的操作:
- (cx) = (cx) -1
- 判断cx中的值,不为零则转至标号处执行程序;如果为零则向下执行。
注意:cx中要提前存放循环次数,循环多少次则cx设置为多少;并且需要定义一个标号。
用loop指令编程实例:
p26 Loop指令使用再例
注意,一定要分析,累加之后,是否有可能超过dx的存储能力
如果你在编写的时候遇到了这个问题:mov ax,[6]
被编译成了mov ax,6
别急,看下一章
p27 段前缀的使用
为了解决这个“异常”现象,对策是:在[idata]前面显式地写上段寄存器。
这些出现在访问内存单元的指令中,用于显式的指明内存单元的段地址的'ds、cs、ss、es',在汇编语言中被称为段前缀。
p28 在代码段中使用数据
对策:
- 在程序的段中存放数据,运行时由操作系统分配空间。
- 段的类别:数据段、代码段、栈段
- 各类段中均可由数据
- 可以在单个的段中安置,也可以将数据、代码、栈放入不同的段中
- dw(define word):定义一个字
- db:定义一个字节
- dd:定义一个双字
直接在代码段中添加数据的程序有问题,因为CPU并不知道代码段是从cs:0010
开始的,还将IP设置为0000。
所以怎么让代码从cs:0010
开始呢?
用标号标记程序的开始
p29 在代码段中使用栈
p30 将数据、代码、栈放入不同段
将数据、栈、代码放在一个段的缺点:
- 程序显得混乱,编程和阅读时都要注意何处是数据、何处是栈、何处是代码;
- 只能应用于要处理的数据很少的,栈空间也小,代码也少的情况。
解决方法:将数据、代码、栈放入不同段
注意代码段仍然需要标号标记
注意:DS是程序开始的位置,但是后面紧跟着100H的PSP,所以DS:100H
才是数据开始的地方。
04-内存寻址方式
P31 本章导学
P32 处理字符问题
汇编程序中,用'abc'
的方式指明数据是以字符形式给出的。编译器将它们转化成相对应的ASCII码。ascii码是一字节大小的数据。
可根据这个,做大小写转换:
- 小写转大写:and 1101 1111
- 大写转小写:or 0010 0000
P33 [bx+idata]方式寻址
[bx+idata]
表示一个内存单元,它的偏移地址为(bx)+idata,即bx中的数据加上idata
mov ax,[bx+idata]/mov ax,[idata+bx]
的含义:(ax) = ((ds)*16+200+(bx))
。
mov ax,[bx+idata]
的其他常见写法:mov ax,200[bx]/mov ax,[bx].200
应用: 做数组处理。可将(ds)*16+idata
看作基址,将bx看做偏移量。
P34 SI和DI寄存器
SI和DI是8086CPU中和BX功能相近的寄存器。
SI: source index,源变址寄存器。
DI: destination index,目标变址寄存器。
区别: SI和DI不能分成两个8位寄存器来用。
应用问题: 用寄存器SI和DI实现将字符串'welcome to masm!'复制到它后面的数据区中。
解决方法: 用DS:SI
指向要复制的原始字符串,用DS:DI
指向目的空间。用一个循环来完成复制
P35 [bx+si]和[bx+di]方式寻址
[bx+si]:表示一个内存单元,偏移地址为(BX)+(SI)
。将BX称作基址,SI称作变址。 基址变址寻址。
P36 [bx+si+idata]和[bx+di+idata]方式寻址
[bx+si+idata]:表示一个内存单元,偏移地址为(BX)+(SI)+Idata
。
其他不同的写法:mov ax,[bx+200+si] / mov ax,[200+bx+si] / mov ax,200[bx][si] / mov ax,[bx].200[si] / mov ax,[bx][si].200
P37 不同寻址方式的灵活应用
对内存的寻址方式
形式 | 名称 | 特点 | 意义 | 示例 |
---|---|---|---|---|
[idata] | 直接寻址 | 用一个常量/立即数来表示地址 | 用于直接定位一个内存单元 | mov ax,[200] |
[bx] | 寄存器间接寻址 | 用一个变量来表示内存地址 | 用于间接定位一个内存单元 | mov bx,0 mov ax,[bx] |
[bx+idata] | 寄存器相对寻址 | 用一个变量和一个常量表示地址 | 可在一个起始地址的基础上,用变量间接定位内存单元 | mov bx,4 mov ax[bx+200] |
[bx+si] | 基址变址寻址 | 用两个变量表示地址 | mov ax,[bx+si] | |
[bx+si+idata] | 相对基址变址寻址 | 用两个变量和一个常量表示地址 | mov ax,[bx+si+200] |
案例1:将datasg段中每个单词的头一个字母改为大写字母
案例2:将datasg段中每个单词都改为大写字母
如何解决需要进行双重循环,但只有一个cx的冲突:
法一: 用dx暂存cx
缺陷: CPU中寄存器有限,这样的话dx就会被占用,太浪费
法二: 用固定空间保存数据
缺陷: 在运行过程中,该数据有被覆盖的风险
法三: 用栈保存数据
P38 不同寻址方式演示
P39 用于内存寻址的寄存器
只有**bx、bp、si、di**
可以用在 **[...]**
内对内存单元进行寻址
bx以外的通用寄存器、段寄存器不可以用在[...]内
**bx、bp、si、di**
的搭配:
bx、bp的区别: bx默认ds段;bp默认ss段
P40 在哪里?有多长?
P41 寻址方式的综合应用
要求: 编程修改内存中的过时数据。
P42 用div指令实现触发
切记,提前在默认的寄存器中设置好被除数,且默认寄存器不作别的用处。
P43 用dup设置内存空间
功能:dup和db、dw、dd等数据定义伪指令配合使用,用于进行数据重复。
使用格式:db [重复次数] dup ('重复的内容')
05-流程转移与子程序
P44 本章导学
P45 ”转移“综述
需求: 在时间过程中,长需要改变程序执行的流程
转移指令:
- 可以控制CPU执行内存中某处代码的指令
- 可以修改IP,或同时修改CS和IP的指令
转移指令的分类:
- 按转移行为
段内转移:只修改IP,如jmp ax
段间转移:同时修改CS和IP,如jmp 1000:0
- 根据指令对IP修改的范围不同
段内短转移:IP修改范围为-128~127
,用一个字节来表示
段内近转移:IP修改范围为-32768~32767
,用一个字来表示 - 按转移指令
无条件转义指令:jmp
条件转移指令:jcxz
循环指令:loop
过程
终端
P46 操作符offset
格式:offset 标号
。如offset start
用法: 通过offset
获取标号所在指令的偏移地址
P47 jmp指令
jmp指令的功能:无条件转移,可以只修改IP,也可以同时修改CS和IP
jmp指令的用法:jmp short 标号
注意:jmp short
的机器指令中,包含的是跳转目标指令和IP的相对位置,而不是目标地址
两种段内转移:
-
jmp short 标号
:
功能:(IP)=(IP)+8位位移
核心:8位位移 = "标号"的地址-jmp指令后的第一个字节的地址;8位位移由编译程序在编译时算出 -
jmp near ptr 标号
:
功能:(IP)=(IP)+16位位移
核心:8位位移 = "标号"的地址-jmp指令后的第一个字节的地址;8位位移由编译程序在编译时算出
远转移:jmp far ptr 标号
直接指明了跳转到的目的地址,即包含了标号的段地址CS和偏移地址IP
转移地址在寄存器中的jmp:jmp 16位寄存器
功能:IP = (16位寄存器)
例如:jmp ax
转移地址在内存中的jmp指令
注意:段地址在高位,偏移地址在低位;段地址和偏移地址各用一个字保存
P48 其他转移指令
jcxz指令
格式:jcxz 标号
功能: 如果(cx)=0,则跳转到标号处执行;当(cx)≠0时,程序向下执行
loop指令
P49 call 指令和 ret 指令
call 标号
:调用子程序
ret
:从子程序返回
实质: 都是流程转移指令,它们都修改IP,或同时修改CS和IP
call指令
call指令进行的两步操作:
- 将当前的 IP 或 CS和IP 压入栈中;
相当于:push IP
- 转移到标号处执行指令
相当于:jmp near ptr 标号
ret指令
P50 call 和 ret 的配合使用
P51 mul指令
P52 汇编语言的模块化程序设计
P53 寄存器冲突的问题
实际上就是计组里讲的,“保护现场“
P54 标志寄存器
P55 带进(错)位的加减法
adc
格式:adc 操作对象1,操作对象2
功能: 操作对象1 = 操作对象1+操作对象2+CF
adc是带进位加法指令,利用了CF位上记录的进位值
两个讨论的回答:
- 不可以。
sub ax,ax
是为了将CF置为零 - 不可以。
inc di
是不会产生进位的;但add di,2
是有可能产生进位标记的
sbb
格式:sbb 操作对象1,操作对象2
功能: 操作对象1 = 操作对象1-操作对象2-CF
sbb是带借位减法指令,利用了CF位上记录的借位值
P56 cmp和条件转移指令
cmp
格式:cmp 操作对象1,操作对象2
功能: 操作对象1-操作对象2
注意: cmp是比较指令,功能相当于减法指令,只是不保存结果,只影响标志寄存器
应用: 用标志寄存器的值来确定比较结果
条件转移指令
P57 条件转移指令应用
P58 DF标志和串传送指令
串传送指令
rep指令
**rep+movsb/movsw**
能高效地成片传送数据
06-中断及外部设备操作
P59 阶段导学
P60 移位指令
- 逻辑左移(SHL):
将最高位(最左边的)移入CF中,其他位向左移一位,末尾补零
相当于,X=X*2 - 循环左移(ROL):
将最高位(最左边的)移入CF中,其他位向左移一位,末尾最高位 - 逻辑右移(SHR):
将最低位(最右边的)移入CF中,其他位向右移一位,首位补零
相当于,X=X/2 - 算术右移(SAR):
将最低位(最右边的)移入CF中,其他位向右移一位,最高位不变
最高位不变是为了保证“符号”不变。通常情况下,最高位是符号位
当移动位数大于1时,必须使用cl
表示移动位数。
P61 操作显存数据
屏幕上的内容 = 显存中的数据。 所以想要操作屏幕上的内容,就要操作显存中的数据。
更具体的说,就是需要操作B8000h~BFFFFh
,即显示缓冲区中的数据。
每一个显示内容需要两个字节。 低位字节存储要显示符号的ASCII码,高位字节存储显示属性,即颜色。其中高位字节中内容的前四位,是存储的背景颜色;后四位是存储的前景颜色。
P62 描述内存单元的标号
简化版offset。
当没有冒号的时候,被称为数据标号,数据标号能同时描述内存地址和单元长度(即db=字节,dw=字)
数据标号描述的内存地址,是包括段地址的。
扩展用法:将标号当做数据来定义(用c语言来做通俗解释就是:指针的指针)
P63 数据的直接定址表
直接定址表
问题求解思路: 利用表,在两个数据集合之间建立一种映射关系,用查表的方法根据给出的数据得出其在另一集合中的对应数据。
优点:
- 算法清晰和简洁
- 加快运算速度
- 使程序易于扩充
- 空间换时间的方案
P64 代码的直接定址表(NO)
P65 中断及其处理
低位保存IP,高位保存CS
P66 编制中断处理程序
中断向量表:0000:0000~0000:03FF
P67 单步中断
P68 由int指令引发的中断
P69 BIOS和DOS中断处理
P70 端口的读写
P71 操作CMOS RAM芯片
- 128 个字节的 RAM 中存储:内部实时钟、系统配置信息、相关的程序(用于开机时配置系统信息)。
- CMOS RAM 芯片靠电池供电,关机后其内部的实时钟仍可正常工作, RAM 中的信息不丢失。
- 该芯片内部有两个端口,端口地址为70h和71h,CPU 通过这两个端口读写CMOS RAM:
70h地址端口,存放要访问的CMOS RAM单元的地址;
71h数据端口,存放从选定的单元中读取的数据,或要写入到其中的数据。 - 读取CMOS RAM的两个步骤:
将要读取的单元地址送入70h地址端口;
从数据端口71h读出指定单元的内容。
P72 外设连接与中断
P73 PC机键盘的处理过程
断码 = 通码+80H
P74 定制键盘输入处理
P78 磁盘读写
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了