1.2. 关闭看门狗

1.2.1. pWTCON INTMOD INTMSK INTSUBMSK CLKDIVN

/* turn off the watchdog */
#if defined(CONFIG_S3C2400)
# define pWTCON		0x15300000
# define INTMSK		0x14400008	/* Interupt-Controller base addresses */
# define CLKDIVN	0x14800014	/* clock divisor register */
#elif defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)1
# define pWTCON		0x53000000
# define INTMOD		0X4A000004
# define INTMSK		0x4A000008	/* Interupt-Controller base addresses */
# define INTSUBMSK	0x4A00001C
# define CLKDIVN	0x4C000014	/* clock divisor register */
#endif
        

1

上面几个宏定义所对应的地址,都可以在对应的datasheet中找到对应的定义:

其中,S3C2410和TQ2440开发板所用的CPU S3C2440,两者在这部分的寄存器定义,都是一样的,所以此处,采用CONFIG_S3C2410所对应的定义。

关于S3C2440相关的软硬件资料,这个网站提供的很全面:

http://just4you.springnote.com/pages/1052612

其中有S3C2440的CPU的datasheet:

s3c2440a_um_rev014_040712.pdf

其中有对应的寄存器定义:

图 1.3. pWTCON

pWTCON

图 1.4. INTMOD

INTMOD

图 1.5. INTMSK

INTMSK

图 1.6. INTSUBMSK

INTSUBMSK

图 1.7. CLKDIVN

CLKDIVN

而关于每个寄存器的具体含义,见后面的分析。

1.2.2. ldr pWTCON

#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)
	ldr1     r0, =pWTCON
        

1

这里的ldr和前面介绍的ldr指令不是一个意思。

这里的ldr是伪指令ldr。

[提示] 伪指令

伪指令,就是“伪”的指令,是针对“真”的指令而言的。

真的指令就是那些常见的指令,比如上面说的arm的ldr,bic,msr等等指令,是arm体系架构中真正存在的指令,你在arm汇编指令集中找得到对应的含义。

而伪指令是写出来给汇编程序看的,汇编程序能看的伪指令具体表示的是啥意思,然后将其翻译成真正的指令或者进行相应的处理。

伪指令ldr语法和含义:

http://blog.csdn.net/lihaoweiV/archive/2010/11/24/6033003.aspx

另外还有一个就是ldr伪指令,虽然ldr伪指令和ARM的ldr指令很像,但是作用不太一样。ldr伪指令可以在立即数前加上=,以表示把一个地址写到某寄存器中,比如:

ldr r0, =0x12345678

这样,就把0x12345678这个地址写到r0中了。所以,ldr伪指令和mov是比较相似的。

只不过mov指令后面的立即数是有限制的,这个立即数,能够必须由一个8位的二进制数,即属于0x00-0xFF内的某个值,经过偶数次右移后得到,这样才是合法数据,而ldr伪指令没有这个限制。

那为何ldr伪指令的操作数没有限制呢,那是因为其是伪指令,写出来的伪指令,最终会被编译器解释成为真正的,合法的指令的,一般都是对应的mov指令。

这样的话,写汇编程序的时候,使用MOV指令是比较麻烦的,因为有些简单的数据比较容易看出来,有些数据即不容易看出来是否是合法数据。所以,对此,ldr伪指令的出现,就是为了解决这个问题的,你只管放心用ldr伪指令,不用关心操作数,而写出的ldr伪指令,编译器会帮你翻译成对应的真正的汇编指令的。

而关于编译器是如何将这些ldr伪指令翻译成为真正的汇编指令的,我的理解是,其自动会去算出来对应的操作数,是否是合法的mov 的操作数,如果是,就将该ldr伪指令翻译成mov指令,否则就用别的方式处理,我所观察到的,其中一种方式就是,单独申请一个4字节的空间用于存放操作数,然后用ldr指令实现。

