久久99精品久久久久久琪琪,久久人人爽人人爽人人片亞洲,熟妇人妻无码中文字幕,亚洲精品无码久久久久久久

關于分析今天長安保定百度愛問愛第2章代碼初識 本章首先從較高層次

時間:2019-05-15 09:15:01下載本文作者:會員上傳
簡介:寫寫幫文庫小編為你整理了多篇相關的《關于分析今天長安保定百度愛問愛第2章代碼初識 本章首先從較高層次》,但愿對你工作學習有幫助,當然你在寫寫幫文庫還可以找到更多《關于分析今天長安保定百度愛問愛第2章代碼初識 本章首先從較高層次》。

第一篇:關于分析今天長安保定百度愛問愛第2章代碼初識 本章首先從較高層次

的的范德薩的地方愛的規格愛你啊好文章第2章 代 碼 初 識

本章首先從較高層次介紹Linux內核源程序的概況,這些都是大家關心的一些基本特點。隨后將簡要介紹一些實際代碼。最后介紹如何編譯內核。2.1 Linux內核源程序的部分特點

在過去的一段時期,Linux內核同時使用C語言和匯編語言來實現。這兩種語言需要一定的平衡:C語言編寫的代碼移植性較好、易于維護,而匯編語言編寫的程序則速度較快。一般只有在速度是關鍵因素或者一些因平臺相關特性而產生的特殊要求(例如直接和內存管理硬件進行通訊)時才使用匯編語言。

正如實際中所做的,即使內核并未使用C++的對象特性,部分內核也可以在g++(GNU的C++編譯器)下進行編譯。同其他面向對象的編程語言相比較,相對而言C++的開銷是較低的,但是對于內核開發人員來說,這已經是太多了。

內核開發人員不斷發展編程風格,形成了Linux代碼獨有的特色。本節將討論其中的一些問題。

2.1.1 gcc特性的使用

Linux內核被設計為必須使用GNU的C編譯器gcc來編譯,而不是任何一種C編譯器都可以使用。內核代碼有時要使用gcc特性,本書將陸續介紹其中的一部分。一些gcc特有代碼只是簡單地使用gcc語言擴展,例如允許在C(不只是C++)中使用inline關鍵字指示內聯函數。也就是說,代碼中被調用的函數在每次函數調用時都會被擴充,因而就可以節約實際函數調用的開銷。

一般情況下,代碼的編寫方式比較復雜。因為對于某些類型的輸入,gcc能夠產生比其他輸入效率更高的執行代碼。從理論上講,編譯器可以優化具有相同功能的兩種對等的方法,并且得到相同的結果。因此,代碼的編寫方式是無關緊要的。但在實際上,用某種方法編寫所產生的代碼要比用另外一些方法編寫所產生的代碼執行速度快許多。內核開發人員知道怎樣才能產生更高效的執行代碼,這不斷地在他們編寫的代碼中反映出來。例如,考慮內核中經常使用的goto語句—為了提高速度,內核中經常大量使用這種一般要避免使用的語句。在本書中所包含的不到40 000行代碼中,一共有500多條goto語句,大約是每80行一個。除匯編文件外,精確的統計數字是接近每72行一個goto語句。公平地說,這是選擇偏向的結果:比例如此高的原因之一是本書中涉及的是內核源程序的核心,在這里速度比其他因素都需要優先考慮。整個內核的比例大概是每260行一個goto語句。然而,這仍然是我不再使用Basic進行編程以來見過的使用goto頻率最高的地方。

代碼必需受特定編譯器限制的特性不僅與普通應用程序的開發有很大不同,而且也不同于大多數內核的開發。大多數的開發人員使用C語言編寫代碼來保持較高的可移植性,即使在編寫操作系統時也是如此。這樣做的優點是顯而易見的,最為重要的一點是一旦出現更好的編譯器,程序員們可以隨時進行更換。

內核對于gcc特性的完全依賴使得內核向新的編譯器上移植更加困難。最近Linus對這一問題在有關內核的郵件列表上表明了自己的觀點:“記住,編譯器只是一個工具。”這是對依賴于gcc特性的一個很好的基本思想的表述:編譯器只是為了完成工作。如果通過遵守標準還不能達到工作要求,那么就不是工作要求有問題,而是對于標準的依賴有問題。

在大多數情況下,這種觀點是不能被人所接受的。通常情況下,為了保證和程序語言標準的一致,開發人員可能需要犧牲某些特性、速度或者其他相關因素。其他的選擇可能會為后期開發造成很大的麻煩。

但是,在這種特定的情況下,Linus是正確的。Linux內核是一個特例,因為其執行速度要比向其他編譯器的可移植性遠為重要。如果設計目標是編寫一個可移植性好而不要求快速運行的內核,或者是編寫一個任何人都可以使用自己喜歡的編譯器進行編譯的內核,那么結論就可能會有所不同了;而這些恰好不是Linux的設計目標。實際上,gcc幾乎可以為所有能夠運行Linux的CPU生成代碼,因此,對于gcc的依賴并不是可移植性的嚴重障礙。在第3章中我們將對內核設計目標進行詳細說明。2.1.2 內核代碼習慣用語

內核代碼中使用了一些顯著的習慣用語,本節將介紹常用的幾個。當通讀源代碼時,真正重要的問題并不在這些習慣用語本身,而是這種類型的習慣用語的確存在,而且是不斷被使用和發展的。如果你需要編寫內核代碼,你應該注意到內核中所使用的習慣用語,并把這些習慣用語應用到你的代碼中。當通讀本書(或者代碼)時,看看你還能找到多少習慣用語。為了討論這些習慣用語,我們首先需要對它們進行命名。為了便于討論,筆者創造了這些名字。而在實際中,大家不一定非要參考這些用語,它們只是對內核工作方式的描述而已。一個普通的習慣用語,筆者稱之為“資源獲取”(resource acquisition idiom)。在這個用語中,一個函數必須實現一系列資源的獲取,包括內存、鎖等等(這些資源的類型未必相同)。只有成功地獲取當前所需要的資源之后,才能處理后面的資源請求。最后,該函數還必須釋放所有已經獲取的資源,而不必考慮沒有獲取的資源。

我采用“錯誤變量”這一用語(error variable idiom)來輔助說明資源獲取用語,它使用一個臨時變量來記錄函數的期望返回值。當然,相當多的函數都能實現這個功能。但是錯誤變量的不同點在于它通常是用來處理由于速度的因素而變得非常復雜的流程控制中的問題。錯誤變量有兩個典型的值,0(表示成功)和負數(表示有錯)。

這兩個用語結合使用,我們就可以十分自然地得到符合模式的代碼如下:

(注意變量err是使用錯誤變量的一個明確實例,同樣,諸如out之類的標號則指明了資源獲取用語的使用。)

如果執行到標號out2,則都已經獲取了r1和r2資源,而且也都需要進行釋放。如果執行到標號out1(不管是順序執行還是使用goto語句進行跳轉到),則r2資源是無效的(也可能剛被釋放),但是r1資源卻是有效的,而且必需在此將其釋放。同理,如果標號out能被執行,則r1和r2資源都無效,err所返回的是錯誤或成功標志。

在這個簡單的例子中,對err的一些賦值是沒有必要的。在實踐中,實際代碼必須遵守這種模式。這樣做的原因主要在于同一行中可能包含有多種測試,而這些測試應該返回相同的錯誤代碼,因此對錯誤變量統一賦值要比多次賦值更為簡單。雖然在這個例子中對于這種屬性的必要性并不非常迫切,但是我還是傾向于保留這種特點。有關的實際應用可以參考sys_shmctl(第21654行),在第9章中還將詳細介紹這個例子。2.1.3 減少#if和#ifdef的使用

現在的Linux內核已經移植到不同的平臺上,但是我們還必須解決移植過程中所出現的問題。大部分支持各種不同平臺的代碼由于包含許多預處理代碼而已經變得非常不規范,例如: 這個例子試圖實現操作系統的可移植性,雖然Linux關注的焦點很明顯是實現代碼在各種CPU上的可移植性,但是二者的基本原理是一致的。對于這類問題來說,預處理器是一種錯誤的解決方式。這些雜亂的問題使得代碼晦澀難懂。更為糟糕的是,增加對新平臺的支持有可能要求重新遍歷這些雜亂分布的低質量代碼段(實際上你很難能找到這類代碼段的全部)。與現有方式不同的是,Linux一般通過簡單函數(或者是宏)調用來抽象出不同平臺間的差異。內核的移植可以通過實現適合于相應平臺的函數(或宏)來實現。這樣不僅使代碼的主體簡單易懂,而且在移植的過程中還可以比較容易地自動檢測出你沒有注意到的內容:如引用未聲明函數時會出現鏈接錯誤。有時用預處理器來支持不同的體系結構,但這種方式并不常用,而相對于代碼風格的變化就更是微不足道了。

順便說一下,我們可以注意到這種解決方法和使用用戶對象(或者C語言中充滿函數指針的struct結構)來代替離散的switch語句處理不同類型的方法十分相似。在某些層次上,這些問題和解決方法是統一的。

可移植性的問題并不僅限于平臺和CPU的移植,編譯器也是一個重要的問題。此處為了簡化,假設Linux只使用gcc來編譯。由于Linux只使用同一個編譯器,所以就沒有必要使用#if塊(或者#ifdef塊)來選擇不同的編譯器。

內核代碼主要使用#ifdef來區分需要編譯或不需要編譯的部分,從而對不同的結構提供支持。例如,代碼經常測試SMP宏是否定義過,從而決定是否支持SMP機。2.2 代碼樣例

了解Linux代碼風格最好的方法就是實際研究一下它的部分代碼。即使你不完全理解本節所討論代碼的細節也無關緊要,畢竟本節的主要目的不是理解代碼,一些讀者可以只對本節進行瀏覽。本節的主要目的是讓讀者對Linux代碼進行初步了解,為今后的工作提供必要基礎。該討論將涉及部分廣泛使用的內核代碼。2.2.1 printk printk(25836行)是內核內部消息日志記錄函數。在出現諸如內核檢測到其數據結構出現不一致的事件時,內核會使用printk把相關信息打印到系統控制臺上。對于printk的調用一般分為如下幾類:

?緊急事件(emergency)—例如,panic函數(25563行)多次使用了printk。當內核檢測到發生不可恢復的內部錯誤時就會調用panic函數,然后盡其所能地安全關閉計算機。這個函數中調用printk以提示用戶系統將要關閉。

?調試—從3816行開始的#ifdef塊使用printk來打印SMP邏輯單元(box)中每一個處理器的相關配置信息,但是此過程只有在使用SMP_DEBUG標志編譯代碼的情況下才能夠被執行。?普通信息—例如,當機器啟動時,內核必須估計系統速度以確保設備驅動程序能夠忙等待(busy-wait)一個精確的極短周期。計算這種估計值的函數名為calibrate_delay(19654行),它既在19661行使用printk聲明馬上開始計算,又在19693行報告計算結果。另外,在第4章將詳細的介紹calibrate_delay函數。

如果你已經瀏覽過這些參照行,你可能已經注意到printk和printf的參數十分類似:一個格式化字符串,后跟零個或者多個參數加入字符串中。格式化字符串可能是以一組“”開始,這里的N是從0到7的數字,包括0和7在內。數字區分了消息的日志等級(log level),只有當日志等級高于當前控制臺定義的日志等級(console_loglevel,25650行)時,才會打印消息。root可以通過適當減小控制臺的日志等級來過濾不是很緊急的消息。如果內核在格式化字符串中檢測不到日志等級序列,那么就會一直打印消息(實際上,日志等級序列并不一定要在格式化字符串中出現,可以在格式化文本中查找到它的代碼)。

