OMAPL138的启动顺序

#Bootloader
Bootloader为存储在ROM中的启动代码(一些程序),由TI在芯片出厂时以掩膜方式固化内容。
TI使用ROM空间的一部分,还有一部分剩余空间,用户可以委托TI写入(掩模)所需代码。

##版本

OMAPL138的Bootloader保存在ROM中,检查内存地址0xFFFD0000,在memory window中选择Character,在偏移地址0x08可以读到版本号:版本号为类似于d800k008
##启动模式

启动模式分为两种

  • Master
    从各种内存启动
  • Slave
    从外部Master启动

除了HPI (Host Port Interface)和2种NOR (Parallel Flash) boot模式,其他模式均使用AIS(Application Image Script)格式。

管脚配置详见Using the OMAP-L132/L138 Bootloader Appendix A Boot Mode Selection Table

##启动顺序
OMAP-L138 SOC 的启动详解

OMAP-L138 的ROM内有DSP 与ARM两份启动代码,芯片上电解复位后,DSP Bootloader 先运行,通过PRU 加载ARM初始化代码,因为DSP 不能访问ARM的片上RAM空间,所以这一步通过PRU 完成,然后DSP 通过PSC 使能ARM,运行ARM的Bootloader, ARM再将DSP 置于复位态,并关闭其时钟。这个过程由芯片内部ROM 代码自动完成,所以从用户的角度,芯片就是从ARM 开始启动的。
ARM Bootloader 读取BOOTCFG 寄存器,获取用户设定的启动模式,然后从相应的外设搬移用户代码到相应的地址,跳转到用户代码的入口地址,完成SOC 的启动过程。

下面这段话未找到出处文档

When the device is powered on, it starts execution from DSP ROM. ARM is in in the disable state at this moment.

The DSP ROM code will Read certain registers to know that ARM is present. (Otherwise it will be a DSP-only boot) Program PDSP0 to prepare for ARM reset vector.

Bring ARM out of reset and let ARM starts execution from its ROM. (Yes, that’s the main difference from OMAPL137 silicon 1.x. ARM has its own ROM and will master the boot process afterwards)

DSP stills in the idle loop.

ARM starts execution from its ROM. It will Put DSP into disable state (probably local reset).

Initialize HW, i.e. PSC, PLL, external memory etc. Read bootcfg registers to decide what boot mode it will be and load and run ARM UBL from appropriate boot media, i.e. SPI flash, NAND, NOR etc.

ARM UBL starts running. Its behavior is totally defined by the SW. For example, TI provided ARM UBL will load and run UBOOT which will further load and run Linux. The Linux application can load and run DSP.out via DSPLINK. This model is the same as DaVinci model.

Industrial customers can choose to load and run a DSP AIS image in certain boot media. Meanwhile ARM UBL also starts booting UBOOT and Linux. In that way, DSP can start processing data before Linux finishing boot.


#主要内存地址的Memory Map

ARM可以访问全部地址空间,DSP不能访问ARM的内存空间。

  • DSP (C674x)
    |Section |Size | Start| End |
    |—|---—|---|
    |DSP L2 ROM1|1024K|0x0070 0000/0x1170 0000|0x007F 0000/0x117F FFFF|
    |DSP L2 RAM|256K|0x0080 0000/0x1180 0000|0x0083 0000/0x1183 0000|
    |DSP L1P RAM|32K|0x00E0 0000/0x11E0 0000|0x00E0 7FFF/0x11E0 7FFF|
    |DSP L1D RAM|32K|0x00F0 0000/0x11F0 0000|0x00F0 7FFF/0x11F0 7FFF|
  • ARM (ARM926EJ-S)
Section Size Start End
ARM Local ROM 64K 0xFFFD 0000 0xFFFD FFFF
ARM Interrupt Control 8K 0xFFFE E000 0xFFFE FFFF
ARM Local RAM 8K 0xFFFF 0000 0xFFFF 1FFFF
  • Shared
