
简介这份课后习题答案对应《16/32位微机原理、汇编语言及接口技术教程》面向计算机、电子与自动化等专业的学生以及备考微机原理、汇编语言与接口技术课程的学习者用于核对课后练习、梳理章节重点和查漏补缺。压缩包内仅含1个PDF文件约153KB体量轻便适合在电脑或移动端随时查阅。内容围绕微型计算机系统概述、8088微处理器指令系统、总线与存储器、逻辑地址与物理地址转换、补码与BCD码、ASCII码以及汇编子程序设计等核心考点展开并给出多道习题的参考解答与推导过程如求数据块最大值、内存区域填充、标志位差异、地址计算等。已有303人学习下载可作为期末复习、习题订正和考前知识串联的辅助资料帮助读者对照题目理解解题思路与关键概念。1. 把课后答案当验算器而不是背诵材料把《16、32位微机原理、汇编语言及接口技术教程》的课后习题答案当成背诵材料是这门课最亏的用法。更省时间的做法是把答案当验算器先在 EMU8086 或 DOSBox 加 MASM 的环境里把题面代码跑出结果再回头对答案对不上的地方才是真正要补的知识点。这门课三块内容性质完全不同。16 位实模式的习题大多靠“算”——物理地址、标志位、寻址方式、指令执行后的寄存器快照32 位部分偏向“读”——保护模式下的段描述符、分页与寄存器宽度差异接口技术的习题必须“连”起来看——8255 的方式控制字、8253 的计数初值、8259 的中断向量写错一位整个结果都变形。所以答案文件适合两类人正在准备上机和期末的在校生以及临时接手老工控汇编代码、需要快速回忆 8086 细节的工程师。下面按“算得清、跑得动、验得了”三步走重点放在怎么自己把答案推出来、把代码跑起来。2. 16 位到 32 位物理地址、寻址方式与标志位怎么算准课后习题里最容易“看着会、一算就错”的是物理地址换算、寻址方式判断和标志位推演这三类。它们占了 16 位部分的多数篇幅而答案通常只给一个数字错了也看不出错在哪一步。把计算过程固化成可复现的步骤比多刷十道题管用。2.1 段地址与偏移量的换算类习题8086 在实模式下只有 20 根地址线物理地址等于段基址乘以 16 再加偏移量也就是段基址左移 4 位后与偏移量相加。段基址来自 CS、DS、ES、SS 中的一个偏移量由寻址方式给出。习题一般给“逻辑地址 1234H:5678H求物理地址”或者反过来给物理地址问有几种合法的段基址方案。默认段寄存器的配对是失分重灾区判断寻址方式时必须先确定用哪个段寻址中出现的寄存器默认段寄存器能否加段超越前缀BX、SI、DIDS可以BP、SPSS可以取指令CS:IPCS不可以串操作源操作数DS可以串操作目的操作数ES不可以直接寻址如[1234H]默认也是 DS。只有 BP 参与的寻址默认走 SS这是栈帧访问的基础也是选择题里最爱考的一条。把换算固化成一段 MASM 代码用它验算所有同类题; seg_off.asm 把 段:偏移 换算成 20 位物理地址 ; 输入: AX段基址, BX偏移量 ; 输出: DX 存 bit16~bit19, AX 存低 16 位 mov ax, 1234h mov bx, 5678h mov cl, 4 shl ax, cl ; 段基址左移 4 位, 等价于乘 16 add ax, bx ; 得到物理地址低 16 位 adc dx, 0 ; 若相加有进位, CF 落到 DX 高位参数说明8086 的移位指令用 CL 指定移位次数直接写shl ax,4在 MASM 6.x 下会报错这是新手第一个坑。adc dx,0的作用是把相加产生的进位接进高位20 位地址不能只看 AX。反过来从物理地址推段基址时段基址必须是 16 的倍数所以 179B8H 既能由 1234H:5678H 得到也能由 1000H:79B8H 得到习题问“几种方案”时要把所有合法段值列全别只写一种。2.2 32 位保护模式习题与实模式的三个差异做 32 位部分的习题先把差异表记住否则会习惯性套用实模式的公式。对比项16 位实模式32 位保护模式通用寄存器宽度AX、BX 等 16 位EAX、EBX 等 32 位段寄存器的含义段基址的高 16 位选择子指向 GDT 或 LDT 中的描述符物理地址计算段基址左移 4 位加偏移描述符中的基址直接加偏移偏移量范围64KB由段限长限制最大 4GB段寄存器装载mov ds, axmov ax, sel后mov ds, ax段描述符里的基址虽是 32 位却被拆成三块存放限长是 20 位G 位为 1 时单位是 4KB为 0 时单位是字节。习题常问“基址 00010000H、限长 000FFH、G0可寻址范围是多少”答案是 00010000H 到 000100FFH共 256 字节G1 时要用限长乘以 4KB。判断越界时访问的偏移量必须小于等于限长等于限长是合法的这条细节经常被漏掉。2.3 标志位判定题的推演方法加法类题目看两个标志CF 是有没有从最高位进位OF 是两个同号数相加是否变成异号。减法类题目里 CF 表示借位OF 的判定逻辑不变。逻辑运算会清零 CF 和 OF移位指令把最后移出的那一位送进 CF。手算容易漏掉 OF用下面这段代码把标志位直接读出来对照; flags.asm 执行一条指令后取 FLAGS 快照 mov ax, 7fffh add ax, 0001h ; 7FFFH1 8000H, 符号位翻转 pushf ; FLAGS 压栈 pop ax ; AX 低 8 位含 SF ZF AF PF CF 等 lahf ; 另一种做法, AH SF:ZF:0:AF:0:PF:1:CF分析7FFFH 加 0001H 结果是 8000H最高位没有进位所以 CF0两个正数相加得到负数所以 OF1结果最高位为 1 所以 SF1结果非零所以 ZF0。pushf和pop ax的组合能把 16 位标志寄存器完整取到 AXlahf只取低 8 位但更省事。注意lahf取不到 OF涉及溢出的题目必须用 pushf 的快照否则对不上答案。3. MASM 加 io.lib 的上机链路把习题代码跑成 exe 并验证端口读写上机题通常要求用 MASM 编译、用 io.lib 做端口读写这条链路本身不长但每一步都有固定的坑。先把“编译、链接、调试”三步跑通再谈端口是否真的读到值。3.1 最小可运行流程masm、link、td 三步masm hello.asm; # 生成 hello.obj, 分号表示后续提示一律回车接受默认值 link hello.obj; # 生成 hello.exe, 需要库时写成 link hello.obj,hello,,io.lib; td hello.exe # Turbo Debugger 单步; 没有 td 就用 debug hello.exe分号是关键。MASM 和 LINK 会连续询问目标文件名、列表文件名、库文件名、段对齐方式逐项回车容易漏项加一个分号等于一次性接受全部默认值。需要链接 io.lib 时LINK 的库文件参数是第三个字段写法容易记错直接把它写在对象文件后面用逗号占位更稳。反复改代码时写一个批处理更省事rem build.bat 用法: build hello echo off if %1 goto usage masm %1.asm; if errorlevel 1 goto err link %1.obj; if errorlevel 1 goto err echo BUILD OK goto end :err echo BUILD FAILED goto end :usage echo usage: build filename_without_ext :end参数说明%1是传入的文件名不带扩展名errorlevel 1判断上一步是否失败MASM 或 LINK 只要有错误就会返回非零值。注意批处理里判断错误必须紧跟在命令后面中间插入别的命令会把 errorlevel 覆盖掉这是批处理最常见的低级错误。3.2 io.lib 的链接方式与端口读写参数io.lib 是一组端口读写函数的集合常用的是_inp、_outp、_inpw、_outpw四个。在 MASM 里调用它们要先声明为外部符号并按 C 调用约定传参参数从右往左压栈由调用方负责清栈。函数原型参数入栈顺序调用后清栈_inpint _inp(unsigned port)portadd sp, 2_inpwunsigned _inpw(unsigned port)portadd sp, 2_outpint _outp(unsigned port, int value)valueportadd sp, 4_outpwunsigned _outpw(unsigned port, unsigned value)valueportadd sp, 4; port_io.asm 读 8255 的 C 口状态, 再写到 B 口 .model small .stack 100h extern _inp:near, _outp:near ; C 库函数, 参数从右往左压栈 .code start: mov ax, 0062h ; 8255 的 C 口地址 push ax call _inp ; AL 返回 C 口内容 add sp, 2 ; 调用方清栈, 保持栈平衡 mov ah, 0 push ax ; value 参数先入栈 mov ax, 0061h ; B 口地址 push ax ; port 参数后入栈 call _outp add sp, 4 ; 两个 16 位参数, 清 4 字节 mov ax, 4c00h int 21h end start逻辑说明读函数只有一个参数压一次栈、清 2 字节写函数有两个参数先压 value 再压 port清 4 字节。如果符号名对不上比如报_inp未定义常见原因是不同版本的库把符号做成了__inp或inp_用link /map生成映射文件看一眼导出名就能确定比猜快得多。非 C 约定的库例如 pascal 约定不需要调用方清栈这时多写一句add sp反而会把栈搞乱表现为子程序返回后跳到错误地址。3.3 端口实验跑不通时的排错顺序按下面顺序排查能覆盖大部分卡壳场景现象常见原因处理A2006 undefined symbol没写 extern 声明补extern _inp:nearL2029 unresolved external链接时没带库link x.obj,x,,io.lib;运行直接异常退出在受保护的操作系统用户态执行端口指令换纯实模式环境或仿真器读回恒定值端口地址算错基址加偏移重新核对输出无变化控制字没先写或写错端口先写控制口再写数据口注意端口读写指令属于特权操作在普通用户态进程里执行会触发异常。上机时优先在实模式或专门的仿真环境里跑别在这上面浪费时间。4. 接口芯片习题的工程化验算8255、8253、8259 三件套接口部分的习题几乎都是“给一个应用场景写出初始化程序”。这类题的答案对不对取决于控制字每一位拼得对不对以及初始化顺序对不对。把三个芯片的控制字格式背熟之后用代码验算比逐题对答案高效得多。4.1 8255 方式控制字的位拼装8255 的控制字分两种方式选择控制字D71和 C 口按位置位复位控制字D70。方式字的位定义如下位名称含义D7标志位恒为 1D6 D5A 组方式00 方式001 方式11x 方式2D4A 口方向1 输入0 输出D3C 口高 4 位1 输入0 输出D2B 组方式0 方式01 方式1D1B 口方向1 输入0 输出D0C 口低 4 位1 输入0 输出例如要求 A 口方式 0 输出、B 口方式 0 输入、C 口高 4 位输出、低 4 位输入拼出来是 D71、D6D500、D40、D30、D20、D11、D00即 10000010B 等于 82H。; ppi8255.asm 按上面的要求初始化 8255 PPI_BASE equ 060h ; A口 060H, B口 061H, C口 062H, 控制口 063H mov dx, PPI_BASE3 mov al, 10000010b ; 82H out dx, al ; 写控制字 mov dx, PPI_BASE mov al, 0ffh out dx, al ; A 口全部输出 1参数说明控制口地址是基址加 3A、B、C 三口依次加 0、1、2。写控制字必须在写数据之前顺序反了输出会保持上次的配置。C 口按位置位用out 控制口, 位号*21置 1位号*2复位位号从 0 到 7 对应 PC0 到 PC7。4.2 8253 计数初值与输出频率的计算8253 的计数初值等于输入时钟频率除以目标输出频率取值范围 1 到 65536写 0000H 表示 65536。二进制计数时写 16 位BCD 计数时写 4 位十进制数最大 9999。工作方式共 6 种习题里最常考的是方式 2 和方式 3方式名称输出特征0计数结束中断计到 0 时输出变高并保持1可编程单稳触发后输出一个负脉冲2频率发生器周期性输出自动重装3方波发生器周期为计数值的对称方波4软件触发选通计到 0 输出一个负脉冲5硬件触发选通由外部触发启动例输入时钟 2MHz要得到 1kHz 方波选方式 3初值为 2000000 除以 1000 等于 2000。; timer8253.asm 计数器0 工作在方式3, 初值 2000 TMR_BASE equ 040h ; 计数器0 040H, 1 041H, 2 042H, 控制口 043H mov dx, TMR_BASE3 mov al, 00110110b ; 00 计数器0, 11 先低后高, 011 方式3, 0 二进制 36H out dx, al mov dx, TMR_BASE mov ax, 2000 out dx, al ; 先写低字节 mov al, ah out dx, al ; 再写高字节参数说明控制字高两位选计数器中间两位选读写格式01 只读低 8 位10 只读高 8 位11 先低后高再三位选工作方式最低位选计数制式。读当前计数值要用锁存命令把控制字 D7D6 置 11、D5 置 0再按同样顺序读否则读到的两个字节可能不是同一时刻的值。4.3 8259 中断向量表填写与 ISR 收尾中断类型号 N 对应的向量表位置是内存 0000H 段的 N 乘以 4 处连续 4 个字节依次存放偏移低 8 位、偏移高 8 位、段低 8 位、段高 8 位。类型号 8 对应 0000H:0020H这一点很多题会直接问。; pic8259.asm 安装类型号 8 的中断服务程序 cli xor ax, ax mov es, ax mov bx, 08h*4 ; 类型号 8 的向量在 0000H:0020H mov word ptr es:[bx], offset myisr mov ax, cs mov word ptr es:[bx2], ax sti ; ... 主程序 myisr proc far push ax push dx ; 保护现场 ; 具体中断处理 mov dx, 020h mov al, 20h out dx, al ; 发非特殊 EOI pop dx pop ax iret myisr endp要点说明中断服务程序必须是 far 过程末尾用iret而不是ret用到的寄存器要自己保护编译器不会代劳。EOI 必须在处理结束时发出否则同级中断不会再次被响应表现为“只中断一次就再也没反应”。cli和sti包住向量表改写过程避免改到一半发生中断。4.4 没有实验箱时的替代验证验证手段能验证什么局限EMU8086 虚拟外设指令执行、寄存器与标志位外设模型较简化Proteus 挂芯片模型8255、8253、8259 的时序与波形建模型耗时纯手算加对照表控制字、初值、向量地址验证不了时序真实实验箱全部依赖硬件可用性选哪种取决于题目问什么。问控制字和初值的手算加表格最快问“输出波形什么样”的得靠仿真或实验箱。用仿真器跑之前先确认端口地址与题目一致很多人栽在仿真里用了默认地址、和题面给的不一样。5. 单步快照与错题回归集把答案校到指令级答案给的是一个结果而习题考的是过程。把结果拆成一条条指令的快照才是真正把答案用起来的方式。5.1 用 T 命令逐条比对寄存器与标志在 DEBUG 里用T单步Turbo Debugger 里按 F7每执行一条指令就检查全部寄存器AX、BX、CX、DX、SI、DI、BP、SP、DS、ES、SS、CS、IP以及 FLAGS 里的 CF、ZF、SF、OF。做法是先把答案预期结果写成一行注释贴在代码旁边单步到对应位置时逐项比对第一个对不上的点就是错误源头。最容易被跳过的是 SP。涉及 push、call、中断的题目SP 变化不对往往是栈段没设或清栈语句漏写这类错误不会体现在最终数据上但会在子程序返回时炸掉。5.2 把易错题固化成可回归的批处理集把每道做错的题单独存成一个 asm 文件放进同一个目录配一个批处理一次跑完rem runall.bat 批量编译运行并比对输出 echo off setlocal enabledelayedexpansion for %%f in (t*.asm) do ( masm %%f; link %%~nf; %%~nf.exe %%~nf.out fc %%~nf.out %%~nf.exp nul if errorlevel 1 (echo FAIL: %%f) else (echo PASS: %%f) )逻辑说明%%~nf取不带扩展名的文件名每个题目配一个同名.exp文件存放期望输出fc做文本比对返回非零说明结果与期望不一致。改一处公共代码后跑一遍就能看出哪些题被改坏了。这个习惯的价值在期末复习阶段特别明显比重新翻一遍答案快得多。5.3 三类题各自的验证优先级题型首选验证次选不建议地址与标志位计算写小 exe 打印 FLAGS 快照DEBUG 单步直接背答案数字指令序列结果Turbo Debugger 单步EMU8086 仿真只看最终结果接口芯片初始化对照控制字逐位拼装Proteus 看波形抄同学的控制字提示把每道错题的最小复现 exe 和期望输出留在同一个目录里就是一套自己的回归测试集。控制字改一位、初值换一个跑一遍 fc 就能知道影响面这比在纸上重新推一遍可靠。真正的分水岭不在做了多少题而在于每道题都留下了能重跑的 exe 和比对脚本答案文件只是最后用来确认的那一步。本文还有配套的精品资源点击获取