從14946行開始的#define塊說明了這些特殊序列,這些定義可以幫助調用者正確區分對printk的調用。簡單地說,我稱日志等級0到4為“緊急事件”,等級5到等級6為“普通信息”,等級7自然就是我所說的“調試”(這種分類方法并不意味著其他更好的分類方法沒有用處,而只是目前我們還不關心它而已)。在上面討論的基礎上,我們研究一下代碼本身。printk 25836:參數fmt是printf類型的格式化字符串。如果你對“...”部分的內容不熟悉,那就 需要參閱一本好的C語言參考書(在其索引中查找“變參函數,variadic function”)。另外,在安裝的GNU/Linux中的stdarg幫助里也包含了一個有關變參函數的簡明描述,在這兒只需要敲入“man stdarg”就可以看到。簡單地說,“...”部分提示編譯器fmt后面可能緊跟著數量不定的任何類型的參數。由于這些參數在編譯的時候還沒有類型和名字,內核使用由三個宏va_start、va_arg和va_end組成的特殊組及一個特殊類型—va_list對它們進行處理。25842:msg_level記錄了當前消息的日志等級。它是靜態的,這看起來可能會有些奇怪—為什么下一次對printk的調用需要記錄日志等級呢?問題的答案是只有打印出新行(n)或者賦給一個新的日志等級序列以后,當前消息才會結束。這樣,通過在包含消息結束的新行里調用printk,就保證了在多個短期沖突的情況下,調用者只打印唯一一個長消息。

25845:在SMP邏輯單元中,內核可能試圖從不同的CPU向控制臺同時打印信息(有時在單處理機(UP)邏輯單元中也會發生同樣問題,但由于中斷還未被覆蓋掉,所以問題也并不十分明顯)。如果不進行任何協同的話,結果就將處于完全無法讓人了解的雜亂無章的狀態,每個消息的各個部分都和其他消息的各個部分混雜交織在一起。

相反,內核使用旋轉鎖(spin-lock)來控制對控制臺的訪問。旋轉鎖將在第10章進行深入介紹。

如果你對flags 在傳送給spin_lock_irqsave之前為什么不對它初始化感到疑惑,請不要擔心:spin_lock_irqsave(對于不同的版本請分別參看12614行,12637行,12716行和12837行)是一個宏,而不是一個函數。該宏實際上是將值寫入flags中,而不是從flags中讀出值(在25895行中,存儲在flags中的信息被spin_unlock_irqrestore回讀,請參看12616行,12639行,12728行和12841行)。

25846:初始化變量args,該變量代表printk參數中的“...”部分。25848:調用內核自身的vsprintf(為節省空間而省略)實現。該函數的功能與標準vsprintf函數非常相似,向buf中寫入格式化文本(25634行)并返回寫入字符串的長度(長度不包括最后一位終止字符0字節)。很快,你將可以看到為什么這種機制會忽略buf的前三個字符。(正如25847行的注釋中所述)我們應該注意到在這里并沒有采取嚴格的措施來保證緩沖器不會過載。這里系統假定1024個字符長度的buf已經足夠使用(參閱25634行)。如果內核在這里能夠使用vsnprintf函數的話,情況就會好許多。然而,vsnprintf還有另外一個參數限制了它能夠寫入緩沖器的字符長度。

25849:計算buf中最近使用的元素,調用va_end終止對“...”參數的處理。

25851:開始格式化消息的循環。其中存在一個內部循環能夠處理更多內容(這一點隨后就能看到),因此,每次內循環開始,都開始一個新的打印行。由于通常情況下printk只用于打印單行,所以在每次調用中,這種循環通常只執行一次。

25853:如果預先不知道消息的日志等級,printk會檢查當前行是否以日志等級序列開頭。25860:如果不是,buf中開始未使用的三個字符就能夠起作用了(第一次以后的每次循環,都會覆蓋部分消息文本,但是這樣并不會引起問題,因為這里的文本只是前面行中的一部分,它們已經被打印過,而且以后也不再需要了)。這樣,就可以將日志等級插入buf中。25866:此處有如下屬性:p指向日志等級序列(消息文本緊隨其后),msg指向消息文本—請注意25852行和25865行中對msg的賦值。

由于已知p用來指示日志等級序列的開頭—該日志等級序列可能是由函數自身所創建的,日志等級可以從p中抽出并存到msg_level中。25868:沒有檢測到新行,清空line_feed標志。

25869:這是前面談到過的內循環,循環將運行到本行結束(也就是檢測到新行標志)或者緩沖器的末尾為止。

25870:除了將消息打印到控制臺之外,printk還能夠記錄最近打印的長度為LOG_ BUF_LEN的字符組(LOG_BUF_LEN為16K,請參看25632行)。如果在控制臺打開之前,內核就已經調用printk,則顯然不能在控制臺上正確打印消息,但是這些消息將被盡可能地存儲到log_buf中(25656行)。當控制臺打開以后,緩存在log_buf中的數據就可以轉儲并在控制臺上打印出來,請參看25988行。

log_buf是一個循環緩沖器,log_start和log_size變量(25657行和25646行)分別記錄當前緩沖器的開始位置和長度。本行中的按位與(AND)操作實際上是快速求模(%)運算,它的正確性依賴于LOG_BUF_LEN的值是2的冪。25872:保存變量跟蹤記錄循環日志的值。顯然,日志大小會不斷增長,直至達到LOG_BUF_LEN的值為止。此后,log_size將保持不變,而插入新字符將導致log_start的增長。

25878:請注意logged_chars(25658行)記錄從機器啟動之后由printk寫入的所有字符的長度,它在每次循環中都會被更新,而不是在循環結束后才改變一次。基于同樣的道理,log_start和log_size的處理方式也是一樣。這實際上是一種優化的時機,本書將在結束對函數的介紹之后再對它進行詳細討論。

25879:消息被分為若干行,這當然要使用新行標志符來進行分割。一旦內核檢測到新行標志符,就寫入一個完整行,從而內循環的執行也可以提前終止。25884:在這里我們先不考慮內部循環是否會提前退出,從msg到p的字符序列是專門提供給控制臺使用的(這種字符序列我稱之為行,但是不要忘了,這里的行可能并不意味著新行終止,因為buf也許還沒有終止)。如果該行的日志等級高于系統控制臺定義的日志等級,而且當前又有控制臺可供打印,那么就能夠正確打印該行。(記住,printk可能在所有控制臺打開之前就已經被調用過了。)

如果在該消息塊中沒有發現日志等級序列,并且在前面的printk調用中也沒有對msg_level賦值,那么本行中的msg_level就是-1。由于console_loglevel總不小于1(除非root通過sysctl接口鎖定),于是總是可以打印這些行。

25886:本行應該能夠被打印。printk通過遍歷打開的控制臺驅動鏈表告知每一個控制臺驅動去打印當前行設備驅動在本書的討論范圍之外,因此,控制臺驅動代碼則并不包含在內)。25888:請注意這里消息文本的開頭使用的是msg而不是p,這樣就在沒有日志等級序列的情況下寫入消息了。然而,日志等級序列已經被存儲到log_buf緩沖器中了。這樣就使后來能夠訪問log_buf以獲取消息日志等級的代碼(請參看25998行),不會再產生顯示混亂信息序列的現象。

25892:如果內層for循環發現一新行,那么buf中的剩余字符(如果有的話)將被認為是新的消息,因此msg_level會被重置。但是無論怎樣,外層循環都會持續到buf清空為止。25895:釋放在25845行獲取的控制臺鎖(console lock)。

25896:喚醒等待被寫入控制臺日志的所有進程。注意即使沒有文本被實際寫入任何控制臺,這個過程也仍然會發生。這樣處理是正確的,因為無論是否要往控制臺中寫入文本,等待進程實際上都是在等待從log_buf中讀出信息。在25748行,進程被轉入休眠狀態以等待log_buf的活動。在休眠、喚醒和等待隊列中所使用的機制將在下一節中進行討論。25897:返回日志中寫入的字符長度。

如果對于每個字符的處理工作都能減少一點,那么從25869行開始的for循環就執行得更快一點。當循環存在時,我們可以通過只在循環退出時將logged_chars更新一次來稍微提高運行速度。然而我們還可以通過其他努力來提高速度。由于我們可以預知消息的長度,因此log_size和log_start可以到最后再增長。讓我們來實驗一下這樣能否提高速度,下面是一段經過理想優化的代碼:

請注意循環通常只需要執行一次,只有在log_buf末尾寫入信息需要折行時才會多次執行。因而log_size和log_buf只需要更新一次(或者當寫入需要換行時是兩次)。

這時速度的確提高了,但是有兩個原因使我們并不能這樣做。首先,內核可能有自己特有的memcpy函數,我們必須確保對memcpy的調用不會再次進入對printk的調用(有一部分內核移植版定義了自己特有的速度較快的memcpy函數版本,因此所有的移植都要在這一點上保持一致)。如果memecpy調用printk來報告失敗,那么就有可能觸發無限循環。

然而在這一點上也并不是真的無藥可救。使用這種解決方案的最大問題在于該內核循環的形式中也要留意新行標志符,因此使用memcpy將整個消息拷貝到log_buf中是不正確的:如果此處存在新行,我們將無法對其進行處理。

我們可以試驗一個一箭雙雕的辦法。下面這種替代的嘗試雖然可能比前面那種初步解決方法速度要慢,但是它保持了內核版本的語意:

(請注意gcc的優化器十分靈敏,它足以能檢測到循環內部的表達式log_buf+LOG_BUF_LEN并沒有改變,因此在上面的循環中試圖手工加速計算是沒有任何效果的。)

不幸的是,這種方法并不能比現在的內核版本在速度上快許多,而且那樣會使得代碼晦澀難懂(如果你編寫過更新log_size和log_start的代碼,你就能清楚地了解這一點)。你可以自己決定這種折衷是否值得。然而無論怎樣,我們學到了一些東西,通常,不管成功與否,改進內核代碼都可以加深你對內核工作原理的理解。2.2.2 等待隊列

前一節我們曾簡要的提到進程(也就是正在運行的程序)可以轉入休眠狀態以等待某個特定事件,當該事件發生時這些進程能夠被再次喚醒。內核實現這一功能的技術要點是把等待隊列(wait queue)和每一個事件聯系起來。需要等待事件的進程在轉入休眠狀態后插入到隊列中。當事件發生之后,內核遍歷相應隊列,喚醒休眠的任務讓它投入運行狀態。任務負責將自己從等待隊列中清除。

等待隊列的功能強大得令人吃驚,它們被廣泛應用于整個內核中。更重要的是,實現等待隊列的代碼量并不大。1.wait_queue結構

18662:簡單的數據結構就是等待隊列節點,它包含兩個元素: ?task—指向struct task_struct結構的指針,它代表一個進程。從16325行開始的struct task_struct結構將在第7章中進行介紹。

?next—指向隊列中下一節點的指針。因而,等待隊列實際上是一個單鏈表。

通常,我們用指向等待隊列隊首的指針來表示等待隊列。例如,printk使用的等待隊列log_wait(25647行)。2.wait_event 16840:通過使用這個宏,內核代碼能夠使當前執行的進程在等待隊列wq中等待直至給定condition(可能是任何的表達式)得到滿足。

