Lecture 1: CPU

计算机架构

计算机主要采用两种架构:

Note

现代高性能CPU通常结合冯诺依曼和哈佛架构的特点,例如通过“拆分缓存”设计来优化性能。

img

具体而言,冯诺依曼架构和哈佛架构的区别体现在以下几点:

  1. 存储器结构:冯诺依曼架构使用统一存储器,而哈佛架构使用独立的指令和数据存储器.
  2. 总线设计:冯诺依曼架构使用单条总线,哈佛架构使用多条独立总线.

8086的硬件组成

8086 CPU主要由以下两部分组成:

img

BIU: 总线接口单元

EU: 执行单元

指令周期是8086 CPU的基本工作单位,具体流程如下:

  1. Fetch:从内存中获取指令.
  2. Decode:对指令进行解码.
  3. Execute:执行解码后的指令.

Note

8086 CPU的指令周期通常占用4个时钟周期,因此1GHz的处理器每秒约可执行2.5亿条指令。

ALU: 算术逻辑单元

8086的ALU支持以下基本操作:

此外,ALU还支持移位操作,具体包括:

Note

移位操作在二进制运算中非常重要,常用于快速实现乘除法。

img

左移和右移的实现方法如下:

img


Lecture 2: Assembly Language (Ⅰ)

寄存器们

通用寄存器

img

指针和变址寄存器

段寄存器

控制寄存器

标志位寄存器

8086在特殊的16位标志寄存器中跟踪某些计算的结果:

img

8086的分段内存模型

分段内存模型概述

img

数据段寄存器 (DS)

Note

偏移量的来源包括:

  • 直接寻址:偏移量可以是指令中直接给出的一个常量 (例如 mov ax, [0x1234]) 。
  • 寄存器寻址:偏移量可以使用通用寄存器 (例如 BX, SI, DI) (例如 mov ax, [bx]) 。
  • 寄存器 + 常量:偏移量可以是寄存器值 + 常量 (例如 mov ax, [bx+0x10]) 。

堆栈段寄存器 (SS)

附加段寄存器 (ES)

MASM 程序结构

程序结构

img

编译过程

img

运算符和操作数

img

Note

这里的Operand也可以称作立即数

Hello, world !

详细实现

.MODEL medium
.STACK
.DATA

msg1 db "Hello, world.$"

.CODE
.STARTUP

mov ax,@data                    ; 将 ax 寄存器的值设置为 @data 段的值
mov ds,ax                       ; 将 DS 寄存器的值设置为 @data 段的值
lea bx,msg1                     ; 获得msg1的偏移地址, 在这个情况下(DS<<4+BX)就是实际的存储msg1的地址

back:
    mov dl,[bx]                 ; 间接寻址, 获取bx寄存器对应的内存地址的第一个值到dx寄存器
    cmp dl,'$'                  ; 将 dl 寄存器中的字符与字符 $ 进行比较
    jz done                     ; 如果 dl 寄存器中的字符和$相等 (即 ZF 标志位为 1 ), 则跳转到done执行

    mov ah,02h                  ; 设置 DOS 中断 21h 的功能号为 02h, 表示调用显示字符的功能
    int 21h                     ; 调用 DOS 中断 21h, 将 dl 寄存器中的字符显示在屏幕上

    inc bx                      ; 将 bx 寄存器的值加 1, 指向字符串 msg1 的下一个字符
    jmp back                    ; 无条件跳转到 back 标签处

done:
    nop                         ; 空操作指令

.EXIT

END

简洁实现

.MODEL small
.STACK
.DATA
    msg DB 'Hello, World!$'    ; 定义字符串,以$结尾
    
.CODE
.STARTUP

    mov ax, @data
    mov ds, ax

    mov ah, 09h               ; 打印字符串
    lea dx, msg
    int 21h

.EXIT

END

常用 21h 功能号

重要ASCII码


Lecture 3: Assembly Language (Ⅱ)

寻址模式

立即寻址

寄存器寻址

直接寻址

寄存器间接寻址

8086 指令格式

img

Byte 1

Byte 2

Low Byte/High Byte

8086 寄存器编号

img

8086 寻址模式

img

寻址模式详解

示例

mov SP, BX的二进制指令是:

opcode D W Mod Reg R/M
100010 1 1 11 100 011
mov to register word 寄存器寻址模式 to SP to BX

Lecture 4: Assembly Language (Ⅲ)

算数运算命令

指令 代码 作用
ADD ADD AX, BX 加法运算, 将 AX 和 BX 相加, 结果存入 AX
ADC ADC AX, BX 带进位的加法运算, 将 AX, BX, CF 相加, 结果存入 AX
SUB SUB AX, BX 减法运算, 将 AX 减去 BX, 结果存入 AX
MUL MUL BX 无符号乘法, 将 AX 和 BX 相乘, 结果存入 DX:AX
IMUL IMUL BX 有符号乘法, 将 AX 和 BX 相乘, 结果存入 DX:AX
DIV DIV BX 无符号除法, 将 DX:AX 除以 BX, 商存入 AX, 余数存入 DX
IDIV IDIV BX 有符号除法, 将 DX:AX 除以 BX, 商存入 AX, 余数存入 DX

Note

DIVIDIV在除数是word(16bit)的时候, 被除数是 32 位的 DX:AX,DX的值可能会产生意想不到的结果

MULIMUL在乘数是word(16bit)的时候, 结果是32位的, 低 16 位保存在 AX 里面, 高 16 位保存到 DX 里面, 导致DX寄存器的值被覆盖

十进制算数

img

ASCII调整指令

mov al, '9'  ; AL = 39h ('9'的ASCII码)
add al, '8'  ; AL = 39h + 38h = 71h
aaa          ; 调整AL为09h, AH += 1 (AH = 01h)
; 结果: AL = 09h, AH = 01h (表示BCD格式的17)
mov ax, 0507h  ; AH = 05h, AL = 07h (表示未压缩BCD的57)
aad            ; AX = 0037h (37的二进制形式)
mov bl, 6      ; BL = 6
div bl         ; AX / BL, AL = 6 (商), AH = 1 (余数)
; 结果: AL = 06h, AH = 01h

BCD调整指令

mov al, 59h  ; AL = 59h (59的压缩BCD格式)
add al, 27h  ; AL = 59h + 27h = 80h
daa          ; 调整AL为86h (86的压缩BCD格式)
; 结果: AL = 86h
mov al, 47h  ; AL = 47h (47的压缩BCD格式)
sub al, 59h  ; AL = 47h - 59h = EEh (借位发生)
das          ; 调整AL为88h (88的压缩BCD格式)
; 结果: AL = 88h

逻辑指令

指令 示例 含义
AND AND A, B 按位与
OR OR A, B 按位或
XOR XOR A, B 异或
BT BT Base, Offset 指定地址的值赋给 CF
BTC BTC Base, Offset 指定地址位的值赋给 CF, 该位取反
BTR BTR Base, Offset 指定地址位的值赋给 CF, 该位设零
BTS BTS Base, Offset 指定地址位的值赋给 CF, 该位设一
BSF BSF A, B B 最低的 1 是第几位, 赋给 A
BSR BSR A, B B 最高的 1 是第几位, 赋给 A

逻辑偏移

指令 示例 含义
SHL SHL AX, 1 将AX寄存器的内容逻辑左移1位, 空出的位用0填充
SHR SHR BX, 2 将BX寄存器的内容逻辑右移2位, 空出的位用0填充
SAL SAL CX, 1 将CX寄存器的内容算术左移1位, 空出的位用0填充 (与SHL相同 )
SAR SAR DX, 3 将DX寄存器的内容算术右移3位, 空出的位用符号位填充
ROL ROL AL, 1 将AL寄存器的内容循环左移1位, 移出的位重新填充到右侧
ROR ROR BL, 2 将BL寄存器的内容循环右移2位, 移出的位重新填充到左侧
RCL RCL AX, 1 将AX寄存器的内容带进位循环左移1位, 进位标志 (CF) 参与循环

img

Note

逻辑右移 (SHR )用0填充空出的高位, 而算术右移 (SAR )用符号位填充空出的高位

标志位指令

指令 含义
CLC 进位标志置零
STC 进位标志设一
CMC 进位标志取反
CLD 方向标志置零
STD 方向标志设一
CLI IF 置零, 关闭中断
STI IF 设一, 打开中断

比较指令

CMP 命令(Compare,比较)是 8086 汇编语言中的一个非常重要的指令。它用于 比较两个操作数的大小关系,但 不会修改任何操作数的值CMP 命令的 “结果” 不是直接返回一个数值,而是 设置 CPU 的标志寄存器 (Flags Register) 中的某些标志位。 这些标志位反映了比较的结果,然后可以被后续的条件跳转指令(如 JE, JNE, JL, JG 等)使用,以实现程序的分支控制。

CMP 指令的基本格式:

cmp destination, source

CMP 指令的操作:

CMP destination, source 指令 在内部执行的操作是 destination - source (目的操作数减去源操作数)但是,减法的结果不会被存储到任何寄存器或内存位置,而是直接被丢弃。 CMP 指令的 唯一作用 就是根据这次减法运算的结果 设置标志寄存器中的标志位

CMP 指令影响的标志位 (Flags):

CMP 指令主要影响以下几个标志位:

  1. 零标志位 (Zero Flag, ZF):

    • ZF = 1: 如果 destination - source = 0,即 destination 等于 source,则 ZF 被设置为 1。
    • ZF = 0: 如果 destination - source ≠ 0,即 destination 不等于 source,则 ZF 被设置为 0。
  2. 符号标志位 (Sign Flag, SF):

    • SF = 1: 如果 destination - source 的结果为 负数 (结果的最高位为 1,在有符号数表示中),则 SF 被设置为 1。 这通常意味着在 有符号数比较 中,destination 小于 source
    • SF = 0: 如果 destination - source 的结果为 非负数 (结果的最高位为 0),则 SF 被设置为 0。 这通常意味着在 有符号数比较 中,destination 大于等于 source
  3. 进位标志位 (Carry Flag, CF):

    • CF = 1: 如果在 无符号数减法 中,发生了 借位 (borrow),则 CF 被设置为 1。 这通常意味着在 无符号数比较 中,destination 小于 source
    • CF = 0: 如果在 无符号数减法 中,没有发生借位,则 CF 被设置为 0。 这通常意味着在 无符号数比较 中,destination 大于等于 source
  4. 溢出标志位 (Overflow Flag, OF):

    • OF = 1: 如果在 有符号数减法 中,发生了 溢出 (结果超出了有符号数的表示范围),则 OF 被设置为 1。 溢出标志用于判断 有符号数运算结果是否溢出。 在比较有符号数大小时,OF 需要和 SF 一起考虑。
    • OF = 0: 如果在 有符号数减法 中,没有发生溢出,则 OF 被设置为 0。