Section Size Start End
EMIFA SDRAM data (CS0) 512M 0x4000 0000 0x5FFF FFFF
EMIFA async data (CS1) 32M 0x6000 0000 0x61FF FFFF
EMIFA async data (CS2) 32M 0x6000 0000 0x61FF FFFF
EMIFA async data (CS3) 32M 0x6200 0000 0x63FF FFFF
EMIFA async data (CS4) 32M 0x6400 0000 0x65FF FFFF
EMIFA async data (CS5) 32M 0x6600 0000 0x67FF FFFF
EMIFA Control Regs 32K 0x6800 0000 0x6800 7FFF
Shared Memory 128K 0x8000 0000 0x8001 FFFF
DDR2/mDDR Control Regs 32K 0xB000 0000 0xB000 7FFF
DDR2/mDDR Data 256M 0xC000 0000 0xCFFF FFFF

#ARM启动DSP的步骤

OMAPL138的Bootloader启动ARM后(138是DSP先启动,实际上在Bootloader中是先启动DSP,DSP唤醒ARM后,DSP转入IDLE,所以从用户的角度来看,相当于ARM先启动),DSP由ARM负责启动。
DSP启动前,需要确保其处于Local Reset状态,ARM则要处于Supervisor模式下:

  • ARM将DSP 代码的入口地址写入HOSTCFG1 寄存器, DSP 的入口地址要求以1K 字节对齐
  • ARM使能DSP 模块时钟,即PSC0.MDCTL15[NEXT]=3,这样DSP 片上内存才可以被访问;
  • ARM加载DSP 代码,对于ARM端使用带文件系统的操作系统来说,DSP 代码可以做为文件系统的一个文件存储,如果使用DSP Link,其驱动直接解析.out 文件进行加载。对于没有文件系统的场景,通常将DSP 代码转换成二进制文件,存放在flash 上用户指定的位置,ARM 代码从指定的位置按照文件的组织格式进行读取、加载。
  • ARM释放DSP Local Reset:PSC0.MDCTL15[LRST]=1,DSP 从HOSTCFG1 设置的入口地址开始运行。

在系统运行过程中,ARM 可以控制DSP 的复位,重新加载新的DSP 应用代码,以实现不同的功能。

ARM与DSP还可以通过AIS文件实现同时加载,具体参见这里第6章。


#启动失败的常规检查方法

不加载gel文件,连接仿真器后检查

  1. BOOTCFG寄存器的Boot mode;
  2. 查看PC指针,如果停在ROM空间,表示没有读到有效的启动文件;
  3. 代码跑飞2
  1. 用CCS打开DSP或ARM正在跑的工程,下载符号表(symbol),将PC设置为工程的入口,这样可以将内存中的代码和工程代码对应起来,进行仿真调试;
  2. 对比从FLASH启动后的内存代码和使用CCS下载工程以后的内存代码是否一致,如果不一致,这种错误有可能是由于DDR工作不稳定造成的;
  3. 使用仿真器调试时,有可能使用gel初始化了某些外设,但是在AIS或者程序中没有进行相同的初始化。

#ARM用户程序的一般流程

ARM用户程序不像DSP用户程序一样与C/C++类似,只需要配置好中断向量表和主函数main就行了,ARM用户程序需要进行一些特殊设置。

##ARM的“模式”

ARM有7中基本模式,在每种模式下使用各自独立的栈,和一部分各自独立的寄存器,有些操作只有在**Privileged(特权)**模式下才能执行。
7种模式分别为

模式 描述 Privileged mode? 编码
Supervisor(SVC) Reset后进入,或者执行SWI (Software Interrupt) Yes 10011
FIQ 高优先级(快)中断被触发 Yes 10001
IRQ 低优先级(普通)中断被触发 Yes 10010
Abort 用来处理非法的内存访问 Yes 10111
Undef 用来处理未定义的指令 Yes 11011
System 与User模式使用同一组寄存器,区别只是System模式为Privileged mode Yes 11111
User 执行一般程序、OS任务 No 10000

模式的区别和作用