16842:如果條件已經為真,當前進程顯然也就無需等待了。16844:否則,進程必須等待給定條件轉變為真。這可以通過調用__wait_event來實現(16824行),我們將在下一節介紹它。由于__wait_event已經同wait_event分離,已知條件為假的部分內核代碼可以直接調用__wait_queue,而不用通過宏來進行冗余的(特別是在這些情況下)測試,實際上也沒有代碼會真正這樣處理。更為重要的是,如果條件已經為真,wait_event會跳過將進程插入等待隊列的代碼。

注意wait_event的主體是用一個比較特殊的結構封閉起來的:

奇怪的是,這個小技巧并沒有得到應有的重視。這里的主要思路是使被封閉的代碼能夠像一個單句一樣使用。考慮下面這個宏,該宏的目的是如果p是一個非空指針,則調用free: 除非你在如下所述的情況下使用FREE1,否則所有調用都是正確有效的: FREE1經擴展以后,else就和錯誤的if(FREE1的if)聯系在一起。有些程序員通過如下途徑解決這種問題:

這兩種方法都不盡人意,程序員在調用宏以后自然而然使用的分號會把擴展信息弄亂。以FREE2為例,在宏展開之后,為了使編譯器能更準確地識別,我們還需要進行一定的縮進調節,最終代碼如下所示:

這樣就會引起語法錯誤—else和任何一個if都不匹配。FREE3從本質上講也存在同樣的問題。而且在研究問題產生原因的同時,就能夠明白為什么宏體里是否包含if是無關緊要的。不管宏體內部內容如何,只要使用一組括號來指定宏體,就會碰到相同的問題。

引入do/while(0)技巧能夠克服前面所出現的所有問題,現在我們可以編寫FREE4。

將FREE4和其他宏一樣插入相同代碼之后,宏展開后其代碼如下所示(為清晰起見,我們再次調整了縮進格式):

這段代碼當然可以正確執行。編譯器能夠優化這個偽循環,舍棄循環控制,因此執行代碼并沒有速度的損失,我們也從而得到了能夠實現理想功能的宏。

雖然這是一個可以接受的解決方案,但是我們不能不提到的是編寫函數要比編寫宏好得多。不過如果你不能提供函數調用所需的開銷,那么就需要使用內聯函數。這種情況雖然在內核中經常出現,但是在其他地方就要少得多。(不可否認,當使用C++、gcc或者任何實現了將要出現的修正版ISO標準C的編譯器時,這種方案只是一種選擇,就是最后為C增加內聯函數。)

3.__wait_event 16824:__wait_event使當前進程在等待隊列wq中等待,直至condition為真。16829:通過調用add_wait_queue(16791行),局部變量__wait可以被鏈接到隊列上。注意__wait是在堆棧中而不是在內核堆中分配空間,這是內核中常用的一種技巧。在宏運行結束之前,__wait就已經被從等待隊列中移走了,因此等待隊列中指向它的指針總是有效的。16830:重復分配CPU給另一個進程直至條件滿足,這一點將在下面幾節中討論。16831:進程被置為TASK_UNINTERRUPTIBLE狀態(16190行)。這意味著進程處于休眠狀態,不應被喚醒,即使是信號也不能打斷該進程的休眠。信號在第6章中介紹,而進程狀態則在第7章中介紹。

16832:如果條件已經滿足,則可以退出循環。

請注意如果在第一次循環時條件就已經滿足,那么前面一行的賦值就浪費了(因為在循環結束之后進程狀態會立刻被再次賦值)。__wait_event假定宏開始執行時條件還沒有得到滿足。而且,這種對進程狀態變量state的延遲賦值也并沒有什么害處。在某些特殊情況下,這種方法還十分有益。例如當__wait_event開始執行時條件為假,但是在執行到16832行時就為真了。這種變化只有在為有關進程狀態的代碼計算condition變量值時才會出現問題。但是在代碼中這種情況我沒有發現。

16834:調用schedule(26686行,在第7章中討論)將CPU轉移給另一個進程。直到進程再次獲得CPU時,對schedule的調用才會返回。這種情況只有當等待隊列中的進程被喚醒時才會發生。

16836:進程已經退出了,因此條件必定已經得到了滿足。進程重置TASK_RUNNING的狀態(16188行),使其適合CPU運行。

16837:通過調用remove_wait_queue(16814行)將進程從等待隊列中移去。wait_event_interruptible和__wait_event_interruptible(分別參見16868行和16847)基本上與wait_event和__wait_event相同,但不同的是它們允許休眠的進程可以被信號中斷。信號將在第6章中介紹。

請注意wait_event是被如下結構所包含的。

和do/while(0)技巧一樣,這樣可以使被封閉起來的代碼能夠像一個單元一樣運行。這樣的封閉代碼就是一個獨立的表達式,而不是一個獨立的語句。也就是說,它可以求值以供其他更復雜的表達式使用。發生這種情況的原因主要在于一些不可移植的gcc特有代碼的存在。通過使用這類技巧,一個程序塊中的最后一個表達式的值將定義為整個程序塊的最終值。當在表達式中使用wait_event_interruptible時,執行宏體后賦__ret的值為宏體的值(參見16873行)。對于有Lisp背景知識的程序員來說,這是個很常見的概念。但是如果你僅僅了解一點C和其他一些相關的過程性程序設計語言,你可能就會覺得比較奇怪。__wake_up 26829:該函數用來喚醒等待隊列中正在休眠的進程。它由wake_up和wake_up_ interruptible調用(請分別參見16612行和16614行)。這些宏提供mode參數,只有狀態滿足mode所包含的狀態之一的進程才可能被喚醒。

26833:正如將在第10章中詳細討論的那樣,鎖(lock)是用來限制對資源的訪問,這在SMP邏輯單元中尤其重要,因為在這種情況下當一個CPU在修改某數據結構時,另一個CPU可能正在從該數據結構中讀取數據,或者也有可能兩個CPU同時對同一個數據結構進行修改,等等。在這種情況下,受保護的資源顯然是等待隊列。非常有趣的是所有的等待隊列都使用同一個鎖來保護。雖然這種方法要比為每一個等待隊列定義一個新鎖簡單得多,但是這就意味著SMP邏輯單元可能經常會發現自己正在等待一個實際上并不必須的鎖。

26838:本段代碼遍歷非空隊列,為隊列中正確狀態的每一個進程調用wake_up_process(26356行)。如前所述,進程(隊列節點)在此可能并沒有從隊列中移走。這在很大程度上是由于即使隊列中的進程正在被喚醒,它仍然可能希望繼續存在于等待隊列中,這一點正如我們在__wait_event中發現的問題一樣。2.2.3 內核模塊

整個內核并不需要同時裝入內存。應該確認,為保證系統能夠正常運行,一些特定的內核必須總是駐留在內存中,例如,進程調度代碼就必須常駐內存。但是內核其他部分,例如大部分的設備驅動就應該僅在內核需要的時候才裝載,而在其他情況下則無需占用內存。

舉例來說,只有在內核真正和CD-ROM通訊時才需要使用完成內核與CD-ROM通訊的設備驅動程序,因此內核可以被設置為在和設備通訊之前才裝載相應代碼。內核完成和設備的通訊之后可以將這部分代碼丟棄。也就是說,一旦代碼不再需要,就可以從內存中移走。系統運行過程中可以增減的這部分內核稱為內核模塊。內核模塊的優點是可以簡化內核自身的開發。假設你購買了一個新的高速CD-ROM驅動器,但是現有的CD-ROM驅動程序并不支持該設備。你自然就希望增加對這種高速模式的支持以提高系統光驅設備的性能。如果作為內核模塊來編譯驅動程序,你的工作將會方便得多:編譯驅動程序、加載到內核、測試、卸載驅動程序、修改驅動程序、再次加載驅動程序到內核、測試,如此周而復始。如果你的驅動程序是直接編輯在內核中的,那么你就必須重新編譯整個內核并且在每次修改驅動程序之后重新啟動機器。這樣慢得很多。

自然,你也必須留意內核模塊。對于指明其他內核模塊在磁盤上的駐留位置的那些模塊,一定不能從內存中卸載,否則,內核將只能通過訪問磁盤來裝載處理磁盤訪問的內核模塊,這是不可能實現的。這也是我們要選擇把部分內核作為模塊編譯還是直接編譯進內核使其常駐內存的又一個原因。知道自己系統的設置方式,因而也就可以選擇正確使用的方式(如果為了確保安全,可以簡單的忽略內核模塊系統的優點,而把所有的內容都編譯到內核里面)。內核模塊會帶來一些速度上的損失,這是因為一些必需的代碼現在并不在RAM中,必需要從磁盤讀入。但是整個系統的性能通常會有所提高,這主要是因為通過丟棄暫時不使用的模塊可以釋放出額外的RAM供應用程序使用。如果這部分內存被內核所占用,應用程序將只能更加頻繁地進行磁盤交換,而這種磁盤交換會顯著地降低應用程序的性能(磁盤交換將在第8章中討論)。

內核模塊還會帶來因復雜度的增加所造成的開銷,這是因為在系統運行的過程中,移進移出部分內核需要額外的代碼。然而,復雜度的開銷是可以管理的。通過使用外部程序來代理一些必需的工作還可以更進一步降低復雜度的開銷(更為確切的說法是,這樣做不是減少了復雜度的開銷,而是把復雜度的開銷重新分配了一下)。這是對內核模塊原理的一個小小的擴展:即使是內核的支持模塊,對于內核來說也只是外部的、部分可用的,只有在需要的時候才被裝入內存。

通常用于這種目的程序稱為modprobe。有關的modprobe代碼超出了本書的范圍,但是在Linux的每個發行版本中都包含有它。本節的剩余部分將討論同modprobe協同工作,以裝載內核模塊的內核代碼。1.request_module 24432:作為函數說明之前的注釋,request_module是一個函數。內核的其他模塊在需要裝載其他內核模塊的時候,都必須調用這個函數。就像內核處理其他工作一樣,這種調用也是為當前運行的進程進行的。從進程的角度來看,這種調用的請求通常是隱含的—正在執行進程其他請求的內核可能會發現,必須調入一個模塊才能夠完成該請求。例如,請參見10070行,這里是一些將在第7章中討論的代碼。

24446:以內核中的一個獨立進程的形式執行exec_modprobe函數(24384行)。這并不能只通過函數的簡單調用實現,因為exec_modprobe要繼續調用exec來執行一個程序。因此,對函數exec_modprobe的簡單調用將永遠不會有返回。

這和使用fork以準備exec調用十分類似,你可以認為kernel_thread對內核來說就是較低版本的fork,雖然兩者有很大不同。fork是從指定函數開始執行新的進程,而不是從調用者的當前位置開始運行。正如fork一樣,kernel_thread返回的值是新進程的進程號。24448:和fork一樣,從kernel_thread返回的負值表示內部錯誤。

24455:正如函數中論述的一樣,大部分的信號將因當前進程而被暫時阻塞。

24462:等待exec_modprobe執行完畢,同時指出所需要的模塊是已經成功裝入內存,還是裝載失敗了。

24465:結束運行,恢復信號。如果exec_modprobe返回錯誤代碼,則打印錯誤消息。2.exec_modprobe 24384:exec_modprobe運行為內核增加內核模塊的程序。這里的模塊名是一個void*的指針,而不是char*的指針。原因簡單說來就是kernel_thread 產生的函數通常都使用void*指針參數。

