5.2 启动阶段的设置

5.2.1 关开门狗

启动阶段喂狗比较麻烦,而且启动阶段都是初始化,看门狗这时的作用不大。根据用户手册,可以找到关看门狗的寄存器,只需要对这个寄存器的第五位写0即可

5.2.2 设置栈调用C语言

首先,C语言中的所有局部变量全都存在栈里,所以在调用C语言程序之前,必须把栈先初始化了。

其次,在初始化栈的时候,因为每个模式下都有自己独立的SP寄存器(R13)所以必须先进入对应的模式下才行,系统在复位后默认是在SVC模式下,我们就不用再另外设置CPSR了。

此外,要注意,手册里面为我们写出了栈的地址及大小,为0xD0037780-0xD0037D7F,此外,在ARM中,默认使用的是满减栈(存的时候先减再存),所以我们这里的栈指针要设置在0xD0037D80处,这样才往里存的时候才先减1移到0xD0037D7F处

5.2.3 cache高速缓存

执行程序时,从 Flash先把程序读到内存里面,然后每执行一条程序,就会从PC指向的内存中把指令读到寄存器,然后再通过寄存器给到CPU去执行,这个时候,对于容量来说,CPU<寄存器<<DDR;对于速度来说,CPU>寄存器>>DDR,所以在工作时,CPU执行完程序后,需要等待DDR慢慢把指令传给寄存器,效率非常低

所以就用一个cache缓存放在寄存器和DDR之间作为中介。容量上来看,CPU<寄存器<cache<DDR,速度来看CPU>寄存器>cache>DDR。当执行程序时,cache会把正在执行的指令的周围几条都拿过来缓存着,当CPU要执行下一条指令的时候,先检查cache里面有没有需要执行的指令,如果有就直接从cache传到寄存器,速度大大提高,如果没有的话就会从内存中重新读取,然后cache清缓存、存入新的一批指令。

这里,我们的内部icache的动作是自动的,不用认为干预,我们只需要程序开启/关闭icache即可,这里就用到了前面汇编指令介绍的CP15协处理器的指令

5.2.4 重定义和链接脚本、位置有关码和位置无关码

程序从源码到可执行程序主要经历以下几个步骤,其中前三个步骤是必须的,其他步骤根据需求可选

① 预编译:主要是去掉宏定义、注释等这些信息(像是洗菜削皮)

② 编译:编译器把.C、.S文件编译成.o文件。.o文件里面是由很多个函数一段一段构成,所以需要第三步(切菜)

③ 链接:把各个函数段链接起来(把菜按先后顺序下锅)

④ strip:把可执行程序中的符号信息去除,从而节省空间

⑤ objcopy:由可执行程序生成可烧录的bin文件

⑥ objdump:由可执行程序反汇编得到汇编程序

了解链接前,先了解一个概念,位置无关码(PIC,position independent code)和位置有关码,就是,汇编源文件被编码成二进制可执行程序时,编码方式和位置(内存)地址是否相关。

设计程序的时候,会给程序指定预期规划的运行地址,此时这个预先指定的地址叫链接地址,将来程序在执行时,必须把程序放在指定的链接地址下面执行,否则不行,这就是位置有关编码。

链接地址:连接时,连接脚本指定的地址

运行地址:程序运行时放的地址

这两个地址必须相同

如果不相同,我们就要通过代码为这段程序重定义位置,让它能正常执行。

这里在哈工大李治军老师的《计算机操作系统》课程中前面linux的启动过程也有提到过代码的重定义这个概念。

而链接地址的决定,可以在makefile中连接到指定地址或者在makefile中指定连接脚本,然后根据链接脚本里面指定的链接地址地址来链接。

使用makefile直接连接时,像下图,链接地址是由makefile中的-Ttext来决定。使用makefile直接规定链接地址时,指令arm-linux-ld -Ttext 0x0 -o led.elf $^中的-Ttext 0x0,就是把程序连接到0x0处

使用连接脚本来链接时,先了解一下链接脚本。链接脚本就是通过段名和地址,为每一个段分配相应的地址和链接顺序,像这里,. = 0xd002400,就是让里的链接起始地址是0xd002400,然后.text表示这里是代码段(放函数编译后生成的东西),大括号指定了代码段开头必须让start.o,然后后面放其他代码段属性的文件,不限顺序;之后是.data数据段(用来放显示初始化为非0的全局变量);然后是. bss段,又叫ZI段即zero initial段(用来放显示初始化为0或者没有初始化的全局变量,这就可以知道为什么全局变量不初始化时默认大小就是0了)。然后他们中间有个bss_start = . 和bss_end = .,这两个变量分别记录了地址值,方便后面计算这个. bss段的大小,或者做其他的用途。另外,要在makefile中指定出使用的链接脚本,如指令arm-linux-ld -Tlink.lds -o led.elf $^中的-Tlink.lds就表示要使用link.lds这个链接脚本

 

