news 2026/9/17 19:44:14

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
微机原理与汇编语言习题实战: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 和比例变址[EBX+ESI*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.OBJ+IO.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 位,产生进位时 CF=1 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 是 CF,OV/NV 是 OF,ZR/NZ 是 ZF,PL/NG 是 SF,DN/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], 12H
initializer magnitude too large汇编立即数或数据定义超出 16 位拆成两条或改用 DW/DD 定义
unresolved external链接调用了外部过程但没链接对应 .OBJ/.LIB在 LINK 行补上+IO.LIB之类
运行后一闪而过运行忘了 4CH 号功能结束程序补上MOV AH,4CHINT 21H

2.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, [BX+10H](BX) + 10H
基址变址MOV AX, [BX+SI](BX) + (SI)
相对基址变址MOV AX, [BX+SI+10H](BX) + (SI) + 10H

拿一道典型题演算:已知 DS=1000H、BX=0200H、SI=0030H,求MOV AX,[BX+SI+10H]的物理地址。EA = 0200H + 0030H + 10H = 0240H,物理地址 = 1000H × 16 + 0240H = 10240H。默认段寄存器的规则也要记住,BXSIDI加位移默认走 DS,BPSP默认走 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 start

CMP做的是减法,但不把结果写回操作数,只影响标志位,所以后面紧跟条件转移指令。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, [si+bx] ; 取一个字累加 add bx, 2 ; 字数组,偏移每次加 2 而不是 1 loop next pop bx ; 恢复现场 ret SUM16 ENDP

[SI+BX]是相对基址变址寻址,SI 是基地址、BX 是变化的偏移,这样写比每次INC SI两次更直观。pushpop必须配对,中间任何一条提前返回的指令都会让堆栈失衡,这是子程序题最常被扣分的地方。如果题目要求返回 32 位和,累加时还要把进位一起累加到高位寄存器里,光用ADD AX,[SI+BX]会丢进位。

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 start

09H号功能靠$判断字符串结束,忘了结尾符会把后面的数据一起打到屏幕上,这是运行结果异常时第一个要检查的地方。0AH号功能的缓冲区格式更绕:第一字节由程序填写最大允许长度,第二字节由 DOS 填写实际读入长度,真正的字符从第三个字节开始存放,习题里经常拿这个位置关系出填空。

4. 接口技术习题:8255、8253、8259 的控制字怎么推

4.1 端口地址译码:从地址线到片选信号

接口部分的题几乎都要先算端口地址,算错了后面的控制字全白搭。方法固定:先看片选信号由哪些地址线决定,写出让片选有效的二进制组合,得到基址,再把 A1、A0 的四种组合接到基址上得到四个端口。假设某片 8255 的 CS 接在译码电路上,A7 到 A2 为010000时片选有效,A1、A0 直接连芯片,则四个端口如下。

片内端口A1 A0端口地址
A 口0 040H
B 口0 141H
C 口1 042H
控制口1 143H

推导的关键在于确认哪些地址线参与了译码。如果只有 A7 到 A2 参与,那么 A15 到 A8 取任何值都会选中同一片芯片,同样四个端口会对应一大片地址,这就是部分译码带来的地址重叠。习题里问"该芯片共占用多少个地址单元",答的往往是重叠后的总数而不是 4 个。全译码则要求地址线一根不落地接进译码电路,重叠区只剩片内的 4 个单元。不同教材画的译码图不一样,基址必须按题图算,背下来的基址换一张图就错。

4.2 8255 方式控制字:用位表反推

8255 的方式控制字有固定的位定义,最高位 D7 固定为 1,表示这是一个方式设置字而不是 C 口的位操作字。

含义
D7标志位,方式设置字固定为 1
D6 D5A 组方式,00 为方式 0
D4A 口方向,1 输入、0 输出
D3C 口高 4 位方向,1 输入、0 输出
D2B 组方式,0 为方式 0
D1B 口方向,1 输入、0 输出
D0C 口低 4 位方向,1 输入、0 输出

一道典型题:A 口方式 0 输出、B 口方式 0 输入、C 口高 4 位输出、低 4 位输入。按上表逐位填,D7=1、D6D5=00、D4=0、D3=0、D2=0、D1=1、D0=1,合成10000011B,也就是 83H。