24386:設置modprobe的參數列表和環境。modprobe_path(24363行)用來定位modprobe程序的位置。它可以通過內核的sysctl特性來修改,這一點將在第11章中介紹(參見30388行)。這意味著root可以動態選擇不同于/sbin/modprobe的程序來運行,以適應當modprobe被安裝到其他地方或者使用修改過的modprobe替換掉了原有的modprobe之類的情況。24400:(正如代碼中描述的一樣)出于安全性考慮,丟棄所有掛起的信號和信號句柄(handl-ers)。這里最重要的部分是對flush_signal_handlers的調用(28041行),它使用內核默認的信號句柄代替所有用戶定義的信號句柄。如果在此時有信號被傳送到內核,它將獲得默認響應—通常是忽略信號或殺死進程。但是不管怎樣都不會引起安全風險。由于該函數從觸發它的進程中分離出來(如前所述),所以,不管原始進程在此處是否改變其原來分配的信號,句柄都不會產生任何影響。

24405:關閉調用進程打開的所有文件。最重要的是,這意味著modprobe程序不再從調用進程中繼承標準輸入輸出和標準錯誤。這很有可能會引起安全漏洞(這可能是在替代modprobe的程序中引起的問題,但是modprobe本身實際上并不關心這個差異)。

24413:modprobe程序作為root運行,它擁有root所擁有的所有權限。和整個內核中其他地方一樣,請注意root使用用戶ID號0的假定在這里已經被寫入程序。用戶ID號和權能系統(capability system,在接下來的幾行中會用到)將在第7章中介紹。

24421:試圖執行modprobe程序。如果嘗試失敗,內核將使用printk打印錯誤消息并返回錯誤代碼。這里是可能產生printk的緩沖器過載的地點之一。module_name的長度并沒有明確限制,就我們對該調用的看法而言,它可能長達一百萬個字符。為防止printk緩沖器過載,你必需遍歷所有對于該函數的調用(實際上是對request_module的調用),以保證每個調用者使用足夠短的、不會為printk造成麻煩的模塊名。

24427:當execve成功執行時,它不會返回任何結果,因此本處是不可能執行到的。但是編譯器卻并不知道這一點,因此,此處使用了return語句以保證gcc不出錯。

對于內核的進一步討論將超出本章的既定范圍,因此在這個問題上我們到此為止。然而本書中也包括了其他必需的內核代碼。在讀完第4章和第5章之后,也許你會希望再次仔細研讀一下這部分內容。有關這個問題的兩個文件是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行)四個函數需要特別注意一樣,struct module(15581行)也要特別引起注意。這些函數實現了modprobe及insmod、lsmod和rmmod所使用的系統調用,以完成模塊的裝載、定位和卸載。

內核觸發直接回調內核程序的現象看起來很令人奇怪。但是,實際上進行的工作不止于此。例如,modprobe必須實際訪問磁盤以搜尋要裝載的模塊。而且更為重要的一點是,這種方法賦予root對內核模塊系統更多的控制能力。這主要是因為root也可以運行modprobe及相關程序。因此,root既可以手工裝載、查詢、卸載模塊,也可以由內核自動完成。2.3 配置與編譯內核

你可能僅僅研讀、欣賞而并不修改Linux內核源代碼。但是,更普遍的情況是,用戶有強烈的愿望去改進內核代碼并完成相應的測試,這樣我們就需要知道如何重建內核。本節就是要告訴你如何實現這一點,而最終則歸結于如何把你所做的修改發行給別人,以使得每個人都能從你的工作中受益。2.3.1 配置內核

編譯內核的第一步就是配置內核,這是增加或者減少對內核特性的支持及修改內核的一些特性的必要步驟。例如,你可以要求內核為自己的聲卡指定一個不同的DMA通道。如果內核配置和你的需要相同,那么你可以直接跳過本節,否則請繼續閱讀以下內容。為了完成內核的配置,請先切換到root用戶,然后轉入如下內核源程序目錄: cd /usr/src/linux 接著敲入如下命令組: make config make menuconfig make xconfig 這三條命令都可以用來配置內核,但它們發揮作用的方式各不相同:

?make config—三種方法中最簡單也是最枯燥的一種。但是最基本的一點是,它可以適應任何情況。通過為每一個內核支持的特性向用戶提問的方式來決定在內核中需要包含哪些特性。對于大多數問題,你只要回答y(yes,把該特性編譯進內核中)、m(作為模塊編譯)或者n(no,根本不對該特性提供支持)。在決定之前用戶應該考慮清楚,因為這個過程是不可逆的。如果你在該過程中犯了錯誤,就只能按Ctrl+C退出。你也可以敲入?以獲取幫助。圖2-1顯示了這種方法在X終端上運行的情況。圖2-1 運行中的make config 幸運的是,這種方法還有一些智能。例如,如果你對SCSI支持回答no,那么系統就不會再詢問你有關SCSI的細節問題了。而且你可以只按回車鍵以接受默認的選擇,也就是當前的設置(因此,如果當前內核將對于SCSI的支持編譯進了內核,在這個問題上按回車鍵就意味著繼續把對SCSI的支持編譯進內核中)。即使是這樣,大部分用戶還是寧愿使用另外的兩種方法。

?make menuconfig—一種基于終端的配置機制,用戶擁有通過移動光標來進行瀏覽等功能。圖2-2顯示了在X終端上運行的make menuconfig。雖然在控制臺上顯示的是彩色,但是在終端上的顯示仍然相當單調。使用menuconfig必須要有相應的ncurses類庫。圖2-2 運行中的make menuconfig ?make xconfig—這是我最喜歡的一種配置方式。只有你能夠在X server上用root用戶身份運行X應用程序時,這種配置方式才可以使用(有些偏執的用戶就不愿意使用這種方式)。你還必須擁有Tcl窗口系統,這實際上還意味著你必須擁有Tcl、Tk以及一個正在運行的X安裝程序。作為補償,用戶獲得的是更漂亮的、基于X系統的以及和menuconfig功能相同的配置方法。圖2-3顯示了在這種方法運行過程中打開“可裝載模塊支持(Loadable module support)”子窗口的情況。

圖2-3 運行中的make xconfig 如上所述,這三種方法都實現了相同的功能:它們都生成在構建內核時使用的.config文件。而唯一的區別在于創建這個文件時的難易程度不同。2.3.2 構建內核

構建內核要做的工作要比配置內核所做的工作少得多。雖然有幾種方式都能實現這一功能,但是選擇哪一種依賴于你希望怎樣對系統進行設置。長期以來,我已經形成了如下的習慣。雖然這種習慣比我所必須要做的略微多一些,但是它包含了所有基本的問題。首先,如果你還不在內核源程序目錄中,請先再次轉入這一目錄: cd /usr/src/linux 現在,切換到root用戶,使用下面顯示的命令生成內核。現在在shell中敲入下面的命令,注意make命令因為空間關系分成了兩行,但實際上這在shell輸入時是一個只有一行的命令: make dep clean zlilo boot modules modules_install 當給出了如上多個目標時,除非前面所有的目標都成功了,否則make能夠知道沒有必要繼續嘗試下面的目標。因此,如果make能夠運行結束,成功退出,那么這就意味著所有的目標都正確構建了。現在你可以重新啟動機器以運行新的內核。2.3.3 備份的重要性

當修改(fooling)內核時,你必須準備一個能夠啟動的備用內核。實現該目的的一種方式是通過配置Linux加載程序(LILO)以允許用戶選擇啟動的內核映象,其中之一是從沒有修改過的內核的備份(我總是這樣做的)。

如果你比較有耐心,那么你就可以使用zdisk目標而不使用zlilo目標;它可以把能夠啟動的內核映象寫入軟盤中。這樣你就可以通過在啟動時插入軟盤的方式啟動你的測試內核;如果沒有插入軟盤,則啟動正常的內核。

但是請注意:內核模塊并沒有被裝載到軟盤中,它們實際上是裝在硬盤中的(除非你愿意承擔更多的麻煩)。因此,如果你弄亂了內核模塊,即使是zdisk目標也救不了你。實際上,上面提到的這兩種方法都存在這個問題。雖然有比較好的解決方法可用,但是最簡單的方法(也就是我所使用的方法)是把備份內核作為嚴格獨立的內核來編譯,而不使用可裝載模塊的支持。通過這種方法,即使我弄亂了內核而不得不使用備份啟動系統,那么不管問題是實驗性內核不正確還是內核模塊的原因都無關緊要。不管怎樣,在備份的內核中已經有我需要的所有東西了。

由于用戶所做的修改可能導致系統的崩潰,如損壞磁盤上的數據等等,并不僅僅只是打亂設備驅動程序或文件系統,在測試新內核之前,備份系統的最新數據也是一個英明的決策(雖然設備驅動程序的開發不是本書的主題,但是必需指出的是,設備驅動程序的缺陷可能會引起系統的物理損壞。例如顯示器是不能備份的,而且因價格昂貴而不易替換)。作為一個潛在的內核黑客,你的最佳投資(當然是讀過本書以后)是一個磁帶驅動器和充足的磁帶。2.3.4 發布你的改進

下面是有關發布你所做修改的一些基本規則:

?檢查最新發行版本,確保你所處理的不是已經解決了的問題。

?遵守Linux 內核代碼編寫的風格。簡要的說就是8字符縮進以及K&R括號風格(if,else,for,while,switch或者do后面同一行中緊跟著開括號)。在內核源程序目錄下面的文檔編寫和代碼風格文件給出了完整的規則,不過我們已經介紹了其中的關鍵部分。注意本書中包含的源程序代碼為節省空間而進行了大量的重新編輯,在該過程中我可能打破了其中的一些規則。

?獨立發行相對無關的修改。這樣,只想使用你所做的某部分修改的人就可以十分方便地獲得想要的東西,而不用一次檢驗所有的修改內容。

?讓使用你所做修改的用戶清楚他們可以從你的修改中獲取什么。同樣,你也應該給出這些問題的可信度。你是15min之前才匆匆完成你的修改,甚至還沒有時間對它們進行編譯,還是已經在你和你的朋友的系統中已長期穩定地運行過這個修改?

假設現在你已經準備好發行自己的修改版本了,那么要做的第一步是建立一個說明你所做的修改的文件。你可以使用diff程序自動創建這個文件。結果或者被稱為diffs,或者在Linux中更普遍的被稱為補丁(patch)。

發布的過程十分簡單。假設原來沒有修改過的源程序代碼在linux-2.2.5目錄下,而你修改過的源程序代碼在linux-my目錄下,那么只要進行如下的簡單工作就可以了(只有在鏈接不存在的情況下才需要執行ln):

現在,輸出文件my.patch包含了其他用戶應用這個修改程序時所需要的一切內容。(警告:如上所述,兩個源程序間的所有差別都會包含在這個補丁文件中。diff不能區分修改部分之間的關系,所以就把它們都羅列了出來。)如果補丁文件相對較小,你可以使用郵件直接發往內核郵件列表。如果補丁很大,那么就需要通過FTP或者Web站點發布。這時發給郵件列表的信件中就只需要包含一個URL。Linux內核郵件列表的常見問題解答(FAQ)文件位于http://www.tmdps.cn。

阿道夫 的 范德薩 啊訂單式

第二篇:關于分析今天長安保定百度愛問愛學位論文寫作方法學位論文.

的的范德薩的地方愛的規格愛你啊好文章梁慧星:學位論文寫作方法(2):

學位論文的結構

三、學位論文的結構

答辯委員會成員或委員會外的專家對碩士、博士論文作鑒定、寫評語,有一個內容是就論文結構表態。一篇合格的學位論文,要求結構合理。肯定的評語是:本文結構合理、邏輯嚴謹、層次清晰。什么叫“結構合理”?結構合理就是指論文的“層次清晰”、“邏輯嚴密”。這就要求了解論文的一般結構,這里注重講碩士論文、博士論文的結構。