Most application programs execute in User mode. When the processor is in User mode, the program being executed is unable to access some protected system resources or to change mode, other than by causing an exception to occur (see Exceptions on page A2-16). This allows a suitably-written operating system to control the use of system resources. The modes other than User mode are known as privileged modes. They have full access to system resources and can change mode freely. Five of them are known as exception modes:

  • FIQ
  • IRQ
  • Supervisor
  • Abort
  • Undefined.

These are entered when specific exceptions occur. Each of them has some additional registers to avoid corrupting User mode state when the exception occurs (see Registers on page A2-4 for details).

中文简单的解释可以看这个。

###模式切换
####寄存器
ARM共有37个寄存器,其中有6个状态寄存器PSR (Programme Status Register) ,在模式间切换需要用到两组重要的PSR寄存器——C(urrent)PSRS(aved)PSR,PSR共有6个,分别为CPSR、SPSR_svc、SPRS_abt、SPSR_und、SPSR_irq和SPSR_fiq。

处理器在所有模式下均可访问CPSR,SPSR用来在进入异常^Exception of ARM前保存CPSR的状态,以便从异常返回时回复异常前的工作状态。

几个特殊寄存器:

  • SP - Stack Pointer (R13)
  • LR - Link Pointer (R14),记录程序调用(Function Call)的返回地址。
  • PC - Program Counter (R15)

PSR的定义:

31 N 30 Z 29 C 28 V 27:9 8 I 7 F 6 T 4:0 Mode
Negative or less than Zero Carry or borrow Overflow or underflow Reserved IRQ disabled(1), enabled(0) FIQ disabled(1), enabled(0) Thumb mode(1), ARM mode(0) Supervisor(SVC) 10011, FIQ 10001, IRQ 10010, Abort 10111, Undef 11011, System 11111, User 10000

其中31:28 NZCV为最近一次ALU操作的结果,具体含义为:

  • N: 在结果是有符号数的情况下,如果结果为负数N=1,如果结果为非负数N=0;
  • Z: 如果结果为0则Z=1,如果结果为非0则Z=0;
  • C:
    • 加法指令如果产生进位C=1,否则C=0;
    • 减法指令如果产生借位C=0,否则C=1;
    • 有移位操作的非法指令,C为最后移出位的值;
    • 其他指令C不变;
  • V: 对于加减法指令如果发生溢出则V=1,否则V=0;其他指令V不变。

####常用汇编指令
关于汇编指令的详细信息,参考《ARM® Compiler armasm User Guide》。

label和mnemonic
label是汇编中符号(symbol)的标识符,表示符号在程序中的地址。
mnemoic是汇编指令的助记符,mnemoic不能在每一行顶格开始写,这样会被认为是定义label,任何非 ‘.’ (点)开头的字符串均是合法的label定义伪指令,即mnemonic之前必须要有空格。

#####MRS
MRS有两种指令:

  1. PSR to general-purpose register
    将CPSR或APSR的内容放入通用寄存器。
  2. system coprocessor register to ARM register
    将系统协处理器[^ARM coprocessor]寄存器内容放入ARM的寄存器。ARM启动初始化未用到,此处不详细展开。其他指令也有类似的情况,本文中只讨论实际用到的指令。
    [^ARM coprocessor]: ARM最多可支持16个协处理器P0-P15,每个协处理器寄存器名称为C0-C15。ARM926EJ-S的片上协处理器为CP15系统控制协处理器
MRS{cond} Rd, psr

cond 条件[^Condition usage]
[^Condition usage]: 条件语句的语法,以跳转指令B为例,BNE label表示ALU的上一次计算结果不等于0则跳转到label。

Rd 目标寄存器
psr CPSR或者SPSR。在User和System模式下不要操作SPSR。

cond条件标志:

