一:异常向量表
异常定义:因为内部或者外部一些事件,导致处理器停下正在处理的工作,转而去处理这些发生的事件。当一种异常发生的时候,ARM处理器会跳转到对应该异常的固定地址去执行异常处理程序,而这个固定的地址,就称之为异常向量。以下为七个异常向量及处理函数跳转关系组成的表。

在Data Abort和IRQ之间有一段地址没有用上,在初始化的时候需要补上一段_not_used ,不然的话会报错,在发生异常的时候,程序会跳转到undefined_instruction: nop这段去执行,由于现在还不需要操作这些异常向量,所以在后面只加上nop。具体以后还会进一步学到
.text
.global _start
_start:
b reset
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq
_undefined_instruction: .word undefined_instruction
_software_interrupt: .word software_interrupt
_prefetch_abort: .word prefetch_abort
_data_abort: .word data_abort
_not_used: .word not_used
_irq: .word irq
_fiq: .word fiq
undefined_instruction:
nop
software_interrupt:
nop
prefetch_abort:
nop
data_abort:
nop
not_used:
nop
irq:
nop
fiq:
nop
reset:
nop
undefined_instruction这个标号是一个地址,在这里,用_undefined_instruction: .word undefined_instruction的形式,_undefined_instruction也是一个标号,这个标号存放32位的值,这个值就是undefined_instruction的地址,然后将_undefined_instruction装载到pc指针中去,此时ldr就不是伪指令了,而是装载指令,以此类推,其他的都一样。这样程序框架就出来了。
二:设置处理器模式
首先要清楚为什么要设置处理器模式,对于ARM11,有8种模式,不同的模式,权限是不一样的。在bootloader开发的时候,我们需要将处理器的模式设置为Supervisor模式,即SVC模式。此时的权限就高了,可以访问ARM的所有资源。用户模式的权限是最低的。

在设置svc模式的时候,需要先了解一下CPSR寄存器,即程序状态寄存器,它包含了条件标志位、中断禁止位、当前处理器模式标志以及其他的一些控制和状态位。

从手册中可以看出,设置不同的处理器模式即就是在设置cpsr寄存器的低五位,当设置svc模式时,低五位就是0b10011,以下是代码:
set_svc:
mrs r0, cpsr
bic r0, r0,#0x1f
orr r0, r0,#0xd3 //换算成16进制,有的设置为0x1f,其实目前来看都一样
msr cpsr, r0
mov pc, lr
注意:在设置cpsr的时候,我们只要记住,不能直接修改cpsr,而是要先mrs,再msr,即先将状态寄存器放到通用寄存器中,在通用寄存器中修改值,最后在将通用寄存器放到状态寄存器中去。
三:关闭看门狗
对于看门狗,简单一点来说,对于嵌入式产品,在长期工作的时候,难免会出现死机的情况,看门狗的作用就是检测系统如果出现死机的情况,会让其自动重启。在硬件上实现计时的功能。下面是看门狗的原理图

看门狗的时钟从PCLK来,然后经过一个预分频器,这个预分频器的分频是可以通过寄存器配置的。然后又到一个分频器,一个选择器选择是哪一路的分频有效。然后分频后的时钟到达看门狗的计数器,这个计数器是一个递减的计数器。计数器的上面有一个设置初始值的寄存器。当看门狗没有使能的时候,该初始值会载入到计数器中。当计数器递减为0的时候,会产生超时信号,如果开启看门狗的中断的话,就会产生中断信号,否则不执行任何操作。复位信号产生器接收这个超时信号,如果使能看门狗复位,就会产生一个复位信号,使CPU复位,没有的话,不执行任何操作。每次超时操作之后,看门狗会自动加载看门狗数据寄存器WTDAT到WTCNT中。
所以,如果关闭复位中断,看门狗就是一个定时器了。
关闭看门狗,主要的原因是由于行业老大uboot中把看门狗给关闭了,其实在很多时候,我们使用的BootLoader比较简单,不需要看门狗,所以将其关闭。通过配置下图寄存器的值可以实现关闭看门狗,主要是看第0位,disable watchdog timer 就是将其设置为零,其他的位用不到就都设置为零。

