2010-09-18 91 views
1

現在, 在dwelch的這個線程中進行了一些長時間的討論之後,我的懷疑已經變成了確切點。當我們打開嵌入式主板時會發生什麼?

「如果您想知道處理器如何準備好執行第一條指令,那麼邏輯的設計方式就是」邏輯如何設計?你能給我更多的想法嗎?有沒有任何文件給我更多的細節?所有體系結構背後的算法是相同的嗎?

+0

不知道哪個板子是不可能的...除此之外,你的董事會的文件應該告訴你更多 – stijn 2010-09-18 14:35:00

+1

當我這樣做時,白色的煙霧。具體而言,請提及您感興趣的板類型。 – 2010-09-18 14:35:36

+0

這是一個普遍性問題,並非針對定製處理器或主板。但是你可以用你的處理器流程回覆你的想法,所以我也能理解。 – 2010-09-20 05:01:37

回答

2

「如果你想知道處理器 如何準備好執行第一 指令的方式的邏輯是 設計的」 - 如何邏輯的設計? 你能給我更多的想法嗎?有 有沒有任何文件給我更多 的詳細資料?所有 體系結構背後的算法是否相同?

從概念上講,程序計數器(PC)可能被認爲具有與指令週期有關的增量邏輯。它可以被認爲是在每個指令週期結束時執行的以下邏輯。

if (RESET)   //reset pin input is asserted 
    PC = 0x0000; // or any other predetermined value 
else 
    PC = PC + length(currentInstruction); 

爲了便於理解,可以考慮在每個時鐘週期執行1條指令的處理器。另外考慮所有的指令都是相同的大小(4個字節)。

則邏輯變得更簡單

if (RESET) 
    PC = 0x0000; 
else 
    PC = PC + 4; 

現在這個邏輯決策是很簡單的實現爲使用柵極的數字邏輯電路,其具有輸入 - RESET,和PC和輸出 - PC,並通過時鐘處理器時鐘。只要RESET信號有效,就會有其他邏輯禁止執行流水線和取數據電路。

當RESET置位時,PC載入重啓地址。

現在聲明和釋放RESET信號的責任在於復位電路,它只有在它接收到POWERGOOD信號和/或CLOCKSTABLE信號後纔會選擇這樣做。

時鐘信號穩定並可用後,clockgenerator輸出CLOCKSTABLE。

POWERGOOD信號在電壓穩定後由電源電路斷言。

所有這些信號可能不存在或在特定平臺中使用。通常在所有處理器上都可以找到RESET信號。

一旦RESET信號被釋放,執行流水線被啓用並且執行邏輯從該地址啓動FETCH。

關於數字邏輯設計的書通常會有這種信息。並舉例說明如何設計ALU。每個體系結構背後的PC遞增算法將是相似的(概念上),但必須考慮處理器設計的特性。

如果處理器支持根據跳線設置2個不同的充重啓地址,它通常可以通過具有在所述處理器上的附加管腳,其連接到其可以其拉至邏輯1或0。

跳線實現

現在PC遞增邏輯變爲

if (RESET) 
    if(RESETADDRESSJUMPER) 
     PC = 0x0000; 
    else 
     PC = 0xfff0; 
else 
    PC = PC + 4; 

同樣地,也可以定義任何複雜的邏輯復位由所述處理器體系結構所需的處理器。

0

它取決於電路板上的CPU - 以及內存中的內容(ROM或EPROM的變體之一)。

一種情況是,處理器在地址0處執行代碼 - 所以硬件必須確保處理器有一些有效的代碼在該地址執行,例如JMP os_start跳轉到操作系統的啓動真實的代碼。

另一種情況是,處理器將啓動視爲發生了特定中斷,並在非零的已知地址處查找中斷處理程序。同樣,硬件必須確保處理器在該地址執行有一些有效的代碼。

在這兩種情況下,跳轉到的代碼通常是引導程序加載程序 - 一個非常小的程序,它可以複製一些關鍵數據或設置一些關鍵值,然後加載一個更大的程序來完成更多工作。

1

不可能告訴系統(即CPU)如何啓動,因爲它可以是特定實現並且在CPU之間不同。然而,它通常看起來像這樣:

一旦系統啓動,CPU使用中斷向量表跳轉到重置代碼。 CPU需要知道中斷向量的位置,因此它的位置通常是固定的(儘管有CPU可以更改)。假設你使用的是內置閃存中的代碼的嵌入式CPU,這通常意味着復位向量代碼是一個簡單的跳轉指令,用於實際啓動代碼。如果你的應用程序是用匯編語言編寫的,那麼這可能是你的應用程序本身,你就完成了。