在uboot中,最后make完毕之后,会生产u-boot,

通过:

arm-linux-objdump –d u-boot > dump_u-boot.txt

就可以把对应的汇编代码输出到该txt文件了,其中就能找到伪指令:

ldr     r0, =0x53000000

所对应的,真正的汇编代码:

33d00068:	e3a00453 	mov	r0, #1392508928	; 0x53000000

所以被翻译成了mov指令。

而经过我的尝试,故意将0x53000000改为0x53000010,对应的生产的汇编代码为:

33d00068:	e59f0408 	ldr	r0, [pc, #1032]	; 33d00478 <fiq+0x58>
......
33d00478:	53000010 	.word	0x53000010
                    

其中可以看到,由于0x53000010不是有效的mov的操作数,没法找到合适的0x00-0Xff去通过偶数次循环右移而得到,所以只能换成此处这种方式,即在另外申请一个word的空间用于存放这个值:

33d00478:	53000010 	.word	0x53000010

然后通过计算出相对当前PC的偏移,得到的地址,用ldr指令去除该地址中的值,即0x53000010,送给r0,比起mov指令,要复杂的多,也多消耗了一个word的空间。

对应地,其他的方式,个人理解,好像也可以通过MVN指令来实现,具体细节,有待进一步探索。

而这里的:

ldr     r0, =pWTCON

意思就很清楚了,就是把宏pWTCON的值赋值给r0寄存器,即

r0=0x53000000

1.2.3. mov

	mov1     r1, #0x0
        

1

mov指令语法:

1、 MOV指令

MOV指令的格式为:

MOV{条件}{S} 目的寄存器,源操作数

MOV指令可完成从另一个寄存器、被移位的寄存器或将一个立即数加载到目的寄存器。其中S选项决定指令的操作是否影响CPSR中条件标志位的值,当没有S时指令不更新CPSR中条件标志位的值。

指令示例:

MOV R1,R0 ;将寄存器R0的值传送到寄存器R1

MOV PC,R14 ;将寄存器R14的值传送到PC,常用于子程序返回

MOV R1,R0,LSL#3 ;将寄存器R0的值左移3位后传送到R1

不过对于MOV指令多说一句,那就是,一般可以用类似于:

MOV R0,R0

的指令来实现NOP操作。

上面这句mov指令很简单,就是把0x0赋值给r1,即

r1=0x0

1.2.4. str

	str1     r1, [r0]
        

1

str指令语法:

4、STR指令

STR指令的格式为:

STR{条件} 源寄存器,<存储器地址>

STR指令用于从源寄存器中将一个32位的字数据传送到存储器中。该指令在程序设计中比较常用,且寻址方式灵活多样,使用方式可参考指令LDR。

指令示例:

STR R0,[R1],#8 ;将R0中的字数据写入以R1为地址的存储器中,并

将新地址R1+8写入R1。

STR R0,[R1,#8] ;将R0中的字数据写入以R1+8为地址的存储器中。

所以这句str的作用也很简单,那就是将r1寄存器的值,传送到地址值为r0的(存储器)内存中。

用C语言表示就是:

*r0 = r1

所以,上面几行代码意思也很清楚:

先是用r0寄存器存pWTCON的值,然后r1=0,再将r1中的0写入到pWTCON中,其实就是

pWTCON = 0;

而pWTCON寄存器的具体含义是什么呢?下面就来了解其详细含义:

图 1.8. WTCON寄存器的位域

WTCON寄存器的位域

注意到bit[0]是Reset Enable/Disable,而设置为0的话,那就是关闭Watchdog的reset了,所以其他位的配置选项,就更不需要看了。

我们只需要了解,在此处禁止了看门狗WatchDog(的复位功能),即可。

关于看门狗的作用,以及为何要在系统初始化的时候关闭看门狗,请参见本文档后面的章节:第 3.3 节 “什么是watchdog + 为何在要系统初始化的时候关闭watchdog”