🔄 第10课:逻辑与移位

📖 本课目标

深入实现逻辑与移位指令:AND、OR、XOR、NOT、SHL、SHR、ROL、ROR。这些指令是位操作的基石,在I/O控制、数据打包、图形编程中无处不在。我们将实现每种指令的实际应用场景。

🧠 位操作的力量

8位CPU最擅长的事情之一就是位操作。每一个位都有明确的含义——一个LED、一个开关、一个像素。逻辑和移位指令让你精确控制每一位。

位操作典型应用场景 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ AND (位掩码/清零) ┌────────────────┐ │ 1 0 1 1 0 1 0 0│ 原始值 │&1 1 1 1 0 0 0 0│ 掩码(保留高4位) │────────────────│ │ 1 0 1 1 0 0 0 0│ 结果:高4位不变,低4位清零 └────────────────┘ 用途: 提取字节的一部分 OR (位设置) ┌────────────────┐ │ 1 0 1 1 0 0 0 0│ 原始值 │|0 0 0 0 1 1 1 1│ 设置位 │────────────────│ │ 1 0 1 1 1 1 1 1│ 结果:低4位全部置1 └────────────────┘ 用途: 设置特定位为1 XOR (位翻转) ┌────────────────┐ │ 1 0 1 1 0 1 0 0│ 原始值 │^0 0 0 0 0 0 1 0│ 翻转位(bit1) │────────────────│ │ 1 0 1 1 0 1 1 0│ 结果:bit1翻转 └────────────────┘ 用途: 切换/翻转特定位 SHL (乘以2) ┌────────────────┐ │ 0 0 0 0 1 0 1 0│ = 10 │ ← ← ← ← ← ←0│ 左移1位,补0 │────────────────│ │ 0 0 0 1 0 1 0 0│ = 20 (10×2=20 ✅) └────────────────┘ SHR (除以2) ┌────────────────┐ │ 0 0 0 1 0 1 0 0│ = 20 │ 0→ → → → → → │ 右移1位,补0 │────────────────│ │ 0 0 0 0 1 0 1 0│ = 10 (20/2=10 ✅) └────────────────┘

🔧 实际应用——I/O端口位操作

// 场景:控制8个LED,每个LED对应GPIO的一个位

// 打开LED 3 (bit3)
LDA  R1, $FF07    // 读取GPIO数据寄存器
ORI  R1, #0x08    // 设置bit3 = 1
STA  R1, $FF07    // 写回GPIO

// 关闭LED 5 (bit5)
LDA  R1, $FF07
ANDI R1, #0xDF    // 清除bit5 (0xDF = 1101_1111)
STA  R1, $FF07

// 翻转LED 0 (bit0)
LDA  R1, $FF07
XORI R1, #0x01    // 翻转bit0
STA  R1, $FF07

// 测试LED 2是否亮
LDA  R1, $FF07
ANDI R1, #0x04    // 提取bit2
JZ   led_off      // Z=1说明bit2=0(灭)
// LED 2亮

// 组合多个字段
// 高4位=颜色(0-15), 低4位=亮度(0-15)
// 从颜色和亮度合成字节:
SHL  R1          // 颜色左移4位
SHL  R1
SHL  R1
SHL  R1
OR   R1, R2      // 合并亮度(R2)
// R1 = (color << 4) | brightness

🔍 移位指令的进阶应用

快速乘除法

移位是最高效的乘/除2的幂的运算:

// 乘以4 = 左移2次
SHL R1
SHL R1

// 乘以10 = (×8) + (×2)
// R1 × 10
MOV R2, R1     // 保存原始值
SHL R1         // R1 × 2
MOV R3, R1     // R3 = R1 × 2
SHL R1         // R1 × 4
SHL R1         // R1 × 8
ADD R1, R3     // R1 × 8 + R1 × 2 = R1 × 10

循环移位与CRC校验

循环移位(ROL/ROR)在CRC校验计算中是核心操作:

// 简化的CRC-8计算
// 对每个数据字节:
//   8次循环: ROL data, 如果进位=1则XOR多项式
CRC_LOOP:
    ROL  R1         // 循环左移,C ← MSB
    JNC  NO_XOR     // 无进位则跳过XOR
    XORI R1, #0x07  // CRC-8多项式
NO_XOR:
    DEC  R2         // 计数器-1
    JNZ  CRC_LOOP   // 循环8次

📝 练习

练习1:位域提取

从一个8位值中提取bit5-bit3(3位字段),写出指令序列。即:result = (value >> 3) & 0x07

练习2:位反转

实现一个8位值的位反转(bit0↔bit7, bit1↔bit6, ...)。最少需要几条指令?

练习3:软件串行通信

用SHL/SHR实现软件UART发送:将一个8位值逐位输出到GPIO的某一位。画出时序图。

🏆 成就解锁

🔄 位操作专家

达成条件:

奖励:位操作是8位编程的精髓。掌握它们,你就能精确控制硬件的每一个引脚、数据的每一个位。

🔬 位操作的高级技巧

位操作远不止简单的掩码。以下是一些8位编程中的经典技巧:

无分支的条件操作

在某些性能敏感的场景,可以用位操作代替分支:

// 将R1钳制到0-15范围(无分支)
// 如果R1 > 15,则R1 = 15
LDI R2, #15
CMP R1, R2       // R1 - 15
JNN no_clamp     // 如果 < 15, 跳过
MOV R1, R2       // 否则 R1 = 15
no_clamp:

// 用位操作实现取绝对值
// 如果R1是负数(N=1),取反+1
// 如果R1是正数(N=0),不变
// 技巧:利用符号位扩展
// mask = R1[7] ? 0xFF : 0x00
// result = (R1 XOR mask) - mask
// 正数: XOR 0 - 0 = 原值
// 负数: XOR FF - FF = ~R1 + 1 = -R1

快速位计数

计算一个字节中有多少个1(population count):

// 计算 R1 中1的个数,结果在 R2
LDI R2, #0       // 计数器
LDI R3, #8       // 循环8次
COUNT_LOOP:
    SHL R1         // 左移,MSB→C
    JNC no_count   // C=0则不计数
    INC R2         // C=1则计数+1
no_count:
    DEC R3
    JNZ COUNT_LOOP

查找第一个置1的位

在优先级编码器等场景中,需要找到最低位的1的位置:

// 找R1中最低位的1的位置,结果在R2
// 技巧:R1 AND (-R1) = 只保留最低位的1
MOV R2, R1
NEG R2           // R2 = -R1 (取反+1)
AND R2, R1       // R2 = R1 & (-R1)
// 现在R2只有一个1,位于最低位
// 接下来用移位计数确定位置

📊 移位指令应用场景汇总

场景指令说明
乘以2SHL无符号乘2
除以2SHR无符号除2
有符号除以2算术右移保持符号位(需要额外逻辑)
串行数据发送SHL + C逐位输出到GPIO
串行数据接收SHR + C逐位从GPIO读入
CRC校验ROL + 条件XOR循环校验计算
伪随机数XOR + SHL/SHRLFSR线性反馈移位寄存器
图形旋转ROL/ROR精灵图旋转
灰度转换位提取+SHL颜色位提取和重组

📐 逻辑指令的数学性质

布尔代数基础

逻辑运算遵循布尔代数定律,理解这些定律是优化代码的关键:

定律AND形式OR形式
交换律A & B = B & AA | B = B | A
结合律(A&B)&C = A&(B&C)(A|B)|C = A|(B|C)
分配律A&(B|C) = (A&B)|(A&C)A|(B&C) = (A|B)&(A|C)
德摩根~(A&B) = ~A|~B~(A|B) = ~A&~B
吸收律A&(A|B) = AA|(A&B) = A
互补律A&~A = 0A|~A = 0xFF

XOR的特殊性质

XOR有很多独特的性质,使它在密码学和图形编程中特别有用:

// XOR交换两个变量(不需要临时变量)
// R1 ← R1 ^ R2
// R2 ← R2 ^ R1 = R2 ^ R1 ^ R2 = R1
// R1 ← R1 ^ R2 = R1 ^ R2 ^ R1 = R2
XOR R1, R2
XOR R2, R1
XOR R1, R2
// 现在 R1 和 R2 的值已经交换!

🔬 位域打包与解包

在通信协议和文件格式中,数据经常以位域的形式打包。逻辑和移位指令是处理位域的主要工具:

// 将两个4位值打包成一个8位字节
// R1 = 高4位, R2 = 低4位
ANDI R1, #0x0F    // 确保只有4位
ANDI R2, #0x0F
SHL  R1           // 左移4次
SHL  R1
SHL  R1
SHL  R1
OR   R1, R2       // 合并 = (high << 4) | low

// 从8位字节解包两个4位值
// R1 = 打包字节
MOV  R2, R1       // 复制
ANDI R1, #0x0F    // R1 = 低4位
SHR  R2           // 右移4次
SHR  R2
SHR  R2
SHR  R2
// R2 = 高4位

📊 逻辑指令完整参考卡

AND 真值表与用法

ABA&B
000
010
100
111

AND用于:清零特定位(掩码)、测试特定位提取位域

常用掩码:0x01=test bit0, 0x0F=低4位, 0xF0=高4位, 0x7F=去掉bit7, 0xFE=去掉bit0

OR 真值表与用法

ABA|B
000
011
101
111

OR用于:设置特定位为1合并位域

常用值:0x01=set bit0, 0x80=set bit7, 0xFF=all bits

XOR 真值表与用法

ABA^B
000
011
101
110

XOR用于:翻转特定位清零寄存器(A^A=0)简单加密