微型计算机原理入门:从进制转换到CPU寻址的底层逻辑

发布时间:2026/11/2 22:35:04
微型计算机原理入门:从进制转换到CPU寻址的底层逻辑

简介:本资源是《微型计算机原理与接口技术》(尹建华编著)配套习题的完整参考答案,面向高校计算机、电子、自动化等专业本科生及考研复习者,解决课后习题无标准解析、核心概念理解困难、数制转换与汇编指令实践薄弱等典型学习痛点。资源为单文件PDF,大小仅23KB,内容覆盖全书六章重点:第一章聚焦二进制/十六进制/BCD码转换、原反补码计算与溢出判断;第二章详解8086存储器组织与总线周期(含等待/空闲周期);第三章系统梳理寄存器寻址、相对基址变址等八类寻址方式辨析;第四至六章深入MOV/XOR/SAL等指令应用、排序程序设计、存储器译码扩展及I/O端口编程。已有673人学习下载,答案步骤清晰、推导严谨,含大量手写风格演算过程与易错点标注,可直接用于作业核对、考前冲刺与原理-代码联动理解。

1. 这不是“背公式”的数学课,而是让你看懂电脑怎么“听懂人话”的第一把钥匙

你有没有好奇过:键盘按下一个“1”,屏幕为什么就跳出个“1”?鼠标点一下,程序怎么就知道该放大还是保存?这些动作背后,没有魔法,只有一套被设计得极其精密、又必须被人类“翻译”出来的底层语言——微型计算机原理与接口技术。它不是教你怎么用电脑,而是带你掀开机箱盖子,看清CPU怎么数数、内存怎么记地址、外设怎么“敲门”才能被CPU听见。尹建华老师这本教材,就像一位不说话但手把手带你搭积木的老师:第一章教你把十进制数字“翻译”成电脑能存的二进制(比如156D = 10011100B),第二章告诉你CPU复位后第一眼看到的地址是0FFFF0H,第三章开始让你亲手写MOV AX, 0让寄存器清零……这份《习题答案.pdf》,就是你搭完第一块积木后,立刻能对照着检查“我拧对螺丝了吗?”的那张校准图。它专为零基础新手准备——不需要你先会汇编,不需要你拆过主板,只要你愿意从“156D = 10011100B”这个等式开始,亲手把抽象符号变成可验证的动作。如果你曾对着“原码/反码/补码”发懵,或在“段基址:偏移地址=物理地址”这行字前卡住超过三分钟,这份答案就是为你写的“后悔药”:它不讲大道理,只告诉你每一步算什么、为什么这么算、错在哪一行。

2. 先搞懂一个概念:所有计算,本质都是“数数”和“找位置”

微型计算机再复杂,干的也就两件事:存数和找数。而“数”怎么存、“位置”怎么找,全靠一套统一的规则。这份习题答案的第一章,就是帮你把这套规则从“天书”变成“家常话”。

2.1 进制转换不是考试陷阱,是电脑的“母语发音表”

电脑只认识0和1,但它得跟人类打交道。人类习惯十进制(逢十进一),电脑就得学会“翻译”。答案里出现的156D = 10011100B = 9CH,就是最典型的三语对照:

  • 156D:D代表Decimal(十进制),这是你日常用的数字;
  • 10011100B:B代表Binary(二进制),这是CPU真正存储和运算的形式;
  • 9CH:H代表Hexadecimal(十六进制),这是人类给二进制起的“昵称”——因为每4位二进制刚好对应1位十六进制(0000→0, 1111→F),写起来比一长串01短得多,也更不容易看错。

提示:别死记硬背换算口诀。记住一个核心:除2取余法。比如把156转二进制:
156 ÷ 2 = 78 余 0(最低位)
78 ÷ 2 = 39 余 0
39 ÷ 2 = 19 余 1
19 ÷ 2 = 9 余 1
9 ÷ 2 = 4 余 1
4 ÷ 2 = 2 余 0
2 ÷ 2 = 1 余 0
1 ÷ 2 = 0 余 1(最高位)
把余数从下往上写:10011100B。这就是答案里那个等式的来路。

2.2 带小数的转换:重点在“乘2取整”,不是“除2取余”

