ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

微机原理与汇编语言习题实战:8086寻址与8255/8253/8259控制字

微机原理与汇编语言习题实战:8086寻址与8255/8253/8259控制字 简介这份PDF是《16/32位微机原理、汇编语言及接口技术教程》的配套课后习题参考答案面向学习微机原理、汇编语言与接口技术的高校本科生、考研复习者及自学者。答案覆盖第1章微型计算机系统概述、第2章微处理器指令系统等章节逐题给出通用微处理器、单片机、DSP与嵌入式系统的概念辨析总线三组信号各自作用以及计算机字长、取指—译码—执行周期、ROM-BIOS、中断、ISA总线等名词解答数字表示部分含十六进制转十进制、压缩BCD码互换、8位二进制补码表示与ASCII码对照练习并涉及8088逻辑地址与物理地址换算、CF与OF标志差异分析。汇编编程部分还提供求数据块最大值、按指定区域填充字节等题目的参考代码思路。资源包含1个PDF文件压缩包约153KB体积轻便便于打印或随查随用。目前已有303人学习适合课后核对答案与考前查漏补缺。1. 从抄答案到验答案微机原理习题的坑都埋在数值里翻开一份《16、32位微机原理、汇编语言及接口技术教程》的课后习题答案最常见的用法是对着题号抄一遍考前再背一遍。可这类题的答案几乎全是数值有效地址、物理地址、计数初值、方式控制字、中断类型号换一个数据就全废。能带走的从来不是那串数字而是算出它的流程。下面面向正在啃 8086 实模式寻址、要手写 MASM 程序段、还要推导 8255/8253/8259 控制字的读者把课后习题当成一个个可复现的小工程来做先把能跑的汇编环境搭起来再把手算过程写成脚本对拍最后用调试器看寄存器与标志位把答案是多少变成这个数为什么是它。做完至少能做到拿到题敢算、算完能跑、跑错知道错在哪一位。2. 搭一套能跑 8086 汇编习题的最小环境2.1 为什么 32 位的题也要先过 16 位这一关教材的章节顺序基本是 8086 实模式、80386 保护模式与 32 位寻址、再往下才是接口芯片。课后习题里求物理地址写程序段绝大多数是 16 位题用不到保护模式而 32 位部分会考.386、.model flat、扩展寄存器 EAX/EBX/ESI 和比例变址[EBXESI*4]。这两类题没法用一个环境通吃工具选型建议按题目类型分开。题目类型常用工具运行方式典型场景16 位 8086 程序段MASM 5.x/6.x LINKDOSBox 挂载目录后直接执行教材前半、上机题32 位 80386 程序段ML.EXE LINK控制台程序教材后半、寻址扩展只看寄存器与标志位DEBUG交互式单步指令类小题课程自带 io.lib 的上机LINK 时附加 IO.LIB与 16 位相同学校给定的输入输出库前两类必须有一个真实可执行的环境因为习题里程序执行后 AX 等于多少这种题手推容易在标志位那一环翻车跑一遍最省事。2.2 DOSBox 里把 MASM 链路跑通的最小命令常见做法是把工具链和源码都放在同一个目录用 DOSBox 挂成 C 盘然后依次执行汇编、链接、运行。分号的作用是让汇编器对所有提示都取默认值不生成中间清单文件也不逐项询问。# 假设 masm.exe、link.exe 和源码都在 C:\ASM 下 MOUNT C C:\ASM # 把宿主目录挂成 DOS 的 C 盘 C: # 切到 C 盘 MASM T1.ASM; # 汇编分号所有提示取默认值 LINK T1.OBJ; # 链接生成 T1.EXE T1.EXE # 运行如果课程的上机要求链接一个提供输入输出过程的 IO.LIB链接命令行写成LINK T1.OBJIO.LIB;即可缺了这个库会报未解析的外部符号。下面这段程序可以用来验证链路是否正常它做的正是习题里常见的 32 位加法低位用 ADD高位必须用 ADC 把进位补进去。; T1.ASM —— 16 位环境下算 DX:AX 32 位被加数 32 位加数 .model small .stack 100h .code start: mov ax, 1234h ; 被加数低 16 位 mov dx, 0ABCDh ; 被加数高 16 位 add ax, 0F000h ; 加数低 16 位产生进位时 CF1 adc dx, 0001h ; 高 16 位带进位加把 CF 一起加进去 mov ah, 4Ch ; DOS 功能号 4CH结束程序 int 21h end start.model small表示代码段和数据段各占一个 64KB 段教材前半的例题几乎都是这个模型.stack 100h分配 256 字节堆栈end start指定start为程序入口。4CH号功能是 16 位 DOS 下结束进程的标准写法漏掉它程序跑完会回到一个不确定的位置看起来像卡死。2.3 用 DEBUG 单步核对寄存器与标志位DEBUG 是这批习题最直接的验算器它能一条一条执行机器码并把执行后的标志位打在屏幕上。对执行下列指令后 CF、OF、ZF 各是什么这类题比手推快得多。DEBUG T1.EXE -u # 反汇编确认第一条指令的偏移 -r # 查看 AX/BX/CX/DX/SP/BP/SI/DI 和全部标志位 -t # 单步一条观察寄存器与标志位变化 -t 2 # 连续单步两条 -r ax # 直接改写 AX用来构造不同的测试数据DEBUG 显示的标志位是缩写CY/NC 是 CFOV/NV 是 OFZR/NZ 是 ZFPL/NG 是 SFDN/UP 是 DF。做完一条 ADD 立刻看 CY 和 OV就能对上习题里是否溢出的答案。DEBUG 显示标志位含义CY / NCCF进位或借位无符号数溢出标志OV / NVOF有符号数溢出标志ZR / NZZF运算结果是否为零PL / NGSF结果最高位的符号DN / UPDF串操作的方向地址递增或递减提示CF 和 OF 是两套独立的判断标准无符号数看 CF有符号数看 OF。题目里出现溢出两个字时先判断题目把操作数当有符号还是无符号再决定看哪个。2.4 报错对照表别在工具链上耗时间习题集里的代码大多是片段直接丢给汇编器经常报错报错信息本身不难读难在不知道对应哪个书写习惯。报错出现阶段大概率原因处理办法undefined symbol汇编标号拼错或标号定义在使用之后核对拼写把标号移到引用之前syntax error汇编操作数宽度没说清如MOV [2000H], 12H写成MOV BYTE PTR [2000H], 12Hinitializer magnitude too large汇编立即数或数据定义超出 16 位拆成两条或改用 DW/DD 定义unresolved external链接调用了外部过程但没链接对应 .OBJ/.LIB在 LINK 行补上IO.LIB之类运行后一闪而过运行忘了 4CH 号功能结束程序补上MOV AH,4CH与INT 21H2.5 32 位程序段在同一台机器上怎么落地32 位题目要用 32 位汇编器伪指令.386打开 32 位指令集.model flat使用平坦内存模型此时 CS、DS、ES 都指向同一个 4GB 空间不再需要手工初始化 DS。下面这段程序把数组前 4 个双字相加正好覆盖 32 位寄存器、比例指针递增和循环三条考点。; T2.ASM —— 32 位EAX 数组前 4 个双字之和 .386 .model flat, stdcall ExitProcess PROTO :DWORD .data arr DWORD 1, 2, 3, 4 .code start: mov esi, OFFSET arr ; ESI 指向数组首地址 mov eax, 0 ; 累加器清零 mov ecx, 4 ; 循环次数 L1: add eax, [esi] ; 取一个双字累加 add esi, 4 ; 双字指针后移 4 字节 loop L1 INVOKE ExitProcess, 0 end start汇编命令是ML /c /coff T2.ASM链接命令是LINK /subsystem:console T2.OBJ kernel32.lib最后一行必须带上kernel32.lib否则INVOKE ExitProcess会报未解析的外部符号。32 位段里LOOP依然用 ECX 计数这一点和 16 位用 CX 是对应的很多答案在这里写成 ECX 是经过调整的版本考试时按题目给的段属性来写。3. 汇编语言习题的三类高频题型寻址、程序段、子程序3.1 寻址方式与有效地址先算 EA再拼物理地址寻址方式题的核心只有一个公式物理地址 段基址 × 16 有效地址。乘 16 就是左移 4 位段基址和偏移在硬件上拼成 20 位地址。把 EA 的构成先列清楚后面就不会乱。寻址方式示例有效地址 EA立即寻址MOV AX, 1234H没有 EA操作数在指令里寄存器寻址MOV AX, BX没有 EA操作数在寄存器直接寻址MOV AX, [2000H]2000H寄存器间接MOV AX, [BX](BX)寄存器相对MOV AX, [BX10H](BX) 10H基址变址MOV AX, [BXSI](BX) (SI)相对基址变址MOV AX, [BXSI10H](BX) (SI) 10H拿一道典型题演算已知 DS1000H、BX0200H、SI0030H求MOV AX,[BXSI10H]的物理地址。EA 0200H 0030H 10H 0240H物理地址 1000H × 16 0240H 10240H。默认段寄存器的规则也要记住BX、SI、DI加位移默认走 DSBP、SP默认走 SS串操作的源走 DS、目的走 ES。访问类型可用寄存器默认段寄存器取指令IPCS堆栈操作SP、BPSS一般数据BX、SI、DI、位移DS串操作源SIDS串操作目的DIES需要越段访问时加段超越前缀写法是MOV AX, ES:[BX]这类小题在习题里出现的频率很高写的时候把段寄存器写在方括号前面。3.2 程序段题从寄存器分配开始写程序段题的通用套路是四步先定输入和输出放在哪再把它们分配给寄存器接着判断数据宽度够不够最后才写循环或分支。跳过前两步直接写指令通常会在改寄存器的时候把循环计数冲掉。下面这道统计字节数组中 0 的个数是经典题型。; COUNT0.ASM —— 统计字节数组 arr 中 0 的个数 .model small .stack 100h .data arr db 0, 5, 0, 8, 0, 1, 2, 0 ; 8 个字节 cnt db 0 ; 结果存放处 .code start: mov ax, data mov ds, ax ; 16 位模型下必须手工初始化 DS mov si, OFFSET arr ; SI 作数组指针 mov cx, 8 ; CX 作循环计数与元素个数一致 mov bl, 0 ; BL 作计数器 again: cmp byte ptr [si], 0 ; 与 0 比较只改标志位不改操作数 jne skip inc bl ; 相等则计数加一 skip: inc si ; 指针后移一个字节 loop again ; CX 减一非零继续 mov cnt, bl ; 结果写回数据段 mov ah, 4Ch int 21h end startCMP做的是减法但不把结果写回操作数只影响标志位所以后面紧跟条件转移指令。LOOP隐含使用 CX循环体里任何改动 CX 的指令都会破坏循环次数这就是把计数器放在 BL 而不放在 CL 的原因。BYTE PTR在这里不能省因为另一个操作数是立即数 0汇编器无法判断该按字节还是按字比较。3.3 子程序题参数传递、现场保护与堆栈平衡子程序题考三件事参数怎么传、被调过程改动的寄存器要不要恢复、堆栈指针最后是否回到入口时的位置。寄存器传参最省事但必须把用到的寄存器先压栈出口再弹回否则调用者原来的值就被破坏了。; SUM16 —— 求字数组和入口 SI首地址, CX元素个数出口 AX和 SUM16 PROC push bx ; 保护现场BX 属于调用者的资源 xor ax, ax ; 累加器清零 xor bx, bx ; BX 作字节偏移量 next: add ax, [sibx] ; 取一个字累加 add bx, 2 ; 字数组偏移每次加 2 而不是 1 loop next pop bx ; 恢复现场 ret SUM16 ENDP[SIBX]是相对基址变址寻址SI 是基地址、BX 是变化的偏移这样写比每次INC SI两次更直观。push和pop必须配对中间任何一条提前返回的指令都会让堆栈失衡这是子程序题最常被扣分的地方。如果题目要求返回 32 位和累加时还要把进位一起累加到高位寄存器里光用ADD AX,[SIBX]会丢进位。3.4 INT 21H 调用题入口参数和返回值必须写全DOS 功能调用题的答案通常只有三五行但入口参数、功能号和返回值的对应关系必须背熟写错一个寄存器整段就白写。功能号 AH作用入口参数出口结果01H键盘输入单字符并回显无AL 输入的字符02H显示单个字符DL 待显示字符无09H显示以$结尾的字符串DS:DX 串首地址无0AH带回显的缓冲输入DS:DX 缓冲区首地址缓冲区被填入数据4CH结束程序返回 DOS无无.model small .stack 100h .data msg db Hello, 8086$ ; 必须以 $ 结尾09H 才会停止 .code start: mov ax, data mov ds, ax mov dx, OFFSET msg ; DS:DX 指向字符串首地址 mov ah, 09h ; 功能号 09H显示字符串 int 21h mov ah, 4Ch ; 结束程序 int 21h end start09H号功能靠$判断字符串结束忘了结尾符会把后面的数据一起打到屏幕上这是运行结果异常时第一个要检查的地方。0AH号功能的缓冲区格式更绕第一字节由程序填写最大允许长度第二字节由 DOS 填写实际读入长度真正的字符从第三个字节开始存放习题里经常拿这个位置关系出填空。4. 接口技术习题8255、8253、8259 的控制字怎么推4.1 端口地址译码从地址线到片选信号接口部分的题几乎都要先算端口地址算错了后面的控制字全白搭。方法固定先看片选信号由哪些地址线决定写出让片选有效的二进制组合得到基址再把 A1、A0 的四种组合接到基址上得到四个端口。假设某片 8255 的 CS 接在译码电路上A7 到 A2 为010000时片选有效A1、A0 直接连芯片则四个端口如下。片内端口A1 A0端口地址A 口0 040HB 口0 141HC 口1 042H控制口1 143H推导的关键在于确认哪些地址线参与了译码。如果只有 A7 到 A2 参与那么 A15 到 A8 取任何值都会选中同一片芯片同样四个端口会对应一大片地址这就是部分译码带来的地址重叠。习题里问该芯片共占用多少个地址单元答的往往是重叠后的总数而不是 4 个。全译码则要求地址线一根不落地接进译码电路重叠区只剩片内的 4 个单元。不同教材画的译码图不一样基址必须按题图算背下来的基址换一张图就错。4.2 8255 方式控制字用位表反推8255 的方式控制字有固定的位定义最高位 D7 固定为 1表示这是一个方式设置字而不是 C 口的位操作字。位含义D7标志位方式设置字固定为 1D6 D5A 组方式00 为方式 0D4A 口方向1 输入、0 输出D3C 口高 4 位方向1 输入、0 输出D2B 组方式0 为方式 0D1B 口方向1 输入、0 输出D0C 口低 4 位方向1 输入、0 输出一道典型题A 口方式 0 输出、B 口方式 0 输入、C 口高 4 位输出、低 4 位输入。按上表逐位填D71、D6D500、D40、D30、D20、D11、D01合成10000011B也就是 83H。; 8255 初始化A口方式0输出B口方式0输入C口高4位输出、低4位输入 MOV DX, 43H ; 控制口地址来自 4.1 的译码结果 MOV AL, 10000011B ; 83H直接写二进制比写十六进制更容易核对 OUT DX, AL ; 方式控制字必须在读写数据之前先写对 C 口做位操作时要用另一套字D7 必须为 0D3 到 D1 选定位号D0 决定置 1 还是清 0。例如把 PC3 置 1字是00000111B即 07H把 PC3 清 0 则是 06H。位操作字只能作用于 C 口对 A 口 B 口无效题目里问能否用位操作字单独改变 A 口某一位答案是不能。4.3 8253 计数初值公式、方式和读写顺序8253 的题分两步先按初值 输入时钟频率 ÷ 输出频率算出计数初值再按通道号、读写方式、工作方式、计数进制拼出控制字。假设输入时钟 1MHz要求通道 0 输出 1kHz 方波初值就是 1000即 03E8H工作方式选方式 3。位含义本例取值D7 D6通道选择00 为通道 000D5 D4读写方式11 为先低字节后高字节11D3 D2 D1工作方式011 为方式 3011D0计数进制0 为二进制0合起来是00110110B即 36H。写初值时的高低字节顺序是最容易错的地方顺序写反结果会差 256 倍。; 8253 通道0方式3 方波二进制计数初值 1000 MOV DX, 4BH ; 控制口地址假设这片 8253 占用 48H~4BH MOV AL, 00110110B ; 36H通道0 / 先低后高 / 方式3 / 二进制 OUT DX, AL MOV DX, 48H ; 通道0 数据口 MOV AX, 1000 ; 03E8H OUT DX, AL ; 先写低字节 E8H MOV AL, AH OUT DX, AL ; 再写高字节 03H控制字里的读写方式位 D5 D4 必须和实际写数据的顺序一致如果控制字写的是只写低字节那么第二个OUT写进去的高字节会被当成下一个初值的低字节通道频率直接错乱。另外 8253 的初值范围是 1 到 65536其中 65536 用 0000H 表示这一条在填空题里出现的频率很高。4.4 8259 初始化与中断向量表的定位8259 的初始化命令字有四条按顺序写进同一个端口中间不能插别的操作。中断向量表的定位公式是向量号为 N 的中断其入口地址存放在物理地址N × 4开始的 4 个字节里前两个字节是偏移后两个字节是段基址。; 8259 主片初始化假设命令口 20H、数据口 21H MOV DX, 20H MOV AL, 13H ; ICW1边沿触发需要 ICW4 OUT DX, AL MOV DX, 21H MOV AL, 20H ; ICW2中断类型号基址 20H即 IR0 对应 20H OUT DX, AL MOV AL, 01H ; ICW48086/8088 模式非自动 EOI OUT DX, AL MOV AL, 0FEH ; OCW1只开放 IR0其余屏蔽 OUT DX, ALICW1的 13H 拆开看是D71 表示这是 ICW1D31 表示需要 ICW4D01 表示需要初始化。ICW2的高 5 位就是中断类型号基址低 3 位由 8259 按引脚号自动填。中断服务程序里必须发一次 EOI否则同级及更低级的中断不会再被响应写法是MOV AL,20H加OUT 20H,AL最后用IRET返回。以INT 21H为例它的向量号是 21H入口地址在21H × 4 84H处偏移占 84H、85H段基址占 86H、87H。习题里问中断向量表的哪几个单元被 INT n 占用直接用 n 乘 4 算出起始地址再往后数四个字节即可。5. 课后习题的自校验流程算一遍、跑一遍、对一遍5.1 用几行脚本把手算结果对一遍物理地址和计数初值这两类计算最适合用脚本对拍手算完再跑一遍几秒钟就能发现移位和取整的错误。def phys(seg, off): 段基址左移 4 位加偏移得到 20 位物理地址 return (seg 4) off print(hex(phys(0x1000, 0x0240))) # 0x10240 def count_init(f_in, f_out): 8253 计数初值超过 65536 说明需要级联或换通道 n round(f_in / f_out) assert 1 n 65536, 初值超出单个计数器范围 return n 0xFFFF # 65536 写作 0000H print(hex(count_init(1_000_000, 1_000))) # 0x3e8函数里的assert比算式更有价值它把超出范围这个隐含条件显式写出来了。习题里常见的坑就是给一个需要级联的时钟比考生硬算出一个大于 65536 的初值交上去写惯了校验就知道该先看上限。5.2 用 DEBUG 的 -a 现敲指令验标志位指令类小题不需要写完整程序直接在 DEBUG 里敲两条指令就能看到标志位。DEBUG -a # 从当前地址开始输入汇编指令 xxxx:0100 MOV AL, 7FH xxxx:0102 ADD AL, 01H xxxx:0104 # 空行结束输入 -t 2 # 单步两条执行后 AL 变成 80H屏幕上显示 OVOF1和 NGSF1而 CY 保持为 NC。这正是有符号溢出但无符号不进位的经典组合7FH 加 01H 对无符号数来说是 127 加 1没超过 255所以 CF0对 8 位有符号数来说超过了 127 的上限所以 OF1。手推标志位时把这两个概念混在一起是这个题型最集中的失分点。5.3 错题定位的固定顺序发现自己算的答案和参考值对不上时按一个固定顺序排查比乱翻书快得多。先看操作数宽度再看标志位的种类最后看端口读写的顺序。症状先查什么常见结论结果差 256 倍操作数宽度字节与字混用或高低字节顺序颠倒符号判断和答案相反CF 与 OF 混淆无符号看 CF有符号看 OF输出频率差 65536 倍计数初值上限65536 应写成 0000H中断不响应向量表首址与 EOIn×4 定位错或服务程序里没发 EOI端口读数始终不变控制字是否先写8255/8253 必须先写控制字再读写数据下次再遇到 8253 的题先把控制字 36H 和两条 OUT 的先后顺序写下来再回头算计数初值顺序反了必错。本文还有配套的精品资源点击获取
返回列表