gentleman
发表于 2023-8-30 08:41:59
2023/08/22 第二十三集
跳转太多了不好,会占用指令周期
占用流水线
JLE/JSL等判断Z或CY
CJNEDJNE 这种是老朋友了 8051汇编就很常用的
DJNZ 40H,LABEL1
DJNZ 50H,LABEL2
DJNZ 60H,LABEL
RAM0X400X01
0X500X70
0X600X15
执行后
0X40 0X00
0X50 0X6F
0X60 0X14
其实一般都用这两条做循环
MOV R2,#8
TOGGLE:CPL P1.7
DJNZ R2,TOGGLE
NOP 空指令
机器码 0
1个时钟
PC 指针+1
有些库通过内嵌汇编 打到精准操作,给出精准的NOP
汇编语言的程序设计
keil的帮助手册可以去看看
A251编译器 相对地址
L251链接器 链接到绝对地址
LIB251库,看不见
OH251 生成HEX文件的
gentleman
发表于 2023-8-30 09:17:22
2023/08/22 第二十四集
汇编语言程序设计
汇编注重逻辑
汇编程序是啥
是汇编语言助记符 + 汇编器助记符命令
谁家的汇编都是这两部分
汇编器助记符不翻译成机器指令
例子1:
code 中的四个 立即数搬到edata里面
用C来说 (应该对吧,自己是这样理解的)
short code a = {0x13,0x0,0x2,0x4};
short b;
for(i = 0;i<4;i++)
{
b = a;
}
汇编代码
data_seg1 SEGMENT CODE ;声明个代码段
RSG data_seg1 ;用这个代码段
TABLE: DW 0x0123,0x4567,0x89ab,0xcdef ;用DW 建个表 地址由链接器分频
data_seg2 SEGMENT EDATA ;声明个edata段
RSG data_seg2 ;用这个edata段
STORE: DSW 4 ;整4个空间8个字节
prog_seg SEGMENT CODE ; 代码段
RSEGporg_seg ;用代码段
LJMPmain ;跳主程序
ORG 0x0220 ;跳过中断的区域
main:
MOV DPTR,#TABLE ;指向表首地址
MOV WR0,#STORE ;把整个地址给寄存器
MOV R4,#0x4 ;要循环的次数
CON:
MOV A,#0x0 ; 给累加器 0
MOVC A,@A+DPTR ; 开始指向第一个数据
MOV R2,A ; 放寄存器R2
INC DPTR ; DPTR+1
MOV A,#0X0 ; 又清0
MOV A,@A+DPTR ; 指向后8位
MOV R3,A ; 后8位放R3 由于R2 R3组成WR2
MOV @WR0,WR2 ; 把WR2中 数据给WR0 中对应的地址
INC DPTR ; 指向code中下一个数据的地址
ADD WR0,#0x2 ; 指向edata放下个放数据的地址
MOV A,R4 ;R4是循环的次数
SUBB A,#0x1 ; A-1
MOV R4,A ; A 放R4
JNZ CON ; 不为零就 跳CON里 这就相当于for循环
NOP ;空指令
为便于理解,给程序添加了逐行注释。
segment段
同名合并
codedata 等
gentleman
发表于 2023-9-1 07:34:45
2023/08/25第二十五集
何老师带着大家复习了一下上节课的汇编程序
code ->edata
查看c的反汇编语言
数据先放到DR8 中
由于不能操作32位
分别放到WR8 WR10
组成32位
MOVWR6,@DR8+0x0006
这里吧DR8 偏移6 搬到WR6寄存器
MOVWR4,@DR8+0x0004
MOVWR2,@DR8+0x0002
MOVWR0,@DR8
这是code区
继续搬,可以看到把数据搬到了 这4个寄存器
MOV@WR10+0x0010,WR4
搬了最高的循环从4开始
在监视窗口看到 搬了1个最高的数据到 STROE 中
DEC 给R7 -1
然后比较CMP R7 是否0
JNC 判断标志位 来决定是否跳转
后面3次循环与这次类似
这是这个搬移的过程 的反汇编分析
补充一下用到的几个指令
SEGMENT
能用 下面这些段
RSEG声明段
DW初始化存储器
前面都一样,后面用了32位拓展汇编指令
MAIN:
MOV DPTR,#TABLE
MOV DPXL,#0FFH
MOV WR0,#STROE
MOVR4,#0x04
CON:
MOVWR6,@DR56
MOV@WR0,WR6
INCDR56,#2
INCWR0,#2
DECR4,#1
JNE CON
可看到 32位拓展的汇编指令能极大的 增加程序的简洁性
8位的汇编要搬到AB来处理,AB 还只有有8位,增加了程序的复杂度
gentleman
发表于 2023-9-1 08:46:13
本帖最后由 gentleman 于 2023-9-1 08:53 编辑
2023/08/25 第二十六集
MOV DPXL ,#01
这条可以指向xdata区域
开始时edta 区域
EBIT
扩展位可寻址
EDATA HDATA
这两个等效
符号
不能数字开头
EQUSET
LABEL:
标号
定义位置 作用跳转或提升可读性
只能定义一次
汇编器标号
表达式与操作数
vvvEQU 3
数字
记得字母前面加0
可加$
可用决定地址 (不完全可用,编译器不让,让用EDATA)
字符
不能超过2个
字符串
KEYMSG: DB 'SDFKLJSDLFKJSLDKFJ SDLJFL'
EOLMSG: DB 'End of line', 00h
位置计数器
ORG 改初值
$ 当前位置计数器
JMP $
优先级
类操作符
讲过好几次了
类运算符
gentleman
发表于 2023-9-1 10:36:56
2023/08/25 第二十七集
控制语句
不产生代码
ALIGN位置计数器设置为下一个地址模2^表达式
确保2^n 边界对齐
51 不用 arm 得用用了有缝隙
EVEN位置计数器指向下一个偶数
ORG 这个太熟了 更改当前段 位置计数器为后续设置原点
ORG 0200H
USING选用哪个寄存器组R0~R73组
PUSH PSW
MOV PSW,#(2 SHL 3)
POP PSW
EQU 定义AR0 要谨慎
DB
MSG: DB 'PRESS A KEY',0
TAB: DB2,3,4,5,6,7,';'
DD32位双字
DW2个字节
DBIT 段保留 几个位
DS /DSB 保留字节
DSD 32位双字(double)
DSW 16位
PROCENDP
子程序
LABEL标号位置
EXTRN/EXTERN 多文件?必须public
PUBLIC 公共符号
CSEGCODE 绝对段
CSEG AT0300H 我说这么眼熟中断号拓展用的这个指令
ISEGIDATA段
RSEG声明可重定义段 上节课的例子用了
SEGMENT
XSEG
BIT 指定位地址
CODE/DATA 定义地址
EQU 只能定义一次
sbit 能用再A251中
SET创建新符号
不能PUBLIC
sfr 定义SFR
_ERROR_指定错误信息
END 结束
汇编接近尾声,c语言即将开始
gentleman
发表于 2023-9-2 08:47:41
2023/08/29 第二十八集
条件汇编
单个源文件 不同版本
$
有个例子 在编译器SET AA = 10
使用$IF
...
$ELSE
..
$ENDIF
通过keil调试 进行测试
不带$
直接使用AA SET 10 指令设置
宏定义
注意宏定义与子程序的区别
宏适合做表不跳转,直接复制一份到下一行, 多次调用增加代码长度
子程序跳转不增加代码长度
A251 3种宏
macro-name MACRO <[> parmeter-list <]
<[> LOCAL local-labels <]>
... ...
macro-body
... ...
ENDM
不调用 不展开
例子
gentleman
发表于 2023-9-2 10:10:15
2023/08/29 第二十九集
汇编实例 -点灯
外设复用理念
解决io不够用的问题
传统跳线 麻烦
晶体管 电压 好用
I/O 寄存器
端口寄存器
PXM0 PXM1
4种模式
上下设置,不是左右组合设置
数据寄存器
PX.Y =0 低电平
PX.Y = 1 高电平
程序要点
DATA 定义寄存器地址
ORG 0x200前面给中断留着
MOV 寄存器复制
用 A 放循环移位初值
ACALL延时子程序
RL 移位
MOV 吧A 搬到 端口数据寄存器
延时子程序
SUBJNE 实现延时
掌握这些,应该就可以独立完成流水灯的程序了。
配合调试可以更清晰的看到程序运行的过程。
gentleman
发表于 2023-9-2 10:23:12
2023/08/29 第三十集
汇编实例-中断
按下按键 灯移动一位
按键按下io被拉低
得出结论
TCON.0=1
TCON.2 =1
EX0 = 1
EX1 = 1
EA = 1
程序新增要点
EQU 定义寄存器位
ORG放中断入口
中断子程序 实现RL/RR
硬件/软件调试 判断是否进入中断
这两节课的代码比较简单,在论坛上都有,就没有抄。
到此mcs-251汇编就已经结束了,刚刚接触大量新增指令集的时候,确实很吃力。
后面结合程序看,就好多了。
当然现在也仅仅能看懂汇编,并不能完成汇编的程序设计。
现阶段的目标也是能看懂汇编,配合c调试时生成的反汇编可以分析错误,分析底层逻辑。
后面学习操作系统时,再来加强对汇编的理解。
gentleman
发表于 2023-9-9 14:39:57
本帖最后由 gentleman 于 2023-9-23 09:00 编辑
发现09/01 的课没有打卡,后面补上了
2023/09/05 第三十四集
C251 限定符
const 运行未修改
volatile 可能会被修改
通常是硬件
const 声明 的可以用xdata/code 指定存储位置 ,定义直接初始化
const 指针 不能改他指向的常数
普通指针 指向常数,改指向的值,不报错,也没效果
特殊用法定义一个不可更改的指针
volatile 不让编译器优化
硬件寄存器不能给优化,优化了寄存器就没配置成功
使用keil 调试,可以直观的看到这些变量定义与运算的过程
单字 双字 直接MOV
4字节 要MOV 两次
gentleman
发表于 2023-9-9 14:53:27
本帖最后由 gentleman 于 2023-9-23 09:00 编辑
2023/09/05 第三十五集
一开始就有干货
看到浮点定义的过程
这个要配合以前讲浮点数的内容理解
去掉volatile
就3行,被编译器优化了
编译器认为a b 没用
只记了结果
后面是个列表求和的例子
再次提到指令高速缓存概念
汇编帮助DEBUG
auto register static extern
这几个都很好理解