恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

从冒泡排序到8259A中断:一份可复现的汇编实验全记录

  • 首页
  • 资讯中心
  • /
  • 从冒泡排序到8259A中断:一份可复现的汇编实验全记录

相关资讯

制药数字化工厂落地路线:从MES到电子批记录,打通GMP数据闭环 2026/10/6 23:23:51
万用表实测CC1/CC2引脚,锁定PD快充不握手故障点 2026/10/6 23:23:51
数字孪生智能工厂:MES/ERP与PLC实时闭环集成实践 2026/10/6 23:23:51

最新资讯

回溯法详解:LeetCode 46. 全排列
【Web全栈进阶】PostgreSQL上手:Docker跑库 + 把早报站从SQLite迁过去
AI获客怎样减少重复线索?意客AI的原文复用与版本筛选
装配车间MES落地指南:SimpleMES工单流转、BOM与齐套检查实战
基于sEMG与IMU的手语手势识别:从数据采集到实时部署避坑指南
26年程序员转AI指南:收藏这份学习路线,轻松拥抱大模型时代!

今日推荐

本周热门

MR25H40CDF + PIC18F65K40:工业记录仪高可靠存储实战
基于STM32的数控恒压恒流电源设计:从硬件到PID调参全解析
LT9211 MIPI重定时器原理与双路扇出实战指南

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

从冒泡排序到8259A中断:一份可复现的汇编实验全记录

