韦东山老师 RTOS 入门课程(一)RTOS 介绍,熟悉裸机的汇编逻辑

韦东山老师 RTOS 入门课程

课程链接:韦东山直播公开课:RTOS实战项目之实现多任务系统 第1节:裸机程序框架和缺陷_哔哩哔哩_bilibili

RTOS 介绍

裸机:固定顺序执行。

中断:可以一直专心做循环里的事情,直到触发中断。也可以中断里设立 flag 在循环里检测执行,防止中断超时。

定时器:太多个任务的时候不适合说都用中断。可以用定时器,设定不同任务的执行频率,比如 A 1ms 执行一次,B 2ms 执行一次…… 但是相互之间会有影响,比如 A 卡住了会影响 B。

还有一种解决办法是状态机。每个函数设定几个状态,每次执行一部分状态后保留当前状态退出,下次进入的时候继续执行。

image-20230818232306800

状态机有四大概念:状态,事件,动作,变换。

状态就是不同的状态。

事件是执行某个操作的触发条件,比如门开状态我发起关门事件,门关事件我发起开门事件。

动作是由事件触发额具体行为。

变换是状态之间的切换。

状态机忒麻烦而且也没有那么优。

RTOS 比如可以设定每个程序按一定时间片执行,到时间自己切换,不用自己写状态机那么复杂。而且现在 RTOS 生态比较好(特别是 rt-thread),而且大多数开发都需要 RTOS 。其实用了 RTOS 反而更简单。

ARM 基础

程序是什么?

运行程序时,先把程序烧录到 flash 文件中,数据放入 RAM 中(可变),CPU 读指令取数据写数据。RAM 中的数据是拿到了 CPU 的寄存器中。