整数部分用“除2取余”,小数部分恰恰相反:乘2取整。看答案里的0.675D = 0.1011B:
0.675 × 2 = 1.35 → 取整数部分1(小数点后第一位)
0.35 × 2 = 0.7 → 取整数部分0(第二位)
0.7 × 2 = 1.4 → 取整数部分1(第三位)
0.4 × 2 = 0.8 → 取整数部分0(第四位)
0.8 × 2 = 1.6 → 取整数部分1(第五位,但答案只写了4位,说明四舍五入或截断)
所以是0.1010...B,答案写0.1011B,是因为继续算下去:0.6×2=1.2→1,0.2×2=0.4→0,0.4×2=0.8→0,0.8×2=1.6→1… 实际上0.675的二进制是无限循环小数0.1010110011001100...,0.1011B是四舍五入到4位的结果(0.1011B = 0.6875D,比0.675D略大)。这解释了为什么答案里写的是0.1011B而不是更长的串——它告诉你:精度是可控的,也是有代价的。

2.3 为什么需要原码、反码、补码?——解决“负数怎么存”的千年难题

电脑的寄存器只有0和1,没有“-”号。怎么表示-1?最直觉的想法是:最高位当符号位,0正1负,剩下位存绝对值。这就是原码(如-1的8位原码是10000001B)。但问题来了:1 + (-1)应该等于0,可00000001B + 10000001B = 10000010B,这结果是-2,不是0!
于是有了反码:正数同原码;负数是符号位不变,其余位取反。-1的反码是11111110B。再算1 + (-1):00000001B + 11111110B = 11111111B,这结果是-0(反码里有+0和-0),还是不对。
最后是补码:正数同原码;负数是反码加1。-1的补码是11111111B。00000001B + 11111111B = 00000000B(最高位溢出丢弃),完美等于0!
答案里-128的补码是10000000B,这就是8位补码能表示的最小数(-128 ~ +127)。它之所以能多表示一个负数,正是因为补码把10000000B这个“原码/反码无法合理解释”的编码,明确赋予了-128的含义。补码不是数学发明,是硬件工程师为让加法电路能同时处理正负数而做的最优妥协。

2.4 地址怎么算?段基址和偏移地址,就是“楼号+房间号”

CPU要读内存里的一个字节,得知道它的“门牌号”。但8086 CPU的地址总线是20位,能寻址1MB空间(00000H ~ FFFFFH),而它的寄存器只有16位,存不下20位地址。怎么办?分两半存:段基址(16位)和偏移地址(16位)。
物理地址 = 段基址 × 16 + 偏移地址 = 段基址左移4位 + 偏移地址。
答案第二章第6题:1230H : 0045H的物理地址 =1230H << 4 + 0045H = 12300H + 0045H = 12345H。
1000H : 2345H=10000H + 2345H = 12345H。
看!两个完全不同的“段:偏移”组合,算出来是同一个物理地址12345H。这就像“中关村大厦3层305室”和“海淀区知春路100号3层305室”,地址不同,但指向同一个房间。段地址不是固定不变的,它是CPU为了管理大内存而设计的灵活“分区”机制。

2.5 避坑:进制与编码的5个新手高频翻车点