#define pWTCON 0x7e004000
disable_watchdog:
ldr r0, =pWTCON
mov r1, #0x0
str r1, [r0]
mov pc, lr
使用ldr伪指令,给r0赋值WTCON的地址0x7E004000。
使用mov指令,给r1寄存器赋值为0
使用str指令。将r1的数据,写入到r0指向的地址去,就是写到0x7e004000去,
最后跳转。
这样,就实现了开门狗的关闭了。
四 :关闭中断
中断是嵌入式系统中很重要的东西了。因为有了这个东西,可以使CPU解放出来,做更多的事。至于S3C6410的中断的具体的一些应用,等后面开发用到的时候再分析,这里只是关心怎么把所有中断给关闭掉。

从手册上截取的部分图可以看出VICxINTENABLE是控制中断的寄存器,6410上有两组中断使能寄存器。我们找到这个寄存器,发现这个寄存器只是中断使能,要屏蔽中断,需要设置VICINTENCLEAR寄存器,

只要设置下面两个寄存器,写入全1,就可以屏蔽所有的中断。

代码很简单,只要往两个寄存器中写入全一即可。
disable_interrupt:
mvn r1,#0x0
ldr r0,=0x71200014
str r1,[r0]
ldr r0,=0x71300014
str r1,[r0]
mov pc, lr
使用ldr伪指令,将iVIC0INTCLEAR寄存器的地址给r0寄存器
使用mvn指令,将对0取反的值给r1寄存器。这个时候r1的值就是全1。
使用str指令,将r1的值写入到r0代表的地址中去。就相当于往寄存器iVIC0INTCLEAR里面写入全1了。
五:关闭MMU和cache
在关闭了所有中断后,就要关闭MMU和CACHE了。因为这个时候,还在初始化环境,这两个东西是用不到的。防止意想不到的错误发生,在以后会用到,再学习这部分内容。
MMU是Memory Management Unit的缩写,中文名是存储器管理单元。主要是两个功能:
1、虚拟地址转换为物理地址
2、实现内存的保护
虚拟地址:程序中使用的地址。
物理地址:物理存储单元实际的地址
CACHE是高速缓冲存储器。CPU工作速度是很快的,而外部内存是工作很慢的,所以当CPU对内存访问的时候,是要等待内存访问结束的。所以中间CPU就在等待,这就浪费了时间。所以在CPU和内存之间加一个CACHE,当CPU写数据到内存中的时候,就先写入到CACHE中,然后CACHE再写入到内存中。CPU写CACHE是很快的,所以就提高了写数据的效率。读数据的话,CPU先在CACHE中去找数据,没有找到的话,CACHE将数据从内存中取出来,再给CPU,同时把这个数据存起来。当CPU在CACHE中找到数据的话,就直接使用这个数据,就不用再去内存中取数据了。

cache在arm11中分为两种,I-Cache和D-cache,I-Cache存储指令,D-cache存储数据。
我们需要查看S3C6410的核ARM1176JZFS手册。在这里,我们要接触到一个系统控制处理器,CP15。也叫做协处理器。
对于CP15寄存器组中,可以看出C1是控制寄存器,在手册中打开C1寄存器


C1的第十二位控制I-Cache,第二位控制D-cache,第零位控制MMU,同时,还需要设置C7寄存器,因为在关闭I-cache和D-cache前需要将它们无效。

步骤:
一:使I-cache和D-cache失效
二:关闭 I,D-cache,mmu
下图表明怎么使用C1控制寄存器

disable_mmu:
mcr p15,0,r0,c7,c7,0 //使cache无效
mrc p15,0,r0,c1,c0,0 // 按照手册使用控制寄存器
bic r0, r0, #0x00000007//这里主要把低三位清零,关于I-cache可关可不关
mcr p15,0,r0,c1,c0,0
mov pc, lr
文中若有什么错误,麻烦各位指出,我会虚心的更改的。