分支控制

条件跳转是短跳转, 操作数是一个字节, 允许向后跳转 -128 或向前跳转 +127

img

编码方式

最常用都是PC相对的 (PC-relative) 。也就是,它们会将目标指令的地址与紧跟在跳转指令后面那条指令的地址之间的差作为编码。这些地址偏移量可以编 码为1、2或4个字节,第二种编码方法是给出“绝对”地址,用4个字节直接指定目标 汇编器和链接器会选择适当的跳转目的编码。

例如源汇编代码 (x86-64,AT&T) 是:

movq    %rdi, %rax
jmp     .L3
.L2:    sarq    %rax
.L3:    testq   %rax, %rax
        jg      .L2
rep; ret

下面是链接后的程序反汇编版本:

4004d0:  48 89 f8        mov    %rdi,%rax
4004d3:  eb 03           jmp    4004d8 <loop+0x8>
4004d5:  48 d1 f8        sar    %rax
4004d8:  48 85 c0        test   %rax,%rax
4004db:  7f f8           jg     4004d5 <loop+0x5>
4004dd:  f3 c3           repz retq

反汇编器产生的注释中,第2行中跳转指令的跳转目标指明为0xB,第5行中跳转指令的跳转目标是0x5(反汇编器以十六进制格式给出所有的数字)。不过,观察指令的字节编码,会看到第一条跳转指令的目标偏移量(在第二个字节中)为0x03。把它加上0x5,也就是下一条指令的地址,就得到跳转目标地址0x8,也就是第4行指令的地址。类似地,第二个跳转指令的目标偏移量用单字节、补码表示编码为0xf8(十进制-8)。将这个数加上0xD(十进制13),即第6行指令的地址,我们得到0x5,即第3行指令的地址。**当执行PC相对寻址时,程序计数器的值是跳转指令之后的那条指令的地址,而不是跳转指令本身的地址。**这种惯例可以追溯到早期的实现,当时的处理器会在更新程序计数器之后作为执行一条指令的第一步。

循环

主要有三种:

延迟

通过调整运行的语句来延迟特定的时间,和CPU的频率有关

短延迟

对于如下程序

  mov cx, N  ; 消耗 4 时钟周期, 这里 N 是字面量, 但是取值还未确定
tag:
  nop        ; 消耗 3 时钟周期
  nop        ; 消耗 3 时钟周期
  loop tag   ; 消耗 17 个时钟周期, 退出循环时仅 5 个时钟周期

总延迟时间的计算公式为: $C = 4 + N \times 23 - 12$

假设需要延迟 1000 个时钟周期, 可以通过以下步骤计算循环次数 ( N ):

$1000 = 4 + N \times 23 - 12$

解方程得到:

$N = \frac{1000 - 4 + 12}{23} \approx 43.65$

因此, 设置 ( N = 44 ) 即可实现大约 1000 个时钟周期的延迟

长延迟

考虑如下程序

.STARTUP
mov ah,02
mov dl,'S'
int 021h

mov bx, 30000 ;4

back2: 
  mov cx, 30000 ;4
back1: 
  nop ;3
  loop back1

  dec bx
  jnz back2

  mov ah,02
  mov dl,'F'
  int 021h
EXIT

延迟计算公式为:

$C_{T}=C_{0}+N(C_{BK}){-12}$

先计算内循环:

$\begin{flalign*}
&C_T = C_0 + N(C_{_{BK}}) - 12 \
&C_T = 4 + 3000(20) - 12 \
&C_T = 599992
\end{flalign*}$

然后计算外循环:

$\begin{flalign*}
&C_T = C_0 + N(C_{BK}) - 12 \
&C_T = 4 + 30000(59992 + 2 + 16) - 12 \
&C_T = 1.8 \times 10^{10} \text{ Clock cycles}
\end{flalign*}$

实际上程序只花了15s来运行, 计算出来的时钟频率是1200MHz, 是目标机器的时钟频率(300MHz)的4倍,原因是现代处理器使用 指令并行 技术

打印数字

基于栈的实现:

.MODEL medium
.STACK
.DATA
ten db 10
.CODE
.STARTUP
mov ax, 12345
call Print
.EXIT

Print:
    push bx        ; 函数调用, 储存原来寄存器的值, 固定操作
    push cx
    push dx
    mov cx, 5      ; 初始化循环计数器为 5
    mov bx, 10000

again:
    mov dx, 0h     ; 除法前清空 dx
    div bx         ; dx:ax /= bx
    or al, 030h    ; 数字转 ASCII
    push dx        ; 保存余数
    mov dl, al     ; 传参给 21h 中断
    mov ah, 02h    ; 输出字符模式
    int 021h
    mov dx, 0h     ; 除法前清空 dx
    mov ax, bx     ; bx /= 10
    div ten
    mov bx, ax
    pop ax
    loop again     ; cx 自动减 1, 不为 0 则跳转
    pop dx         ; 函数调用结束, 恢复原来寄存器的值, 固定操作
    pop cx
    pop bx
    ret

END

Lecture 5: 汇编语言 (Ⅳ)

打印负数

负数打印的原理

打印负数的汇编代码实现

.MODEL medium
.STACK
.DATA
ten word 10
    .CODE
    .STARTUP
    mov ax, 32768  ; 将要打印的数值 (示例为 -32768 的补码表示) 放入 AX 寄存器
    call Print     ; 调用 Print 子程序进行打印
    .EXIT

; Print 子程序:负责将 AX 寄存器中的数值以十进制形式打印到屏幕
Print:
    push bx       ; 保护寄存器 BX, CX, DX 的值
    push cx
    push dx
    mov cx, 5       ; 设置循环次数为 5,用于打印五位十进制数
    mov bx, 10000   ; BX 寄存器设置为 10000,用于取出万位数字
    test ax, 8000h  ; 检测 AX 寄存器的最高位 (符号位)
    jz Positive     ; 如果符号位为 0 (正数),跳转到 Positive 标签
    ; 如果是负数,执行以下代码:
    push ax       ; 暂时保存 AX 的值
    mov ah, 02h   ; 设置 DOS 功能号为 02h (显示字符)
    mov dl, '-'   ; 将 '-' 字符的 ASCII 码放入 DL 寄存器
    int 021h      ; 调用 DOS 中断 21h,显示 '-' 字符
    pop ax        ; 恢复 AX 寄存器的值 (负数)
    not ax        ; AX 取反 (按位非)
    add ax, 1     ; AX 加 1,得到负数的绝对值 (补码转原码)
    jmp Positive    ; 跳转到 Positive 标签,打印绝对值

; Positive 标签:处理正数和负数的绝对值打印
Positive:
    mov dx, 0h    ; DX 寄存器清零,为除法运算做准备
    div bx        ; AX 除以 BX (10000),商在 AX,余数在 DX。这里用于取出万位数字,但第一次循环BX是10000,实际是取最高位
    or al, 030h   ; 将 AL 寄存器的值与 30h (字符 '0' 的 ASCII 码) 进行按位或运算,将数字转换为 ASCII 字符
    push dx       ; 余数 DX 入栈,暂存个位/十位/百位/千位数字,后续会依次出栈打印
    mov dl, al    ; 将个位数字的 ASCII 码放入 DL 寄存器
    mov ah, 02h   ; 设置 DOS 功能号为 02h (显示字符)
    int 021h      ; 调用 DOS 中断 21h,显示当前数字字符
    mov dx, 0h    ; DX 寄存器清零,为下一次除法运算做准备
    mov ax, bx    ; 将 BX 的值 (当前的除数,初始为 10000) 复制到 AX
    div ten       ; AX 除以 ten (10),结果商在 AX,余数在 DX。用于将除数降一位 (10000 -> 1000 -> 100 -> 10 -> 1)
    mov bx, ax    ; 将新的除数 (缩小 10 倍) 更新到 BX 寄存器
    pop ax        ; 从栈中弹出之前暂存的余数到 AX,为下一次循环做准备 (实际上这里pop出来的是上一次div的余数,但是后面又被mov dx, 0h覆盖了,应该pop到dx才对,这里代码有误)
    loop Positive   ; 循环 CX 次,打印剩余的数字
    pop dx        ; 恢复寄存器 DX, CX, BX 的值
    pop cx
    pop bx
    ret           ; 子程序返回
END

字符串

字符串的定义

字符串 (String) 是一组用于描述文本的 ASCII(美国信息交换标准代码) 字符序列。在汇编语言中,字符串通常以不同的方式进行定义和存储,常见的表示方法包括:

字符串的存储方式

字符串操作

LEA 命令:加载有效地址

LEA (Load Effective Address) 命令用于将有效地址加载到指定的寄存器中,常用于获取变量或内存地址。

MOVSB 命令:移动字符串字节

MOVSB (Move String Byte) 命令用于将数据从源地址复制到目标地址,以字节为单位进行操作。

CMPSB 命令:比较字符串字节

CMPSB (Compare String Byte) 命令用于比较两个字符串中的字节。

Note

REP(Repeat) 修饰符可以放在多种字符串指令 (如 MOVSB, CMPSB, STOSB, LODSB 等) 的前面,用于重复执行该指令 CX 次.REP 代表 重复字符串前缀,它可以简化循环控制,提高字符串操作的效率。

CISC 与 RISC 指令集对比

MOVSBCMPSB 等字符串操作指令是 CISC(复杂指令集计算机) 架构的特点之一。为了更好理解 CISC 的特点,以下进行 CISC 和 RISC(精简指令集计算机) 的对比:

浮点数

浮点数的概念

浮点数 (Floating-point Number) 是一种用科学计数法表示实数的方式,用于在计算机中存储和处理小数或非常大/小的数值。浮点数表示方法通常包含三个关键组成部分:

