劉力維
(北京信息職業(yè)技術學院人工智能學院 北京 100018)
隨著集成電路技術的不斷發(fā)展,基于處理器的智能系統(tǒng)在移動通信、物聯(lián)網(wǎng)等行業(yè)得到了廣泛應用。處理器的不斷更新?lián)Q代,需要能夠快速開發(fā)出與之相匹配的嵌入式系統(tǒng)。而Boot Loader 作為處理器板級開發(fā)的第一個軟件程序,是整個嵌入式系統(tǒng)板級軟件開發(fā)的基礎[1]。
出于容量和使用成本等方面考慮,用于支撐CPU 系統(tǒng)運行的內(nèi)存設備通常采用動態(tài)隨機存取存儲器(DRAM)。為支持DRAM 正常工作,需要針對DRAM 的控制器(內(nèi)存控制器)完成比較復雜的參數(shù)配置,以滿足DRAM 工作需要的正確時序和刷新要求[2]。因此,內(nèi)存控制器的配置是Boot Loader 啟動過程中的一項重要任務。同時,由于在配置內(nèi)存控制器之前無法使用內(nèi)存,導致無法執(zhí)行高級語言函數(shù)調(diào)用過程中必需的入棧和出棧操作,因此內(nèi)存控制器初始化的代碼不能使用高級語言實現(xiàn)。在很多傳統(tǒng)的Boot Loader 中,這部分功能是使用匯編語言實現(xiàn)的。在實際的板級開發(fā)調(diào)試中,內(nèi)存控制器的初始化過程作為處理器啟動的早期階段,使用匯編語言實現(xiàn)調(diào)試信息的輸出功能,實現(xiàn)代碼較為煩瑣。再加上Boot Loader 每次更新程序都需要進行固件燒寫等因素,導致這一階段一旦出現(xiàn)需要軟硬件聯(lián)調(diào)的問題,調(diào)試手段欠缺,調(diào)試過程復雜,有時還需要額外的CPU 仿真器支持調(diào)試,增加了開發(fā)成本[3]。
高速緩沖存儲器(Cache)在嵌入式系統(tǒng)中通常位于CPU 和DRAM 之間,訪問速度比DRAM 更快。DRAM 訪問時鐘頻率通常會比CPU 主頻低1 ~2 個數(shù)量級,Cache 讀寫訪問時鐘頻率通常介于CPU 主頻和DRAM 訪問時鐘頻率之間。通過對高頻訪問的內(nèi)存數(shù)據(jù)提供緩存,提高CPU 系統(tǒng)的整體數(shù)據(jù)訪問速率[4]。
本文提出的設計方案主要基于Cache 的兩個特性:首先,Cache 在硬件上通常由靜態(tài)隨機存取存儲器(SRAM)實現(xiàn),與DRAM 相比,SRAM 初始化流程簡單,正常通電即可使用,不需要執(zhí)行復雜的時序配置和刷新操作。其次,很多CPU 提供了緩存鎖定功能,可以支持將特定的數(shù)據(jù)鎖定在Cache 中[5]。一些Boot Loader 在啟動過程中充分利用了Cache 的上述兩個特性,實現(xiàn)了使用高級語言進行內(nèi)存控制器的配置。李雪峰[6]給出了一個利用Cache 鎖定實現(xiàn)通過nandflash 啟動Boot Loader 的實例。另一個典型的實例是boot[7],在內(nèi)存控制器初始化之前,首先執(zhí)行相對簡單的Cache 初始化,并將一個由C 語言編寫并單獨編譯的內(nèi)存控制器初始化代碼映像以及需要的??臻g刷新并固定在Cache 中,然后跳轉(zhuǎn)到編譯時指定的程序入口。由于程序的所有代碼都固化在Cache 中,代碼的執(zhí)行過程100%命中Cache,相當于將Cache 當作內(nèi)存來使用,由CPU 和Cache 組成一個臨時的最小系統(tǒng),支持高級語言所編譯生成代碼的執(zhí)行。這樣做的優(yōu)點是顯而易見的:一是可以使用高級語言編寫復雜的內(nèi)存控制器初始化代碼,相對于使用匯編語言編寫更易于實現(xiàn)和修改;二是可以使用高級語言實現(xiàn)串口的輸入輸出,為板級調(diào)試提供更豐富的手段。
隨著處理器的不斷發(fā)展以及片上系統(tǒng)(SOC)和多核處理器在嵌入式系統(tǒng)中的普遍應用,越來越多的處理器在芯片內(nèi)部集成了多級Cache,并且Cache 的容量不斷增大。本文基于上述硬件發(fā)展趨勢,總結并擴展了前述Boot Loader 啟動過程中高級語言代碼映像所實現(xiàn)的功能,提出了一種Boot Loader啟動早期階段的板級調(diào)試交互平臺。該板級調(diào)試交互平臺實現(xiàn)了基于原有Boot Loader 進行功能擴展的方法,充分利用了Cache 系統(tǒng),采用C 語言編寫,通過串口提供基本的用戶交互指令,實現(xiàn)了調(diào)試信息串口輸出、硬件自檢、寄存器讀寫訪問等功能,為復雜的嵌入式系統(tǒng)板級調(diào)試帶來了便利。
板級調(diào)試交互平臺的代碼由C 語言編寫,使用代碼重定位技術[8],并單獨編譯為一個映像。該映像與Boot Loader 其他部分編譯生成的二進制代碼映像一起燒寫到用于支持單板啟動的非易失存儲設備(FLASH、EEPROM 等)中,運行時將被鎖定到Cache 中。
板級調(diào)試交互平臺的啟動和執(zhí)行過程見圖1。圖1 中左側(cè)所列流程是在正常的Boot Loader 啟動流程基礎上,增加了啟動板級調(diào)試交互平臺的條件判斷。板級調(diào)試交互平臺的啟動通過特定條件進行觸發(fā),比如調(diào)試串口上接收到某個特殊字符,或者GPIO 檢測到通過硬件跳線實現(xiàn)的電平變化等。Bootloader 正常啟動過程中,不會滿足該觸發(fā)條件,避免對正常的系統(tǒng)啟動流程產(chǎn)生影響。當需要執(zhí)行板級調(diào)試交互平臺相關功能時,通過執(zhí)行滿足觸發(fā)條件的外部動作,啟動板級調(diào)試交互平臺。新增的判斷是否啟動板級調(diào)試交互平臺功能,作為Boot Loader 正常啟動流程的新增部分,代碼通過匯編語言實現(xiàn)。
圖1 中右側(cè)所列流程為板級調(diào)試交互平臺新增功能。板級調(diào)試交互平臺的執(zhí)行可具體劃分為以下3 個過程。
這部分代碼同樣作為原有Boot Loader 中新增功能,通過匯編語言實現(xiàn)。具體包含如下工作:(1)在正常啟動Boot Loader 流程中Cache 初始化的基礎上,初始化并使能多級Cache,獲得盡可能大的Cache 存儲空間。這里不區(qū)分指令和數(shù)據(jù)Cache,對于只有一級Cache 的情況可以通過分別對指令和數(shù)據(jù)Cache 進行操作實現(xiàn)本設計相關功能。(2)通過讀取存放Boot Loader 的非易失存儲器中的數(shù)據(jù),將板級調(diào)試交互平臺映像中的程序指令刷新到Cache 空間低地址。(3)指定棧頂?shù)刂窞镃ache 空間最高地址。通過上述操作,保證CPU 的讀指令和棧操作兩種內(nèi)存訪問始終命中Cache,實現(xiàn)了由CPU 和Cache 共同構成的最小系統(tǒng)。(4)在CPU 通用寄存器中保存退出調(diào)試交互平臺返回Boot Loader 正常啟動流程時要執(zhí)行的下一條指令地址。這項工作是為退出板級調(diào)試交互平臺返回Boot Loader 正常啟動流程所做的準備。(5)修改當前指令執(zhí)行指針,指向Cache 空間低地址中調(diào)試交互平臺的代碼入口,執(zhí)行跳轉(zhuǎn),開始調(diào)試交互平臺代碼的執(zhí)行[9]。
這部分功能由C 語言映像實現(xiàn),通過串口進行簡單的人機交互(菜單或者簡單的命令行),實現(xiàn)調(diào)試交互主要功能。本平臺實現(xiàn)了硬件自檢和寄存器讀寫功能。具體功能的實現(xiàn)參見本文板級調(diào)試交互平臺的功能分析部分。
這部分代碼主要負責Boot Loader 正常啟動流程的恢復,由板級調(diào)試交互平臺執(zhí)行過程中用戶通過菜單或者命令執(zhí)行的退出操作觸發(fā)。具體包含如下工作:(1)從CPU 通用寄存器中讀出返回Boot Loader 正常啟動流程時的指令地址,并跳轉(zhuǎn)到該地址。上述代碼作為板級調(diào)試交互平臺返回正常Boot Loader 啟動流程的出口,由C 語言實現(xiàn)。(2)在指令跳轉(zhuǎn)目的地址處,進行Cache 的整體刷新或重新初始化,清除鎖定在Cache 中的板級調(diào)試交互平臺代碼。然后繼續(xù)執(zhí)行后續(xù)Boot Loader 初始化流程。這部分代碼由匯編語言實現(xiàn)。
基于嵌入式系統(tǒng)板級調(diào)試早期階段的實際需要,本平臺實現(xiàn)了調(diào)試信息以函數(shù)形式通過串口輸出、寄存器讀寫和硬件自檢功能。
板級調(diào)試早期階段由于調(diào)試手段的缺乏,導致軟件配合硬件定位問題非常復雜。傳統(tǒng)的調(diào)試手段包括在單板啟動的不同階段控制GPIO 輸出不同電平點亮LED,通過LED 狀態(tài)標識單板啟動狀態(tài);以及通過匯編語言控制串口寄存器,實現(xiàn)串口字符的輸出等。上述調(diào)試方法由匯編語言實現(xiàn)的過程較復雜并且不易進行代碼移植,使用中有很大局限性。板級調(diào)試交互平臺代碼通過高級語言編寫,可以通過對串口寄存器的訪問控制實現(xiàn)查詢方式的串口字符輸入輸出。串口字符輸出的具體實現(xiàn)過程見圖2。考慮到不同硬件平臺的差異性,后續(xù)描述過程中忽略了訪問串口控制寄存器的實現(xiàn)細節(jié)。首先循環(huán)查詢串口輸出狀態(tài)寄存器,直到串口輸出緩沖區(qū)處于空閑狀態(tài)為止;在串口空閑狀態(tài)下向發(fā)送寄存器寫入要發(fā)送的字符;再次循環(huán)查詢串口輸出狀態(tài)寄存器,直到輸出緩沖區(qū)處于空閑狀態(tài),本次串口字符發(fā)送完成。上述通過設置和查詢寄存器實現(xiàn)串口字符輸出的過程不依賴于硬件中斷服務。類似的過程也可以實現(xiàn)串口字符的輸入,并且基于單一字符的輸入輸出,可以通過簡單擴展實現(xiàn)字符串的輸入輸出函數(shù)。有了串口字符串輸出這一調(diào)試手段,可以方便地實現(xiàn)調(diào)試數(shù)據(jù)的輸出,為板級調(diào)試提供了極大便利。
調(diào)試交互平臺通過串口輸入輸出實現(xiàn)了基本的人機交互功能,主要用于實現(xiàn)CPU 尋址空間內(nèi)的讀寫訪問??紤]到Cache 容量導致的代碼總量限制,該人機交互功能只負責接收用戶輸入的3 個數(shù)據(jù),分別是:選擇讀操作還是寫操作;輸入訪問操作的CPU 尋址空間起始地址;輸入要訪問的數(shù)據(jù)長度。獲取上述信息后,首先進行輸入地址和訪問長度的有效性判斷,并對有效的地址和長度執(zhí)行訪問,通過串口返回訪問結果。上述訪問適用于板級調(diào)試階段的CPU 尋址空間操作,可用于進行內(nèi)存訪問或者寄存器讀寫。該功能的實現(xiàn)進一步增加了嵌入式系統(tǒng)板級交互調(diào)試手段,避免了反復燒寫B(tài)oot Loader。
調(diào)試交互平臺實現(xiàn)了內(nèi)存和硬件自檢功能[10]。理論上,可以通過CPU 尋址實現(xiàn)讀寫訪問的硬件都能夠?qū)崿F(xiàn)寄存器的讀寫檢測,并設計相應的自檢功能。這部分功能既可用于嵌入式系統(tǒng)開發(fā)過程中板級調(diào)試問題的定位,也可用于生產(chǎn)過程中實現(xiàn)裝備測試功能。
實現(xiàn)板級調(diào)試交互平臺對系統(tǒng)的軟硬件設計存在一定要求。
(1)單板上存在用于實現(xiàn)調(diào)試過程中人機交互的串口,并且該串口可以在Boot Loader 啟動時通過CPU 尋址訪問進行操作。
(2)CPU 芯片內(nèi)部集成或者在板上設計了高速緩存,其容量大于板級調(diào)試交互平臺編譯的映像大小,并有足夠的剩余空間作為函數(shù)調(diào)用??臻g。
(3)由于板級調(diào)試交互生成的編譯映像與Boot Loader 其他部分一起燒寫在非易失存儲器上,會導致Boot Loader 總大小變大,硬件上要求Boot Loader 二進制映像的總大小不超過非易失存儲器總?cè)萘俊?/p>
(4)在板級調(diào)試交互平臺運行過程中占用了一個CPU通用寄存器用于保存返回正常啟動流程時的指令地址。
上述2、3項要求限制了板級調(diào)試交互平臺功能的復雜性,決定了板級調(diào)試交互平臺只適合實現(xiàn)支持軟硬件早期調(diào)試的關鍵功能,不能作為整個Boot Loader 功能的完整替代。
綜上所述,板級調(diào)試交互平臺本質(zhì)上是基于Boot Loader 正常啟動流程的功能擴展,可以方便地移植到各種Boot Loader 中。通過實現(xiàn)板級調(diào)試交互平臺,可以方便地實現(xiàn)調(diào)試信息的串口輸出以及寄存器和內(nèi)存的基本讀寫訪問,極大地方便了CPU 系統(tǒng)的早期軟硬件聯(lián)調(diào),并豐富了CPU 板級系統(tǒng)裝備生產(chǎn)和問題定位的實現(xiàn)手段。