这里可能还不明白链接地址和运行地址这两个概念的作用是什么,可以看接下来的代码,实验中,我们把程序通过链接脚本链接到0xd002400处,然后把程序下载到0xd0020010,于是这里的链接地址就是0xd002400,运行地址就是0xd0020010。这两个地址不同,所以只能利用位置无关码在运行位置有关码之前把代码搬到0xd002400处运行。

这里注意,Ldr是伪指令操作pc寄存器时,它是位置有关码,比如ldr pc,=_start,而Adr是位置无关码,比如adr r0,_start

程序中,通过adr r0,_start获取当前运行地址(也就是0xd0020010),通过ldr r1,=_start获取链接地址(也就是0xd002400),然后通过ldr r2,=bss_start获取在链接脚本中定义的bss段起始地址,然后通过复制当前运行地址处的程序到链接地址处,这里我们复制到bss段前面即可,主要原因是:bss段存的全是值为0的全局变量,所以我们只需要把bss的空间长度里的内容全部清零就好了,并不需要再复制一遍了,麻烦。这里我们重定位来的程序bss是自己手动清零的,而下载到0xd0020010的程序中的bss段是在C语言编译器和连接器帮我们在程序前面添加的一段头程序,在main()之前自动清bss,就不需要我们关心了。

接下来看反汇编程序,来分析ldr和adr,根据上面汇编程序的32行、34行、36行,一个adr两个ldr伪指令分别对应下面的15 16 17行。需要注意,这里的PC是当前正在执行指令向后两条的地址,所以应该是前面的值+8,但是!!我们的程序实际下载到的地方是0xd0020010,所以从原理上来说,板子里下载进去的程序是从0xd0020010开始的,每一条指令一条一条按照顺序从0xd0020010往后放,所以PC的地址是运行地址+8,这也就是运行地址的意义。

接着看,第15行,是r0 = pc-36=pc-0x24,来计算一下,按照链接时的定义,pc此时相对于最开头的d0024000偏移量是0xd002401c+0x08-0xd0024000=0x24,所以pc的真实值应该是0xd0020010+0x24 = 0xd0020034,于是计算一下,r0=0xd0020010,就是我们之前下载进去的地址(运行地址),所以可以知道这里的adr反汇编过来的sub只是计算偏移量,是相对跳转

接着看第16行,它的反汇编是由ldr r1,=_start得来,这里的pc+72取的是地址,而指令都是按照顺序排列在一起,所以不管运行地址链接地址如何,pc加上一个值指向的地址肯定是在这段代码里面的同一位置,不信可以计算一下来看看:pc的真实值是0xd0024020+0x08-0xd0024000+0xd0020010 = 0x28+0xd0020010 = 0xd0020038,然后再加上72,就是0xd0020080。然后0xd0020080-0xd0020010得到这个内存空间相对于下载进去的起始地址便宜0x70,所以就可以找到最终程序里对应位置0x70+0xd0024000 = 0xd0024070;这个地方他直接存着一个值,就是d0024000,

分析到这里,我们知道可以看到ldr伪指令得到的数是一个绝对的数值,那么一旦ldr r1,_start里面的操作对象不是r1而是pc,即源程序中的63行,ldr pc,=led_blink,那程序不就直接跳到了实际内存存着不知道是什么东西的0xd0024000的链接地址后面的d0024060了吗,这时程序就会跑飞了,所以ldr伪指令操作PC跳转到某一函数是位置有关码,它对PC的赋值与程序的链接地址有关。

这里,我们把ldr伪指令命令成为长跳转(操作PC)或者长加载(操作通用寄存器),adr命令成为短跳转(操作PC)或者短加载(操作通用寄存器)

5.2.5 外部拓展SDRAM

SDRAM:同步动态随机存储器。SDRAM容量大、价格低、掉点易失、随机读写、总线式访问,使用前必须先初始化(这一点和NAND Flash一样)。DDR是DDR SDRAM,是SDRAM的升级版。(DDR:double rate,双倍速度的SDRAM),还有DDR1 DDR2 DDR3 DDR4 LPDDR等。

我们板子上用的是K4T1G164QE,是DDR2,K表示三星产品,4表示是DRAM,T表示产品号码,1G表示容量(1Gb,等于128MB,我们开发板X210上一共用了4片相同的内存,所以总容量是128×4=512MB)16表示单芯片是16位宽的,4表示是4bank。

在手册中,可以看到S5PV210这块芯片所指定的存储,

DRAM0:内存地址范围:0x20000000~0x3FFFFFFF(512MB),对应引脚是Xm1xxxx

DRAM1: 内存地址范围:0x40000000~0x7FFFFFFF(1024MB),对应引脚是Xm2xxxx

看Port1口,有14根地址线,32根数据线,但是对于我们这块DDR芯片来说,只有16根数据线,我们在使用时,用两块128MB的DDR并联接入,从原理上来看,就和一整块256MB的一样。

看数据手册《NT5TU64M16GG-DDR2-1G-G-R18-Consumer》第10页的block diagram。