img

浮点数的通用表示形式

浮点数的通用数学表示形式为:

$\text{Value} = (-1)^{\text{Sign}} \times \text{Mantissa} \times 2^{\text{Exponent}}$

规格化浮点数

规格化浮点数 (Normalized Floating-point Number) 是 IEEE 754 标准 中最常用的一种浮点数表示形式。

规格化浮点数的表示方法

规格化浮点数的计算公式

$\text{Value} = (-1)^{\text{Sign}} \times 1.\text{Mantissa} \times 2^{\text{Exponent} - \text{Bias}}$

规格化浮点数示例

单精度浮点数示例

假设有一个单精度浮点数,其二进制表示为:

计算数值

$\text{Value} = 1.101_2 \times 2^{2} = 110.1_2 = 6.5_{10}$

非规格化浮点数

非规格化浮点数 (Denormalized Floating-point Number) 用于表示非常接近于零的数值,其特点是尾数部分的最高位不隐含为 1,而是显式表示。

非规格化浮点数的表示方法

非规格化浮点数的计算公式

$\text{Value} = (-1)^{\text{Sign}} \times 0.\text{Mantissa} \times 2^{1 - \text{Bias}}$

Note

非规格化浮点数的指数部分固定为 1 - Bias,而不是 0 - Bias,这是 IEEE 754 标准的规定,目的是为了平滑地过渡到规格化浮点数。

非规格化浮点数示例

单精度浮点数示例

假设有一个单精度非规格化浮点数,其二进制表示为:

计算数值

$\text{Value} = 0.00000000000000000000001_2 \times 2^{-126} \approx 1.4 \times 10^{-45}$

【CSAPP-深入理解计算机系统】2-4.浮点数(上)

【CSAPP-深入理解计算机系统】2-4.浮点数(下)

浮点数的计算

浮点数加减运算的原则

浮点数加减运算 遵循 先对齐,再计算 的原则。

浮点数加法运算示例

例如,计算 0.5 与 0.125 的和。

  1. 浮点数表示

    • 0.5 的浮点数表示:$(-1)^0 \times 1.0 \times 2^{-1}$
    • 0.125 的浮点数表示:$(-1)^0 \times 1.0 \times 2^{-3}$
  2. 对阶

    • 比较指数位:0.5 的指数为 -1,0.125 的指数为 -3。0.5 的指数较大。
    • 对齐指数位:将 0.125 的指数对齐到 -1,需要将指数增加 2 (从 -3 增加到 -1),尾数位右移 2 位。
    • 对阶后的 0.125 表示:$(-1)^0 \times 0.01 \times 2^{-1}$ (尾数 1.0 右移两位变为 0.01)
  3. 尾数相加

    • 将对阶后的两个浮点数的尾数部分相加:$1.0 + 0.01 = 1.01$
  4. 结果规格化 (本例中已规格化):

    • 最终结果的浮点数表示:$(-1)^0 \times 1.01 \times 2^{-1}$
  5. 结果转换为十进制

    • $(-1)^0 \times 1.01_2 \times 2^{-1} = 1.01_2 \times 2^{-1} = 0.101_2 = 0.625_{10}$ (此处计算有误,应为0.5 + 0.125 = 0.625,但示例中0.5+0.125=0.625的二进制表示应为0.101,而示例结果1.01 * 2^-1 = 1.01/2 = 0.505,计算过程需要修正)

修正后的计算结果

因此,0.5 + 0.125 = 0.625 的浮点数表示为 $(-1)^0 \times 1.01 \times 2^{-1}$。

8087 数学协处理器

处理器都有 CP 了 (╯‵□′)╯︵┻━┻

8087 协处理器的概述

8087 协处理器 (8087 Coprocessor) 是一种数学协处理器,也常被称为 浮点处理器 (Floating-Point Processor) 或 数字数据处理器 (Numeric Data Processor, NDP)

img

8087 的状态字组

状态字组 (Status Word) 是 8087 协处理器中的一个寄存器,用于记录浮点运算的状态和异常信息。

img

8087 的控制字组

控制字组 (Control Word) 是 8087 协处理器中的另一个寄存器,用于控制浮点运算的精度、舍入模式、异常处理方式等。

img

8087 的栈结构

栈 (Stack) 是 8087 协处理器内部用于存储浮点数据的存储区域。

img

8087 常用指令

8087 提供了丰富的指令集,用于执行各种浮点运算和数据操作。以下列举一些常用的 8087 指令:


Lecture 6: Assembly Language (V)

浮点数计算 —— 毕达哥拉斯问题

image-20250118下午94629825

使用 FP 处理器 (8087 ) 执行上述计算

.8087                                ; 告诉 MASM 协处理器存在
.MODEL medium
.STACK
.DATA

SX dd 5.0                            ; 定义短实数 (4 字节 ), 初始值为 5.0
SY dd 12.0                           ; 定义短实数 (4 字节 ), 初始值为 12.0
HY dd 0.0                            ; 定义短实数 (4 字节 ), 用于存储结果
cntrl dw 03FFh                       ; 定义控制字, 用于设置 8087 协处理器的状态
stat dw 0                            ; 定义状态字, 用于存储 FPU 的状态

.CODE
.STARTUP

FINIT                                ; 初始化 FPU, 将其设置为默认状态
FLDCW cntrl                          ; 加载控制字, 设置舍入模式为偶数, 并屏蔽中断

FLD SX                               ; 将 SX 压入 FPU 栈
FMUL ST, ST(0)                       ; 将栈顶元素与自身相乘, 结果存储在栈顶
FLD SY                               ; 将 SY 压入 FPU 栈
FMUL ST, ST(0)                       ; 将栈顶元素与自身相乘, 结果存储在栈顶
FADD                                 ; 将栈顶的两个数相加
FSQRT                                ; 计算栈顶元素的平方根
FSTSW stat                           ; 将 FPU 的状态字加载到 [stat]
mov ax, stat                         ; 将 [stat] 复制到 AX
and al, 0BFh                         ; 检查所有 6 个状态位
jnz pass                             ; 如果有任何位被设置, 则跳转到 pass
FSTP HY                              ; 将栈顶的结果存储到 HY
jmp print                            ; 跳转到打印函数

print:
    mov bx, OFFSET HY                ; 将 HY 的地址加载到 BX 寄存器
    mov ax, [bx+2]                   ; 将 HY+2 的值加载到 AX 寄存器
    mov cx, 16                       ; 设置循环次数为 16
    call print_num                  
    mov ax, [bx]                     ; 将 HY 的值加载到 AX 寄存器
    mov cx, 16
    call print_num
    jmp pass

print_num:
    push bx                          ; 存储 BX 寄存器
    rol ax, 1                        ; 将 AX 寄存器左移一位
    jc set                           ; 如果 ZF=1 , 则 DL='1'
    mov dl, '0'                      ; DL='0'
    jmp over

set:
    mov dl, '1'

over:
    push ax                          ; 存储 AX 寄存器
    mov ah, 02h
    int 21h
    pop ax                           ; 恢复 AX 寄存器
    loop print_num
    pop bx                           ; 恢复 BX 寄存器
    ret

pass: 
    nop

; 程序结束
mov ah, 4Ch        ; 设置 AH 为 4Ch (DOS 功能调用: 程序退出 )
int 21h

END

HY在内存中的排列:

img

汇编的内容终于结束了 (≧▽≦)/


好的,这是根据您的规范重构后的关于半导体的笔记内容:

Lecture 7: 半导体

能级

原子能级与固体能带的区别

原子和固体的能级结构存在显著差异,理解这些差异有助于认识半导体的特性。

img

能带宽度与材料导电性

能带理论解释了不同材料的导电性差异,主要通过禁带宽度来区分绝缘体导体半导体

img

P型硅与N型硅

为了实现半导体的可控导电性,通常需要进行掺杂,形成 P 型半导体N 型半导体

P型硅 (P-type Silicon)

P 型硅 (P-type Silicon) 是通过掺杂 三价元素 (如 (Boron)) 到本征半导体 (Intrinsic Semiconductor) 硅中形成的。

img

N型硅 (N-type Silicon)

N 型硅 (N-type Silicon) 是通过掺杂 五价元素 (如 (Phosphorus)) 到本征半导体硅中形成的。

img

img

二极管

二极管 (Diode) 是利用 PN 结 的单向导电性制成的半导体器件,是电子电路中最基本和重要的元件之一。

PN 结的形成

PN 结 (PN Junction) 形成于 P 型半导体N 型半导体 的交界面。

img

PN 结的正向偏置

正向偏置 (Forward Bias) 是指将外部电源的正极连接到 P 区负极连接到 N 区

img

PN 结的反向偏置

反向偏置 (Reverse Bias) 是指将外部电源的正极连接到 N 区负极连接到 P 区

img

PN 结电流方向与导电方向

二极管的伏安特性曲线

伏安特性曲线 (Current-Voltage Characteristic Curve) 描述了二极管电流随电压变化的规律,体现了二极管的单向导电性

img

二极管的典型应用

二极管因其单向导电性,在电路中有着广泛的应用。


Lecture 8: 晶体管与场效应管

结型晶体管 (BJT)

结型晶体管的结构与原理

结型晶体管 (Bipolar Junction Transistor, BJT),俗称三极管,是一种电流控制电流型的半导体器件,常用于放大和开关电路中。NPN 型晶体管是最常见的 BJT 类型之一,它由三个区域构成:

BJT 的工作原理可以类比为一个小阀门

img

结型晶体管的电流增益

电流增益 (Current Gain) 是衡量 BJT 放大能力的重要参数,通常用符号 β (贝塔) 或 hFE 表示。它定义为集电极电流 (IC)基极电流 (IB) 之比:

$\beta = \frac{I_C}{I_B}$

公式中:

电流增益的计算示例

假设:

则集电极电流 IC 为:

$I_C = \beta \times I_B = 100 \times 1 \text{ mA} = 100 \text{ mA}$

结论1 mA 的输入基极电流 可以控制 100 mA 的输出集电极电流,实现了电流的放大,体现了电流增益的作用。

基于BJT的或非门 (NOR Gate) 实现

或非门 (NOR Gate) 是一种基本的逻辑门,其输出为低电平,当且仅当所有输入均为低电平时;否则输出为高电平。使用 NPN 型晶体管可以构建 NOR 门电路。