新手在做第一章习题时,最容易在以下5个地方栽跟头,每一条都来自真实血泪经验:

  1. 现象:把79D算成1001111B,但答案写1001111B(少了一个1)?
    原因:漏掉了最高位。79 ÷ 2 = 39余1,39÷2=19余1,19÷2=9余1,9÷2=4余1,4÷2=2余0,2÷2=1余0,1÷2=0余1 → 从下往上是1001111B(7位),但8位寄存器里要补前导零,写成01001111B。答案里4FH是十六进制,4F转二进制是01001111B,和01001111B一致。关键:答案给的是标准形式,不是最简形式;寄存器宽度决定了位数。

  2. 现象:0.675D = 0.1011B,但自己算出来是0.1010B,纠结哪个对?
    原因:二进制小数转换存在精度损失。0.1011B = 0.6875D,0.1010B = 0.625D,而0.675D介于两者之间。答案选0.1011B是四舍五入(0.675离0.6875更近)。关键:小数转换永远有误差,题目要求几位,就取几位,不必追求绝对精确。

  3. 现象:-128的原码写成10000000B,但答案写1000000010000000B(16位)?
    原因:题目没说位宽!答案里-128出现在8位补码讨论中(8位补码范围-128~+127),所以-128的8位补码是10000000B。但后面-128的原码写成1000000010000000B,这是16位原码(符号位+15位绝对值)。关键:原/反/补码的位数必须和题目上下文一致;同一题里可能混用不同位宽,要看清题干。

  4. 现象:37.164D转二进制,小数部分算到0.0011B就停了,但答案写0.0011B,怀疑自己漏了?
    原因:0.164D转二进制:0.164×2=0.328→0,0.328×2=0.656→0,0.656×2=1.312→1,0.312×2=0.624→0,0.624×2=1.248→1… 所以是0.00101...B。答案0.0011B是四舍五入到4位(0.0011B=0.1875D,比0.164D略大)。关键:带小数的转换,答案给的通常是四舍五入后的近似值,不是无限展开。

  5. 现象:151作为无符号数,答案写151;作为符号数,写-105?
    原因:这是8位数的歧义!151的二进制是10010111B。如果当无符号数,就是151;如果当有符号数(补码),最高位1表示负数,其绝对值是01101001B(取反加1)= 105,所以是-105。关键:“151”本身只是个十进制数,它在计算机里存成什么,取决于你把它当无符号还是有符号来解读。

3. 别急着写代码,先学会“指挥CPU”:指令与寻址方式的实战逻辑

第三章的答案,表面是判断MOV AX, [BX+SI]是什么寻址方式,实则是教你如何向CPU下达一条清晰、无歧义的指令。就像指挥一个只懂简单动词的机器人:“去(取地址)→ 拿(读数据)→ 放(存到AX)”。理解这个过程,比死记“基址变址寻址”这个词重要一百倍。

3.1 寻址方式的本质:CPU找数据的“导航地图”

CPU执行MOV AX, [BX+SI]时,脑子里在跑一个极简脚本:

  1. 看操作数:[BX+SI]——方括号表示“我要的是这个地址里的内容”,不是BX或SI本身的值;
  2. 算地址:BX寄存器里存着一个数(比如1234H),SI里存着另一个数(比如0010H),把它们加起来:1234H + 0010H = 1244H;
  3. 去取数:拿着1244H这个地址,到内存里找到那个位置,把里面2个字节(一个字)的数据读出来;
  4. 放目标:把读到的数据,放进AX寄存器。

这就是基址变址寻址。BX是“基址”(像大楼的楼号),SI是“变址”(像楼层里的房间号),加起来才是完整门牌。答案里第1题⑶的相对基址变址寻址,就是在BX+SI基础上再加一个常数(比如[BX+SI+10H]),相当于“楼号+房间号+门牌号”。所有寻址方式,都是在回答一个问题:CPU,你到底要去哪拿这个数?

3.2 为什么MOV AX, 0和XOR AX, AX都能清零?——理解指令的“副作用”

第三章第6题答案给了两种清零方法:

⑴ MOV AX, 0 ⑵ XOR AX, AX

MOV AX, 0直白:把0搬进AX。
XOR AX, AX玄学:AX和自己异或。异或规则:0^0=0,1^1=0, 所以任何数和自己异或都等于0。XOR AX, AX执行后,AX一定为0。
但为什么老程序员偏爱XOR?因为它不改变标志位中的CF(进位标志)和OF(溢出标志),而MOV不碰任何标志位。更重要的是,XOR AX, AX通常比MOV AX, 0生成的机器码更短(2字节 vs 3字节),执行更快。这不是炫技,是在资源(内存、速度)极度受限的底层世界里,一种精打细算的生存智慧。

3.3 看懂一段排序代码:从CMP到XCHG的完整控制流

第四章第5题答案是一个冒泡排序片段,它完美展示了指令如何协同工作:

