矫情招人烦 發表於 2019-5-5 21:05:00

王爽8086汇编语言第二版学习笔记

<h2>1 基础知识</h2>
<h3>1.1 存储单元</h3>
<p>一个存储单元存储一个字节</p>
<h3>1.2 地址总线</h3>
<p>一个CPU有N根地址线,则可以说这个CPU的地址总线的宽度为N。这样的CPU最多可以寻找2的N次方个内存单元。</p>
<p>地址总线的宽度决定了CPU的寻址能力。</p>
<h3>1.3 数据总线</h3>
<p>数据总线的宽度决定了CPU和外界的数据传送速度。8根数据总线一次可以传送一个8位二进制数据(1个字节)。</p>
<p>8086的数据总线宽度为16。</p>
<p>数据总线的宽度决定了CPU与其他器件进行数据传送时的一次数据传送量。</p>
<h3>1.4 控制总线</h3>
<p>控制总线的宽度决定了CPU对外部器件的控制能力。</p>
<h3>1.5 内存地址空间</h3>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201905/1201453-20190505210343986-985498801.png" alt=""></p>
<p>地址0~7FFFH的32KB空间为主随机存储器的地址空间;</p>
<p>地址8000H~9FFFH的8KB空间为显存地址空间;</p>
<p>地址A000H~FFFFH的24KB空间为各个ROM的地址空间。</p>
<h2>2 寄存器</h2>
<h3>2.1 通用寄存器</h3>
<p>8086CPU的所有寄存器是16位的,可以存放两个字节。AX,BX.CX.DX这4个寄存器通常用来存放一般性的数据,被称为通用寄存器。</p>
<p>AX分为AH和AL;</p>
<p>BX分为BH和BL;</p>
<p>以此类推。</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201905/1201453-20190505211155748-386650231.png" alt=""></p>
<p>AX的低8位构成了AL寄存器,AX的高8位构成了AH寄存器。</p>
<h3>2.2 字在寄存器中的存储</h3>
<p>字节:Byte,一个字节由8个bit组成,可以存在8位寄存器中。</p>
<p>字:word,一个字由两个字节组成,这两个字节分别称为这个字的高位字节和低位字节。</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201905/1201453-20190505211537916-48807003.png" alt=""></p>
<h3>2.3 8086CPU的物理地址</h3>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201905/1201453-20190505212230722-862677233.png" alt=""></p>
<p>物理地址=段地址*16+偏移地址</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201905/1201453-20190505212248743-1217217603.png" alt=""></p>
<p>一个数据的二进制形式左移N位,相当于该数据乘以2的N次方;</p>
<p>段地址*16表示以二进制形式存放的段地址左移4位,十六进制形式存放的段地址左移1位。</p>
<h3>2.4 段</h3>
<p>CPU可以用不同的段地址和偏移地址形成同一个物理地址。</p>
<p>偏移地址16位,变化范围为0~FFFFH,仅用偏移地址来寻址最多可寻64KB个内存单元。</p>
<p>比如给定段地址1000H,用偏移地址寻址,CPU的寻址范围为:10000H~1FFFFH。</p>
<h3>2.5 CS和IP</h3>
<p>CS为代码段寄存器,IP为指令指针寄存器。</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201905/1201453-20190506205518638-798564000.png" alt=""></p>
<p>8086CPU的工作过程可以简要描述如下。</p>
<ol>
<li>从CS:IP指向的内存单元读取指令,读取的指令进入指令缓冲器;</li>
<li>IP=IP+所读取指令的长度,从而指向下一条指令;</li>
<li>执行指令。转到步骤1,重复这个过程</li>
</ol>
<h3>2.6 修改CS,IP的指令</h3>
<p>JMP 段地址:偏移地址:用指令中给出的段地址修改CS,偏移地址修改IP。</p>
<p>JMP 某一合法寄存器:用寄存器的值修改IP。</p>
<h3>2.7 代码段</h3>
<p>对于8086PC机,我们可以将长度为N(N&lt;=64KB)的一组代码,存在一组地址连续、起始地址为16的倍数的内存单元中。</p>
<h2>3 寄存器(内存访问)</h2>
<h3>3.1 字的传送</h3>
<p>在内存和寄存器之间传送字型数据时,高地址单元和高8位寄存器、低地址单元和低8位寄存器相对应。</p>
<h3>3.2 DS和</h3>
<p>DS是数据段寄存器,用来存放要访问数据的段地址。</p>
<p>""表示一个内存单元,X表示内存单元的偏移地址</p>
<h3>3.3 CPU提供的栈机制</h3>
<p>push ax:将寄存器ax中的数据送入栈中。</p>
<p>pop ax:从栈顶取出数据送入ax。</p>
<p>任意时刻,SS:SP指向栈顶元素。</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201905/1201453-20190506213820426-594858434.png" alt=""></p>
<p>push ax的执行过程</p>
<ol>
<li>SP=SP-2,SS:SP指向当前栈顶前面的单元,以当前栈顶前面的单元为新的栈顶;</li>
<li>将ax中的内容送入SS:SP指向的内存单元处。SS:SP此时指向新栈顶。</li>
</ol>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201905/1201453-20190506214217490-194907583.png" alt=""></p>
<p>SP=最底部的字单元的偏移地址+2,此时最底部的字单元的偏移地址SP是000EH,加2后SP是0010H</p>
<p>&nbsp;</p>
<p>pop ax的执行过程</p>
<p>将SS:SP指向的内存单元处的数据送入ax中;</p>
<p>SP=SP+2,SS:SP指向当前栈顶下面的单元,以当前栈顶下面的单元为新的栈顶。</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201905/1201453-20190506214620381-709142448.png" alt=""></p>
<p>用栈来暂存以后需要恢复的寄存器的内容时,寄存器出栈的顺序要和入栈的顺序相反</p>
<p>&nbsp;</p>
<h2>4 第一个程序</h2>
<h3>4.1 源程序</h3>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201905/1201453-20190508213431360-333879670.png" alt=""></p>
<p>1.伪指令</p>
<p>伪指令是由编译器来执行的指令,没有对应的机器指令。</p>
<p>(1)XXX segment&nbsp;XXX ends:定义一个段。</p>
<p>(2)end:汇编程序的结束标记。</p>
<p>(3)assume:它假设某一寄存器和程序中的某一个用segment...ends定义的段相关联</p>
<p>2.汇编指令</p>
<p>汇编指令有对应的机器码指令,可以被编译为机器指令,最终为CPU所执行。</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201905/1201453-20190507214433793-235661736.png" alt=""></p>
<h3>4.2 shell将可执行文件中的程序装载进入内存并使它运行</h3>
<p>PS:操作系统的外壳</p>
<p><em>任何通用的操作系统,都要提供一个称为shell(外壳)的程序,用户使用这个程序来操作计算机系统进行工作。</em></p>
<p><em>DOS中有一个程序command.com,这个程序在DOS中称为命令解释器,也就是DOS系统的shell。</em></p>
<ol>
<li>在DOS中直接执行1.exe时,是正在运行的command,将1.exe中的程序加载如内存;</li>
<li>command设置CPU的CS:IP指向程序的第一条指令(即程序的入口),从而使程序得以运行;</li>
<li>程序运行结束后,返回到command中,CPU继续运行command。</li>
</ol>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201905/1201453-20190507221032958-656773868.png" alt=""></p>
<h2>5 和loop指令</h2>
<h3>5.1 </h3>
<p>表示一个内存单元,它的偏移地址在bx中。</p>
<h3>5.2 Loop指令</h3>
<p>CPU执行loop指令的时候,要进行两步操作</p>
<ol>
<li>(cx)=(cx)-1</li>
<li>判断cx中的值,不为零则转至标号处执行程序,如果为零则向下执行</li>
</ol>
<h3>5.3 段前缀</h3>
<p>在访问内存单元的指令中显式地给出内存单元的段地址所在的段寄存器。比如:</p>
<p>mov ax,ds:</p>
<h3>5.4 一段安全的空间</h3>
<p>当我们需要直接向一段内存中写入内容时,这段内存空间不应存放系统或其他程序的数据或代码,否则写入操作很可能引发错误;</p>
<p>DOS方式下,一般情况,0:200~0:2ff空间中没有系统或其他程序的数据或代码,这段内存空间是安全的;</p>
<h2>6 包含多个段的程序</h2>
<h3>6.1 在代码段中使用数据</h3>
<p>dw:define word,用来开辟内存空间。</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201905/1201453-20190508213306204-1500447605.png" alt=""></p>
<p>end指令指明了程序的入口在标号start处</p>
<h3>6.2 在代码段中使用栈</h3>
<p>程序运行时,定义的数据存放在CS:0~CS:F单元中,共8个字单元。依次将这8个字单元的数据入栈,然后再依次出栈到这8个字单元中,从而实现数据的逆序存放。</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201905/1201453-20190520091946643-1912936205.png" alt=""></p>
<p>把start标识符去掉的话,编译器会认为CS:0是指令开始处,实际上CS:0~CS:F是数据,CS:10开始才是代码段。</p>
<h3>6.3 将数据、代码、栈放入不同的段</h3>
<p>将数据、栈和代码都放到一个段里面,会有以下两个问题:</p>
<ol>
<li>把它们放到一个段中使程序显得混乱;</li>
<li>在8086中,如果数据、栈和代码需要的空间超过64KB,就不能放在一个段中。</li>
</ol>
<p>如下程序实现和程序6.2同样的功能,不同之处在于它将数据、栈和代码放入了不同的段中。</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201905/1201453-20190520141337173-290848300.png" alt=""></p>
<h2>7 更灵活的定位内存地址的方法</h2>
<h3>7.1 and和or指令</h3>
<p>and指令:逻辑与指令,按位进行与运算。</p>
<p>例如:</p>
<p>mov al,01100011B</p>
<p>and al,00111011B</p>
<p>执行后:al=00100011B</p>
<p>or指令:逻辑或指令,按位进行或运算。</p>
<p>例如:</p>
<p>mov al,01100011B</p>
<p>or al,00111011B</p>
<p>al=01111011B</p>
<h3>7.2 以字符形式给出的数据</h3>
<div class="cnblogs_code">
<pre>assume <span style="color: rgba(0, 128, 128, 1)">cs:</span>code,<span style="color: rgba(0, 128, 128, 1)">ds:</span><span style="color: rgba(0, 0, 0, 1)">data
data segment
   db </span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">unIX</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">
   db </span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">forRK</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">