210的DDR端口信号中有BA0~BA2,接在内存芯片的BA0~BA2上,这些引脚就是用来选择bank的。共8个bank,每个bank内部有128Mb,通过row address(14位) + column address(10位)的方式来综合寻址。一共能寻址的范围是:2的14次方+2的10次方 = 2的24次方。对应16MB(128Mbit)内存。

初始化SDRAM时,直接使用SOC内的DDR控制器控制即可。在S5PV210的数据手册里,有详细的初始化步骤。

对应的初始化程序:

S5PV210学习笔记——(2) 启动阶段的设置相关推荐

  1. LIteOS学习笔记-7LiteOS启动流程与编译流程

    LIteOS学习笔记-7LiteOS启动流程与编译流程 LiteOS启动流程 1. 启动方式 2. 启动流程 硬件初始化 内核初始化 调试串口初始化 尝试进行网络连接 启动任务调度 LiteOS编译流 ...

  2. Contiki学习笔记——Cooja启动失败

    Contiki学习笔记--Cooja启动失败 Cooja启动 Cooja启动 进入Terminal: cd Contiki/tools/cooja ant run 出现错误: Could not fi ...

  3. 学习笔记 | Heckman两阶段法介绍

    最近看的两篇VC文献,都是有使用到Heckman两阶段法,所以就借此机会系统学习了Heckman两阶段法 本篇内容主要学习了如下文章: 1 CJAR的带你了解Heckman两步法 2 计量经济圈的He ...

  4. 黑马程序员C++学习笔记<第一阶段_基础篇>

    配套视频网址: 黑马程序员:http://yun.itheima.com/course/520.html?bili B站:https://www.bilibili.com/video/BV1et411 ...

  5. [学习笔记] Rocket.Chat 安装与设置启动项

    这篇文章主要介绍手动安装的方式来安装Rocket.Chat,在Rocket.Chat官方有三种安装方式, 面向开发人员的直接使用meteor部署 传统的源码编译安装 Docker方式部署 接下来分别介 ...

  6. php连接tidb,TiDB源码学习笔记:启动TiDB

    作者:院长,神州数码云基地开发工程师,目前专注于TiDB源码研究. TiDB源码研究系列第一篇,简述TiDB的核心架构,从tidb-server/mian.go开始,探索启动TiDB的方法. 最近因为 ...

  7. 涛涛的若依学习笔记——项目启动

    文章目录 前言 1 模块划分 2.项目启动 后端 1. 数据准备 2. nacos 单节点运行 3. Seata启动 4. redis启动 5. 进入nacos修改 yml 配置,主要是数据源 6.启 ...

  8. MySQL学习笔记之启动停止与登录,显示相关信息

    1.MySQL的启动与停止 net start/stop mysql 退出MySQL命令行界面\q (exit) 2.登录 连接本机: mysql -umysql所属用户名 -p密码 [-h用户名] ...

  9. linux0.1x内核代码学习笔记-boot启动

    linux0.11上电时把启动盘第1扇区bootsect.s的代码拷贝到0x7c00位置处,这段代码自己把自己拷贝到0x90000 这个位置然后开始执行,利用bios预先设置好的中断函数,把第2扇区s ...

最新文章

  1. oracle 参数=gt;,解析gt参数
  2. 电磁学讲义2:库仑定律
  3. Python基础教程(十三):JSON、练习题100题
  4. 【转】聊聊分布式事务,再说说解决方案
  5. Java项目打包成exe的详细教程
  6. (android 实战总结)android第三方组件实现总结
  7. bzoj 1061 志愿者招募 费用流
  8. 两大开源硬件之树莓派与a_开源硬件之美
  9. Linux vgchange 命令
  10. 状态码为200 java 类
  11. logback介绍和配置详解
  12. 一次非常成功的项目经验分享和糟糕项目的对比
  13. C++ primer 个人学习总结
  14. 性能优化|一张图带你了解JVM是如何进行内存分配
  15. 【无标题】如何做APP客户端数据埋点
  16. CSS mask遮罩
  17. React学习笔记_从create-react-app学习webpack
  18. electron-bulider 12 打包出现的问题
  19. 电脑上的ofd格式文件如何打开呢_OFD格式的文件怎么打开预览?,来充电吧
  20. StormMedia: 一个关于暴风影音的文件夹

热门文章

  1. java最大子序列和问题_一文看懂《最大子序列和问题》(内含Java,Python,JS代码)...
  2. JAVA之坦克大战(三)我方坦克发射炮弹
  3. 服务器增加链路带宽,ESXI5 如何通过绑定双网卡来提升链路带宽?
  4. 最新淘宝无人直播技术防违规交流
  5. 疫情之下,企业财务职能面临的挑战与机遇并存
  6. oracle cmd窗口输入sqlplus / as sysdba 报协议适配器错误
  7. 网络安全之URL介绍
  8. 情感分析 ( Sentiment Analysis ) 专知荟萃
  9. java字符串替换空格符_字符串替换空格
  10. 如何调试Vue3源代码?