电路原理

工作原理

img

金属氧化物半导体场效应晶体管 (MOSFET)

金属氧化物半导体场效应晶体管 (Metal-Oxide-Semiconductor Field-Effect Transistor, MOSFET) 是一种电压控制电流型的半导体器件,相比 BJT,MOSFET 具有输入阻抗高功耗低等优点,被广泛应用于集成电路中。

MOSFET 的基本结构

MOSFET 主要由以下几个部分构成:

img

NMOS 场效应晶体管的工作原理

N 沟道 MOSFET (NMOS) 为例,说明 MOSFET 的工作原理。

工作原理

  1. 未施加栅极电压 (VG = 0)

    • 在栅极下方的 P 型衬底 中,存在少量自由电子 (少数载流子) 和大量空穴 (多数载流子)。
    • 由于没有栅极电压的吸引,自由电子分布稀少,源极 (S)漏极 (D) 之间无法形成导电沟道,器件截止
  2. 施加正向栅极电压 (VG > 0)

    • 电子积累:正向栅极电压会在栅极下方的 P 型衬底表面吸引大量的自由电子
    • 空穴耗尽:同时,正向栅极电压会排斥空穴,导致栅极下方的空穴浓度降低,形成耗尽层
    • N 沟道形成:当栅极电压达到一定阈值后,栅极下方的自由电子积累到足够多,在源极和漏极之间形成一条N 型导电沟道,称为 N 沟道 (N-channel)
    • 电流导通:一旦 N 沟道形成,在 漏极电压 (VD) 的作用下,电子可以从源极 (S)N 沟道 流向 漏极 (D),形成漏极电流 (ID),器件导通

img

Note

这里MOSFET讲的很抽象,参考【硬核科普】带你认识CPU第00期——什么是MOSFET

区分

互补金属氧化物半导体 (CMOS)

互补金属氧化物半导体 (Complementary Metal-Oxide-Semiconductor, CMOS) 电路是现代数字电路中最主流的电路形式。CMOS 电路利用 PMOS (P 沟道 MOSFET)NMOS (N 沟道 MOSFET) 的互补特性,实现低功耗、高性能的逻辑功能。

CMOS 反相器的工作原理

CMOS 反相器 (Inverter) 是 CMOS 电路中最基本的逻辑门,它由一个 PMOS 管 和一个 NMOS 管 串联组成。

工作原理

总结:CMOS 反相器实现了输入与输出电平的反转,是构成更复杂 CMOS 逻辑门的基础。

img


Lecture 9: I/O

I/O

I/O 操作与地址空间

I/O (Input/Output) 操作是计算机系统中 CPU (中央处理器) 与外部设备进行数据交换的关键方式。8086 微处理器架构中,I/O 操作的设计特点包括:

常见 I/O 地址示例

下表列出了一些 常见 I/O 地址 及其用途,这些地址在早期的 IBM PC 兼容机 中被广泛使用,用于控制各种外围设备:

地址 名称 方向 用途
0x378 Parallel Printer Latch 输出 并行打印机数据端口,常用于 LPT1 (Line Printer 1),向打印机发送打印数据.
0x37A Printer Control Latch 输出 并行打印机控制端口,常用于 LPT1,控制打印机的各种操作,例如初始化、选择打印机等.
0x379 Printer Status 输入 并行打印机状态端口,常用于 LPT1,读取打印机的状态信息,例如是否忙碌、是否有纸等.
0x3D9 VDU Colour Register 输出 视频显示单元 (VDU) 颜色寄存器,用于设置 DOS 文本模式 下的边框颜色.
0x278 Parallel Printer Latch 输出 并行打印机数据端口,常用于 LPT2 (Line Printer 2),向打印机发送打印数据.

总线共享与内存访问周期

Z80A CPU 架构对比

分离总线设计

与 8086 的总线复用设计不同,Z80A CPU数据总线地址总线 采用了分离的设计,拥有独立的引脚,简化了总线控制逻辑,并可能提升总线操作的效率。

img

基于 AND 门的地址解码器

为了实现地址解码,Z80A 系统中使用了几个巨大的 AND 门 作为地址解码器 (Address Decoder)

img

三态缓冲器与数据传输控制

三态缓冲器 (Tri-state Buffer) 在 I/O 接口中扮演着重要的角色,用于控制数据流的方向和连接状态。

img

对于输出操作,三态缓冲器会被 D 触发器 (D Flip-Flop) 替代,用于锁存输出数据。

img

汇编语言 I/O 指令

OUT 指令:端口输出

OUT 指令 用于将数据从 CPU 寄存器 (通常是累加器 AL, AX, EAX) 写入 到指定的 I/O 端口

OUT port, acc

OUT 指令的两种寻址模式

  1. 立即数模式 (Immediate Mode)

    • 端口地址 直接在指令中指定为 立即数 (0-255)
    • 寻址范围限制: 这种模式只能访问 256 个端口 (地址范围 00h-FFh)。
    OUT 30h, AL  ; 将 AL 寄存器中的 8 位数据写入端口地址 30h
  2. DX 寄存器模式 (Register Mode)

    • 端口地址 存储在 DX 寄存器 中。
    • 寻址范围扩展: 这种模式可以访问 64K 个端口 (0-65535),提供了更大的 I/O 空间访问能力。
    mov dx, 0x378 ; 将端口地址 0x378 放入 DX 寄存器
    OUT DX, AX    ; 将 AX 寄存器中的 16 位数据写入 DX 寄存器指定的端口

IN 指令:端口输入

IN 指令 用于从指定的 I/O 端口 读取数据CPU 寄存器 (通常是累加器 AL, AX, EAX) 。

IN acc, port

IN 指令的两种寻址模式

  1. 立即数模式 (Immediate Mode)

    • 端口地址 直接在指令中指定为 立即数 (0-255)
    • 寻址范围限制: 这种模式只能访问 256 个端口 (地址范围 00h-FFh)。
    IN AL, 30h  ; 从端口地址 30h 读取 8 位数据,存储到 AL 寄存器
  2. DX 寄存器模式 (Register Mode)

    • 端口地址 存储在 DX 寄存器 中。
    • 寻址范围扩展: 这种模式可以访问 64K 个端口 (0-65535),提供了更大的 I/O 空间访问能力。
    mov dx, 0x379 ; 将端口地址 0x379 放入 DX 寄存器
    IN AX, DX    ; 从 DX 寄存器指定的端口读取 16 位数据,存储到 AX 寄存器

[!NOTE] I/O 特权级 (IOPL)

IOPL (I/O Privilege Level, I/O 特权级)x86 架构 中用于控制 I/O 端口访问权限 的保护机制。它存储在 EFLAGS 寄存器第 12 和 13 位,定义了程序执行 I/O 指令 (如 IN, OUT) 所需的最低特权级别 (CPL, Current Privilege Level)