Code Suffix Description Flags
0000 EQ Equal / equals zero Z
0001 NE Not equal !Z
0010 CS / HS Carry set / unsigend higher or same C
0011 CC / LO Carry clear / unsigned lower !C
0100 MI Minus / negative N
0101 PL Plus / positive or zero !N
0110 VS Overflow V
0111 VC No overflow !V
1000 HI Unsigned higher C and !Z
1001 LS Unsigned lower or same !C or Z
1010 GE Signed greater than or equal N == V
1011 LT Signed less than N != V
1100 GT Signed greater than !Z and (N == V)
1101 LE Signed less than or equal Z or (N != V)
1110 AL Always(default) any

#####BIC (bit clear)
BIC{S}{cond} Rd, Rn, Operand2

S 计算结束后更新条件标志;
Rd 目标寄存器;
Rn 保存第一个操作数的寄存器
Operand2 第二个操作数

BIC指令对Rn和Operand2的补码进行AND操作,例如: BIC R0, R0, #0x1F ;清除R0寄存器的4:0位。


#####ORR (logical OR)

ORR{S}{cond} Rd, Rn, Operand2

与BIC类似,ORR指令对Rn和Operand2进行OR操作。


#####MSR (general-purpose register to PSR)
与MRS的功能相反。

MSR{cond} PSR_flags, Rm

PSR CPSR或SPSR
flags cxsf中的一个或多个。

CPSR_f、CPSR_x、CPSR_s和CPSR_c通过掩码方式分别表示CPSR的四个域:
f: 标志域掩码(PSR [31:24])
s: 状态域掩码(PSR[23:16])
x: 扩展域掩码(PSR[15:8])
c: 控制域掩码(PSR[7:0])

Rm 源寄存器,不能使用PC


#####LDR (load register)
将label所指的内容放入寄存器。

LDR{type}{cond}{.W} Rt, label

Rt 目标寄存器
label 标识符

#####ADD (add without carry) 和 SUB (subtract without carry)
ADD{cond} {Rd}, Rn, Operand2
SUB{cond} {Rd}, Rn, Operand2

Rd 目标寄存器
Rn 存有第一个操作数的寄存器
Operand2 第二个操作数


#####LDM (load multiple register) 和 STM (store multiple register)
LDM{addr_mode}{cond} Rn{!}, reglist{^}
STM{addr_mode}{cond} Rn{!}, reglist{^}

addr_mode 见 ARM926EJ-S Technical Reference Manual
Rn 基址寄存器 (base register) ,代表开始传输的起始地址,不能是PC;

! 回写后缀,最终运算结果会写回到Rn中:

例如:LDM SP!, {R0-R2, R3} 结果:R0 = *SP R1 = *(SP + 4) R2 = *(SP + 8) R3 = *(SP + 12) SP = SP + 12

reglist 寄存器列表,可以操作R0至R15
^ A32[^A32 and T32]模式下可用的后缀,并且不能在 User 和 System
模式下使用。表示保存或读取到User模式的寄存器而不是当前模式的寄存器。

[^A32 and T32]: A32 (ARM) 指令集全部为32位指令,T32 (Thumb) 指令集为32位指令和某些架构下16位指令的混合指令集。T32模式下,能够提高代码密度,但会牺牲一些性能。T32指令功能与A32指令几乎完全相同,但是在某些指令中,T32模式会有额外的限制,具体参考ARM926EJ-S Technical Reference Manual。

可以使用STM和LDM来实现压栈和弹栈操作 此时Rn一般为SP,配合面向堆栈的后缀 (Stack-oriented suffixes) 实现压栈和弹栈的操作。 4种 Stack-oriented suffixes 分别为

  • FD Full Descending stack
  • FA Full Ascending stack
  • ED Empty Descending stack
  • EA Empty Ascending stack

其中:
Full 表示 SP 在传递前指向栈中最后一个有数据的地址 (full stack) ;
Empty 表示 SP 在传递前指向栈中第一个空闲的地址 (empty stack) ;
Descending 表示堆栈地址由高到低向下生长
Ascending 表示堆栈地址由低到高向上生长