學術論文的結構:

目錄

序言

導論

本論

結論

參考文獻目錄

后記

上述結構中,導論、本論、結論三部分構成論文的本體;目錄、序言、參考文獻目錄和后記,是附屬部分。最重要的當然是本體。一篇完整的學位論文,其本體由導論、本論、結論三部分構成。有沒有特殊的,有特殊的,所謂特殊,無非是在一般結構基礎上省略了其中的某個部分,或者省略結論,或者省略導論,但無論如何不能省略本論。如果以重要性為標準進行劃分,則導論和結論屬于組成部分,本論屬于本質部分。例如一個人,頭和軀干是本質部分,四肢是組成部分。沒有手臂,甚至手腳都沒有,不影響人這個事物的存在,仍然是人;但沒有頭和軀干,光有四肢就不成其為人。同理,省略了導論、結論,不影響學術論文的本質,但學術論文的完整性大大受到損害,專家作鑒定會寫上一句:結構不完整。當然,學術論文不可能沒有本論,假設沒有本論,就不成其為學術論文。

可見,本論部分特別重要,答辯委員會成員評價學位論文結構合理不合理,注重的是本論部分。

下面對各部分作簡要說明:

(一)導論

導論起什么作用?導論的作用在于引起讀者的閱讀興趣。讀者拿到一篇學術論文,通常好多萬字、二三十萬字,是否值得花費寶貴的時間,光看題目還難以判斷,總是首先讀導論,希望從導論的內容判斷本文是否有閱讀價值,是否值得花費時間閱讀。

導論的內容,通常是交待課題,本文究竟要研究一個什么課題,這個課題的產生背景,說明作者為什么要研究這個課題,它有什么理論意義和現實意義。如果是博士論文,通常還要交待所采用的研究方法,交待論文的大體結構。

實例1:

博士論文:合同自由與公序良俗

第一章 導論

(一)選題背景及意義

(二)研究狀況和文獻綜述

(三)研究方法和主要內容

實例2:

博士論文:國際貨物貿易中的補貼與反補貼法律問題研究

導論

(一)本文研究的目的和意義

(二)本文研究范圍

(三)素材選取與研究方法

(四)體例安排

(二)結論

學術論文應當有結論,是學術研究的規律性決定的。學術研究是一個過程,有其始端和終端。導論是始端,結論是終端。結論表明一項科學研究的結束。同時,一項研究當有其研究結果。最終得到一個什么研究結果,應當在結論部分作出概括。如果還有遺留問題沒有解決,也應在結論部分指出。

從學位論文答辯的角度講,論文要經專家鑒定,寫出評語。答辯委員會成員也要審讀論文,寫出評語。考慮到一篇博士學位論文通常二十多萬字,甚至三十多萬字,專家教授通常不可能一口氣讀完。總是讀幾頁,放下了,又讀幾頁,有什么事情又放下了。經過好多次才斷續讀完,讀到末尾,前面的內容已經模糊、記不清了。不可否認,有的評定人因時間關系不可能讀完全文,閱讀了導論部分,翻閱、選讀幾個章節,然后就寫評語。如果有一個結論,概括本文的研究結果、作者的基本學術見解、本研究結果的理論意義和實踐價值,對于審定人作出總的評價有莫大的幫助。這對于論文最后能否通過答辯,有極重大的意義。切不可掉以輕心!

實例:

博士論文:合同自由與公序良俗

第六章 結論

(一)總結

(二)論文的基本觀點

(三)論文的主要創新點

(四)論文的局限和不足

有的學位論文以立法建議代替結論,這大抵屬于制度型選題,研究某一項法律制度,研究最后得到的基本學術見解或結論,表現為建議我國立法機關制定某一法律或對現行法作修改,并形成了立法或修改的基本設想甚至條文草案。另外,也有以結束語代替結論的。以立法建議代替結論,以結束語代替結論,不等于沒有結論。省略結論,影響論文結構的完整性,完整性是合理性的一個方面,因此沒有結論將影響論文結構的合理性。

(三)本論

本論是一篇學位論文的本質部分,沒有本論就不成其為一篇論文。就象沒有頭和軀干不能成其為人一樣。本論的內容是研究過程的反映,應當寫什么,自然不用我在這里說。這里只是介紹本論部分的結構安排。評價一篇論文的結構是否合理,主要是針對本論部分的結構是否合理。

1、本論部分的結構

大體上有五種:

總分結構

三分結構

四分結構

編章結構

章節結構

總分結構,實際是分為兩個部分,稱為總論與分論。實際上,是哲學上的“一般”與“特殊”、“共性”與“個性”的關系。有關本課題的一般理論、共同理論,在總論部分;然后分別研究本課題內部各特殊部分或特殊問題,叫做分論。實際是“二分結構”:總論、分論。然后總論再分為若干部分(章),分論再分若干部分(章)。如果將總論、分論作為兩編,每編下分若干章,這就是“二分結構”加“編章結構”。有的博士論文,在總論、分論之前再設緒論,研究本課題的前提性的問題,作為另一個部分,稱為緒論編,包括若干章。這樣就變成“三分結構”加“編章結構”。可以說幾乎所有的選題,都有總論與分論的劃分,都可采用“二分結構”加“編章結構”。但是,如果屬于一般理論、共同理論的內容太少,不足以再分為若干章,就會出現這樣的情況:總論編只有一章,分論編包括若干章,顯得不協調、不成比例。因此可不設編,直接采用“章節結構”,第一章實際是總論,從第二章起實際是分論。下面舉一些實例。

采“四分結構”的實例:

蔣新苗的博士論文:國際收養法律制度研究 第一編 導論,包括第一、二章;

第二編 國際收養中的國際私法問題,包括第三、四章;

第三編 國際收養法的統一化進程,包括第五、六章;

第四編 中國與國際收養法統一化進程,包括第七、八、九章。

須說明的是,第一編導論,內容實際是緒論。緒論是本論的一部,導論不是本論的一部。本文省略了結論。

采“三分結構”的實例1:

傅靜坤的博士后論文:契約沖突法論

第一部分 契約沖突法的基本原則和規范,包括第一、二章;

第二部分 統一國際契約實體法與統一國際契約沖突法,包括第三、四章;

第三部分 區際契約沖突法,包括第五章。

(本文省略了結論)

采“三分結構”的實例2:

沈涓的博士論文:中國區際沖突法研究

第一編 中國區際沖突法的歷史與現狀,包括第一至三章;

第二編 中國區際沖突法的方法與規則,包括第四至五章;

第三編 中國區際法律關系沖突的調整,包括第六至十一章。

(本文省略結論)

2、總分結構

這種結構最為常見,通常先劃分為總論與分論兩大部分,然后各部分再分若干章;或設總論編、分論編,然后各編再分若干章;或不設編,總論作為第一章,分論分為若干章。實際是總分結構加編章結構。多數博士論文、碩士論文采用這樣的結構。

實例:

肖厚國的博士論文:物權變動研究

(導論)

第一章 物權變動的基本理論

第二章 物權變動的立法主義

(一)第三章 物權變動的立法主義

(二)第四章 不動產物權變動的公示

(一)第五章 不動產物權變動的公示

(二)第六章 動產物權變動

第七章 善意取得 第八章 取得時效

(結束語)

本論實際上分為“總論”與“分論”兩大部分,“總論”再分為“物權變動的基本理論”(第一章)與“物權變動的立法主義”(第二、三章)兩部分;“分論”分為“積極的物權變動”與“消極的物權變動”兩部分,其中“積極的物權變動”,再分為“不動產物權變動”(第四、五章)與“動產物權變動”(第六章)兩部分;“消極的物權變動”,再分為“善意取得”(第七章)與“取得時效”(第八章)兩部分。屬于典型的“總分結構+章節結構”。

不合理的結構:

如果本論分為兩大塊,下面不再劃分章節,或者本論僅有兩章,屬于單純的二分結構,應當認為結構不合理。為什么這樣的結構不合理?首先是不合習慣。其次是美學上的考慮。一篇論文,前面一個序言,后面一個結語,本論部分就兩章,第一章、第二章。如果序言、結語都省略了,一篇論文就兩塊,第一部分,第二部分,或者第一章、第二章,這不好看。要進一步追問為什么?也難以回答。可能是太呆板。下面舉實例。

實例1:

碩士論文題目:作者精神權利性質探討

第一部分 概述

第二部分 作者精神權利性質探討

論文前面沒有導言,后面沒有結論,本論就兩部分,很不合理。

實例2:

一篇碩士論文

序言

第一章

第二章

結語

前有一個序言,后有一個簡短的結語,中間本論部分就兩章,屬于結構不合理。

3、關于切題

關于本論的結構,無論采取哪一種結構模式,其共同的要求是:緊扣題目,亦即我們平常所謂“切題”。這主要從每部分的標題來體現。

從上引博士論文的結構,我們看到,每一個標題,都緊扣住題目。如物權變動研究一文,第一至第六章的標題都有“物權變動”一語,第七、八兩章的標題雖然沒有“物權變動”四個字,但“善意取得”和“取得時效”是物權變動的具體形式。可見,所謂切題,所謂緊扣題目,往往通過在本論各部分標題中“反復出現”論文題目中的“關鍵詞語”來體現。反之,如果本論各標題與論文題目無關,找不到論文題目的關鍵詞語,我們就會覺得不切題,沒有緊扣題目。下面舉例。

實例1:

博士論文題目:論私法對國際法的影響

第一章 萬民法與國際法

第二章 人或主體

第三章 領土主權與所有權

第四章 條約與契約

評論:

在各部分標題中,沒有出現論文題目中的關鍵詞語“私法”和“國際法”。從各部分的標題,讀者很難理解該部分內容與題目間是否有密切的關聯。這就是沒有緊扣題目,或者說不切題。

實例2:

博士論文題目:現代商人法研究

其本論分三章:

第二章 現代商人法產生和發展的歷史過程

第三章 現代商人法的適用及其法律效力

第四章 現代商人法與沖突法及國際仲裁法的完善和發展

評論:

題目中的關鍵詞語是“現代商人法”,我們看到本論部分每一個標題都重復“現代商人法”一語,使讀者覺得各部分內容與題目的關系非常緊密,扣得很緊,這就叫“切題”。

4、小結

從上述本論部分的結構安排,我們可以看到,博士論文采用總分結構加編章結構,或者采用章節結構的最常見,這類結構安排系以“章”為單位,碩士論文也以章節結構最常見,也有的用“部分”為單位,“部分”下面以一、二、三、四為序。是否可以作出這樣一個判斷:

無論以“章”或“部分”為單位,本論部分所劃分的單位至少應在三個以上,例如不少于三章或三個部分。否則,就叫結構不合理。

5、邏輯關系 以上僅指對結構安排的形式要求。在此基礎上,還有對邏輯性的要求。指本論部分的結構安排要具有一定的邏輯關系。大體有下面三種邏輯關系:

第一種 總分關系

第二種 并立關系

第三種 遞進關系

第一種:總分關系

關于本課題的一般性問題、一般理論、基本理論、基本原則的內容,屬于總論。特殊問題、特殊理論、具體制度、具體問題、構成條件、實際運用等內容,屬于分論。總論與分論之間,是一般與個別、普遍與特殊的關系,通常總論部分應當在前,分論部分應當在后。無論采用總分結構或者編章結構、章節結構,都要求總論與分論有清晰的界限,不能混淆,總論內容寫完再安排分論,分論部分不能插入總論的內容,不能顛倒順序,一般不能先分論后總論,應當先總論后分論。

其規則是:先總、后分。

第二種:并列關系

