单龙芯3A3000-7A1000PMON研究学习-(15)撸起袖子干-先来一杯代码吧
1.扭扭捏捏,准备工作都是一大堆,要不来点汇编开开胃
/** Register usage:** s0 link versus load offset, used to relocate absolute adresses.* s1 free* s2 memory size.* s3 free.* s4 Bonito base address.* s5 dbg.* s6 sdCfg.* s7 rasave.* s8 L3 Cache size.*/.set noreorder.globl _start.globl start.globl __main
_start:
start:.globl stack
stack = start - 0x4000 /* Place PMON stack below PMON start in RAM *//* NOTE!! Not more that 16 instructions here!!! Right now it's FULL! */.set push.set mips64mfc0 t0, $16, 6or t0, 0x100 xori t0, 0x100 /*先或再异或,清零第8位*/mtc0 t0, $16, 6/* no sw combine */mfc0 t0, $16, 6ori t0, 0x200 /*第九位置1*/mtc0 t0, $16, 6mfc0 t0, $22lui t1, 0x0000//lui t1, 0x8000or t0, t1, t0 /*或操作一个0,没意义呀 */mtc0 t0, $22.set popmtc0 zero, COP_0_STATUS_REG /*清零COP_0_STATUS_REG 寄存器*/mtc0 zero, COP_0_CAUSE_REG /*清零COP_0_CAUSE_REG 寄存器*/li t0, SR_BOOT_EXC_VEC /* Exception to Boostrap Location 异常向量表*/ //[22]置1mtc0 t0, COP_0_STATUS_REG /* 将异常向量表写入寄存器 */ //例外向量入口地址启动,BEV置1,采用rom的异常入口la sp, stack /* 设置堆栈寄存器 ,指向起始代码的下方(地址减小的方向) */la gp, _gp /* 设置GP寄存器 */WatchDog_Close /* 这是个宏定义,关闭看门狗 *//* spi speedup */li t0, 0xbfe00220li t1, 0x07sb t1, 0x4(t0)/* locate 在下面,约423行的样子。 */bal locate /* Get current execute address */ /* 跳转到locate ,返回(绝对)地址保存在al寄存器中 */nop
来了一段汇编,要能看懂汇编,还得学点汇编指令啊。
1.1首先,.开头的都是伪操作,应该用于提示编译器,后面的代码应该如何处理,或者一些声明。
至少你得知道,伪操作,一般不能翻译为一条机器指令,它用来控制编译器的一些行为吧。
比如.global 声明一个全局的名称,让这个名称在别的文件可以使用,相当于c的extern。因为汇编跟c不同,汇编文件中默认所有的名称只能在本文件中使用,(相当于加了static)。如果你要让这个标号全局可见,就必须使用global修饰一下。但这并不会产生机器指令(在最终的可以执行的bin文件中也不会占用任何字节空间),只是在编译的时候能够识别到这个标号而已啦。
前面我们讲过,_start,start是整个程序的入口,那肯定有别的文件(如ld.scripts)需要识别到这个标号,所以这个标号必然要用global修饰一下。
.set 的操作比较多,我也是网上抄一点吧。
.set mipsn。n是一个从0到5的数字,或是数字32或64。1到5,32或64使汇编器从源程序中的这一点开始接受相应ISA级别的指令。 .set mipsn 不仅影响允许使用那些指令,还影响到某些宏如何被扩展。 .set mips0保持原本的ISA级别:这个级别是您通过命令行选项选择的,或者是您的配置的默认值。您可以通过这个特性在32位汇编模式中使用r4000的指令。小心使用这个命令!
命令‘.set mips16’使汇编器进入MIPS 16模式,传统的汇编器不支持这个命令
伪操作 .set mips3 告诉汇编器下面的指令是MIPS IV(64位指令集,兼容32位指令)中的指令。
.set mipsn
n是一个从0到5的数字,或是数字32或64。1到5,32或64使汇编器从源程序中的这一点开始接受相应ISA级别的指令。 .set mipsn 不仅影响允许使用那些指令,还影响到某些宏如何被扩展。
.set mips0保持原本的ISA级别:这个级别是通过命令行选项选择的,或者是配置的默认值。可以通过这个特性在32位汇编模式中使用r4000的指令
.set mips1 下面的指令是R2000/R3000指令,即MIPS I指令集
.set mips2下面的指令是R6000指令,即MIPS II指令集,这个没有产品化的芯片,一般不要使用
.set mips3下面的指令是R4000指令,即MIPS III,第一个支持64位的指令集
.set mips4支持MIPS IV指令集,它是在MIPSIII的基础上增加了一些浮点指令
.set mips5支持MIPS V指令集,在MIPS IV上增加了SIMD指令
另外.set mips32/mips64支持MIPS32/MIPS64指令集
这个牵扯到MIPS的指令集标准历史,1998年MIPS Technologies从SGI公司分离出来之后发布的指令集标准,MIPS32是MIPS II的超集,MIPS64是MIPS IV的超集,还是得回去读“历史”
.set noreorder/reorder
默认汇编器处在reorder的模式下,该模式允许汇编器对指令进行重新排序,以避免流水线堵塞并获得更好的性能,在这种模式下,是不允许在代码中插入 nop指令的。反之,在noreorder模式下,指令的顺序不会被改变也不会对代码进行任何优化。这样做的优点是程序员可以完全控制代码的执行顺序,缺点是必须手工对指令排序,并在分支和加载指令的延迟槽中填上有用的指令或nop指令.比如:
.set noreorder
lw t0, 0(a0)
nop #加载指令延迟槽
sub t0, 1
bne t0, zero, loop
nop #分支指令延迟槽
.set reorder
.set volatile/novolatile
处在volatile区的所有存取指令都不会被移动位置(特别是存取指令之间的相对位置)。这一点对访问内存映射设备的寄存器非常重要。因为对于外围设备而言,读写的次序十分重要。另外对读状态寄存器也非常重要。因为想得到的状态都是最新的。举例来说,如果下列代码没有使用.set volatile,那么汇编器很有可能会对第二个lw指令移到指令的前面,因为这样可以填充第一条lw指令的延迟槽:
.set volatile
lw t0, 0(a0)
sw t0, 0(a1)
lw t0, 4(a0)
.set novalatile
避免流水线堵塞的操作以及其他各种优化措施不受该设定的影响.
noat, nomacro, noreorder: 汇编语言控制操作,为程序员提供了一种方式来关闭汇编器做的一些更复杂的工作,这些工作不总是受欢迎的(相应的没有“no”的名字将该特性重新打开)
.set noat 阻止汇编器将汇编代码翻译成二进制序列依赖at/$1寄存器
.set nomacro 阻止汇编器将一条汇编代码翻译成多条指令
.set noreorder 阻止汇编器调整代码序列来将有用的指令放入分支延迟槽。
.set push --> save all settings (指的是什么设置???指的是现有的.set汇编指示环境)
.set reorder/noreorder --> let/don't let assembler reorder instructions
.set at/noat --> let/don't let assembler use the register $at in instruction aliases (li,la, etc.)
.set pop --> restore saved settings
1.2 用到得汇编指令:
mfc0 从协处理器0的寄存器中读出数据,f表示from
mtc0 把数据写入到协处理器0的寄存器中,t表示to
or 或运算 ,跟c语言按位或运算一致
xori xor表示异或,与c一致,i表示立即数,表示这个操作是与一个数字进行的。
ori 立即数的或运算
lui 加载立即数到高16位,u表示高16位uper,l表示加载(load),从内存读数据到寄存器
li 加载立即数,这是条伪指令,汇编的时候可能需要根据情况自动转为其他指令
la 加载标号对应的地址,a表示address
sb s表示存储(store),表示是从寄存器写入到内存,b表示字节,表示该指令只操作一个字节
bal b表示跳转(branch),bal表示跳转的同时,保存返回地址到ra寄存器。跳出去还可以回来。
上述代码中用到的汇编稍微解释了一下,不懂的继续百度,或者加我qq166781997
1.3 上述代码做了什么?
1.3.1 协处理器0的寄存器需要参考手册《user2.pdf》
mfc0 t0, $16, 6 ,表示从寄存器16读取数据到t0寄存器,后面的数字6,表示第6个 选择寄存器。
这里考虑到的是兼容性问题,当初没有设计那么多协处理器寄存器,但是后来又需要跟多,为了与之前的兼容,做了select这样的设计。
结合后面的语句,或操作,然后异或,那就是要清零寄存器中第8位,然后把这个值写进去。
好,这四句就是关闭这个自动写合并功能。(具体是啥,以后再琢磨吧。)
1.3.2 接下来3句
mfc0 t0, $16, 6
ori t0, 0x200 /*第九位置1*/
mtc0 t0, $16, 6
置1第9位,看pdf:
文档说必须写,那就写吧,这还能咋样???
1.3.3接下来4句
mfc0 t0, $22 //这条是访问寄存器22,后面没有数字,表示select 0
lui t1, 0x0000
//lui t1, 0x8000
or t0, t1, t0 /*或操作一个0,没意义呀 */
mtc0 t0, $22
似乎没得意义????高木及。。。。
1.3.5 接下来几句:
mtc0 zero, COP_0_STATUS_REG /*清零COP_0_STATUS_REG 寄存器*/
mtc0 zero, COP_0_CAUSE_REG /*清零COP_0_CAUSE_REG 寄存器*/
li t0, SR_BOOT_EXC_VEC /*0x40,0000*/ //[22]置1
mtc0 t0, COP_0_STATUS_REG //例外向量入口地址启动,BEV置1,采用rom的异常入口
la sp, stack /* 设置堆栈寄存器 ,指向起始代码的下方(地址减小的方向) */
la gp, _gp /* 设置GP寄存器 */
1.3.6 最后几句吧
WatchDog_Close /* 这是个宏定义,关闭看门狗 */
#define WatchDog_Close \
GPIO_CLEAR_OUTPUT(0x1<<5); \
GPIO_SET_OUTPUT(0x1<<3|0x1<<4); \
GPIO_CLEAR_OUTPUT(0x1<<13); \
/* spi speedup */
li t0, 0xbfe00220
li t1, 0x07
sb t1, 0x4(t0)
bal locate /* Get current execute address */ /* 跳转到locate ,返回(绝对)地址保存在al寄存器中 */
nop
1.4 做了什么?
1.做了一些清理工作,处理器模式,中断这些都清除掉,中断入口应该设置位rom,现在程序还在rom里面。
2.关闭看门狗
3.sp寄存器,和gp寄存器设置好了,但是sp应该还不能用(ddr没有初始化)。跳到下一个函数继续初始化。
在这里我们也看到,修改一个寄存器的基本步骤,是读出这个寄存器的值,通过位操作修改这个值(只改变你需要改变的位),然后把这个值再写入到寄存器。
这是嵌入式开发的常用操作。
单龙芯3A3000-7A1000PMON研究学习-(15)撸起袖子干-先来一杯代码吧相关推荐
- 单龙芯3A3000-7A1000PMON研究学习-(14)撸起袖子干-分析代码前的准备工作2
1.我细细回想一下,感觉要准备的东西很多. 比如体系结构,汇编指令,地址映射,外设.... 然而,光体系结构就复杂到要用n页(官方的)pdf才能说清楚(其实不一定能说清楚,可能还得慢慢去琢磨).这里还 ...
- come type6 定义_COMe-B6101龙芯3A3000 COM Express Type6模块
COMe-B6101是一款以龙芯3A多核处理器和AMD RS780E SB710芯片组为核心,高可靠性和高效能的主板模块.COMe-B6101 内部集成ATI M72-based图像引擎,支持双屏显示 ...
- 单龙芯3A3000-7A1000PMON研究学习-(16)撸起袖子干-分析代码前的准备工作3-寄存器
1.这篇还是稍微介绍一下cpu相关的寄存器. 手册里面说到的寄存器分两种,一种是cpu使用的(汇编中用来存放数据的),另一种是外部设备寄存器(一般用于配置功能,或者读写外部设备数据用的.),在手册中都 ...
- 【保姆级教程】在龙芯3A5000上编译arrow-0.15.1
环境信息 处理器:龙芯3C5000 操作系统:Loongnix Server 8.4.1 内核版本:4.19.190-6.5 1.arrow-0.15.1的编译参数 每家的参数不一样,可以根据自己需求 ...
- 龙梦拿下3万片大单 龙芯电脑年底量产无悬疑
10月9日,龙芯有关人士通过搜狐博客透露,"龙梦电脑已经有人拿到货,批量生产在11月15日以后,因为量产的芯片11月15日才到."这与龙梦科技此前关于"龙芯电脑年底量产& ...
- 单龙芯3A3000-7A1000PMON研究学习-(19)撸起袖子干-再来一杯代码3
1.start.S包含一个独立的pcitlb.S文件 ########################################## PRINTSTR("NO TLB cach ...
- 单龙芯3A3000-7A1000PMON研究学习-(8)撸起袖子干-make tgt=rom初步分析(a)
1.make tgt=rom 开始编译了. 在zloader.3a3000_7a目录下的Makefile.inc,指定了我们要的目标. tgt = rom. 所以就是执行73行的rom这个目标. 这里 ...
- 单龙芯3A3000-7A1000PMON研究学习-(11)撸起袖子干-make tgt=rom的编译过程
1. 今天来分析一下makefile,看看如何编译出执行文件pmon的. 先贴几张图,makefile的内容,这是一些依赖关系 图一 图二 图三 图四 图五 2.图一解释 rom这个目标又三个依赖,c ...
- 单龙芯3A3000-7A1000PMON研究学习-(12)撸起袖子干-分析代码前的准备工作1
1.make的过程我说了个大概,大家可以参考一下前面的文章.现在准备分析代码吧,其实这个准备工作内容应该蛮多的.可能后面还要补充. 2.首先找到关键的bin文件啊,就是可以最终下载到flash,能启动 ...
- 走进龙芯3A3000(四)安装XFCE4
我想要安装KDE 我想要qtwebengine的MIPS64实现.曾经读过千里孤坟的<KDE综览>,就深深喜欢上了KDE,当时的版本还是KDE3.后来KDE4发布,千里孤坟又写了<K ...
最新文章
- puppet原理及配置
- oracle控制文件的损坏或完全丢失的恢复办法
- c include 多层目录_Rsync 秒杀一切备份工具,你能手动屏蔽某些目录吗?
- 理解总结篇—List、Set、Map
- 蒙特卡洛法求圆周率 c语言,c++蒙特卡洛法求圆周率
- 解决IDEA运行Flink报错java.lang.NoClassDefFoundError: org/apache/flink/api/common/ExecutionConfig....
- Python简洁的出入库系统(模块化)
- docker 时区_centos7.X上部署docker并运行常用的应用
- C++ 将模板申明为友元
- 介绍几款高级DAC解码芯片(整编)
- 2012年度总结:内心宁静的2012
- 《英语语法新思维初级教程》学习笔记(五)形容词
- 教你们如何快速建立一个完美的python项目
- 南开大学计算机本科论文,南开大学本科(论文)模板.doc
- 用python3实现HDU爬虫(后续可能更新VJ)2016.11.4更新
- 自我管理数据缓冲区内存
- Java虚拟机规范 Java SE 8版 - class文件格式(二)
- 闭关修炼(八)反射机制
- 某微型计算机标明piv 1.8g,计算机必备.doc
- 网络安全 社会工程学--钓鱼网站的制作和利用(让你了解整个钓鱼网站 背后的秘密.)