##IRQ与FIQ配置
如果需要使用 IRQ 和 FIQ,则 ARM 不能工作在 User 模式下,一般选择工作在 System 模式。在有操作系统的时候,System 模式用来执行操作系统的底层功能,User 模式用来执行操作系统的任务。

ARM 上电后首先进入 Supervisor 模式,执行 _c_int003 后会进入 User 模式。Privileged 模下式可以通过直接操作CPSR切换为其他模式,但进入 User 模式后,如果想切换成别的模式,是不能通过操作CPSR完成的。

在 User 模式下切换模式可以通过调用编译器原语 (Compiler intrinsic) _call_swi()进入 Supervisor 模式,再切换到 FIQ 和 IRQ 模式,配置其各自的栈区,之后使能PSR中的中断标志。

###ARM的中断机制
和 DSP 的多中断机制不同,ARM 内核只有两个中断—— FIQ 和 IRQ,也被称为宿主中断 (host interrupts)。

ARM 通过中断通道 (channel) 的方式,可以响应101种中断源的中断信息,这101种中断源称为系统中断 (system interrupts)。

101个中断源中:
中断0和1为 JTAG Debug 用的;
中断2为 NINT 不可屏蔽中断,相当于DSP的 NMI;
中断3到10为 PRU 中断。
因此实际 ARM 上可用的外设中断源为91个。

通道0和1通过硬连接 (hard-wired) 映射到 FIQ 上,通道2到31映射到 IRQ 上。通道0的优先级最高,通道31的优先级最低。

###中断映射与执行
####C语言
初始化中断配置之前,调用以下 intrinsics 禁用中断

_disable_interrupts();
或
_disable_IRQ();
_disable_FIQ();

AINTC->VBR中配置系统中断服务函数 (Interrupt Service Routine, ISR) 向量表地址。System ISR 向量表可以是C语言的函数指针列表,这个函数列表是中断向量化的重要组成部分,当一个中断被触发时,AINTC->GPVR中保存了当前处于挂起 (Pending) 状态的优先级最高的 System Interrupt ISR 的地址,因此在 Host ISR 中,不需要查询再跳转到 System ISR,只需要跳转到 AINTC->GPVR中的地址开始执行就可以了,这种机制被称为中断向量化 (Interrupt Vectorization)

static void (*AIntC0IsrTable[IRQ_END_OF_INTERRUPTS])(void);

AINTC->VBR = (unsigned int) AIntC0IsrTable;

此时每一个指针占用一个字 (32-bit word),因此相应的配置 AINTC->VSR为0,表示中断服务函数长度为4字节。

AINTC->CMR[n]共有26个(0到25),每个寄存器对应4个 System Interrupt,寄存器内容为要映射到的通道号,如要将中断58 USB0_INT 映射到通道3的代码为

AINTC->CMR[14] = 3 << 16; // CMR[14]的4个字节由高到低对应中断 59 58 57 56
AINTC->ESR1 = 1 << 26; // 使能 System Interrupt 58

_enable_FIQ();
_enable_IRQ();

####Assembly
#####Host ISR 映射
在ARM中,某一个异常被激发后,PC指针会跳转到固定的地址,执行 Host ISR。

异常 地址
Reset Interrupt 0xFFFF0000
Undefined Instructions Interrupt 0xFFFF0004
Software Interrupt 0xFFFF0008
Prefetch Abort Interrupt 0xFFFF000C
Data Abort Interrupt 0xFFFF0010
Reserved For Future Expansion 0xFFFF0014
IRQ Interrupt 0xFFFF0018
FIQ Interrupt 0xFFFF001C

其中 0xFFFF0000 为 OMAPL138 ARM 片上 RAM 的起始地址,因此在系统初始化时,需要将异常处理函数的写入上述地址:

;****************************************************************************
;* MAP EXCEPTION HANDLER TO CORRESPONDING EXCEPTION ADDRESS
;****************************************************************************
 	.sect ".intvecs"        ;  定义一个初始化的段 .intvecs