如果您的應用程序使用c這樣的高級語言編寫,那麼必須設置c環境。也就是說,需要設置各種內存段:.bss需要歸零,.data需要用變量數據初始化,甚至更多。該系統很可能還需要做一些硬件設置,尤其是時鐘。這部分啓動通常是用匯編語言編寫的(通常是「crt0.S」,至少部分啓動類型也需要在PC上啓動c應用程序)。之後,c環境已建立,主應用程序可以通過調用main函數開始。然而,在一個獨立的環境中(嵌入式系統通常是這樣的,除非你在其上運行嵌入式Linux或類似的東西),與託管環境有一些重要的區別。這裏最重要的是獨立環境不需要具有功能main,也不需要具有通常的原型int main(int argc, char* argv[])。它在系統中的外觀如何與實現相關,但主程序void main(void)的輸入功能很常見。

+0

Thanks.Please請參考我以前回答的評論dwelch – 2010-09-20 05:22:35

4

芯片/處理器文檔中描述了開始執行的處理器內存空間中的哪個地址。在該地址開始執行的過程對於該芯片是真實的,無論它焊接到的電路板的尺寸或用途如何。嵌入式,單板電腦,筆記本主板,臺式機主板,烤麪包機等

電路板的原理圖將顯示上電覆位的來源或來源。如果上電覆位是由可編程器件管理的,那麼您可能無法訪問所有血腥詳細信息來確定發生了什麼,但對於嵌入式開發板,供應商應該已經爲您提供了足夠的時間信息來完成您的工作。某些設備(如閃存)可能需要從功耗達到全功率的某個百分比(例如3.3V的75%)到最初讀取時間的最短時間。或者在復位釋放之前,某些器件在時鐘輸入上需要X個時鐘週期,諸如此類。 Fpga和其他類似的設備從某種類型的prom中加載它們的硬件設計需要一個時鐘,一個上電覆位,一段時間來加載設計等。而fpga可能是處理器的內存控制器,所以在你啓動處理器之前,你可能需要啓動fpga來運行你的flash或ram請求,你可能會讓fpga初始化dram,使它看起來像處理器的sram。處理器重置將不得不暫停,直到發生所有情況。一些電壓調節器或其他設備具有良好的輸出功率,表明功率被調節到所需的電壓並準備使用。管理重置的設備可能會在處理器釋放重置之前等待該電源處於良好狀態。所有這些都是在處理器啓動之前必須發生的一些事情。

一旦芯片/處理器復位被釋放,就如其他答案中所述。

根據處理器的不同,處理器的引腳上可能會有帶選項,用於描述引導配置,這可能會影響執行的起始地址,這將在處理器文檔中介紹。處理器可能總是從已知地址或基於發生的事件,復位,中斷,從低功耗模式/睡眠中喚醒等地址表(向量表,異常表等等,以多種名稱)啓動。處理器/芯片文檔將描述啓動過程和/或如何確定執行的第一條指令的內容或位置。

一旦處理器終於開始執行指令,那麼根據系統的不同,您可能需要啓用USB接口,以便主機可以枚舉設備,您可能需要快速啓用PCI接口,以便主機可以枚舉設備/電路板。如果你有dram,你可能必須在芯片上或者關閉的時候初始化一個dram控制器,在處理器和dram之間的某個地方。如果這些內存或其他內存有某種錯誤檢測或更正,您可能需要初始化該內存以初始化ECC標記。該內存必須先啓動並運行,然後才能將其用於堆棧或初始化.bss和.data。有些設備在芯片內部禁用外設時啓動(如rs232端口,USB等),根據您的應用程序,您可能希望在調用main()之前在啓動代碼中打開它們。董事會可能有LED指示某些事情,有時代碼就是這樣的。

如果你的編譯器生成.data或.bss段,這是一個軟件的事情,硬件沒有這個概念,大多數程序員會更喜歡那些內存段被初始化(毫無疑問在一個標準語言)。對於.bss,這意味着將其歸零,對於.data來說,這意味着用初始值填充。這通常適用於C或其他高級語言,對於自己可能正在管理的彙編器而言,鏈接器可能並不關心被鏈接的對象是C還是彙編器,並且可能會創建獨立於內存的.data,.bss等內存部分源語言。

例如:

 
const int a=27; 
int b=28; 
int c; 

變量a將被放置在所述可執行代碼或的.text段。變量b將被放置在.data中,因爲在調用main()之前,程序員會期望內存位置包含該值。而C會在。bss段,因爲作爲程序員,您希望/期望在main()被調用之前內存位置爲零。

啓動代碼也根據具體情況初始化堆棧指針或指針,它可以啓用緩存並執行各種其他操作。

在reset和main()之間可能會發生很多事情,而且好像我們認爲這是您問題的根源。

既然你提到嵌入式,你可能希望接管啓動代碼。編譯器工具通常會爲目標處理器提供啓動代碼,但它與您的嵌入式處理器內存映射匹配的機率不太可能,至少在使用像gcc這樣的通用編譯器時。對於PIC C編譯器或兔子半導體或某些其他專門針對單一芯片系列的編譯器而言,在編譯時需要指定芯片,並告知編譯器內存映射,以便它可以管理初始化這些區域。 Gcc/binutils支持鏈接器腳本,並且根據目標處理器的性質以及創建該開源代碼的個人,爲各種處理器提供了許多預構建的代碼啓動模塊,您可能可以操縱其中的某些內容,而無需編寫自己的或修改啓動代碼。不管怎麼說,你可能希望這樣做,因爲修改/編寫可能比修改/編寫更容易,而不是找出所有必須轉動的旋鈕,以獲得通用的按鈕來執行所需的操作。

