第一篇:關(guān)于分析今天長安保定百度愛問愛第2章代碼初識 本章首先從較高層次
的的范德薩的地方愛的規(guī)格愛你啊好文章第2章 代 碼 初 識
本章首先從較高層次介紹Linux內(nèi)核源程序的概況,這些都是大家關(guān)心的一些基本特點。隨后將簡要介紹一些實際代碼。最后介紹如何編譯內(nèi)核。2.1 Linux內(nèi)核源程序的部分特點
在過去的一段時期,Linux內(nèi)核同時使用C語言和匯編語言來實現(xiàn)。這兩種語言需要一定的平衡:C語言編寫的代碼移植性較好、易于維護,而匯編語言編寫的程序則速度較快。一般只有在速度是關(guān)鍵因素或者一些因平臺相關(guān)特性而產(chǎn)生的特殊要求(例如直接和內(nèi)存管理硬件進行通訊)時才使用匯編語言。
正如實際中所做的,即使內(nèi)核并未使用C++的對象特性,部分內(nèi)核也可以在g++(GNU的C++編譯器)下進行編譯。同其他面向?qū)ο蟮木幊陶Z言相比較,相對而言C++的開銷是較低的,但是對于內(nèi)核開發(fā)人員來說,這已經(jīng)是太多了。
內(nèi)核開發(fā)人員不斷發(fā)展編程風(fēng)格,形成了Linux代碼獨有的特色。本節(jié)將討論其中的一些問題。
2.1.1 gcc特性的使用
Linux內(nèi)核被設(shè)計為必須使用GNU的C編譯器gcc來編譯,而不是任何一種C編譯器都可以使用。內(nèi)核代碼有時要使用gcc特性,本書將陸續(xù)介紹其中的一部分。一些gcc特有代碼只是簡單地使用gcc語言擴展,例如允許在C(不只是C++)中使用inline關(guān)鍵字指示內(nèi)聯(lián)函數(shù)。也就是說,代碼中被調(diào)用的函數(shù)在每次函數(shù)調(diào)用時都會被擴充,因而就可以節(jié)約實際函數(shù)調(diào)用的開銷。
一般情況下,代碼的編寫方式比較復(fù)雜。因為對于某些類型的輸入,gcc能夠產(chǎn)生比其他輸入效率更高的執(zhí)行代碼。從理論上講,編譯器可以優(yōu)化具有相同功能的兩種對等的方法,并且得到相同的結(jié)果。因此,代碼的編寫方式是無關(guān)緊要的。但在實際上,用某種方法編寫所產(chǎn)生的代碼要比用另外一些方法編寫所產(chǎn)生的代碼執(zhí)行速度快許多。內(nèi)核開發(fā)人員知道怎樣才能產(chǎn)生更高效的執(zhí)行代碼,這不斷地在他們編寫的代碼中反映出來。例如,考慮內(nèi)核中經(jīng)常使用的goto語句—為了提高速度,內(nèi)核中經(jīng)常大量使用這種一般要避免使用的語句。在本書中所包含的不到40 000行代碼中,一共有500多條goto語句,大約是每80行一個。除匯編文件外,精確的統(tǒng)計數(shù)字是接近每72行一個goto語句。公平地說,這是選擇偏向的結(jié)果:比例如此高的原因之一是本書中涉及的是內(nèi)核源程序的核心,在這里速度比其他因素都需要優(yōu)先考慮。整個內(nèi)核的比例大概是每260行一個goto語句。然而,這仍然是我不再使用Basic進行編程以來見過的使用goto頻率最高的地方。
代碼必需受特定編譯器限制的特性不僅與普通應(yīng)用程序的開發(fā)有很大不同,而且也不同于大多數(shù)內(nèi)核的開發(fā)。大多數(shù)的開發(fā)人員使用C語言編寫代碼來保持較高的可移植性,即使在編寫操作系統(tǒng)時也是如此。這樣做的優(yōu)點是顯而易見的,最為重要的一點是一旦出現(xiàn)更好的編譯器,程序員們可以隨時進行更換。
內(nèi)核對于gcc特性的完全依賴使得內(nèi)核向新的編譯器上移植更加困難。最近Linus對這一問題在有關(guān)內(nèi)核的郵件列表上表明了自己的觀點:“記住,編譯器只是一個工具。”這是對依賴于gcc特性的一個很好的基本思想的表述:編譯器只是為了完成工作。如果通過遵守標準還不能達到工作要求,那么就不是工作要求有問題,而是對于標準的依賴有問題。
在大多數(shù)情況下,這種觀點是不能被人所接受的。通常情況下,為了保證和程序語言標準的一致,開發(fā)人員可能需要犧牲某些特性、速度或者其他相關(guān)因素。其他的選擇可能會為后期開發(fā)造成很大的麻煩。
但是,在這種特定的情況下,Linus是正確的。Linux內(nèi)核是一個特例,因為其執(zhí)行速度要比向其他編譯器的可移植性遠為重要。如果設(shè)計目標是編寫一個可移植性好而不要求快速運行的內(nèi)核,或者是編寫一個任何人都可以使用自己喜歡的編譯器進行編譯的內(nèi)核,那么結(jié)論就可能會有所不同了;而這些恰好不是Linux的設(shè)計目標。實際上,gcc幾乎可以為所有能夠運行Linux的CPU生成代碼,因此,對于gcc的依賴并不是可移植性的嚴重障礙。在第3章中我們將對內(nèi)核設(shè)計目標進行詳細說明。2.1.2 內(nèi)核代碼習(xí)慣用語
內(nèi)核代碼中使用了一些顯著的習(xí)慣用語,本節(jié)將介紹常用的幾個。當通讀源代碼時,真正重要的問題并不在這些習(xí)慣用語本身,而是這種類型的習(xí)慣用語的確存在,而且是不斷被使用和發(fā)展的。如果你需要編寫內(nèi)核代碼,你應(yīng)該注意到內(nèi)核中所使用的習(xí)慣用語,并把這些習(xí)慣用語應(yīng)用到你的代碼中。當通讀本書(或者代碼)時,看看你還能找到多少習(xí)慣用語。為了討論這些習(xí)慣用語,我們首先需要對它們進行命名。為了便于討論,筆者創(chuàng)造了這些名字。而在實際中,大家不一定非要參考這些用語,它們只是對內(nèi)核工作方式的描述而已。一個普通的習(xí)慣用語,筆者稱之為“資源獲取”(resource acquisition idiom)。在這個用語中,一個函數(shù)必須實現(xiàn)一系列資源的獲取,包括內(nèi)存、鎖等等(這些資源的類型未必相同)。只有成功地獲取當前所需要的資源之后,才能處理后面的資源請求。最后,該函數(shù)還必須釋放所有已經(jīng)獲取的資源,而不必考慮沒有獲取的資源。
我采用“錯誤變量”這一用語(error variable idiom)來輔助說明資源獲取用語,它使用一個臨時變量來記錄函數(shù)的期望返回值。當然,相當多的函數(shù)都能實現(xiàn)這個功能。但是錯誤變量的不同點在于它通常是用來處理由于速度的因素而變得非常復(fù)雜的流程控制中的問題。錯誤變量有兩個典型的值,0(表示成功)和負數(shù)(表示有錯)。
這兩個用語結(jié)合使用,我們就可以十分自然地得到符合模式的代碼如下:
(注意變量err是使用錯誤變量的一個明確實例,同樣,諸如out之類的標號則指明了資源獲取用語的使用。)
如果執(zhí)行到標號out2,則都已經(jīng)獲取了r1和r2資源,而且也都需要進行釋放。如果執(zhí)行到標號out1(不管是順序執(zhí)行還是使用goto語句進行跳轉(zhuǎn)到),則r2資源是無效的(也可能剛被釋放),但是r1資源卻是有效的,而且必需在此將其釋放。同理,如果標號out能被執(zhí)行,則r1和r2資源都無效,err所返回的是錯誤或成功標志。
在這個簡單的例子中,對err的一些賦值是沒有必要的。在實踐中,實際代碼必須遵守這種模式。這樣做的原因主要在于同一行中可能包含有多種測試,而這些測試應(yīng)該返回相同的錯誤代碼,因此對錯誤變量統(tǒng)一賦值要比多次賦值更為簡單。雖然在這個例子中對于這種屬性的必要性并不非常迫切,但是我還是傾向于保留這種特點。有關(guān)的實際應(yīng)用可以參考sys_shmctl(第21654行),在第9章中還將詳細介紹這個例子。2.1.3 減少#if和#ifdef的使用
現(xiàn)在的Linux內(nèi)核已經(jīng)移植到不同的平臺上,但是我們還必須解決移植過程中所出現(xiàn)的問題。大部分支持各種不同平臺的代碼由于包含許多預(yù)處理代碼而已經(jīng)變得非常不規(guī)范,例如: 這個例子試圖實現(xiàn)操作系統(tǒng)的可移植性,雖然Linux關(guān)注的焦點很明顯是實現(xiàn)代碼在各種CPU上的可移植性,但是二者的基本原理是一致的。對于這類問題來說,預(yù)處理器是一種錯誤的解決方式。這些雜亂的問題使得代碼晦澀難懂。更為糟糕的是,增加對新平臺的支持有可能要求重新遍歷這些雜亂分布的低質(zhì)量代碼段(實際上你很難能找到這類代碼段的全部)。與現(xiàn)有方式不同的是,Linux一般通過簡單函數(shù)(或者是宏)調(diào)用來抽象出不同平臺間的差異。內(nèi)核的移植可以通過實現(xiàn)適合于相應(yīng)平臺的函數(shù)(或宏)來實現(xiàn)。這樣不僅使代碼的主體簡單易懂,而且在移植的過程中還可以比較容易地自動檢測出你沒有注意到的內(nèi)容:如引用未聲明函數(shù)時會出現(xiàn)鏈接錯誤。有時用預(yù)處理器來支持不同的體系結(jié)構(gòu),但這種方式并不常用,而相對于代碼風(fēng)格的變化就更是微不足道了。
順便說一下,我們可以注意到這種解決方法和使用用戶對象(或者C語言中充滿函數(shù)指針的struct結(jié)構(gòu))來代替離散的switch語句處理不同類型的方法十分相似。在某些層次上,這些問題和解決方法是統(tǒng)一的。
可移植性的問題并不僅限于平臺和CPU的移植,編譯器也是一個重要的問題。此處為了簡化,假設(shè)Linux只使用gcc來編譯。由于Linux只使用同一個編譯器,所以就沒有必要使用#if塊(或者#ifdef塊)來選擇不同的編譯器。
內(nèi)核代碼主要使用#ifdef來區(qū)分需要編譯或不需要編譯的部分,從而對不同的結(jié)構(gòu)提供支持。例如,代碼經(jīng)常測試SMP宏是否定義過,從而決定是否支持SMP機。2.2 代碼樣例
了解Linux代碼風(fēng)格最好的方法就是實際研究一下它的部分代碼。即使你不完全理解本節(jié)所討論代碼的細節(jié)也無關(guān)緊要,畢竟本節(jié)的主要目的不是理解代碼,一些讀者可以只對本節(jié)進行瀏覽。本節(jié)的主要目的是讓讀者對Linux代碼進行初步了解,為今后的工作提供必要基礎(chǔ)。該討論將涉及部分廣泛使用的內(nèi)核代碼。2.2.1 printk printk(25836行)是內(nèi)核內(nèi)部消息日志記錄函數(shù)。在出現(xiàn)諸如內(nèi)核檢測到其數(shù)據(jù)結(jié)構(gòu)出現(xiàn)不一致的事件時,內(nèi)核會使用printk把相關(guān)信息打印到系統(tǒng)控制臺上。對于printk的調(diào)用一般分為如下幾類:
?緊急事件(emergency)—例如,panic函數(shù)(25563行)多次使用了printk。當內(nèi)核檢測到發(fā)生不可恢復(fù)的內(nèi)部錯誤時就會調(diào)用panic函數(shù),然后盡其所能地安全關(guān)閉計算機。這個函數(shù)中調(diào)用printk以提示用戶系統(tǒng)將要關(guān)閉。
?調(diào)試—從3816行開始的#ifdef塊使用printk來打印SMP邏輯單元(box)中每一個處理器的相關(guān)配置信息,但是此過程只有在使用SMP_DEBUG標志編譯代碼的情況下才能夠被執(zhí)行。?普通信息—例如,當機器啟動時,內(nèi)核必須估計系統(tǒng)速度以確保設(shè)備驅(qū)動程序能夠忙等待(busy-wait)一個精確的極短周期。計算這種估計值的函數(shù)名為calibrate_delay(19654行),它既在19661行使用printk聲明馬上開始計算,又在19693行報告計算結(jié)果。另外,在第4章將詳細的介紹calibrate_delay函數(shù)。
如果你已經(jīng)瀏覽過這些參照行,你可能已經(jīng)注意到printk和printf的參數(shù)十分類似:一個格式化字符串,后跟零個或者多個參數(shù)加入字符串中。格式化字符串可能是以一組“
從14946行開始的#define塊說明了這些特殊序列,這些定義可以幫助調(diào)用者正確區(qū)分對printk的調(diào)用。簡單地說,我稱日志等級0到4為“緊急事件”,等級5到等級6為“普通信息”,等級7自然就是我所說的“調(diào)試”(這種分類方法并不意味著其他更好的分類方法沒有用處,而只是目前我們還不關(guān)心它而已)。在上面討論的基礎(chǔ)上,我們研究一下代碼本身。printk 25836:參數(shù)fmt是printf類型的格式化字符串。如果你對“...”部分的內(nèi)容不熟悉,那就 需要參閱一本好的C語言參考書(在其索引中查找“變參函數(shù),variadic function”)。另外,在安裝的GNU/Linux中的stdarg幫助里也包含了一個有關(guān)變參函數(shù)的簡明描述,在這兒只需要敲入“man stdarg”就可以看到。簡單地說,“...”部分提示編譯器fmt后面可能緊跟著數(shù)量不定的任何類型的參數(shù)。由于這些參數(shù)在編譯的時候還沒有類型和名字,內(nèi)核使用由三個宏va_start、va_arg和va_end組成的特殊組及一個特殊類型—va_list對它們進行處理。25842:msg_level記錄了當前消息的日志等級。它是靜態(tài)的,這看起來可能會有些奇怪—為什么下一次對printk的調(diào)用需要記錄日志等級呢?問題的答案是只有打印出新行(n)或者賦給一個新的日志等級序列以后,當前消息才會結(jié)束。這樣,通過在包含消息結(jié)束的新行里調(diào)用printk,就保證了在多個短期沖突的情況下,調(diào)用者只打印唯一一個長消息。
25845:在SMP邏輯單元中,內(nèi)核可能試圖從不同的CPU向控制臺同時打印信息(有時在單處理機(UP)邏輯單元中也會發(fā)生同樣問題,但由于中斷還未被覆蓋掉,所以問題也并不十分明顯)。如果不進行任何協(xié)同的話,結(jié)果就將處于完全無法讓人了解的雜亂無章的狀態(tài),每個消息的各個部分都和其他消息的各個部分混雜交織在一起。
相反,內(nèi)核使用旋轉(zhuǎn)鎖(spin-lock)來控制對控制臺的訪問。旋轉(zhuǎn)鎖將在第10章進行深入介紹。
如果你對flags 在傳送給spin_lock_irqsave之前為什么不對它初始化感到疑惑,請不要擔(dān)心:spin_lock_irqsave(對于不同的版本請分別參看12614行,12637行,12716行和12837行)是一個宏,而不是一個函數(shù)。該宏實際上是將值寫入flags中,而不是從flags中讀出值(在25895行中,存儲在flags中的信息被spin_unlock_irqrestore回讀,請參看12616行,12639行,12728行和12841行)。
25846:初始化變量args,該變量代表printk參數(shù)中的“...”部分。25848:調(diào)用內(nèi)核自身的vsprintf(為節(jié)省空間而省略)實現(xiàn)。該函數(shù)的功能與標準vsprintf函數(shù)非常相似,向buf中寫入格式化文本(25634行)并返回寫入字符串的長度(長度不包括最后一位終止字符0字節(jié))。很快,你將可以看到為什么這種機制會忽略buf的前三個字符。(正如25847行的注釋中所述)我們應(yīng)該注意到在這里并沒有采取嚴格的措施來保證緩沖器不會過載。這里系統(tǒng)假定1024個字符長度的buf已經(jīng)足夠使用(參閱25634行)。如果內(nèi)核在這里能夠使用vsnprintf函數(shù)的話,情況就會好許多。然而,vsnprintf還有另外一個參數(shù)限制了它能夠?qū)懭刖彌_器的字符長度。
25849:計算buf中最近使用的元素,調(diào)用va_end終止對“...”參數(shù)的處理。
25851:開始格式化消息的循環(huán)。其中存在一個內(nèi)部循環(huán)能夠處理更多內(nèi)容(這一點隨后就能看到),因此,每次內(nèi)循環(huán)開始,都開始一個新的打印行。由于通常情況下printk只用于打印單行,所以在每次調(diào)用中,這種循環(huán)通常只執(zhí)行一次。
25853:如果預(yù)先不知道消息的日志等級,printk會檢查當前行是否以日志等級序列開頭。25860:如果不是,buf中開始未使用的三個字符就能夠起作用了(第一次以后的每次循環(huán),都會覆蓋部分消息文本,但是這樣并不會引起問題,因為這里的文本只是前面行中的一部分,它們已經(jīng)被打印過,而且以后也不再需要了)。這樣,就可以將日志等級插入buf中。25866:此處有如下屬性:p指向日志等級序列(消息文本緊隨其后),msg指向消息文本—請注意25852行和25865行中對msg的賦值。
由于已知p用來指示日志等級序列的開頭—該日志等級序列可能是由函數(shù)自身所創(chuàng)建的,日志等級可以從p中抽出并存到msg_level中。25868:沒有檢測到新行,清空line_feed標志。
25869:這是前面談到過的內(nèi)循環(huán),循環(huán)將運行到本行結(jié)束(也就是檢測到新行標志)或者緩沖器的末尾為止。
25870:除了將消息打印到控制臺之外,printk還能夠記錄最近打印的長度為LOG_ BUF_LEN的字符組(LOG_BUF_LEN為16K,請參看25632行)。如果在控制臺打開之前,內(nèi)核就已經(jīng)調(diào)用printk,則顯然不能在控制臺上正確打印消息,但是這些消息將被盡可能地存儲到log_buf中(25656行)。當控制臺打開以后,緩存在log_buf中的數(shù)據(jù)就可以轉(zhuǎn)儲并在控制臺上打印出來,請參看25988行。
log_buf是一個循環(huán)緩沖器,log_start和log_size變量(25657行和25646行)分別記錄當前緩沖器的開始位置和長度。本行中的按位與(AND)操作實際上是快速求模(%)運算,它的正確性依賴于LOG_BUF_LEN的值是2的冪。25872:保存變量跟蹤記錄循環(huán)日志的值。顯然,日志大小會不斷增長,直至達到LOG_BUF_LEN的值為止。此后,log_size將保持不變,而插入新字符將導(dǎo)致log_start的增長。
25878:請注意logged_chars(25658行)記錄從機器啟動之后由printk寫入的所有字符的長度,它在每次循環(huán)中都會被更新,而不是在循環(huán)結(jié)束后才改變一次?;谕瑯拥牡览恚琹og_start和log_size的處理方式也是一樣。這實際上是一種優(yōu)化的時機,本書將在結(jié)束對函數(shù)的介紹之后再對它進行詳細討論。
25879:消息被分為若干行,這當然要使用新行標志符來進行分割。一旦內(nèi)核檢測到新行標志符,就寫入一個完整行,從而內(nèi)循環(huán)的執(zhí)行也可以提前終止。25884:在這里我們先不考慮內(nèi)部循環(huán)是否會提前退出,從msg到p的字符序列是專門提供給控制臺使用的(這種字符序列我稱之為行,但是不要忘了,這里的行可能并不意味著新行終止,因為buf也許還沒有終止)。如果該行的日志等級高于系統(tǒng)控制臺定義的日志等級,而且當前又有控制臺可供打印,那么就能夠正確打印該行。(記住,printk可能在所有控制臺打開之前就已經(jīng)被調(diào)用過了。)
如果在該消息塊中沒有發(fā)現(xiàn)日志等級序列,并且在前面的printk調(diào)用中也沒有對msg_level賦值,那么本行中的msg_level就是-1。由于console_loglevel總不小于1(除非root通過sysctl接口鎖定),于是總是可以打印這些行。
25886:本行應(yīng)該能夠被打印。printk通過遍歷打開的控制臺驅(qū)動鏈表告知每一個控制臺驅(qū)動去打印當前行設(shè)備驅(qū)動在本書的討論范圍之外,因此,控制臺驅(qū)動代碼則并不包含在內(nèi))。25888:請注意這里消息文本的開頭使用的是msg而不是p,這樣就在沒有日志等級序列的情況下寫入消息了。然而,日志等級序列已經(jīng)被存儲到log_buf緩沖器中了。這樣就使后來能夠訪問log_buf以獲取消息日志等級的代碼(請參看25998行),不會再產(chǎn)生顯示混亂信息序列的現(xiàn)象。
25892:如果內(nèi)層for循環(huán)發(fā)現(xiàn)一新行,那么buf中的剩余字符(如果有的話)將被認為是新的消息,因此msg_level會被重置。但是無論怎樣,外層循環(huán)都會持續(xù)到buf清空為止。25895:釋放在25845行獲取的控制臺鎖(console lock)。
25896:喚醒等待被寫入控制臺日志的所有進程。注意即使沒有文本被實際寫入任何控制臺,這個過程也仍然會發(fā)生。這樣處理是正確的,因為無論是否要往控制臺中寫入文本,等待進程實際上都是在等待從log_buf中讀出信息。在25748行,進程被轉(zhuǎn)入休眠狀態(tài)以等待log_buf的活動。在休眠、喚醒和等待隊列中所使用的機制將在下一節(jié)中進行討論。25897:返回日志中寫入的字符長度。
如果對于每個字符的處理工作都能減少一點,那么從25869行開始的for循環(huán)就執(zhí)行得更快一點。當循環(huán)存在時,我們可以通過只在循環(huán)退出時將logged_chars更新一次來稍微提高運行速度。然而我們還可以通過其他努力來提高速度。由于我們可以預(yù)知消息的長度,因此log_size和log_start可以到最后再增長。讓我們來實驗一下這樣能否提高速度,下面是一段經(jīng)過理想優(yōu)化的代碼:
請注意循環(huán)通常只需要執(zhí)行一次,只有在log_buf末尾寫入信息需要折行時才會多次執(zhí)行。因而log_size和log_buf只需要更新一次(或者當寫入需要換行時是兩次)。
這時速度的確提高了,但是有兩個原因使我們并不能這樣做。首先,內(nèi)核可能有自己特有的memcpy函數(shù),我們必須確保對memcpy的調(diào)用不會再次進入對printk的調(diào)用(有一部分內(nèi)核移植版定義了自己特有的速度較快的memcpy函數(shù)版本,因此所有的移植都要在這一點上保持一致)。如果memecpy調(diào)用printk來報告失敗,那么就有可能觸發(fā)無限循環(huán)。
然而在這一點上也并不是真的無藥可救。使用這種解決方案的最大問題在于該內(nèi)核循環(huán)的形式中也要留意新行標志符,因此使用memcpy將整個消息拷貝到log_buf中是不正確的:如果此處存在新行,我們將無法對其進行處理。
我們可以試驗一個一箭雙雕的辦法。下面這種替代的嘗試雖然可能比前面那種初步解決方法速度要慢,但是它保持了內(nèi)核版本的語意:
(請注意gcc的優(yōu)化器十分靈敏,它足以能檢測到循環(huán)內(nèi)部的表達式log_buf+LOG_BUF_LEN并沒有改變,因此在上面的循環(huán)中試圖手工加速計算是沒有任何效果的。)
不幸的是,這種方法并不能比現(xiàn)在的內(nèi)核版本在速度上快許多,而且那樣會使得代碼晦澀難懂(如果你編寫過更新log_size和log_start的代碼,你就能清楚地了解這一點)。你可以自己決定這種折衷是否值得。然而無論怎樣,我們學(xué)到了一些東西,通常,不管成功與否,改進內(nèi)核代碼都可以加深你對內(nèi)核工作原理的理解。2.2.2 等待隊列
前一節(jié)我們曾簡要的提到進程(也就是正在運行的程序)可以轉(zhuǎn)入休眠狀態(tài)以等待某個特定事件,當該事件發(fā)生時這些進程能夠被再次喚醒。內(nèi)核實現(xiàn)這一功能的技術(shù)要點是把等待隊列(wait queue)和每一個事件聯(lián)系起來。需要等待事件的進程在轉(zhuǎn)入休眠狀態(tài)后插入到隊列中。當事件發(fā)生之后,內(nèi)核遍歷相應(yīng)隊列,喚醒休眠的任務(wù)讓它投入運行狀態(tài)。任務(wù)負責(zé)將自己從等待隊列中清除。
等待隊列的功能強大得令人吃驚,它們被廣泛應(yīng)用于整個內(nèi)核中。更重要的是,實現(xiàn)等待隊列的代碼量并不大。1.wait_queue結(jié)構(gòu)
18662:簡單的數(shù)據(jù)結(jié)構(gòu)就是等待隊列節(jié)點,它包含兩個元素: ?task—指向struct task_struct結(jié)構(gòu)的指針,它代表一個進程。從16325行開始的struct task_struct結(jié)構(gòu)將在第7章中進行介紹。
?next—指向隊列中下一節(jié)點的指針。因而,等待隊列實際上是一個單鏈表。
通常,我們用指向等待隊列隊首的指針來表示等待隊列。例如,printk使用的等待隊列l(wèi)og_wait(25647行)。2.wait_event 16840:通過使用這個宏,內(nèi)核代碼能夠使當前執(zhí)行的進程在等待隊列wq中等待直至給定condition(可能是任何的表達式)得到滿足。
16842:如果條件已經(jīng)為真,當前進程顯然也就無需等待了。16844:否則,進程必須等待給定條件轉(zhuǎn)變?yōu)檎?。這可以通過調(diào)用__wait_event來實現(xiàn)(16824行),我們將在下一節(jié)介紹它。由于__wait_event已經(jīng)同wait_event分離,已知條件為假的部分內(nèi)核代碼可以直接調(diào)用__wait_queue,而不用通過宏來進行冗余的(特別是在這些情況下)測試,實際上也沒有代碼會真正這樣處理。更為重要的是,如果條件已經(jīng)為真,wait_event會跳過將進程插入等待隊列的代碼。
注意wait_event的主體是用一個比較特殊的結(jié)構(gòu)封閉起來的:
奇怪的是,這個小技巧并沒有得到應(yīng)有的重視。這里的主要思路是使被封閉的代碼能夠像一個單句一樣使用。考慮下面這個宏,該宏的目的是如果p是一個非空指針,則調(diào)用free: 除非你在如下所述的情況下使用FREE1,否則所有調(diào)用都是正確有效的: FREE1經(jīng)擴展以后,else就和錯誤的if(FREE1的if)聯(lián)系在一起。有些程序員通過如下途徑解決這種問題:
這兩種方法都不盡人意,程序員在調(diào)用宏以后自然而然使用的分號會把擴展信息弄亂。以FREE2為例,在宏展開之后,為了使編譯器能更準確地識別,我們還需要進行一定的縮進調(diào)節(jié),最終代碼如下所示:
這樣就會引起語法錯誤—else和任何一個if都不匹配。FREE3從本質(zhì)上講也存在同樣的問題。而且在研究問題產(chǎn)生原因的同時,就能夠明白為什么宏體里是否包含if是無關(guān)緊要的。不管宏體內(nèi)部內(nèi)容如何,只要使用一組括號來指定宏體,就會碰到相同的問題。
引入do/while(0)技巧能夠克服前面所出現(xiàn)的所有問題,現(xiàn)在我們可以編寫FREE4。
將FREE4和其他宏一樣插入相同代碼之后,宏展開后其代碼如下所示(為清晰起見,我們再次調(diào)整了縮進格式):
這段代碼當然可以正確執(zhí)行。編譯器能夠優(yōu)化這個偽循環(huán),舍棄循環(huán)控制,因此執(zhí)行代碼并沒有速度的損失,我們也從而得到了能夠?qū)崿F(xiàn)理想功能的宏。
雖然這是一個可以接受的解決方案,但是我們不能不提到的是編寫函數(shù)要比編寫宏好得多。不過如果你不能提供函數(shù)調(diào)用所需的開銷,那么就需要使用內(nèi)聯(lián)函數(shù)。這種情況雖然在內(nèi)核中經(jīng)常出現(xiàn),但是在其他地方就要少得多。(不可否認,當使用C++、gcc或者任何實現(xiàn)了將要出現(xiàn)的修正版ISO標準C的編譯器時,這種方案只是一種選擇,就是最后為C增加內(nèi)聯(lián)函數(shù)。)
3.__wait_event 16824:__wait_event使當前進程在等待隊列wq中等待,直至condition為真。16829:通過調(diào)用add_wait_queue(16791行),局部變量__wait可以被鏈接到隊列上。注意__wait是在堆棧中而不是在內(nèi)核堆中分配空間,這是內(nèi)核中常用的一種技巧。在宏運行結(jié)束之前,__wait就已經(jīng)被從等待隊列中移走了,因此等待隊列中指向它的指針總是有效的。16830:重復(fù)分配CPU給另一個進程直至條件滿足,這一點將在下面幾節(jié)中討論。16831:進程被置為TASK_UNINTERRUPTIBLE狀態(tài)(16190行)。這意味著進程處于休眠狀態(tài),不應(yīng)被喚醒,即使是信號也不能打斷該進程的休眠。信號在第6章中介紹,而進程狀態(tài)則在第7章中介紹。
16832:如果條件已經(jīng)滿足,則可以退出循環(huán)。
請注意如果在第一次循環(huán)時條件就已經(jīng)滿足,那么前面一行的賦值就浪費了(因為在循環(huán)結(jié)束之后進程狀態(tài)會立刻被再次賦值)。__wait_event假定宏開始執(zhí)行時條件還沒有得到滿足。而且,這種對進程狀態(tài)變量state的延遲賦值也并沒有什么害處。在某些特殊情況下,這種方法還十分有益。例如當__wait_event開始執(zhí)行時條件為假,但是在執(zhí)行到16832行時就為真了。這種變化只有在為有關(guān)進程狀態(tài)的代碼計算condition變量值時才會出現(xiàn)問題。但是在代碼中這種情況我沒有發(fā)現(xiàn)。
16834:調(diào)用schedule(26686行,在第7章中討論)將CPU轉(zhuǎn)移給另一個進程。直到進程再次獲得CPU時,對schedule的調(diào)用才會返回。這種情況只有當?shù)却犃兄械倪M程被喚醒時才會發(fā)生。
16836:進程已經(jīng)退出了,因此條件必定已經(jīng)得到了滿足。進程重置TASK_RUNNING的狀態(tài)(16188行),使其適合CPU運行。
16837:通過調(diào)用remove_wait_queue(16814行)將進程從等待隊列中移去。wait_event_interruptible和__wait_event_interruptible(分別參見16868行和16847)基本上與wait_event和__wait_event相同,但不同的是它們允許休眠的進程可以被信號中斷。信號將在第6章中介紹。
請注意wait_event是被如下結(jié)構(gòu)所包含的。
和do/while(0)技巧一樣,這樣可以使被封閉起來的代碼能夠像一個單元一樣運行。這樣的封閉代碼就是一個獨立的表達式,而不是一個獨立的語句。也就是說,它可以求值以供其他更復(fù)雜的表達式使用。發(fā)生這種情況的原因主要在于一些不可移植的gcc特有代碼的存在。通過使用這類技巧,一個程序塊中的最后一個表達式的值將定義為整個程序塊的最終值。當在表達式中使用wait_event_interruptible時,執(zhí)行宏體后賦__ret的值為宏體的值(參見16873行)。對于有Lisp背景知識的程序員來說,這是個很常見的概念。但是如果你僅僅了解一點C和其他一些相關(guān)的過程性程序設(shè)計語言,你可能就會覺得比較奇怪。__wake_up 26829:該函數(shù)用來喚醒等待隊列中正在休眠的進程。它由wake_up和wake_up_ interruptible調(diào)用(請分別參見16612行和16614行)。這些宏提供mode參數(shù),只有狀態(tài)滿足mode所包含的狀態(tài)之一的進程才可能被喚醒。
26833:正如將在第10章中詳細討論的那樣,鎖(lock)是用來限制對資源的訪問,這在SMP邏輯單元中尤其重要,因為在這種情況下當一個CPU在修改某數(shù)據(jù)結(jié)構(gòu)時,另一個CPU可能正在從該數(shù)據(jù)結(jié)構(gòu)中讀取數(shù)據(jù),或者也有可能兩個CPU同時對同一個數(shù)據(jù)結(jié)構(gòu)進行修改,等等。在這種情況下,受保護的資源顯然是等待隊列。非常有趣的是所有的等待隊列都使用同一個鎖來保護。雖然這種方法要比為每一個等待隊列定義一個新鎖簡單得多,但是這就意味著SMP邏輯單元可能經(jīng)常會發(fā)現(xiàn)自己正在等待一個實際上并不必須的鎖。
26838:本段代碼遍歷非空隊列,為隊列中正確狀態(tài)的每一個進程調(diào)用wake_up_process(26356行)。如前所述,進程(隊列節(jié)點)在此可能并沒有從隊列中移走。這在很大程度上是由于即使隊列中的進程正在被喚醒,它仍然可能希望繼續(xù)存在于等待隊列中,這一點正如我們在__wait_event中發(fā)現(xiàn)的問題一樣。2.2.3 內(nèi)核模塊
整個內(nèi)核并不需要同時裝入內(nèi)存。應(yīng)該確認,為保證系統(tǒng)能夠正常運行,一些特定的內(nèi)核必須總是駐留在內(nèi)存中,例如,進程調(diào)度代碼就必須常駐內(nèi)存。但是內(nèi)核其他部分,例如大部分的設(shè)備驅(qū)動就應(yīng)該僅在內(nèi)核需要的時候才裝載,而在其他情況下則無需占用內(nèi)存。
舉例來說,只有在內(nèi)核真正和CD-ROM通訊時才需要使用完成內(nèi)核與CD-ROM通訊的設(shè)備驅(qū)動程序,因此內(nèi)核可以被設(shè)置為在和設(shè)備通訊之前才裝載相應(yīng)代碼。內(nèi)核完成和設(shè)備的通訊之后可以將這部分代碼丟棄。也就是說,一旦代碼不再需要,就可以從內(nèi)存中移走。系統(tǒng)運行過程中可以增減的這部分內(nèi)核稱為內(nèi)核模塊。內(nèi)核模塊的優(yōu)點是可以簡化內(nèi)核自身的開發(fā)。假設(shè)你購買了一個新的高速CD-ROM驅(qū)動器,但是現(xiàn)有的CD-ROM驅(qū)動程序并不支持該設(shè)備。你自然就希望增加對這種高速模式的支持以提高系統(tǒng)光驅(qū)設(shè)備的性能。如果作為內(nèi)核模塊來編譯驅(qū)動程序,你的工作將會方便得多:編譯驅(qū)動程序、加載到內(nèi)核、測試、卸載驅(qū)動程序、修改驅(qū)動程序、再次加載驅(qū)動程序到內(nèi)核、測試,如此周而復(fù)始。如果你的驅(qū)動程序是直接編輯在內(nèi)核中的,那么你就必須重新編譯整個內(nèi)核并且在每次修改驅(qū)動程序之后重新啟動機器。這樣慢得很多。
自然,你也必須留意內(nèi)核模塊。對于指明其他內(nèi)核模塊在磁盤上的駐留位置的那些模塊,一定不能從內(nèi)存中卸載,否則,內(nèi)核將只能通過訪問磁盤來裝載處理磁盤訪問的內(nèi)核模塊,這是不可能實現(xiàn)的。這也是我們要選擇把部分內(nèi)核作為模塊編譯還是直接編譯進內(nèi)核使其常駐內(nèi)存的又一個原因。知道自己系統(tǒng)的設(shè)置方式,因而也就可以選擇正確使用的方式(如果為了確保安全,可以簡單的忽略內(nèi)核模塊系統(tǒng)的優(yōu)點,而把所有的內(nèi)容都編譯到內(nèi)核里面)。內(nèi)核模塊會帶來一些速度上的損失,這是因為一些必需的代碼現(xiàn)在并不在RAM中,必需要從磁盤讀入。但是整個系統(tǒng)的性能通常會有所提高,這主要是因為通過丟棄暫時不使用的模塊可以釋放出額外的RAM供應(yīng)用程序使用。如果這部分內(nèi)存被內(nèi)核所占用,應(yīng)用程序?qū)⒅荒芨宇l繁地進行磁盤交換,而這種磁盤交換會顯著地降低應(yīng)用程序的性能(磁盤交換將在第8章中討論)。
內(nèi)核模塊還會帶來因復(fù)雜度的增加所造成的開銷,這是因為在系統(tǒng)運行的過程中,移進移出部分內(nèi)核需要額外的代碼。然而,復(fù)雜度的開銷是可以管理的。通過使用外部程序來代理一些必需的工作還可以更進一步降低復(fù)雜度的開銷(更為確切的說法是,這樣做不是減少了復(fù)雜度的開銷,而是把復(fù)雜度的開銷重新分配了一下)。這是對內(nèi)核模塊原理的一個小小的擴展:即使是內(nèi)核的支持模塊,對于內(nèi)核來說也只是外部的、部分可用的,只有在需要的時候才被裝入內(nèi)存。
通常用于這種目的程序稱為modprobe。有關(guān)的modprobe代碼超出了本書的范圍,但是在Linux的每個發(fā)行版本中都包含有它。本節(jié)的剩余部分將討論同modprobe協(xié)同工作,以裝載內(nèi)核模塊的內(nèi)核代碼。1.request_module 24432:作為函數(shù)說明之前的注釋,request_module是一個函數(shù)。內(nèi)核的其他模塊在需要裝載其他內(nèi)核模塊的時候,都必須調(diào)用這個函數(shù)。就像內(nèi)核處理其他工作一樣,這種調(diào)用也是為當前運行的進程進行的。從進程的角度來看,這種調(diào)用的請求通常是隱含的—正在執(zhí)行進程其他請求的內(nèi)核可能會發(fā)現(xiàn),必須調(diào)入一個模塊才能夠完成該請求。例如,請參見10070行,這里是一些將在第7章中討論的代碼。
24446:以內(nèi)核中的一個獨立進程的形式執(zhí)行exec_modprobe函數(shù)(24384行)。這并不能只通過函數(shù)的簡單調(diào)用實現(xiàn),因為exec_modprobe要繼續(xù)調(diào)用exec來執(zhí)行一個程序。因此,對函數(shù)exec_modprobe的簡單調(diào)用將永遠不會有返回。
這和使用fork以準備exec調(diào)用十分類似,你可以認為kernel_thread對內(nèi)核來說就是較低版本的fork,雖然兩者有很大不同。fork是從指定函數(shù)開始執(zhí)行新的進程,而不是從調(diào)用者的當前位置開始運行。正如fork一樣,kernel_thread返回的值是新進程的進程號。24448:和fork一樣,從kernel_thread返回的負值表示內(nèi)部錯誤。
24455:正如函數(shù)中論述的一樣,大部分的信號將因當前進程而被暫時阻塞。
24462:等待exec_modprobe執(zhí)行完畢,同時指出所需要的模塊是已經(jīng)成功裝入內(nèi)存,還是裝載失敗了。
24465:結(jié)束運行,恢復(fù)信號。如果exec_modprobe返回錯誤代碼,則打印錯誤消息。2.exec_modprobe 24384:exec_modprobe運行為內(nèi)核增加內(nèi)核模塊的程序。這里的模塊名是一個void*的指針,而不是char*的指針。原因簡單說來就是kernel_thread 產(chǎn)生的函數(shù)通常都使用void*指針參數(shù)。
24386:設(shè)置modprobe的參數(shù)列表和環(huán)境。modprobe_path(24363行)用來定位modprobe程序的位置。它可以通過內(nèi)核的sysctl特性來修改,這一點將在第11章中介紹(參見30388行)。這意味著root可以動態(tài)選擇不同于/sbin/modprobe的程序來運行,以適應(yīng)當modprobe被安裝到其他地方或者使用修改過的modprobe替換掉了原有的modprobe之類的情況。24400:(正如代碼中描述的一樣)出于安全性考慮,丟棄所有掛起的信號和信號句柄(handl-ers)。這里最重要的部分是對flush_signal_handlers的調(diào)用(28041行),它使用內(nèi)核默認的信號句柄代替所有用戶定義的信號句柄。如果在此時有信號被傳送到內(nèi)核,它將獲得默認響應(yīng)—通常是忽略信號或殺死進程。但是不管怎樣都不會引起安全風(fēng)險。由于該函數(shù)從觸發(fā)它的進程中分離出來(如前所述),所以,不管原始進程在此處是否改變其原來分配的信號,句柄都不會產(chǎn)生任何影響。
24405:關(guān)閉調(diào)用進程打開的所有文件。最重要的是,這意味著modprobe程序不再從調(diào)用進程中繼承標準輸入輸出和標準錯誤。這很有可能會引起安全漏洞(這可能是在替代modprobe的程序中引起的問題,但是modprobe本身實際上并不關(guān)心這個差異)。
24413:modprobe程序作為root運行,它擁有root所擁有的所有權(quán)限。和整個內(nèi)核中其他地方一樣,請注意root使用用戶ID號0的假定在這里已經(jīng)被寫入程序。用戶ID號和權(quán)能系統(tǒng)(capability system,在接下來的幾行中會用到)將在第7章中介紹。
24421:試圖執(zhí)行modprobe程序。如果嘗試失敗,內(nèi)核將使用printk打印錯誤消息并返回錯誤代碼。這里是可能產(chǎn)生printk的緩沖器過載的地點之一。module_name的長度并沒有明確限制,就我們對該調(diào)用的看法而言,它可能長達一百萬個字符。為防止printk緩沖器過載,你必需遍歷所有對于該函數(shù)的調(diào)用(實際上是對request_module的調(diào)用),以保證每個調(diào)用者使用足夠短的、不會為printk造成麻煩的模塊名。
24427:當execve成功執(zhí)行時,它不會返回任何結(jié)果,因此本處是不可能執(zhí)行到的。但是編譯器卻并不知道這一點,因此,此處使用了return語句以保證gcc不出錯。
對于內(nèi)核的進一步討論將超出本章的既定范圍,因此在這個問題上我們到此為止。然而本書中也包括了其他必需的內(nèi)核代碼。在讀完第4章和第5章之后,也許你會希望再次仔細研讀一下這部分內(nèi)容。有關(guān)這個問題的兩個文件是include/linux/module.h(從15529行開始)和/kernel/module.c(從24476行開始)。和sys_create_module(24586行)、sys_init_module(24637行)、sys_delete_module(24860行)和sys_query_module(25148行)四個函數(shù)需要特別注意一樣,struct module(15581行)也要特別引起注意。這些函數(shù)實現(xiàn)了modprobe及insmod、lsmod和rmmod所使用的系統(tǒng)調(diào)用,以完成模塊的裝載、定位和卸載。
內(nèi)核觸發(fā)直接回調(diào)內(nèi)核程序的現(xiàn)象看起來很令人奇怪。但是,實際上進行的工作不止于此。例如,modprobe必須實際訪問磁盤以搜尋要裝載的模塊。而且更為重要的一點是,這種方法賦予root對內(nèi)核模塊系統(tǒng)更多的控制能力。這主要是因為root也可以運行modprobe及相關(guān)程序。因此,root既可以手工裝載、查詢、卸載模塊,也可以由內(nèi)核自動完成。2.3 配置與編譯內(nèi)核
你可能僅僅研讀、欣賞而并不修改Linux內(nèi)核源代碼。但是,更普遍的情況是,用戶有強烈的愿望去改進內(nèi)核代碼并完成相應(yīng)的測試,這樣我們就需要知道如何重建內(nèi)核。本節(jié)就是要告訴你如何實現(xiàn)這一點,而最終則歸結(jié)于如何把你所做的修改發(fā)行給別人,以使得每個人都能從你的工作中受益。2.3.1 配置內(nèi)核
編譯內(nèi)核的第一步就是配置內(nèi)核,這是增加或者減少對內(nèi)核特性的支持及修改內(nèi)核的一些特性的必要步驟。例如,你可以要求內(nèi)核為自己的聲卡指定一個不同的DMA通道。如果內(nèi)核配置和你的需要相同,那么你可以直接跳過本節(jié),否則請繼續(xù)閱讀以下內(nèi)容。為了完成內(nèi)核的配置,請先切換到root用戶,然后轉(zhuǎn)入如下內(nèi)核源程序目錄: cd /usr/src/linux 接著敲入如下命令組: make config make menuconfig make xconfig 這三條命令都可以用來配置內(nèi)核,但它們發(fā)揮作用的方式各不相同:
?make config—三種方法中最簡單也是最枯燥的一種。但是最基本的一點是,它可以適應(yīng)任何情況。通過為每一個內(nèi)核支持的特性向用戶提問的方式來決定在內(nèi)核中需要包含哪些特性。對于大多數(shù)問題,你只要回答y(yes,把該特性編譯進內(nèi)核中)、m(作為模塊編譯)或者n(no,根本不對該特性提供支持)。在決定之前用戶應(yīng)該考慮清楚,因為這個過程是不可逆的。如果你在該過程中犯了錯誤,就只能按Ctrl+C退出。你也可以敲入?以獲取幫助。圖2-1顯示了這種方法在X終端上運行的情況。圖2-1 運行中的make config 幸運的是,這種方法還有一些智能。例如,如果你對SCSI支持回答no,那么系統(tǒng)就不會再詢問你有關(guān)SCSI的細節(jié)問題了。而且你可以只按回車鍵以接受默認的選擇,也就是當前的設(shè)置(因此,如果當前內(nèi)核將對于SCSI的支持編譯進了內(nèi)核,在這個問題上按回車鍵就意味著繼續(xù)把對SCSI的支持編譯進內(nèi)核中)。即使是這樣,大部分用戶還是寧愿使用另外的兩種方法。
?make menuconfig—一種基于終端的配置機制,用戶擁有通過移動光標來進行瀏覽等功能。圖2-2顯示了在X終端上運行的make menuconfig。雖然在控制臺上顯示的是彩色,但是在終端上的顯示仍然相當單調(diào)。使用menuconfig必須要有相應(yīng)的ncurses類庫。圖2-2 運行中的make menuconfig ?make xconfig—這是我最喜歡的一種配置方式。只有你能夠在X server上用root用戶身份運行X應(yīng)用程序時,這種配置方式才可以使用(有些偏執(zhí)的用戶就不愿意使用這種方式)。你還必須擁有Tcl窗口系統(tǒng),這實際上還意味著你必須擁有Tcl、Tk以及一個正在運行的X安裝程序。作為補償,用戶獲得的是更漂亮的、基于X系統(tǒng)的以及和menuconfig功能相同的配置方法。圖2-3顯示了在這種方法運行過程中打開“可裝載模塊支持(Loadable module support)”子窗口的情況。
圖2-3 運行中的make xconfig 如上所述,這三種方法都實現(xiàn)了相同的功能:它們都生成在構(gòu)建內(nèi)核時使用的.config文件。而唯一的區(qū)別在于創(chuàng)建這個文件時的難易程度不同。2.3.2 構(gòu)建內(nèi)核
構(gòu)建內(nèi)核要做的工作要比配置內(nèi)核所做的工作少得多。雖然有幾種方式都能實現(xiàn)這一功能,但是選擇哪一種依賴于你希望怎樣對系統(tǒng)進行設(shè)置。長期以來,我已經(jīng)形成了如下的習(xí)慣。雖然這種習(xí)慣比我所必須要做的略微多一些,但是它包含了所有基本的問題。首先,如果你還不在內(nèi)核源程序目錄中,請先再次轉(zhuǎn)入這一目錄: cd /usr/src/linux 現(xiàn)在,切換到root用戶,使用下面顯示的命令生成內(nèi)核。現(xiàn)在在shell中敲入下面的命令,注意make命令因為空間關(guān)系分成了兩行,但實際上這在shell輸入時是一個只有一行的命令: make dep clean zlilo boot modules modules_install 當給出了如上多個目標時,除非前面所有的目標都成功了,否則make能夠知道沒有必要繼續(xù)嘗試下面的目標。因此,如果make能夠運行結(jié)束,成功退出,那么這就意味著所有的目標都正確構(gòu)建了。現(xiàn)在你可以重新啟動機器以運行新的內(nèi)核。2.3.3 備份的重要性
當修改(fooling)內(nèi)核時,你必須準備一個能夠啟動的備用內(nèi)核。實現(xiàn)該目的的一種方式是通過配置Linux加載程序(LILO)以允許用戶選擇啟動的內(nèi)核映象,其中之一是從沒有修改過的內(nèi)核的備份(我總是這樣做的)。
如果你比較有耐心,那么你就可以使用zdisk目標而不使用zlilo目標;它可以把能夠啟動的內(nèi)核映象寫入軟盤中。這樣你就可以通過在啟動時插入軟盤的方式啟動你的測試內(nèi)核;如果沒有插入軟盤,則啟動正常的內(nèi)核。
但是請注意:內(nèi)核模塊并沒有被裝載到軟盤中,它們實際上是裝在硬盤中的(除非你愿意承擔(dān)更多的麻煩)。因此,如果你弄亂了內(nèi)核模塊,即使是zdisk目標也救不了你。實際上,上面提到的這兩種方法都存在這個問題。雖然有比較好的解決方法可用,但是最簡單的方法(也就是我所使用的方法)是把備份內(nèi)核作為嚴格獨立的內(nèi)核來編譯,而不使用可裝載模塊的支持。通過這種方法,即使我弄亂了內(nèi)核而不得不使用備份啟動系統(tǒng),那么不管問題是實驗性內(nèi)核不正確還是內(nèi)核模塊的原因都無關(guān)緊要。不管怎樣,在備份的內(nèi)核中已經(jīng)有我需要的所有東西了。
由于用戶所做的修改可能導(dǎo)致系統(tǒng)的崩潰,如損壞磁盤上的數(shù)據(jù)等等,并不僅僅只是打亂設(shè)備驅(qū)動程序或文件系統(tǒng),在測試新內(nèi)核之前,備份系統(tǒng)的最新數(shù)據(jù)也是一個英明的決策(雖然設(shè)備驅(qū)動程序的開發(fā)不是本書的主題,但是必需指出的是,設(shè)備驅(qū)動程序的缺陷可能會引起系統(tǒng)的物理損壞。例如顯示器是不能備份的,而且因價格昂貴而不易替換)。作為一個潛在的內(nèi)核黑客,你的最佳投資(當然是讀過本書以后)是一個磁帶驅(qū)動器和充足的磁帶。2.3.4 發(fā)布你的改進
下面是有關(guān)發(fā)布你所做修改的一些基本規(guī)則:
?檢查最新發(fā)行版本,確保你所處理的不是已經(jīng)解決了的問題。
?遵守Linux 內(nèi)核代碼編寫的風(fēng)格。簡要的說就是8字符縮進以及K&R括號風(fēng)格(if,else,for,while,switch或者do后面同一行中緊跟著開括號)。在內(nèi)核源程序目錄下面的文檔編寫和代碼風(fēng)格文件給出了完整的規(guī)則,不過我們已經(jīng)介紹了其中的關(guān)鍵部分。注意本書中包含的源程序代碼為節(jié)省空間而進行了大量的重新編輯,在該過程中我可能打破了其中的一些規(guī)則。
?獨立發(fā)行相對無關(guān)的修改。這樣,只想使用你所做的某部分修改的人就可以十分方便地獲得想要的東西,而不用一次檢驗所有的修改內(nèi)容。
?讓使用你所做修改的用戶清楚他們可以從你的修改中獲取什么。同樣,你也應(yīng)該給出這些問題的可信度。你是15min之前才匆匆完成你的修改,甚至還沒有時間對它們進行編譯,還是已經(jīng)在你和你的朋友的系統(tǒng)中已長期穩(wěn)定地運行過這個修改?
假設(shè)現(xiàn)在你已經(jīng)準備好發(fā)行自己的修改版本了,那么要做的第一步是建立一個說明你所做的修改的文件。你可以使用diff程序自動創(chuàng)建這個文件。結(jié)果或者被稱為diffs,或者在Linux中更普遍的被稱為補丁(patch)。
發(fā)布的過程十分簡單。假設(shè)原來沒有修改過的源程序代碼在linux-2.2.5目錄下,而你修改過的源程序代碼在linux-my目錄下,那么只要進行如下的簡單工作就可以了(只有在鏈接不存在的情況下才需要執(zhí)行l(wèi)n):
現(xiàn)在,輸出文件my.patch包含了其他用戶應(yīng)用這個修改程序時所需要的一切內(nèi)容。(警告:如上所述,兩個源程序間的所有差別都會包含在這個補丁文件中。diff不能區(qū)分修改部分之間的關(guān)系,所以就把它們都羅列了出來。)如果補丁文件相對較小,你可以使用郵件直接發(fā)往內(nèi)核郵件列表。如果補丁很大,那么就需要通過FTP或者Web站點發(fā)布。這時發(fā)給郵件列表的信件中就只需要包含一個URL。Linux內(nèi)核郵件列表的常見問題解答(FAQ)文件位于http://004km.cn。
阿道夫 的 范德薩 啊訂單式
第二篇:關(guān)于分析今天長安保定百度愛問愛學(xué)位論文寫作方法學(xué)位論文.
的的范德薩的地方愛的規(guī)格愛你啊好文章梁慧星:學(xué)位論文寫作方法(2):
學(xué)位論文的結(jié)構(gòu)
三、學(xué)位論文的結(jié)構(gòu)
答辯委員會成員或委員會外的專家對碩士、博士論文作鑒定、寫評語,有一個內(nèi)容是就論文結(jié)構(gòu)表態(tài)。一篇合格的學(xué)位論文,要求結(jié)構(gòu)合理??隙ǖ脑u語是:本文結(jié)構(gòu)合理、邏輯嚴謹、層次清晰。什么叫“結(jié)構(gòu)合理”?結(jié)構(gòu)合理就是指論文的“層次清晰”、“邏輯嚴密”。這就要求了解論文的一般結(jié)構(gòu),這里注重講碩士論文、博士論文的結(jié)構(gòu)。
學(xué)術(shù)論文的結(jié)構(gòu):
目錄
序言
導(dǎo)論
本論
結(jié)論
參考文獻目錄
后記
上述結(jié)構(gòu)中,導(dǎo)論、本論、結(jié)論三部分構(gòu)成論文的本體;目錄、序言、參考文獻目錄和后記,是附屬部分。最重要的當然是本體。一篇完整的學(xué)位論文,其本體由導(dǎo)論、本論、結(jié)論三部分構(gòu)成。有沒有特殊的,有特殊的,所謂特殊,無非是在一般結(jié)構(gòu)基礎(chǔ)上省略了其中的某個部分,或者省略結(jié)論,或者省略導(dǎo)論,但無論如何不能省略本論。如果以重要性為標準進行劃分,則導(dǎo)論和結(jié)論屬于組成部分,本論屬于本質(zhì)部分。例如一個人,頭和軀干是本質(zhì)部分,四肢是組成部分。沒有手臂,甚至手腳都沒有,不影響人這個事物的存在,仍然是人;但沒有頭和軀干,光有四肢就不成其為人。同理,省略了導(dǎo)論、結(jié)論,不影響學(xué)術(shù)論文的本質(zhì),但學(xué)術(shù)論文的完整性大大受到損害,專家作鑒定會寫上一句:結(jié)構(gòu)不完整。當然,學(xué)術(shù)論文不可能沒有本論,假設(shè)沒有本論,就不成其為學(xué)術(shù)論文。
可見,本論部分特別重要,答辯委員會成員評價學(xué)位論文結(jié)構(gòu)合理不合理,注重的是本論部分。
下面對各部分作簡要說明:
(一)導(dǎo)論
導(dǎo)論起什么作用?導(dǎo)論的作用在于引起讀者的閱讀興趣。讀者拿到一篇學(xué)術(shù)論文,通常好多萬字、二三十萬字,是否值得花費寶貴的時間,光看題目還難以判斷,總是首先讀導(dǎo)論,希望從導(dǎo)論的內(nèi)容判斷本文是否有閱讀價值,是否值得花費時間閱讀。
導(dǎo)論的內(nèi)容,通常是交待課題,本文究竟要研究一個什么課題,這個課題的產(chǎn)生背景,說明作者為什么要研究這個課題,它有什么理論意義和現(xiàn)實意義。如果是博士論文,通常還要交待所采用的研究方法,交待論文的大體結(jié)構(gòu)。
實例1:
博士論文:合同自由與公序良俗
第一章 導(dǎo)論
(一)選題背景及意義
(二)研究狀況和文獻綜述
(三)研究方法和主要內(nèi)容
實例2:
博士論文:國際貨物貿(mào)易中的補貼與反補貼法律問題研究
導(dǎo)論
(一)本文研究的目的和意義
(二)本文研究范圍
(三)素材選取與研究方法
(四)體例安排
(二)結(jié)論
學(xué)術(shù)論文應(yīng)當有結(jié)論,是學(xué)術(shù)研究的規(guī)律性決定的。學(xué)術(shù)研究是一個過程,有其始端和終端。導(dǎo)論是始端,結(jié)論是終端。結(jié)論表明一項科學(xué)研究的結(jié)束。同時,一項研究當有其研究結(jié)果。最終得到一個什么研究結(jié)果,應(yīng)當在結(jié)論部分作出概括。如果還有遺留問題沒有解決,也應(yīng)在結(jié)論部分指出。
從學(xué)位論文答辯的角度講,論文要經(jīng)專家鑒定,寫出評語。答辯委員會成員也要審讀論文,寫出評語??紤]到一篇博士學(xué)位論文通常二十多萬字,甚至三十多萬字,專家教授通常不可能一口氣讀完。總是讀幾頁,放下了,又讀幾頁,有什么事情又放下了。經(jīng)過好多次才斷續(xù)讀完,讀到末尾,前面的內(nèi)容已經(jīng)模糊、記不清了。不可否認,有的評定人因時間關(guān)系不可能讀完全文,閱讀了導(dǎo)論部分,翻閱、選讀幾個章節(jié),然后就寫評語。如果有一個結(jié)論,概括本文的研究結(jié)果、作者的基本學(xué)術(shù)見解、本研究結(jié)果的理論意義和實踐價值,對于審定人作出總的評價有莫大的幫助。這對于論文最后能否通過答辯,有極重大的意義。切不可掉以輕心!
實例:
博士論文:合同自由與公序良俗
第六章 結(jié)論
(一)總結(jié)
(二)論文的基本觀點
(三)論文的主要創(chuàng)新點
(四)論文的局限和不足
有的學(xué)位論文以立法建議代替結(jié)論,這大抵屬于制度型選題,研究某一項法律制度,研究最后得到的基本學(xué)術(shù)見解或結(jié)論,表現(xiàn)為建議我國立法機關(guān)制定某一法律或?qū)ΜF(xiàn)行法作修改,并形成了立法或修改的基本設(shè)想甚至條文草案。另外,也有以結(jié)束語代替結(jié)論的。以立法建議代替結(jié)論,以結(jié)束語代替結(jié)論,不等于沒有結(jié)論。省略結(jié)論,影響論文結(jié)構(gòu)的完整性,完整性是合理性的一個方面,因此沒有結(jié)論將影響論文結(jié)構(gòu)的合理性。
(三)本論
本論是一篇學(xué)位論文的本質(zhì)部分,沒有本論就不成其為一篇論文。就象沒有頭和軀干不能成其為人一樣。本論的內(nèi)容是研究過程的反映,應(yīng)當寫什么,自然不用我在這里說。這里只是介紹本論部分的結(jié)構(gòu)安排。評價一篇論文的結(jié)構(gòu)是否合理,主要是針對本論部分的結(jié)構(gòu)是否合理。
1、本論部分的結(jié)構(gòu)
大體上有五種:
總分結(jié)構(gòu)
三分結(jié)構(gòu)
四分結(jié)構(gòu)
編章結(jié)構(gòu)
章節(jié)結(jié)構(gòu)
總分結(jié)構(gòu),實際是分為兩個部分,稱為總論與分論。實際上,是哲學(xué)上的“一般”與“特殊”、“共性”與“個性”的關(guān)系。有關(guān)本課題的一般理論、共同理論,在總論部分;然后分別研究本課題內(nèi)部各特殊部分或特殊問題,叫做分論。實際是“二分結(jié)構(gòu)”:總論、分論。然后總論再分為若干部分(章),分論再分若干部分(章)。如果將總論、分論作為兩編,每編下分若干章,這就是“二分結(jié)構(gòu)”加“編章結(jié)構(gòu)”。有的博士論文,在總論、分論之前再設(shè)緒論,研究本課題的前提性的問題,作為另一個部分,稱為緒論編,包括若干章。這樣就變成“三分結(jié)構(gòu)”加“編章結(jié)構(gòu)”??梢哉f幾乎所有的選題,都有總論與分論的劃分,都可采用“二分結(jié)構(gòu)”加“編章結(jié)構(gòu)”。但是,如果屬于一般理論、共同理論的內(nèi)容太少,不足以再分為若干章,就會出現(xiàn)這樣的情況:總論編只有一章,分論編包括若干章,顯得不協(xié)調(diào)、不成比例。因此可不設(shè)編,直接采用“章節(jié)結(jié)構(gòu)”,第一章實際是總論,從第二章起實際是分論。下面舉一些實例。
采“四分結(jié)構(gòu)”的實例:
蔣新苗的博士論文:國際收養(yǎng)法律制度研究 第一編 導(dǎo)論,包括第一、二章;
第二編 國際收養(yǎng)中的國際私法問題,包括第三、四章;
第三編 國際收養(yǎng)法的統(tǒng)一化進程,包括第五、六章;
第四編 中國與國際收養(yǎng)法統(tǒng)一化進程,包括第七、八、九章。
須說明的是,第一編導(dǎo)論,內(nèi)容實際是緒論。緒論是本論的一部,導(dǎo)論不是本論的一部。本文省略了結(jié)論。
采“三分結(jié)構(gòu)”的實例1:
傅靜坤的博士后論文:契約沖突法論
第一部分 契約沖突法的基本原則和規(guī)范,包括第一、二章;
第二部分 統(tǒng)一國際契約實體法與統(tǒng)一國際契約沖突法,包括第三、四章;
第三部分 區(qū)際契約沖突法,包括第五章。
(本文省略了結(jié)論)
采“三分結(jié)構(gòu)”的實例2:
沈涓的博士論文:中國區(qū)際沖突法研究
第一編 中國區(qū)際沖突法的歷史與現(xiàn)狀,包括第一至三章;
第二編 中國區(qū)際沖突法的方法與規(guī)則,包括第四至五章;
第三編 中國區(qū)際法律關(guān)系沖突的調(diào)整,包括第六至十一章。
(本文省略結(jié)論)
2、總分結(jié)構(gòu)
這種結(jié)構(gòu)最為常見,通常先劃分為總論與分論兩大部分,然后各部分再分若干章;或設(shè)總論編、分論編,然后各編再分若干章;或不設(shè)編,總論作為第一章,分論分為若干章。實際是總分結(jié)構(gòu)加編章結(jié)構(gòu)。多數(shù)博士論文、碩士論文采用這樣的結(jié)構(gòu)。
實例:
肖厚國的博士論文:物權(quán)變動研究
(導(dǎo)論)
第一章 物權(quán)變動的基本理論
第二章 物權(quán)變動的立法主義
(一)第三章 物權(quán)變動的立法主義
(二)第四章 不動產(chǎn)物權(quán)變動的公示
(一)第五章 不動產(chǎn)物權(quán)變動的公示
(二)第六章 動產(chǎn)物權(quán)變動
第七章 善意取得 第八章 取得時效
(結(jié)束語)
本論實際上分為“總論”與“分論”兩大部分,“總論”再分為“物權(quán)變動的基本理論”(第一章)與“物權(quán)變動的立法主義”(第二、三章)兩部分;“分論”分為“積極的物權(quán)變動”與“消極的物權(quán)變動”兩部分,其中“積極的物權(quán)變動”,再分為“不動產(chǎn)物權(quán)變動”(第四、五章)與“動產(chǎn)物權(quán)變動”(第六章)兩部分;“消極的物權(quán)變動”,再分為“善意取得”(第七章)與“取得時效”(第八章)兩部分。屬于典型的“總分結(jié)構(gòu)+章節(jié)結(jié)構(gòu)”。
不合理的結(jié)構(gòu):
如果本論分為兩大塊,下面不再劃分章節(jié),或者本論僅有兩章,屬于單純的二分結(jié)構(gòu),應(yīng)當認為結(jié)構(gòu)不合理。為什么這樣的結(jié)構(gòu)不合理?首先是不合習(xí)慣。其次是美學(xué)上的考慮。一篇論文,前面一個序言,后面一個結(jié)語,本論部分就兩章,第一章、第二章。如果序言、結(jié)語都省略了,一篇論文就兩塊,第一部分,第二部分,或者第一章、第二章,這不好看。要進一步追問為什么?也難以回答??赡苁翘舭濉O旅媾e實例。
實例1:
碩士論文題目:作者精神權(quán)利性質(zhì)探討
第一部分 概述
第二部分 作者精神權(quán)利性質(zhì)探討
論文前面沒有導(dǎo)言,后面沒有結(jié)論,本論就兩部分,很不合理。
實例2:
一篇碩士論文
序言
第一章
第二章
結(jié)語
前有一個序言,后有一個簡短的結(jié)語,中間本論部分就兩章,屬于結(jié)構(gòu)不合理。
3、關(guān)于切題
關(guān)于本論的結(jié)構(gòu),無論采取哪一種結(jié)構(gòu)模式,其共同的要求是:緊扣題目,亦即我們平常所謂“切題”。這主要從每部分的標題來體現(xiàn)。
從上引博士論文的結(jié)構(gòu),我們看到,每一個標題,都緊扣住題目。如物權(quán)變動研究一文,第一至第六章的標題都有“物權(quán)變動”一語,第七、八兩章的標題雖然沒有“物權(quán)變動”四個字,但“善意取得”和“取得時效”是物權(quán)變動的具體形式??梢?,所謂切題,所謂緊扣題目,往往通過在本論各部分標題中“反復(fù)出現(xiàn)”論文題目中的“關(guān)鍵詞語”來體現(xiàn)。反之,如果本論各標題與論文題目無關(guān),找不到論文題目的關(guān)鍵詞語,我們就會覺得不切題,沒有緊扣題目。下面舉例。
實例1:
博士論文題目:論私法對國際法的影響
第一章 萬民法與國際法
第二章 人或主體
第三章 領(lǐng)土主權(quán)與所有權(quán)
第四章 條約與契約
評論:
在各部分標題中,沒有出現(xiàn)論文題目中的關(guān)鍵詞語“私法”和“國際法”。從各部分的標題,讀者很難理解該部分內(nèi)容與題目間是否有密切的關(guān)聯(lián)。這就是沒有緊扣題目,或者說不切題。
實例2:
博士論文題目:現(xiàn)代商人法研究
其本論分三章:
第二章 現(xiàn)代商人法產(chǎn)生和發(fā)展的歷史過程
第三章 現(xiàn)代商人法的適用及其法律效力
第四章 現(xiàn)代商人法與沖突法及國際仲裁法的完善和發(fā)展
評論:
題目中的關(guān)鍵詞語是“現(xiàn)代商人法”,我們看到本論部分每一個標題都重復(fù)“現(xiàn)代商人法”一語,使讀者覺得各部分內(nèi)容與題目的關(guān)系非常緊密,扣得很緊,這就叫“切題”。
4、小結(jié)
從上述本論部分的結(jié)構(gòu)安排,我們可以看到,博士論文采用總分結(jié)構(gòu)加編章結(jié)構(gòu),或者采用章節(jié)結(jié)構(gòu)的最常見,這類結(jié)構(gòu)安排系以“章”為單位,碩士論文也以章節(jié)結(jié)構(gòu)最常見,也有的用“部分”為單位,“部分”下面以一、二、三、四為序。是否可以作出這樣一個判斷:
無論以“章”或“部分”為單位,本論部分所劃分的單位至少應(yīng)在三個以上,例如不少于三章或三個部分。否則,就叫結(jié)構(gòu)不合理。
5、邏輯關(guān)系 以上僅指對結(jié)構(gòu)安排的形式要求。在此基礎(chǔ)上,還有對邏輯性的要求。指本論部分的結(jié)構(gòu)安排要具有一定的邏輯關(guān)系。大體有下面三種邏輯關(guān)系:
第一種 總分關(guān)系
第二種 并立關(guān)系
第三種 遞進關(guān)系
第一種:總分關(guān)系
關(guān)于本課題的一般性問題、一般理論、基本理論、基本原則的內(nèi)容,屬于總論。特殊問題、特殊理論、具體制度、具體問題、構(gòu)成條件、實際運用等內(nèi)容,屬于分論??傉撆c分論之間,是一般與個別、普遍與特殊的關(guān)系,通??傉摬糠謶?yīng)當在前,分論部分應(yīng)當在后。無論采用總分結(jié)構(gòu)或者編章結(jié)構(gòu)、章節(jié)結(jié)構(gòu),都要求總論與分論有清晰的界限,不能混淆,總論內(nèi)容寫完再安排分論,分論部分不能插入總論的內(nèi)容,不能顛倒順序,一般不能先分論后總論,應(yīng)當先總論后分論。
其規(guī)則是:先總、后分。
第二種:并列關(guān)系
如果采用總分結(jié)構(gòu),總論部分與分論部分,已具有并列的意義,總論下面的各章、分論下面的各章,也可以是并列的關(guān)系,即各章的內(nèi)容應(yīng)當處在同一層次。采用編章結(jié)構(gòu),各編的內(nèi)容可以是并列的關(guān)系,例如緒論編、總論編、分論編,編下面的各章可以是并列關(guān)系。
其規(guī)則是:位階同一
實例1:
肖厚國的博士論文:物權(quán)變動研究
第一章 物權(quán)變動的基本理論
第二章 物權(quán)變動的立法主義
(一)第三章 物權(quán)變動的立法主義
(二)第四章 不動產(chǎn)物權(quán)變動的公示
(一)第五章 不動產(chǎn)物權(quán)變動的公示
(二)第六章 動產(chǎn)物權(quán)變動
第七章 善意取得
第八章 取得時效
其結(jié)構(gòu)屬于典型的并列關(guān)系,而且是多層次的并列關(guān)系。第一個層次是總論(第1、2、3章)與分論(第4、5、6、7、8章)的并列;第二個層次是總論下面物權(quán)變動的基本理論(第1章)與物權(quán)變動的立法主義(第2、3章)的并列,分論下面積極的物權(quán)變動(第4、5、6章)與消極的物權(quán)變動(第7、8章)的并列;第三個層次是不動產(chǎn)物權(quán)變動(第4、5章)、動產(chǎn)物權(quán)變動(第6章)、善意取得(第7章)、取得時效(第8章)的并列。
實例2:
楊松的博士論文:國際貨幣基金協(xié)定研究
本論分五章:
第四章 國際收支平衡的法律制度研究
第五章 國際儲備的法律制度研究
第六章 匯兌安排國際法律制度研究
第七章 外匯管制法律問題研究
第八章 基金協(xié)定的監(jiān)督與磋商機制研究
其結(jié)構(gòu)也屬于典型的并列關(guān)系。
第三種:遞進關(guān)系
采編章結(jié)構(gòu),在一編之下的各章可以是遞進關(guān)系。采章節(jié)結(jié)構(gòu),各章之間也可以是遞進關(guān)系。章下面的節(jié),也可以是遞進關(guān)系。就一篇博士論文而言,可能各編之間是并列關(guān)系,各編下面的章是遞進關(guān)系,或者總論編下面的各章是并列關(guān)系,分論編下面各章是遞進關(guān)系?;蛘卟煽偡纸Y(jié)構(gòu)不設(shè)編,總論僅一章,從第二章開始是分論,分論各章是遞進關(guān)系。至于章下面的各節(jié)之間的關(guān)系,當然可以某些章下面的各節(jié)之間是并列關(guān)系,某些章下面的各節(jié)之間是遞進關(guān)系。
這里有一個要求,某編下面的各章,或者某章下面的各節(jié),如果采遞進關(guān)系,就一定是遞進關(guān)系,不能混淆。不能出現(xiàn)這樣的情況,一編有五章,其中一、二、三、五章顯然是遞進關(guān)系,中間第四章與各章不構(gòu)成遞進關(guān)系,或者一章下面若干節(jié),其中幾節(jié)似乎是遞進關(guān)系,中間又有幾節(jié)似乎是并列關(guān)系。
遞進關(guān)系有三種不同形態(tài):
時間上的遞進關(guān)系
空間上的遞進關(guān)系
純粹邏輯上的遞進關(guān)系
(1)時間上的遞進關(guān)系
時間上的遞進關(guān)系,是指在時間上由遠到近,先從該制度的歷史說起,從古羅馬法說起,中世紀有什么變化,近代有何發(fā)展,直到現(xiàn)在的現(xiàn)狀,實際是采歷史研究方法。法制史研究論文,大體體現(xiàn)這樣的遞進關(guān)系。在部門法,例如民法碩士、博士論文中,也常常采用歷史研究方法,因此在論文的某個部分會反映時間上的遞進關(guān)系,通常在緒論或總論部分,或者某一章下面的節(jié),不大可能一篇民法論文各章之間都反映時間上的遞進關(guān)系。
這種遞進關(guān)系,要求嚴格按照時間的先后順序,如果出現(xiàn)時間先后順序的錯亂,就叫層次不清、邏輯混亂。
其規(guī)則是:時間愈早愈在前,時間愈近愈在后。
(2)空間上的遞進關(guān)系
此所謂“空間”實際上包括兩種情形:一是地域上的空間;一是抽象的空間。無論屬于地域上的空間,或者抽象的空間,都要求“由外到內(nèi)”,先討論外部的問題,后討論內(nèi)部的問題。先研究外國的制度、發(fā)展、經(jīng)驗教訓(xùn),再討論本國的制度、發(fā)展、構(gòu)成、適用、存在問題及對策等;或者先討論該制度的外部關(guān)系,產(chǎn)生原因、背景、哲學(xué)思想、政策取向、功能等,然后進入該制度內(nèi)部,討論其構(gòu)成要件、法律效果、解釋適用等。
空間上的遞進關(guān)系,要求區(qū)分內(nèi)外,先外后內(nèi)。如果外部問題未討論完就進入內(nèi)部問題的討論,中途再反過來討論外部問題,或者一開始討論本國制度,中間突然插入外國制度的探討,然后再回到本國制度的研究,就叫層次不清、邏輯混亂。
其規(guī)則是:先外、后內(nèi)。
(3)純粹邏輯上的遞進關(guān)系
所謂純粹邏輯上的遞進關(guān)系,是指在邏輯上由抽象到具體。先從概念、定義說起,解釋其含義,探討其內(nèi)涵、外延,確定其適用范圍,分析適用條件、法律效果。通常采用法律解釋學(xué)的研究方法,就反映這種遞進關(guān)系。要求符合從抽象到具體的邏輯順序,愈抽象的問題愈在前,愈具體的問題愈在后,否則就叫層次不清、邏輯混亂。
其規(guī)則是:愈抽象愈在前,愈具體愈在后。
實例:
碩士論文:最高額抵押權(quán)研究
第一部分 最高額抵押權(quán)的意義
第二部分 最高額抵押權(quán)的歷史演進
第三部分 最高額抵押權(quán)的設(shè)定
第四部分 最高額抵押權(quán)的效力
第五部分 最高額抵押權(quán)的確定
第六部分 最高額抵押權(quán)的消滅
其第一、二部分屬于總論;第三至第六部分屬于分論。其分論的結(jié)構(gòu)顯然符合純粹邏輯的遞進關(guān)系。須注意的是,在一篇論文中,尤其是長篇專題研究論文、碩士論文、博士論文,不是只反映一種遞進關(guān)系形態(tài),可能某一編、某一章內(nèi)部是時間上的遞進關(guān)系,另外的編、章內(nèi)部是邏輯上的遞進關(guān)系。
關(guān)于本論部分的邏輯關(guān)系,還有一個要求是要有重點,避免等分式、無重點、面面俱到和過分枝蔓。我上研究生的時候,研究生院院長溫濟澤教授作報告,講到學(xué)術(shù)論文寫作多次引用前人的詩句:“刪繁就簡三秋樹,領(lǐng)異標新二月花”。前一句就是指,文章的結(jié)構(gòu),要避免過分枝蔓,要突出重點。
下面舉不合邏輯的實例:
實例1:
碩士論文:著作權(quán)若干問題研究
一、著作權(quán)的成因、發(fā)展和不同制度比較;
二、我國著作權(quán)制度的歷史、現(xiàn)狀和立法構(gòu)想;
三、著作權(quán)若干問題的具體探究。
評論:
問題在于邏輯關(guān)系混亂,第一部分的成因、發(fā)展、不同制度比較與第二部分的歷史、現(xiàn)狀是重復(fù)的;立法構(gòu)想應(yīng)該在整個研究完成之后提出,卻安排在第二部分,全部研究未完成,尤其對著作權(quán)的若干基本問題還未研究清楚,就提出立法構(gòu)想,也不合邏輯。
實例2:
碩士論文:論新聞侵權(quán)為題的碩士論文
第一章 新聞侵權(quán)概述
第二章 新聞侵害名譽權(quán)的民事責(zé)任
第三章 新聞侵害隱私權(quán)的民事責(zé)任
第四章 新聞侵害肖像權(quán)的民事責(zé)任
第五章 新聞侵權(quán)民事責(zé)任主體
第六章 新聞侵權(quán)損害的救濟方式
評論:
問題在于總分顛倒,第二、三、四章屬于分論,卻安排在前面,第五章新聞侵權(quán)的責(zé)任主體和第六章救濟方式應(yīng)當屬于總論,卻安排在后面。
實例3:
碩士論文:論企業(yè)集團的法律地位
一、企業(yè)集團產(chǎn)生的客觀必然性;
二、企業(yè)集團的概念;
三、企業(yè)集團的類型及其規(guī)范化;
四、企業(yè)集團的法律地位是由其內(nèi)外關(guān)系決定的;
五、問題與對策。
評論:
問題是各部分邏輯關(guān)系混亂。連什么是企業(yè)集團都未介紹,一開頭就講客觀必然性,不合思維習(xí)慣和邏輯。思維習(xí)慣和邏輯是,先講“是什么”,再講“為什么”。概念屬于“是什么”,本應(yīng)當在前面,卻安排在第二部分。客觀必然性屬于“為什么”,本應(yīng)當在后面。第四部分是一個完整的句子,與標題不合,標題不能是句子,再說也與其他部分不協(xié)調(diào)。
實例4:
碩士論文:論時效制度
一、對時效制度的歷史考察
二、關(guān)于消滅時效效力的探討
三、我國民法是否需要設(shè)立取得時效制度
四、對完善我國民法時效制度的設(shè)想
五、時效完成后義務(wù)人的履行
六、除斥期間
評論:
同樣邏輯混亂,第三、四部分交叉、重復(fù),層次不清,第六部分除斥期間屬于課題之外的問題。
實例5:
碩士論文:論民法的締約過失責(zé)任
一、締約過失責(zé)任的由來
二、締約過失責(zé)任的幾個基本理論問題
三、英美法系的締約過失責(zé)任――非合同義務(wù)
四、締約過失責(zé)任的新發(fā)展與合同預(yù)備性文件的效力
五、我國締約過失責(zé)任的理論與實踐
評論:
存在的問題是邏輯混亂:“締約過失責(zé)任”是否包括英美法系的締約過失責(zé)任?如果回答是肯定的,則何以單獨論及英美法系的締約過失責(zé)任,而未專門論及大陸法系的締約過失責(zé)任?如果回答是否定的,即締約過失責(zé)任僅指大陸法系的制度,則何以在研究過程的中間,突然提出英美法系的締約過失責(zé)任問題?
實例6: 碩士論文:保證責(zé)任研究
一、保證責(zé)任的成立;
二、保證責(zé)任的性質(zhì);
三、保證責(zé)任的范圍;
四、保證責(zé)任的方式;
五、保證責(zé)任的期間;
六、保證責(zé)任的消滅。
評論:
相對而言,成立、范圍、方式、期間、消滅都是具體的,唯性質(zhì)是抽象的。而將性質(zhì)安排在成立之后、范圍等之前,違背了“愈抽象愈在前”的規(guī)則,造成邏輯混亂。如果在前面設(shè)一個部分:保證責(zé)任概述,在其中論及責(zé)任性質(zhì),就合乎邏輯了。
實例7:
碩士論文:融資性租賃合同研究
一、融資性租賃合同的概念及特征;
二、融資性租賃合同的訂立及條款;
三、融資性租賃合同的擔(dān)保;
四、融資性租賃合同責(zé)任。
評論:
按照思維的邏輯習(xí)慣,一提到合同的訂立,馬上會想到合同的生效、合同的履行,這也正是事物本身的邏輯。但本文在論及訂立之后,卻未論及合同的生效、合同的履行等問題,而僅研究合同的擔(dān)保。其邏輯難謂合理、嚴密。
實例8:
碩士論文:論農(nóng)地承包經(jīng)營權(quán)
第一部分 農(nóng)地承包經(jīng)營權(quán)的基本特點和主要缺點
第二部分 農(nóng)地承包經(jīng)營權(quán)的革新
(一)第三部分 農(nóng)地承包經(jīng)營權(quán)的革新
(二)第四部分 他國(地區(qū))農(nóng)地使用制度與農(nóng)業(yè)發(fā)展的經(jīng)驗介紹
第五部分 農(nóng)地承包經(jīng)營權(quán)規(guī)范化建構(gòu)的制約因素及其發(fā)展態(tài)勢分析
第六部分 農(nóng)地承包經(jīng)營權(quán)目標模式的建構(gòu)
評論:
問題是,先講中國,后講外國,最后再來講中國,違反先外國后本國的空間上的遞進關(guān)系。邏輯關(guān)系是混亂的。
實例9:
碩士論文:加害給付研究
第一章 德國法中的積極侵害債權(quán)
第二章 中國法的加害給付
第三章 加害給付的構(gòu)成要件及法律效果
第四章 民事責(zé)任競合概述及責(zé)任比較
第五章 外國民事責(zé)任競合處理
第六章 中國法的責(zé)任競合
評論:
問題是題目確定的研究范圍不能涵蓋第四、五、六章的“民事責(zé)任競合”,各章之間邏輯關(guān)系不清。
實例10:
碩士論文:我國合同解除制度立法研究:
第一章 關(guān)于合同解除的歷史考察
第二章 我國現(xiàn)行合同法關(guān)于合同解除的規(guī)定及其問題
第三章 合同解除的概念和意義
第四章 解除權(quán)的性質(zhì)、種類與發(fā)生原因
第五章 行使法定解除權(quán)的原因
第六章 行使解除權(quán)的方法
第七章 合同解除的效力
第八章 合同解除權(quán)的消滅
評論:
問題主要是第二章我國現(xiàn)行合同法關(guān)于我國合同解除的規(guī)定及其問題,本應(yīng)當安排在本文最后予以分析并提出對策建議,卻安排在第二章,不符合邏輯思維順序和習(xí)慣,破壞了其他各章從遠到近、從抽象到具體的遞進關(guān)系。
6、對各部分標題的要求
第一項要求:標題應(yīng)當是名詞或名詞性短語,不能是一個句子
第二項要求:標題只確定本部分的研究對象,不表達作者觀點
第三項要求:標題應(yīng)明確、簡短而忌冗長
第四項要求:標題應(yīng)當出現(xiàn)題目中的關(guān)鍵詞
第五項要求:同一層次的各標題應(yīng)相互協(xié)調(diào)
實例1:
博士論文:荷蘭國際私法研究
第一章 荷蘭國際私法概述
第二章 荷蘭與國際私法統(tǒng)一化
第三章 荷蘭國際私法法典化編纂
評論:
我們看到各章的標題,都是名詞性短語,而不是句子,符合第一項要求;各標題只是確定本章研究對象或范圍,而不表達作者觀點,符合第二項要求;各標題符合明確、簡短而不冗長的第三項要求;論文題目中的關(guān)鍵詞,亦即“動賓結(jié)構(gòu)”中的名詞“國際私法”,在各章標題中重復(fù)出現(xiàn),這也就是所謂“切題”,符合第四項要求;各標題結(jié)構(gòu)、長短比較協(xié)調(diào),符合第五項要求。
再看其中第一章下面的各節(jié):
第一節(jié) 荷蘭國際私法的概念
第二節(jié) 荷蘭國際私法的淵源
第三節(jié) 荷蘭國際私法的性質(zhì)
第四節(jié) 荷蘭國際私法的歷史發(fā)展
同樣符合關(guān)于標題的五項要求。
實例2:
博士論文為例:責(zé)任保險論
第一章 責(zé)任保險概述
第二章 責(zé)任保險的分類
第三章 責(zé)任保險合同
第四章 責(zé)任保險人的給付責(zé)任
第五章 責(zé)任保險的第三人
第六章(責(zé)任保險的)抗辯與和解的控制
第七章 責(zé)任保險人的抗辯義務(wù)
第八章 責(zé)任保險與再保險
評論:
同樣符合上述五項要求。須補充的是,在章節(jié)標題設(shè)計上,可能出現(xiàn)在一個標題中有兩個名詞性短語,亦即一個章、節(jié)可以有兩個或三個研究對象。在節(jié)以下層次的標題,第三項要求,可以不象章、節(jié)(特別是章)那樣嚴格。再就是,有的論文章標題似未重復(fù)論文題目中的關(guān)鍵詞,而直接采用論文題目關(guān)鍵詞的下位概念,以作為各章標題的賓語短語。
實例3:
博士論文為例:國際貨幣基金協(xié)定研究 第四章 國際收支平衡的法律制度研究
第五章 國際儲備的法律制度研究
第六章 匯兌安排國際法律制度研究
第七章 外匯管制法律問題研究
第八章 基金協(xié)定的監(jiān)督與磋商機制研究
評論:
實際上可以認為,各章標題中省略了論文題目中的關(guān)鍵詞“國際貨幣基金協(xié)定”:
第五章(國際貨幣基金協(xié)定中的)國際收支平衡的法律制度研究
第六章(國際貨幣基金協(xié)定中的)國際儲備的法律制度研究
第七章(國際貨幣基金協(xié)定中的)匯兌安排國際法律制度研究
第八章(國際貨幣基金協(xié)定中的)外匯管制法律問題研究
第九章(國際貨幣)基金協(xié)定的監(jiān)督與磋商機制研究
不適當?shù)膶嵗?:
博士論文:論私法對國際法的影響
第一章 萬民法與國際法
第二章 人或主體
第三章 領(lǐng)土主權(quán)與所有權(quán)
第四章 條約與契約
評論:
問題是不符合關(guān)于標題的第三項要求:各章標題中沒有出現(xiàn)論文題目中的關(guān)鍵詞,因此給人的印象是不切題。如果對各章標題的文字作一些調(diào)整,效果就會不同:
第一章 萬民法與國際法
第二章 私法主體與國際法主體
第三章 私法所有權(quán)與國際法領(lǐng)土主權(quán)
第四章 私法契約與國際法條約
不適當?shù)膶嵗?:
碩士論文:論物權(quán)立法
其第三部分 我國現(xiàn)實歷史條件下物權(quán)立法之必要性研討
第一節(jié) 建立我國完整統(tǒng)一的物權(quán)制度是馬克思所有權(quán)理論的必然要求
第二節(jié) 建立完整統(tǒng)一的物權(quán)制度是我國現(xiàn)經(jīng)濟基礎(chǔ)的客觀要求
第三節(jié) 建立完整而統(tǒng)一的物權(quán)制度是我國現(xiàn)實司法實務(wù)更有利于保護公民法人的合法權(quán)益的客觀要求
評論:
存在的問題是,標題不是一個名詞性短語,而是一個完整的句子,違背第一項要求;不是確定各節(jié)研究對象、研究范圍,而是直接表達作者觀點,違背第二項要求;各標題十分冗長,第三節(jié)標題長達41個字,顯然違背第四項要求;第一節(jié)標題“建立我國完整統(tǒng)一的”,第二節(jié)標題“建立完整統(tǒng)一的”,第三節(jié)標題“建立完整而統(tǒng)一的”,甚不協(xié)調(diào),違背第五項要求。
如果作下述調(diào)整,效果將會改觀:
第一節(jié) 從馬克思所有權(quán)理論看我國物權(quán)立法
第二節(jié) 從現(xiàn)實經(jīng)濟基礎(chǔ)看我國物權(quán)立法
第三節(jié) 從公民法人合法權(quán)益保護看我國物權(quán)立法
結(jié)語
碩士論文、博士論文的結(jié)構(gòu),除導(dǎo)論、本論、結(jié)論三部分外,前面必須有目錄,還可以有序言。后面必須有參考著作目錄,可以再寫個后記。后記的內(nèi)容沒有一定之規(guī),通常是致謝及發(fā)感慨。
阿道夫 的 范德薩 啊訂單式
第三篇:關(guān)于分析今天保定百度百度愛問愛第3章C54x DSP系統(tǒng)硬件結(jié)構(gòu)DSP芯片
關(guān)于分析今天保定百度百度愛問愛第3章C54x DSP系統(tǒng)硬件結(jié)構(gòu)DSP芯片.txt
-你腳踏倆只船,你劃得真漂亮。-每個說不想戀愛的人 心里都裝著一個不可能的人。我心疼每一個不快樂卻依然在笑的孩子。(有沒有那么一個人,看透我在隱身,知道我在等人。的的的地方地方愛的規(guī)格愛你啊好文章第3章 C54x DSP系統(tǒng)硬件結(jié)構(gòu)
DSP芯片是一種特殊結(jié)構(gòu)的微處理器,為了快速地實現(xiàn)數(shù)字信號處理運算,采用了流水線指令執(zhí)行結(jié)構(gòu)和相應(yīng)的并行處理結(jié)構(gòu),可在一個周期內(nèi)對數(shù)據(jù)進行高速的算術(shù)運算和邏輯運算。本章主要介紹C54x DSP芯片的硬件結(jié)構(gòu),重點對芯片的引腳功能、CPU結(jié)構(gòu)、內(nèi)部存儲器、片內(nèi)外設(shè)電路、系統(tǒng)控制以及內(nèi)、外部總線進行討論。3.1 C54x DSP的基本架構(gòu) TMS320 C54x DSP(簡稱C54x)是TI公司為實現(xiàn)低功耗、高速實時信號處理而專門設(shè)計的16位定點數(shù)字信號處理器。其內(nèi)核包含在第1章已經(jīng)討論過的哈佛結(jié)構(gòu)和高級算術(shù)特點中。另外,C54x還具有多總線結(jié)構(gòu)以及強大的片上外設(shè),具有高度的操作靈活性和運行速度,適應(yīng)遠程通信等實時嵌入式應(yīng)用的需要,現(xiàn)已廣泛地應(yīng)用于無線通信系統(tǒng)中。3.1.1 C54x DSP的基本結(jié)構(gòu)圖
一塊DSP芯片上集成CPU、片內(nèi)存儲器、外圍電路、總線以及外部總線接口。圖3-1所示為TMS320C54x基本結(jié)構(gòu)框圖,它包含了主要模塊和總線結(jié)構(gòu)。圖3-2所示為TMS320C54x功能結(jié)構(gòu)圖。與傳統(tǒng)微處理器相比較,DSP最顯著的結(jié)構(gòu)特點是具有高效存取數(shù)據(jù)、單周期乘法器和零開銷硬件循環(huán)等。3.1.2 C54x DSP的主要特征
1.具有快速處理性能的CPU部分 CPU是DSP芯片中的核心部分,CPU內(nèi)的硬件構(gòu)成決定其指令系統(tǒng)的性能。采用了流水線指令執(zhí)行結(jié)構(gòu)和相應(yīng)的并行處理結(jié)構(gòu),可在一個周期內(nèi)對數(shù)據(jù)進行高速的算術(shù)運算和邏輯運算,TMS320C54x的CPU包括以下幾部分:
(1)先進的多總線結(jié)構(gòu),包括1條程序總線、3條數(shù)據(jù)總線、4條地址總線和外設(shè)總線;(2)40位算術(shù)邏輯單元(ALU),包括1個40位的桶形移位寄存器和2個獨立的40位累加器;
(3)17×17的并行乘法器,并與1個40位的專用加法器配合,用于非流水線的單周期乘/累加操作;DSP芯片技術(shù)及工程實例第3章 C54x DSP系統(tǒng)硬件結(jié)構(gòu)圖3-1 TMS320C54x基本結(jié)構(gòu)框圖
圖3-2 TMS320C54x功能結(jié)構(gòu)圖
(4)比較、選擇和存儲單元,用于維特比運算中的加/比較選擇;(5)指數(shù)編碼器,可以在單周期內(nèi)計算40位累加器的指數(shù)值;
(6)2個地址生成器,包括8個輔助寄存器和2個輔助寄存器算術(shù)單元;(7)雙內(nèi)核結(jié)構(gòu)(只適用于C5420).2.具有哈佛結(jié)構(gòu)的存儲器系統(tǒng)
(1)具有獨立的程序存儲器和數(shù)據(jù)存儲器,可同時訪問,使許多處理運算比傳統(tǒng)的馮·諾依曼結(jié)構(gòu)有效得多。
(2)具有192K字可尋址存儲空間,包括片內(nèi)、外64K字程序存儲空間,片內(nèi)、外64K字數(shù)字存儲空間和片外64K字的I/O空間。其中一些型號DSP的程序存儲器空間可擴展至8M字,例如TMS320C548、TMS320C549、TMS320C5402、TMS320C5410和TMS320C5420.(3)提供一定容量的片內(nèi)存儲器,片內(nèi)存儲器配置因型而異,包括片內(nèi)ROM和RAM,通過內(nèi)部多總線,CPU可以同時、快速地訪問它們,以實現(xiàn)并行處理。但對于外部存儲器,DSP提供了外部接口,它與內(nèi)部多總線結(jié)構(gòu)復(fù)接,但外部只有一組I/O接口線,所以不能在單周期內(nèi)并行實現(xiàn)讀寫操作。3.片內(nèi)外設(shè)和專用電路
除了DSP內(nèi)核外,DSP芯片上還需配置一些外設(shè)專用器件。這些器件可以與DSP內(nèi)核平行操作,只占用很小的內(nèi)核指令周期,依靠這些器件無縫出入DSP處理內(nèi)核的能力,可大大提高DSP處理數(shù)據(jù)的能力。TMS320C54x的片內(nèi)外設(shè)和專用電路采用模塊化的結(jié)構(gòu)設(shè)計,常見的外設(shè)包括以下幾種。
(1)可編程軟件等待狀態(tài)發(fā)生器。(2)可編程分區(qū)轉(zhuǎn)換邏輯電路。
(3)可采用內(nèi)部振蕩器或外部時鐘源的片內(nèi)鎖相環(huán)(PLL)時鐘發(fā)生器。
(4)外部總線接口可以禁止或允許外部數(shù)據(jù)總線、地址總線和控制線的輸出。(5)數(shù)據(jù)總線具有總線保持功能。(6)可編程定時器。
(7)8位并行主機接口(HPI),有些產(chǎn)品還包括擴展的8位并行主機接口(HPI8)和16位并行主機接口(HPI16).(8)片內(nèi)的串行口按不同的型號分為全雙工串口(支持8位和16位數(shù)據(jù)傳送)、時分多路(TDM)串口和緩沖(BSP)串口。
C54x系列定點DSP芯片共享同樣的CPU內(nèi)核和總線結(jié)構(gòu),但每一種器件片內(nèi)存儲器的配置和片內(nèi)外設(shè)不盡相同。表3-1列出了TMS320C54x系列DSP基本配置匯總。表3-1 TMS320C54x系列DSP基本配置匯總表型 號電壓/VcoreI/O片內(nèi)存儲器RAM/ KBROM/ KBDAT/ PRO/B外 設(shè)McBSPTimerHPIDMAMIPS封 裝C54011.83.384128K/2M228位6通道50144LQFP/ 144BGAC54021.6/ 1.83.3328/32128K/2M/ 128K/16M2/31/28位6通道100/ 160144LQFP/ 144BGAC54041.53.332128128K/16M328/16位6通道120144LQFP/ 144BGA續(xù)表型 號電壓/VcoreI/O片內(nèi)存儲器RAM/ KBROM/ KBDAT/ PRO/B外 設(shè)McBSPTimerHPIDMAMIPS封 裝C54071.63.380256128K/16M328/16位6通道120144LQFP/ 144BGAC54091.5~
1.83.36432128K/16M318/16位6通道80~ 160144LQFP/ 144BGAC54101.5~
2.53.312832128K/16M318/16位6通道100~ 160144LQFP/ 144BGAC54161.5/ 1.63.325632128K/16M318/16位6通道120/ 160144LQFP/ 144BGAC54201.83.32000128K/16M6216位12通道200144LQFP/ 144BGA4.指令系統(tǒng)
在TMS320C54x的指令系統(tǒng)中,具有單指令重復(fù)和塊指令重復(fù)操作指令,32位長操作數(shù)指令,同時讀入2個或3個操作數(shù)的算術(shù)指令。支持存儲器塊傳送指令,能并行存儲和并行加載的算術(shù)指令,支持條件存儲指令及中斷快速返回指令。5.執(zhí)行速度
對TMS320C54x而言,其執(zhí)行單周期定點指令時間為25/20/15/12.5/10ns(對應(yīng)每秒指令數(shù)分別為40/50/66/80/100MIPS).6.電源和功耗
TMS320C54x DSP芯片可采用5V、3.3V、3V和1.5V、1.8V或2.5V的超低電壓供電。而且其功耗可采用下降指令I(lǐng)DLE1、IDLE2和IDLE3來控制,以便使DSP工作在節(jié)電模式下可控制關(guān)斷CLKOUT信號。7.芯片仿真功能 具有符合IEEE 1149.1標準的片內(nèi)仿真JTAG接口,其主要功能是用于與主機相連接,實現(xiàn)芯片的仿真與測試。3.2 總線結(jié)構(gòu)
按照結(jié)構(gòu)來區(qū)分,又可將總線分成內(nèi)部總線和外部總線,本節(jié)只介紹內(nèi)部總線,外部總線的結(jié)構(gòu)和功能將在3.8節(jié)介紹。
為了提高CPU高度的并行性,達到最大的處理能力,例如在單周期內(nèi)完成算術(shù)、邏輯和位操作等運算,TMS320C54x DSP片內(nèi)采用多總線結(jié)構(gòu),用8條總線,可同時對程序指令和數(shù)據(jù)進行雙訪問,這8條16位的總線包括4條程序/數(shù)據(jù)總線和4條地址總線。另外,CPU訪問片內(nèi)外設(shè)是通過在片雙向總線來實現(xiàn)的,如圖3-2所示的功能結(jié)構(gòu)圖。正是這種改進型哈佛總線結(jié)構(gòu),形成了支持高速指令執(zhí)行的硬件基礎(chǔ)。
(1)程序總線(PB): 傳送來自程序存儲器的指令代碼和立即數(shù)。
(2)3組數(shù)據(jù)總線(CB、DB和EB): 負責(zé)將片內(nèi)的各種元器件相互連接,如CPU、數(shù)據(jù)地址產(chǎn)生邏輯、程序地址產(chǎn)生邏輯、片內(nèi)外設(shè)和數(shù)據(jù)存儲器等。其中,CB和DB總線傳送從存儲器讀出的數(shù)據(jù),即“讀”操作使用的數(shù)據(jù)總線;EB總線傳送向存儲器寫入的數(shù)據(jù),即“寫”操作使用的數(shù)據(jù)總線。
(3)地址總線(PAB、CAB、DAB、EAB): 負責(zé)傳送執(zhí)行指令所需的地址。
(4)在片雙向總線: TMS320C54x用一組雙向的片內(nèi)總線訪問片內(nèi)外設(shè),這組總線輪流使用DB和EB與CPU連接。用這組總線進行讀/寫操作需要兩個或更多的周期,具體所需周期數(shù)取決于片內(nèi)外設(shè)的結(jié)構(gòu)。
TMS320C54x能利用兩個輔助寄存器算術(shù)單元(ARAU0和ARAU1)在同一個周期內(nèi)生成兩個數(shù)據(jù)存儲器地址,可實現(xiàn)片內(nèi)RAM 的雙訪問功能。
表3-2列出了各種不同類型的總線訪問形式。從表中看到,C54x器件在任何給定的機器周期內(nèi)可執(zhí)行4個并行存儲器操作: 1次取指、讀取2個操作數(shù)和寫1個操作數(shù)?;蛲ㄟ^CB、DB、PB總線同時取操作數(shù),可在一個機器周期內(nèi)完成從數(shù)據(jù)存儲器讀雙數(shù)據(jù)同時從程序存儲器讀一個常數(shù)的3個操作數(shù)讀取,而片上外設(shè)的讀、寫則是通過DB和EB總線輪流與CPU連接完成,所以使用這組總線進行讀/寫操作需要兩個或更多的周期。表3-2 C54x DSP讀/寫操作占用總線情況讀/寫方式地 址 總 線PABCABDABEAB程序總線
PB數(shù) 據(jù) 總 線CBDBEB程序讀√√程序?qū)憽獭虇螖?shù)據(jù)讀√√雙數(shù)據(jù)讀√√√√32位長數(shù)據(jù)讀√(hw)√(lw)√(hw)√(lw)單數(shù)據(jù)寫√√數(shù)據(jù)讀/數(shù)據(jù)寫√√√√雙數(shù)據(jù)讀/系數(shù)讀√√√√√√外設(shè)讀√√外設(shè)寫√√3.3 存儲器結(jié)構(gòu) TMS320C54x DSP存儲器采用改進型哈佛結(jié)構(gòu)。與馮·諾依曼結(jié)構(gòu)的存儲器相比較,哈佛結(jié)構(gòu)的程序/數(shù)據(jù)總線和空間是分開的,馮·諾依曼結(jié)構(gòu)的程序/數(shù)據(jù)總線和空間是合二為一的,而改進型哈佛結(jié)構(gòu)的部分程序/數(shù)據(jù)空間可交叉,因此提供了高度的并行性。3.3.1 DSP存儲器空間的劃分 C54x DSP的存儲空間共192K字,由3個獨立可選的存儲空間組成,包括64K字的程序存儲空間、64K字的數(shù)據(jù)存儲空間和64K字的I/O空間。其中有些型號芯片的程序空間還可以進一步擴展。
存儲器分為片內(nèi)存儲器和片外存儲器。片內(nèi)存儲器有3種類型: 雙訪問RAM(DARAM)、單訪問RAM(SARAM)和ROM.RAM總是安排到數(shù)據(jù)存儲空間,但也可以配置在程序存儲空間。C54x片上還有26個映射到數(shù)據(jù)存儲空間的CPU寄存器和外設(shè)寄存器。ROM一般映射到程序存儲空間,也可以部分地映射到數(shù)據(jù)存儲空間。在TMS320C54x DSP中,片外存儲器主要包括程序存儲器、數(shù)據(jù)存儲器、I/O空間。與片外存儲器相比,片內(nèi)存儲器不需插入等待狀態(tài),成本低,功耗低。但是,片外存儲器具有尋址較大存儲空間的能力,而片內(nèi)存儲器尋址存儲空間較小。C54x通過設(shè)置處理器工作方式狀態(tài)寄存器(PMST)中的3個狀態(tài)位MP/MC、OVLY和DROM(詳見3.4.1節(jié)),可以很方便地“使能”和“禁止”程序與數(shù)據(jù)空間中的片內(nèi)存儲器。(1)MP/MC位
MP/MC位決定是否使用片內(nèi)ROM.若MP/MC=0,稱微計算機模式,片內(nèi)ROM使能并能夠訪問。若MP/MC=1,稱微處理器模式,表示片內(nèi)ROM無法訪問。(2)OVLY位
OVLY位決定是否讓數(shù)據(jù)存儲器映射到程序存儲器空間。若OVLY=0,片內(nèi)RAM只映射到數(shù)據(jù)存儲空間。
若OVLY=1,片內(nèi)RAM同時映射到程序和數(shù)據(jù)存儲空間。(3)DROM位
DROM位決定是否讓部分程序存儲器映射到數(shù)據(jù)存儲器空間。若DROM=0,片內(nèi)ROM不映射到數(shù)據(jù)存儲空間。若DROM=1,部分片內(nèi)ROM映射到數(shù)據(jù)存儲空間。DROM位的用法與MP/MC位的用法無關(guān)。不同的C54x的數(shù)據(jù)和程序存儲區(qū)分配并不完全相同。圖3-3(a)所示為TMS320C549存儲器空間分配圖,圖3-3(b)所示為TMS320C5416存儲器空間分配圖,從圖中可以看到在任何一個存儲空間內(nèi),RAM、ROM都可以駐留在片內(nèi)或者片外,但需要通過對3個狀態(tài)位MP/MC、OVLY和DROM的設(shè)置來配置。圖3-3 存儲器空間分配圖 圖3-3(續(xù))
所有C54x DSP器件提供一定數(shù)量的片內(nèi)ROM和RAM, DSP有兩種類型的RAM,包括雙尋址RAM(DARAM)和單尋址RAM(SARAM)。表3-3列出了不同C54x系列DSP 片內(nèi)各種存儲器的配置。
1.片內(nèi)ROM 片內(nèi)ROM是程序存儲器的一部分,對某些DSP器件來說,也可是數(shù)據(jù)存儲空間的一部分,如C5402。當MP/MC設(shè)置為0時,可以映射到程序存儲空間的ROM為4KB;當DROM設(shè)置為1時,可以映射到數(shù)據(jù)存儲器空間的ROM為4KB。不同芯片的片內(nèi)可用ROM容量是不一樣的,見表3-3。對于ROM少的DSP器件(2KB), ROM中含有自舉加載器,在程序啟動時,將用戶的代碼從慢的外部ROM、串口,或JTAG加載到內(nèi)部存儲器,這樣可以加快程序的運行速度。對于具有較大ROM的器件,部分ROM可以映射到數(shù)據(jù)和程序空間,用戶提供的代碼或數(shù)據(jù)以目標文件格式寫入ROM, TI公司可以將程序掩膜到該ROM中。2.片內(nèi)雙尋址RAM(DARAM)所謂DARAM,就是在一個指令周期內(nèi),CPU可對其進行讀和寫兩次存取操作,DARAM由塊組成,CPU能在每個周期內(nèi)對同一塊DARAM進行讀和寫。DARAM總是映射在數(shù)據(jù)存儲器空間,用于存儲數(shù)據(jù),當OVLY設(shè)置為1時,它也可同時映射在程序存儲器空間,用于存儲程序代碼。表3-3 常見的C54x系列DSP片內(nèi)存儲器配置KB存儲器類型C541C542C543C545C546C548C549C5402C5416C5420ROM***程序ROM***程序/數(shù)據(jù)ROM800161600400DARAM***SARAM***3.片內(nèi)單尋址RAM(SARAM)在一個指令周期內(nèi)只能進行一次讀或?qū)懖僮?。SARAM也由塊組成,與DARAM一樣,SARAM總是映射在數(shù)據(jù)存儲器空間,用于存儲數(shù)據(jù),當OVLY設(shè)置為1時,也可同時映射在程序存儲器空間,用于存儲程序代碼。4.存儲器映射寄存器
CPU內(nèi)部專用寄存器和片上外設(shè)寄存器總是映射在數(shù)據(jù)存儲器的0頁上,對它們的訪問很簡單,存儲器映射訪問提供了一種方便途徑,用于寄存器的存儲和恢復(fù),也用于累加器與其他寄存器之間的信息傳遞。3.3.2 程序存儲器
程序存儲器空間存放要執(zhí)行的指令和執(zhí)行中所用的系數(shù)表。C54x DSP可以尋址64 K字的程序存儲空間。但也有一些型號的DSP可以擴展到8 M字,如C548、C549、C5410、C5402和C5420。下面分別講述程序存儲器的組織、片內(nèi)ROM 的安排、擴展程序存儲器等內(nèi)容。1.程序存儲器空間的配置
程序存儲器空間由片內(nèi)和片外程序存儲器組成。如前所述,片內(nèi)程序空間的組織主要通過設(shè)置MP/MC、OVLY位來實現(xiàn)。表3-4列出了各種C54x芯片片內(nèi)程序存儲器配置情況。MP/MC和OVLY 位決定了哪個片內(nèi)存儲器在程序空間中可用。例如,當OVLY設(shè)置為1時,DARAM或SARAM才能被配置到程序存儲器空間;而只有當MP/MC設(shè)置為0時,片內(nèi)ROM才可用。MP/MC是DSP的一個外部引腳,設(shè)置MP/MC狀態(tài)有兩種方法,一種是直接給MP/MC引腳低電平或高電平,當DSP器件復(fù)位時,MP/MC引腳的邏輯狀態(tài)被傳送到PMST寄存器的MP/MC位。另一種方法是用戶通過軟件來設(shè)置或清除PMST寄存器的MP/MC位,以便禁止或使能片內(nèi)ROM。如果片內(nèi)存儲器配置到程序存儲器中,則芯片在訪問程序存儲器時會自動訪問這些存儲單元。當PAGEN產(chǎn)生了一個不在片內(nèi)存儲器的地址時,會自動使用一個外部總線操作。C54x器件程序存儲器空間配置圖如圖3-3(a)和圖3-3(b)所示。表3-4 TSM320C54x芯片片內(nèi)程序存儲器配置KB型 號ROMDARAM(OVLY=1)SARAM(OVLY=1)TMS320C541285-TMS320C542210-TMS320C543210-TMS320C545486-TMS320C546486-TMS320C5482824TMS320C54916824TMS320C5402416-TMS320C541616856TMS320C5420-32168 2.片內(nèi)ROM 的組織和內(nèi)容
為了增強處理器的性能,將片內(nèi)ROM再細分為若干塊,這樣就可以在片內(nèi)ROM的一個塊內(nèi)取指的同時又在別的塊中讀數(shù)據(jù)。圖3-4所示為各種C54x器件的片內(nèi)ROM分塊圖。根據(jù)C54x器件的不同,ROM可以組織為2KB、4KB或8KB的塊。圖3-4 C54x 器件片內(nèi)ROM分塊圖
(1)對于2K-ROM器件,其ROM 塊為2K字。
(2)對于4K-ROM和28K-ROM 器件,其ROM塊為4K字。(3)對于16K-ROM和48K-ROM器件,其ROM塊為8K字。C54x的片內(nèi)ROM容量有大(28K或48K字)有小(2K或4K字),但對于程序存儲器空間的最高2K字程序空間(F800h~FFFFh),容量大的片內(nèi)ROM(C541/C545/C546)可以把 阿道夫 的 范德薩 啊訂單式