这里我们重点关注6条 arm 指令即可。

  1. 读指令。LDR R0,[R1,#4],指明了 rd, rs, length。LDR 是固定取 4B,从 R1+4 地址取。
  2. 写指令。STR R0,[R1,#4]
  3. 加减。ADD R0,R1,R2 ADD R0,R0,#1 SUB R0,R1,R2
  4. 比较。CMP R0,R1 结果存在 PSR 中。
  5. 跳转 B BL ,BL 是跳转后还保存返回地址。

分析C的汇编码,理解程序

image-20230819133726104

用一个很简单的程序来举例,Keil 进入调试模式后可以看到对应代码的汇编码。

首先通过 PUSH 指令自动压栈 r3 lr 并修改 sp 指针,保存 r3 寄存器和函数返回地址

第二句令 r0 = a 的地址。

第三句根据地址取出 a 的值存入 r0.

第四句 r0 的值存入栈0的位置,因为刚才压栈后,栈中从高到低分别存了 lr r3,也就是说r0 实际上是把数据存入栈中 r3 的位置,r3 入栈是在栈中占了一个栈中的位。

然后出栈,lr 赋值给 pc 以供函数返回,r3 获取到栈中写入的值。

再看第二个程序:

int add_val(int *pa, int *pb)
{volatile int tmp;tmp = *pa;tmp += *pb;return tmp;
}int mymain()
{volatile int a = 1;volatile int b = 2;volatile int c;c = add_val(&a, &b);return 0;
}

汇编得到的代码(在 .dis 文件中):

    i.mymainmymain0x08000372:    b50e        ..      PUSH     {r1-r3,lr}0x08000374:    2001        .       MOVS     r0,#10x08000376:    9002        ..      STR      r0,[sp,#8]0x08000378:    2002        .       MOVS     r0,#20x0800037a:    9001        ..      STR      r0,[sp,#4]0x0800037c:    a901        ..      ADD      r1,sp,#40x0800037e:    a802        ..      ADD      r0,sp,#8 ;传参0x08000380:    f7ffffca    ....    BL       add_val ; 0x80003180x08000384:    9000        ..      STR      r0,[sp,#0]0x08000386:    2000        .       MOVS     r0,#00x08000388:    bd0e        ..      POP      {r1-r3,pc}0x0800038a:    0000        ..      MOVS     r0,r0i.add_valadd_val0x08000318:    b508        ..      PUSH     {r3,lr}0x0800031a:    4602        .F      MOV      r2,r00x0800031c:    6810        .h      LDR      r0,[r2,#0]0x0800031e:    9000        ..      STR      r0,[sp,#0]0x08000320:    6808        .h      LDR      r0,[r1,#0]0x08000322:    9b00        ..      LDR      r3,[sp,#0]0x08000324:    4418        .D      ADD      r0,r0,r30x08000326:    9000        ..      STR      r0,[sp,#0]0x08000328:    9800        ..      LDR      r0,[sp,#0]0x0800032a:    bd08        ..      POP      {r3,pc}

可见几个函数参数 r0 r1… 来传入,超过 r3 的一般压栈,这是一个约定俗成的标准,直接传入的参数不超过4个。

参数问题,我们再尝试第二个代码:传入4个参数的 add。

程序:

int add_val(int a, int b, int c, int d)
{return a+b+c+d;
}int mymain()
{volatile int a = 1;volatile int b = 2;volatile int c = 3;volatile int d = 4;volatile int sum;sum = add_val(a,b,c,d);return 0;
}
i.mymainmymain0x0800036a:    b500        ..      PUSH     {lr}0x0800036c:    b085        ..      SUB      sp,sp,#0x140x0800036e:    2001        .       MOVS     r0,#10x08000370:    9004        ..      STR      r0,[sp,#0x10]0x08000372:    2002        .       MOVS     r0,#20x08000374:    9003        ..      STR      r0,[sp,#0xc]0x08000376:    2003        .       MOVS     r0,#30x08000378:    9002        ..      STR      r0,[sp,#8]0x0800037a:    2004        .       MOVS     r0,#40x0800037c:    9001        ..      STR      r0,[sp,#4]0x0800037e:    e9dd3201    ...2    LDRD     r3,r2,[sp,#4]0x08000382:    e9dd1003    ....    LDRD     r1,r0,[sp,#0xc]0x08000386:    f7ffffc7    ....    BL       add_val ; 0x80003180x0800038a:    9000        ..      STR      r0,[sp,#0]0x0800038c:    2000        .       MOVS     r0,#00x0800038e:    b005        ..      ADD      sp,sp,#0x140x08000390:    bd00        ..      POP      {pc}0x08000392:    0000        ..      MOVS     r0,r0

存入 lr r3 r2 r1 r0 后,从低到高地址加载 r3 r2 r1 r0(大概是因为输入入栈顺序和函数参数顺序是反的),然后跳转。

i.add_valadd_val0x08000318:    b510        ..      PUSH     {r4,lr}0x0800031a:    4604        .F      MOV      r4,r00x0800031c:    1860        `.      ADDS     r0,r4,r10x0800031e:    4410        .D      ADD      r0,r0,r20x08000320:    4418        .D      ADD      r0,r0,r30x08000322:    bd10        ..      POP      {r4,pc}

这里涉及到了函数中的寄存器保护。最近在看 MIPS 的体系结构,那里面是分了不同的寄存器(t,s,a……)arm 也是有不同作用之分。

r0-r3 传参。r13 sp,r14 lr,r15 pc。

传参的三个函数随意使用,无需保护,返回的时候值不同了也没关系。r4-r11 也可以用,但是得保存和恢复。上例中 add 函数就使用了 r4.

比如,如果代码改为:

int add_val(int a, int b, int c, int d)
{// 故意使用R4register int sum asm("r4");sum = a+b+c+d;return sum;
}

汇编:

    i.add_valadd_val0x08000318:    b530        0.      PUSH     {r4,r5,lr}0x0800031a:    4604        .F      MOV      r4,r00x0800031c:    1865        e.      ADDS     r5,r4,r10x0800031e:    4415        .D      ADD      r5,r5,r20x08000320:    18e8        ..      ADDS     r0,r5,r30x08000322:    bd30        0.      POP      {r4,r5,pc}

r5 相当于中间计算结果,他和 r4 都要回复。

中断处理

保存现场-处理中断-还原现场,继续源程序执行。要保存哪些寄存器?

  • 首先参数寄存器要存,不然函数还没处理参数呢来个中断参数丢了。

  • r4-r11 要保存,不然函数还没压栈保存呢这些丢了找不回来了,没法还原了。

  • lr 要保存,一样道理,没压栈的时候 lr 被修改了就没法跳转回原位置了。

实际上,发生中断的一瞬间所有寄存器都要存!

我们调用的 c 中断处理函数只能保证 r4-r11 不被破坏,所以如果想保证所有寄存器都能被保存,调用 c 函数之前就要保存。硬件自动保存其他寄存器.

恢复的时候也是硬件自动恢复其他寄存器,c 函数保证恢复 r4-r11.

硬件要保存的寄存器有 r0-r3,r12,lr,当前中断返回位置。一个典型的误区是,lr 不就是当前中断返回位置吗? 并不是。比如 main 函数调用 A 函数,A 函数执行到一半发生了中断,这时 lr 里的值是 A 函数返回到 main 函数所需的位置地址,中断返回到 A 函数的地址需要再单独保存。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/49366.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

IntelliJ IDEA 官方网站 idea官网 http://www.jetbrains.com/idea/

IntelliJ IDEA 官方网站 idea官网 http://www.jetbrains.com/idea/ Idea下载官网一键直达: 官网一键直达

01、Cannot resolve MVC View ‘xxxxx前端页面‘

Cannot resolve MVC View ‘xxxxx前端页面’ 没有找到对应的mvc的前端页面。 代码&#xff1a;前端这里引入了 thymeleaf 模板 解决&#xff1a; 需要添加 thymeleaf 的依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>s…

阿里云ECS服务器安装PostgreSQL

1. 概述 PostgreSQL是一个功能强大的开源数据库&#xff0c;它支持丰富的数据类型和自定义类型&#xff0c;其提供了丰富的接口&#xff0c;可以自行扩展其功能&#xff0c;支持使用流行的编程语言编写自定义函数 PostgreSQL数据库有如下优势&#xff1a; PostgreSQL数据库时…

【ThingJS | 3D可视化】开发框架,一站式数字孪生

博主&#xff1a;_LJaXi Or 東方幻想郷 专栏&#xff1a; 数字孪生 | 3D可视化框架 开发工具&#xff1a;ThingJS在线开发工具 ThingJs 低代码开发 ThingJs 低代码开发注意点场景效果配置层级层级常用API实例化 Thing&#xff0c;加载场景load 加载函数ThingJs 层级关系图查找层…

山西电力市场日前价格预测【2023-08-24】

日前价格预测 预测明日&#xff08;2023-08-24&#xff09;山西电力市场全天平均日前电价为319.98元/MWh。其中&#xff0c;最高日前电价为370.78元/MWh&#xff0c;预计出现在19: 30。最低日前电价为272.42元/MWh&#xff0c;预计出现在12: 45。 价差方向预测 1&#xff1a; 实…

港联证券|燃气板块午后走高,美能能源涨停,水发燃气大幅拉升

燃气板块21日午后快速拉升&#xff0c;到发稿&#xff0c;美能动力涨停&#xff0c;水发燃气涨超7%&#xff0c;蓝天燃气涨超5%&#xff0c;贵州燃气涨逾4%。 消息面上&#xff0c;受澳大利亚LNG工厂罢工忧虑影响&#xff0c;欧洲基准天然气价格一度大涨18%。 有报导称&#x…

记录:ubuntu20.04+ORB_SLAM2_with_pointcloud_map+ROS noetic

由于相机实时在线运行需要ROS&#xff0c;但Ubuntu22.04只支持ROS2&#xff0c;于是重装Ubuntu20.04。上一篇文章跑通的是官方版本的ORB_SLAM2&#xff0c;不支持点云显示。高翔修改版本支持RGB-D相机的点云显示功能。 高翔修改版本ORB_SLAM2&#xff1a;https://github.com/ga…

linux 安装 kibana

首先下载 kibana https://www.elastic.co/cn/downloads/kibana 然后上传到linux /usr/local 目录下解压安装 修改config/kibana.yml 配置文件&#xff0c;将elasticsearch.hosts 然后再nginx 中做一个端口映射&#xff0c;实现在浏览器中输入后xxxx:5602 nginx 可以将请求转发…

【LeetCode】224. 基本计算器

224. 基本计算器&#xff08;困难&#xff09; 方法&#xff1a;双栈解法 思路 我们可以使用两个栈 nums 和 ops 。 nums &#xff1a; 存放所有的数字ops &#xff1a;存放所有的数字以外的操作&#xff0c;/- 也看做是一种操作 然后从前往后做&#xff0c;对遍历到的字符做…

Docker搭建Redis集群

Docker搭建Redis集群 一 、搭建Redis集群的优点 先说说单个redis的缺点&#xff1a; 1、单个redis具有不稳定性。当redis服务死机了或者redis服务被kill掉了&#xff0c;就没有可用的redis服务了。 2、单个redis的读写能力是有限的。 再根据单个redis服务的缺点谈谈redis集群…

借助frp的xtcp+danted代理打通两边局域网p2p方式访问

最终效果 实现C内网所有设备借助c1内网代理访问B内网所有服务器 配置公网服务端A frps 配置frps.ini [common] # 绑定frp穿透使用的端口 bind_port 7000 # 使用token认证 authentication_method token token xxxx./frps -c frps.ini启动 配置service自启(可选) /etc/…

计算机视觉:比SAM快50倍的分割一切视觉模型FastSAM

目录 引言 1 FastSAM介绍 1.1 FastSAM诞生 1.2 模型算法 1.3 实验结果 2 FastSAM运行环境构建 2.1 conda环境构建 2.2 运行环境安装 2.3 模型下载 3 FastSAM运行 3.1 命令行运行 3.1.1 Everything mode 3.1.2 Text prompt 3.1.3 Box prompt (xywh) 3.1.4 Points p…

网络安全--wazuh环境配置及漏洞复现

目录 一、wazuh配置 二、wazuh案例复现 一、wazuh配置 1.1进入官网下载OVA启动软件 Virtual Machine (OVA) - Installation alternatives (wazuh.com) 1.2点击启动部署&#xff0c;傻瓜式操作 1.3通过账号&#xff1a;wazuh-user&#xff0c;密码&#xff1a;wazuh进入wazuh…

系统架构:数据库

文章目录 数据库设计关系代数规范化理论求候选键特殊函数依赖Armstrong公理范式无损分解 数据库设计 步骤产出说明1.根据数据要求和处理要求进行需求分析数据流图、数据字典、需求说明书等分析数据流向、数据详细含义等&#xff0c;分析具体需求2.对现实世界进行抽象&#xff0…

Day3: 前端路由(基础篇)

❝ 「目标」: 持续输出&#xff01;每日分享关于web前端常见知识、面试题、性能优化、新技术等方面的内容。 ❞ ❝ 「主要面向群体&#xff1a;」前端开发工程师&#xff08;初、中、高级&#xff09;、应届、转行、培训等同学 ❞ Day3-今日话题 想必大家经常会在面试中或者工作…

AD域组策略开机脚本客户端不执行:解决方法

本例实现的计算机开机重置本地管理员的密码 1、创建组策略 2、在AD域中添加脚本 3、注意脚本的路径&#xff1a;就是打开 Show Files 目录 4、本例建了2个脚本&#xff0c;一个是用来测试的 &#xff08;1&#xff09;CreateFile.ps1 文件&#xff1a;用来在D盘创建一个 file…

Linux权限

Linux中一切皆文件&#xff0c;那么文件就应该有相对于的类型&#xff0c;而在Linux当中&#xff0c;类型不是直接看后缀来决定的。 -普通文件、文本、可执行、归档文件等d目录b块设备、block、磁盘c字符设备、键盘、显示器p管道文件s网络socket文件l链接文件 link 然后后面的九…

C++入门:引用是什么

目录 1.引用的概念 2.引用的特征 3.常引用 4.引用使用场景 5.传值&#xff0c;传引用效率比较 6.引用与指针的区别 1.引用的概念 引用不是新定义一个变量&#xff0c;而是给已存在变量取了一个别名&#xff0c;编译器不会为引用变量开辟内存空 间&#xff0c;它和它引用…

Can‘t find end of central directory : is this a zip file ? at XMLHttpRequest

导出woed出现这个报错,原因其实很简单,路径写错了, 这个word首先必须是docx格式,然后必须放在public文件包下 如果放在public文件包下还没有用,则放在public包下 参考帖子: https://www.cnblogs.com/hejun26/p/13647927.html

数据结构——栈和队列

栈和队列的建立 前言一、栈1.栈的概念2.栈的实现3.代码示例&#xff08;1&#xff09;Stack.h&#xff08;2&#xff09;Stack.c&#xff08;3&#xff09;Test.c&#xff08;4&#xff09;运行结果&#xff08;5&#xff09;完整代码演示 二、队列1.队列的概念2.队列的实现3.代…