INT_VECS:					;  EXCEPTION						  ADDRESS
 	LDR PC, __c_int00      	;Reset Interrupt					(0xFFFF0000)
 	.word 0					;Undefined Instructions Interrupt	(0xFFFF0004)
 	LDR PC, __SWI_handler	;Software Interrupt					(0xFFFF0008)
 	.word 0		    		;Prefetch Abort Interrupt			(0xFFFF000C)
 	.word 0			 		;Data Abort Interrupt				(0xFFFF0010)
 	.word 0					;Reserved For Future Expansion		(0xFFFF0014)
 	LDR PC, __IRQ_handler	;IRQ Interrupt						(0xFFFF0018)
 	LDR PC, __FIQ_handler	;FIQ Interrupt						(0xFFFF001C)

在cmd文件中

--retain INTVECT[^retain] // 如果使用EABI (ELF)格式,需要这句话
MEMORY
{
	ARMRAM:      		o = 0xFFFF0000  l = 0x00002000
    ARM_DDR2:			o = 0xC0000000	l = 0x04000000	// 64MB
}

SECTIONS
{
    .intvecs	>	ARMRAM				/* Interrupt Vectors				*/
}

关于 --retain编译选项

使用EABI (ELF) 格式编译的情况下,默认不会编译未使用的符号,对于整个程序来说,没有显示调用INT_VECS的地方,因此对于编译器会将INT_VECS识别为未使用的符号,这样就会导致最终的可执行程序中没有这一段代码,表现为程序跑飞。

#####Host ISR
以 IRQ 中断为例

;****************************************************************************
;* FUNCTION DEF: IRQ_handler
;****************************************************************************	
IRQ_handler:.asmfunc					; .asmfunc 与 编译选项 -g (--symdebug:dwarf) 配合使用,像C/C++调试一样调试汇编
		STMFD	SP!, {R0-R12, R14}		; 压栈,保护之前的模式现场
		SUB		SP, SP, #0x4			; 调整栈顶指针,指向 empty stack 应该可以用 STMED 代替 STMFD 和 SUB 这两句
		LDR		R0, _AINTC_GPVR_ADDR	; 将 GPVR 的地址读入 R0
		LDR		R1, [R0]				; 将 GPVR 中的内容,即当前待处理的中断里,优先级最高的中断 ISR 的地址读入 R1
		ADD		R14, PC, #0x0			; 保存 PC 到 LR 中
										; 实际存入 LR 的 PC 数值是 debug 时看到的 PC 值加8,即 PC = PC + 8 bytes,原因见下方说明
		LDR		PC, [R1]				; 执行 System ISR
										; System ISR执行完毕后执行下一行汇编指令
		ADD		SP, SP, #0x4			; 调整栈顶指针,指向 full stack
		LDMFD	SP!, {R0-R12, R14}		; 弹栈,恢复现场
		SUBS	PC, R14, #0x4			; 返回之前的状态,R14-4表示原现场执行完ADD		R14, PC, #0x0 后接下来要执行的指令
	.endasmfunc

关于 PC = PC + 8
ARM7(ARMv3 或 ARMv4架构,冯诺依曼结构内核)是三级流水,FETCH - DECODE - EXECUTE。PC 始终指向取指的地址,而不是运行的地址
因此,当 ADD R14, PC, #0x0被执行时,PC 已经指向了 ADD SP, SP, #0x4,所以执行后有 PC = PC + 8。
在ARM9(ARMv4或ARMv5架构,哈佛结构内核)是五级流水,FETCH - DECODE - EXECUTE - MEMORY - WRITE,但仍然是 PC = PC + 8,因为EXECUTE所处的流水线深度和ARM7是一样的,都是(从1起)第3级,所以与ARM7的三级流水情况一样。

##设定程序入口(Entry Point)


  1. DSP L2 ROM是只读的。 ↩︎

  2. 连接仿真器的时候,程序没有任何问题也可能跑飞。 ↩︎

  3. 这个函数在 RTS 库里,源文件在 CCS 编译器目录下的 boot.asm。 ↩︎

你可能感兴趣的:(SoC,DSP,bootloader)