发布时间:2026/10/6 23:23:51
从冒泡排序到8259A中断:一份可复现的汇编实验全记录 简介这是一份汇编语言与接口技术课程的实验报告PDF面向高校计算机、电子及相关专业学生特别适合正在完成汇编程序设计或中断接口实验的读者。报告整理了两个典型实验实验1使用MASM 6.11开发环境通过MOV、CMP、XCHG、LOOP等指令实现冒泡法排序对一批8位无符号数和8位有符号数分别按升序排列并给出程序流程图、完整源代码和DEBUG调试的运行结果其中还涉及数据段、代码段的定义以及循环嵌套和子程序调用实验2基于8259A可编程中断控制器自定义78H软件中断完成ASCII码到压缩BCD码的转换同时设计IRQ10~IRQ12外部硬件中断服务程序在屏幕上输出“Interrupt service routine n”提示并包含中断向量安装、中断屏蔽字设置、EOI命令发送等细节。对于理解中断向量表设置、8259A初始化、软硬件中断编程技术也有直接帮助。报告包含实验目的、实验要求、程序设计思路、代码清单及结果分析结构完整可直接作为实验报告模板或上机调试参考。压缩包内共1个PDF文件大小约1.03MB已有131人学习下载。1. 这份汇编实验报告值得照着敲一遍从冒泡排序到8259A中断的完整路线学汇编语言的人大多有个共同困境教材把MOV、CMP、LOOP讲得明明白白一到上机就卡在环境装不上、中断向量看不透、程序跑飞了不知道从哪开始查。这份《汇编语言与接口技术实验报告》恰好把这条路走通了——从MASM 6.11环境搭建、冒泡法排序这批8位数据到8259A可编程中断控制器的软硬件中断再到键盘扫描码读取和TSR驻留程序的替换与恢复四个实验由浅入深代码基本完整照着敲一遍就能跑。它的价值不在被扫描的PDF页脚上而在那一行需要反复推敲的CMP/JNA指令选择、一次8259A屏蔽字的设置、一套换掉INT 09H后又优雅恢复的思路。正在上微机原理课、准备实验考试或者刚接触汇编语言想找个能实实在在跑起来的入门例子的读者这份报告比单纯停留在概念层面的教程实用得多。2. 冒泡法排序的两种打开方式MASM 6.11环境与jna/jle的分野2.1 先把MASM 6.11跑起来DOSBox挂载与编译链接实验报告第一个任务落在“安装MASM 6.11”这一步卡住的人远比想象中多。MASM 6.11是16位实模式汇编工具拿到今天64位Windows上直接运行多半报错或者一闪而过。常见做法是装一个DOSBox模拟DOS环境再把MASM工具目录挂载进去。我一般习惯把整个MASM文件夹放到固定路径比如D:\masm611里面至少要有ML.EXE、LINK.EXE和DEBUG.EXE三个文件。mount c: /users/yourname/masm611 c: ml /c sort.asm link sort.objmount命令把DOSBox的虚拟C盘指向MASM目录ml /c只编译不链接生成sort.objlink负责把目标文件链接成sort.exe。注意新版MASM的ml默认可能生成32位PE格式实验里这套代码是16位段如果link报格式错改用ml /AT sort.asm这种简化汇编模式或者直接在命令行加/coff参数调整。DOSBox本身不需要配置内存默认值足够跑这些实验。2.2 摸清数据8个十六进制数在内存里的真实身份实验给的这批数据是61H, 84H, 93H, 0C4H, 17H, 0FFH, 52H, 2AH看起来只是8个字节但“无符号”和“有符号”两种视角下它们的身份完全不同。同一个0FFH无符号看是255有符号看是-1排序结果自然不一样。我先把它列出来。字节十六进制无符号值有符号值161H9797284H132-124393H147-10940C4H196-60517H232360FFH255-1752H828282AH4242无符号排序时0FFH最大最终排在最后有符号排序时0FFH是-184H、93H、0C4H这些带符号的负数全部要排到正数前面。这个对比是实验的核心考点代码里只差一个条件跳转指令结果就差出整个顺序。2.3 无符号冒泡jna的边界条件报告给的冒泡代码是典型的双重循环外层控制轮数内层从首地址开始相邻比较不符合升序就交换。完整程序如下。.model small .data n dw 8 block db 61h,84h,93h,0c4h,17h,0ffh,52h,2ah .stack 60h .code .startup mov ax, data mov ds, ax mov cx, n dec cx loop1: mov dx, cx ; dx保存外层剩余次数 mov bx, 0 ; bx做偏移指针 loop2: mov al, block[bx] cmp al, block[bx1] jna continue ; 无符号不高于则跳 xchg al, block[bx1] mov block[bx], al continue: add bx, 1 loop loop2 mov cx, dx loop loop1 .exit end重点在jna continue这条指令。jna是“jump if not above”看的是CF和ZF标志位含义是“无符号不大于”也就是当前元素下一个元素时不用交换只有当前元素更大时才执行xchg和mov两步完成互换。这里有一个很多人第一次写会犯的错把jna写成jnae或者反过来用ja一旦搞反排序就从升序变降序或者出现部分有序的怪序列。外层mov dx, cx保存本轮剩余次数内层loop loop2把cx减到0再mov cx, dx恢复实现每轮内循环次数递减这是标准冒泡优化。2.4 切到有符号只有一行代码不同第二段程序几乎一模一样唯一的改动是把jna换成jle。jle是“jump if less or equal”基于ZF、SF和OF组合判断适用于带符号数比较。对0FFH这种字节无符号时它比谁都大有符号时它比谁都小比较指令如果不区分这两种视角结果必然翻车。loop2: mov al, block[bx] cmp al, block[bx1] jle continue ; 有符号的小于等于则跳过交换 xchg al, block[bx1] mov block[bx], al continue: add bx, 1 loop loop2有符号升序最终结果是84H, 93H, 0C4H, 0FFH, 17H, 2AH, 52H, 61H。可以从标志位上解释CMP执行减法无符号比较看CF借位有符号比较看OF溢出和SF符号的异或结果。jna只看CF/ZFjle则多看了SF和OF这是两类比较指令最本质的区别也是这份实验报告最值得背下来的一条结论。2.5 DEBUG验证一下排序结果和内存长什么样报告里提到的DEBUG工具很多人以为是老古董实际在实验环境下它比任何IDE都直观。程序编译链接后用DEBUG加载EXE反汇编和查内存都靠几个单字母命令。debug sort1.exe -u 0 20 -d 0 -g -d 0u反汇编查看指令序列先定位程序的入口地址d直接查看数据段内容排序前后各执行一次对比数据区的字节顺序g是运行到断点或结束。报告里记录入口在0017那是.startup伪指令生成的启动代码在不同版本下的偏移不一定每次都一样以自己反汇编结果为准。DEBUG看内存时注意block在数据段偏移0处8个字节连续排在一起排序结果一眼就能确认。3. 中断向量与8259A软件中断78H、硬件中断IRQ10到IRQ12的完整接线3.1 中断向量表软件中断怎么“注册”实验2的软件中断部分核心操作是“自定义一个中断类型码78H的中断服务程序”。中断类型码对应中断向量表实模式下向量表在内存0地址开始每个表项4字节段地址偏移地址。类型码78H的向量位置在78H*4 0x1E0处。往这个位置写入自己的服务程序入口最正规的写法是用DOS功能调用。mov ax, seg asc_bcd mov ds, ax mov dx, offset asc_bcd mov ax, 2578h int 21hAH25H是DOS的“设置中断向量”功能AL78H是中断类型码DS:DX指向新服务程序入口。中断调用前要先保证DS指向asc_bcd所在段所以第一行mov ax, seg asc_bcd取出段地址。完成这三行后再执行int 78h就会跳进asc_bcd过程。这个套路在所有中断实验里通用后面改键盘中断也是同一套机制。3.2 ASCII转压缩BCD的算法拆解服务程序本身做的是把ASCII数字字符串转成压缩BCD。所谓压缩BCD就是一个字节放两个十进制数高4位一个、低4位一个。实验的ASCADDR里存了0到9十个字符NUMBER10转换后应该是5个BCD字节。算法每次从字符串取两个字符放进AX低字节是第一个字符、高字节是第二个字符。asc_bcd proc mov ax, dseg mov ds, ax mov si, offset ascaddr mov di, offset bcdaddr mov ch, number shr ch, 1 mov cl, 4 cont: mov ax, [si] ; AX 两个ASCII字符 and al, 0fh ; 保留低字符低4位 shl ah, cl ; 高字符低4位移到高4位 or al, ah ; 合并成压缩BCD mov [di], al add si, 2 inc di dec ch jnz cont iret asc_bcd endpshr ch, 1把字符个数除以210个字符循环5次shl ah, cl是关键的移位操作CL4把高字节里的数字位推到高4位位置再和低4位合并。例如AX中是10and al, 0fh得到00Hshl ah, 4把31H变10Hor完就是10H正好是数字10的BCD编码。这个算法一次处理两个字符效率不错但有个隐含边界条件留到避坑部分细说。3.3 8259A的套路OCW1写屏蔽字主片从片分开硬件中断部分涉及8259A实验要求IRQ10到IRQ12作为外部中断源对应中断类型号72H到74H。这里有个必须背下来的常识8259A主片端口是20H/21H从片端口是A0H/A1H。IRQ0到IRQ7在主片IRQ8到IRQ15在从片IRQ10到IRQ12具体是从片的IR2、IR3、IR4。要让外部中断触发先要在中断控制器里把对应的屏蔽位打开。OCW1就是中断屏蔽字寄存器位为1表示屏蔽位为0表示允许。从片端口A1H写入11100011B意思是bit2、bit3、bit4清零其他位保持屏蔽。in al, 0a1h and al, 11100011b out 0a1h, alin al, 0a1h读当前屏蔽字and操作保留原来该开的位、只清这三位比直接mov al, 11100011b更安全因为不会覆盖BIOS已经设置好的其他位。主片这边还要确保级联IRQ2没被屏蔽实验报告代码里有in al, 21h; and al, 11111101b; out 21h, al就是把主片IRQ2的屏蔽位清零。漏掉这步从片的中断请求到达不了CPU按键不会有任何反应。3.4 中断服务程序的收尾EOI不能漏中断服务程序执行完后必须向8259A发送EOI中断结束命令否则8259A对应位一直处于服务状态同级别中断再也不会触发。代码里明确的把EOI写到从片端口A0Hmov al, 20h out 0a0h, al如果还需要重新开放主片可以在从片EOI之后向20H端口再发一次。很多人第一次调8259A实验现象是“中断进去了第一次第二次按键完全没反应”十有八九就是EOI没发或者发错端口。这里还有一个小坑实验要求按数字键1到3模拟外部中断源实际代码在键盘读取后根据1、2、3分别执行int 72h、int 73h、int 74h所以EOI也只是针对从片的中断服务主片的EOI在模拟场景下可发可不发但真实硬件接线环境里主片也必须发。4. 键盘扫描码的“截胡”从60H端口读码到INT 09H替换与TSR驻留4.1 键盘数据的原始来源60H端口和扫描码实验3的标题是“键盘接口实验”实际做的是把系统键盘中断INT 09H换成自己写的服务程序直接从硬件端口读扫描码。键盘控制器8255的PA端口地址是60H每按下一个键60H端口就产生一个扫描码松开时产生断码断码通常是通码的0x80倍。比如按下A键扫描码是1EH松开是9EH。实验程序在kbint里第一步就是in al, 60h然后立刻test al, 80h; jnz keyend用最高位判断是不是断码。断码直接丢弃只有通码才进入后面的扫描码转ASCII流程。这个判断如果漏掉一次按键会被当成两次键事件处理屏幕上可能打出重字。4.2 XLAT换码表扫描码到ASCII的映射扫描码本身不是ASCII转成ASCII最常用的手段是XLAT指令。XLAT的作用是AL DS:BXAL把一个字节当表偏移取表里对应的字节。实验代码里定义了一张scantabscantab db 0,0,1234567890-,08h,0 db QWERTYUIOP[],0dh,0 db ASDFGHJKL;,0,0,0,0 db ZXCVBNM,./,0,0,0,20h db 13 dup(0) db 789-4561230#表按键盘扫描码顺序排列扫描码2对应数字键1在表里第3个位置扫描码16对应Q键扫描码57对应空格。XLAT执行后AL变成对应的ASCII字符。报告里特意安排了一段“输入小写字母显示大写”的效果根源就在这张表表里放的全是大写字母ASCII不管Shift状态如何按键直接输出大写。kbint proc push ax push bx push ds push cs pop ds ; DS指向代码段 sti mov bx, offset scantab in al, 60h ; 读扫描码 test al, 80h jnz keyend ; 断码退出 ... xlat ; AL DS:BXAL ... keyend: mov al, 20h out 20h, al ; 发EOI pop ds pop bx pop ax iret kbint endppush cs; pop ds把数据段寄存器临时指向代码段这样scantab才能被XLAT访问。mov al, 20h; out 20h, al是发给主片8259A的EOI键盘中断IRQ1在主片这个必须发不然整个键盘系统会冻结。4.3 偷换INT 09H取旧向量、装新向量、改8259屏蔽替换INT 09H不是直接往向量表写地址而是用DOS功能调用保存和设置。先AH35H取出旧向量放到ES:BX再AH25H把新向量装进去。mov ax, 3509h int 21h mov word ptr oldint, bx mov word ptr oldint2, es mov dx, offset kbint mov ax, 2509h int 21holdint是个4字节变量保存旧的段地址和偏移地址。这一步的目的很明确程序退出时要把原中断恢复回来或者按下ESC键要临时切回系统键盘处理。装完新向量后还要改8259A的IMR寄存器确保IRQ1没被屏蔽。正常系统里IRQ1本来就没屏蔽但稳妥起见还是做一次in al, 21h and al, 11111101b out 21h, al11111101B是只清bit1其他位不动。这里如果直接用mov al, 11111101B覆盖会把其他中断的屏蔽状态全部打乱。4.4 TSR驻留与ESC切换把这个程序留在内存里实验程序用int 27h驻留退出这是DOS时代标准的TSR做法。驻留的意思是程序结束但代码和数据都留在内存里中断向量继续指向它。ESC键的切换逻辑是自己的中断服务程序里判断扫描码是01HESC键时翻转flagflag0时走jmp cs:oldint把控制权还给系统原来的INT 09H处理程序。install: cli push cs pop ds mov ax, 3509h int 21h cmp bx, offset kbint jnz load int 20h ; 已安装则直接退出 load: mov word ptr oldint, bx mov word ptr oldint2, es mov dx, offset kbint mov ax, 2509h int 21h ... mov dx, offset install int 27h ; TSR驻留退出cmp bx, offset kbint; jnz load判断当前向量是不是已经指向自己的处理程序这是防止重复安装的经典防护。mov dx, offset install; int 27h意思是驻留到install标签为止中断服务程序本身在install之前所以不会被释放。读oldint里的段值和偏移用jmp跳过去执行能保证两个中断服务程序之间安全切换。4.5 替换中断的正确姿势键盘控制器端口61H处理不能少实验代码里有一段看起来无关的指令是键盘处理绕不开的“握手”步骤push ax in al, 61h or al, 80h out 61h, al and al, 7fh out 61h, al pop ax端口61H是8255的PB端口bit7控制键盘的允许/禁止信号。or al, 80h把bit7拉高、and al, 7fh再拉低产生一个负脉冲通知键盘控制器“扫描码已被读取可以发下一个”。很多从零开始写键盘中断的人漏掉这段之后发现按键第一次有效第二次就无响应或者键盘灯都乱了。原因就是键盘控制器没收到清除信号一直认为上一帧数据还没取走。这个细节在教科书里往往只有一句“读取后需发送应答信号”报告里这段代码是完整的值得照抄。5. 避坑实验报告里那些疑似笔误和调试中常见的五个问题5.1 有符号排序结果不对jna和jle选错现象同一批数据两段程序跑出来的结果完全一样或者20H以下的负数全排到了最后面。原因jna和jle没区分。无符号排序用jna看的是CF和ZF有符号排序必须用jle看的是SF、OF、ZF联合结果。0FFH无符号是255、有符号是-1用错指令它在数组里的位置天差地别。解决确认实验要求是“有符号”还是“无符号”有符号一律查jle/jge系列无符号用jna/jb系列。如果不确定用DEBUG在排序后d 0看内存无符号结果里FFH一定在末尾有符号结果里84H会出现在最前面。5.2 压缩BCD转换漏掉最后一个字符现象源字符串长度是奇数比如NUMBER9转换完发现第一个字符被吞掉或者最后一位丢失。原因shr ch, 1把9除以2得到4循环4次只处理了8个字符最后一位永远没机会进转换流程。报告里NUMBER是10碰巧偶数所以代码没暴露这个问题。常见的临时方案是循环结束后单独判断原长度低位为1则补一个高4位为0的BCD字节。解决先把字符串长度复制一份做奇偶判断。奇数时最后一个字节单独处理只取低4位存入高4位补0或者干脆把源字符串前面补一个0让长度变偶数转换结果高位多一个0再另做修正。我一般用第二种代码改动最少。5.3 硬件中断触发不了8259A屏蔽字和EOI两个方向查现象程序运行后按数字键1、2、3屏幕上没有任何“Interrupt service routine n is running...”输出。原因两种可能。一种是从片OCW1没写对IRQ10对应从片bit2屏蔽字11100011B写成了11101111B之类把要用的位屏蔽了另一种是服务程序里EOI只发主片out 20h, al没发从片out 0a0h, al从片状态一直没清第二次中断进不来。解决先查out 0a1h的屏蔽字再查中断服务程序末尾有没有out 0a0h, al。EOI一般先发从片后发主片两个都发最稳。还有一点被忽略的是主片IRQ2级联位out 21h时and al, 11111101b这步漏了从片请求根本到不了CPU。5.4 TSR退出后系统键盘失灵现象程序驻留退出后按ESC切回系统键盘输入字母变成大写或者完全没反应。原因ESC切换逻辑走的是jmp cs:oldint但如果oldint保存的向量本身已经被破坏或者在恢复前程序又跑了一遍install导致重复安装中断向量会自己指向自己形成死循环。解决安装前判断cmp bx, offset kbint已经装过就直接退出恢复时用mov dx, word ptr oldint; mov ax, 2509h重新写回向量表。ESC切换后不要立刻int 20h退出驻留先观察键盘响应是否恢复恢复了再退出。5.5 键盘显示乱码scantab表和实际按键错位现象按下A键显示的不是A而是别的字符按下数字键显示字母。原因scantab表项和扫描码没对齐。XLAT把扫描码直接当表偏移表里第0项对应扫描码0、第1项对应ESC键。如果表开头少写了一个0占位整个表往后错一位所有输出都错位。报告里表开头是0,0,1234567890-第一个0对应扫描码0第二个0对应ESC键从第三个字节开始才是数字键1。解决把表第一行对照键盘扫描码表一行行检查特别是08h退格、0dh回车这类控制字符位置。调试时按顺序按一排键比如依次按1、2、3、4看输出是否依次是1 2 3 4从哪个位置开始错就重点查它前面那个表的项。6. 让实验结果“看得见”DEBUG单步、内存查看与移动笑脸的定时器改造实验4的“移动笑脸”报告只有流程图没有代码正好适合自己动手补全。最简单的实现是死循环里“显示、延迟、清除、改坐标”四步用INT 10H的02H功能定位光标09H功能在当前光标写字符延迟用纯loop嵌套空转之后再定位到原位置写空格清掉笑脸。这个流程能跑但有个明显缺陷循环期间按键盘没反应整个程序占死CPU。常见的改造方案是挂到INT 1CH上——这是ROM BIOS每秒触发约18.2次的定时器中断把笑脸的坐标更新逻辑放到中断服务程序里主程序就可以空出来做别的。clock proc far push ax push bx push dx push ds push cs pop ds mov dl, col mov dh, row mov ah, 02h int 10h ; 定位到当前笑脸坐标 mov al, 01h mov bh, 0 mov cx, 1 mov ah, 09h int 10h ; 显示笑脸 inc col cmp col, 79 jb done mov col, 0 done: pop ds pop dx pop bx pop ax iret clock endpINT 1CH的中断服务程序必须用iret结尾不能带EOI——它本身挂靠在INT 08H后面EOI由INT 08H处理这里写EOI反而会重复发。坐标变量col每次中断加1到屏幕边缘回0实现从左往右循环移动。如果想上下移动再维护一个row变量控制方向。把这套代码编译后驻留再配合实验3的键盘TSR一起运行就能看到键盘切中断的同时笑脸还在后台跑——两个实验变成一个小作品。从那以后我每次做汇编实验都强制自己走一遍这三步先看数据段的内存布局再单步走一遍核心循环最后把实验结果用DEBUG dump出来留档。遇到中断类实验先确认向量装没装对、EOI发没发对再谈功能逻辑这套顺序帮我少踩了很多坑。这份报告里四个实验都值得亲手跑一遍尤其是冒泡排序里jna换jle那一行和8259A的屏蔽字设置自己敲过一遍比背一百条考点都牢。希望这份整理能帮你把实验做得更顺下载下来照着复现一遍收获会远超预期。本文还有配套的精品资源点击获取

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号