如果采用總分結構,總論部分與分論部分,已具有并列的意義,總論下面的各章、分論下面的各章,也可以是并列的關系,即各章的內容應當處在同一層次。采用編章結構,各編的內容可以是并列的關系,例如緒論編、總論編、分論編,編下面的各章可以是并列關系。

其規則是:位階同一

實例1:

肖厚國的博士論文:物權變動研究

第一章 物權變動的基本理論

第二章 物權變動的立法主義

(一)第三章 物權變動的立法主義

(二)第四章 不動產物權變動的公示

(一)第五章 不動產物權變動的公示

(二)第六章 動產物權變動

第七章 善意取得

第八章 取得時效

其結構屬于典型的并列關系,而且是多層次的并列關系。第一個層次是總論(第1、2、3章)與分論(第4、5、6、7、8章)的并列;第二個層次是總論下面物權變動的基本理論(第1章)與物權變動的立法主義(第2、3章)的并列,分論下面積極的物權變動(第4、5、6章)與消極的物權變動(第7、8章)的并列;第三個層次是不動產物權變動(第4、5章)、動產物權變動(第6章)、善意取得(第7章)、取得時效(第8章)的并列。

實例2:

楊松的博士論文:國際貨幣基金協定研究

本論分五章:

第四章 國際收支平衡的法律制度研究

第五章 國際儲備的法律制度研究

第六章 匯兌安排國際法律制度研究

第七章 外匯管制法律問題研究

第八章 基金協定的監督與磋商機制研究

其結構也屬于典型的并列關系。

第三種:遞進關系

采編章結構,在一編之下的各章可以是遞進關系。采章節結構,各章之間也可以是遞進關系。章下面的節,也可以是遞進關系。就一篇博士論文而言,可能各編之間是并列關系,各編下面的章是遞進關系,或者總論編下面的各章是并列關系,分論編下面各章是遞進關系。或者采總分結構不設編,總論僅一章,從第二章開始是分論,分論各章是遞進關系。至于章下面的各節之間的關系,當然可以某些章下面的各節之間是并列關系,某些章下面的各節之間是遞進關系。

這里有一個要求,某編下面的各章,或者某章下面的各節,如果采遞進關系,就一定是遞進關系,不能混淆。不能出現這樣的情況,一編有五章,其中一、二、三、五章顯然是遞進關系,中間第四章與各章不構成遞進關系,或者一章下面若干節,其中幾節似乎是遞進關系,中間又有幾節似乎是并列關系。

遞進關系有三種不同形態:

時間上的遞進關系

空間上的遞進關系

純粹邏輯上的遞進關系

(1)時間上的遞進關系

時間上的遞進關系,是指在時間上由遠到近,先從該制度的歷史說起,從古羅馬法說起,中世紀有什么變化,近代有何發展,直到現在的現狀,實際是采歷史研究方法。法制史研究論文,大體體現這樣的遞進關系。在部門法,例如民法碩士、博士論文中,也常常采用歷史研究方法,因此在論文的某個部分會反映時間上的遞進關系,通常在緒論或總論部分,或者某一章下面的節,不大可能一篇民法論文各章之間都反映時間上的遞進關系。

這種遞進關系,要求嚴格按照時間的先后順序,如果出現時間先后順序的錯亂,就叫層次不清、邏輯混亂。

其規則是:時間愈早愈在前,時間愈近愈在后。

(2)空間上的遞進關系

此所謂“空間”實際上包括兩種情形:一是地域上的空間;一是抽象的空間。無論屬于地域上的空間,或者抽象的空間,都要求“由外到內”,先討論外部的問題,后討論內部的問題。先研究外國的制度、發展、經驗教訓,再討論本國的制度、發展、構成、適用、存在問題及對策等;或者先討論該制度的外部關系,產生原因、背景、哲學思想、政策取向、功能等,然后進入該制度內部,討論其構成要件、法律效果、解釋適用等。

空間上的遞進關系,要求區分內外,先外后內。如果外部問題未討論完就進入內部問題的討論,中途再反過來討論外部問題,或者一開始討論本國制度,中間突然插入外國制度的探討,然后再回到本國制度的研究,就叫層次不清、邏輯混亂。

其規則是:先外、后內。

(3)純粹邏輯上的遞進關系

所謂純粹邏輯上的遞進關系,是指在邏輯上由抽象到具體。先從概念、定義說起,解釋其含義,探討其內涵、外延,確定其適用范圍,分析適用條件、法律效果。通常采用法律解釋學的研究方法,就反映這種遞進關系。要求符合從抽象到具體的邏輯順序,愈抽象的問題愈在前,愈具體的問題愈在后,否則就叫層次不清、邏輯混亂。

其規則是:愈抽象愈在前,愈具體愈在后。

實例:

碩士論文:最高額抵押權研究

第一部分 最高額抵押權的意義

第二部分 最高額抵押權的歷史演進

第三部分 最高額抵押權的設定

第四部分 最高額抵押權的效力

第五部分 最高額抵押權的確定

第六部分 最高額抵押權的消滅

其第一、二部分屬于總論;第三至第六部分屬于分論。其分論的結構顯然符合純粹邏輯的遞進關系。須注意的是,在一篇論文中,尤其是長篇專題研究論文、碩士論文、博士論文,不是只反映一種遞進關系形態,可能某一編、某一章內部是時間上的遞進關系,另外的編、章內部是邏輯上的遞進關系。

關于本論部分的邏輯關系,還有一個要求是要有重點,避免等分式、無重點、面面俱到和過分枝蔓。我上研究生的時候,研究生院院長溫濟澤教授作報告,講到學術論文寫作多次引用前人的詩句:“刪繁就簡三秋樹,領異標新二月花”。前一句就是指,文章的結構,要避免過分枝蔓,要突出重點。

下面舉不合邏輯的實例:

實例1:

碩士論文:著作權若干問題研究

一、著作權的成因、發展和不同制度比較;

二、我國著作權制度的歷史、現狀和立法構想;

三、著作權若干問題的具體探究。

評論:

問題在于邏輯關系混亂,第一部分的成因、發展、不同制度比較與第二部分的歷史、現狀是重復的;立法構想應該在整個研究完成之后提出,卻安排在第二部分,全部研究未完成,尤其對著作權的若干基本問題還未研究清楚,就提出立法構想,也不合邏輯。

實例2:

碩士論文:論新聞侵權為題的碩士論文

第一章 新聞侵權概述

第二章 新聞侵害名譽權的民事責任

第三章 新聞侵害隱私權的民事責任

第四章 新聞侵害肖像權的民事責任

第五章 新聞侵權民事責任主體

第六章 新聞侵權損害的救濟方式

評論:

問題在于總分顛倒,第二、三、四章屬于分論,卻安排在前面,第五章新聞侵權的責任主體和第六章救濟方式應當屬于總論,卻安排在后面。

實例3:

碩士論文:論企業集團的法律地位

一、企業集團產生的客觀必然性;

二、企業集團的概念;

三、企業集團的類型及其規范化;

四、企業集團的法律地位是由其內外關系決定的;

五、問題與對策。

評論:

問題是各部分邏輯關系混亂。連什么是企業集團都未介紹,一開頭就講客觀必然性,不合思維習慣和邏輯。思維習慣和邏輯是,先講“是什么”,再講“為什么”。概念屬于“是什么”,本應當在前面,卻安排在第二部分。客觀必然性屬于“為什么”,本應當在后面。第四部分是一個完整的句子,與標題不合,標題不能是句子,再說也與其他部分不協調。

實例4:

碩士論文:論時效制度

一、對時效制度的歷史考察

二、關于消滅時效效力的探討

三、我國民法是否需要設立取得時效制度

四、對完善我國民法時效制度的設想

五、時效完成后義務人的履行

六、除斥期間

評論:

同樣邏輯混亂,第三、四部分交叉、重復,層次不清,第六部分除斥期間屬于課題之外的問題。

實例5:

碩士論文:論民法的締約過失責任

一、締約過失責任的由來

二、締約過失責任的幾個基本理論問題

三、英美法系的締約過失責任――非合同義務

四、締約過失責任的新發展與合同預備性文件的效力

五、我國締約過失責任的理論與實踐

評論:

存在的問題是邏輯混亂:“締約過失責任”是否包括英美法系的締約過失責任?如果回答是肯定的,則何以單獨論及英美法系的締約過失責任,而未專門論及大陸法系的締約過失責任?如果回答是否定的,即締約過失責任僅指大陸法系的制度,則何以在研究過程的中間,突然提出英美法系的締約過失責任問題?

實例6: 碩士論文:保證責任研究

一、保證責任的成立;

二、保證責任的性質;

三、保證責任的范圍;

四、保證責任的方式;

五、保證責任的期間;

六、保證責任的消滅。

評論:

相對而言,成立、范圍、方式、期間、消滅都是具體的,唯性質是抽象的。而將性質安排在成立之后、范圍等之前,違背了“愈抽象愈在前”的規則,造成邏輯混亂。如果在前面設一個部分:保證責任概述,在其中論及責任性質,就合乎邏輯了。

實例7:

碩士論文:融資性租賃合同研究

一、融資性租賃合同的概念及特征;

二、融資性租賃合同的訂立及條款;

三、融資性租賃合同的擔保;

四、融資性租賃合同責任。

評論:

按照思維的邏輯習慣,一提到合同的訂立,馬上會想到合同的生效、合同的履行,這也正是事物本身的邏輯。但本文在論及訂立之后,卻未論及合同的生效、合同的履行等問題,而僅研究合同的擔保。其邏輯難謂合理、嚴密。

實例8:

碩士論文:論農地承包經營權

第一部分 農地承包經營權的基本特點和主要缺點

第二部分 農地承包經營權的革新

(一)第三部分 農地承包經營權的革新

(二)第四部分 他國(地區)農地使用制度與農業發展的經驗介紹

第五部分 農地承包經營權規范化建構的制約因素及其發展態勢分析

第六部分 農地承包經營權目標模式的建構

評論:

問題是,先講中國,后講外國,最后再來講中國,違反先外國后本國的空間上的遞進關系。邏輯關系是混亂的。

實例9:

碩士論文:加害給付研究

第一章 德國法中的積極侵害債權

第二章 中國法的加害給付

第三章 加害給付的構成要件及法律效果

第四章 民事責任競合概述及責任比較

第五章 外國民事責任競合處理

第六章 中國法的責任競合

評論:

問題是題目確定的研究范圍不能涵蓋第四、五、六章的“民事責任競合”,各章之間邏輯關系不清。

實例10:

碩士論文:我國合同解除制度立法研究:

第一章 關于合同解除的歷史考察

第二章 我國現行合同法關于合同解除的規定及其問題

第三章 合同解除的概念和意義

第四章 解除權的性質、種類與發生原因

第五章 行使法定解除權的原因

第六章 行使解除權的方法

第七章 合同解除的效力

第八章 合同解除權的消滅

評論:

問題主要是第二章我國現行合同法關于我國合同解除的規定及其問題,本應當安排在本文最后予以分析并提出對策建議,卻安排在第二章,不符合邏輯思維順序和習慣,破壞了其他各章從遠到近、從抽象到具體的遞進關系。

6、對各部分標題的要求

第一項要求:標題應當是名詞或名詞性短語,不能是一個句子

第二項要求:標題只確定本部分的研究對象,不表達作者觀點

第三項要求:標題應明確、簡短而忌冗長

第四項要求:標題應當出現題目中的關鍵詞

第五項要求:同一層次的各標題應相互協調

實例1:

博士論文:荷蘭國際私法研究