MOV AL, [SI] ; 把第一个数放进AL INC SI ; SI指针移到第二个数 MOV BL, [SI] ; 把第二个数放进BL INC SI ; SI指针移到第三个数 MOV CL, [SI] ; 把第三个数放进CL CMP AL, BL ; 比较AL和BL(第一个和第二个) JB L1 ; 如果AL < BL,跳到L1(不用交换) XCHG AL, BL ; 否则,交换AL和BL(让小的在前) L1: CMP AL, CL ; 再比较AL(现在是前两个中较小的)和CL(第三个) JB L2 ; 如果AL < CL,跳L2 XCHG AL, CL ; 否则交换,AL现在是三个数中最小的 L2: CMP BL, CL ; 最后比较BL和CL(剩下两个) JB L3 ; 如果BL < CL,跳L3 XCHG BL, CL ; 否则交换,BL和CL就有序了 L3: MOV DI, OFFSET RESULT ; 把结果存到RESULT地址 MOV [DI], AL ; 存最小的 INC DI MOV [DI], BL ; 存中间的 INC DI MOV [DI], CL ; 存最大的

这段代码没用循环,是手动展开的3个数排序。关键在CMP(比较)和条件跳转JB(Jump if Below,即无符号小于)。CMP AL, BL实际是做AL - BL,但不保存结果,只设置标志位(比如ZF零标志、CF进位标志)。JB就去看CF:如果AL < BL(无符号),减法会产生借位,CF=1,就跳;否则CF=0,不跳,执行后面的XCHG。CPU的“智能”,就藏在这些标志位和跳转指令的配合里——它不思考,只机械地响应信号。

3.4 避坑:指令与寻址的5个致命误解

刚接触汇编的新手,常因对指令行为理解偏差而写出“看似正确、实则崩溃”的代码:

  1. 现象:MOV [SI], AX报错“operand must have size”,或者运行出错。
    原因:[SI]只是一个地址,CPU不知道你要存1个字节(byte)还是1个字(word)。AX是16位寄存器,必须明确告诉CPU“我要存一个字”。正确写法是MOV WORD PTR [SI], AX(WORD PTR是“字类型指针”)。关键:内存操作数必须显式声明大小,寄存器操作数则由寄存器名隐含(AX=word, AL=byte)。

  2. 现象:ADD AX, [BX]执行后,AX的值和预期不符,查了半天发现BX里是0000H,但[BX]地址里存的是乱码。
    原因:BX只是个地址寄存器,它指向的内存位置[BX],必须是你之前用MOV或其他指令写入过有效数据的地方。如果BX=0,[0]是中断向量表起始,乱改会死机。关键:所有内存访问,前提是你“拥有”并“初始化”了那块内存;不要假设某个地址天然就有安全数据。

  3. 现象:JZ ZERO(Jump if Zero)没跳,但CMP AL, 0后AL确实是0。
    原因:CMP设置标志位,但中间插入了其他会改标志位的指令,比如MOV BL, AL不会改标志,但ADD BL, 1会!JZ只看上一条影响标志位的指令(这里是ADD)的结果。关键:条件跳转只依赖最近一次影响标志位的指令;CMP之后不能插任何“污染”标志位的指令。

  4. 现象:SAL AX, CL(算术左移)想乘以4,CL=2,但结果错了。
    原因:SAL是“算术左移”,对有符号数安全;但若AX里存的是无符号大数(如8000H),左移2位变成0000H(高位溢出丢弃),这没问题。但如果误用了SHL(逻辑左移),效果一样;但若用ROL(循环左移),8000H左移2位变成0002H,就完全错了。关键:移位指令有5种(SAL/SHL, SAR/SHR, ROL/ROR),名字差一个字母,行为天壤之别;必须根据数据是有符号/无符号、是否允许溢出,严格选择。

  5. 现象:IN AL, DX从端口读数据,但AL总是0,或程序卡死。
    原因:IN指令需要外设(如键盘控制器)准备好数据,并通过READY信号通知CPU。如果外设没响应,IN会一直等(死循环)。答案第四章第4题的WAIT循环,就是先IN AL, DX读状态端口,TEST AL, 80H检查第7位(80H=10000000B),如果为1才表示数据就绪,再执行真正的IN。关键:I/O操作不是内存操作,必须遵循外设的“握手协议”;没有等待循环的IN/OUT,大概率失败。

4. 让电脑“认出”你的硬件:存储器与I/O接口的地址规划术

第五章开始,你正式踏入“硬件世界”。这里没有虚拟内存,只有真实的芯片引脚和地址线。答案里那些6116芯片4片、2716芯片4片的计算,不是考数学,而是在教你如何给每个硬件芯片分配一个独一无二的“身份证号”(地址),让CPU叫谁,谁就应声。