您可以選擇簡化啓動代碼併爲項目或至少引導加載程序創建編程規則,即在使用之前必須初始化所有變量。

例如,而不是:

 
const int a=27; 
int b=28; 
int c; 

是這樣的:

 
const int a=27; 
int b; 
int c; 
void embedded_main (void) 
{ 
    b = 27; 
    c = 0; 
... 

} 

如果你這樣做日啓動代碼不再爲零的.bss或ROM RAM之前複製。數據調用embedded_main()。注意一些編譯器如果看到一個名爲main()的函數,就會在二進制文件中添加額外的(有時)未使用的代碼,如果您瞭解編譯器在做什麼,代碼是什麼以及如果需要它,可以將main()重命名爲任何其他的東西來避免你的二進制文件膨脹並且消耗flash/ROM。

在使用它之前不要初始化變量c(假設它爲零)是不好的形式,一些編譯器會警告您使用可能未初始化的變量。所以你應該初始化它。

通過不準備.bss和.data,您可以在啓動時獲得相當不錯的性能提升,例如,如果您是可能需要每毫秒可以在主機出現之前啓動並運行的PCI目標列舉。您不會在運行時通過初始化變量來保存任何prom,.data段將被替換爲.text段中的代碼,並且根據處理器的不同,它可能會消耗更多的flash來以此方式執行此操作。因此您可以獲得啓動代碼的性能和可移植性,免除了代碼和鏈接器腳本中的許多麻煩,但是如果您不是您稱爲高級代碼的開發人員,則可能會從這些開發人員那裏得到幫助。這是一種折衷,很大程度上取決於系統以及您打算如何處理它。

我的胳膊啓動代碼往往看起來像這樣的例子:

 
.globl _start 
_start: 
    b reset 
    b hang 
    b hang 
    b hang 
    b hang 
    b hang 
    b hang 
    b hang 
    b hang 
    b hang 
    b hang 
    b hang 
    b hang 
    b hang 
    b hang 
    b hang 
    b hang 

reset: 
    ldr sp,=0x2000C000 
    bl notmain 
hang: b hang 

的Cortex-M3的棧指針是零地址就在異常向量表之前,那麼你可以做這樣的事情:

 
.cpu cortex-m3 
.thumb 

.word 0x40080000 
.word _start  
.word hang   
.word hang   
.word hang   
.word hang   
.word hang   
.word hang   
.word hang   
.word hang   
.word hang   
.word hang   
.word hang   
.word hang   
.word hang   
.word hang   
.word hang   
.word hang   
.word hang   
.word hang   


.thumb_func 
hang: b . 

.thumb_func 
.global _start 
_start: 
    bl notmain 
    b hang 
.end 

照照源newlib或glibc的命名文件或crt0.s中的start.s找到支持(通常在彙編各種處理器啓動代碼,並因此會有每個文件該編譯器/庫支持的處理器類型)。

+0

親愛的dwelch,優秀的答案!但我有更多的想法要澄清。當打開一個處理器時,假設它從0x0(處理器製造商專用)開始執行,並執行中斷向量表並跳轉以啓動代碼(引導加載程序),然後執行一些裸板初始化,然後調用main(可以是os_main或app_main取決於系統) – 2010-09-20 04:38:09

+0

和誰配置PC和處理器第一次啓動操作? – 2010-09-20 04:50:45

+0

但我的疑問是堅持第一部分,即打開後它進入0x0(處理器具體),並從那裏開始。誰將PC和處理器配置爲首次從0x0或其他任何地址啓動操作?並且我們不需要讓處理器準備好充當處理器(用於獲取並執行和更新ALU),即我的意思是處理器特定的初始化?(ALU和其他寄存器..)請糾正我是否錯誤。 – 2010-09-20 04:58:03

0

一旦釋放復位,大多數CPU將從復位向量(0x0,0x100,0x80000000,0xfffff100,0xfffffffc)開始。取決於CPu,但通常首先要啓動並運行內存(MMU,SDRAM,ECC總線控制器)。然後,你可以做一些額外的硬件設置,如時鐘,電源管理,看門狗或其他任何東西,但大部分這些都可以在你操作系統或主應用程序完成後完成。現在您將開始一個運行時設置,將您的程序從Flash複製到RAM。您應該準備好運行您的應用程序。在較小的平臺上,您只需在開始之前複製初始化的數據。

+0

謝謝,請查看我對dwelch先前回答的最新評論,以瞭解我確切的疑問。 – 2010-09-20 08:49:14

相關問題