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|
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_modeARM926EJ-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。 ↩︎

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章