IOPL 是一个 2 位 的值,取值范围为 0 到 3,数值越小特权级别越高:

  • 特权级检查:在执行 I/O 指令时,CPU 会比较当前程序CPLIOPL
    • 当 CPL ≤ IOPL 时:程序被允许直接执行 I/O 指令 (如 IN, OUT) ,可以访问 I/O 端口。
    • 当 CPL > IOPL 时:程序没有权限直接执行 I/O 指令。如果尝试执行,会触发 一般保护异常 (General Protection Fault, #GP),导致程序终止或系统崩溃。

作用:IOPL 机制增强了系统的安全性稳定性,防止低特权级别的程序非法访问硬件设备,保护系统资源。

中断机制

中断的引入与优势

中断 (Interrupt) 是一种重要的异步事件处理机制,允许外部设备或软件事件打断 CPU 的正常执行流程,转而处理更紧急或重要的任务。

应用场景:考虑 CPU 从 HDD (硬盘驱动器) 读取数据的场景。

中断处理流程

中断发生时的典型处理流程

  1. 暂停当前程序:CPU 暂停 当前正在执行的主程序
  2. 调用中断处理程序:CPU 跳转 到一个专门服务中断的程序,称为 中断处理程序 (Interrupt Handler)中断服务例程 (ISR, Interrupt Service Routine)
  3. 返回主程序中断处理程序执行完毕后,将控制权返回 到之前被中断的主程序,从断点处继续执行。

img

8086 的中断类型

8086 架构支持多种类型的中断,可以根据触发来源进行分类:

时间片轮询调度 vs 抢占式调度

中断机制 在操作系统中被广泛用于实现任务调度,两种典型的调度方式是 时间片轮询调度抢占式调度

中断优先级

中断优先级 (Interrupt Priority) 用于区分不同中断请求的重要性。在多中断源的系统中,当多个中断同时发生时,优先级较高的中断 会被优先处理

中断向量表 (IVT)

中断向量表 (Interrupt Vector Table, IVT) 是计算机系统中管理和处理中断 的核心数据结构。

中断向量表结构示意图

img

重写中断向量表的例子

    ; 保存原INT 8h中断向量
    cli                 ; 禁用中断
    xor ax, ax
    mov es, ax          ; ES=0000h(中断向量表段)
    mov bx, 8*4         ; INT 8h向量地址(8h*4=20h)

    ; 保存原处理程序地址
    mov ax, es:[bx]
    mov old_ip, ax
    mov ax, es:[bx+2]
    mov old_cs, ax

    ; 设置新中断向量
    mov ax, OFFSET isr
    mov es:[bx], ax
    mov ax, cs
    mov es:[bx+2], ax
    sti                 ; 重新启用中断

Note

注意这里由于8086是使用小端法,偏移在低地址,段地址在高地址!

中断控制器 8259A

8259A 的功能与连接

8259A 可编程中断控制器 (Programmable Interrupt Controller, PIC) 是一种常用的硬件中断管理芯片,用于扩展 CPU 的中断处理能力管理多个中断源,并实现中断优先级控制

8259A 级联结构

IBM PC 架构中,通常使用 两个 8259A 芯片 级联 构成中断系统,以支持更多的中断源

8259A 中断系统连接示意图

img

IRQ 与中断向量的映射关系

8259A硬件中断请求 (IRQ) 信号 映射中断向量 (INT) 号,从而与 中断向量表 (IVT) 关联起来。

IRQ 与中断向量映射表

IRQ 中断向量 (十六进制) 描述
0 0x08 定时器节拍 (Timer Tick)
1 0x09 键盘 (Keyboard)
2 0x0A 辅助 8259A (Second 8259A)
3 0x0B COM2 (串行端口 2)
4 0x0C COM1 (串行端口 1)
5 0x0D 声卡 / LPT2
6 0x0E 软盘驱动器控制器
7 0x0F LPT1 (并行端口)
8 0x70 实时时钟 (RTC)
9 0x71 可用 (传统: IRQ2)
10 0x72 可用
11 0x73 可用
12 0x74 PS/2 鼠标
13 0x75 数学协处理器
14 0x76 主 IDE 控制器
15 0x77 辅助 IDE 控制器

Note

中断向量 INT 0-7 不由 8259A 控制,而是直接CPU 硬件BIOS 预留和使用,通常用于处理 CPU 异常早期的硬件中断,例如:

  • INT 0: 除法错误异常
  • INT 1: 单步中断 (调试)
  • INT 2: NMI (非可屏蔽中断)
  • INT 3: 断点中断
  • INT 4: 溢出中断

CPU 中断处理流程详解

CPU 处理硬件中断请求的详细步骤

  1. 中断触发 (Interrupt Trigger)

    • 外部设备内部异常 产生中断请求 (IRQ)
    • 中断信号 通过 中断线 发送到 CPU中断控制器 (如 8259A)
  2. 中断响应 (Interrupt Acknowledge)

    • CPU完成当前指令的执行后检测中断请求
    • 如果中断允许 (中断标志位 IF=1,且非屏蔽中断) ,CPU 发出 中断响应信号 (INTA, Interrupt Acknowledge)
  3. 保存现场 (Save Context)

    • CPU 自动将 当前程序的状态 压入堆栈 (Stack) 保存,以便在中断处理完成后恢复执行
    • 保存内容 通常包括:
      • 程序计数器 (PC, Program Counter) / 指令指针 (IP, Instruction Pointer):指向下一条要执行的指令地址,用于记录中断发生时的程序执行位置。
      • 标志寄存器 (FLAGS):保存 状态标志位控制标志位 的值,如 进位标志 CF零标志 ZF中断使能标志 IF 等。
  4. 获取中断向量 (Get Interrupt Vector)

    • CPU中断控制器 (如 8259A) 读取直接接收 中断号 (或称为 中断向量号)。
    • 根据中断号中断向量表 (IVT)查找 对应的 中断服务例程 (ISR) 入口地址 (代码段地址 CS 和偏移地址 IP) 。
  5. 跳转到 ISR (Jump to ISR)

    • CPU 加载 从中断向量表读取的 ISR 入口地址 (CS:IP)代码段寄存器 CS指令指针寄存器 IP
    • 程序控制权 转移中断服务例程 (ISR) 的起始地址,开始执行 ISR 代码。
  6. 执行中断处理 (Execute ISR)

    • CPU 执行 中断服务例程 (ISR) 代码,完成特定设备异常 的具体处理逻辑
    • ISR 代码 负责:
      • 识别中断源 (如果需要)。
      • 读取写入 I/O 端口,与设备进行数据交换。
      • 清除中断状态复位设备 (如果需要)。
      • 发送中断结束命令 (EOI) 给中断控制器 (对于 8259A 等可编程中断控制器)。
  7. 恢复现场 (Restore Context)

    • 中断处理完成 后,ISR 代码 通常会执行 IRET (中断返回) 指令。
    • IRET 指令 会从 堆栈 (Stack)弹出 之前 保存的程序状态 (包括 FLAGSCS:IP)。
    • CPU 寄存器程序状态 恢复中断发生前的状态
  8. 返回原程序 (Return to Original Program)

    • CPU 恢复执行 被中断的 原程序,从 断点处 (即 中断发生时 PC 指向的地址) 继续运行

8259A 操作命令:中断屏蔽

中断屏蔽寄存器 (IMR, Interrupt Mask Register)8259A 可编程中断控制器 (PIC) 的一个重要寄存器,用于控制 哪些 中断请求 (IRQ) 被允许禁止 (屏蔽)。

设置中断屏蔽的汇编代码示例

以下代码示例演示了如何通过设置 IMR屏蔽 IRQ 7, IRQ 3 和 IRQ 1 中断

mov al, 137     ; 十进制 137, 十六进制 89H
                ; 二进制 10001001B
                ; 位 7, 3, 0 设置为 1,对应屏蔽 IRQ7, IRQ3, IRQ1
mov dx, 21h     ; 中断屏蔽寄存器 (IMR) 的端口地址 (主 8259A)
out dx, AL      ; 将屏蔽值写入 IMR 寄存器

屏蔽值 137 (89H) 的二进制表示 10001001B 的含义

img

中断结束命令 (EOI)

中断结束 (End of Interrupt, EOI) 命令是 8259A 可编程中断控制器 (PIC) 中用于通知控制器 中断处理程序 (ISR) 已经完成,可以重新接受新的中断请求 的命令。

发送非特定 EOI 命令的汇编代码示例

EOI_command:
    mov al, 20h     ; EOI 命令字 (非特定 EOI)
    out 20h, al     ; 发送到 8259A 的主控制器命令端口 (20H)

Note

何时发送 EOI 命令

  • 在中断服务例程 (ISR) 的末尾IRET (中断返回) 指令之前必须发送 EOI 命令 给中断控制器。
  • 目的
    • 通知 8259A 中断处理已完成。
    • 重置 8259A 的内部状态,准备 接收和处理新的中断请求
    • 如果忘记发送 EOI 命令8259A 可能无法正确响应后续的中断请求,导致系统功能异常。

自定义中断服务例程 (ISR)

自定义中断服务例程 (ISR) 是指程序员 自己编写中断处理程序,用于替换 系统默认的 ISR,以实现特定的中断处理逻辑。

自定义定时器 ISR 的示例

INT 08H (定时器中断)IBM PC 架构 中由 系统定时器 周期性触发的 硬件中断默认情况下INT 08HISR 通常用于更新系统时间 等操作。

直接访问屏幕内存 (VRAM)

直接访问屏幕内存 是一种高效的屏幕显示技术,允许程序直接 读写 视频 RAM (Video RAM, VRAM),从而快速 控制屏幕显示内容

DOS 屏幕内存组织结构

img

属性字节 (Attribute Byte) 结构

属性字节 (Attribute Byte) 用于控制 DOS 文本模式字符的显示属性,例如 前景色背景色闪烁亮度 等。

属性字节的位结构

img

汇编代码示例:屏幕打印 "Hello, world!"

以下汇编代码示例演示了如何在 DOS 文本模式 下,直接访问屏幕内存,在屏幕上打印字符串 "Hello, world!"

.MODEL small
.STACK
.DATA
    msg db 'Hello, world!'
.CODE
start:
    ; 设置数据段寄存器 DS 指向数据段
    mov ax, @data
    mov ds, ax

    ; 设置附加段寄存器 ES 指向显存段 (B800h)
    mov ax, 0B800h
    mov es, ax

    ; 清空屏幕
    xor dx, dx            ; DX 寄存器清零,用于存储空格字符和属性
    mov cx, 2000          ; 屏幕字符总数 (80列 * 25行)
    xor di, di            ; DI 寄存器清零,作为显存地址偏移量
clear_screen:
    mov es:[di], dx       ; 将空格字符和属性写入显存,清空屏幕
    add di, 2             ; 显存地址偏移量增加 2 (每个字符占 2 字节)
    loop clear_screen     ; 循环清空整个屏幕

    ; 循环写入字符和属性,打印字符串 "Hello, world!"
    mov cx, 13            ; 字符串长度 (13个字符)
    mov di, (12 * 80 + 33) * 2 
    lea bx, msg           ; BX 寄存器指向字符串 msg 的首地址
print_loop:
    mov al, [bx]          ; 从字符串中取出一个字符,放入 AL 寄存器
    mov ah, 07h           ; 设置属性字节为 07h (黑底白字)
    mov es:[di], ax       ; 将字符和属性字节写入显存
    inc bx              ; 字符串指针 BX 加 1,指向下一个字符
    add di, 2             ; 显存地址偏移量增加 2
    loop print_loop       ; 循环打印整个字符串

    ; 等待按键按下后退出程序
wait_for_key:
    mov ah, 1
    int 16h             ; BIOS 键盘输入中断,检测是否有按键按下 (不回显)
    jz wait_for_key     ; 如果没有按键按下,继续等待
    mov ah, 0
    int 16h             ; BIOS 键盘输入中断,读取按键的 ASCII 码 (回显)

    ; 退出程序,返回 DOS
    mov ax, 4C00h
    int 21h             ; DOS 程序结束中断
END

驻留程序 (TSR)

驻留程序 (Terminate and Stay Resident, TSR) 是一种在 DOS 系统 中使用的特殊程序类型。

TSR 程序的典型应用

热键检测

; 伪代码:检测热键 Ctrl+Alt+X
check_hotkey:
    mov ah, 02h       ; BIOS 功能号 02h:读取键盘状态
    int 16h           ; 调用 BIOS 键盘中断 16h,读取键盘状态字节到 AL 寄存器
    and al, 00001111b ; 屏蔽 AL 寄存器高 4 位,仅保留低 4 位 (Shift, Ctrl, Alt, Scroll Lock 状态位)
    cmp al, 00001100b ; 与 00001100b (Ctrl+Alt 键按下) 进行比较
    jne no_hotkey     ; 如果比较结果不相等 (Ctrl+Alt 未同时按下),跳转到 no_hotkey 标签

    ; 如果 Ctrl+Alt 键同时按下,继续检测 X 键是否按下
    mov ah, 00h       ; BIOS 功能号 00h:读取键盘输入
    int 16h           ; 调用 BIOS 键盘输入中断 16h,读取键盘扫描码和 ASCII 码
    cmp al, 'x'       ; 比较 AL 寄存器中的 ASCII 码是否为字符 'x' (小写 x)
    je hotkey_pressed ; 如果比较结果相等 (X 键按下),跳转到 hotkey_pressed 标签

no_hotkey:
    ret               ; 如果热键未按下,子程序返回

hotkey_pressed:
    ; 在这里编写 TSR 程序的功能代码
    ; 例如:弹出计算器窗口、显示系统信息等
    ret               ; 热键处理程序返回

Lecture10: MASM Code for Interrupts

一个显示在屏幕右上角的后台计时器

.MODEL small
.STACK 100h

.DATA
    ; 注意:TSR运行时DS可能改变,变量存储在代码段
    ; 以下变量通过CS段前缀访问

.CODE
.STARTUP
jmp install_tsr    ; 跳过数据区

    ; 变量存储在代码段 (保持驻留) 
    dseg   db '0',0    ; 当前显示字符
    cntr   db 0        ; 中断计数器
    old_ip dw 0        ; 原中断处理程序IP
    old_cs dw 0        ; 原中断处理程序CS

install_tsr:
    ; 保存原INT 8h中断向量
    cli                 ; 禁用中断
    xor ax, ax
    mov es, ax          ; ES=0000h (中断向量表段) 
    mov bx, 8*4         ; INT 8h向量地址 (8h*4=20h) 

    ; 保存原处理程序地址
    mov ax, es:[bx]
    mov old_ip, ax
    mov ax, es:[bx+2]
    mov old_cs, ax

    ; 设置新中断向量
    mov ax, OFFSET isr
    mov es:[bx], ax
    mov ax, cs
    mov es:[bx+2], ax
    sti                 ; 重新启用中断

    ; 计算驻留内存大小并终止驻留
    mov dx, OFFSET tsr_end  ; DX=程序结束地址
    mov cl, 4
    shr dx, cl           ; 转换为段落 (除以16) 
    inc dx               ; 向上取整
    mov ax, 3100h        ; AH=31h TSR功能,AL=返回码
    int 21h

; 中断服务程序 (ISR) 
isr PROC far
	pushf
    push di
    push si
    push bp
    push ds
    push es

    ; 使用CS段访问变量
    mov bx, cs
    mov ds, bx

    ; 更新计数器
    inc cs:cntr
    cmp cs:cntr, 18      ; 约1秒 (18.2次/秒) 
    jb chain_int

    ; 重置计数器并更新显示
    mov cs:cntr, 0
    inc cs:dseg
    cmp cs:dseg, '9'
    jbe update_screen
    mov cs:dseg, '0'

update_screen:
    ; 直接写入显存B800h
    mov ax, 0B800h
    mov es, ax
    mov di, (79)*2
    mov al, cs:dseg
    mov es:[di], al

chain_int:
    ; 恢复环境并链式调用原中断处理程序
    pop es
    pop ds
    pop bp
    pop si
    pop di
    popf
    jmp cs:dword ptr old_ip  ; 跳转到原处理程序

isr ENDP

tsr_end:   ; 标记TSR代码结束
END

Lecture 11: 内存层次结构:动态与静态随机存储器

内存的层次结构

内存层次结构的重要性

现代计算机系统采用内存层次结构 (Memory Hierarchy) 以平衡 速度成本容量 之间的矛盾。这种结构利用了程序访问数据的局部性原理,通过多层不同特性的存储器协同工作,实现高性能的内存系统。

img

主存储器 (Main Memory)

主存的分类:DRAM 与 SRAM

主存储器 (Main Memory),也常被称为 内存RAM (Random Access Memory),是计算机系统中用于 高速 存储 正在运行的程序和数据 的关键组件.主存储器主要分为两种类型: DRAM (动态随机存取存储器)SRAM (静态随机存取存储器)

静态随机存取存储器 (SRAM)

静态随机存取存储器 (Static Random Access Memory, SRAM) 是一种高速的半导体存储器,其特点包括:

SRAM 存储单元结构图

img

SRAM 访问方式示意图

img

动态随机存取存储器 (DRAM)

动态随机存取存储器 (Dynamic Random Access Memory, DRAM) 是另一种常用的半导体存储器,其特性如下:

DRAM 存储单元结构图

img

4-bit DRAM 结构示意图

DRAM 通常以 阵列形式 组织,例如 4 位 DRAM 结构.通过 激活字线 (Word Line) 来选择 存储单元行,然后通过 列选择 (Column Select) 来选择 特定的位 进行读写操作。

img

DRAM 读写与刷新周期

DRAM 的读写操作

DRAM 的读写操作 流程如下:

  1. 行激活 (Row Activation):通过 激活字线 (Word Line) 选择 存储单元阵列中的一行.这会将选定行中 所有存储单元的数据 读出位线 (Bit Line)
  2. 列选择与数据传输 (Column Select & Data Transfer): 通过 激活列线 (Column Line)列选择信号 (CAS, Column Address Select), 从选定行中 选择特定的列 (即 特定的存储单元)。
  3. 数据写入 (Write)读回 (Readback)
    • 读取模式 (Read Mode)列线被激活,选定存储单元的数据被 输出。同时,读出的数据 会被 写回 (Write Back)存储单元,以 保持数据
    • 写入模式 (Write Mode)列线被激活新的数据 通过 列线写入 到选定的 存储单元

DRAM 刷新 (Refresh)

DRAM 刷新 (Refresh) 是维持 DRAM 数据完整性 的关键操作。

内存封装类型

常见内存封装

内存芯片 采用多种 封装形式 (Package),以适应不同的应用场景和安装需求.常见的内存封装类型包括:

内存封装类型示意图

img


Lecture 12: 内存管理与缓存策略

访问局部性

在计算机科学中,引用局部性,也称为局部性原理,是指处理器在短时间内重复访问同一组内存位置的趋势。引用局部性有两种基本类型——时间局部性空间局部性。时间局部性指的是在相对较短的时间内重复使用特定的数据和/或资源。空间局部性 (也称为数据局部性) 指的是使用相对接近的存储位置中的数据元素。顺序局部性是空间局部性的一种特殊情况,当数据元素以线性方式排列和访问时发生,例如遍历一维数组中的元素。

局部性是计算机系统中发生的一种可预测的行为。表现出强引用局部性的系统非常适合通过使用诸如缓存内存预取以及处理器核心的高级分支预测器之类的技术来进行性能优化。

引用局部性的类型

引用局部性是指程序在执行过程中访问存储器的地址倾向于聚集在某些区域的特性。引用局部性是缓存得以有效工作的理论基础,可以分为两种主要类型:

img

示例

缓存 (Cache)

理解计算机Cache (一) :从块到缓存结构,以及逐步推出映射策略

理解计算机Cache (二) :缓存与内存的交互

缓存的工作原理

**缓存 (Cache)**是一种高速、小容量的存储器,位于 **CPU (中央处理器) **和 **主存储器 (DRAM) **之间,用于缓解 CPU 与主存之间速度不匹配的问题。

总结:缓存的工作原理类似于在处理器和主存之间建立一个“快速通道”,通过存储常用数据,减少了处理器访问慢速主存的次数,从而提高了程序的整体执行速度。

x86 缓存模型

img

典型缓存参数

img

缓存组织方式

缓存控制器包含一个缓存目录 (Cache Directory),用于管理缓存中的数据。常见的缓存组织方式包括:

直接映射缓存 (Direct Mapped Cache)

直接映射缓存的地址映射机制如下 (以 80386 处理器为例):

**内存地址分解 (虚拟地址) **

img

内存访问流程

内存访问流程

  1. CPU 生成虚拟地址: CPU 在执行指令时,生成一个 32 位 (或其他位数) 的虚拟地址,用于访问内存中的数据。
  2. 缓存控制器接收虚拟地址: 缓存控制器拦截 CPU 发出的虚拟地址。
  3. 缓存查找 (使用虚拟地址) : 缓存控制器从虚拟地址中提取:
    • 标记位 (Tag Bits): 用于与缓存目录中的标记进行比较。
    • 块索引位 (Index Bits): 用于在缓存目录中选择对应的条目。
    • 块内偏移 (Offset Bits): 用于在缓存块中选择特定的字节。
      缓存控制器使用索引位在缓存目录中找到对应的条目,并将提取的标记位与该条目中的标记进行比较.同时,检查该缓存行的有效位。
  4. 缓存命中/未命中判断:
    • 缓存命中 (Cache Hit): 如果标记匹配且有效位为真,则发生缓存命中。
    • 数据读取: 缓存控制器使用偏移位从缓存块中读取对应的数据,并将数据返回给 CPU.地址转换到此为止不需要进行。
    • 缓存未命中 (Cache Miss): 如果标记不匹配或有效位为假,则发生缓存未命中。
  5. MMU 地址转换 (仅在缓存未命中时):
    • 缓存控制器将 虚拟地址 发送给 MMU。
    • 物理地址生成: MMU 将虚拟地址转换为物理地址。
  6. 内存访问 (DRAM):
    • MMU 将 物理地址 发送给内存控制器。
    • 内存控制器访问 DRAM,读取所需的数据。
  7. 缓存更新 (在缓存未命中时):
    • 缓存控制器将从 DRAM 中获取的数据存储到缓存中.这可能涉及到缓存行的替换 (Eviction),例如使用 LRU (Least Recently Used) 算法。
    • 缓存控制器更新缓存目录中的标记位和有效位。
  8. 数据返回给 CPU: 缓存控制器将从缓存中读取的数据 (现在数据已经在缓存中了) 返回给 CPU。

抖动 (Thrashing) 问题

**抖动 (Thrashing)**问题在直接映射缓存中尤为突出。

例如,如果程序反复调用地址 0 和地址 32,768,则可能发生颠簸 (thrashing) ,导致缓存命中率严重下降!!!

img

全相联缓存 (Fully Associative Cache)

全相联缓存提供了最大的灵活性,但实现成本和复杂度也最高。

全相联缓存的缺点

  1. 查找速度慢:需要遍历整个缓存目录才能确定缓存是否命中。
  2. 替换策略复杂:当缓存满时,需要复杂的替换策略 (如 LRU) 来丢弃旧数据.LRU 策略的实现需要维护每个缓存行的访问历史信息,增加了硬件开销。

全相联缓存由于实现复杂,成本高昂,在 PC (个人计算机) 中不常使用 (尤其是在 1995 年左右) 。

组相联缓存 (Set Associative Cache)

组相联缓存平衡了直接映射缓存的抖动问题和全相联缓存高成本问题

双路组相联缓存示意图

img

缓存效率

缓存虽然在空间容量上远小于内存,但它比内存快得多,在程序执行速度上起着至关重要的作用。由于缓存的容量有限,只能存储一小部分频繁访问的数据,因此当 CPU 尝试访问的数据不在缓存中时,就会发生缓存未命中 (cache miss) ,此时 CPU 不得不从速度较慢的内存中加载所需数据。

缓存未命中的原因

缓存的效果评估:Amdahl 定律

**Amdahl 定律 (Amdahl's Law)**用于评估通过改进系统资源 (例如使用缓存) 所能获得的性能提升。

Amdahl 定律公式

$Speedup = \frac{1}{(1-p) + \frac{p}{s}}$

公式中:

缓存性能提升示例

假设:

计算加速比

$Speedup = \frac{1}{(1-0.95) + \frac{0.95}{10}} = \frac{1}{0.05 + 0.095} = \frac{1}{0.145} \approx 6.89$

结论:加入缓存后,内存访问速度比仅使用 DRAM 时提高了约 6.89 倍。

有效访问时间 (EAT) 估算

**有效访问时间 (Effective Access Time, EAT)**用于综合评估包含缓存的内存系统的平均访问性能。

EAT 计算公式

$\text{EAT} = (1 - \text{命中率}) \times \text{缓存访问时间} + \text{命中率} \times (\text{缓存访问时间} + \text{未命中惩罚})$

EAT 估算示例

假设:

计算 EAT

$\begin{aligned} \text{EAT} &= (1 - 0.95) \times 10 \text{ns} + 0.95 \times 100 \text{ns} \ &= 0.05 \times 10 \text{ns} + 0.95 \times 100 \text{ns} \ &= 0.5 \text{ns} + 95 \text{ns} \ &\approx 14.5 \text{ns} \end{aligned}$

加速比验证

$\text{加速比} = \frac{\text{DRAM 访问时间}}{\text{EAT}} = \frac{100 \text{ns}}{14.5 \text{ns}} \approx 6.89$

结论:内存系统的有效访问时间约为 14.5 纳秒,相较于 100 纳秒的 DRAM 访问时间,速度提升约为 6.89 倍,与 Amdahl 定律的计算结果一致。

写策略 (Write Policies)

**写策略 (Write Policies)**定义了数据写入缓存时,如何保证缓存和主内存数据一致性的策略。

DMA (直接内存访问) 与缓存一致性

**DMA (Direct Memory Access, 直接内存访问) **允许某些硬件设备 (例如 DMA 控制器) 直接读写主存储器,无需 CPU 的参与.DMA 操作可能导致缓存与主内存之间的数据不一致问题。

多级缓存 (Multilevel Caches)

**多级缓存 (Multilevel Caches)**是现代高性能处理器中常用的缓存组织方式。

示例参数

DMA

**DMA (Direct Memory Access, 直接内存访问) **技术允许某些硬件设备 (例如 DMA 控制器) 直接读写主存储器,无需 CPU 的参与。

DMA 控制器 (DMA Controller)

**DMA 控制器 (DMA Controller) **是实现 DMA 传输的关键硬件组件。

DMA 控制器结构示意图

img

DMA 传输序列 (DMA Sequence)

DMA 控制器通过一系列握手信号与 CPU 和外围设备协同工作,完成 DMA 数据传输。

  1. **DMA 请求:外围设备 (例如智能磁盘控制器) 准备好数据后,设置 DREQ 信号线为高电平,请求 DMA 传输。
  2. **HOLD 请求:DMA 控制器接收到 DREQ 信号后,向 CPU 发送 HOLD 请求信号 (HOLD)。
  3. HOLD 响应:CPU 在完成当前总线周期后,释放总线控制权,并将 HLDA 信号线拉高,响应 DMA 请求。
  4. 总线控制权转移:DMA 控制器接管数据总线、地址总线和控制总线的控制权.CPU 暂时与内存断开连接。
  5. DMA 确认:DMA 控制器向外围设备发送 DMA 确认信号 (DACK),允许设备开始 DMA 传输。
  6. 数据传输:外围设备 (例如智能磁盘驱动器) 通过 DMA 控制器直接向主内存写入数据或从主内存读取数据。
  7. HOLD 释放:DMA 传输完成后,DMA 控制器释放 HOLD 请求。
  8. CPU 恢复总线控制:CPU 重新获得总线控制权,HLDA 信号线被拉低。

ROM (只读存储器)

**ROM (Read-Only Memory, 只读存储器) **是一种非易失性存储器,断电后数据不会丢失.ROM 通常用于存储固件 (Firmware) 和引导代码 (Boot Sequence Code),例如 BIOS (基本输入/输出系统)。

ROM 的类型

EPROM 编程与擦除原理示意图

img

2716 EPROM 引脚图

img

ROM 组合 (或与其他类型存储器组合)

ROM 芯片 (或其他类型的存储器芯片) 可以通过芯片选择 (CS, Chip Select) 信号线和多路复用器 (Demultiplexer) 组合在同一内存空间中。

ROM 组合应用示意图

img

虚拟内存 (Virtual Memory)

【CSAPP-深入理解计算机系统】9-1. 虚拟内存

虚拟内存的概念

**虚拟内存 (Virtual Memory)**是一种内存管理技术,将磁盘 (硬盘) 的一部分作为内存的扩展来使用,使得程序可以访问比实际物理内存更大的地址空间。

虚拟内存的工作原理

虚拟内存的性能


Lecture 13 A: 磁盘与CD-ROM

机械硬盘的结构

img

在每一个盘片上有多个磁道,每个磁道可以分为多个扇区,通常情况下,每个扇区可以存储 512 byte 的数据

img

编码方式

两个事实:

FM 编码

img

在 FM 编码中,每个位周期 (Bit Cell) 都包含一个时钟转换 (Clock Transition) ,位于位周期的起始位置。

锁相环

一个能从数据信号中提取时钟信号的装置

MFM 编码

img

MFM 编码减少了磁通转换的次数,这意味着在单位时间内需要写入的磁通变化更少。这降低了对磁记录系统的带宽要求,并减少了因频繁转换而引起的信号失真。

RLL 编码

img

RLL 编码通过限制连续的 0 (零) 的数量来优化磁记录过程。说是比 MFM 编码好 40%

性能参数

访问时间 (Access Time): 从请求数据到接收到数据之间的时间,通常为 20 mS。

寻道时间 (Seek Time): 磁头移动到特定位置所需的时间,通常为 12 mS。

延迟时间 (Latency Time): 例如锁相环 (PLL) 等开始从磁道读取数据所需的时间,为 8 mS。

传输速率 (Transfer Rate): 从磁盘以持续速率读取数据的速率。10 Mbits/Sec (硬盘 HD),1 Mbit/sec (软盘 Floppy)。

磁道/扇区格式

img

磁道,扇区上面会存储一些控制信息

磁盘控制器

img

磁盘有一个自己的控制器来响应 CPU 的 I/O 操作,并且维护磁盘逻辑块号和物理磁盘扇区的关系

差错检测与纠正

最简单的就是直接记录 校验和,复杂一点就上 CRC 或者 汉明码

磁盘格式

  1. 磁盘引导
  2. 文件分配表
  3. 文件分配表副本
  4. 根目录
  5. 数据区

FAT/簇

FAT 是一种简单且广泛使用的文件系统,簇是 FAT 文件系统用于存储数据的最小单位。 一个簇由一个或多个连续的扇区组成。其硬盘大小限制是 2GB,簇大小限制是 32,768 bytes,至少需要一个簇来存储文件,所以假如簇很大却存了一个很小的文件,会导致浪费

FAT 32 是 FAT 16 的升级,最大支持 268435456 个簇,适用于较大的硬盘

FAT 32 有回收站机制

根目录

字节编号 (Byte Number)

根目录标识特定文件的 FAT 中的第一个簇,FAT 的第一个簇入口将包含第二个簇的簇号。此过程会持续进行,直到链接足够的簇以包含文件大小。 (很像链表)

长这样:

img

连接方式

IDE (Integrated Disk Electronics)

SCSI (Small Computer Systems Interface)

RAID 磁盘阵列

img

光盘

img

单层DVD的容量为4.7GB,CD的容量为680MB,而双面双层DVD的容量可达17GB,CD既可以通过母盘复制/压制进行批量生产,也可以使用CD-R或CD-RW技术进行单独创建。


Lecture 13 B: 硬件保护

I/O 结构

微处理器 (µP) 通过 UART (通用异步收发器) 与外部设备进行数据传输,UART 里面有一个缓冲区能加快数据传输。img

同步 I/O

在同步 I/O 中,应用程序发起 I/O 操作后,必须等待 I/O 操作完成才能继续执行后续代码。 也就是说,应用程序会被 阻塞 在 I/O 操作上,直到数据传输完成。

img

异步 I/O

在异步 I/O 中,应用程序发起 I/O 操作后, 无需等待 I/O 操作完成就可以继续执行后续代码。 操作系统或 I/O 设备会在后台执行 I/O 操作,并在操作完成后通过中断等机制通知应用程序。

img

硬件保护

CPU允许两种操作模式。在寄存器中的一个位设置了CPU正在运行的模式。

在用户模式下,应用不能切换到监控模式。操作系统在启动用户程序之前,会先切换到监控模式,然后创建一个新的进程或线程,并将控制权交给该进程或线程。只有在监控模式下才能使用能够危害其他程序的特权指令。因此只有通过操作系统,用户程序才能和硬件交互

img

内存保护

恶意程序在没有内存保护的情况下能直接修改中断向量表,造成严重的系统异常!!!

CPU 保护

操作系统理念有一个计时器,规定了一个程序最长能占用的CPU周期,防止某个进程霸占 CPU 导致系统崩溃,计时器中断触发会保存当前上下文,然后把控制权交给下一个进程


Lecture 14: CISC/RISC 向量处理器与并行处理器

RISC vs CISC

CISC (Complex Instruction Set)

核心理念:通过丰富的指令集和寻址方式,尽可能地用一条指令完成复杂的任务。

RISC (Reduced Instruction Set)

核心理念:简化指令集,使用少量、简单、定长的指令,并通过优化指令执行流程来提高整体性能。

CISC 和 RISC 在追求更好性能时的策略

CISC 和 RISC 实现乘法

RISC 实现乘法

.STARTUP

mov ax, 0        ; 初始化结果寄存器 AX 为 0
mov dx, 100      ; 乘数 100 放入 DX 寄存器
mov bx, 123      ; 被乘数 123 放入 BX 寄存器
mov cx, 8        ; 循环次数设置为 8 (假设进行 8 位乘法)

back:
    rcr dx, 1    ; 将 DX 寄存器最低位循环移入 CF (进位标志位)
    jnc over     ; 如果 CF = 0 (最低位为 0),则跳转到 over 标签
    add ax, bx   ; 如果 CF = 1 (最低位为 1),则将 BX 累加到 AX (部分积)

over:
    shl bx, 1    ; 将 BX 寄存器左移一位,相当于乘以 2
    loop back    ; 循环计数器 CX 减 1,如果 CX != 0,则跳转到 back 标签继续循环

call Print
.EXIT

CISC 实现乘法

.STARTUP

mov dl, 100    ; 乘数 100 放入 DL 寄存器
mov al, 123    ; 被乘数 123 放入 AL 寄存器

mul dl         ; 执行乘法指令 mul,AL * DL,结果存储在 AX 寄存器

call Print
.EXIT

流水线

早期 CPU 执行一条指令从出生到入土,非得霸占整个逻辑处理单元不撒手。Fetch, Decode, Execute 三兄弟明明能各干各的,非得搞什么"一条龙服务"——结果就是ALU天天摸鱼,寄存器天天加班。图灵的在天之灵振臂高呼:杂鱼 CPU 就应该狠狠的填满🥵,上流水线!

流水线执行:时间管理大师の骚操作

  1. 周期1:Ins.1刚扒上Fetch的窗口,CPU就开始偷瞄下一条
  2. 周期2:Ins.1在Decode里翻来覆去,Ins.2已经蹲在Fetch门口催单
  3. 周期3:Ins.1终于Execute,后面俩小弟Ins.2/3直接卡成贪吃蛇
  4. 周期4:Ins.1 Execute 完了,提起裤子直接跑了,轮到 Ins.2 上场接力

img

img

【奔腾の骚操作手册】

流水线の黑暗面:你以为的效率革命,其实是 CPU 的血泪史

1. 资源冲突:CPU版《鱿鱼游戏》

2. 控制依赖:薛定谔的跳转指令

3. 数据依赖:套娃式死亡连环call

浮点运算の流水线魔法:从牛车到高铁的骚操作

标量运算の原始社会:

流水线の工业革命:

周期 C (Check if Zero) S (Shift) A (Add) N (Normalize)
1 加法 1
2 加法 2 加法 1
3 加法 3 加法 2 加法 1
4 加法 4 加法 3 加法 2 加法 1
5 加法 5 加法 4 加法 3 加法 2
6 加法 6 加法 5 加法 4 加法 3
7 加法 6 加法 5 加法 4
8 加法 6 加法 5
9 加法 6

(拍黑板)看见没?资本家CPU的终极奥义:

假如还有这个屠龙宝剑,计算8个加法甚至只要5周期!

img

向量处理

例如要计算 $\begin{bmatrix}1\2\3\end{bmatrix}+\begin{bmatrix}3\4\5\end{bmatrix}=\begin{bmatrix}4\6\8\end{bmatrix}$ 使用标量处理至少需要3个周期,但是加上流水线和并行处理可能能在一个周期内解决

M. Flynn 并行处理器分类

多处理器

共享内存,受限于内存带宽,不能做到很大的规模

img

多计算机

每个处理器由自己独立的内存,说白了就是分布式系统,通过PVM来交换数据

img

拓扑架构

img

超标量处理器

一次能执行多条指令的 CPU,前提是指令之间不存在依赖或者冲突关系

好的,我将根据您提供的信息,对并行系统进行重写,力求更清晰、准确和易懂:

并行系统

并行系统本质上是由多个处理器组成的计算系统,旨在通过同时执行多个任务来提高性能和可靠性。 它们可以被视为多处理器系统,具有以下关键特征:

并行系统的分类

根据处理器之间的关系和任务分配方式,并行系统可以分为以下几种类型:

并行系统的优点


Lecture 15: 总线

总线

总线 (Buses) 是一组共享的通信线路,用于连接计算机的不同组件,并提供使用该线路的标准。

计算机总线

img

总线时序 (Bus Timing)

在任何一个时间点,只能有一个设备可以发送数据,所有其他设备必须监听或忽略数据。 发送控制信息的设备被称为主设备 (master),其他单元被称为从设备 (slave),总线会产生瓶颈。

PC 总线

PC 中的主要总线类型:ISA 和 PCI

早期的 PC 中主要有两种总线:ISA 和 PCI。

img

争用

像计算机上的地址总线这样的单向总线易于实现。 CPU 产生地址,所有设备监视地址线路。

但是数据总线这样的一些总线需要双向传输数据。如果两个输出连接在一起,结果称为争用。 小则数据损坏,严重就直接把电路烧了,就像这样:

img

电流吸收逻辑

当然也可以这样,接一个上拉电阻,限制最大电流,这样就不会烧坏电路了,不过这种方案有速度慢和浪费电力等缺点

img

使用三态缓冲器

三态设备用另一根控制线来断开设备与总线的连接。当断开连接的时候,它的输入阻抗 (High-impedance) 变得非常大,这样就能避免总线争用的情况了。

img

仲裁 (Arbitration)

不同设备可能希望同时使用总线,这个时候需要总线仲裁用于避免总线上的冲突或竞争。

级联 (Cascading)

当设备想要使用总线时,它会拉高 Request 信号。 如果 Busy 信号为高电平,表示总线正忙,控制器将忽略新的 Request 信号。 反之,如果 Busy 信号为低电平,控制器则发送 Grant 信号给该设备,允许其使用总线。 收到 Grant 信号后,设备会立即拉高 Busy 信号,并将数据放到总线上传输。

img

轮询 (Polling)

当设备想要使用总线时,它会拉高 Request 信号。 一旦收到请求,控制单元就开始挨个查看轮询线,看看哪个设备想要用总线。 找到了想用的,就把 Busy 信号拉高,然后把数据线连通,让这个设备用。

通俗一点来就像点名一样:设备想用总线先举手 (发出请求)。然后控制器一个一个地问:“1 号,你要用总线吗? 2 号,你要用总线吗? 3 号,你要用总线吗?...”,一旦点到某个举手的设备,控制单元就说:“好,给你用!” 然后把 Busy 信号设为“忙碌”,并把数据线连通,让这个设备传输数据。“点名”的顺序决定了谁先被服务,也就是谁的优先级最高。 如果 1 号总是先被点到,那么 1 号的优先级就最高。

img

独立请求 (Independent Request)

每个外设单元都有单独的请求线 (Request) 和授权线 (Grant)。优先级由总线控制单元来决定。不过缺点就是比较复杂,因为每个单元都需要单独的请求线和授权线。

img


Lecture 16: 闪存与 FPGA

闪存

闪存 (Flash) 的存储单元包含一个带控制栅和浮动栅的存储晶体管。浮动栅通过薄氧化层与晶体管隔离,用于存储电荷并控制电流。

img

NAND Flash VS NOR Flash

Flash RAM 分为 NOR 和 NAND Flash 存储器。

SSD

基于 Flash 的介质基于硅基板,因此被称为固态设备。有很多种接口:2.5"SATA, mSATA, M.2, PCle Add-In Card

img

FPGA

现场可编程逻辑门阵列(英语:field-programmable gate array,缩写为FPGA)以PAL、GAL、CPLD等可编程逻辑器件为技术基础发展而成。作为特殊应用集成电路中的一种半定制电路,它既弥补全定制电路不足,又克服原有可编程逻辑控制器逻辑门数有限的缺点。可以利用逻辑合成和布局、布线工具软件,快速地刻录至FPGA上进行测试,这一过程是现代集成电路设计验证的技术主流。这些可编程逻辑组件可以被用来实现一些基本的逻辑门数字电路(比如与门、或门、异或门、非门)或者更复杂一些的组合逻辑功能,比如译码器等。在大多数的FPGA里面,这些可编辑的组件里也包含记忆组件,例如触发器(Flip-flop)或者其他更加完整的记忆块,从而构成时序逻辑电路。

系统设计师可以根据需要,通过可编辑的连接,把FPGA内部的逻辑块连接起来。这就好像一个电路试验板被放在了一个芯片里。一个出厂后的成品FPGA的逻辑块和连接可以按照设计者的需要而改变,所以FPGA可以完成所需要的逻辑功能。

FPGA一般来说比特殊应用集成电路(ASIC)的速度要慢,无法完成更复杂的设计,并且会消耗更多的电能。但是,FPGA具有很多优点,比如可以快速成品,而且其内部逻辑可以被设计者反复修改,从而改正程序中的错误,此外,使用FPGA进行调试的成本较低。厂商也可能会提供便宜、但是编辑能力有限的FPGA产品。因为这些芯片有的可编辑能力较差,所以这些设计的开发是在普通的FPGA上完成的,然后将设计转移到一个类似于专用集成电路的芯片上。在一些技术更新比较快的行业,FPGA几乎是电子系统中的必要部件,因为在大批量供货前,必须迅速抢占市场,这时FPGA方便灵活的优势就显得很重要。

FPGA (Field Programmable Gate Array) 是一种 SSD 设备。通过硬件描述语言 (HDL) 描述的电路,可以烧录到FPGA上,在原型设计产品(如微波炉或洗衣机)时,工程师可以为 FPGA 编写软件来测试系统的功能,对于大众消费产品,使用 FPGA 进行原型设计更便宜,因为 HDL 程序可用于设置掩模以构建特定应用集成电路 (ASIC) 芯片,该芯片的生产成本非常低。

FPGA 结构

img

Verilog

有几种 HDL,但最常用于教学的是 Verilog。与工业中使用的 VHDL 不同,Verilog 是一种更易于学习的语言,并且可以执行 VHDL 可以执行的几乎所有功能。

用 Verilog 编写的 SR 锁存器的简单结构描述

module SRlatch(
  output Q, Q_bar,
  input S, R);
  nor N1(Q_bar, S, Q);
  nor N2(Q, R, Q_bar);
endmodule

The End ~~~ : )