第一章 荷蘭國際私法概述

第二章 荷蘭與國際私法統一化

第三章 荷蘭國際私法法典化編纂

評論:

我們看到各章的標題,都是名詞性短語,而不是句子,符合第一項要求;各標題只是確定本章研究對象或范圍,而不表達作者觀點,符合第二項要求;各標題符合明確、簡短而不冗長的第三項要求;論文題目中的關鍵詞,亦即“動賓結構”中的名詞“國際私法”,在各章標題中重復出現,這也就是所謂“切題”,符合第四項要求;各標題結構、長短比較協調,符合第五項要求。

再看其中第一章下面的各節:

第一節 荷蘭國際私法的概念

第二節 荷蘭國際私法的淵源

第三節 荷蘭國際私法的性質

第四節 荷蘭國際私法的歷史發展

同樣符合關于標題的五項要求。

實例2:

博士論文為例:責任保險論

第一章 責任保險概述

第二章 責任保險的分類

第三章 責任保險合同

第四章 責任保險人的給付責任

第五章 責任保險的第三人

第六章(責任保險的)抗辯與和解的控制

第七章 責任保險人的抗辯義務

第八章 責任保險與再保險

評論:

同樣符合上述五項要求。須補充的是,在章節標題設計上,可能出現在一個標題中有兩個名詞性短語,亦即一個章、節可以有兩個或三個研究對象。在節以下層次的標題,第三項要求,可以不象章、節(特別是章)那樣嚴格。再就是,有的論文章標題似未重復論文題目中的關鍵詞,而直接采用論文題目關鍵詞的下位概念,以作為各章標題的賓語短語。

實例3:

博士論文為例:國際貨幣基金協定研究 第四章 國際收支平衡的法律制度研究

第五章 國際儲備的法律制度研究

第六章 匯兌安排國際法律制度研究

第七章 外匯管制法律問題研究

第八章 基金協定的監督與磋商機制研究

評論:

實際上可以認為,各章標題中省略了論文題目中的關鍵詞“國際貨幣基金協定”:

第五章(國際貨幣基金協定中的)國際收支平衡的法律制度研究

第六章(國際貨幣基金協定中的)國際儲備的法律制度研究

第七章(國際貨幣基金協定中的)匯兌安排國際法律制度研究

第八章(國際貨幣基金協定中的)外匯管制法律問題研究

第九章(國際貨幣)基金協定的監督與磋商機制研究

不適當的實例1:

博士論文:論私法對國際法的影響

第一章 萬民法與國際法

第二章 人或主體

第三章 領土主權與所有權

第四章 條約與契約

評論:

問題是不符合關于標題的第三項要求:各章標題中沒有出現論文題目中的關鍵詞,因此給人的印象是不切題。如果對各章標題的文字作一些調整,效果就會不同:

第一章 萬民法與國際法

第二章 私法主體與國際法主體

第三章 私法所有權與國際法領土主權

第四章 私法契約與國際法條約

不適當的實例2:

碩士論文:論物權立法

其第三部分 我國現實歷史條件下物權立法之必要性研討

第一節 建立我國完整統一的物權制度是馬克思所有權理論的必然要求

第二節 建立完整統一的物權制度是我國現經濟基礎的客觀要求

第三節 建立完整而統一的物權制度是我國現實司法實務更有利于保護公民法人的合法權益的客觀要求

評論:

存在的問題是,標題不是一個名詞性短語,而是一個完整的句子,違背第一項要求;不是確定各節研究對象、研究范圍,而是直接表達作者觀點,違背第二項要求;各標題十分冗長,第三節標題長達41個字,顯然違背第四項要求;第一節標題“建立我國完整統一的”,第二節標題“建立完整統一的”,第三節標題“建立完整而統一的”,甚不協調,違背第五項要求。

如果作下述調整,效果將會改觀:

第一節 從馬克思所有權理論看我國物權立法

第二節 從現實經濟基礎看我國物權立法

第三節 從公民法人合法權益保護看我國物權立法

結語

碩士論文、博士論文的結構,除導論、本論、結論三部分外,前面必須有目錄,還可以有序言。后面必須有參考著作目錄,可以再寫個后記。后記的內容沒有一定之規,通常是致謝及發感慨。

阿道夫 的 范德薩 啊訂單式

第三篇:關于分析今天保定百度百度愛問愛第3章C54x DSP系統硬件結構DSP芯片

關于分析今天保定百度百度愛問愛第3章C54x DSP系統硬件結構DSP芯片.txt

