单龙芯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	mips64
	mfc0	t0, $16, 6
	or	t0, 0x100 
	xori	t0, 0x100       /*先或再异或,清零第8位*/
	mtc0	t0, $16, 6

    /* no sw combine */
    mfc0    t0, $16,  6
    ori     t0, 0x200		/*第九位置1*/
    mtc0    t0, $16,  6

	mfc0	t0, $22
	lui	t1, 0x0000
	//lui	t1, 0x8000
	or	t0, t1, t0        /*或操作一个0,没意义呀 */
	mtc0	t0, $22
	.set	pop

	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	/* Exception to Boostrap Location  异常向量表*/   //[22]置1
	mtc0	t0, COP_0_STATUS_REG   /* 将异常向量表写入寄存器 */  //例外向量入口地址启动,BEV置1,采用rom的异常入口
	la	sp, stack				/* 设置堆栈寄存器 ,指向起始代码的下方(地址减小的方向) */
	la	gp, _gp					/* 设置GP寄存器 */


	WatchDog_Close     /* 这是个宏定义,关闭看门狗 */


	/* spi speedup */
	li  t0, 0xbfe00220
	li  t1, 0x07
	sb  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没有初始化)。跳到下一个函数继续初始化。

在这里我们也看到,修改一个寄存器的基本步骤,是读出这个寄存器的值,通过位操作修改这个值(只改变你需要改变的位),然后把这个值再写入到寄存器。

这是嵌入式开发的常用操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大智兄

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值