data ends
code segment
</span><span style="color: rgba(0, 128, 128, 1)">start:</span>
<span style="color: rgba(0, 0, 255, 1)">mov</span> al,<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">a</span><span style="color: rgba(128, 0, 0, 1)">'</span>
<span style="color: rgba(0, 0, 255, 1)">mov</span> bl,<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">b</span><span style="color: rgba(128, 0, 0, 1)">'</span>
<span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> ax,4c00h
</span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> 21h
code ends
end start</span></pre>
</div>
<p>&nbsp;db 'unIX'相当于"db 75H,6EH,49H,58H","u","n","I","X"的ASCII码分别为75H,6EH,49H,58H;</p>
<h3>7.3 大小写转换问题</h3>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201905/1201453-20190520144353895-601280249.png" alt=""></p>
<p>将“BaSiC”转化为小写,将'iNfOrMaTiOn'转化为大写</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201905/1201453-20190520150203618-887365793.png" alt=""></p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201905/1201453-20190520150212365-1934836520.png" alt=""></p>
<h3>7.4 用的方式进行数组的处理</h3>
<p>起始地址不需要像7.3显示地声明mov bx,5</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201905/1201453-20190520152152039-304192094.png" alt=""></p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201905/1201453-20190520152219628-1170815263.png" alt=""></p>
<p>以上汇编程序用C语言描述如下</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201905/1201453-20190520152325477-195975180.png" alt=""></p>
<h3>7.5 SI和DI</h3>
<p>si和di是8086CPU中和bx功能象进的寄存器, si和di不能够分成两个8位寄存器来使用。</p>
<p>下面的3组指令实现了相同的功能</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201905/1201453-20190520154342852-934843316.png" alt=""></p>
<p>下面的3组指令实现了相同的功能</p>
<p>&nbsp;<img src="https://img2018.cnblogs.com/blog/1201453/201905/1201453-20190520154350264-336157466.png" alt=""></p>
<h3>7.6 不同的寻址方式的灵活应用</h3>
<p>用一个常量来表示地址,可用于直接定位一个内存单元;</p>
<p>用一个变量来表示内存地址,可用于间接定位一个内存单元;</p>
<p>用一个变量和常量表示地址,可在一个起始地址的基础上用变量间接定位一个内存单元;</p>
<p>用两个变量表示地址;</p>
<p>用两个变量和一个常量表示地址。</p>
<p>编程,将datasg段中每个单词改为大写字母。</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201905/1201453-20190520162022428-285573527.png" alt=""></p>
<p>程序如下:</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201905/1201453-20190520161950910-1333814142.png" alt=""></p>
<h2>8 数据处理的两个基本问题</h2>
<h3>8.1 bx,si,di和bp</h3>
<p>1.在8086CPU中,只有bx,si,di和bp这4个寄存器可以用在"[...]"中来进行内存单元的寻址。</p>
<p>以下的指令都是正确的:</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201905/1201453-20190530162719023-307556358.png" alt=""></p>
<p>2.在[...]中,这4个寄存器可以单个出现,或只能以4种组合出现:bx和si、bx和di、bp和si、bp和di。</p>
<p>以下的指令都是正确的:</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201905/1201453-20190530162927628-1384483405.png" alt=""></p>
<h3>8.2 寻址方式</h3>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201905/1201453-20190530163246368-1571259396.png" alt=""></p>
<h3>8.3 指令要处理的数据有多长</h3>
<p>在没有寄存器名存在的情况下,用操作符X ptr指明内存单元的长度,X在汇编指令种可以为word或byte。</p>
<p>例如,下面的指令中,用word ptr指明了指令访问的内存单元是一个字单元。</p>
<div class="cnblogs_code">
<pre>mov word ptr ds:[<span style="color: rgba(128, 0, 128, 1)">0</span>],<span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">
inc word ptr
inc word ptr ds:[</span><span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">]
add word ptr ,</span><span style="color: rgba(128, 0, 128, 1)">2</span></pre>
</div>
<p>下面的指令中,用byte ptr指明了指令访问的内存单元是一个字节单元。</p>
<div class="cnblogs_code">
<pre>mov <span style="color: rgba(0, 0, 255, 1)">byte</span> ptr ds:[<span style="color: rgba(128, 0, 128, 1)">0</span>],<span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">
inc </span><span style="color: rgba(0, 0, 255, 1)">byte</span><span style="color: rgba(0, 0, 0, 1)"> ptr
inc </span><span style="color: rgba(0, 0, 255, 1)">byte</span> ptr ds:[<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">]
add </span><span style="color: rgba(0, 0, 255, 1)">byte</span> ptr ,<span style="color: rgba(128, 0, 128, 1)">2</span></pre>
</div>
<p>内存内容如下</p>
<p>2000:1000 FF FF FF FF FF FF ......</p>
<p>那么指令</p>
<p>mov ax,2000H</p>
<p>mov ds,ax</p>
<p>mov byte ptr ,1</p>
<p>将使内存变为:</p>
<p>2000:1000 01 FF FF FF FF FF ......</p>
<p>而指令</p>
<p>mov ax,2000H</p>
<p>mov ds,ax</p>
<p>mov word ptr ,1</p>
<p>将使内存中的内容变为:</p>
<p>2000:1000 01 00 FF FF FF FF ......</p>
<h3>8.4 寻址方式的综合应用</h3>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201905/1201453-20190531165048966-1268696403.png" alt=""></p>
<p>数据存放示意</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201905/1201453-20190531164931504-2048686003.png" alt=""></p>
<p>汇编和C语言对应关系</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201905/1201453-20190531164848486-1795320655.png" alt=""></p>
<p>8086CPU提供的如的寻址方式为结构化数据的处理提供了方便。一般来说,我们可以用的方式来访问结构体中的数据。</p>
<p>用bx定位整个结构体,用idata定位结构体中的某一个数据项,用si定位数组顶中的每个元素。</p>
<h3>8.5 div指令</h3>
<p>被除数:</p>
<p>如果除数为8位,被除数为16位,默认存放在AX;</p>
<p>如果除数为16位,被除数则为32位,在DX和AX中存放,DX存放高16位,AX存放低16位;</p>
<p>结果:</p>
<p>如果除数为8位,AL存储商,AH存储余数;</p>
<p>如果除数为16位,AX存储商,DX存储余数;</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201905/1201453-20190531170908664-1119567773.png" alt=""></p>
<p>编程,利用除法指令计算100001/100</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201905/1201453-20190531171232153-2020435455.png" alt=""></p>
<p>编程,利用除法指令计算1001/100</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201905/1201453-20190531171325174-625509118.png" alt=""></p>
<h3>8.6 dd和dup指令</h3>
<p>dd:define double word</p>
<p>dup:用来进行数据的重复</p>
<p>db 重复的次数 dup (重复的字节型数据)</p>
<p>db 重复的次数 dup (重复的字型数据)</p>
<p>db 重复的次数 dup (重复的双字型数据)</p>
<h2>9 转移指令的原理</h2>
<h3>9.1 操作符offset</h3>
<p>操作符offset在汇编语言中是由编译器处理的符号,它的功能是取得标号的偏移地址。</p>
<p>如下面的程序:</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201906/1201453-20190603174229775-1734636676.png" alt=""></p>
<h3>9.2 依据位移进行转移的jmp指令</h3>
<p>jmp short 标号:段内短转移,它对IP的修改范围为-128~127。</p>
<p>实际上,“jmp short 标号”的功能为:(IP)=(IP)+8位位移。</p>
<ul>
<li>8位位移=标号处的地址-jmp指令后的第一个字节的地址;</li>
<li>short指明此处的位移为8位位移;</li>
<li>8位位移的范围为-128~127,用补码表示;</li>
<li>8位位移由编译程序在编译时算出。</li>
</ul>
<p>“jmp short 标号”指令所对应的机器码中,并不包含转移的目的地址,而包含的是转移的位移。</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201906/1201453-20190603175406025-660340295.png" alt=""></p>
<p>jump near ptr 标号:段内近转移</p>
<p>“jmp near ptr 标号”的功能为:(IP)=(IP)+16位位移。</p>
<ul>
<li>16位位移=标号处的地址-jmp指令后的第一个字节的地址;</li>
<li>near ptr 指明此处的位移为16位位移,进行的时段内近转移;</li>
<li>16位位移的范围为-32768~32767,用补码表示;</li>
<li>16位位移由编译程序在编译时算出。</li>
</ul>
<h3>9.3 转移的目的地址在指令中的jmp指令</h3>
<p>jmp far ptr 标号:段间转移,又称为远转移。</p>
<p>far ptr指明了指令用标号的段地址和偏移地址修改CS和IP。</p>
<p>jmp far ptr s所对应的机器码包含转移的目的地址</p>
<h3>9.4 转移地址在内存中的jmp指令</h3>
<p>1.jmp word ptr 内存单元地址(段内转移)</p>
<p>功能:从内存单元地址处开始存放着一个字,是转移的目的偏移地址。</p>
<p>2.jmp dword ptr 内存单元地址(段间转移)</p>
<p>功能:从内存单元地址处开始存放着两个字,高地址处的字是转移的目的短地址,低地址处的字是转移的目的偏移地址</p>
<h3>9.5 jcxz指令</h3>
<p>jcxz指令为有条件转移指令,所有的有条件转移指令都是短转移,在对应的机器码中包含转移的位移,对IP的修改范围是:-128~127。</p>
<p>指令格式:jcxz标号(如果(cx)=0,转移到标号处执行)</p>
<p>操作:</p>
<p>当(cx)=0时,(IP)=(IP)+8位位移;</p>
<p>8位位移=标号处的地址-jcxz指令后的第一个字节的地址;</p>
<p>8位位移的范围时-128~127,用补码表示;</p>
<p>8位位移由编译程序在编译时算出。</p>
<p>当(cx)≠0时,程序向下执行。</p>
<h3>9.6 loop指令</h3>
<p>loop指令为循环指令,所有的循环指令都是短转移,在对应的机器码中包含转移的位移,而不是目的地址。对IP的修改范围都为:-128~127。</p>
<p>指令格式:loop标号((cx)=(cx)-1,如果(cx)≠0,转移到标号处执行。)</p>
<p>操作:</p>
<p>(1) (cx)=(cx)-1</p>
<p>(2) 如果(cx)≠0,(IP)=(IP)+8位位移</p>
<p>8位位移=标号处的地址-loop指令后的第一个字节的地址;</p>
<p>8位位移的范围为-128~127,用补码表示;</p>
<p>8位位移由编译程序在编译时算出。</p>
<p>如果(cx)=0,什么也不做(程序向下执行)。</p>
<h2>10 CALL和RET指令</h2>
<h3>10.1 ret和retf</h3>
<p>ret指令用栈中的数据,修改IP的内容,从而实现近转移</p>
<p>retf指令用栈中的数据,修改CS和IP的内容,从而实现远转移</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201906/1201453-20190611145930860-1178950393.png" alt=""></p>
<p>用汇编语法解释ret和retf指令,则</p>
<p>CPU执行ret指令时,相当于进行:</p>
<p>pop IP</p>
<p>CPU执行retf指令时,相当于进行:</p>
<p>pop IP</p>
<p>pop CS</p>
<h3>10.2 依据位移进行转移的call指令</h3>
<p>call标号(将当前的IP压栈后,转到标号处执行指令)</p>
<p>CPU执行此种格式的call指令时,进行如下的操作:</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201906/1201453-20190611150353488-713699566.png" alt=""></p>
<p>16位位移=标号处的地址-call指令后的第一个字节的地址;</p>
<p>16位位移的范围为-32768~32767,用补码表示;</p>
<p>16位位移由编译程序在编译时算出。</p>
<p>CPU执行"call 标号"时,相当于进行:</p>
<p>push IP</p>
<p>jmp near ptr 标号</p>
<h3>10.3 转移的目的地址在指令中的call指令</h3>
<p>"call far ptr 标号"实现的是段间转移。</p>
<p>CPU执行此种格式的call指令时,进行如下操作。</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201906/1201453-20190611150806379-640523574.png" alt=""></p>
<p>CPU执行“call far ptr 标号”时,相当于进行:</p>
<p>push CS</p>
<p>push IP</p>
<p>jmp far ptr 标号</p>
<h3>10.4 转移地址在寄存器中的call指令</h3>
<p>指令格式:call 16位reg</p>
<p>功能:</p>
<p>(SP)=(SP)-2</p>
<p>((SS)*16+(SP))=(IP)</p>
<p>(IP)=(16位reg)</p>
<p>CPU执行“call 16位reg”,相当于进行:</p>
<p>push IP</p>
<p>jmp 16位reg</p>
<h3>10.5 转移地址在内存中call指令</h3>
<p>(1)call word ptr 内存单元地址</p>
<p>用汇编语法来解释此种格式的call指令,则</p>
<p>CPU执行“call word ptr 内存单元地址”时,相当于进行:</p>
<p>push IP</p>
<p>jmp word ptr 内存单元地址</p>
<p>(2)call dword ptr 内存单元地址</p>
<p>用汇编语法来解释此种格式的call指令,则:</p>
<p>CPU执行“call dword ptr 内存单元地址”时,相当于进行:</p>
<p>push CS</p>
<p>push IP</p>
<p>jmp dword ptr 内存单元地址</p>
<h3>10.6 mul指令</h3>
<p>mul是乘法指令</p>
<p>(1)两个相乘的数:两个相乘的数,要么都是8位,要么都是16位。如果是8位,一个默认放在AL中,另一个放在8位reg或内存字节单元中;如果</p>
<p>是16位,一个默认在AX中,另一个放在16位reg或内存字单元中。</p>
<p>(2)结果:如果是8位乘法,结果默认放在AX中;如果是16位乘法,结果高位默认在DX中存放,低位在AX中存放。</p>
<p>格式如下:</p>
<p>mul reg</p>
<p>mul 内存单元</p>
<p>例子1</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201906/1201453-20190611153157893-263503118.png" alt=""></p>
<p>例子2</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201906/1201453-20190611153216973-260084044.png" alt=""></p>
<p>&nbsp;</p>
<h2>11 标志寄存器</h2>
<p>标志寄存器具有以下作用</p>
<ol>
<li>用来存储相关指令的某些执行结果;</li>
<li>用来为CPU执行相关指令提供行为依据;</li>
<li>用来控制CPU的相关工作方式;</li>
</ol>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201906/1201453-20190621091434216-14742031.png" alt=""></p>
<h3>11.1 ZF标志</h3>
<p>零标志位</p>
<p>结果为0,zf=1;结果不为0,那么zf=0</p>
<h3>11.2 PF标志</h3>
<p>奇偶标志位</p>
<p>1的个数为偶数,pf=1;1的个数为奇数,那么pf=0;</p>
<h3>11.3 SF标志</h3>
<p>符号标志位</p>
<p>结果为负,sf=1;结果非负,sf=0;</p>
<h3>11.4 CF标志</h3>
<p>进位标志位</p>
<p>存在最高有效位向更高位进位/借位的情况,cf=1;否则cf=0</p>
<h3>11.5 OF标志位</h3>
<p>溢出标志位</p>
<p>进行有符号数运算的时候,结果超过了机器所能表示的范围称为溢出,溢出of=1,无溢出,of=0;</p>
<h3>11.6&nbsp; adc指令</h3>
<p>指令格式:adc 操作对象1,操作对象2</p>
<p>功能:操作对象1 = 操作对象1 + 操作对象2 + CF</p>
<p>例如adc ax,bx 实现的功能是:(ax)=(ax)+(bx)+CF</p>
<h3>11.7 sbb指令</h3>
<p>指令格式:sbb 操作对象1,操作对象2</p>
<p>功能:操作对象1 = 操作对象1-操作对象2-CF</p>
<p>比如指令 sbb ax,bx 实现的功能是:(ax)=(ax)-(bx)-CF</p>
<h3>11.8 cmp指令</h3>
<p>cmp的功能相当于减法指令,只是不保存结果。cmp指令执行后,将对标志寄存器产生影响。</p>
<p>cmp 指令格式:cmp 操作对象1,操作对象2</p>
<p>例如,指令cmp ax,ax,做(ax)-(ax)的运算,结果为0,但并不在ax中保存,仅影响flag的相关各位。指令执行后:zf=1,pf=1,sf=0,cf=0,of=0</p>
<h3>11.9 检测比较结果的条件转移指令</h3>
<p>je  等于则转移  zf=1</p>
<p>jne  不等于则转移  zf=0</p>
<p>jb  低于则转移  cf=1</p>
<p>jnb  不低于则转移  cf=0</p>
<p>ja  高于则转移  cf=0且zf=0</p>
<p>jna  不高于则转移  cf=1或zf=1</p>
<h3>11.10 DF标志和串传送指令</h3>
<h4>DF标志</h4>
<p>DF是方向标志位。</p>
<p>df=0  每次操作后si,di递增;</p>
<p>df=1  每次操作后si,di递减。</p>
<h4>串传送指令</h4>
<p>格式:movb</p>
<p>功能:执行movsb指令相当于进行下面几步操作。</p>
<p>((es)*16+(di))=((ds)*16+(si))</p>
<p>如果df=0则:(si)=(si)+1</p>
<p>      (di)=(di)+1</p>
<p>如果df=1则:(si)=(si)-1</p>
<p>      (di)=(di)-1</p>
<p>格式:movsw</p>
<p>movsw的功能是将ds:si指向的内存字单元中的字送入es:di中,然后根据标志寄存器df位的值,将si和di递增2或递减2。</p>
<p>rep movsb</p>
<p>用汇编语法来解释</p>
<p>s:movsb</p>
<p>loop s</p>
<p>rep的作用是根据cx的值,重复执行后面的串传送指令。</p>
<h3>11.11 pushf和popf</h3>
<p>pushf:将标志寄存器的值压入栈</p>
<p>popf:从栈中弹出数据</p>
<h2>12 内中断</h2>
<h3>12.1 中断向量表</h3>
<p>中断源:中断信息的来源</p>
<p>中断类型码:由8位组成</p>
<p>中断向量表:中断向量的列表</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201907/1201453-20190701091234097-2098849473.png" alt=""></p>
<p>中断类型码作为中断向量表的表项号,定位相应的表项,从而得到中断处理程序的入口地址。</p>
<p>内存0000:0000到0000:03FF的1024个单元中存放着中断向量表。</p>
<p>对于8086CPU,一个表项占两个字,高地址存放段地址,低地址存放偏移地址。</p>
<h3>12.2 中断过程</h3>
<p>简洁地描述中断过程</p>
<ol>
<li>取得中断类型码N</li>
<li>pushf</li>
<li>TF=0,IF=0</li>
<li>push CS</li>
<li>push IP</li>
<li>(IP)=(N*4),(CS)=(N*4+2)</li>
</ol>
<p>在最后一步完成后,CPU开始执行由程序员编写的中断处理程序。</p>
<h3>12.3 中断处理程序和iret指令</h3>
<p>中断处理程序的常规步骤</p>
<ol>
<li>保存用到的寄存器;</li>
<li>处理中断;</li>
<li>恢复用到的寄存器;</li>
<li>用iret指令返回;</li>
</ol>
<p>iret指令的功能用汇编语法描述为:</p>
<p>pop IP</p>
<p>pop CS</p>
<p>popf</p>
<h3>12.4 编程处理0号中断</h3>
<p>assume cs:code</p>
<p>code segment</p>
<p>start:设置es:di指向目的地址</p>
<p>  设置ds:si指向源地址</p>
<p>  设置cx为传输长度</p>
<p>  设置传输方向为正</p>
<p>  rep movsb</p>
<p>  设置中断向量表</p>
<p>  mov ax,4c00h</p>
<p>  int 21h</p>
<p>do0:显示字符串"overflow"</p>
<p>  mov ax,4c00h</p>
<p>  int 21h</p>
<p>code ends</p>
<p>end start</p>
<h3>12.5 设置中断向量</h3>
<p>mov ax,0</p>
<p>mov es,ax</p>
<p>mov word ptr es:,200h</p>
<p>mov word ptr es:,0</p>
<h3>12.6 单步中断</h3>
<p>CPU在执行完一条指令之后,如果检测到标志寄存器的TF位为1,则产生单步中断,引发中断过程。单步中断的中断类型码为1,它引发的中断过程如下。</p>
<ol>
<li>取得中断类型码1</li>
<li>标志寄存器入栈,TF、IF设置为0;</li>
<li>CS、IP入栈;</li>
<li>(IP)=(1*4),(CS)=(1*4+2);</li>
</ol>
<p>在进入中断处理程序之前,设置TF=0。从而避免CPU在执行中断处理程序的时候发生中断。</p>
<h3>12.7 响应中断的特殊情况</h3>
<p>在执行完ss寄存器传送数据的指令后,即便是发生中断,CPU也不会响应。</p>
<p>这样做的主要原因是,ss:sp联合指向栈顶,而对它们的设置应该连续完成。所以debug的时候mov sp,0不会单步中断。</p>
<h2>13 int指令</h2>
<h3>13.1 int指令</h3>
<p>int指令的格式:int n,n为中断类型码,它的功能是引发中断过程。</p>
<p>CPU执行int n指令,相当于引发一个n号中断的中断过程,执行过程如下。</p>
<ol>
<li>取得中断类型码n</li>
<li>标志寄存器入栈,TF、IF设置为0;</li>
<li>CS、IP入栈;</li>
<li>(IP)=(1*4),(CS)=(1*4+2);</li>
</ol>
<p>mov ah,9</p>
<p>int 21h</p>
<p>调用21h例程9号子程序</p>
<h3>13.2 编写供应用程序调用的中断例程</h3>
<p>功能:将一个全是字母,以0结尾的字符串,转化为大写。</p>
<p>参数:ds:si指向字符串的首地址。</p>
<p>assume cs:code</p>
<p>data segment</p>
<p>db 'conversation',0</p>
<p>data ends</p>
<p>code segment</p>
<p>start:</p>
<p>  mov ax,data</p>
<p>  mov ds,ax</p>
<p>  mov si,0</p>
<p>  int 7ch</p>
<p>  mov ax,4c00h</p>
<p>  int 21h</p>
<p>code ends</p>
<p>end start</p>
<p>安装程序如下</p>
<div class="cnblogs_code">
<pre>assume <span style="color: rgba(0, 128, 128, 1)">cs:</span><span style="color: rgba(0, 0, 0, 1)">code
code segment

</span><span style="color: rgba(0, 128, 128, 1)">start:</span>
      <span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> ax,cs
      </span><span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> ds,ax
      </span><span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> si,offset capital
      </span><span style="color: rgba(0, 0, 255, 1)">mov</span> ax,<span style="color: rgba(128, 0, 128, 1)">0</span>
      <span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> es,ax
      </span><span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> di,200h
      </span><span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> cx,offset capitalend - offset capital
      </span><span style="color: rgba(0, 0, 255, 1)">cld</span>
      <span style="color: rgba(0, 0, 255, 1)">rep</span> <span style="color: rgba(0, 0, 255, 1)">movsb</span>

      <span style="color: rgba(0, 0, 255, 1)">mov</span> ax,<span style="color: rgba(128, 0, 128, 1)">0</span>
      <span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> es,ax
      </span><span style="color: rgba(0, 0, 255, 1)">mov</span> word ptr <span style="color: rgba(0, 128, 128, 1)">es:</span>,200h
      </span><span style="color: rgba(0, 0, 255, 1)">mov</span> word ptr <span style="color: rgba(0, 128, 128, 1)">es:</span>,<span style="color: rgba(128, 0, 128, 1)">0</span>

      <span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> ax,4c00h
      </span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> 21h

</span><span style="color: rgba(0, 128, 128, 1)">capital:</span>
      <span style="color: rgba(0, 0, 255, 1)">push</span><span style="color: rgba(0, 0, 0, 1)"> cx
      </span><span style="color: rgba(0, 0, 255, 1)">push</span><span style="color: rgba(0, 0, 0, 1)"> si
      
</span><span style="color: rgba(0, 128, 128, 1)">change:</span>
      <span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> cl,
      </span><span style="color: rgba(0, 0, 255, 1)">mov</span> ch,<span style="color: rgba(128, 0, 128, 1)">0</span>
      <span style="color: rgba(0, 0, 255, 1)">jcxz</span><span style="color: rgba(0, 0, 0, 1)"> ok
      </span><span style="color: rgba(0, 0, 255, 1)">and</span> byte ptr ,11<span style="color: rgba(128, 0, 128, 1)">011111b</span>
      <span style="color: rgba(0, 0, 255, 1)">inc</span><span style="color: rgba(0, 0, 0, 1)"> si
      </span><span style="color: rgba(0, 0, 255, 1)">jmp</span><span style="color: rgba(0, 0, 0, 1)"> short change
</span><span style="color: rgba(0, 128, 128, 1)">ok:</span>   
      <span style="color: rgba(0, 0, 255, 1)">pop</span><span style="color: rgba(0, 0, 0, 1)"> si
      </span><span style="color: rgba(0, 0, 255, 1)">pop</span><span style="color: rgba(0, 0, 0, 1)"> cx
      </span><span style="color: rgba(0, 0, 255, 1)">iret</span>
      
<span style="color: rgba(0, 128, 128, 1)">capitalend:</span><span style="color: rgba(0, 0, 255, 1)">nop</span><span style="color: rgba(0, 0, 0, 1)">

code ends

end start</span></pre>
</div>
<h3>13.3 BIOS和DOS中断例程的安装过程</h3>
<ol>
<li>&nbsp;开机后,CPU一加电,初始化(CS)=0FFFFH,(IP)=0,自动从FFFF:0单元开始执行程序。FFFF:0处有一条转跳指令,CPU执行该指令,转去执行BIOS中的硬件系统检测和初始化程序。</li>
<li>初始化程序将简历BIOS所支持的中断向量,即将BIOS提供的中断例程的入口地址登记在中断向量表中。注意,对于BIOS所提供的中断例程,只需将入口地址登记在中断向量表中即可,因为它们是固化到ROM中的程序,一直在内存中存在。</li>
<li>硬件系统检测和初始化完成后,调用int 19h 进行操作系统的引导。从此将计算机交由操作系统控制。</li>
<li>DOS启动后,除完成其他工作外,还将它所提供的中断例程装入内存,并建立相应的中断向量。</li>
</ol>
<h2>14 端口</h2>
<p>在PC机系统中,和CPU通过总线相连的芯片除各种存储器外,还有以下3种芯片。</p>
<ol>
<li>各种接口卡(网卡,显卡)上的接口芯片,它们控制接口卡进行工作;</li>
<li>主板上的接口芯片,CPU通过它们对部分外设进行访问;</li>
<li>其他芯片,用来存储相关的系统信息,或进行相关的输入输出处理。</li>
</ol>
<h3>14.1 端口的读写</h3>
<p>端口的读写指令只有两条:in和out,分别用于从端口读取数据和往端口写入数据。</p>
<p>CPU执行内存访问指令和端口访问指令的比较</p>
<p>(1).访问内存</p>
<p>mov ax,ds: ;假设执行前(ds)=0</p>
<ol>
<li>CPU通过地址线将地址信息8发出;</li>
<li>CPU通过控制线发出内存读命令,选中存储芯片,并通知它,将要从中读取数据;</li>
<li>存储器将8号单元中的数据通过数据线送入CPU。</li>
</ol>
<p>(2).访问端口</p>
<p>in al,60h</p>
<ol>
<li>CPU通过地址线将地址信息60h发出;</li>
<li>CPU通过控制线发出端口读命令,选中端口所在的芯片,并通知它,将要从中读取数据;</li>
<li>存储器将60h号端口中的数据通过数据线送入CPU。</li>
</ol>
<p>注意,在in和out指令中,只能使用ax或al来存放端口中读入的数据或要发送到端口中的数据。</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201907/1201453-20190705102001080-1817725170.png" alt=""></p>
<h3>14.2&nbsp; CMIOS RAM芯片</h3>
<p>CMOS RAM芯片,一般简称为CMOS。此芯片特征如下。</p>
<ol>
<li>包含一个实时钟和一个有128个存储单元的RAM存储器。</li>
<li>该芯片靠电池供电,所以,关机后其内部的实时钟仍可正常工作,RAM中的信息不丢失。</li>
<li>128个字节的RAM中,内部时钟占用 0~0dh&nbsp; 单元来保存时间信息,其余大部分单元用于保存系统配置信息,供系统启动时BIOS程序读取。</li>
<li>该芯片内部有两个端口,端口地址为 70h 和 71h 。CPU 通过这两个端口来读写CMOS RAM。</li>
<li>70h 为地址端口存放要访问的 CMOS RAM 单元的地址; 71h&nbsp; 为数据端口,存放从选定的 CMOS RAM 单元中读取的数据,或要写入到其中的数据。</li>
</ol>
<p>比如,读CMOS RAM的2号单元</p>
<ul>
<li>将2送入端口70h;</li>
<li>从端口71h读取2号单元的内容。</li>
</ul>
<h3>14.3 shl和shr指令</h3>
<p>shl是逻辑左移指令,它的功能为:</p>
<ol>
<li>将一个寄存器或内存单元中的数据向左移位;</li>
<li>将最后移出的一位写入CF中;</li>
<li>最低位用0补充。</li>
</ol>
<p>指令:</p>
<p>mov al,01001000b</p>
<p>shl al,1</p>
<p>执行后(al)=10010000b,CF=0。</p>
<p>shr是逻辑左移指令,它的功能为:</p>
<ol>
<li>将一个寄存器或内存单元中的数据向右移位;</li>
<li>将最后移出的一位写入CF中;</li>
<li>最高位用0补充。</li>
</ol>
<p>指令:</p>
<p>mov al,01010001b</p>
<p>mov cl,3</p>
<p>shl al,cl</p>
<p>执行后(al)=10001000b,因为最后移出的一位是0,所以CF=0。</p>
<h3>14.4 CMOS RAM中存储的时间信息</h3>
<p>年、月、日、时、分、秒存放单元依次为</p>
<p>0H、2H、4H、7H、8H、9H</p>
<p>这些数据以BCD码的方式存放。</p>
<p>在屏幕中间显示当前的月份</p>
<p>程序如下</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">编程:在屏幕中间显示当前的月份</span>
<span style="color: rgba(0, 0, 0, 1)">
assume </span><span style="color: rgba(0, 128, 128, 1)">cs:</span><span style="color: rgba(0, 0, 0, 1)">code

code segment
</span><span style="color: rgba(0, 128, 128, 1)">start:</span>
      <span style="color: rgba(0, 0, 255, 1)">mov</span>    al,<span style="color: rgba(128, 0, 128, 1)">8</span>
      <span style="color: rgba(0, 0, 255, 1)">out</span><span style="color: rgba(0, 0, 0, 1)"> 70h,al
      </span><span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)">    al,71h
      </span><span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> ah,al
      </span><span style="color: rgba(0, 0, 255, 1)">mov</span> cl,<span style="color: rgba(128, 0, 128, 1)">4</span>
      <span style="color: rgba(0, 0, 255, 1)">shr</span><span style="color: rgba(0, 0, 0, 1)"> ah,cl
      </span><span style="color: rgba(0, 0, 255, 1)">and</span> al,<span style="color: rgba(128, 0, 128, 1)">00001111b</span>

      <span style="color: rgba(0, 0, 255, 1)">add</span><span style="color: rgba(0, 0, 0, 1)"> ah,30h
      </span><span style="color: rgba(0, 0, 255, 1)">add</span><span style="color: rgba(0, 0, 0, 1)"> al,30h

      </span><span style="color: rgba(0, 0, 255, 1)">mov</span> bx,0b800h    <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">显存</span>
      <span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> es,bx
      </span><span style="color: rgba(0, 0, 255, 1)">mov</span> byte ptr <span style="color: rgba(0, 128, 128, 1)">es:</span>[<span style="color: rgba(128, 0, 128, 1)">160</span>*<span style="color: rgba(128, 0, 128, 1)">12</span>+<span style="color: rgba(128, 0, 128, 1)">40</span>*<span style="color: rgba(128, 0, 128, 1)">2</span>],ah   <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">显示月份的十位数码</span>
      <span style="color: rgba(0, 0, 255, 1)">mov</span> byte ptr <span style="color: rgba(0, 128, 128, 1)">es:</span>[<span style="color: rgba(128, 0, 128, 1)">160</span>*<span style="color: rgba(128, 0, 128, 1)">12</span>+<span style="color: rgba(128, 0, 128, 1)">40</span>*<span style="color: rgba(128, 0, 128, 1)">2</span>+<span style="color: rgba(128, 0, 128, 1)">2</span>],al   <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">显示月份的个位数码</span>

      <span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> ax,4c00h
      </span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> 21h

code ends
end start</span></pre>
</div>
<h2>15 外中断</h2>
<h3>15.1 接口芯片与端口</h3>
<p>PC系统的接口卡和主板上,装有各种接口芯片。这些外设接口芯片的内部有若干寄存器,CPU将这些寄存器当作端口来访问。</p>
<p>外设的输入送入相关的接口芯片的端口中;CPU向外设的输出先送入端口中,再由相关的芯片送到外设。</p>
<p>CPU向外设输出控制命令,这些命令先送到相关芯片的端口中,然后再由相关的芯片根据命令对外设实施控制。</p>
<p>可见,CPU通过端口和外部设备进行联系。</p>
<h3>15.2 外中断信息</h3>
<p>1.可屏蔽中断</p>
<p>CPU可以不响应的中断。当CPU检测到可屏蔽中断信息时,如果IF=1,则CPU在执行完当前指令后响应中断,引发中断过程;</p>
<p>如果IF=0,则不响应可屏蔽中断,禁止其他的可屏蔽中断。</p>
<p>sti:设置IF=1</p>
<p>cli:设置IF=0</p>
<p>2.不可屏蔽中断</p>
<p>不可屏蔽中断是CPU必须响应的中断。当CPU检测到不可屏蔽中断信息时,则在执行完当前指令后,立即响应,引发中断过程。</p>
<p>不可屏蔽中断的中断类型码固定为2,所以中断过程中,不需要获取中断类型码。</p>
<h3>15.3 PC机键盘的处理过程</h3>
<p>1.键盘输入</p>
<p>按下一个键,该芯片产生一个扫描码,叫做通码。扫描码被送入主板上的相关接口芯片的寄存器中,该寄存器的端口地址为60h。</p>
<p>松开按下的键,也产生一个扫描码,叫做断码。松开按键时产生的扫描码也被送入60h端口中。</p>
<p>扫描码长度为一个字节,通码的第7位为0,断码的第7位为1,即:</p>
<p>断码=通码 + 80h</p>
<p>例如,g键的通码为22h,断码为a2h。</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201907/1201453-20190711150326307-281436015.png" alt=""></p>
<p>2.引发9号中断</p>
<p>键盘的输入到达60h端口时,相关的芯片就会向CPU发出中断类型码为9的可屏蔽中断信息。CPU检测到该中断信息后,如果IF=1,则响应中断,</p>
<p>引发中断过程,转去执行int9中断例程。</p>
<p>3.执行int9中断例程</p>
<p>(1)读取60h端口的扫描码;</p>
<p>(2)如果是字符键的扫描码,将该扫描码的和它所对应的ASCII码送入内存中的BIOS键盘缓冲区;如果是控制键(Ctrl)和切换键(Capslock)的扫描码,</p>
<p>则将其转变为状态字节(用二进制位记录控制键和切换键状态的字节)写入内存中存储状态字节的单元;</p>
<p>(3)对键盘系统进行相关的控制。</p>
<p>BIOS键盘缓冲区中,一个键盘输入用一个字单元存放,高位字节存放扫描码,低位字节存放字符码</p>
<p>0040:17单元存储键盘状态字节,该字节记录了控制键和切换键的状态。键盘状态字节各位记录的信息如下。</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201907/1201453-20190711151433198-331262651.png" alt=""></p>
<h3>15.4 指令系统总结</h3>
<p>8086CPU 提供以下几大类指令:<br>1、数据传送指令<br>比如:mov、push、pop、pushf、popf、xchg等都是数据传送指令,这些指令实现寄存器和内存、寄存器和寄存器之间的单个数据传送。<br>2、算术运算指令<br>比如:add、sub、adc、sbb、inc、dec、cmp、imul、idiv、aaa等都是算术运算指令,这些指令实现寄存器和内存中的数据的算数运算。<br>它们的执行结果影响标志寄存器的:sf、zf、of、cf、pf、af位。<br>3、逻辑指令<br>比如:and、or、not、xor、test、shl、shr、sal、sar、rol、ror、rcl、rcr 等都是逻辑指令。<br>除了not指令外,它们的执行结果都影响标志寄存器的相关标志位。<br>4、转移指令<br>可以修改IP ,或同时修改CS 和IP 的指令统称为转移指令。转移指令分为以下几类:<br>(1)无条件转移指令,比如:jmp;<br>(2)条件转移指令,比如:jcxz、je、jb、ja、jnb、jna等;<br>(3)循环指令,比如:loop;<br>(4)过程,比如:call、ret、retf;<br>(5)中断,比如int、iret。<br>5、处理机控制指令<br>这些指令对标志寄存器或其他处理机状态进行设置,比如:cld、std、cli、sti、nop、clc、cmc、stc、hlt、wait、esc、lock等都是处理机控制指令。<br>6、串处理指令<br>这些指令对内存中的批量数据进行处理<br>比如:movsb、movsw、cmps、scas、lods、stos等。<br>若要使用这些指令方便地进行批量数据的处理,则需要和rep、repe、repne等前缀指令配合使用。</p>
<h2>16 直接定址表</h2>
<h3>16.1 数据标号</h3>
<p>数据标号标记了存储数据的单元的地址和长度。</p>
<p>对于程序中的a db 1,2,3,4,5,6,7,8:</p>
<p>指令:mov al,a</p>
<p>相当于:mov al,cs:0</p>
<p>指令:mov al,a</p>
<p>相当于:mov al,cs:0</p>
<p>指令:mov al,a</p>
<p>相当于:mov al,cs:0</p>
<h3>16.2 在其他段中使用数据标号</h3>
<p>在其他段中,我们可以使用数据标号来描述存储数据的单元的地址和长度。</p>
<p>在后面加有":"的地址标号,只能在代码段中使用,不能在其他段中使用。</p>
<p>assume cs:code,ds:data</p>
<p>data segment</p>
<p>  a db 1,2,3,4,5,6,7,8</p>
<p>  b dw 0</p>
<p>data ends</p>
<p>code segment</p>
<p>start:</p>
<p>mov ax,data</p>
<p>mov ds,ax</p>
<p>mov si,0</p>
<p>mov cx,8</p>
<p>s:</p>
<p>mov al,a</p>
<p>mov ah,0</p>
<p>add b,ax</p>
<p>inc si</p>
<p>loop s</p>
<p>mov ax,4c00h</p>
<p>int 21h</p>
<p>code ends</p>
<p>end start</p>
<h3>16.3 直接定址表</h3>
<p>建立一张具有映射关系的表,节省计算时间。</p>
<p>编写程序,以十六进制的形式在屏幕中间显示给定的字节型数据。</p>
<p>在数值0~15和字符"0"~"F"建立映射关系。</p>
<div class="cnblogs_code">
<pre>assume <span style="color: rgba(0, 128, 128, 1)">cs:</span><span style="color: rgba(0, 0, 0, 1)">code

code segment
</span><span style="color: rgba(0, 128, 128, 1)">start:</span>
      <span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> al,0eh

      </span><span style="color: rgba(0, 0, 255, 1)">call</span><span style="color: rgba(0, 0, 0, 1)"> showbyte

      </span><span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> ax,4c00h
      </span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> 21h

</span><span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">子程序:</span><span style="color: rgba(0, 128, 0, 1)">
;</span><span style="color: rgba(0, 128, 0, 1)">用al传送要显示的数据</span>

<span style="color: rgba(0, 128, 128, 1)">showbyte:</span>
      <span style="color: rgba(0, 0, 255, 1)">jmp</span><span style="color: rgba(0, 0, 0, 1)"> short show

      table db </span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">0123456789ABCDEF</span><span style="color: rgba(128, 0, 0, 1)">'</span>    <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">字符表</span>

<span style="color: rgba(0, 128, 128, 1)">show:</span>   <span style="color: rgba(0, 0, 255, 1)">push</span><span style="color: rgba(0, 0, 0, 1)"> bx
      </span><span style="color: rgba(0, 0, 255, 1)">push</span><span style="color: rgba(0, 0, 0, 1)"> es

      </span><span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> ah,al
      </span><span style="color: rgba(0, 0, 255, 1)">shr</span> ah,<span style="color: rgba(128, 0, 128, 1)">1</span>         
      <span style="color: rgba(0, 0, 255, 1)">shr</span> ah,<span style="color: rgba(128, 0, 128, 1)">1</span>
      <span style="color: rgba(0, 0, 255, 1)">shr</span> ah,<span style="color: rgba(128, 0, 128, 1)">1</span>
      <span style="color: rgba(0, 0, 255, 1)">shr</span> ah,<span style="color: rgba(128, 0, 128, 1)">1</span>                <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">右移4位,ah中得到高4位的值</span>
      <span style="color: rgba(0, 0, 255, 1)">and</span> al,<span style="color: rgba(128, 0, 128, 1)">00001111b</span>      <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">al中为低4位的值</span>

      <span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> bl,ah
      </span><span style="color: rgba(0, 0, 255, 1)">mov</span> bh,<span style="color: rgba(128, 0, 128, 1)">0</span>
      <span style="color: rgba(0, 0, 255, 1)">mov</span> ah,table      <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">用高4位的值作为相对于table的偏移,取得对应的字符</span>

      <span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> bx,0b800h
      </span><span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> es,bx
      </span><span style="color: rgba(0, 0, 255, 1)">mov</span> <span style="color: rgba(0, 128, 128, 1)">es:</span>[<span style="color: rgba(128, 0, 128, 1)">160</span>*<span style="color: rgba(128, 0, 128, 1)">12</span>+<span style="color: rgba(128, 0, 128, 1)">40</span>*<span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">],ah

      </span><span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> bl,al
      </span><span style="color: rgba(0, 0, 255, 1)">mov</span> bh,<span style="color: rgba(128, 0, 128, 1)">0</span>
      <span style="color: rgba(0, 0, 255, 1)">mov</span> al,table      <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">用低4位的值作为相对于table的偏移,取得对应的字符</span>
      
      <span style="color: rgba(0, 0, 255, 1)">mov</span> <span style="color: rgba(0, 128, 128, 1)">es:</span>[<span style="color: rgba(128, 0, 128, 1)">160</span>*<span style="color: rgba(128, 0, 128, 1)">12</span>+<span style="color: rgba(128, 0, 128, 1)">40</span>*<span style="color: rgba(128, 0, 128, 1)">2</span>+<span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">],al

      </span><span style="color: rgba(0, 0, 255, 1)">pop</span><span style="color: rgba(0, 0, 0, 1)"> es
      </span><span style="color: rgba(0, 0, 255, 1)">pop</span><span style="color: rgba(0, 0, 0, 1)"> bx
      </span><span style="color: rgba(0, 0, 255, 1)">ret</span><span style="color: rgba(0, 0, 0, 1)">

code ends
end start</span></pre>
</div>
<h3>16.4 程序入口地址的直接定址表</h3>
<p>实现一个子程序,为显示输出提供如下功能。</p>
<ol>
<li>清屏;</li>
<li>设置前景色;</li>
<li>设置背景色;</li>
<li>向上滚动一行;</li>
</ol>
<p>入口参数说明:</p>
<p>(1)用ah 寄存器传递功能号:<br>0 表示清屏,<br>1表示设置前景色,<br>2 表示设置背景色,<br>3 表示向上滚动一行;<br>(2)对于2、3号功能,用al传送颜色值,<br>&nbsp;&nbsp;&nbsp; (al)∈{ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 }<br>下面,我们讨论一下各种功能如何实现 :<br>(1)清屏<br>将显存中当前屏幕中的字符设为空格符;<br>(2)设置前景色<br>设置显存中当前屏幕中处于奇地址的属性字节的第0、1、2位;<br>(3)设置背景色<br>设置显存中当前屏幕中处于奇地址的属性字节的第4、5、6位;<br>(4)向上滚动一行<br>依次将第 n+1行的内容复制到第n行处:最后一行为空。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">编程:实现一个子程序setscreen,为显示输出提供如下功能:</span><span style="color: rgba(0, 128, 0, 1)">
;</span><span style="color: rgba(0, 128, 0, 1)">(1) 清屏。</span><span style="color: rgba(0, 128, 0, 1)">
;</span><span style="color: rgba(0, 128, 0, 1)">(2) 设置前景色。</span><span style="color: rgba(0, 128, 0, 1)">
;</span><span style="color: rgba(0, 128, 0, 1)">(3) 设置背景色。</span><span style="color: rgba(0, 128, 0, 1)">
;</span><span style="color: rgba(0, 128, 0, 1)">(4) 向上滚动一行。</span><span style="color: rgba(0, 128, 0, 1)">
;
;</span><span style="color: rgba(0, 128, 0, 1)">入口参数说明:</span><span style="color: rgba(0, 128, 0, 1)">
;</span><span style="color: rgba(0, 128, 0, 1)">(1) 用 ah 寄存器传递功能号:0 表示清屏,1表示设置前景色,2 表示设置背景色,3 表示向上滚动一行;</span><span style="color: rgba(0, 128, 0, 1)">
;</span><span style="color: rgba(0, 128, 0, 1)">(2) 对于2、3号功能,用 al 传送颜色值,(al) ∈{0,1,2,3,4,5,6,7}</span>

<span style="color: rgba(0, 128, 128, 1)">setscreen:</span> <span style="color: rgba(0, 0, 255, 1)">jmp</span><span style="color: rgba(0, 0, 0, 1)"> short set

    tabledw sub1,sub2,sub3,sub4

</span><span style="color: rgba(0, 128, 128, 1)">set:</span>   
    <span style="color: rgba(0, 0, 255, 1)">push</span><span style="color: rgba(0, 0, 0, 1)"> bx   
    </span><span style="color: rgba(0, 0, 255, 1)">cmp</span> ah,<span style="color: rgba(128, 0, 128, 1)">3</span>      <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">判断传递的是否大于 3</span>
    <span style="color: rgba(0, 0, 255, 1)">ja</span><span style="color: rgba(0, 0, 0, 1)"> sret
    </span><span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> bl,ah
    </span><span style="color: rgba(0, 0, 255, 1)">mov</span> bh,<span style="color: rgba(128, 0, 128, 1)">0</span>
    <span style="color: rgba(0, 0, 255, 1)">add</span> bx,bx      <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">根据ah中的功能号计算对应子程序的地址在table表中的偏移</span>
   
    <span style="color: rgba(0, 0, 255, 1)">call</span> word ptr table    <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">调用对应的功能子程序</span>

<span style="color: rgba(0, 128, 128, 1)">sret:</span>   
    <span style="color: rgba(0, 0, 255, 1)">pop</span><span style="color: rgba(0, 0, 0, 1)"> bx   
    </span><span style="color: rgba(0, 0, 255, 1)">iret</span>

<span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">功能子程序1:清屏</span>
<span style="color: rgba(0, 128, 128, 1)">sub1:</span>   
    <span style="color: rgba(0, 0, 255, 1)">push</span><span style="color: rgba(0, 0, 0, 1)"> bx
    </span><span style="color: rgba(0, 0, 255, 1)">push</span><span style="color: rgba(0, 0, 0, 1)"> cx
    </span><span style="color: rgba(0, 0, 255, 1)">push</span><span style="color: rgba(0, 0, 0, 1)"> es
    </span><span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> bx,0b800h
    </span><span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> es,bx
    </span><span style="color: rgba(0, 0, 255, 1)">mov</span> bx,<span style="color: rgba(128, 0, 128, 1)">0</span>
    <span style="color: rgba(0, 0, 255, 1)">mov</span> cx,<span style="color: rgba(128, 0, 128, 1)">2000</span>
   
<span style="color: rgba(0, 128, 128, 1)">sub1s:</span>
    <span style="color: rgba(0, 0, 255, 1)">mov</span> byte ptr <span style="color: rgba(0, 128, 128, 1)">es:</span>,<span style="color: rgba(128, 0, 0, 1)">'</span> <span style="color: rgba(128, 0, 0, 1)">'</span>
    <span style="color: rgba(0, 0, 255, 1)">add</span> bx,<span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">
    loop sub1s
    </span><span style="color: rgba(0, 0, 255, 1)">pop</span><span style="color: rgba(0, 0, 0, 1)"> es
    </span><span style="color: rgba(0, 0, 255, 1)">pop</span><span style="color: rgba(0, 0, 0, 1)"> cx
    </span><span style="color: rgba(0, 0, 255, 1)">pop</span><span style="color: rgba(0, 0, 0, 1)"> bx
    </span><span style="color: rgba(0, 0, 255, 1)">ret</span> <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">sub1 ends</span>

<span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">功能子程序2:设置前景色</span>
<span style="color: rgba(0, 128, 128, 1)">sub2:</span>   
    <span style="color: rgba(0, 0, 255, 1)">push</span><span style="color: rgba(0, 0, 0, 1)"> bx
    </span><span style="color: rgba(0, 0, 255, 1)">push</span><span style="color: rgba(0, 0, 0, 1)"> cx
    </span><span style="color: rgba(0, 0, 255, 1)">push</span><span style="color: rgba(0, 0, 0, 1)"> es
    </span><span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> bx,0b800h
    </span><span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> es,bx
    </span><span style="color: rgba(0, 0, 255, 1)">mov</span> bx,<span style="color: rgba(128, 0, 128, 1)">1</span>
    <span style="color: rgba(0, 0, 255, 1)">mov</span> cx,<span style="color: rgba(128, 0, 128, 1)">2000</span>
   
<span style="color: rgba(0, 128, 128, 1)">sub2s:</span>   
    <span style="color: rgba(0, 0, 255, 1)">and</span> byte ptr <span style="color: rgba(0, 128, 128, 1)">es:</span>,11111<span style="color: rgba(128, 0, 128, 1)">000b</span>   
    <span style="color: rgba(0, 0, 255, 1)">or</span> <span style="color: rgba(0, 128, 128, 1)">es:</span><span style="color: rgba(0, 0, 0, 1)">,al
    </span><span style="color: rgba(0, 0, 255, 1)">add</span> bx,<span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">
    loop sub2s

    </span><span style="color: rgba(0, 0, 255, 1)">pop</span><span style="color: rgba(0, 0, 0, 1)"> es
    </span><span style="color: rgba(0, 0, 255, 1)">pop</span><span style="color: rgba(0, 0, 0, 1)"> cx
    </span><span style="color: rgba(0, 0, 255, 1)">pop</span><span style="color: rgba(0, 0, 0, 1)"> bx
    </span><span style="color: rgba(0, 0, 255, 1)">ret</span> <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">sub2 ends</span>

<span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">功能子程序3:设置背景色</span>
<span style="color: rgba(0, 128, 128, 1)">sub3:</span>   
    <span style="color: rgba(0, 0, 255, 1)">push</span><span style="color: rgba(0, 0, 0, 1)"> bx
    </span><span style="color: rgba(0, 0, 255, 1)">push</span><span style="color: rgba(0, 0, 0, 1)"> cx
    </span><span style="color: rgba(0, 0, 255, 1)">push</span><span style="color: rgba(0, 0, 0, 1)"> es
    </span><span style="color: rgba(0, 0, 255, 1)">mov</span> cl,<span style="color: rgba(128, 0, 128, 1)">4</span>
    <span style="color: rgba(0, 0, 255, 1)">shl</span><span style="color: rgba(0, 0, 0, 1)"> al,cl
    </span><span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> bx,0b800h
    </span><span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> es,bx
    </span><span style="color: rgba(0, 0, 255, 1)">mov</span> bx,<span style="color: rgba(128, 0, 128, 1)">1</span>
    <span style="color: rgba(0, 0, 255, 1)">mov</span> cx,<span style="color: rgba(128, 0, 128, 1)">2000</span>
   
<span style="color: rgba(0, 128, 128, 1)">sub3s:</span>   
    <span style="color: rgba(0, 0, 255, 1)">and</span> byte ptr <span style="color: rgba(0, 128, 128, 1)">es:</span>,1<span style="color: rgba(128, 0, 128, 1)">0001111b</span>
    <span style="color: rgba(0, 0, 255, 1)">or</span> <span style="color: rgba(0, 128, 128, 1)">es:</span><span style="color: rgba(0, 0, 0, 1)">,al
    </span><span style="color: rgba(0, 0, 255, 1)">add</span> bx,<span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">
    loop sub2s

    </span><span style="color: rgba(0, 0, 255, 1)">pop</span><span style="color: rgba(0, 0, 0, 1)"> es
    </span><span style="color: rgba(0, 0, 255, 1)">pop</span><span style="color: rgba(0, 0, 0, 1)"> cx
    </span><span style="color: rgba(0, 0, 255, 1)">pop</span><span style="color: rgba(0, 0, 0, 1)"> bx
    </span><span style="color: rgba(0, 0, 255, 1)">ret</span> <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)"> sub3 ends</span>

<span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">功能子程序4:向上滚动一行</span>
<span style="color: rgba(0, 128, 128, 1)">sub4:</span>   
    <span style="color: rgba(0, 0, 255, 1)">push</span><span style="color: rgba(0, 0, 0, 1)"> cx
    </span><span style="color: rgba(0, 0, 255, 1)">push</span><span style="color: rgba(0, 0, 0, 1)"> si
    </span><span style="color: rgba(0, 0, 255, 1)">push</span><span style="color: rgba(0, 0, 0, 1)"> di
    </span><span style="color: rgba(0, 0, 255, 1)">push</span><span style="color: rgba(0, 0, 0, 1)"> es
    </span><span style="color: rgba(0, 0, 255, 1)">push</span><span style="color: rgba(0, 0, 0, 1)"> ds

    </span><span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> si,0b800h
    </span><span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> es,si
    </span><span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> ds,si
    </span><span style="color: rgba(0, 0, 255, 1)">mov</span> si,<span style="color: rgba(128, 0, 128, 1)">160</span>            <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">ds:si指向第n+1行</span>
    <span style="color: rgba(0, 0, 255, 1)">mov</span> di,<span style="color: rgba(128, 0, 128, 1)">0</span>            <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">es:di指向第n行</span>
    <span style="color: rgba(0, 0, 255, 1)">cld</span>
    <span style="color: rgba(0, 0, 255, 1)">mov</span> cx,<span style="color: rgba(128, 0, 128, 1)">24</span><span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">共复制24行</span>

<span style="color: rgba(0, 128, 128, 1)">sub4s:</span>   
    <span style="color: rgba(0, 0, 255, 1)">push</span><span style="color: rgba(0, 0, 0, 1)"> cx
    </span><span style="color: rgba(0, 0, 255, 1)">mov</span> cx,<span style="color: rgba(128, 0, 128, 1)">160</span>
    <span style="color: rgba(0, 0, 255, 1)">rep</span> <span style="color: rgba(0, 0, 255, 1)">movsb</span>             <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">复制</span>
      <span style="color: rgba(0, 0, 255, 1)">pop</span><span style="color: rgba(0, 0, 0, 1)"> cx
    loop sub4s

    </span><span style="color: rgba(0, 0, 255, 1)">mov</span> cx,<span style="color: rgba(128, 0, 128, 1)">80</span>   
    <span style="color: rgba(0, 0, 255, 1)">mov</span> si,<span style="color: rgba(128, 0, 128, 1)">0</span>
   
<span style="color: rgba(0, 128, 128, 1)">sub4s1:</span>
    <span style="color: rgba(0, 0, 255, 1)">mov</span> byte ptr <span style="color: rgba(0, 128, 128, 1)">es:</span>[<span style="color: rgba(128, 0, 128, 1)">160</span>*<span style="color: rgba(128, 0, 128, 1)">24</span>+si],<span style="color: rgba(128, 0, 0, 1)">'</span> <span style="color: rgba(128, 0, 0, 1)">'</span>      <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">最后一行清空</span>
    <span style="color: rgba(0, 0, 255, 1)">add</span> si,<span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">
    loop sub4s1

    </span><span style="color: rgba(0, 0, 255, 1)">pop</span><span style="color: rgba(0, 0, 0, 1)"> ds
    </span><span style="color: rgba(0, 0, 255, 1)">pop</span><span style="color: rgba(0, 0, 0, 1)"> es
    </span><span style="color: rgba(0, 0, 255, 1)">pop</span><span style="color: rgba(0, 0, 0, 1)"> di
    </span><span style="color: rgba(0, 0, 255, 1)">pop</span><span style="color: rgba(0, 0, 0, 1)"> si
    </span><span style="color: rgba(0, 0, 255, 1)">pop</span><span style="color: rgba(0, 0, 0, 1)"> cx
    </span><span style="color: rgba(0, 0, 255, 1)">ret</span> <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">sub4 ends</span></pre>
</div>
<h2>17 使用BIOS进行键盘输入和磁盘读写</h2>
<h3>17.1 int9中断例程对键盘输入的处理</h3>
<p>我们通过下面几个键A,B,C,D,E,shift_A,A的输入过程,简要地看一下int9中断例程对键盘输入的处理方法。</p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201907/1201453-20190716143411529-103215304.png" alt=""></p>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201907/1201453-20190716143430090-563060574.png" alt=""></p>
<h3>17.2 使用int16h中断例程读取键盘缓冲区</h3>
<p>int16h中断例程是从键盘缓冲区读取一个键盘输入,并且将其从缓冲区中删除,该功能的编号为0。</p>
<p>编程,接收用户的键盘输入,输入"r",将屏幕上的字符设置为红色;输入"g",将屏幕上的字符设置为绿色;输入"b",将屏幕上的字符设置为蓝色。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">编程:</span><span style="color: rgba(0, 128, 0, 1)">
;</span><span style="color: rgba(0, 128, 0, 1)">接收用户的键盘输入,输入“r”,将屏幕上的字符设置为红色:输入“g”, </span><span style="color: rgba(0, 128, 0, 1)">
;</span><span style="color: rgba(0, 128, 0, 1)">将屏幕上的字符设置为绿色;输入“b ”,将屏幕上的字符设置为蓝色。</span>


<span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">A、B、C处的程序指令比较有技巧,请读者自行分析</span>
<span style="color: rgba(0, 0, 0, 1)">
assume </span><span style="color: rgba(0, 128, 128, 1)">cs:</span><span style="color: rgba(0, 0, 0, 1)">code

code segment
</span><span style="color: rgba(0, 128, 128, 1)">start:</span>   
    <span style="color: rgba(0, 0, 255, 1)">mov</span> ah,<span style="color: rgba(128, 0, 128, 1)">0</span>
    <span style="color: rgba(0, 0, 255, 1)">int</span> 16h                <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">int 16h 0号功能实现从键盘缓冲区读取一个键盘输入</span>
      
    <span style="color: rgba(0, 0, 255, 1)">mov</span> ah,<span style="color: rgba(128, 0, 128, 1)">1</span>            <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">A 001</span>
    <span style="color: rgba(0, 0, 255, 1)">cmp</span> al,<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">r</span><span style="color: rgba(128, 0, 0, 1)">'</span>
    <span style="color: rgba(0, 0, 255, 1)">je</span><span style="color: rgba(0, 0, 0, 1)"> red
    </span><span style="color: rgba(0, 0, 255, 1)">cmp</span> al,<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">g</span><span style="color: rgba(128, 0, 0, 1)">'</span>
    <span style="color: rgba(0, 0, 255, 1)">je</span><span style="color: rgba(0, 0, 0, 1)"> green
    </span><span style="color: rgba(0, 0, 255, 1)">cmp</span> al,<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">b</span><span style="color: rgba(128, 0, 0, 1)">'</span>
    <span style="color: rgba(0, 0, 255, 1)">je</span><span style="color: rgba(0, 0, 0, 1)"> blue
    </span><span style="color: rgba(0, 0, 255, 1)">jmp</span><span style="color: rgba(0, 0, 0, 1)"> short sret
   
</span><span style="color: rgba(0, 128, 128, 1)">red:</span>   
    <span style="color: rgba(0, 0, 255, 1)">shl</span> ah,<span style="color: rgba(128, 0, 128, 1)">1</span>            <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">B 100</span>
<span style="color: rgba(0, 128, 128, 1)">green:</span>   
    <span style="color: rgba(0, 0, 255, 1)">shl</span> ah,<span style="color: rgba(128, 0, 128, 1)">1</span>            <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">C 010</span>

<span style="color: rgba(0, 128, 128, 1)">blue:</span>   
    <span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> bx,0b800h
    </span><span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> es,bx
    </span><span style="color: rgba(0, 0, 255, 1)">mov</span> bx,<span style="color: rgba(128, 0, 128, 1)">1</span>
    <span style="color: rgba(0, 0, 255, 1)">mov</span> cx,<span style="color: rgba(128, 0, 128, 1)">2000</span>
<span style="color: rgba(0, 128, 128, 1)">s:</span>    <span style="color: rgba(0, 0, 255, 1)">and</span> byte ptr <span style="color: rgba(0, 128, 128, 1)">es:</span>,11111<span style="color: rgba(128, 0, 128, 1)">000b</span>
    <span style="color: rgba(0, 0, 255, 1)">or</span> <span style="color: rgba(0, 128, 128, 1)">es:</span><span style="color: rgba(0, 0, 0, 1)">,ah
    </span><span style="color: rgba(0, 0, 255, 1)">add</span> bx,<span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">
    loop s

</span><span style="color: rgba(0, 128, 128, 1)">sret:</span>   
    <span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> ax,4c00h
    </span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> 21h
   
code ends

end start</span></pre>
</div>
<p>&nbsp;</p>
<h3>17.3 字符串的输入</h3>
<p>简单地确定程序的处理过程如下。</p>
<ol>
<li>调用int16h读取键盘输入;</li>
<li>如果是字符,进入字符栈,显示字符栈中的所有字符;继续执行1;</li>
<li>如果是退格键,从字符栈中弹出一个字符,显示字符栈中的所有字符;继续执行1;</li>
<li>如果是Enter键,向字符栈中压入0,返回。</li>
</ol>
<p>完整的接收字符串输入的子程序如下所示。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">最基本的字符串输入程序,需要具备下面的功能:</span><span style="color: rgba(0, 128, 0, 1)">
;</span><span style="color: rgba(0, 128, 0, 1)">(1) 在输入的同时需要显示这个字符串;</span><span style="color: rgba(0, 128, 0, 1)">
;</span><span style="color: rgba(0, 128, 0, 1)">(2)一般在输入回车符后,字符串输入结束;</span><span style="color: rgba(0, 128, 0, 1)">
;</span><span style="color: rgba(0, 128, 0, 1)">(3)能够删除已经输入的字符。</span>

<span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">编写一个接收字符串的输入子程序,实现上面三个基本功能。</span><span style="color: rgba(0, 128, 0, 1)">
;</span><span style="color: rgba(0, 128, 0, 1)">因为在输入的过程中需要显示,子程序的参数如下:</span><span style="color: rgba(0, 128, 0, 1)">
;</span><span style="color: rgba(0, 128, 0, 1)">    (dh)、(dl)=字符串在屏幕上显示的行、列位置;</span><span style="color: rgba(0, 128, 0, 1)">
;</span><span style="color: rgba(0, 128, 0, 1)">    ds:si 指向字符串的存储空间,字符串以O 为结尾符。</span>
<span style="color: rgba(0, 0, 0, 1)">

assume </span><span style="color: rgba(0, 128, 128, 1)">cs:</span><span style="color: rgba(0, 0, 0, 1)">code

code segment
</span><span style="color: rgba(0, 128, 128, 1)">start:</span>   
    <span style="color: rgba(0, 0, 255, 1)">call</span><span style="color: rgba(0, 0, 0, 1)"> getstr   

</span><span style="color: rgba(0, 128, 128, 1)">return:</span>   
    <span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> ax,4c00h
    </span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> 21h

</span><span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">完整的接收字符串输入的子程序</span>

<span style="color: rgba(0, 128, 128, 1)">getstr:</span>   
    <span style="color: rgba(0, 0, 255, 1)">push</span><span style="color: rgba(0, 0, 0, 1)"> ax

</span><span style="color: rgba(0, 128, 128, 1)">getstrs:</span>
    <span style="color: rgba(0, 0, 255, 1)">mov</span> ah,<span style="color: rgba(128, 0, 128, 1)">0</span>
    <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> 16h
   
    </span><span style="color: rgba(0, 0, 255, 1)">cmp</span><span style="color: rgba(0, 0, 0, 1)"> al,20h
    </span><span style="color: rgba(0, 0, 255, 1)">jb</span> nochar         <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">判断的是ASCII码小于0,说明不是字符</span>
    <span style="color: rgba(0, 0, 255, 1)">mov</span> ah,<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 128, 0, 1)">;
</span>    <span style="color: rgba(0, 0, 255, 1)">call</span> charstack      <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">字符入栈</span>
    <span style="color: rgba(0, 0, 255, 1)">mov</span> ah,<span style="color: rgba(128, 0, 128, 1)">2</span>
    <span style="color: rgba(0, 0, 255, 1)">call</span> charstack      <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">显示栈中的字符</span>
    <span style="color: rgba(0, 0, 255, 1)">jmp</span><span style="color: rgba(0, 0, 0, 1)"> getstrs


</span><span style="color: rgba(0, 128, 128, 1)">nochar:</span>   
    <span style="color: rgba(0, 0, 255, 1)">cmp</span> ah,0eh            <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">退格键的扫描码</span>
    <span style="color: rgba(0, 0, 255, 1)">je</span><span style="color: rgba(0, 0, 0, 1)"> backspace
    </span><span style="color: rgba(0, 0, 255, 1)">cmp</span> ah,1ch            <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">回车键的扫描码</span>
    <span style="color: rgba(0, 0, 255, 1)">je</span> <span style="color: rgba(0, 0, 255, 1)">enter</span>
    <span style="color: rgba(0, 0, 255, 1)">jmp</span><span style="color: rgba(0, 0, 0, 1)"> getstrs
   
   
</span><span style="color: rgba(0, 128, 128, 1)">backspace:</span>                <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">退格</span>
    <span style="color: rgba(0, 0, 255, 1)">mov</span> ah,<span style="color: rgba(128, 0, 128, 1)">1</span>   
    <span style="color: rgba(0, 0, 255, 1)">call</span> charstack      <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">字符出栈</span>
    <span style="color: rgba(0, 0, 255, 1)">mov</span> ah,<span style="color: rgba(128, 0, 128, 1)">2</span>
    <span style="color: rgba(0, 0, 255, 1)">call</span> charstack      <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">显示栈中的字符</span>
    <span style="color: rgba(0, 0, 255, 1)">jmp</span><span style="color: rgba(0, 0, 0, 1)"> getstrs

</span><span style="color: rgba(0, 0, 255, 1)">enter</span>:                  <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">回车</span>
    <span style="color: rgba(0, 0, 255, 1)">mov</span> al,<span style="color: rgba(128, 0, 128, 1)">0</span>
    <span style="color: rgba(0, 0, 255, 1)">mov</span> ah,<span style="color: rgba(128, 0, 128, 1)">0</span>
    <span style="color: rgba(0, 0, 255, 1)">call</span> charstack         <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">0入栈</span>
    <span style="color: rgba(0, 0, 255, 1)">mov</span> ah,<span style="color: rgba(128, 0, 128, 1)">2</span>
    <span style="color: rgba(0, 0, 255, 1)">call</span> charstack      <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">显示栈中的字符</span>

    <span style="color: rgba(0, 0, 255, 1)">pop</span><span style="color: rgba(0, 0, 0, 1)"> ax
    </span><span style="color: rgba(0, 0, 255, 1)">ret</span> <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">getstr ends</span>


<span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">功能子程序实现</span>

<span style="color: rgba(0, 128, 128, 1)">charstack:</span>
    <span style="color: rgba(0, 0, 255, 1)">jmp</span><span style="color: rgba(0, 0, 0, 1)"> short charstart
   
    table dw charpush,charpop,charshow
    top dw </span><span style="color: rgba(128, 0, 128, 1)">0</span>               <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">栈顶</span>
   
<span style="color: rgba(0, 128, 128, 1)">charstart:</span>
    <span style="color: rgba(0, 0, 255, 1)">push</span><span style="color: rgba(0, 0, 0, 1)"> bx
    </span><span style="color: rgba(0, 0, 255, 1)">push</span><span style="color: rgba(0, 0, 0, 1)"> dx
    </span><span style="color: rgba(0, 0, 255, 1)">push</span><span style="color: rgba(0, 0, 0, 1)"> di
    </span><span style="color: rgba(0, 0, 255, 1)">push</span><span style="color: rgba(0, 0, 0, 1)"> es

    </span><span style="color: rgba(0, 0, 255, 1)">cmp</span> ah,<span style="color: rgba(128, 0, 128, 1)">2</span>
    <span style="color: rgba(0, 0, 255, 1)">ja</span><span style="color: rgba(0, 0, 0, 1)"> sret
    </span><span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> bl,ah
    </span><span style="color: rgba(0, 0, 255, 1)">mov</span> bh,<span style="color: rgba(128, 0, 128, 1)">0</span>
    <span style="color: rgba(0, 0, 255, 1)">add</span><span style="color: rgba(0, 0, 0, 1)"> bx,bx
    </span><span style="color: rgba(0, 0, 255, 1)">jmp</span><span style="color: rgba(0, 0, 0, 1)"> word ptr table

</span><span style="color: rgba(0, 128, 128, 1)">charpush:</span>
    <span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> bx,top
    </span><span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> ,al
    </span><span style="color: rgba(0, 0, 255, 1)">inc</span><span style="color: rgba(0, 0, 0, 1)"> top
    </span><span style="color: rgba(0, 0, 255, 1)">jmp</span><span style="color: rgba(0, 0, 0, 1)"> sret

</span><span style="color: rgba(0, 128, 128, 1)">charpop:</span>
    <span style="color: rgba(0, 0, 255, 1)">cmp</span> top,<span style="color: rgba(128, 0, 128, 1)">0</span>
    <span style="color: rgba(0, 0, 255, 1)">je</span><span style="color: rgba(0, 0, 0, 1)"> sret
    </span><span style="color: rgba(0, 0, 255, 1)">dec</span><span style="color: rgba(0, 0, 0, 1)"> top
    </span><span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> bx,top
    </span><span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> al,   
    </span><span style="color: rgba(0, 0, 255, 1)">jmp</span><span style="color: rgba(0, 0, 0, 1)"> sret

</span><span style="color: rgba(0, 128, 128, 1)">charshow:</span>
    <span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> bx,0b800h
    </span><span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> es,bx
    </span><span style="color: rgba(0, 0, 255, 1)">mov</span> al,<span style="color: rgba(128, 0, 128, 1)">160</span>
    <span style="color: rgba(0, 0, 255, 1)">mov</span> ah,<span style="color: rgba(128, 0, 128, 1)">0</span>   
    <span style="color: rgba(0, 0, 255, 1)">mul</span><span style="color: rgba(0, 0, 0, 1)"> dh
    </span><span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> di,ax
    </span><span style="color: rgba(0, 0, 255, 1)">add</span><span style="color: rgba(0, 0, 0, 1)"> dl,dl
    </span><span style="color: rgba(0, 0, 255, 1)">mov</span> dh,<span style="color: rgba(128, 0, 128, 1)">0</span>
    <span style="color: rgba(0, 0, 255, 1)">add</span><span style="color: rgba(0, 0, 0, 1)"> di,dx

    </span><span style="color: rgba(0, 0, 255, 1)">mov</span> bx,<span style="color: rgba(128, 0, 128, 1)">0</span>

<span style="color: rgba(0, 128, 128, 1)">charshows:</span>
    <span style="color: rgba(0, 0, 255, 1)">cmp</span><span style="color: rgba(0, 0, 0, 1)"> bx,top
    </span><span style="color: rgba(0, 0, 255, 1)">jne</span><span style="color: rgba(0, 0, 0, 1)"> noempty
    </span><span style="color: rgba(0, 0, 255, 1)">mov</span> byte ptr <span style="color: rgba(0, 128, 128, 1)">es:</span>,<span style="color: rgba(128, 0, 0, 1)">'</span> <span style="color: rgba(128, 0, 0, 1)">'</span>   
    <span style="color: rgba(0, 0, 255, 1)">jmp</span><span style="color: rgba(0, 0, 0, 1)"> sret

</span><span style="color: rgba(0, 128, 128, 1)">noempty:</span>
    <span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> al,
    </span><span style="color: rgba(0, 0, 255, 1)">mov</span> <span style="color: rgba(0, 128, 128, 1)">es:</span><span style="color: rgba(0, 0, 0, 1)">,al
    </span><span style="color: rgba(0, 0, 255, 1)">mov</span> byte ptr <span style="color: rgba(0, 128, 128, 1)">es:</span>,<span style="color: rgba(128, 0, 0, 1)">'</span> <span style="color: rgba(128, 0, 0, 1)">'</span>
    <span style="color: rgba(0, 0, 255, 1)">inc</span><span style="color: rgba(0, 0, 0, 1)"> bx
    </span><span style="color: rgba(0, 0, 255, 1)">add</span> di,<span style="color: rgba(128, 0, 128, 1)">2</span>
    <span style="color: rgba(0, 0, 255, 1)">jmp</span><span style="color: rgba(0, 0, 0, 1)"> charshows

</span><span style="color: rgba(0, 128, 128, 1)">sret:</span>   
    <span style="color: rgba(0, 0, 255, 1)">pop</span><span style="color: rgba(0, 0, 0, 1)"> es
    </span><span style="color: rgba(0, 0, 255, 1)">pop</span><span style="color: rgba(0, 0, 0, 1)"> di
    </span><span style="color: rgba(0, 0, 255, 1)">pop</span><span style="color: rgba(0, 0, 0, 1)"> dx
    </span><span style="color: rgba(0, 0, 255, 1)">pop</span><span style="color: rgba(0, 0, 0, 1)"> bx
    </span><span style="color: rgba(0, 0, 255, 1)">ret</span><span style="color: rgba(0, 0, 0, 1)">

code ends

end start</span></pre>
</div>
<p>&nbsp;</p>
<h3>17.4 应用int 13h中断例程对磁盘进行读写</h3>
<p>3.5英寸软盘分为上下两面,每面有80个磁道,每个磁道分为18个扇区,每个扇区的大小为512个字节。</p>
<p>则:2面*80磁道*18扇区*512字节=1440KB=1.44MB</p>
<p>BIOS提供的访问磁盘的中断例程为int 13h</p>
<div class="cnblogs_code">
<pre>assume <span style="color: rgba(0, 128, 128, 1)">cs:</span><span style="color: rgba(0, 0, 0, 1)">code

code segment

</span><span style="color: rgba(0, 128, 128, 1)">start:</span>   
    <span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> ax,0b800h
    </span><span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> es,ax
    </span><span style="color: rgba(0, 0, 255, 1)">mov</span> bx,<span style="color: rgba(128, 0, 128, 1)">0</span>    <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">es:bx    指向将写入磁盘的数据的内存区</span>

    <span style="color: rgba(0, 0, 255, 1)">mov</span> al,<span style="color: rgba(128, 0, 128, 1)">8</span>   <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">写入的扇区数</span>
    <span style="color: rgba(0, 0, 255, 1)">mov</span> ch,<span style="color: rgba(128, 0, 128, 1)">0</span>   <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">磁道号,从0开始</span>
    <span style="color: rgba(0, 0, 255, 1)">mov</span> cl,<span style="color: rgba(128, 0, 128, 1)">1</span>   <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">扇区号 从1开始</span>
    <span style="color: rgba(0, 0, 255, 1)">mov</span> dl,<span style="color: rgba(128, 0, 128, 1)">0</span>   <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">驱动器号0:软驱A,1:软驱B,硬盘从80h开始, 80h:硬盘C,81h:硬盘D</span>
    <span style="color: rgba(0, 0, 255, 1)">mov</span> dh,<span style="color: rgba(128, 0, 128, 1)">0</span>   <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">磁头号,(对于软盘即面号,因为一个面用一个磁头来读写)</span>
    <span style="color: rgba(0, 0, 255, 1)">mov</span> ah,<span style="color: rgba(128, 0, 128, 1)">3</span>    <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">传递 int 13h 写入数据的功能号</span>
    <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> 13h

            </span><span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">返回参数</span>
            <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">操作成功:(ah) = 0,(al) = 写入的扇区数</span>
            <span style="color: rgba(0, 128, 0, 1)">;</span><span style="color: rgba(0, 128, 0, 1)">操作失败:(ah) = 出错代码</span>
   
<span style="color: rgba(0, 128, 128, 1)">return:</span>   
    <span style="color: rgba(0, 0, 255, 1)">mov</span><span style="color: rgba(0, 0, 0, 1)"> ax,4c00h
    </span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> 21h

code ends
end start</span></pre>
</div>
<h2>&nbsp;资料</h2>
<p><img src="https://img2018.cnblogs.com/blog/1201453/201907/1201453-20190716211219491-851014791.jpg" alt=""></p>
<p>电子书:https://pan.baidu.com/s/1oF3qs08fWCG8mZoPNQD_kg  提取码:3vwj</p>
<p>小甲鱼视频:https://pan.baidu.com/s/1cmX-U-YVk6Hv83xzZTzSKg  提取码:got0</p>
<p>小甲鱼视频ppt和书中的源码:https://pan.baidu.com/s/1Qo63M0diytfTTjMEq884AA  提取码:pqs9</p>
<p>课后习题答案:https://blog.csdn.net/andrewgithub/article/details/78432046</p>
<p>侵删。</p>

</div>
<div id="MySignature" role="contentinfo">
    <div id="AllanboltSignature">      
<p id="PSignature" style="border-top: #e0e0e0 1px dashed; border-right: #e0e0e0 1px dashed; border-bottom: #e0e0e0 1px dashed; border-left: #e0e0e0 1px dashed; padding-top: 10px; padding-right: 10px; padding-bottom: 10px; padding-left: 60px; background: url(&quot;https://images.cnblogs.com/cnblogs_com/lloydsheng/239039/o_copyright.gif&quot;) #e5f1f4 no-repeat 1% 50%; font-family: 微软雅黑; font-size: 11px">            
<br>
作者:Rest探路者            
<br>
出处:http://www.cnblogs.com/Java-Starter/
<br>本文版权归作者和博客园共有,欢迎转载,但未经作者同意请保留此段声明,请在文章页面明显位置给出原文连接
<br>Github:https://github.com/cjy513203427   
</p>
</div><br><br>
来源:https://www.cnblogs.com/Java-Starter/p/10816298.html
頁: [1]
查看完整版本: 王爽8086汇编语言第二版学习笔记