资讯动态

MASM 6.11 汇编与接口技术实验全解析:从冒泡排序到8259A/8255中断编程

发布时间:2026/10/22 7:38:29 来源:尧图企业网站定制
简介这份PDF实验报告面向学习汇编语言与接口技术的高校学生聚焦MASM 6.11开发环境下的程序设计与中断接口编程适合课程实验提交、上机调试参考及期末复习使用。报告完整覆盖两大实验模块一是汇编语言程序设计围绕8位无符号数与有符号数的冒泡排序给出程序流程图、完整代码及DEBUG调试分析二是系统中断接口实验包含自定义78H软件中断实现ASCII码到压缩BCD码转换以及8259A可编程中断控制器下IRQ10至IRQ12硬件中断服务程序编写并附主程序与中断服务程序代码。资源包共1个PDF文件大小约1.03MB内容按实验目的、内容、要求、程序说明、代码与运行结果逐项展开结构清晰。目前已有131人学习下载可帮助读者对照实验要求快速理解排序算法实现、中断向量设置与调试流程适合作为课程实验的完整参考与排错依据。1. 从一份 2012 级实验报告说起MASM 6.11 环境到底还能不能跑翻到这份《汇编语言与接口技术实验报告》的时候我第一反应是——这玩意儿现在还有人用第二反应是——还真有而且不少高校的接口技术课至今没换过实验箱和 MASM 6.11 这套组合。报告里四个实验冒泡排序无符号/有符号两版、8259A 软硬件中断、8255 键盘扫描码读取、显示器笑脸动画基本覆盖了 8086 汇编和接口芯片的核心操作。如果你正在做类似实验、或者想拿这份报告当模板复现一遍那它确实能省你不少翻手册的时间。这份资源适合三类人一是正在上汇编/接口课、需要交实验报告的学生二是想重新捡起 8086 汇编、理解中断机制和端口读写的开发者三是需要一份完整可运行代码参考的从业者。它解决的核心问题是把 MASM 6.11 下的完整代码、DEBUG 调试步骤、中断向量表操作、8259A/8255 端口编程这些散落在教材各处的知识点串成一条能跑通的链路。下面我按「环境怎么搭 → 代码怎么跑 → 坑在哪 → 怎么验证」的顺序拆一遍。2. MASM 6.11 环境搭建与冒泡排序的两种写法2.1 为什么是 MASM 6.11 而不是 MASM32 或 NASM报告里明确写了 MASM 6.11这不是随便选的。MASM 6.11 是 16 位汇编的经典版本支持.model small、.startup、.exit这些简化段定义伪指令对 8086 实模式下的段寄存器操作非常友好。NASM 语法差异大MASM32 偏 32 位保护模式都不太适合直接跑这份报告里的代码。常见做法是在 DOSBox 里挂载 MASM 6.11 目录或者用虚拟机装个 DOS 6.22。我一般会推荐 DOSBox-X它对端口读写和中断模拟比原版 DOSBox 更完整跑 8259A 和 8255 实验时不容易卡死。安装步骤不复杂但有几个点容易翻车# 假设 MASM 6.11 解压在 C:\MASM611 # DOSBox 挂载命令 mount c c:\masm611 c: # 设置路径 set pathc:\masm611\bin;c:\masm611\binr # 验证 masm逻辑说明mount把宿主机目录映射为 DOS 下的 C 盘set path让 MASM、LINK、DEBUG 这些工具能在任意目录调用。参数上注意binr目录放的是实模式工具别只挂bin。如果masm命令报「Bad command or file name」八成是路径没设对或者 DOSBox 挂载时目录名有空格。2.2 无符号排序与有符号排序一条跳转指令的差别报告里两段排序代码结构几乎一样唯一区别在cmp后面的跳转指令无符号用jna不大于则跳过交换有符号用jle小于等于则跳过交换。这个差别是整份报告里最值得细看的地方。; 无符号版本核心循环 loop2: mov al, block[bx] cmp al, block[bx1] jna continue ; 无符号比较al block[bx1] 则不交换 xchg al, block[bx1] mov block[bx], al continue: add bx, 1 loop loop2; 有符号版本核心循环 loop2: mov al, block[bx] cmp al, block[bx1] jle continue ; 有符号比较al block[bx1] 则不交换 xchg al, block[bx1] mov block[bx], al continue: add bx, 1 loop loop2逻辑说明cmp指令本身不区分符号它只做减法并设置标志位。jna看的是 CF 和 ZF把数据当无符号数jle看的是 SF、OF、ZF把数据当有符号数。报告里那批数据61H, 84H, 93H, 0C4H, 17H, 0FFH, 52H, 2AH正好是个典型例子——84H无符号是 132有符号是 -1240FFH无符号是 255有符号是 -1。同一批数据两种解释下排序结果完全不同。参数说明n dw 8定义数据个数dec cx后外层循环跑 7 轮内层loop2每轮比较相邻两个数。bx从 0 开始每次加 1直到cx减到 0。这里有个细节内层循环的cx在外层被mov dx, cx保存内层跑完后mov cx, dx恢复否则外层循环次数会乱。2.3 用 DEBUG 验证排序结果别只看最终内存报告里写了「在命令行 debug反汇编找到初始程序入口 0017」这一步很多人会跳过直接看最终内存。但排序类实验中间过程比结果更重要。我一般会这样做# 编译链接 masm sort.asm; link sort.obj; # 进入 DEBUG debug sort.exe # 反汇编看入口 -u # 单步执行观察寄存器变化 -t # 查看数据段内存 -d ds:0逻辑说明-u反汇编后找到mov ax, data的地址这就是数据段初始化入口。-t单步执行时每按一次看一次AX、BX、CX和标志位。重点看cmp执行后 CF、ZF、SF、OF 的变化以及jna/jle是否按预期跳转。-d ds:0查看数据段排序前后各看一次对比结果。注意DEBUG 下-t遇到int 21h这类中断调用时可能会跳到系统中断处理程序里别慌按-p直接跳过整个中断调用即可。如果程序跑飞先检查.startup有没有正确初始化 DS这是 16 位汇编最常见的翻车点。3. 8259A 软硬件中断从 78H 到 72H~74H 的完整链路3.1 软件中断 78HASCII 转压缩 BCD 的边界处理实验 2 的软件中断部分要求自定义 78H 号中断把 ASCII 码转成压缩 BCD 码。报告里的代码有个地方值得注意shr ch, 1把 NUMBER 除以 2因为两个 ASCII 字符合成一个 BCD 字节。但代码里mov ax, [si]一次读的是 16 位低 8 位是第一个 ASCII 字符高 8 位是第二个。and al, 0fh取第一个字符的低 4 位shl ah, cl把第二个字符的低 4 位左移 4 位然后or al, ah合并。asc_bcd proc mov ax, dseg mov ds, ax mov si, offset ascaddr mov di, offset bcdaddr mov ch, number shr ch, 1 ; NUMBER/2因为两个 ASCII 合成一个 BCD mov cl, 4 cont: mov ax, [si] ; 读两个 ASCII 字符 and al, 0fh ; 取第一个字符低 4 位 shl ah, cl ; 第二个字符低 4 位左移 4 位 or al, ah ; 合并成压缩 BCD mov [di], al add si, 2 ; 跳过两个 ASCII 字符 inc di dec ch jnz cont iret asc_bcd endp逻辑说明shr ch, 1是核心NUMBER 必须是偶数否则最后一个字符会被丢掉。add si, 2每次跳两个字节因为一个 BCD 字节对应两个 ASCII 字符。iret而不是ret因为这是中断服务程序需要恢复中断前的 FLAGS、CS、IP。参数说明ascaddr db 0123456789是源数据number db 10是长度bcdaddr db 20 dup(?)是目标缓冲区。注意number是 10shr后ch5循环 5 次生成 5 个 BCD 字节。如果number是奇数最后一个 ASCII 字符不会被处理这是代码的边界限制。3.2 硬件中断 72H~74H中断向量安装与 EOI 发送硬件中断部分报告用int 21h的25h功能安装中断向量mov ax, 2572h表示把isradd1的地址写入 72H 号中断向量。然后通过读 8255 的 PA 端口地址 0A1H获取按键按 1、2、3 分别触发 72H、73H、74H 中断。; 安装中断向量 mov ax, seg isradd1 mov ds, ax mov dx, offset isradd1 mov ax, 2572h int 21h ; 中断服务程序结尾发送 EOI isradd1 proc push ds push ax mov ax, seg disp1 mov ds, ax mov dx, offset disp1 mov ah, 9 int 21h mov al, 20h out 0a0h, al ; 发送 EOI 到从片 8259A pop ax pop ds iret isradd1 endp逻辑说明25h功能调用把 DS:DX 指向的地址写入中断向量表对应位置。out 0a0h, al是向从片 8259A 发送 EOIEnd of Interrupt命令告诉它中断处理完毕。如果不发 EOI同级或更低优先级的中断会被屏蔽程序看起来就像「卡死」了。参数说明0a0h是从片 8259A 的偶地址端口20h是 EOI 命令字。主片 8259A 的端口是20h和21h从片是0a0h和0a1h。报告里inal, 0a1h和out 0a1h, al是在操作从片的屏蔽寄存器and al, 11100011b把 IRQ10~IRQ12 对应的位清零允许这三个中断。3.3 中断嵌套与优先级为什么按 1 之后按 2 没反应这是硬件中断实验里最常见的坑。8259A 默认是全嵌套模式IRQ10 优先级高于 IRQ11IRQ11 高于 IRQ12。如果 IRQ10 的中断服务程序还没执行完没发 EOIIRQ11 和 IRQ12 的中断请求会被屏蔽。现象就是按 1 显示正常再按 2 没反应必须等 1 的服务程序跑完。解决办法有两个一是用特殊全嵌套模式Special Fully Nested Mode在 8259A 初始化时设置 ICW4 的 SFNM 位二是在中断服务程序里提前发 EOI但这样会破坏嵌套逻辑。我一般推荐第一种初始化时把 ICW4 设成00010001b而不是默认的00000001b。报告里没写 8259A 的初始化代码因为实验箱通常已经初始化好了但如果你自己搭电路这一步不能省。4. 8255 键盘扫描码读取与显示器笑脸动画的实操细节4.1 键盘中断从端口 60H 读扫描码到 XLAT 换码实验 3 要求直接从 8255 的 PA 端口地址 60H读键盘扫描码用 XLAT 换成 ASCII 显示。报告里的scantab表是关键它把扫描码映射成 ASCII 字符。inal, 60h读扫描码test al, 80h判断是按下还是松开xlat用bx指向表首、al作为索引查表。kbint: push ax push bx push ds push cs pop ds sti mov bx, offset scantab in al, 60h test al, 80h jnz keyend ; 最高位为 1 表示松开不处理 push ax in al, 61h or al, 80h out 61h, al ; 置位 PB7通知键盘已接收 and al, 7fh out 61h, al ; 复位 PB7 pop ax cmp al, 01h jnz disp inc flag ; ESC 键切换标志 disp: test flag, 01h jz user xlat ; 查表换码 cmp al, 0 jz keyend mov ah, 14 mov al, 0dh int 10h mov al, 0ah int 10h mov al, 20h int 10h jmp keyend user: ; 调用系统 INT 09H 处理 ... keyend: mov al, 20h out 20h, al ; 发送 EOI 到主片 8259A pop ds pop bx pop ax iret逻辑说明in al, 61h和out 61h, al是操作 8255 的 PB 端口PB7 置位再复位是告诉键盘控制器「扫描码已读取」。xlat用al作为偏移ds:bx作为基址查scantab表得到 ASCII 码。flag变量控制是否使用用户自定义的中断处理程序按 ESC 切换。参数说明scantab表的前几个字节是0, 0, 1234567890-对应扫描码 0~12。注意扫描码 1 是 ESC表里对应 0所以cmp al, 0时跳过显示。int 10h的ah14是显示字符功能al0dh回车、al0ah换行、al20h空格。4.2 显示器笑脸动画坐标计算与延迟循环实验 4 的笑脸动画核心是int 10h的ah02设置光标位置、ah09显示字符、ah06清屏。报告里的流程图写了「显示笑脸 → 延迟 → 清除 → 改变坐标 → 重复」但代码没贴全。我补一个常见的实现框架; 设置光标位置 mov ah, 02h mov bh, 0 ; 页号 mov dh, row ; 行 mov dl, col ; 列 int 10h ; 显示笑脸字符 mov ah, 09h mov al, 01h ; 笑脸 ASCII mov bh, 0 mov bl, 0eh ; 颜色黄色 mov cx, 1 ; 重复次数 int 10h ; 延迟循环 mov cx, 0ffffh delay: loop delay ; 清除笑脸显示空格 mov ah, 09h mov al, 20h mov bl, 0 int 10h逻辑说明ah02设置光标后ah09在当前光标位置显示字符。bl是颜色属性0eh是黄色。延迟循环用loop指令cx越大延迟越久。清除时显示空格颜色设为 0黑色相当于擦掉。参数说明row和col是行、列坐标范围分别是 0~24 和 0~79。每次循环后改变row或col笑脸就会移动。注意int 10h的ah09不会移动光标所以每次显示前都要重新设置光标位置。4.3 端口读写权限DOSBox 下 in/out 指令的坑在 DOSBox 里跑in/out指令可能会遇到「非法指令」或「端口访问被拒绝」。这是因为 DOSBox 默认不允许直接访问硬件端口。解决办法是在 DOSBox 配置文件里加[cpu]段的corenormal和cputypeauto或者用 DOSBox-X 的allow port access选项。如果还是不行检查实验箱的端口地址是否和代码一致——报告里 8255 的 PA 端口是 60H但不同实验箱可能映射到不同地址这个必须对照硬件手册确认。5. 避坑与排查四个实验里最容易翻车的五件事5.1 现象MASM 编译报「A2006: undefined symbol」原因.model small之前没有.386或.8086伪指令或者段定义顺序不对。报告里的代码用了.startup和.exit这两个伪指令要求.model在前且不能和手写的start:标号混用。解决要么全用简化段定义.model small.startup.exit要么全用手写段定义dseg segmentcseg segmentstart:。报告里实验 1 用简化段实验 2 用手写段两种风格别混。5.2 现象程序跑起来后死机DEBUG 单步正常原因中断服务程序里没发 EOI或者iret写成了ret。iret会恢复 FLAGS、CS、IPret只恢复 IP中断返回后 FLAGS 和 CS 是乱的。解决检查所有中断服务程序的结尾必须是iret。硬件中断还要确认out 20h, al或out 0a0h, al有没有执行。5.3 现象排序结果不对但代码看起来没问题原因cmp后面的跳转指令用错了。无符号排序用了jle有符号排序用了jna结果会完全相反。解决记住口诀——无符号看 CF用ja/jna有符号看 SF 和 OF用jg/jle。拿84H和17H试一下无符号84H 17H有符号84H 17H用 DEBUG 单步看标志位就能确认。5.4 现象键盘中断只响应一次之后没反应原因8255 的 PB7 没有正确置位复位键盘控制器以为上次扫描码还没被读取不再发送新扫描码。解决确认in al, 61h→or al, 80h→out 61h, al→and al, 7fh→out 61h, al这五步都执行了。顺序不能反or和and之间不能插入其他端口操作。5.5 现象笑脸动画闪烁严重或者移动不连贯原因延迟循环太短或者清除和显示之间没有同步。int 10h的ah09是直接写显存如果延迟不够人眼会看到闪烁。解决增大延迟循环的cx值或者在清除和显示之间加int 10h的ah02重新设置光标。如果还是闪考虑用ah06滚动屏幕代替逐个清除。6. 进阶验证用 DEBUG 脚本自动化检查中断向量表跑完四个实验后怎么确认中断向量真的装对了手动-d 0000:01c0看 72H 号中断的地址太慢我一般会写个 DEBUG 脚本批量检查。72H 号中断向量在内存0000:01C8处72H × 4 1C8H74H 在0000:01D0处。# DEBUG 脚本检查 72H~74H 中断向量 debug -d 0000:01c8 l 10 # 输出示例 # 0000:01C0 XX XX XX XX XX XX XX XX-XX XX XX XX XX XX XX XX # 每 4 字节一个中断向量偏移在前段地址在后逻辑说明-d 0000:01c8 l 10从0000:01C8开始显示 16 字节正好覆盖 72H、73H、74H、75H 四个中断向量。每个向量 4 字节前 2 字节是偏移地址后 2 字节是段地址。对照isradd1、isradd2、isradd3的编译地址确认是否一致。参数说明l 10表示显示 16 字节10是十六进制。如果想看更多改成l 20。注意 DEBUG 的-d默认显示 128 字节加l参数可以控制长度。另一个验证技巧在中断服务程序里加一句out 0e0h, al如果实验箱有 LED 端口每次中断触发时 LED 闪一下比看屏幕输出更直观。我当年做 8259A 实验时就是靠一个 LED 确认中断到底有没有进去——屏幕没输出不一定是中断没触发也可能是显示代码写错了。从那以后我每次跑中断实验都强制先在服务程序入口加一个端口输出或者内存写标记确认中断真的进去了再调显示逻辑。这个习惯帮我省了至少一半的调试时间。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