VCC 发表于 2024-11-2 21:37:12

8051指令集机器代码赏析——逻辑移位与循环移位

本帖最后由 a496298685 于 2024-11-2 21:38 编辑

在关于逻辑移动问题 - 学习打卡区 | 感悟 国芯技术交流网站 - AI32位8051交流社区贴子里,楼主问:
【C语言已经提供了逻辑位移指令<<和>>为什么keil还要在INTRINS.H提供_cror_等指令】


借着这个问题,探究一下8051指令集究竟是如何完成的逻辑移位和循环移位


8051指令集只有如下5个和移位有关的指令



分别是

RL——ACC循环左移1位,例如ACC={B7 B6 B5 B4 B3 B2 B1 B0},执行后ACC变为B6 B5 B4 B3 B2 B1 B0 B7
RR——ACC循环右移1位,例如ACC={B7 B6 B5 B4 B3 B2 B1 B0},执行后ACC变为B0 B7 B6 B5 B4 B3 B2 B1
RLC——ACC带进位C左移1位,例如ACC={B7 B6 B5 B4 B3 B2 B1 B0},执行后ACC变为B6 B5 B4 B3 B2 B1 B0 C,进位标志变为B7
RRC——ACC带进位C右移1位,例如ACC={B7 B6 B5 B4 B3 B2 B1 B0},执行后ACC变为C B7 B6 B5 B4 B3 B2 B1,进位标志变为B0
SWAP——ACC半字节交换(循环移4位),例如ACC={B7 B6 B5 B4 B3 B2 B1 B0},执行后ACC变为B3 B2 B1 B0 B7 B6 B5 B4


下面测试6个案例,看看它们是如何用8051指令集完成的
分别包括:
1. 左移2位
2. 右移2位
3. 右移4位
4. 右移7位
5. 循环右移3位
6. 循环右移1位

一起来感受8051指令集的魅力吧~


案例1
左移2位是如何实现的?

在keil仿真窗口可以看到:

编译器并没有使用任何移位指令

而是:
1. 将原始数据从P0送入累加器A
2. 执行A <--- A+A
3. 执行A <--- A+A
4. 将数据从A送入SFR寄存器P0
其中两步加法实现了A <--- A*4的效果,和左移2位是等效的


案例2
右移2位是如何实现的?

在keil仿真窗口可以看到:

编译器使用了带进位循环右移指令(个人认为带不带进位都是等效的)

具体:
1. 将原始数据从P0送入累加器A,记为{B7 B6 B5 B4 B3 B2 B1 B0}
2. A带符号位循环右移1位,变为{C B7 B6 B5 B4 B3 B2 B1}
3. A带符号位循环右移1位,变为{B0 C B7 B6 B5 B4 B3 B2}
4. 执行A <--- A&0x3F,变为{0 0 B7 B6 B5 B4 B3 B2}
5. 将数据从A送入SFR寄存器P0

案例3
右移4位是如何实现的?

在keil仿真窗口可以看到:

编译器使用了8051特有的SWAP命令,极度简洁!

具体:
1. 将原始数据从P0送入累加器A,记为{B7 B6 B5 B4 B3 B2 B1 B0}
2. A进行半字交换,变为{B3 B2 B1 B0 B7 B6 B5 B4}
3. 执行A <--- A&0xF0,变为{B3 B2 B1 B0 0 0 0 0}
4. 将数据从A送入SFR寄存器P0

案例4
右移7位是如何实现的?

在keil仿真窗口可以看到:

编译器使用了很多条指令

具体:
1. 将原始数据从P0送入累加器A,记为{B7 B6 B5 B4 B3 B2 B1 B0}
2. A进行半字交换,变为{B3 B2 B1 B0 B7 B6 B5 B4}
3. 执行A带进位循环右移,变为{C B3 B2 B1 B0 B7 B6 B5}
4. 执行A带进位循环右移,变为{B4 C B3 B2 B1 B0 B7 B6}
5. 执行A带进位循环右移,变为{B5 B4 C B3 B2 B1 B0 B7}
6. 执行A <--- A&0x01,变为{0 0 0 0 0 0 0 B7}
7. 将数据从A送入SFR寄存器P0

案例5
循环右移3位是如何实现的?

在keil仿真窗口可以看到:

好长啊……

具体:
1. 将原始数据从P0送入寄存器R7,记为{B7 B6 B5 B4 B3 B2 B1 B0}
2. 将立即数3送入寄存器R0
3. 将暂存在R7里P0状态数据送入累加器A【疑问,为什么不在第一步直接将数据送入累加器A呢?】
4. 使寄存器R0自增【疑问,为什么不在第二步直接将数据4送入寄存器R0呢?】
5. R0自减,如果自减后R0≠0,那么执行A循环右移指令(共发生3次移位)
6. 将数据从A送入SFR寄存器P0

案例6
循环右移1位是如何实现的?

在keil仿真窗口可以看到:

似乎和上面的循环右移3位一模一样,唯一区别就是MOV进R0的立即数有变化。看来_cror_这个实现得非常草率啊,没有任何优化

具体:
1. 将原始数据从P0送入寄存器R7,记为{B7 B6 B5 B4 B3 B2 B1 B0}
2. 将立即数3送入寄存器R0
3. 将暂存在R7里P0状态数据送入累加器A【疑问,为什么不在第一步直接将数据送入累加器A呢?】
4. 使寄存器R0自增【疑问,为什么不在第二步直接将数据4送入寄存器R0呢?】
5. R0自减,如果自减后R0≠0,那么执行A循环右移指令(共发生3次移位)
6. 将数据从A送入SFR寄存器P0
页: [1]
查看完整版本: 8051指令集机器代码赏析——逻辑移位与循环移位