
简介这份PDF文档是Intel 8086 16位HMOS微处理器的官方技术手册1990年9月版Order Number 231455-005面向计算机体系结构学习者、汇编语言开发者与嵌入式硬件工程师用于系统理解8086的架构、引脚定义与工作模式。手册完整覆盖8086/8086-2/8086-1三种时钟频率版本5、8、10MHz包含CPU框图、40引脚配置与逐脚功能说明、1MB直接寻址能力、14个16位寄存器组、24种操作数寻址模式以及位、字节、字与块操作和二进制/十进制有符号无符号乘除运算等内容并讲解最小模式与最大模式下的局部总线、中断应答三态行为及MULTIBUS兼容接口。资源包共1个PDF文件约629KB轻量便携适合随时查阅。目前已有632人学习下载可作为课程学习、汇编实践与硬件设计中的案头参考。1. 8086 手册为什么 40 个引脚能撑起 1MB 寻址翻开一份 1990 年的 16 位微处理器数据手册最先让人愣住的往往不是指令集而是引脚表40 个引脚却要同时承担 20 位地址、16 位数据、总线控制、中断、DMA 握手。地址和数据居然共用同一组线A0 还要兼职做字节选择。这种“一根线干三份活”的设计在今天看来近乎抠门但它恰恰是 8086 能被大规模采用的关键。Intel8086 手册把这种取舍写得很直白AD15–AD0 在 T1 周期输出地址在 T2、T3、TW、T4 周期传输数据靠一个 ALE 信号在时间上切开。搞懂这套时分复用机制你才能理解后来 x86 的段式内存、总线周期、甚至现代 CPU 前端预取的思想源头。这份手册值得逐页啃不是因为它是古董而是因为它把“资源受限下如何做架构决策”摊开给你看。2. 总线时分复用20 位地址怎么塞进 16 根线2.1 AD15–AD0 的双重身份与 ALE 的锁存时机8086 最核心的硬件机制是地址/数据总线复用。手册里 AD15–AD0 标注为 I/O 类型描述写得很清楚这些线在 T1 周期是存储器或 I/O 地址在 T2、T3、TW、T4 周期是数据总线。问题在于地址只在 T1 有效而外设需要在整个总线周期内看到稳定地址。解决办法是外部加一片 8282/8283 地址锁存器由 ALEAddress Latch Enable在 T1 期间的高脉冲触发锁存。手册对 ALE 的描述是“HIGH pulse active during T1 of any bus cycle”并且特别注明 ALE 永远不会被浮空——这是它作为系统同步基准的资格。我一般会这么理解这个设计CPU 内部其实有完整的 20 位地址但封装只有 40 脚如果地址和数据各占一组引脚数直接翻倍40 脚封装根本装不下。时分复用把引脚压力转嫁给了外部锁存器代价是系统多一颗芯片、时序多一个约束。这个取舍在 1978 年是对的因为当时锁存器便宜、引脚贵。# 总线周期时序的抽象表达T1 锁地址T2-T4 传数据 T1: AD[15:0] A[15:0] ALE1 - 8282 锁存低 16 位地址 T1: A[19:16]/S[6:3] A[19:16] T2: AD[15:0] D[15:0] ALE0 地址锁存器保持输出 T3: 数据稳定READY 采样 T4: 总线周期结束上面这段伪时序不是手册原文而是把手册中 AD15–AD0、ALE、READY 三处描述串起来的执行视图。关键参数是 ALE 的宽度它只在 T1 为高所以锁存器必须在 T1 上升沿附近完成采样晚一拍地址就丢了。这也是为什么早期 8086 系统板上 8282 紧贴 CPU 布局走线长了 T1 的建立时间就吃紧。2.2 BHE 与 A0一个字为什么要拆成两个字节选通手册里 BHE/S7 和 A0 的配合表是另一个容易被跳过的细节。BHE 低有效A0 低有效两者组合决定当前总线周期传的是整字、高字节、低字节还是什么都不传。表里写得很清楚BHE0、A00 传整字BHE0、A01 从奇地址取高字节BHE1、A00 从偶地址取低字节BHE1、A01 不传。这个设计的动机是 8086 允许字操作数落在奇地址上不像很多 16 位机强制偶对齐。代价是奇地址字访问要拆成两个总线周期性能掉一半。手册没有明说“所以你要尽量偶对齐”但 BHE/A0 表本身就是这个结论的硬件证据。写汇编时把 word 变量放偶地址不是玄学是直接绕开这条拆分路径。提示BHE 在中断应答的第一个周期也会拉低手册在 BHE 描述末尾专门提了一句。做总线监控或逻辑分析仪抓包时别把中断应答误判成高字节传输。2.3 最小模式与最大模式同一组引脚的两套人格MN/MX 引脚第 33 脚决定芯片是单处理器还是多处理器配置。最小模式下第 24–31 脚是 INTA、ALE、DEN、DT/R、M/IO、WR、HOLD、HLDA最大模式下同样这些脚变成 S2/S1/S0、RQ/GT0、RQ/GT1、LOCK、QS1/QS0。手册把两套引脚描述分开列就是因为同一物理引脚在不同模式下语义完全不同。这个设计的精妙之处在于8086 没有为多处理器额外增加引脚而是把总线控制权“外包”给 8288 总线控制器。最大模式下 S2/S1/S0 只输出状态编码由 8288 译码出 MEMR、MEMW、IOR、IOW 等信号。CPU 从“自己驱动控制线”退化成“只报告状态”系统复杂度上去了但多主控能力有了。RQ/GT 的脉冲握手协议请求 1 拍、授权 1 拍、释放 1 拍每次交换后强制一个死时钟也是在这个背景下才成立的。3. BIU 与 EU 分离指令预取为什么能藏住取指延迟3.1 六字节 FIFO 队列与“取指不阻塞执行”的边界手册 Functional Description 一节把 8086 内部逻辑分成两个单元Bus Interface UnitBIU和 Execution UnitEU。BIU 负责取指、排队、取操作数、地址重定位和总线控制EU 从队列取指令并执行。关键句是“Up to 6 bytes of the instruction stream can be queued”以及“Whenever there is space for at least 2 bytes in the queue, the BIU will attempt a word fetch memory cycle”。这就是 8086 性能提升的核心机制EU 执行当前指令时BIU 已经在总线上预取下一条。队列是 FIFOEU 按需取字节。手册举了个反例遇到分支指令后队列被清空第一个进入队列的字节立即可用给 EU。换句话说顺序执行时预取能藏住大部分取指时间跳转时预取收益归零还要付清空队列的代价。我一般会这么理解这 6 字节队列是后来所有 CPU 指令预取器的祖先但它没有分支预测所以跳转惩罚是硬性的。写 8086 汇编时把热循环体压小、减少跳转不只是减少指令数更是减少队列清空次数。这个直觉在今天的 CPU 上依然成立只是惩罚从“清空 6 字节”变成了“清空流水线”。# 用伪代码模拟 BIU/EU 的队列交互帮助理解预取边界 QUEUE_SIZE 6 queue [] def biu_prefetch(memory, pc): # 只要队列剩余空间 2 字节就发起一次字取指 while len(queue) QUEUE_SIZE - 2: word memory.read_word(pc) # 一次总线周期取 2 字节 queue.extend(word.to_bytes(2, little)) pc 2 return pc def eu_execute(queue): if not queue: return None # 队列空EU 必须等 BIU opcode queue.pop(0) # FIFO 取指 return decode_and_run(opcode)这段伪代码对应手册里“queue acts as a First-In-First-Out buffer”和“if the queue is empty, the first byte becomes available immediately”两句。参数上QUEUE_SIZE6 是手册明写的上限len(queue) QUEUE_SIZE - 2对应“space for at least 2 bytes”才发起字取指的条件。真实硬件里 BIU 和 EU 是异步并行的伪代码串行化只是为了把边界条件写清楚队列满时 BIU 停队列空时 EU 停两个停顿点就是性能分析该盯的地方。3.2 段寄存器与 20 位物理地址的合成公式手册 Memory Organization 一节给出 8086 寻址的底层公式所有内存引用都相对于段寄存器中的基地址段寄存器自动按规则选择代码段、数据段、堆栈段、附加段。物理地址由段基址左移 4 位加偏移得到段落在 16 字节边界上每段最大 64KB总空间 1MB00000H–FFFFFH。这个设计的动机手册写得很克制“By structuring memory into relocatable areas of similar characteristics and by automatically selecting segment registers, programs are shorter, faster, and more structured.” 翻译成工程语言16 位寄存器只能直接寻址 64KB要覆盖 1MB 必须引入额外位宽段寄存器就是那 4 个额外位。代价是同一物理地址有多种段:偏移表示指针比较不能直接比数值这是后来保护模式和现代操作系统里“平坦内存模型”要解决的问题。注意手册明确写“Word operands can be located on even or odd address boundaries”字操作数不强制偶对齐。但结合 BHE/A0 表奇地址字访问要两个总线周期。手册没把这两处放一起讲读的时候要自己串起来。3.3 24 种寻址模式背后的 ModR/M 编码空间手册在特性列表里写“24 Operand Addressing Modes”但没有在 Functional Description 里展开编码细节。常见的实现思路是8086 指令的 ModR/M 字节用 3 位 mod、3 位 reg、2 位 r/m 组合出寄存器直接、寄存器间接、带位移的间接等多种形式再叠加段前缀凑出 24 种操作数寻址组合。这个编码空间是 x86 变长指令的起点也是后来解码器复杂度爆炸的源头。从设计取舍看24 种模式让汇编程序员能用一条指令表达“从 [BXSIdisp] 取数”这类复合地址减少指令条数代价是解码逻辑变复杂且指令长度不固定BIU 预取时无法简单按固定宽度切分。手册里 6 字节队列的存在某种程度上就是在吸收变长指令带来的取指不确定性。4. 中断与总线仲裁INTR、NMI 和 RQ/GT 的优先级怎么排4.1 INTR 的电平触发与 NMI 的边沿触发差异手册对两个中断输入的描述差异很值得细读。INTR 是电平触发在每个指令最后一个时钟周期采样可被软件通过中断允许位屏蔽内部已同步。NMI 是边沿触发低到高跳变在当前指令结束时触发类型 2 中断不可被软件屏蔽内部也同步。RESET 则要求至少 4 个时钟周期的高电平返回低后重新开始执行。这三种触发方式的差异不是随意定的。INTR 电平触发适合接 8259 这类中断控制器控制器保持请求直到 CPU 应答NMI 边沿触发适合接电源故障、内存校验错这类“事件型”信号跳变一次算一次不需要保持。手册还特别写“INTR is internally synchronized”意味着外部不需要额外同步电路但 NMI 和 RESET 同样内部同步这点常被忽略。# 中断采样点的时序语义按手册描述归纳 每个指令最后一个 CLK 周期: 采样 INTR 电平 - 若允许且为高进入中断应答 NMI 低到高跳变 - 当前指令结束后触发类型 2 RESET 高电平 4 CLK - 立即终止当前活动返回低后重启这段归纳的关键参数是“最后一个时钟周期”和“4 个时钟周期”。前者决定了中断响应的延迟下限是一条指令后者决定了复位电路的去抖时间常数。做复位电路时如果高电平不足 4 拍CPU 行为不保证这是硬件调试里常见的翻车点。4.2 RQ/GT 三脉冲握手与 LOCK 的互斥语义最大模式下RQ/GT0 和 RQ/GT1 让其他总线主控请求本地总线。手册把握手写成三步请求方发 1 拍脉冲pulse 18086 在 T4 或 T1 回 1 拍脉冲pulse 2表示总线将浮空并进入 hold acknowledge请求方再发 1 拍脉冲pulse 3表示请求即将结束。每次交换后必须有一个死时钟周期。RQ/GT0 优先级高于 RQ/GT1两脚有内部上拉可悬空。手册还列了 CPU 正在执行存储器周期时释放总线的四个条件请求发生在 T2 或之前、当前周期不是奇地址字的低字节、当前不是中断应答的第一个应答周期、没有 LOCK 指令在执行。这四条是总线仲裁的硬约束少一条都不释放。LOCK 信号由 LOCK 前缀指令激活保持到下一指令完成期间其他主控不能拿总线。这套机制的动机是多处理器系统里总线是最稀缺资源必须有一个确定性的仲裁协议不能靠“谁先举手谁先得”。三脉冲握手把请求、授权、释放三个阶段在时间上分开死时钟周期保证双方不会在同一拍驱动总线。代价是每次总线交换至少 3 拍加 1 拍死区频繁切换主控的系统要算这笔开销。4.3 HOLD/HLDA 与 RQ/GT 的适用场景分野最小模式下用 HOLD/HLDA 做 DMA 握手HOLD 高有效CPU 在 T4 或 Ti 中间拉高 HLDA 并浮空本地总线和控制线HOLD 变低后 CPU 拉低 HLDA需要时重新驱动总线。手册注明 HOLD 不是异步输入系统保证不了建立时间就要外部同步。HOLD/HLDA 和 RQ/GT 的区别在于前者是“请求方拿走总线”CPU 完全让出后者是“请求方和 CPU 协商”CPU 在特定边界释放。DMA 控制器适合 HOLD/HLDA因为 DMA 传输是成块的多处理器共享总线适合 RQ/GT因为需要更细粒度的交替。手册把两套机制分列在最小/最大模式描述里读的时候要意识到它们不是替代关系而是不同系统拓扑下的选择。5. 避坑与排查读 8086 手册时最容易翻车的几处5.1 把 ALE 当成常高信号地址锁存器输出乱跳现象系统上电后地址总线不稳定锁存器输出在 T2 之后还在变。原因ALE 只在 T1 为高脉冲如果误以为它像普通使能信号一样常有效锁存器会在数据周期把数据当地址锁进去。解决确认 8282 的 STB 接 ALE且在 T1 上升沿采样用逻辑分析仪看 ALE 宽度若窄于锁存器建立时间检查时钟占空比——手册写明 CLK 是 33% 占空比非对称时钟不是 50%。5.2 忽略 BHE高字节读写全落到低字节现象16 位写操作只有低 8 位生效高 8 位保持原值。原因BHE 没接或接反高字节设备没被选通。手册 BHE/A0 表写明 BHE 低有效才传高字节且 BHE 在 T1 为低。解决检查 BHE 是否在 T1 拉低高字节存储器片选是否由 BHE 参与译码奇地址字访问本来就要两个周期别把两周期误判成故障。5.3 在中断应答周期误判总线状态现象逻辑分析仪抓到中断应答时 AD 总线上有地址样信号误以为 CPU 在取指。原因手册写明中断应答期间 AD 总线浮空到三态 OFFA19/S6–A16/S3 在 I/O 操作时为低。解决用 INTA 信号做触发条件中断应答周期不看 AD 数据S2/S1/S0 编码 000 就是中断应答最大模式下以状态编码为准。5.4 复位高电平不足 4 个时钟CPU 行为不确定现象上电复位偶尔失败系统跑飞。原因手册要求 RESET 高电平至少 4 个 CLK 周期RC 复位电路时间常数不够或时钟还没稳定就开始计数。解决按最慢时钟5MHz 版本周期 200ns算 4 拍即 800ns留足余量确保时钟稳定后才释放 RESET别让复位和时钟启动赛跑。5.5 把 HOLD 当异步信号直接接外设现象DMA 请求偶尔丢或总线冲突。原因手册明确写“HOLD is not an asynchronous input”建立时间不满足时 CPU 可能采不到。解决HOLD 经过同步器再进 CPU或在系统层面保证请求相对 CLK 的建立保持时间HLDA 有内部上拉但别依赖上拉做逻辑判断。6. 从 40 脚封装看架构取舍约束如何倒逼出 x86 的基因8086 手册最值得反复看的地方不是某条引脚定义而是它展示了一整套“在约束下做架构”的方法论。40 脚封装逼出了地址数据复用复用逼出了 ALE 和外部锁存器16 位寄存器逼出了段式寻址段式寻址又埋下了指针不可直接比较的长期成本6 字节预取队列在没有分支预测的年代已经是能拿到的最大收益代价是跳转惩罚硬性存在。这些取舍没有一个是“最优解”但组合起来让 8086 在引脚数、性能、系统成本之间找到了一个能被市场接受的平衡点。约束设计应对留下的长期成本40 脚封装AD 总线时分复用 ALE外部锁存器、时序约束16 位寄存器寻址 1MB段寄存器左移 4 位指针表示不唯一、段溢出问题无分支预测6 字节 FIFO 预取跳转清空队列、惩罚固定多主控需求RQ/GT 三脉冲握手 LOCK总线交换死时钟、仲裁开销验证这套机制是否被真正理解有个很土但有效的办法拿逻辑分析仪抓一次最小模式下的存储器读周期对照手册逐拍标注 T1 的 ALE 和地址、T2 的 RD 拉低、T3 的 READY 采样、T4 的状态回落。如果每一拍的信号都能在手册引脚描述里找到对应句子说明你不是在背结论而是真的把时序和引脚语义对上了。再进一步把 BHE/A0 四种组合各抓一次看数据到底落在高字节还是低字节比读十遍表都管用。我自己的习惯是每次碰这种老芯片手册先不看特性列表直接从引脚表和时序图反推“如果我是设计者为什么只能这么排”。8086 的答案几乎都藏在“引脚不够”这四个字里。从那以后我每次评估一个硬件接口方案都强制先数引脚、再算时序余量最后才看功能列表——顺序反过来血泪经验就是会在流片前才发现锁存器放不下。这份手册的 PDF 版本把引脚表、状态编码表、时序描述都保留在原排版里对照抓包看比任何二手教程都直接需要的话按摘要里的入口取用即可。希望帮到你。本文还有配套的精品资源点击获取