4.1 存储器扩展:为什么需要“译码”?——CPU的地址太宽,芯片的地址太窄

一个6116芯片是2K×8位(2048个字节)的RAM。它的地址线只有11根(A0-A10),只能寻址2048个位置。但8086 CPU的地址总线是20位,能管1M空间。怎么让CPU的20位地址,精准地“命中”这2048个位置,而不误伤隔壁的芯片?靠地址译码器。
答案第五章第8题解释了两种译码法:

  • 全译码:把CPU除了A0-A10(片内地址)之外的所有高位地址线(A11-A19,共9根),全部接到译码器输入端。译码器输出一个唯一的片选信号(CS),只在特定地址范围内有效。比如,给第一组6116分配00000H~007FFH,那么只有当A19-A11全是0时,CS才有效。优点:地址唯一、连续、无重叠;缺点:译码电路复杂(需要9输入与门)。
  • 部分译码:只用其中几根高位地址线(比如A15,A14,A13)去译码。这样,00000H和08000H可能都让CS有效(因为A15-A13相同),导致地址重叠。优点:电路简单;缺点:浪费地址空间,可能引发冲突。
    选择哪种,取决于你对可靠性和成本的权衡。

4.2 I/O端口地址:为什么IN AL, 2F8H能读串口?——端口不是内存,是独立通道

CPU访问内存用地址总线,访问外设(键盘、串口、打印机)用I/O端口地址。8086有独立的I/O地址空间(0000H~FFFFH,64K个端口),用IN/OUT指令访问,和内存访问完全隔离。
答案第六章第4题:WAIT: MOV DX, 101H(状态端口)IN AL, DXTEST AL, 80HJZ WAIT—— 这是在轮询一个串口的状态寄存器(地址101H),检查最高位(80H)是否为1,表示数据已准备好。一旦为1,就执行MOV DX, 100H(数据端口)IN AL, DX去读真正的数据。
关键:每个外设芯片,都有自己的“控制端口”和“数据端口”,地址由硬件设计者固化。你写的程序,必须严格遵循这个地址约定。

4.3 中断控制器8259A:CPU的“前台接待员”,如何登记和分发中断请求

当键盘按下、串口收到数据、定时器到点,这些事件不能直接冲进CPU说“快理我!”,得有个“接待员”先登记、排队、按优先级叫号。8259A就是这个接待员。
答案第七章第11题:ICW1=12H(或16H),ICW2=70H。

  • ICW1(Initialization Command Word 1)是初始化命令字1,12H=00010010B,其中D4=1表示要写ICW4,D3=0表示单片8259A,D0=0表示边沿触发。
  • ICW2(初始化命令字2)是中断类型码的高5位,70H=01110000B,意味着接在这个8259A上的8个中断请求(IRQ0~IRQ7),对应的中断类型号是70H~77H(即112~119号中断)。
    写ICW1和ICW2,就是告诉8259A:“我是单片、边沿触发、我的中断号从112开始排”——这是让它上岗的第一步。

4.4 并行接口8255A:让CPU和LED、开关“对话”的万能转接头

8255A是经典的可编程并行接口芯片,有3个8位端口(A、B、C)和1个控制端口。它像一个“翻译官”:CPU给它发命令(写控制端口),它就决定A/B/C端口是输入还是输出,然后CPU就能通过读/写A/B/C端口,和外部硬件交互。
答案第十章第6题:MOV AL, 92HOUT PORTC, AL—— 这是往控制端口(PORTC)写92H=10010010B,根据8255A的控制字格式,这表示:端口A为方式0输出,端口B为方式0输入,端口C高4位为输出,低4位为输入。
接着MOV AL, 01HOUT PORTC, AL,就把PC0(端口C的第0位)置1,去触发ADC0809(模数转换器)的START信号;MOV AL, 00HOUT PORTC, AL再拉低,完成一次启动脉冲。
8255A的精髓在于:同一个芯片,通过写不同的控制字,就能变身成输入设备、输出设备、甚至握手信号发生器。

4.5 避坑:硬件接口的5个“一接就崩”瞬间