-你腳踏倆只船,你劃得真漂亮。-每個說不想戀愛的人 心里都裝著一個不可能的人。我心疼每一個不快樂卻依然在笑的孩子。(有沒有那么一個人,看透我在隱身,知道我在等人。的的的地方地方愛的規格愛你啊好文章第3章 C54x DSP系統硬件結構

DSP芯片是一種特殊結構的微處理器,為了快速地實現數字信號處理運算,采用了流水線指令執行結構和相應的并行處理結構,可在一個周期內對數據進行高速的算術運算和邏輯運算。本章主要介紹C54x DSP芯片的硬件結構,重點對芯片的引腳功能、CPU結構、內部存儲器、片內外設電路、系統控制以及內、外部總線進行討論。3.1 C54x DSP的基本架構 TMS320 C54x DSP(簡稱C54x)是TI公司為實現低功耗、高速實時信號處理而專門設計的16位定點數字信號處理器。其內核包含在第1章已經討論過的哈佛結構和高級算術特點中。另外,C54x還具有多總線結構以及強大的片上外設,具有高度的操作靈活性和運行速度,適應遠程通信等實時嵌入式應用的需要,現已廣泛地應用于無線通信系統中。3.1.1 C54x DSP的基本結構圖

一塊DSP芯片上集成CPU、片內存儲器、外圍電路、總線以及外部總線接口。圖3-1所示為TMS320C54x基本結構框圖,它包含了主要模塊和總線結構。圖3-2所示為TMS320C54x功能結構圖。與傳統微處理器相比較,DSP最顯著的結構特點是具有高效存取數據、單周期乘法器和零開銷硬件循環等。3.1.2 C54x DSP的主要特征

1.具有快速處理性能的CPU部分 CPU是DSP芯片中的核心部分,CPU內的硬件構成決定其指令系統的性能。采用了流水線指令執行結構和相應的并行處理結構,可在一個周期內對數據進行高速的算術運算和邏輯運算,TMS320C54x的CPU包括以下幾部分:

(1)先進的多總線結構,包括1條程序總線、3條數據總線、4條地址總線和外設總線;(2)40位算術邏輯單元(ALU),包括1個40位的桶形移位寄存器和2個獨立的40位累加器;

(3)17×17的并行乘法器,并與1個40位的專用加法器配合,用于非流水線的單周期乘/累加操作;DSP芯片技術及工程實例第3章 C54x DSP系統硬件結構圖3-1 TMS320C54x基本結構框圖

圖3-2 TMS320C54x功能結構圖

(4)比較、選擇和存儲單元,用于維特比運算中的加/比較選擇;(5)指數編碼器,可以在單周期內計算40位累加器的指數值;

(6)2個地址生成器,包括8個輔助寄存器和2個輔助寄存器算術單元;(7)雙內核結構(只適用于C5420).2.具有哈佛結構的存儲器系統

(1)具有獨立的程序存儲器和數據存儲器,可同時訪問,使許多處理運算比傳統的馮·諾依曼結構有效得多。

(2)具有192K字可尋址存儲空間,包括片內、外64K字程序存儲空間,片內、外64K字數字存儲空間和片外64K字的I/O空間。其中一些型號DSP的程序存儲器空間可擴展至8M字,例如TMS320C548、TMS320C549、TMS320C5402、TMS320C5410和TMS320C5420.(3)提供一定容量的片內存儲器,片內存儲器配置因型而異,包括片內ROM和RAM,通過內部多總線,CPU可以同時、快速地訪問它們,以實現并行處理。但對于外部存儲器,DSP提供了外部接口,它與內部多總線結構復接,但外部只有一組I/O接口線,所以不能在單周期內并行實現讀寫操作。3.片內外設和專用電路

除了DSP內核外,DSP芯片上還需配置一些外設專用器件。這些器件可以與DSP內核平行操作,只占用很小的內核指令周期,依靠這些器件無縫出入DSP處理內核的能力,可大大提高DSP處理數據的能力。TMS320C54x的片內外設和專用電路采用模塊化的結構設計,常見的外設包括以下幾種。

(1)可編程軟件等待狀態發生器。(2)可編程分區轉換邏輯電路。

(3)可采用內部振蕩器或外部時鐘源的片內鎖相環(PLL)時鐘發生器。

(4)外部總線接口可以禁止或允許外部數據總線、地址總線和控制線的輸出。(5)數據總線具有總線保持功能。(6)可編程定時器。

(7)8位并行主機接口(HPI),有些產品還包括擴展的8位并行主機接口(HPI8)和16位并行主機接口(HPI16).(8)片內的串行口按不同的型號分為全雙工串口(支持8位和16位數據傳送)、時分多路(TDM)串口和緩沖(BSP)串口。

C54x系列定點DSP芯片共享同樣的CPU內核和總線結構,但每一種器件片內存儲器的配置和片內外設不盡相同。表3-1列出了TMS320C54x系列DSP基本配置匯總。表3-1 TMS320C54x系列DSP基本配置匯總表型 號電壓/VcoreI/O片內存儲器RAM/ KBROM/ KBDAT/ PRO/B外 設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續表型 號電壓/VcoreI/O片內存儲器RAM/ KBROM/ KBDAT/ PRO/B外 設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.指令系統

在TMS320C54x的指令系統中,具有單指令重復和塊指令重復操作指令,32位長操作數指令,同時讀入2個或3個操作數的算術指令。支持存儲器塊傳送指令,能并行存儲和并行加載的算術指令,支持條件存儲指令及中斷快速返回指令。5.執行速度

對TMS320C54x而言,其執行單周期定點指令時間為25/20/15/12.5/10ns(對應每秒指令數分別為40/50/66/80/100MIPS).6.電源和功耗

TMS320C54x DSP芯片可采用5V、3.3V、3V和1.5V、1.8V或2.5V的超低電壓供電。而且其功耗可采用下降指令IDLE1、IDLE2和IDLE3來控制,以便使DSP工作在節電模式下可控制關斷CLKOUT信號。7.芯片仿真功能 具有符合IEEE 1149.1標準的片內仿真JTAG接口,其主要功能是用于與主機相連接,實現芯片的仿真與測試。3.2 總線結構

按照結構來區分,又可將總線分成內部總線和外部總線,本節只介紹內部總線,外部總線的結構和功能將在3.8節介紹。

為了提高CPU高度的并行性,達到最大的處理能力,例如在單周期內完成算術、邏輯和位操作等運算,TMS320C54x DSP片內采用多總線結構,用8條總線,可同時對程序指令和數據進行雙訪問,這8條16位的總線包括4條程序/數據總線和4條地址總線。另外,CPU訪問片內外設是通過在片雙向總線來實現的,如圖3-2所示的功能結構圖。正是這種改進型哈佛總線結構,形成了支持高速指令執行的硬件基礎。

(1)程序總線(PB): 傳送來自程序存儲器的指令代碼和立即數。

(2)3組數據總線(CB、DB和EB): 負責將片內的各種元器件相互連接,如CPU、數據地址產生邏輯、程序地址產生邏輯、片內外設和數據存儲器等。其中,CB和DB總線傳送從存儲器讀出的數據,即“讀”操作使用的數據總線;EB總線傳送向存儲器寫入的數據,即“寫”操作使用的數據總線。

(3)地址總線(PAB、CAB、DAB、EAB): 負責傳送執行指令所需的地址。

(4)在片雙向總線: TMS320C54x用一組雙向的片內總線訪問片內外設,這組總線輪流使用DB和EB與CPU連接。用這組總線進行讀/寫操作需要兩個或更多的周期,具體所需周期數取決于片內外設的結構。

TMS320C54x能利用兩個輔助寄存器算術單元(ARAU0和ARAU1)在同一個周期內生成兩個數據存儲器地址,可實現片內RAM 的雙訪問功能。

表3-2列出了各種不同類型的總線訪問形式。從表中看到,C54x器件在任何給定的機器周期內可執行4個并行存儲器操作: 1次取指、讀取2個操作數和寫1個操作數。或通過CB、DB、PB總線同時取操作數,可在一個機器周期內完成從數據存儲器讀雙數據同時從程序存儲器讀一個常數的3個操作數讀取,而片上外設的讀、寫則是通過DB和EB總線輪流與CPU連接完成,所以使用這組總線進行讀/寫操作需要兩個或更多的周期。表3-2 C54x DSP讀/寫操作占用總線情況讀/寫方式地 址 總 線PABCABDABEAB程序總線

PB數 據 總 線CBDBEB程序讀√√程序寫√√單數據讀√√雙數據讀√√√√32位長數據讀√(hw)√(lw)√(hw)√(lw)單數據寫√√數據讀/數據寫√√√√雙數據讀/系數讀√√√√√√外設讀√√外設寫√√3.3 存儲器結構 TMS320C54x DSP存儲器采用改進型哈佛結構。與馮·諾依曼結構的存儲器相比較,哈佛結構的程序/數據總線和空間是分開的,馮·諾依曼結構的程序/數據總線和空間是合二為一的,而改進型哈佛結構的部分程序/數據空間可交叉,因此提供了高度的并行性。3.3.1 DSP存儲器空間的劃分 C54x DSP的存儲空間共192K字,由3個獨立可選的存儲空間組成,包括64K字的程序存儲空間、64K字的數據存儲空間和64K字的I/O空間。其中有些型號芯片的程序空間還可以進一步擴展。

存儲器分為片內存儲器和片外存儲器。片內存儲器有3種類型: 雙訪問RAM(DARAM)、單訪問RAM(SARAM)和ROM.RAM總是安排到數據存儲空間,但也可以配置在程序存儲空間。C54x片上還有26個映射到數據存儲空間的CPU寄存器和外設寄存器。ROM一般映射到程序存儲空間,也可以部分地映射到數據存儲空間。在TMS320C54x DSP中,片外存儲器主要包括程序存儲器、數據存儲器、I/O空間。與片外存儲器相比,片內存儲器不需插入等待狀態,成本低,功耗低。但是,片外存儲器具有尋址較大存儲空間的能力,而片內存儲器尋址存儲空間較小。C54x通過設置處理器工作方式狀態寄存器(PMST)中的3個狀態位MP/MC、OVLY和DROM(詳見3.4.1節),可以很方便地“使能”和“禁止”程序與數據空間中的片內存儲器。(1)MP/MC位

MP/MC位決定是否使用片內ROM.若MP/MC=0,稱微計算機模式,片內ROM使能并能夠訪問。若MP/MC=1,稱微處理器模式,表示片內ROM無法訪問。(2)OVLY位

OVLY位決定是否讓數據存儲器映射到程序存儲器空間。若OVLY=0,片內RAM只映射到數據存儲空間。

若OVLY=1,片內RAM同時映射到程序和數據存儲空間。(3)DROM位

DROM位決定是否讓部分程序存儲器映射到數據存儲器空間。若DROM=0,片內ROM不映射到數據存儲空間。若DROM=1,部分片內ROM映射到數據存儲空間。DROM位的用法與MP/MC位的用法無關。不同的C54x的數據和程序存儲區分配并不完全相同。圖3-3(a)所示為TMS320C549存儲器空間分配圖,圖3-3(b)所示為TMS320C5416存儲器空間分配圖,從圖中可以看到在任何一個存儲空間內,RAM、ROM都可以駐留在片內或者片外,但需要通過對3個狀態位MP/MC、OVLY和DROM的設置來配置。圖3-3 存儲器空間分配圖 圖3-3(續)

所有C54x DSP器件提供一定數量的片內ROM和RAM, DSP有兩種類型的RAM,包括雙尋址RAM(DARAM)和單尋址RAM(SARAM)。表3-3列出了不同C54x系列DSP 片內各種存儲器的配置。

1.片內ROM 片內ROM是程序存儲器的一部分,對某些DSP器件來說,也可是數據存儲空間的一部分,如C5402。當MP/MC設置為0時,可以映射到程序存儲空間的ROM為4KB;當DROM設置為1時,可以映射到數據存儲器空間的ROM為4KB。不同芯片的片內可用ROM容量是不一樣的,見表3-3。對于ROM少的DSP器件(2KB), ROM中含有自舉加載器,在程序啟動時,將用戶的代碼從慢的外部ROM、串口,或JTAG加載到內部存儲器,這樣可以加快程序的運行速度。對于具有較大ROM的器件,部分ROM可以映射到數據和程序空間,用戶提供的代碼或數據以目標文件格式寫入ROM, TI公司可以將程序掩膜到該ROM中。2.片內雙尋址RAM(DARAM)所謂DARAM,就是在一個指令周期內,CPU可對其進行讀和寫兩次存取操作,DARAM由塊組成,CPU能在每個周期內對同一塊DARAM進行讀和寫。DARAM總是映射在數據存儲器空間,用于存儲數據,當OVLY設置為1時,它也可同時映射在程序存儲器空間,用于存儲程序代碼。表3-3 常見的C54x系列DSP片內存儲器配置KB存儲器類型C541C542C543C545C546C548C549C5402C5416C5420ROM***程序ROM***程序/數據ROM800161600400DARAM***SARAM***3.片內單尋址RAM(SARAM)在一個指令周期內只能進行一次讀或寫操作。SARAM也由塊組成,與DARAM一樣,SARAM總是映射在數據存儲器空間,用于存儲數據,當OVLY設置為1時,也可同時映射在程序存儲器空間,用于存儲程序代碼。4.存儲器映射寄存器

CPU內部專用寄存器和片上外設寄存器總是映射在數據存儲器的0頁上,對它們的訪問很簡單,存儲器映射訪問提供了一種方便途徑,用于寄存器的存儲和恢復,也用于累加器與其他寄存器之間的信息傳遞。3.3.2 程序存儲器

程序存儲器空間存放要執行的指令和執行中所用的系數表。C54x DSP可以尋址64 K字的程序存儲空間。但也有一些型號的DSP可以擴展到8 M字,如C548、C549、C5410、C5402和C5420。下面分別講述程序存儲器的組織、片內ROM 的安排、擴展程序存儲器等內容。1.程序存儲器空間的配置

程序存儲器空間由片內和片外程序存儲器組成。如前所述,片內程序空間的組織主要通過設置MP/MC、OVLY位來實現。表3-4列出了各種C54x芯片片內程序存儲器配置情況。MP/MC和OVLY 位決定了哪個片內存儲器在程序空間中可用。例如,當OVLY設置為1時,DARAM或SARAM才能被配置到程序存儲器空間;而只有當MP/MC設置為0時,片內ROM才可用。MP/MC是DSP的一個外部引腳,設置MP/MC狀態有兩種方法,一種是直接給MP/MC引腳低電平或高電平,當DSP器件復位時,MP/MC引腳的邏輯狀態被傳送到PMST寄存器的MP/MC位。另一種方法是用戶通過軟件來設置或清除PMST寄存器的MP/MC位,以便禁止或使能片內ROM。如果片內存儲器配置到程序存儲器中,則芯片在訪問程序存儲器時會自動訪問這些存儲單元。當PAGEN產生了一個不在片內存儲器的地址時,會自動使用一個外部總線操作。C54x器件程序存儲器空間配置圖如圖3-3(a)和圖3-3(b)所示。表3-4 TSM320C54x芯片片內程序存儲器配置KB型 號ROMDARAM(OVLY=1)SARAM(OVLY=1)TMS320C541285-TMS320C542210-TMS320C543210-TMS320C545486-TMS320C546486-TMS320C5482824TMS320C54916824TMS320C5402416-TMS320C541616856TMS320C5420-32168 2.片內ROM 的組織和內容

為了增強處理器的性能,將片內ROM再細分為若干塊,這樣就可以在片內ROM的一個塊內取指的同時又在別的塊中讀數據。圖3-4所示為各種C54x器件的片內ROM分塊圖。根據C54x器件的不同,ROM可以組織為2KB、4KB或8KB的塊。圖3-4 C54x 器件片內ROM分塊圖

(1)對于2K-ROM器件,其ROM 塊為2K字。

(2)對于4K-ROM和28K-ROM 器件,其ROM塊為4K字。(3)對于16K-ROM和48K-ROM器件,其ROM塊為8K字。C54x的片內ROM容量有大(28K或48K字)有小(2K或4K字),但對于程序存儲器空間的最高2K字程序空間(F800h~FFFFh),容量大的片內ROM(C541/C545/C546)可以把 阿道夫 的 范德薩 啊訂單式

下載關于分析今天長安保定百度愛問愛第2章代碼初識 本章首先從較高層次word格式文檔
下載關于分析今天長安保定百度愛問愛第2章代碼初識 本章首先從較高層次.doc
將本文檔下載到自己電腦,方便修改和收藏,請勿使用迅雷等下載。
點此處下載文檔

文檔為doc格式


聲明:本文內容由互聯網用戶自發貢獻自行上傳,本網站不擁有所有權,未作人工編輯處理,也不承擔相關法律責任。如果您發現有涉嫌版權的內容,歡迎發送郵件至:645879355@qq.com 進行舉報,并提供相關證據,工作人員會在5個工作日內聯系你,一經查實,本站將立刻刪除涉嫌侵權內容。

相關范文推薦

    主站蜘蛛池模板: 国产av国片精品| 人妻少妇邻居少妇好多水在线| 亚洲精品久久激情国产片| 青青草国产成人久久电影| 五月婷婷开心中文字幕| 成年女人色毛片| 亚洲中字慕日产2020| 久久熟女| 无码国内精品久久综合88| 国产成人a在线观看视频免费| 人妻中文无码久热丝袜| 国产精品久久久久久人妻精品18| 日本精品久久久久中文字幕| 亚洲国产精品无码中文字| 国产亚洲日韩欧美另类丝瓜app| 亚洲自偷自拍另类第1页| 久久久精品日本一区二区三区| 无码午夜福利片| 成人无码小视频在线观看| 天天av天天爽无码中文| 2021年国产精品专区丝袜| 在线看片人成视频免费无遮挡| 99久久99久久精品国产片果冻| 天天综合网亚在线| 999久久国产精品免费人妻| 人妻丝袜无码国产一区| 国产欧美日韩一区二区三区在线| 内射极品少妇xxxxxhd| 欧美日韩精品久久久久| 国内少妇偷人精品视频免费| 国产人澡人澡澡澡人碰视频| 天天躁日日躁狠狠躁欧美老妇小说| 亚洲欧美日韩一区在线观看| 精品无码国产污污污免费| 无码精品尤物一区二区三区| 狠狠色婷婷丁香综合久久| 国产午夜福利久久精品| 日韩欧美在线综合网另类| 亚洲色精品vr一区二区三区| 国产高清国产精品国产专区| 国产精品亚洲综合色区韩国|