; 8255 初始化:A口方式0输出,B口方式0输入,C口高4位输出、低4位输入 MOV DX, 43H ; 控制口地址,来自 4.1 的译码结果 MOV AL, 10000011B ; 83H,直接写二进制比写十六进制更容易核对 OUT DX, AL ; 方式控制字必须在读写数据之前先写

对 C 口做位操作时要用另一套字:D7 必须为 0,D3 到 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 为通道 000
D5 D4读写方式,11 为先低字节后高字节11
D3 D2 D1工作方式,011 为方式 3011
D0计数进制,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 ; ICW4:8086/8088 模式,非自动 EOI OUT DX, AL MOV AL, 0FEH ; OCW1:只开放 IR0,其余屏蔽 OUT DX, AL

ICW1的 13H 拆开看是:D7=1 表示这是 ICW1,D3=1 表示需要 ICW4,D0=1 表示需要初始化。ICW2的高 5 位就是中断类型号基址,低 3 位由 8259 按引脚号自动填。中断服务程序里必须发一次 EOI,否则同级及更低级的中断不会再被响应,写法是MOV AL,20HOUT 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,屏幕上显示 OV(OF=1)和 NG(SF=1),而 CY 保持为 NC。这正是"有符号溢出但无符号不进位"的经典组合:7FH 加 01H 对无符号数来说是 127 加 1,没超过 255,所以 CF=0;对 8 位有符号数来说超过了 +127 的上限,所以 OF=1。手推标志位时把这两个概念混在一起,是这个题型最集中的失分点。

5.3 错题定位的固定顺序

发现自己算的答案和参考值对不上时,按一个固定顺序排查比乱翻书快得多。先看操作数宽度,再看标志位的种类,最后看端口读写的顺序。

症状先查什么常见结论
结果差 256 倍操作数宽度字节与字混用,或高低字节顺序颠倒
符号判断和答案相反CF 与 OF 混淆无符号看 CF,有符号看 OF
输出频率差 65536 倍计数初值上限65536 应写成 0000H
中断不响应向量表首址与 EOIn×4 定位错,或服务程序里没发 EOI
端口读数始终不变控制字是否先写8255/8253 必须先写控制字再读写数据

下次再遇到 8253 的题,先把控制字 36H 和两条 OUT 的先后顺序写下来,再回头算计数初值,顺序反了必错。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/17 19:42:52

CentOS 7 NIS集中账号管理指南:服务端配置与客户端绑定实战

公司服务器从几十台涨到几百台的时候&#xff0c;你会发现最痛苦的不是装系统&#xff0c;而是每台机器都要手动加一遍用户。今天说 CentOS 7 上配置 NIS 的详细过程。NIS 全称 Network Information Service&#xff0c;是早年 Sun 搞出来的集中账号管理方案&#xff0c;虽然比…

作者头像 李华
网站建设 2026/9/17 19:42:36

agent-skills设计实战:打造稳定可靠的智能体技能库

这些年做大模型应用&#xff0c;我越来越觉得“agent-skills”这个说法比“prompt engineering”更贴近真实战场。模型本身的能力边界其实很清晰&#xff0c;真正让一个智能体从“能聊天”变成“能干活”的&#xff0c;是它手里到底攒了多少个设计扎实、边界清楚、可复用、可观…

作者头像 李华
网站建设 2026/9/17 19:39:49

元器件可靠性降额准则一览:从应力模型到选型校验实践

简介&#xff1a;元器件可靠性降额准则一览表面向电子设计与可靠性工程师&#xff0c;聚焦新能源、汽车电子、检测技术等领域&#xff0c;解决元器件可靠性设计与降额选型中的实际问题。文档系统梳理降额&#xff08;derating&#xff09;、额定值、应力比等基本概念&#xff0…

作者头像 李华
网站建设 2026/9/17 19:38:33

C#脚本引擎选型指南:Flee与AScript对比及工控热更新实践

前年冬天在热处理车间调一套上位机&#xff0c;工艺参数表三天一小改、五天一改&#xff0c;每次改完都要重新编译发布&#xff0c;现场停线等我们装包&#xff0c;那滋味真不好受。也就是从那时候起&#xff0c;我开始认真琢磨C# 脚本引擎这件事——让公式、规则、判定逻辑从硬…

作者头像 李华