3939>
4040> 8086 CPU的指令周期通常占用4个时钟周期,因此1GHz的处理器每秒约可执行2.5亿条指令。
4141
42- ### ALU: 算术逻辑单元
42+ #### ALU: 算术逻辑单元
4343
44448086的ALU支持以下基本操作:
4545- ** 算术运算** :
@@ -389,14 +389,61 @@ das ; 调整AL为88h (88的压缩BCD格式)
389389| ` CLI ` | IF 置零, 关闭中断 |
390390| ` STI ` | IF 设一, 打开中断 |
391391
392+ ### 比较指令
393+
394+ ` CMP ` 命令(Compare,比较)是 8086 汇编语言中的一个非常重要的指令。它用于 ** 比较两个操作数的大小关系** ,但 ** 不会修改任何操作数的值** 。 ` CMP ` 命令的 ** “结果”** 不是直接返回一个数值,而是 ** 设置 CPU 的标志寄存器 (Flags Register) 中的某些标志位** 。 这些标志位反映了比较的结果,然后可以被后续的条件跳转指令(如 ` JE ` , ` JNE ` , ` JL ` , ` JG ` 等)使用,以实现程序的分支控制。
395+
396+ ** ` CMP ` 指令的基本格式:**
397+
398+ ``` assembly
399+ cmp destination, source
400+ ```
401+
402+ ** ` CMP ` 指令的操作:**
403+
404+ ` CMP destination, source ` 指令 ** 在内部执行的操作是 ` destination - source ` (目的操作数减去源操作数)** 。 ** 但是,减法的结果不会被存储到任何寄存器或内存位置,而是直接被丢弃。** ` CMP ` 指令的 ** 唯一作用** 就是根据这次减法运算的结果 ** 设置标志寄存器中的标志位** 。
405+
406+ ** ` CMP ` 指令影响的标志位 (Flags):**
407+
408+ ` CMP ` 指令主要影响以下几个标志位:
409+
410+ 1 . ** 零标志位 (Zero Flag, ZF)** :
411+ * ** ZF = 1** : 如果 ` destination - source = 0 ` ,即 ** ` destination ` 等于 ` source ` ** ,则 ZF 被设置为 1。
412+ * ** ZF = 0** : 如果 ` destination - source ≠ 0 ` ,即 ** ` destination ` 不等于 ` source ` ** ,则 ZF 被设置为 0。
413+
414+ 2 . ** 符号标志位 (Sign Flag, SF)** :
415+ * ** SF = 1** : 如果 ` destination - source ` 的结果为 ** 负数** (结果的最高位为 1,在有符号数表示中),则 SF 被设置为 1。 这通常意味着在 ** 有符号数比较** 中,` destination ` 小于 ` source ` 。
416+ * ** SF = 0** : 如果 ` destination - source ` 的结果为 ** 非负数** (结果的最高位为 0),则 SF 被设置为 0。 这通常意味着在 ** 有符号数比较** 中,` destination ` 大于等于 ` source ` 。
417+
418+ 3 . ** 进位标志位 (Carry Flag, CF)** :
419+ * ** CF = 1** : 如果在 ** 无符号数减法** 中,发生了 ** 借位** (borrow),则 CF 被设置为 1。 这通常意味着在 ** 无符号数比较** 中,` destination ` 小于 ` source ` 。
420+ * ** CF = 0** : 如果在 ** 无符号数减法** 中,没有发生借位,则 CF 被设置为 0。 这通常意味着在 ** 无符号数比较** 中,` destination ` 大于等于 ` source ` 。
421+
422+ 4 . ** 溢出标志位 (Overflow Flag, OF)** :
423+ * ** OF = 1** : 如果在 ** 有符号数减法** 中,发生了 ** 溢出** (结果超出了有符号数的表示范围),则 OF 被设置为 1。 溢出标志用于判断 ** 有符号数运算结果是否溢出** 。 在比较有符号数大小时,OF 需要和 SF 一起考虑。
424+ * ** OF = 0** : 如果在 ** 有符号数减法** 中,没有发生溢出,则 OF 被设置为 0。
425+
426+ ** 常用的条件跳转指令和 ` CMP ` 结果的关系:**
427+
428+ | 条件跳转指令 | 含义 (通常用于) | 检查的标志位 |
429+ | ----------------------- | ------------------------------------------------------------ | ----------------- |
430+ | ` JE ` 或 ` JZ ` | 等于 (Equal) 或 结果为零 (Zero) | ZF = 1 |
431+ | ` JNE ` 或 ` JNZ ` | 不等于 (Not Equal) 或 结果非零 (Not Zero) | ZF = 0 |
432+ | ` JG ` 或 ` JNLE ` | 大于 (Greater) (有符号数) 或 不小于等于 (Not Less or Equal) | ZF = 0 且 SF = OF |
433+ | ` JGE ` 或 ` JNL ` | 大于等于 (Greater or Equal) (有符号数) 或 不小于 (Not Less) | SF = OF |
434+ | ` JL ` 或 ` JNGE ` | 小于 (Less) (有符号数) 或 不大于等于 (Not Greater or Equal) | SF ≠ OF |
435+ | ` JLE ` 或 ` JNG ` | 小于等于 (Less or Equal) (有符号数) 或 不大于 (Not Greater) | ZF = 1 或 SF ≠ OF |
436+ | ` JA ` 或 ` JNBE ` | 大于 (Above) (无符号数) 或 不小于等于 (Not Below or Equal) | CF = 0 且 ZF = 0 |
437+ | ` JAE ` 或 ` JNB ` 或 ` JNC ` | 大于等于 (Above or Equal) (无符号数) 或 不小于 (Not Below) 或 无进位 (No Carry) | CF = 0 |
438+ | ` JB ` 或 ` JNAE ` 或 ` JC ` | 小于 (Below) (无符号数) 或 不大于等于 (Not Above or Equal) 或 进位 (Carry) | CF = 1 |
439+ | ` JBE ` 或 ` JNA ` | 小于等于 (Below or Equal) (无符号数) 或 不大于 (Not Above) | CF = 1 或 ZF = 1 |
440+
392441### 分支控制
393442
394443条件跳转是短跳转, 操作数是一个字节, 允许向后跳转 -128 或向前跳转 +127
395444
396445无条件跳跃可以跳得更远, 可以直接地址跳转, 允许 +/-32K 的跳转, 甚至允许跳转到AX寄存器!
397446
398- #### 常用指令
399-
400447| 指令 | 含义 | flag | 反指令 | 反含义 | 反 flag |
401448| ------ | ---------------- | ---------------- | ------ | -------------------- | ---------------- |
402449| ` JA ` | Above | ` ZF=0 and CF=0 ` | ` JNA ` | Not Above | ` ZF=1 or CF=1 ` |
@@ -524,7 +571,7 @@ $\begin{flalign*}
524571
525572实际上程序只花了15s来运行, 计算出来的时钟频率是1200MHz, 是目标机器的时钟频率(300MHz)的4倍,原因是现代处理器使用 ** 指令并行** 技术
526573
527- ### 打印数字的方法
574+ ### 打印数字
528575
529576基于栈的实现:
530577
@@ -1253,6 +1300,11 @@ MOSFET 主要由以下几个部分构成:
12531300>
12541301> 这里MOSFET讲的很抽象,参考[ 【硬核科普】带你认识CPU第00期——什么是MOSFET] ( https://www.bilibili.com/video/BV1nL411x7jH/ )
12551302
1303+ ### 区分
1304+
1305+ - ** N 型 (N-channel) MOSFET:** 载流子是** 电子 (Electrons)** - 记住 ** N 代表 Negative (负)** ,电子带负电,需要 ** 正栅极电压 (Positive Gate Voltage)** 才能导通。
1306+ - ** N 型 (N-channel) MOSFET:** 载流子是** 空穴 (Holes)** - 记住 ** P 代表 Positive (正)** ,空穴可以被认为是带正电的,需要 ** 负栅极电压 (Negative Gate Voltage)** 才能导通。
1307+
12561308### 互补金属氧化物半导体 (CMOS)
12571309
12581310** 互补金属氧化物半导体 (Complementary Metal-Oxide-Semiconductor, CMOS)** 电路是现代数字电路中最主流的电路形式。CMOS 电路利用 ** PMOS (P 沟道 MOSFET)** 和 ** NMOS (N 沟道 MOSFET)** 的互补特性,实现低功耗、高性能的逻辑功能。
@@ -1451,7 +1503,7 @@ IN acc, port
145115038086 架构支持多种类型的中断,可以根据**触发来源**进行分类:
14521504
14531505- **硬件中断 (Hardware Interrupt)**:
1454- - 由**外部硬件设备**通过 **处理器的引脚**发出中断请求信号。
1506+ - 由外部硬件设备通过 **处理器的引脚**发出中断请求信号。
14551507 - **INTR (Interrupt Request)** 引脚:**可屏蔽中断**,可以通过设置**中断标志位 (IF)** 来**屏蔽**或**使能**。
14561508 - **NMI (Non-Maskable Interrupt)** 引脚:**非可屏蔽中断**,**优先级高于 INTR**,通常用于处理**更紧急的硬件错误**,如电源故障或内存奇偶校验错误。
14571509- **异常中断 (Exception Interrupt)**:
@@ -1494,24 +1546,47 @@ IN acc, port
14941546
14951547**中断向量表 (Interrupt Vector Table, IVT)** 是计算机系统中**管理和处理中断** 的核心数据结构。
14961548
1497- - **作用**:**存储中断服务例程 (ISR) 的入口地址**。当**中断发生**时,**CPU** 会根据** 中断号** 在 **中断向量表** 中**查找** 相应的 **入口地址** ,然后 **跳转到该地址** 执行 **中断处理程序 **。
1498- - **存储位置**:**中断向量表** 通常位于 **RAM (随机访问存储器)** 的 **起始地址** 区域 ,即 **前 1024 字节** (地址范围:**0000:0000 到 0000:03FF**) 。
1549+ - **作用**:**存储中断服务例程 (ISR) 的入口地址**。当**中断发生**时,CPU会根据** 中断号** 在 **中断向量表** 中查找相应的入口地址 ,然后**跳转到该地址执行中断处理程序 **。
1550+ - **存储位置**:**中断向量表** 通常位于RAM (随机访问存储器的起始地址区域 ,即 **前 1024 字节** (地址范围:**0000:0000 到 0000:03FF**) 。
14991551- **条目结构**:**每个中断向量** 在中断向量表中占用 **4 个字节**。
15001552 - **前 2 个字节**:存储 **指令指针 (IP, Instruction Pointer)**,即 **ISR 代码段内的偏移地址**。
15011553 - **后 2 个字节**:存储 **代码段选择器 (CS, Code Segment)**,即 **ISR 代码所在的段地址**。
1502- - **地址计算**:对于给定的**中断号 `n`** ,其在中断向量表中的起始地址可以通过以下公式计算:
1554+ - **地址计算**:对于给定的中断号 `n`,其在中断向量表中的起始地址可以通过以下公式计算:
15031555
15041556 `中断向量地址 = 中断号 * 4`
15051557
1506- 例如,假设 **中断号为 `0x21` (十进制 33) **:
1558+ 例如,假设 **中断号为 `0x3` **:
15071559
1508- - **中断向量表位置**:`0x0000:0084` (`0x21 * 4 = 0x84`)
1509- - **入口地址解析**:如果 `0x0084` 处存储的值为 `0x1234:0x5678 `,则表示 **中断处理程序的入口地址** 为 ** 代码段 `0x1234 `,偏移地址 `0x5678`** 。CPU 将跳转到 **物理地址 `0x1234 * 16 + 0x5678 `** 处开始执行 ISR 代码。
1560+ - **中断向量表位置**:`0x0C:0x0F`
1561+ - **入口地址解析**:例如 ``0x0C:0x0F`` 处存储的值为 `0x0070:0x06F4 `,则表示 **中断处理程序的入口地址** 为 代码段 `0x0070 `,偏移地址 `0x06F4` 。CPU 将跳转到 **物理地址 `0x0070 << 4 + 0x06F4 `** 处开始执行 ISR 代码。
15101562
15111563**中断向量表结构示意图**
15121564
15131565
15141566
1567+ **重写中断向量表的例子**
1568+
1569+ ```assembly
1570+ ; 保存原INT 8h中断向量
1571+ cli ; 禁用中断
1572+ xor ax, ax
1573+ mov es, ax ; ES=0000h(中断向量表段)
1574+ mov bx, 8*4 ; INT 8h向量地址(8h*4=20h)
1575+
1576+ ; 保存原处理程序地址
1577+ mov ax, es:[bx]
1578+ mov old_ip, ax
1579+ mov ax, es:[bx+2]
1580+ mov old_cs, ax
1581+
1582+ ; 设置新中断向量
1583+ mov ax, OFFSET isr
1584+ mov es:[bx], ax
1585+ mov ax, cs
1586+ mov es:[bx+2], ax
1587+ sti ; 重新启用中断
1588+ ```
1589+
15151590### 中断控制器 8259A
15161591
15171592#### 8259A 的功能与连接
@@ -1691,10 +1766,9 @@ EOI_command:
16911766
16921767** 自定义中断服务例程 (ISR)** 是指** 程序员** ** 自己编写** 的 ** 中断处理程序** ,用于** 替换** 系统默认的 ** ISR** ,以实现特定的中断处理逻辑。
16931768
1694- - ** 应用场景** :
1695- - ** 硬件驱动程序** :为特定的硬件设备编写 ISR,处理设备发出的中断请求,实现设备的数据传输、控制等功能。
1696- - ** 实时系统** :在实时系统中,需要编写定制化的 ISR,以满足系统对中断响应时间、处理逻辑的特定需求。
1697- - ** 系统功能扩展** :通过自定义 ISR,可以扩展系统的功能,例如实现** 自定义的定时器** 、** 热键检测** 等。
1769+ - ** 硬件驱动程序** :为特定的硬件设备编写 ISR,处理设备发出的中断请求,实现设备的数据传输、控制等功能。
1770+ - ** 实时系统** :在实时系统中,需要编写定制化的 ISR,以满足系统对中断响应时间、处理逻辑的特定需求。
1771+ - ** 系统功能扩展** :通过自定义 ISR,可以扩展系统的功能,例如实现** 自定义的定时器** 、** 热键检测** 等。
16981772
16991773** 自定义定时器 ISR 的示例** :
17001774
@@ -1703,6 +1777,8 @@ EOI_command:
17031777- ** 自定义 ISR 替换** :程序员可以** 编写自己的 ISR 代码** ,** 替换** 原有的 ** INT 08H** 中断处理程序,从而实现** 自定义的定时器功能** 。
17041778- ** 周期性执行** :由于 ** INT 08H** 大约每 ** 50ms** 左右 ** 自动执行一次** ,因此可以利用它来实现** 周期性的任务** ,例如 ** 计时器** 、** 实时数据采集** 、** 周期性系统监控** 等。
17051779
1780+
1781+
17061782### 直接访问屏幕内存 (VRAM)
17071783
17081784** 直接访问屏幕内存** 是一种** 高效的屏幕显示技术** ,允许程序** 直接** ** 读写** ** 视频 RAM (Video RAM, VRAM)** ,从而** 快速** ** 控制屏幕显示内容** 。
@@ -2918,29 +2994,29 @@ call Print
29182994
29192995#### 使用三态缓冲器
29202996
2921- 三态设备用另一根控制线来断开设备与总线的连接。当断开连接的时候,它的输入阻抗变得非常大 ,这样就能避免总线争用的情况了。
2997+ 三态设备用另一根控制线来断开设备与总线的连接。当断开连接的时候,它的输入阻抗 (High-impedance) 变得非常大 ,这样就能避免总线争用的情况了。
29222998
29232999![ img] ( https://s2.loli.net/2025/02/12/AgRbmW2oTGNVzai.png )
29243000
2925- ### 仲裁
3001+ ### 仲裁 (Arbitration)
29263002
29273003不同设备可能希望同时使用总线,这个时候需要总线仲裁用于避免总线上的冲突或竞争。
29283004
2929- #### 级联
3005+ #### 级联 (Cascading)
29303006
29313007当设备想要使用总线时,它会拉高 Request 信号。 如果 Busy 信号为高电平,表示总线正忙,控制器将忽略新的 Request 信号。 反之,如果 Busy 信号为低电平,控制器则发送 Grant 信号给该设备,允许其使用总线。 收到 Grant 信号后,设备会立即拉高 Busy 信号,并将数据放到总线上传输。
29323008
29333009![ img] ( https://s2.loli.net/2025/02/12/lb1pjHLfEuRwS9i.png )
29343010
2935- #### 轮询
3011+ #### 轮询 (Polling)
29363012
29373013当设备想要使用总线时,它会拉高 Request 信号。 一旦收到请求,控制单元就开始挨个查看轮询线,看看哪个设备想要用总线。 找到了想用的,就把 Busy 信号拉高,然后把数据线连通,让这个设备用。
29383014
29393015通俗一点来就像点名一样:设备想用总线先举手 (发出请求)。然后控制器一个一个地问:“1 号,你要用总线吗? 2 号,你要用总线吗? 3 号,你要用总线吗?...”,一旦点到某个举手的设备,控制单元就说:“好,给你用!” 然后把 Busy 信号设为“忙碌”,并把数据线连通,让这个设备传输数据。“点名”的顺序决定了谁先被服务,也就是谁的优先级最高。 如果 1 号总是先被点到,那么 1 号的优先级就最高。
29403016
29413017![ img] ( https://s2.loli.net/2025/02/12/18kxLOaZqwTBgJr.png )
29423018
2943- #### 独立请求
3019+ #### 独立请求 (Independent Request)
29443020
29453021每个外设单元都有单独的请求线 (Request) 和授权线 (Grant)。优先级由总线控制单元来决定。不过缺点就是比较复杂,因为每个单元都需要单独的请求线和授权线。
29463022
0 commit comments