和真实硬件打交道,容错率极低,一个参数错,整个系统就静音:

  1. 现象:给6116芯片接地址线,A0-A10接对了,但A11没接(悬空),结果内存时好时坏。
    原因:悬空的地址线电平不确定,可能是高也可能是低,导致片选信号随机有效或无效。关键:所有未使用的地址线、数据线、控制线,必须明确接高(VCC)或接低(GND),绝不能悬空。

  2. 现象:OUT 2F8H, AL向串口发数据,但串口没反应,用示波器看TX引脚没波形。
    原因:忘了初始化串口芯片(如16550)的波特率、数据位、停止位。2F8H只是数据端口,必须先往2F9H(除数锁存器低)、2FAH(除数锁存器高)写入波特率因子,再往2FCH(线路控制寄存器)写03H(8位数据、1停止位、无校验)。关键:I/O端口操作有严格时序,数据端口只是“最后一环”,前面的初始化寄存器必须先配好。

  3. 现象:8259A初始化后,中断服务程序不执行,或执行错乱。
    原因:ICW2(中断类型码)设错了。比如设成08H,那么IRQ0就对应中断号8(INT 08H),但你的中断向量表里08H*4=20H地址处,放的却是别的程序的入口。关键:ICW2的值,必须和你在内存0000H:0020H(INT 08H向量)等位置存放的中断服务程序入口地址严格匹配。

  4. 现象:8255A控制字写80H,端口A/B/C全设成输入,但读PORTA得到的值全是FFH(255)。
    原因:端口设为输入时,外部硬件必须提供确定的电平(高或低)。如果A端口接的开关没接上拉/下拉电阻,引脚悬空,读到的就是随机值(常为FFH)。关键:输入端口必须有明确的电平来源;输出端口可以驱动LED,但输入端口需要外部“推”或“拉”。

  5. 现象:用MOV AL, 5BHOUT 2FBH, AL初始化8250串口,但5BH是错误的。
    原因:5BH是01011011B,其中D7=0表示“写除数锁存器低字节”,D6=1表示“允许接收中断”,D5=0表示“允许发送保持寄存器空中断”,D4=1表示“允许接收线路状态中断”,D3=0表示“无奇偶校验”,D2=1表示“1停止位”,D1-D0=11表示“数据位为8位”。这看起来没错,但5BH的D7=0,意味着接下来要往2F8H(除数锁存器低)写波特率因子,而2F8H正是数据端口!关键:写控制字前,必须确保DLAB(除数锁存器访问位)为0,否则会误操作数据端口;5BH的D7=0是正确的,但新手常混淆5BH和0DH(线路控制寄存器)。

5. 从习题答案到真实项目:你的第一个可运行的汇编小程序

光看答案还不够,得亲手敲一行代码,看到它在模拟器里跑起来。下面,我们就用答案第四章第9题的“十进制转十六进制显示”思路,写一个能在DOSBox里运行的、完整的.asm程序。它不复杂,但包含了从数据定义、计算、到屏幕输出的全流程。

5.1 第一步:环境准备——你需要什么?

  • 汇编器:MASM 5.0(经典,兼容性好)或TASM。下载后解压,把ml.exe(Microsoft Macro Assembler)或tasm.exe放到系统PATH里。
  • 链接器:link.exe(随MASM提供)。
  • 调试/运行环境:DOSBox(免费,模拟真实DOS环境)。安装后,在DOSBox里用mount c c:\myasm把你的代码目录挂载为C盘。
  • 编辑器:任何纯文本编辑器(Notepad++、VS Code),保存为.asm文件,编码选ANSI(DOS默认)。

5.2 第二步:抄答案,改代码——把习题变成可执行程序

答案第四章第9题是:将十进制数369转换为十六进制,并在屏幕上显示为字符串(如"171")。我们把它扩展成一个完整程序:

; 文件名: DEC2HEX.ASM ; 功能:将立即数369D转换为十六进制字符串"171H",并在DOS下显示 ; 编译:ml /c /Zi dec2hex.asm ; 链接:link dec2hex.obj; ; 运行:dec2 <p> <a href="https://download.csdn.net/download/m0_62051506/30345897" style="color:#ec7500;font-size:14px;"> 本文还有配套的精品资源,点击获取 </a> <img alt="menu-r.4af5f7ec.gif" src="https://csdnimg.cn/release/wenkucmsfe/public/img/menu-r.4af5f7ec.gif" style="width:16px;margin-left:4px;vertical-align:text-bottom;cursor:text;"> </p>