日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > windows >内容正文

windows

西电计科院微机原理与系统设计课程笔记(车向泉版)

發(fā)布時(shí)間:2023/12/10 windows 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 西电计科院微机原理与系统设计课程笔记(车向泉版) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

微機(jī)原理與系統(tǒng)設(shè)計(jì)

以下內(nèi)容是西安電子科技大學(xué)計(jì)算機(jī)科學(xué)與技術(shù)學(xué)院2021年大三上學(xué)期車向泉老師的微機(jī)原理與系統(tǒng)設(shè)計(jì)課程的隨課筆記。筆記的PDF版本和課程的學(xué)在西電上課錄像下載鏈接如下(請(qǐng)勿將錄像上傳到B站等網(wǎng)站!!):

鏈接:https://pan.baidu.com/s/12b7Ssu6uygtFn-gfBYoy6g
提取碼:2v5w

?

閱讀時(shí)請(qǐng)注意:

1.筆記中的刪除線標(biāo)注了上課時(shí)老師做了講解但筆記沒(méi)有詳細(xì)記述的內(nèi)容,有需要可以自己觀看錄播的相應(yīng)內(nèi)容學(xué)習(xí)

2.9月30日的錄播缺失,該節(jié)課的內(nèi)容對(duì)應(yīng)第三章最后的幾小節(jié),期末考試不要求

3.第8章只講了前一部分,該章內(nèi)容就是第6章、第7章知識(shí)的綜合運(yùn)用,所以沒(méi)有記述。第8章和復(fù)習(xí)課內(nèi)容對(duì)應(yīng)錄播資源的最后四節(jié),可以自行觀看學(xué)習(xí)

4.雖然筆記的內(nèi)容比較多,但實(shí)際上32位匯編、C語(yǔ)言與匯編語(yǔ)言的混合編程、總線的大部分內(nèi)容等等都不是期末考試要求的內(nèi)容。具體哪些內(nèi)容不要求在每學(xué)期末車?yán)蠋煹膹?fù)習(xí)課里都會(huì)說(shuō)

其他各科筆記匯總

開(kāi)課介紹

數(shù)字電路與邏輯設(shè)計(jì):用電路來(lái)實(shí)現(xiàn)邏輯關(guān)系,了解常用的一些模塊和芯片

?

計(jì)算機(jī)組織與體系結(jié)構(gòu):這個(gè)課以前是計(jì)算機(jī)組成原理和計(jì)算機(jī)系統(tǒng)結(jié)構(gòu)兩門課。上學(xué)期上課時(shí)講過(guò)三個(gè)概念:計(jì)算機(jī)系統(tǒng)結(jié)構(gòu),計(jì)算機(jī)組成,計(jì)算機(jī)實(shí)現(xiàn)

在設(shè)計(jì)計(jì)算機(jī)時(shí),首先要做一個(gè)總體的架構(gòu),包括指令集,流水線結(jié)構(gòu)等等,這個(gè)主體設(shè)計(jì)就是計(jì)算機(jī)系統(tǒng)結(jié)構(gòu)要研究的內(nèi)容

之后要細(xì)化為邏輯電路,這就是計(jì)算機(jī)組成要研究的內(nèi)容

然后要選擇合適的芯片,芯片之間連接構(gòu)成電路,最后調(diào)試。實(shí)實(shí)在在地做出來(lái),這是計(jì)算機(jī)實(shí)現(xiàn)要解決的問(wèn)題

?

單片機(jī)電路設(shè)計(jì)與開(kāi)發(fā)/微機(jī)原理與系統(tǒng)設(shè)計(jì)/嵌入式系統(tǒng)這三門課很像,都對(duì)應(yīng)計(jì)算機(jī)實(shí)現(xiàn)。要構(gòu)成一個(gè)計(jì)算機(jī)系統(tǒng),首先要選擇一個(gè)CPU,然后增加一些外圍的東西,如存儲(chǔ)器,各種接口芯片。在此基礎(chǔ)上還要設(shè)計(jì)一些軟件讓它工作,這個(gè)整體思路都是一樣的。區(qū)別在于:

1.研究的CPU不一樣

單片機(jī)的CPU相對(duì)來(lái)講性能比較弱,像8051是8位CPU,純粹單任務(wù),不支持虛擬存儲(chǔ)管理,多任務(wù),也沒(méi)有流水線和高速緩存

嵌入式系統(tǒng)主要研究ARM的Cortex-A系列,有MMU存儲(chǔ)管理單元,支持虛擬存儲(chǔ)管理,多任務(wù),也有流水線和高速緩存,可以移植一些操作系統(tǒng),如Linux

微機(jī)原理則研究Intel和AMD的X86處理器

2.編程用語(yǔ)言不一樣

3.課程教授方式不同

4.涉及領(lǐng)域不一樣

單片機(jī)一般用在物聯(lián)網(wǎng),如一些家用電器里面,成本低且可靠性高

ARM的Cortex-A系列一般用在智能手機(jī),平板電腦等手持移動(dòng)設(shè)備上,操作系統(tǒng)以Android為主

x86一般用在筆記本電腦,臺(tái)式機(jī),超級(jí)計(jì)算機(jī)等上,操作系統(tǒng)以Linux和Windows為主

?

講了下x86重要性,然后推薦了幾本教材和參考資料

緒論

基本概念

?

要構(gòu)成一個(gè)CPU,得有控制器,運(yùn)算器和寄存器,然后通過(guò)總線連接起來(lái)。在早期這些都是分立元件,隨著芯片的集成度提高后,可以把這些構(gòu)成CPU的東西放在一個(gè)芯片里面,這個(gè)芯片就叫微處理器。隨著集成度越來(lái)越高,芯片里還可以集成一定容量的高速緩存,協(xié)處理器,甚至很多個(gè)CPU的內(nèi)核

微處理器還要從內(nèi)存里取指令然后執(zhí)行指令。人和計(jì)算機(jī)交互要通過(guò)外設(shè),外設(shè)要通過(guò)接口才能夠連接到計(jì)算機(jī)里面。微處理器,內(nèi)存還有各種各樣的接口放在一起通過(guò)系統(tǒng)總線連到一塊就叫微型計(jì)算機(jī)

想要計(jì)算機(jī)工作還需要相應(yīng)的軟件,硬件和軟件加在一塊叫微型計(jì)算機(jī)系統(tǒng)

?

構(gòu)成微型計(jì)算機(jī)的這些東西做到一個(gè)芯片里面,好像一個(gè)芯片就是一個(gè)計(jì)算機(jī),這就叫單片機(jī)。加上相應(yīng)的軟件就構(gòu)成單片機(jī)系統(tǒng)

?

從廣義上講,單片機(jī)系統(tǒng)就屬于嵌入系統(tǒng)。 狹義上講,嵌入系統(tǒng)指的是性能比較強(qiáng)的專用計(jì)算機(jī)

SOC (System on Chips) 把一個(gè)計(jì)算機(jī)系統(tǒng)都集成在芯片里面。Intel最新的x86處理器,如i3,i5,i7i3,i5,i7i3i5i7就屬于SOC,里面不僅集成了多個(gè)CPU內(nèi)核,還集成了圖形處理單元,一些高速的總線接口,內(nèi)存控制器等等,把構(gòu)成計(jì)算機(jī)的大多數(shù)電路都集成在一個(gè)芯片里面

?

微處理器概述

介紹了Intel的x86處理器的歷史,中間比較了幾個(gè)處理器的參數(shù)

8088微處理器是8086微處理器的簡(jiǎn)化版,它的內(nèi)核仍然是16位的CPU,但是外部系統(tǒng)總線數(shù)據(jù)線只有8根線。訪問(wèn)內(nèi)存和接口時(shí)一次只能傳輸8位數(shù)據(jù)

?

?

微型計(jì)算機(jī)概述

假設(shè)有兩臺(tái)CPU是x86指令集兼容,但是如主板,接口連接的外設(shè)等底層硬件不同的計(jì)算機(jī),為什么可以實(shí)現(xiàn)安裝相同的操作系統(tǒng)和軟件?

?

操作系統(tǒng)跟硬件之間隔了一層。 計(jì)算機(jī)剛一加電,啟動(dòng)之后最先執(zhí)行的代碼是固化在計(jì)算機(jī)主板的ROM里面(現(xiàn)在用的是flash存儲(chǔ)器),那段代碼叫BIOS。這個(gè)程序要做的是:

1.硬件的自檢

如檢查一下內(nèi)存有多大,如何控制內(nèi)存,有什么外設(shè)接口等

2.各種外設(shè)接口初始化

接口和外設(shè)內(nèi)也會(huì)有一些寄存器,里面的內(nèi)容決定其工作狀態(tài)。 加電之后的內(nèi)容是隨機(jī)的,所以要BIOS程序?qū)懭雰?nèi)容初始化使其正常工作

3.給操作系統(tǒng)提供功能調(diào)用

BIOS程序執(zhí)行完后,它的代碼還會(huì)駐留在內(nèi)存里面,然后再?gòu)拇疟P的引導(dǎo)扇區(qū)裝代碼,引導(dǎo)代碼裝操作系統(tǒng)。操作系統(tǒng)在裝載的過(guò)程中是通過(guò)BIOS程序提供的編程接口,用調(diào)用函數(shù)或者軟中斷的形式來(lái)調(diào)用BIOS程序的代碼來(lái)訪問(wèn)硬件的

BIOS程序給操作系統(tǒng)提供的編程接口是標(biāo)準(zhǔn)化的,這樣在不同的硬件上就可以裝相同的操作系統(tǒng)

?

x86處理器剛加電啟動(dòng)時(shí)處于實(shí)模式,實(shí)模式相當(dāng)于是一臺(tái)快速的8086,只能夠運(yùn)行16位的程序。所以BIOS程序全部或者說(shuō)最開(kāi)始執(zhí)行的那段代碼肯定要設(shè)計(jì)成16位程序,通常可能還要用匯編語(yǔ)言來(lái)設(shè)計(jì)。 但是隨著操作系統(tǒng)裝載完成,CPU最終要從實(shí)模式切換到32位或64位CPU的保護(hù)模式,這時(shí)操作系統(tǒng)訪問(wèn)硬件就要調(diào)用設(shè)備驅(qū)動(dòng)程序提供的函數(shù),而設(shè)備驅(qū)動(dòng)程序給某一操作系統(tǒng)提供的編程接口也是標(biāo)準(zhǔn)的

不同的硬件設(shè)備驅(qū)動(dòng)程序不一樣,但它給操作系統(tǒng)提供的編程接口調(diào)用方式都是一樣的,這樣在不同的硬件上就可以裝相同的操作系統(tǒng)

?

中間介紹了微型計(jì)算機(jī)的歷史

Intel 單核/多核處理器

單核處理器8086

8086具有以下特點(diǎn):

1.最大內(nèi)存尋址空間可以達(dá)到1M(=220)1M(=2^{20})1M(=220)字節(jié)

2.內(nèi)部的通用寄存器都是16位的,因?yàn)樗?6位的CPU

?

16位的寄存器怎么表示20位的內(nèi)存地址?

對(duì)內(nèi)存采用分段管理方式。段寄存器保存段的起始地址的高16位,低4位默認(rèn)是0;指針寄存器內(nèi)存16位的段內(nèi)偏移

3.x86處理器采用獨(dú)立編址。內(nèi)存與接口和外設(shè)里的存儲(chǔ)器各有獨(dú)立的地址空間,各有不同的指令和讀寫信號(hào)

8086的接口地址空間只有64K字節(jié),不需要分段

?

?

?

8086的內(nèi)部框圖:

8086內(nèi)部有14個(gè)程序員可見(jiàn)的16位通用寄存器

8088的指令隊(duì)列是4個(gè)字節(jié),8086是6個(gè)字節(jié)

分為BIU和EU。由于有指令隊(duì)列,二者可并行工作

總線接口單元BIU (Bus Interface Unit) :負(fù)責(zé)與存儲(chǔ)器,I/O接口出傳遞數(shù)據(jù)

執(zhí)行單元EU (Execute Unit) :負(fù)責(zé)指令的執(zhí)行

?

8086的AX~\sim???DX4個(gè)寄存器可以拆成2個(gè)8位的來(lái)用,如低8位叫AL,高8位叫AH

匯編語(yǔ)言中 [SI] 表示寄存器間接尋址

?

?

?

8086的寄存器結(jié)構(gòu):

SP,BP,SI,DI,IP是指針寄存器,用來(lái)存段內(nèi)偏移。CS,DS,SS,ES是段寄存器,用來(lái)存段起始地址的高16位

例題:

這段程序訪問(wèn)的主存地址是:

MOV DX,0A000H MOV DS,DX MOV SI,9000H MOV AL,[SI]

?

答案:A9000H

解析:

1.數(shù)據(jù)傳送指令不支持立即數(shù)到段寄存器之間的直接傳送,所以要初始化段寄存器必須要先把立即數(shù)傳送到某一個(gè)通用寄存器

2.16進(jìn)制的立即數(shù)形式如果最高位是英文字母,在它的左側(cè)必須要加一個(gè)0,編譯程序才會(huì)認(rèn)為這是一個(gè)立即數(shù)

3.最終DS內(nèi)容為0A000H,SI內(nèi)容為9000H。0A0000H + 9000H = 0A9000H

?

代碼段寄存器 (Code Segment):程序執(zhí)行時(shí)內(nèi)存里會(huì)存機(jī)器指令,這些機(jī)器指令所在的段叫代碼段。代碼段段的起始地址的高16位就存在CS

數(shù)據(jù)段寄存器 (Data Segment):指令執(zhí)行的過(guò)程中肯定需要一些數(shù)據(jù)要從內(nèi)存中取,或者最終的結(jié)果要存到內(nèi)存中去。存儲(chǔ)數(shù)據(jù)的段叫數(shù)據(jù)段

堆棧段寄存器 (Stack Segment):執(zhí)行的指令中會(huì)有PUSH壓棧和POP出棧指令,主程序調(diào)用時(shí)要保護(hù)當(dāng)前的斷點(diǎn),斷點(diǎn)要保護(hù)在堆棧里面,免不了要涉及一些和堆棧有關(guān)的操作。堆棧的這些數(shù)據(jù)所在的段叫堆棧段

附加段寄存器 (Extra Segment):也是用來(lái)訪問(wèn)數(shù)據(jù)的。默認(rèn)用DS,也可以指定用ES來(lái)訪問(wèn)數(shù)據(jù)。一般用于跨段訪問(wèn)數(shù)據(jù)

MOV AX,[BX] ;默認(rèn)段寄存器是DS MOV AX,ES:[BX] ;加段超越前綴,此時(shí)段寄存器是ES

?

?

AX~DXAX\sim DXAXDX??????大多數(shù)情況下都可以隨便用,但也有特殊用途:

數(shù)據(jù)寄存器AX (Accumulator):一些特殊的指令,比如說(shuō)乘法指令,被乘數(shù)是隱含尋址,默認(rèn)在AX。最終結(jié)果的一部分也會(huì)放在AX,除法指令也有類似的規(guī)定。包括后面用來(lái)訪問(wèn)接口的IN指令和OUT指令,寄存器必須得用AX

運(yùn)算結(jié)果的低16位默認(rèn)存在AX,高16位默認(rèn)存在DX

數(shù)據(jù)寄存器BX (Base):也可以當(dāng)指針寄存器來(lái)用,用來(lái)間接尋址

AX,CX,DX不可以

數(shù)據(jù)寄存器CX (Count):在一些特殊的指令中用于計(jì)數(shù),如匯編語(yǔ)言中用LOOP指令實(shí)現(xiàn)循環(huán)時(shí)CX會(huì)記錄剩余循環(huán)次數(shù)

數(shù)據(jù)寄存器DX (Data):純粹用來(lái)存數(shù)據(jù)

?

?

指令指針寄存器 (Instruction Point):為了取得下一條指令的內(nèi)存地址,需要用到CS和IP,分別存代碼段的起始地址的高16位(低4位默認(rèn)為0)和16位的段內(nèi)偏移

堆棧指針寄存器 (Stack Point):SS和SP配合共同確定當(dāng)前堆棧棧頂?shù)奈恢?/p>

注意x86中棧頂是小地址,棧底是大地址

16位的CPU,堆棧里每一個(gè)數(shù)據(jù)必須是16位的。所以沒(méi)有 PUSH AL 和 POP AL,只有 PUSH AX 和 POP AX。32位的x86同理

基址指針寄存器 (Base Point):指針寄存器如果用BX,那默認(rèn)的段寄存器是DS。如果用BP,那默認(rèn)的段寄存器是SS。故BP一般是用來(lái)間接尋址訪問(wèn)堆棧當(dāng)中的任意一個(gè)元素的

源變址寄存器 (Source Point) 和目的變址寄存器 (Destination Point):訪問(wèn)數(shù)據(jù),默認(rèn)的段寄存器是DS,指針寄存器可以用BX,SI,DI,只有這3個(gè)寄存器可以用來(lái)間接尋址訪問(wèn)數(shù)據(jù)段

?

標(biāo)志寄存器/程序狀態(tài)字 (PSW/FLAGS) :

輔助進(jìn)位標(biāo)志位 (Auxiliary Carry - BCD):加法運(yùn)算如果運(yùn)算結(jié)果的第3位向第4位有進(jìn)位,AF置1。BCD數(shù)運(yùn)算有關(guān)的指令里可能會(huì)用到

第幾位從低位,從0開(kāi)始編號(hào)

進(jìn)位/借位標(biāo)志位 (Carry Flag):加法運(yùn)算運(yùn)算結(jié)果的最高位向更高位有進(jìn)位或減法運(yùn)算最高位向更高位有借位,CF置1

這里的加減法理解為無(wú)符號(hào)數(shù)相加減

奇偶標(biāo)志位 (Parity Flag):運(yùn)算結(jié)果中1的結(jié)果如果為偶數(shù)個(gè),PF置1。可用于加奇偶校驗(yàn)位

符號(hào)標(biāo)志位 (Sign Flag):反映運(yùn)算結(jié)果的最高位,最高位是什么SF就是什么

零標(biāo)志位 (Zero Flag):運(yùn)算結(jié)果為0,ZF置1

溢出標(biāo)志位 (Overflow Flag):運(yùn)算結(jié)果溢出時(shí),OF置1

以上標(biāo)志位都是運(yùn)算器的硬件根據(jù)運(yùn)算結(jié)果自動(dòng)管理的

?

中斷允許標(biāo)志位 (Interrupt Enable Flag):關(guān)中斷指令CLI可將IF置0,之后CPU不會(huì)響應(yīng)任何來(lái)自外設(shè)或者接口的中斷請(qǐng)求。開(kāi)中斷指令STL可將IF置1

方向標(biāo)志位 (Direction Flag(Strings) ):CLD可將DF清0,串操作指令在重復(fù)執(zhí)行的時(shí)候就會(huì)從小地址向大地址的方向訪問(wèn)數(shù)組。STD可將DF置1,串操作指令訪問(wèn)數(shù)組時(shí)會(huì)從大地址往小地址的方向訪問(wèn)

陷阱標(biāo)志位 (Trap-Single Step Flag):跟調(diào)試有關(guān),單步跟蹤的時(shí)候可能用到。TF置1后CPU每執(zhí)行完一條指令后就會(huì)在內(nèi)部產(chǎn)生一個(gè)單步中斷,最終會(huì)跳轉(zhuǎn)到單步中斷所對(duì)應(yīng)的中斷服務(wù)程序,即調(diào)試工具代碼的一部分

以上標(biāo)志位有專門的指令進(jìn)行管理,讓CPU工作在不同的狀態(tài)

?

?

?

8086的主存結(jié)構(gòu):

先看雙體結(jié)構(gòu):

8088的內(nèi)存相對(duì)簡(jiǎn)單,不分存儲(chǔ)體,只有一個(gè)8位的存儲(chǔ)體就夠了,接口也一樣,設(shè)計(jì)較簡(jiǎn)單

?

8086把內(nèi)存分為兩個(gè)存儲(chǔ)體,偶地址存儲(chǔ)體和奇地址存儲(chǔ)體,有各自的存儲(chǔ)體選擇信號(hào)以實(shí)現(xiàn)8位和16位傳送讀寫。偶地址存儲(chǔ)體的選擇信號(hào)如果是低電平有效的話,地址線最低位A0 ̄\overline{A_0}A0???????可當(dāng)作偶地址存儲(chǔ)體的選擇信號(hào)。奇地址存儲(chǔ)體的選擇信號(hào)則有專門的引腳信號(hào)BHE ̄\overline{BHE}BHE?

給這兩個(gè)存儲(chǔ)體的都是字的地址,從A1 ̄\overline{A_1}A1??開(kāi)始,A0 ̄\overline{A_0}A0?????理解成偶地址存儲(chǔ)體的選擇信號(hào)

?

要讀16位數(shù)據(jù),會(huì)存在一次和分兩次的情況:

一次,

?

必須分兩次,

體現(xiàn)了數(shù)據(jù)對(duì)齊的重要性。16位數(shù)據(jù)在內(nèi)存中占2個(gè)字節(jié),我們就希望在內(nèi)存里從偶地址開(kāi)始存放,這樣一個(gè)總線周期就能完成讀寫

?

分段結(jié)構(gòu)方式上面已經(jīng)多次提到。注意各個(gè)分段之間可以重疊

6832H:1280H中6832H是段寄存器的內(nèi)容,1280H是段內(nèi)偏移

?

下面再看一些特殊的內(nèi)存區(qū)域:

中斷向量區(qū):00000H~003FFH (1KB),每個(gè)中斷向量占4個(gè)字節(jié)

顯示緩沖區(qū):B0000H~B0F9FH (4000B),B8000H~BFFFFH (32KB)

啟動(dòng)區(qū):FFFF0H~FFFFFH (16B),內(nèi)為無(wú)條件轉(zhuǎn)移指令,使啟動(dòng)時(shí)跳轉(zhuǎn)到BIOS程序的起始地址

操作系統(tǒng)裝載在常規(guī)內(nèi)存中

顯示緩沖區(qū)實(shí)例不要求

?

?

?

8086芯片引腳:

1.電源引腳

2.地址、數(shù)據(jù)線

考慮到不管是訪問(wèn)內(nèi)存還是訪問(wèn)接口,都是先送地址然后再傳數(shù)據(jù),Intel 把地址信號(hào)和數(shù)據(jù)信號(hào)復(fù)用以節(jié)省引腳,在設(shè)計(jì)電路時(shí)外面會(huì)增加一些輔助芯片來(lái)把復(fù)用的信號(hào)分離出來(lái)。即16位的數(shù)據(jù)和低16位的地址是復(fù)用的,高4位地址線和狀態(tài)信號(hào)復(fù)用

S6:廢用狀態(tài),輸出一直是低電平

S5:表示當(dāng)前IF的情況,看該引腳在輸出狀態(tài)時(shí)是輸出高電平還是低電平可知現(xiàn)在是開(kāi)中斷還是關(guān)中斷

S3,S4:一共有4種組合,表示現(xiàn)在CPU正在使用哪一個(gè)段寄存器

3.時(shí)鐘、復(fù)位

CPU剛一加電之后,里面的內(nèi)容是隨機(jī)的,當(dāng)電源電壓穩(wěn)定之后,在RESET引腳加大于4個(gè)時(shí)鐘周期寬度的正脈沖,就可以把CPU內(nèi)部的CS置為全1,其他寄存器清0

8086的時(shí)鐘信號(hào)不是方波,高電平持續(xù)時(shí)間是低電平持續(xù)時(shí)間的12\frac1221???。外部的時(shí)鐘發(fā)生器芯片對(duì)一個(gè)方波進(jìn)行三分頻

4.中斷

NMI:不可屏蔽中斷請(qǐng)求輸入引腳

INTR:可屏蔽中斷請(qǐng)求輸入引腳

INTA ̄\overline{INTA}INTA:中斷應(yīng)答引腳

8086/8088 的計(jì)算機(jī)系統(tǒng)實(shí)現(xiàn)中斷時(shí)需要在外面增加一個(gè)可編程中斷控制器8259,該芯片可以管理8個(gè)中斷源,不夠用還可以多片級(jí)聯(lián)

x86處理器在管理中斷時(shí),每一個(gè)中斷源都有1個(gè)8位二進(jìn)制編碼的編號(hào)(中斷向量),所以x86處理器最多可以管理256個(gè)中斷源

有一些中斷源的編號(hào)是固定的,特別是來(lái)自CPU內(nèi)部的中斷源,比如

0號(hào)中斷對(duì)應(yīng)除法錯(cuò)誤(除數(shù)為0,結(jié)果溢出)

1號(hào)中斷叫單步中斷。調(diào)試工具如果把TF置1,那么CPU每執(zhí)行完一條機(jī)器指令之后都會(huì)在內(nèi)部產(chǎn)生一個(gè)1號(hào)中斷,最終進(jìn)入到單步中斷的中斷服務(wù)程序。那個(gè)程序就是調(diào)試軟件代碼的一部分

3號(hào)中斷叫斷點(diǎn)中斷,也是調(diào)試用的

4號(hào)中斷叫溢出中斷,一些補(bǔ)碼加法結(jié)果溢出

?

這些中斷究竟是怎么運(yùn)作的?

比如CPU內(nèi)部現(xiàn)在產(chǎn)生0號(hào)中斷,一旦中斷產(chǎn)生,CPU馬上獲取對(duì)應(yīng)中斷向量,再根據(jù)中斷向量查找主存中的中斷向量表,讀出對(duì)應(yīng)行的前2個(gè)字節(jié)賦值給IP,后面2個(gè)字節(jié)賦給CS,這2個(gè)寄存器合起來(lái)就相當(dāng)于上學(xué)期講的程序計(jì)數(shù)器PC,被重新賦值后當(dāng)然就會(huì)跳轉(zhuǎn)到0號(hào)中斷源對(duì)應(yīng)的中斷服務(wù)程序執(zhí)行

注意在賦值前必須要把IP和CS這兩個(gè)寄存器原來(lái)的內(nèi)容保護(hù)在堆棧里,這叫斷點(diǎn)保護(hù)。響應(yīng)中斷時(shí),需要壓入IP,CS,PSW的內(nèi)容,然后硬件自動(dòng)把IF置0,再去查中斷向量表

中斷向量表有256行,行號(hào)從0~\sim??????255,每一行對(duì)應(yīng)某一號(hào)中斷,占4個(gè)字節(jié)(前2個(gè)字節(jié)對(duì)應(yīng)段內(nèi)偏移,后2個(gè)字節(jié)是段寄存器的內(nèi)容),存對(duì)應(yīng)的中斷服務(wù)程序。表總共1KB,從內(nèi)存地址0開(kāi)始存放,在計(jì)算機(jī)啟動(dòng)的過(guò)程中由BIOS程序負(fù)責(zé)初始化

CPU內(nèi)部的中斷源還有一個(gè),x86處理器的指令集里專門有一條軟中斷指令I(lǐng)NT 21H ,21H是立即數(shù),表示某中斷向量。編寫16位匯編語(yǔ)言程序時(shí),經(jīng)常需要調(diào)用DOS操作系統(tǒng)的一些功能,DOS操作系統(tǒng)就是利用軟中斷來(lái)給應(yīng)用程序提供功能調(diào)用。上面這條指令在CPU內(nèi)部一執(zhí)行就會(huì)產(chǎn)生33(=21H)號(hào)中斷,對(duì)應(yīng)的中斷服務(wù)程序是DOS操作系統(tǒng)代碼的一部分,其目的就是給用戶程序提供各種功能調(diào)用

?

以上是CPU內(nèi)部的中斷源,然后再看來(lái)自外部的中斷請(qǐng)求,涉及到INTR和NMI

為什么這兩個(gè)一個(gè)叫可屏蔽一個(gè)叫不可屏蔽?

PSW中有IF,如果通過(guò)CLI把IF清0,它實(shí)際上就屏蔽來(lái)自INTR引腳的中斷請(qǐng)求,對(duì)其他的沒(méi)有任何影響,這個(gè)引腳的中斷請(qǐng)求其實(shí)就是來(lái)自接口或外設(shè)。而NMI不能通過(guò)IF屏蔽,通常是非常緊急的中斷請(qǐng)求,比如掉電

INTR和NMI還有一個(gè)區(qū)別,INTR輸入高電平有效,NMI輸入上升沿有效

?

INTR通過(guò)中斷控制器管理來(lái)自接口或者外設(shè)的好多個(gè)中斷源,中斷控制器通過(guò)中斷判優(yōu)決定向CPU發(fā)送哪個(gè)中斷源的中斷請(qǐng)求。CPU當(dāng)前指令執(zhí)行完,并且處在開(kāi)中斷狀態(tài)才會(huì)去響應(yīng)中斷,通過(guò)INTA ̄\overline{INTA}INTA??????????發(fā)送第一個(gè)負(fù)脈沖告知中斷控制器其正在響應(yīng),同時(shí)要準(zhǔn)備好中斷向量。接著發(fā)送第二個(gè)負(fù)脈沖,中斷控制器就把中斷向量送到低8位的數(shù)據(jù)總線上傳給CPU

5.最小模式/最大模式

24~\sim?31號(hào)引腳最小模式下是括號(hào)里的功能,最大模式下是括號(hào)外的功能

工作在最小模式下,所有的控制信號(hào)由8086直接產(chǎn)生,不需要再增加其他的外部芯片,電路規(guī)模通常較小,并且計(jì)算機(jī)系統(tǒng)里通常只有8086一個(gè)處理器

工作在最大模式下,那些控制信號(hào)就不是由這些引腳直接產(chǎn)生的了,需要外面增加一個(gè)別的芯片,比如總線控制器8288芯片來(lái)產(chǎn)生內(nèi)存讀寫,接口讀寫有關(guān)的控制信號(hào)。由省出來(lái)的一部分引腳可以多一些狀態(tài)信號(hào)和DMA相關(guān)的信號(hào),這樣整個(gè)計(jì)算機(jī)系統(tǒng)里還可以接更多的主控設(shè)備,包括其他的協(xié)處理器之類

BHE ̄\overline{BHE}BHE? :上面提過(guò)

S7:廢用狀態(tài)

TEST ̄\overline{TEST}TEST??????:輸入引腳,8086如果正在執(zhí)行WAIT指令,該指令會(huì)判斷該引腳的狀態(tài),如果是高電平這條指令就一直等待,如果是低電平,這個(gè)指令就執(zhí)行完了。該指令主要用來(lái)和數(shù)學(xué)協(xié)處理器8087同步

READY:輸入引腳,講時(shí)序時(shí)再說(shuō)

?

?

?

8086在最小模式下的引腳:

INTA ̄\overline{INTA}INTA?:上面提過(guò)

RD ̄,WR ̄\overline{RD},\overline{WR}RD,WR:讀內(nèi)存讀接口都可以用到,通過(guò)M/IO ̄M/\overline{IO}M/IO 來(lái)區(qū)分是訪問(wèn)內(nèi)存還是接口

ALE:地址鎖存。地址信號(hào)要么和數(shù)據(jù)線,要么和狀態(tài)復(fù)用,那怎么知道什么時(shí)候輸出的是地址呢?

一旦8086正在輸出地址,并且地址是穩(wěn)定的,8086會(huì)通過(guò)該引腳送來(lái)正脈沖。它輸出為高電平時(shí),復(fù)用的信號(hào)正在輸出地址

DEN ̄\overline{DEN}DEN???:輸出允許。低電平表示正在傳遞數(shù)據(jù)

DT/R ̄\overline{R}R?:方向控制。高電平表示數(shù)據(jù)傳輸?shù)姆较蚴前l(fā)送(從CPU內(nèi)到CPU外),低電平表示數(shù)據(jù)傳輸?shù)姆较蚴墙邮?/p>

HOLD,HLDA:和DMA有關(guān)。DMA控制器如果想直接控制總線實(shí)現(xiàn)內(nèi)存和外設(shè)之間的數(shù)據(jù)傳送,就要求8086釋放總線的控制權(quán)。DMA控制器會(huì)首先通過(guò)HOLD引腳給8086發(fā)高電平,若滿足一定條件,8086就通過(guò)HLDA告知DMA自己已釋放總線控制權(quán)

?

8088和8086的外部引腳的區(qū)別在:

1.8088只有低8位地址和數(shù)據(jù)復(fù)用

2.只有一個(gè)存儲(chǔ)體,不需要BHE ̄\overline{BHE}BHE,故34號(hào)引腳就是一個(gè)基本不用的狀態(tài)信號(hào)

3.28號(hào)引腳是IO/M ̄IO/\overline{M}IO/M?,剛好和8086相反

?

最后結(jié)合時(shí)序來(lái)講一下READY引腳,以8088的一個(gè)總線周期(總線周期由時(shí)鐘周期組成)為例:

?

上圖一個(gè)總線周期傳了一個(gè)數(shù)據(jù),花了4個(gè)時(shí)鐘周期的時(shí)間。該時(shí)序有一個(gè)前提條件:內(nèi)存的速度足夠快,讓CPU等一個(gè)時(shí)鐘周期(T3周期),內(nèi)存就能把數(shù)據(jù)準(zhǔn)備好。如果內(nèi)存比較慢,CPU等一個(gè)時(shí)鐘周期內(nèi)存還來(lái)不及把選中單元的數(shù)據(jù)取出來(lái)放在數(shù)據(jù)總線上,希望CPU多等幾個(gè)時(shí)鐘周期,就要用到READY信號(hào)

?

?

T3周期時(shí)會(huì)判斷READY信號(hào)的狀態(tài),如果為高電平,則T3周期結(jié)束之后會(huì)直接進(jìn)入T4周期。如果內(nèi)存比較慢,則外面要有一個(gè)專門的電路,當(dāng)CPU訪問(wèn)內(nèi)存時(shí)該電路必須要在T3周期之前把READY信號(hào)置0來(lái)通知CPU多等幾個(gè)周期,CPU在T3周期開(kāi)始會(huì)采樣READY信號(hào),發(fā)現(xiàn)是低電平則T3周期結(jié)束之后不會(huì)進(jìn)入到T4周期而是插入等待周期TWT_WTW??

例題:

8086微處理器主頻為5MHZ,在不插入等待周期的情況下,從主存地址80006H讀一個(gè)8位數(shù)據(jù)所需要的時(shí)間為:

?

答案:800ns

?

然后講了下總線驅(qū)動(dòng)的原理和重要性

?

?

8086在最小模式下的系統(tǒng)總線形成:

?

8086的引腳數(shù)有限,地址信號(hào)和其他信號(hào)是復(fù)用的,外面必須要增加一些電路以保存地址信號(hào),在整個(gè)內(nèi)存或接口讀寫的過(guò)程中地址由外加的電路來(lái)提供,這樣才能保證在一個(gè)總線周期的時(shí)間段內(nèi)地址總是有效的

現(xiàn)在33號(hào)引腳接高電平,8086工作在最小模式下

要實(shí)現(xiàn)地址和其他信號(hào)的分離需要用到鎖存器,鎖存器有存儲(chǔ)功能,可以把在一個(gè)總線周期的第一個(gè)時(shí)鐘周期輸出的地址保存下來(lái),然后在整個(gè)總線周期的時(shí)間段內(nèi)由鎖存器來(lái)提供地址信號(hào)

地址信號(hào)一共21根線(20根地址線+BHE ̄\overline{BHE}BHE?????),如果用8位鎖存器74LS373,就要3片。鎖存器里存的內(nèi)容希望能一直直接輸出,所以輸出允許OE ̄\overline{OE}OE????接地永遠(yuǎn)有效。鎖存器的鎖存信號(hào)LE由ALE直接提供

在一個(gè)總線周期的第一個(gè)時(shí)鐘周期,當(dāng)輸出地址并且地址穩(wěn)定之后,ALE會(huì)輸出一個(gè)正脈沖

數(shù)據(jù)線AD0~AD15AD_{0}\sim AD_{15}AD0?AD15?不存地址的時(shí)候就當(dāng)數(shù)據(jù)線用,直接引出來(lái)就是數(shù)據(jù)線。如果負(fù)載很多,數(shù)據(jù)線想加驅(qū)動(dòng)器,用74LS245雙向驅(qū)動(dòng)器。16位的數(shù)據(jù),8位的74LS245要用2片,它有兩個(gè)控制信號(hào),方向選擇DIR接DT/R ̄DT/\overline{R}DT/R,輸出允許OE ̄\overline{OE}OEDEN ̄\overline{DEN}DEN

然后剩下單向的控制信號(hào)線,如果想加驅(qū)動(dòng)器用單向的74LS244,輸出允許OE1 ̄,OE2 ̄\overline{OE_1},\overline{OE_2}OE1??,OE2?????接地令其永遠(yuǎn)有效。這4個(gè)信號(hào)經(jīng)過(guò)它驅(qū)動(dòng)之后后面可以帶很多的負(fù)載

CPU訪問(wèn)內(nèi)存和接口的時(shí)候最好能有各自獨(dú)立的讀寫信號(hào),后面還可以加一些電路,借助數(shù)電的知識(shí),這個(gè)附加電路的功能不難理解

時(shí)鐘發(fā)生器8284用來(lái)產(chǎn)生時(shí)鐘信號(hào)

上圖其實(shí)不是很嚴(yán)謹(jǐn)。READY信號(hào)應(yīng)該由慢速的內(nèi)存或者接口電路來(lái)產(chǎn)生,復(fù)位信號(hào)也不是由時(shí)鐘發(fā)生器而是由復(fù)位電路來(lái)產(chǎn)生,該低電平有效復(fù)位信號(hào)在8284里反相之后再做為8086的復(fù)位信號(hào)輸入

現(xiàn)在我們就有了地址,數(shù)據(jù)和控制信號(hào),系統(tǒng)總線就形成了。各自存儲(chǔ)器芯片和接口芯片就可以直接連接到這些系統(tǒng)總線上

?

對(duì)8284工作原理的具體功能講解書上沒(méi)有

以8088為例,講了下更具體實(shí)際的電路下工作在最小模式下系統(tǒng)總線的形成,不太要求,了解即可

?

?

?

8086在最大模式下的引腳:

33號(hào)引腳接地,8086工作在最大模式下

此時(shí)所需要的控制信號(hào),比如內(nèi)存和接口讀寫,中斷應(yīng)答信號(hào)都沒(méi)有,所以外面要多加一個(gè)總線控制器8288來(lái)產(chǎn)生這些信號(hào)

S2 ̄,S1 ̄,S0 ̄\overline{S_2},\overline{S_1},\overline{S_0}S2??,S1??,S0??

8288想從8086知道該產(chǎn)生什么控制信號(hào)需要三個(gè)狀態(tài)信號(hào)S0,S1,S2,這三根線8種組合分別代表CPU的8種不同狀態(tài)

Passive(被動(dòng)):三根狀態(tài)線輸出111,表示CPU已經(jīng)釋放總線了,它在總線上現(xiàn)在是一個(gè)從設(shè)備,處于完全被動(dòng)的狀態(tài)。現(xiàn)在總線的使用權(quán)可能是DMA控制器或者是其他的協(xié)處理器

教材的表格里翻譯成”無(wú)效“

?

QS0 ̄,QS1 ̄\overline{QS0},\overline{QS1}QS0?,QS1?:四種組合,表示當(dāng)前指令隊(duì)列的情況。一般情況下用不到

LOCK ̄\overline{LOCK}LOCK??????:有些時(shí)候希望某條指令在執(zhí)行時(shí)不要釋放總線,可以在這條指令前加lock前綴。這條指令在執(zhí)行時(shí)該引腳輸出低電平,表示現(xiàn)在處于總線封鎖狀態(tài)

RQ ̄/GT0 ̄,RQ ̄/GT1 ̄\overline{RQ}/\overline{GT0},\overline{RQ}/\overline{GT1}RQ?/GT0,RQ?/GT1?????????????:跟最小模式下的HOLD,HLDA功能類似?。一個(gè)引腳是雙向的,既可以當(dāng)HOLD也可以當(dāng)HLDA來(lái)用。如果DMA控制器想要申請(qǐng)總線的控制權(quán),通過(guò)該引腳發(fā)一個(gè)負(fù)脈沖,CPU如果釋放總線會(huì)通過(guò)相同的引腳再往外送一個(gè)負(fù)脈沖告知DMA控制器

?

總結(jié)一下,最大模式下:

1.可以接更多可以成為總線主控設(shè)備的東西,包括DMA控制器,協(xié)處理器之類

2.結(jié)合8288芯片可以產(chǎn)生更多的控制信號(hào),可以實(shí)現(xiàn)更大規(guī)模的計(jì)算機(jī)系統(tǒng)

?

?

?

8086在最大模式下的系統(tǒng)總線形成:

?

最大模式下CPU不直接提供ALE,DT/R ̄,DEN ̄DT/\overline{R},\overline{DEN}DT/RDEN????,這些信號(hào)由總線控制器8288產(chǎn)生

注意8288產(chǎn)生的是DEN, 要加反相器

8288芯片產(chǎn)生的控制信號(hào)有嚴(yán)格的時(shí)序關(guān)系,也應(yīng)有一個(gè)時(shí)間上的基準(zhǔn),它的時(shí)鐘信號(hào)和CPU用的是同一個(gè)。8288本身驅(qū)動(dòng)能力很強(qiáng),故這些輸出的控制信號(hào)后面不需要再加驅(qū)動(dòng),可直接引出作為系統(tǒng)總線的控制信號(hào)

以8088為例,講了下更具體實(shí)際的電路下工作在最大模式下系統(tǒng)總線的形成,不太要求,了解即可

?

Intel 處理器體系結(jié)構(gòu)的發(fā)展

基本沒(méi)講,就舉了個(gè)書上沒(méi)有的宏融合技術(shù)的例子

?

Intel 處理器指令系統(tǒng)及匯編語(yǔ)言

匯編語(yǔ)言基礎(chǔ)(一)

為什么要學(xué)習(xí)匯編語(yǔ)言:

嵌入式系統(tǒng):在特定硬件下,對(duì)程序的大小和運(yùn)行速度需要高速優(yōu)化的情況

BIOS程序的設(shè)計(jì)者,操作系統(tǒng)內(nèi)核、設(shè)備驅(qū)動(dòng)程序的設(shè)計(jì)者,編譯程序、調(diào)試工具的設(shè)計(jì)者、硬件檢測(cè)/測(cè)試/診斷程序的設(shè)計(jì)者、虛擬機(jī)/模擬器的設(shè)計(jì)者

逆向工程

有助于對(duì)計(jì)算機(jī)硬件、操作系統(tǒng)、應(yīng)用程序之間交互的整體理解

突破高級(jí)語(yǔ)言的局限:高級(jí)語(yǔ)言中嵌入?yún)R編

?

?

匯編語(yǔ)言格式主要有Intel和AT&T,上課用的Intel格式,編譯程序用微軟的宏匯編 (MASM)

先以模板程序Hello world為例,大致看下基于8086的16位匯編的整體結(jié)構(gòu)和具體編寫方法:

?

?

?

?

段名:標(biāo)識(shí)段的名字,唯一的或已存在的,可以隨便起

對(duì)齊方式:可以是BYTE、WORD、DWORD、PARA(16B對(duì)齊,不寫默認(rèn))、PAGE(256B對(duì)齊)

組合方式:可以是PRIVATE(不寫默認(rèn))、PUBIC、MEMORY,STACK、COMMON、AT地址。定義堆棧段時(shí)通常寫STACK,告訴編譯程序這個(gè)段當(dāng)堆棧來(lái)處理

?

?

堆棧段定義了一個(gè)100B的空間。db偽指令表示現(xiàn)在要申請(qǐng)以字節(jié)為單位的數(shù)據(jù)塊,字節(jié)數(shù)為100。后面跟dup關(guān)鍵字和一個(gè)括號(hào),如果這100B都想初始化為0,括號(hào)里就填0,括號(hào)里填 ? 編譯之后這100B仍然被初始化為0

偽指令編譯之后不會(huì)產(chǎn)生機(jī)器指令,它就是給編譯程序一些信息

?

數(shù)據(jù)段定義了一個(gè)字符串,message就是一個(gè)用符號(hào)表示的內(nèi)存地址,本質(zhì)上就是段內(nèi)偏移,指向所定義的數(shù)據(jù)的起始位置,這樣在程序中引用字符串就不用直接引用邏輯地址。字符串以字節(jié)為單位,還是用db定義。0dh和0ah分別是回車符和換行符,‘$’ 是字符串的結(jié)束標(biāo)識(shí)

?

assume偽指令并不能實(shí)現(xiàn)對(duì)CS,DS,SS三個(gè)段寄存器的賦值。有些代碼需要算地址,比如 mov dx,offset message,offset操作符取message地址的16位段內(nèi)偏移,而編譯程序需要知道默認(rèn)的段寄存器DS對(duì)應(yīng)的是你自己定義的哪個(gè)段才能算段內(nèi)偏移。assume偽指令告訴編譯程序編譯后面代碼時(shí)要認(rèn)為此時(shí)CS,DS,SS已分別指向了你自己定義的代碼段,數(shù)據(jù)段,堆棧段

第一條指令必須要給它一個(gè)標(biāo)號(hào),整個(gè)程序總的結(jié)尾END偽指令跟這個(gè)標(biāo)號(hào),以指明主程序的入口點(diǎn)

接下來(lái)初始化數(shù)據(jù)段寄存器,引用段名把data段起始地址的高16位傳送到通用寄存器AX,再傳送到DS。這樣DS就真正指向了你自己定義的數(shù)據(jù)段

代碼段寄存器和堆棧段寄存器不需要程序初始化,由操作系統(tǒng)負(fù)責(zé)初始化。操作系統(tǒng)把數(shù)據(jù)段指向了別的位置,這個(gè)寄存器必須要由程序來(lái)初始化

data,offset message經(jīng)過(guò)編譯之后實(shí)際上是立即數(shù)7和0,以后再解釋

接下來(lái)3條指令調(diào)用DOS操作系統(tǒng)的功能,負(fù)責(zé)把定義的字符串顯示到屏幕上

DOS操作系統(tǒng)通過(guò) int 21h 軟中斷指令來(lái)給應(yīng)用程序提供功能調(diào)用,執(zhí)行這條指令之前必須要把功能號(hào)放在AH。9號(hào)功能就是往屏幕上顯示一條字符串,要求段寄存器DS和存段內(nèi)偏移的DX共同指向要顯示的字符串的起始位置。故offset操作符取message地址的16位段內(nèi)偏移傳送到DX寄存器,再執(zhí)行軟中斷指令顯示字符串

不加offset操作符傳送的是內(nèi)容而不是地址

最后調(diào)用DOS操作系統(tǒng) int 21h 的4C號(hào)功能結(jié)束當(dāng)前進(jìn)程,回收其占用的內(nèi)存空間

?

?

以后編寫匯編語(yǔ)言程序時(shí)就可以參考這個(gè)模板來(lái)寫

;1) 完整段定義的程序結(jié)構(gòu)STACK SEGMENT PARA STACK 'STACK'DB 500 DUP(0) STACK ENDS DATA SEGMENT....... DATA ENDS CODE SEGMENTASSUME CS:CODE,DS:DATA,ES:DATA,SS:STACK START:MOV AX,DATAMOV DS,AX.......MOV AH,4CHINT 21H CODE ENDSEND START

MASM的高版本還支持簡(jiǎn)化段定義的寫法

;2) 簡(jiǎn)化段定義的程序結(jié)構(gòu).MODEL SMALL ;存儲(chǔ)模型:小型,16位匯編 .STACK 100H ;定義堆棧段及其大小 .DATA ;定義數(shù)據(jù)段 ....... ;數(shù)據(jù)聲明 .CODE ;定義代碼段START: ;起始執(zhí)行地址標(biāo)號(hào)MOV AX,@DATA ;數(shù)據(jù)段地址MOV DS,AX ;存入數(shù)據(jù)段寄存器....... ;具體程序代碼MOV AH,4CH INT 21HEND START ;程序結(jié)束

然后現(xiàn)場(chǎng)演示運(yùn)行了下Hello world程序

?

?

編譯、鏈接和運(yùn)行程序

用UltraEdit軟件打開(kāi)Hellp.exe,對(duì)其結(jié)構(gòu)進(jìn)行了簡(jiǎn)單的分析

注意x86處理器數(shù)據(jù)采用小端存儲(chǔ)

用二進(jìn)制查看軟件打開(kāi)可執(zhí)行文件Hello.exe。后半部分和源程序內(nèi)容有對(duì)應(yīng)關(guān)系,前半部分是DOS操作系統(tǒng)下可執(zhí)行文件的文件頭,有一些固定的格式,如微軟的操作系統(tǒng)下可執(zhí)行文件的一個(gè)標(biāo)志就是前兩個(gè)字節(jié)固定為"4D 5A"

文件頭是編譯程序生成的,會(huì)記錄DOS操作系統(tǒng)在執(zhí)行該可執(zhí)行文件之前這些寄存器的初值怎么設(shè)置。操作系統(tǒng)從磁盤把這個(gè)可執(zhí)行文件往內(nèi)存裝時(shí),會(huì)分析利用文件頭的一些信息,分析完之后可能就會(huì)丟棄文件頭。編譯程序用的地址是邏輯地址,它總認(rèn)為地址是從0開(kāi)始的,所以他會(huì)認(rèn)為你定義的堆棧段是從地址0開(kāi)始的,相對(duì)應(yīng)的代碼段就從0080開(kāi)始,段的起始地址高16位是0008,故CS的初值應(yīng)為0008。程序的入口點(diǎn)就是代碼段的第一條指令,段內(nèi)偏移是0,故IP的初值是0000。堆棧段從邏輯地址0開(kāi)始,故SS的初值應(yīng)為0。SP的初值為0064,跟x86處理器對(duì)堆棧的管理方式有關(guān)系

x86處理器棧頂是小地址,棧底是大地址。16位模式下堆棧里的每個(gè)數(shù)據(jù)必須都是16位,占2個(gè)字節(jié)2個(gè)地址。該程序定義堆棧時(shí)申請(qǐng)了100B的堆棧空間,邏輯地址從0開(kāi)始。x86處理器SP永遠(yuǎn)指向棧頂上的有用元素,程序剛開(kāi)始運(yùn)行堆棧是空的,SP指向邏輯地址100 (64h)

文件頭記錄了堆棧段和代碼段寄存器的初值,但沒(méi)有記錄數(shù)據(jù)段寄存器的初值。DOS操作系統(tǒng)裝載可執(zhí)行文件之后,DS另作他用,指向用于記錄命令行參數(shù)的數(shù)據(jù)結(jié)構(gòu)程序段前綴PSP,故數(shù)據(jù)段寄存器得由代碼段里的指令初始化,令其指向自己所定義的數(shù)據(jù)段

?

將代碼段編譯之后產(chǎn)生的這些機(jī)器碼用反匯編工具轉(zhuǎn)化成匯編語(yǔ)言的形式。代碼段的前3個(gè)字節(jié)對(duì)應(yīng)的是MOV AX,7,把立即數(shù)7傳送到AX。目標(biāo)寄存器AX16位,故立即數(shù)7也用2字節(jié)16位來(lái)存儲(chǔ),編譯的機(jī)器碼3個(gè)字節(jié)后2個(gè)字節(jié)存儲(chǔ)立即數(shù)7,第1個(gè)字節(jié)存的是該指令的操作碼還有AX寄存器的3位編號(hào)。后面的也類似

把反匯編的結(jié)果跟源代碼比較,可以發(fā)現(xiàn)mov ax,data中定義的數(shù)據(jù)段名稱編譯后變成立即數(shù)7,對(duì)應(yīng)數(shù)據(jù)段起始地址的高16位。這條語(yǔ)句經(jīng)過(guò)編譯程序編譯后產(chǎn)生的機(jī)器指令是把立即數(shù)7傳送到AX。類似的還有mov dx,offset message

?

操作系統(tǒng)不可能把這個(gè)程序從內(nèi)存地址0開(kāi)始裝,操作系統(tǒng)從磁盤把該可執(zhí)行文件讀出來(lái)之后會(huì)檢查足夠大的內(nèi)存空閑區(qū)域裝入,裝完后這些段寄存器應(yīng)該怎么賦初值呢?

比如說(shuō)堆棧段寄存器,它首先查文件頭,文件頭里規(guī)定的初值為0,在0的基礎(chǔ)上再加上起始的地址的段寄存器的內(nèi)容,初始化代碼段寄存器也類似。數(shù)據(jù)段寄存器的初值文件頭里并沒(méi)有規(guī)定,操作系統(tǒng)在裝載這個(gè)程序到內(nèi)存,起始地址確定之后需要修改代碼段。文件頭中有重定位項(xiàng),該程序只有1個(gè)重定位項(xiàng),這2個(gè)字節(jié)相當(dāng)于指針,指向文件頭的另外一個(gè)位置,從該位置開(kāi)始的2個(gè)16位字分別代表段內(nèi)偏移和段起始地址的高16位,它們共同指向代碼段中需要重定位的地方

?

8086的內(nèi)存管理引入分段機(jī)制,第一個(gè)目的是為了擴(kuò)大可尋址的范圍,第二個(gè)目的是能夠?qū)崿F(xiàn)程序在內(nèi)存的任意位置浮動(dòng),一個(gè)程序在內(nèi)存里任何一個(gè)地址開(kāi)始裝,只需要重新初始化段寄存器的內(nèi)容

?

然后驗(yàn)證了一下可執(zhí)行文件的具體格式

?

接下來(lái)再看32位的Hello world匯編程序,沒(méi)有用到通用寄存器,只是2個(gè)函數(shù)調(diào)用

32位應(yīng)該是不要求的,但是后面講課時(shí)涉及的比較多,所以這里簡(jiǎn)單記一下

.386 ;告訴編譯程序要產(chǎn)生32位的機(jī)器指令 .model flat,stdcall ;定義內(nèi)存模型,如果這段程序要運(yùn)行在Windows操作系統(tǒng)下,必須用flat平坦型。平坦的內(nèi)存模型理解成只分頁(yè)不分段 ;函數(shù)調(diào)用參數(shù)傳遞的順序置為stdcall,通過(guò)堆棧向函數(shù)傳遞參數(shù);利用Windows給應(yīng)用程序提供的2個(gè)函數(shù)(子程序),這2個(gè)函數(shù)在代碼里并沒(méi)有,用之前需要聲明原型,比如函數(shù)的名稱,函數(shù)的參數(shù)和參數(shù)類型 ;DOS操作系統(tǒng)通過(guò)軟中斷給應(yīng)用程序提供功能調(diào)用,Windows通過(guò)函數(shù)API的形式給應(yīng)用程序提供功能調(diào)用MessageBoxA PROTO, ; 匯編里用PROTO偽指令聲明函數(shù)原型 hWnd:DWORD, ; 句柄,指向該窗口所屬的父窗口,沒(méi)有父窗口該參數(shù)給0lpText:PTR BYTE, ; 指針,指向一個(gè)要在窗口內(nèi)部顯示的字符串lpCaption:PTR BYTE ; 指針,指向一個(gè)要顯示在窗口標(biāo)題欄上的字符串style:DWORD ; 調(diào)用時(shí)給0,顯示一個(gè)最簡(jiǎn)單的窗口,只有確定按鈕ExitProcess PROTO,exitCode:DWORD ; 如果程序正常結(jié)束,給參數(shù)0.data szCaption db 'A MessageBox !',0 szText db 'Hello, World !',0 .code ;4個(gè)壓棧指令傳參分別對(duì)應(yīng)style,lpCaption,lpText,hwnd start: push 0 ; MB_OKpush offset szCaption push offset szTextpush 0 ; NULLcall MessageBoxA ; 顯示一個(gè)窗口push 0call ExitProcess ; 結(jié)束當(dāng)前進(jìn)程 end start

然后看了一下該程序編譯、鏈接、運(yùn)行的過(guò)程

?

Intel微處理器的組成結(jié)構(gòu)

部分32位x86處理器的內(nèi)部寄存器

增加的段寄存器FS和GS也是用來(lái)訪問(wèn)數(shù)據(jù)的,訪問(wèn)數(shù)據(jù)時(shí)默認(rèn)的段寄存器仍是DS。32位匯編里普通應(yīng)用程序沒(méi)有權(quán)限修改段寄存器的內(nèi)容,所以也不用太關(guān)心

?

通用寄存器主要用于算術(shù)運(yùn)算和數(shù)據(jù)傳送

每個(gè)寄存器可作32位或16位使用。一些16位的寄存器也可以作為兩個(gè)單獨(dú)的8位使用,其余通用寄存器的低16位有獨(dú)立的名字,但不能進(jìn)一步細(xì)分

?

EAX, EBX, ECX, EDX : 高16位不能單獨(dú)使用,低16位可以單獨(dú)使用,目的是為了和8086兼容

ESI, EDI, EBP, ESP : 下面列出的16位寄存器通常只在編寫運(yùn)行于實(shí)地址模式下的程序時(shí)才使用,即編寫32位匯編,必須得用32位。編寫16位匯編,必須得用16位

?

?

匯編語(yǔ)言基礎(chǔ)(二)

匯編語(yǔ)言的基本元素

1.算術(shù)運(yùn)算符號(hào)

匯編語(yǔ)言里面的表達(dá)式最終得到的就是一個(gè)立即數(shù)。如mov AL 15/5*2,這條語(yǔ)句編譯之后并不會(huì)產(chǎn)生除法指令和乘法指令,編譯程序會(huì)計(jì)算表達(dá)式,產(chǎn)生機(jī)器指令把立即數(shù)6傳送到AL寄存器

?

2.標(biāo)識(shí)符

程序員選擇的名字,用來(lái)識(shí)別變量、常量、過(guò)程或代碼標(biāo)號(hào)

這個(gè)標(biāo)識(shí)符本質(zhì)上就是一個(gè)用符號(hào)表示的內(nèi)存地址

  • 可包含1~247個(gè)字符
  • 大小寫不敏感。(匯編器加“-cp”參數(shù)則大小寫敏感)
  • 第一個(gè)字符必須是字母(A~Z和a~z)、下劃線(_)、@、? 或 $,后續(xù)字符可以是數(shù)字
  • 不能與保留字相同
  • 盡量避免用 “@” 和 “_” 作為第一個(gè)字符,因?yàn)樗鼈兗从糜趨R編器,也用于高級(jí)語(yǔ)言編譯器

?

3.指令

程序被加載至內(nèi)存開(kāi)始運(yùn)行后,由處理器執(zhí)行的語(yǔ)句

?

4.定義數(shù)據(jù)

?

?

.data value1 BYTE 10h value2 BYTE ? list1 BYTE 10,20,30,40BYTE 50,60,70,80 list2 BYTE 32,41h,00100010b,'a' greeting BYTE "Good afternoon",0dh,0ah,0 array WORD 5 DUP(?) ;五個(gè)未初始化的值 value3 DWORD 12345678h

?

PTR操作符

Intel處理器采用小端存儲(chǔ)方式

.data myDouble DWORD 12345678h .code mov ax,myDouble ;錯(cuò)誤 mov ax,WORD PTR myDouble ;ax = 5678h mov ax,WORD PTR [myDouble+2] ;ax = 1234h mov bl,BYTE PTR myDouble ;bl = 78h

?

5.符號(hào)常量

不是變量,不占用任何實(shí)際的存儲(chǔ)空間。常量的定義語(yǔ)句編譯之后不會(huì)產(chǎn)生任何機(jī)器指令,也不會(huì)產(chǎn)生任何數(shù)據(jù)

  • 等號(hào)偽指令

    COUNT = 500 ;給編譯程序傳達(dá)一個(gè)信息,告訴它后面不想直接寫500,用COUNT來(lái)代替 .data ...... array WORD COUNT DUP(0) ...... .code......mov cx,COUNT ;產(chǎn)生的機(jī)器指令把500立即數(shù)傳送到cx寄存器 L1: ............loop L1......
  • EQU偽指令

  • TEXTEQU偽指令

?

;計(jì)算數(shù)組和字符串的大小 list1 BYTE 10,20,30,40 List1Size = ($-list1) ;數(shù)組元素所占的字節(jié)數(shù)。微軟的宏匯編語(yǔ)法中,'$'代表當(dāng)前語(yǔ)句的地址myString BYTE "This is a long string,"BYTE " Containing any number"BYTE " of characters",0dh,0ah MyString_len = ($ - myString) ;字符串占的字節(jié)數(shù),也就是字符串里字符的個(gè)數(shù)list2 WORD 1000h,2000h,3000h,4000h ;注意數(shù)組元素的類型是WORD,16位占2個(gè)字節(jié)2個(gè)地址 List2Size = ($ - list2)/2

?

數(shù)據(jù)傳送、尋址和算術(shù)運(yùn)算

數(shù)據(jù)傳送指令

1.MOV指令

MOV指令需要遵循的規(guī)則:

  • 兩個(gè)操作數(shù)的尺寸必須一致

    .DATA VAR1 WORD 30 VAR2 WORD 50 .CODE......MOV AL,VAR1 ;×MOV DX,AL ;×
  • 兩個(gè)操作數(shù)不能同時(shí)為內(nèi)存操作數(shù),要通過(guò)一個(gè)通用寄存器作為中介

    MOV VAR2 VAR1 ;×
  • 目的操作數(shù)不能是CS,EIP和IP,想改這幾個(gè)寄存器的內(nèi)容另有專門的指令

  • 立即數(shù)不能直接送至段寄存器

    MOV DS,7 ;× MOV DS,@DATA ;×,編譯之后產(chǎn)生的是一個(gè)立即數(shù)

?

MOV指令格式:

mov reg,reg mov mem,reg mov reg,mem mov mem,imm mov reg,imm

reg --> 寄存器,mem --> 內(nèi)存變量,imm --> 立即數(shù)

x86處理器其他的兩個(gè)操作數(shù)指令,其實(shí)就是支持類似這幾種格式

?

內(nèi)存之間的移動(dòng)通過(guò)寄存器暫存

.data var1 WORD ? var2 WORD ? .code mov ax,var1 mov var2,ax

?

2.XCHG指令

含義:exchange data,交換兩個(gè)操作數(shù)的內(nèi)容

格式:

xchg reg,reg xchg reg,mem xchg mem,reg

?

交換兩個(gè)內(nèi)存操作數(shù):利用寄存器,MOV與XCHG結(jié)合使用

mov ax,val1 xchg ax,val2 mov val1 ax

?

RISC結(jié)構(gòu)的處理器沒(méi)有這樣的指令,要實(shí)現(xiàn)xchg ax,bx這樣兩個(gè)寄存器之間的交換,可以有好幾種方法:

;方法一:用另外一個(gè)寄存器作為中介 mov cx,ax mov ax,bx mov bx,cx;方法二:通過(guò)堆棧 push ax mov ax,bx pop bx;方法三:用異或指令 xor ax,bx xor bx,ax xor ax,bx

?

?

直接偏移操作數(shù)(直接尋址)

MOV AL 7 ;把立即數(shù)7傳送到AL寄存器

這條指令源操作數(shù)是立即數(shù),立即尋址。目的操作數(shù)寫的是寄存器的助記符,經(jīng)過(guò)編譯之后產(chǎn)生的機(jī)器指令里面存的是這個(gè)寄存器的編號(hào),寄存器尋址

要訪問(wèn)的數(shù)據(jù)在內(nèi)存里面,指令中直接給出內(nèi)存地址,這樣叫直接尋址。我們?cè)趯憛R編程序時(shí)想直接尋址,后面直接給內(nèi)存地址太不直觀,還得數(shù)究竟它放的邏輯地址是什么,這本來(lái)是可以交給編譯程序來(lái)做的。所以在定義數(shù)據(jù)段里那些變量的時(shí)候要給變量起名字,用這個(gè)名字來(lái)表示內(nèi)存地址,這本質(zhì)上也屬于直接尋址

變量、數(shù)組、字符串、子程序的名字在本質(zhì)上來(lái)講都是一個(gè)用符號(hào)來(lái)表示的內(nèi)存地址

.data arrayB BYTE 10h,20h,30h,40h,50h ;arrayB這個(gè)符號(hào)本質(zhì)上來(lái)講就是數(shù)組的首地址(邏輯地址),或者說(shuō)數(shù)組第0個(gè)元素的地址 .code mov al,arrayB ; AL=10h ;在代碼段里直接引用這個(gè)符號(hào)地址,它指向數(shù)組的第0個(gè)元素,把第0個(gè)元素傳送到AL寄存器,屬于直接尋址mov al,[arrayB+1] ; AL=20h ;第一個(gè)元素。編譯程序完成首地址+偏移量的加法,結(jié)果就是一個(gè)邏輯地址,仍屬于直接尋址 ;MASM并不要求一定要使用方括號(hào) mov al,[arrayB+2] ; AL=30hmov al,[arrayB+20] ; AL=?? ;匯編語(yǔ)言不管是編譯程序還是執(zhí)行時(shí),DOS操作系統(tǒng)都不會(huì)做數(shù)組的越界檢查 ;字和雙字?jǐn)?shù)組 .data arrayW WORD 100h,200h,300h .code mov ax,arrayW ; AX=100h mov ax,[arrayW+2] ; AX=200h 字占2個(gè)字節(jié)2個(gè)地址,數(shù)組首地址基礎(chǔ)上+2指向數(shù)組第一個(gè)元素.data arrayD DWORD 10000h,20000h .code mov eax,arrayD ; EAX=10000h mov eax,[arrayD+4] ; EAX=20000h 雙字32位占4個(gè)字節(jié)4個(gè)地址

?

常用的算術(shù)運(yùn)算類指令

1.ADD指令

將同尺寸的源操作數(shù)和目的操作數(shù)相加,結(jié)果在目的操作數(shù)中(不改變?cè)床僮鲾?shù))

格式:同MOV指令,add 目的操作數(shù) 源操作數(shù)

.data var1 DWORD 10000h var2 DWORD 20000h .code mov eax,var1 add eax,var2 ;30000h

?

2.SUB指令

將源操作數(shù)從目的操作數(shù)中減掉,結(jié)果在目的操作數(shù)中(不改變?cè)床僮鲾?shù))

格式:與MOV、ADD指令相同,sub 目的操作數(shù) 源操作數(shù)

.data var1 DWORD 30000h var2 DWORD 10000h .code mov eax,var1 sub eax,var2 ;20000h

影響的標(biāo)志位:CF、ZF、SF、OF、AF、PF

?

3.NEG指令

含義:negate, 求負(fù)

該指令認(rèn)為操作數(shù)為一個(gè)有符號(hào)數(shù),是補(bǔ)碼。將操作數(shù)按位取反、末位加1

格式:

neg reg meg mem

影響的標(biāo)志位:CF、ZF、SF、OF、AF、PF

?

;例子:實(shí)現(xiàn)算術(shù)表達(dá)式 Rval = -Xval + (Yval-Zval).data Rval SDWORD ? ;微軟宏匯編高版本新引入的變量類型SDWORD,有符號(hào)的32位整數(shù),理解成32位補(bǔ)碼 Xval SDWORD 26 Yval SDWORD 30 Zval SDWORD 40 .code mov eax,Xval neg eax ; EAX = -26 mov ebx,Yval sub ebx,Zval ; EBX = -10 add eax,ebx mov Rval,eax ; -36

?

算術(shù)運(yùn)算影響的標(biāo)志

1.零標(biāo)志位

mov cx,1 sub cx,1 ; ZF = 1 mov ax,0FFFFh ; 全1理解成補(bǔ)碼,真值就是-1 inc ax ; ZF = 1 inc ax ; ZF = 0

?

2.符號(hào)標(biāo)志位

mov cx,0 sub cx,1 ; SF = 1 add cx,2 ; SF = 0

?

3.進(jìn)位標(biāo)志位

INC和DEC指令不影響進(jìn)位標(biāo)志

mov al,0FFh add al,1 ; CF = 1mov ax,00FFh add ax,1 ; CF = 0mov ax,0FFFFh add ax,1 ; CF = 1mov al,1 sub al,2 ; CF = 1。最高位向更高位有進(jìn)位或借位時(shí)置1

?

4.溢出標(biāo)志位

OF=Cn⊕Cn?1OF=C_n\oplus C_{n-1}OF=Cn?Cn?1?。其中CnC_nCn?為符號(hào)位產(chǎn)生的進(jìn)位,即標(biāo)志位CFCFCFCn?1C_{n-1}Cn?1?為最高有效位向符號(hào)位產(chǎn)生的進(jìn)位

mov al,+127 add al,1 ; OF = 1mov al,-128 sub al,1 ; OF = 1mov al,-128 ; AL = 10000000b neg al ; AL = 10000000b, OF = 1mov al,+127 ; AL = 01111111b neg al ; AL = 10000001b, OF = 1。

?

CPU如何知道一個(gè)數(shù)字是有符號(hào)的還是無(wú)符號(hào)的?

CPU并不知道——只有程序員才知道。CPU在執(zhí)行指令之后機(jī)械地設(shè)置各種狀態(tài)標(biāo)志,它并不知道那些對(duì)程序員是重要的,程序員自己來(lái)選擇哪些標(biāo)志和忽略哪些標(biāo)志

?

;例子程序(AddSub3).386 .MODEL flat, stdcall .STACK 4096 ExitProcess PROTO,dwExitCode:DWORD ;PROTO偽指令左側(cè)跟函數(shù)的名字,右側(cè)是函數(shù)的參數(shù)和參數(shù)類型.data Rval SDWORD ? Xval SDWORD 26 Yval SDWORD 30 Zval SDWORD 40 .code main PROC ;"主程序的名稱 PROC"開(kāi)始,"相同的名稱 ENDP"作為結(jié)尾;主程序的名稱可以隨便起,本質(zhì)是一個(gè)用符號(hào)表示的內(nèi)存地址,它所定義的就是這個(gè)代碼段 ;的第一條指令的地址,是程序的入口點(diǎn)mov ax,1000h ; INC and DECinc ax ; 1001hdec ax ; 1000h; Expression: Rval = -Xval + (Yval - Zval)mov eax,Xvalneg eax ; EAX = -26mov ebx,Yval sub ebx,Zval ; EBX = -10add eax,ebxmov Rval,eax ; -36; Zero flag example:mov cx,1sub cx,1 ; ZF = 1mov ax,0FFFFh inc ax ; ZF = 1; Sign flag example:mov cx,0sub cx,1 ; SF = 1mov ax,7FFFh add ax,2 ; SF = 1; Carry flag examplemov al,0FFhadd al,1 ; CF = 1, AL = 00; Overflow flag examplemov al,+127 add al,1 ; OF = 1mov al,-128sub al,1 ; OF = 1INVOKE ExitProcess,0 ;32位的匯編最后都要調(diào)用操作系統(tǒng)結(jié)束當(dāng)前進(jìn)程的函數(shù),該函數(shù)調(diào)用前要聲明原型;引入INVOKE偽指令使帶參數(shù)的函數(shù)在調(diào)用的時(shí)候可以一行寫完,后面跟函數(shù)名和參數(shù)main ENDP END main

然后用Visual Studio演示了一下運(yùn)行該程序

?

間接尋址

1.間接操作數(shù)(寄存器間接尋址)

把指針寄存器外加中括號(hào)。它其實(shí)就是一個(gè)指針,指向內(nèi)存的某一個(gè)位置

;32位匯編:三個(gè)雙字相加.data arrayD DWORD 10000h,20000h,30000h .code mov esi,OFFSET arrayD ;OFFSET操作符取數(shù)組的首地址傳送到指針寄存器,引用數(shù)組名,數(shù)組名本質(zhì)上是數(shù)組的首地址;指針寄存器里存的是32位的段內(nèi)偏移,默認(rèn)的段寄存器仍然是數(shù)據(jù)段寄存器DS,DS里存的是段表的行號(hào),該指令執(zhí)行時(shí)會(huì)根據(jù)DS的內(nèi)容查段表對(duì)應(yīng)的行,從該行得到段的起始地址。段的起始地址加指針寄存器的段內(nèi)偏移,結(jié)果就是內(nèi)存地址,然后訪問(wèn)內(nèi)存中的數(shù)組元素;代碼段并沒(méi)有初始化數(shù)據(jù)段寄存器,在32位保護(hù)模式下只有最高特權(quán)級(jí)的代碼,如操作系統(tǒng)內(nèi)核才有權(quán)限修改段寄存器的內(nèi)容,普通的應(yīng)用程序運(yùn)行在最低特權(quán)級(jí)3下沒(méi)有權(quán)限修改段寄存器的內(nèi)容的;16位的匯編段寄存器要由程序自己管理mov eax,[esi] ;寄存器間接尋址,訪問(wèn)數(shù)組的第0個(gè)元素add esi,4 ;數(shù)組元素32位占4個(gè)字節(jié),指針+4指向數(shù)組的第1個(gè)元素 add eax,[esi] add esi,4 add eax,[esi] ;16位匯編:三個(gè)字相加.data arrayW WORD 1000h,2000h,3000h .code mov ax,@data        mov ds,ax ;初始化數(shù)據(jù)段寄存器mov si,OFFSET arrayW ;OFFSET操作符取數(shù)組首地址,或者叫16位的段內(nèi)偏移傳送到指針寄存器mov ax,[si] ;默認(rèn)的段寄存器還是數(shù)據(jù)段寄存器,把數(shù)據(jù)段寄存器的內(nèi)容段起始地址的高16位讀出,末尾添4個(gè)0構(gòu)成20位的段起始地址,再加上指針寄存器里的16位段內(nèi)偏移,結(jié)果為20位的內(nèi)存地址。訪問(wèn)內(nèi)存剛好對(duì)應(yīng)數(shù)組的第0個(gè)元素,從這個(gè)地址開(kāi)始連續(xù)傳送2個(gè)字節(jié)至AXadd si,2 add ax,[si] add si,2 add ax,[si]

?

間接操作數(shù)可以是任何用方括號(hào)括起來(lái)的32位通用寄存器(EAX,EBX,ECX,EDX,ESI,EDI,EBP,ESP)。實(shí)地址模式下只能用SI,DI,BX,BP。通常盡量避免使用BP(BP默認(rèn)的段寄存器是SS,常用來(lái)尋址堆棧而不是數(shù)據(jù)段)

?

PTR與間接操作數(shù)的聯(lián)合使用

inc [esi] ; error: operand must have size. +1指令只有一個(gè)操作數(shù),并且還是一個(gè)指針,指向一個(gè)內(nèi)存位置,不知道存的是8位還是16位,32位inc BYTE PTR [esi] ; 認(rèn)為是8位數(shù)據(jù)

?

2.變址操作數(shù)(寄存器相對(duì)尋址)

.data arrayB BYTE 10h,20h,30h .code mov esi,0 ; 要訪問(wèn)的數(shù)組元素編號(hào)作為偏移量放在指針寄存器 mov al,[arrayB + esi] ; AL = 10h mov al,arrayB[esi] ; 同上另一種格式 mov esi,OFFSET arrayB mov al,[esi] ; AL = 10h mov al,[esi+1] ; AL = 20h mov al,[esi+2] ; AL = 30h

?

實(shí)模式下只能使用SI,DI,BX,BP寄存器。(盡量避免使用BP寄存器)

?

?

JMP和LOOP指令

1.JMP指令

top:...jmp top ;repeat the endless loop

?

2.LOOP指令

格式:LOOP 目的地址

LOOP指令的執(zhí)行:

在實(shí)地址模式下,用做默認(rèn)循環(huán)計(jì)數(shù)器的是CX而不是ECX

?

mov ax,0mov ecx,5 L1: inc ax loop L1 ;循環(huán)體的第一條指令必須要給標(biāo)號(hào)。循環(huán)體的最后一條指令要用loop,后面跟這個(gè)標(biāo)號(hào);循環(huán)結(jié)束時(shí),AX=5 ECX=0

?

循環(huán)的嵌套

.data count DWORD ? .codemov ecx,100 L1: push ecx ; 將循環(huán)計(jì)數(shù)器的內(nèi)容,即外層循環(huán)的當(dāng)前次數(shù)保存mov ecx,20 ; 重新設(shè)置循環(huán)計(jì)數(shù)器的內(nèi)容 L2: ..loop L2pop ecx ; 恢復(fù)循環(huán)計(jì)數(shù)器原來(lái)的內(nèi)容 loop L1

?

;例子:整數(shù)數(shù)組求和; This program sums an array of words. (SumArray.asm) .386 .MODEL flat, stdcall .STACK 4096 ExitProcess PROTO,dwExitCode:DWORD .data intarray WORD 100h,200h,300h,400h .code main PROCmov edi,OFFSET intarray ; address of intarraymov ecx,LENGTHOF intarray ; loop countermov ax,0 ; zero the accumulator L1: add ax,[edi] ; add an integeradd edi,TYPE intarray ; point to next integerloop L1 ; repeat until ECX = 0INVOKE ExitProcess,0 main ENDP END main

?

;例子:拷貝字符串; This program copies a string. (Copystr.asm) .386 .MODEL flat, stdcall .STACK 4096 ExitProcess PROTO,dwExitCode:DWORD .data source BYTE "This is the source string",0 target BYTE SIZEOF source DUP(0) .code main PROCmov esi,0 ; index registermov esi,SIZEOF source ; loop counter L1: mov al,source[esi] ; get a character from sourcetarget[esi],al ; store it in the targetinc esi ; move to next characterloop L1 ; repeat for entire stringINVOKE ExitProcess,0 main ENDP END main

然后用Visual Studio演示了一下運(yùn)行該程序

?

過(guò)程

與外部庫(kù)鏈接

鏈接庫(kù)如何工作?

假設(shè)程序要調(diào)用名為WriteString的過(guò)程在控制臺(tái)上顯示字符串,這個(gè)函數(shù)在另外一個(gè)庫(kù)里,并沒(méi)有在源代碼文件中,則:

1.程序中要用PROTO偽指令聲明要調(diào)用的程序

例:Irvine32.inc 中包含如下語(yǔ)句

WriteString PROTO

2.用一條CALL指令執(zhí)行WriteString過(guò)程

call WriteString

3.當(dāng)程序被編譯時(shí),編譯器知道操作碼但不知道地址碼,因?yàn)檫@個(gè)函數(shù)的代碼不在當(dāng)前文件中,它為CALL指令的目標(biāo)地址留出空白,該空白將由鏈接器在鏈接時(shí)填充

4.鏈接器在鏈接庫(kù)中查找WriteString這個(gè)名字,從庫(kù)中提取函數(shù)代碼,跟編譯產(chǎn)生的目標(biāo)文件鏈接到一起形成可執(zhí)行文件,鏈接到一起之后這個(gè)函數(shù)的首地址邏輯地址才知道,再由鏈接器負(fù)責(zé)把WriteString的首地址填到CALL指令留的空白的位置

?

鏈接器的命令行選項(xiàng)

之前32位匯編的例子里結(jié)束當(dāng)前程序要調(diào)用操作系統(tǒng)的函數(shù),那個(gè)函數(shù)在kernel32.lib庫(kù)文件中

例:

Link32 HelloWin.obj user32.lib kernel32.lib/subsystem:windows

Windows下同一時(shí)刻可能有多個(gè)程序在運(yùn)行,免不了要調(diào)用各種各樣Windows提供的函數(shù),包括結(jié)束當(dāng)前進(jìn)程的函數(shù),幾乎所有程序都要調(diào)用,每個(gè)程序里都會(huì)有很多這種重復(fù)的函數(shù)可執(zhí)行代碼,實(shí)際上是沒(méi)有必要的,也浪費(fèi)內(nèi)存空間

所以實(shí)際在Windows系統(tǒng)里,這些庫(kù)文件里存的所謂的這些函數(shù)的代碼其實(shí)就是函數(shù)的鏈接而不是函數(shù)真正的代碼,可以理解成庫(kù)文件里跟那個(gè)函數(shù)所對(duì)應(yīng)的代碼就是個(gè)跳轉(zhuǎn)指令,跳轉(zhuǎn)指令執(zhí)行后才會(huì)真正地跳轉(zhuǎn)到那個(gè)函數(shù)的代碼去執(zhí)行。那個(gè)函數(shù)的代碼包含在kernel32.dll動(dòng)態(tài)鏈接庫(kù)文件中,重復(fù)的函數(shù)代碼在動(dòng)態(tài)鏈接庫(kù),在內(nèi)存里只有一個(gè)副本

?

?

過(guò)程的定義和使用

1.過(guò)程的定義

子程序定義一般的結(jié)構(gòu):用PROC和ENDP偽指令來(lái)聲明,另外還必須給過(guò)程起一個(gè)名字(一個(gè)有效的標(biāo)識(shí)符),中間寫代碼,代碼的最后一條指令必須得寫ret子程序返回指令

寫主程序的時(shí)候也可以用相同的結(jié)構(gòu)來(lái)寫,主程序的結(jié)束如果是16位的匯編,通常調(diào)用DOS操作系統(tǒng)的4C號(hào)功能并且給操作系統(tǒng)返回0表示程序正常結(jié)束

如果是32位的匯編主程序結(jié)束一般結(jié)合INVOKE偽指令。INVOKE偽指令是微軟宏匯編6.0以上引入的,引入的目的就是為了帶參數(shù)的函數(shù)在調(diào)用的時(shí)候可以一行寫完,后面跟函數(shù)名和參數(shù),多個(gè)參數(shù)用 ‘,’ 隔開(kāi)

具體到這個(gè)例子,這條語(yǔ)句編譯之后會(huì)產(chǎn)生2條機(jī)器指令,首先會(huì)產(chǎn)生壓棧指令,把參數(shù)0壓入堆棧,然后再產(chǎn)生call指令調(diào)用子程序

?

2.例子:三個(gè)整數(shù)之和

SumOf PROCadd eax,ebxadd eax,ecxret SumOf ENDP

?

3.為過(guò)程添加文檔

;------------------------------------------------------------------- SumOf PROC ; ;Calculates and returns the sum of three 32-bit integers. ;Receivers: EAX, EBX, ECX, the three integers. May be ; signed or unsigned ;Returns: EAX = sum, and the status flags (Carry, ; Overflow, etc.) are changed. ;-------------------------------------------------------------------add eax,ebxadd eax,ecxret SumOf ENDP

?

4.向過(guò)程傳遞寄存器參數(shù)

.data theSum DWORD ? .code main PROCmov eax,10000h ; argumentmov ebx,20000h ; argumentmov ecx,30000h ; argumentcall Sumof ; EAX=(EAX+EBX+ECX)mov theSum,eax ; save the sum

?

例子:對(duì)整數(shù)數(shù)組求和

; ArraySum 過(guò)程:;------------------------------------------------------------------- ArraySum PROC ; ; Calculates the sum of an array of 32-bit integers ; Receives: ESI points to the array, ECX = array size ; Returns: EAX = sum of the array elements ;-------------------------------------------------------------------push esi ; save ESI, ECXpush ecxmov eax,0 ; set the sum to zero L1:add eax,[esi] ; add each integer to sumadd esi,4 ; point to next integerloop L1 ; repeat for array sizepop ecx ; restore ECX, ESIpop esiret ; sum is in EAX ArraySum ENDP ; 調(diào)用 ArraySum.data array DWORD 10000h,20000h,30000h,40000h,50000h theSum DWORD ? .code main PROC mov esi,OFFSET array ; ESI points to arraymov ecx,LENGTHOF array ; ECX = array countcall ArraySum ; calculate the summov theSum,eax ; return in EAX......

?

?

LEA DX,mess2和MOV DX,OFFSET mess2功能上等價(jià),直接引用變量的名字,取該變量的地址而不是內(nèi)容到DX寄存器。段內(nèi)偏移放在DX寄存器,而段寄存器主程序已初始化好了

整個(gè)程序總的結(jié)尾用END跟這個(gè)程序的入口點(diǎn),入口點(diǎn)應(yīng)該是主程序的名字,本質(zhì)上是主程序的第一條指令的地址。由于匯編語(yǔ)言用這種方式指明程序的入口點(diǎn),所以寫的時(shí)候也可以把子程序?qū)懺谇懊?#xff0c;主程序?qū)懺诤竺?/p>

?

運(yùn)行一下這個(gè)16位程序。在32位Windows下新建文本文件,后綴名改成.asm,打開(kāi)把代碼粘貼進(jìn)去。保存完之后再用最原始的方法在命令行方式下先后輸入編譯命令和鏈接命令,再輸入產(chǎn)生的可執(zhí)行文件名字運(yùn)行

會(huì)發(fā)現(xiàn)和想象的不太一樣,程序好像是個(gè)循環(huán)程序,循環(huán)到后面報(bào)錯(cuò)了,程序被操作系統(tǒng)強(qiáng)行關(guān)閉。為什么會(huì)這樣?

問(wèn)題出在子程序里面用壓棧指令保護(hù)現(xiàn)場(chǎng),但是返回之前沒(méi)有出棧指令恢復(fù)現(xiàn)場(chǎng),即返回指令之前少寫了POP DX

CALL指令執(zhí)行的時(shí)候CPU首先會(huì)保護(hù)當(dāng)前的斷點(diǎn),把當(dāng)前PC的內(nèi)容壓入堆棧,8086的PC對(duì)應(yīng)兩個(gè)寄存器CS和IP。這個(gè)程序CALL指令和RET指令默認(rèn)都屬于靜調(diào)用和靜返回,靜調(diào)用和靜返回只需要保護(hù)IP,段寄存器的內(nèi)容不需要保護(hù),調(diào)用返回都是在同一個(gè)段里面。所以CALL指令執(zhí)行時(shí)會(huì)首先把當(dāng)前IP的內(nèi)容壓入堆棧,它往堆棧里壓的這個(gè)地址應(yīng)該是CALL指令順序的下一條指令的地址,再跳轉(zhuǎn)到子程序執(zhí)行。子程序又會(huì)把DX原來(lái)的內(nèi)容壓入堆棧,子程序返回指令會(huì)從堆棧段棧頂彈出數(shù)據(jù)到PC,對(duì)8086就是彈到IP,少寫POP指令會(huì)導(dǎo)致把一個(gè)錯(cuò)的數(shù)彈到IP

OFFSET操作符取第一個(gè)字符串的首地址傳送到DX,第一個(gè)字符串是數(shù)據(jù)段里最開(kāi)始定義的字符串,在它之前沒(méi)有任何東西,所以它的段內(nèi)偏移應(yīng)為0,DX的內(nèi)容就是0。所以子程序執(zhí)行到返回指令時(shí),它會(huì)從堆棧里把0彈出賦值給IP。代碼段寄存器內(nèi)容不變,但是段內(nèi)偏移變?yōu)?,就會(huì)從主程序的第一條指令開(kāi)始執(zhí)行,所以會(huì)不停地來(lái)回循環(huán),在屏幕上不停地顯示那兩條字符串

而且每調(diào)用一次子程序都在堆棧里留了一個(gè)數(shù)沒(méi)有彈出,棧只申請(qǐng)了256B的空間,增長(zhǎng)到一定程度就會(huì)導(dǎo)致棧溢出,最終堆棧里的數(shù)據(jù)會(huì)覆蓋代碼段里的的指令,CPU再取指令譯碼發(fā)現(xiàn)是非法指令就產(chǎn)生中斷讓操作系統(tǒng)強(qiáng)行中止程序

?

條件處理

布爾和比較指令

1.AND指令

功能:在操作數(shù)的對(duì)應(yīng)數(shù)據(jù)位之間執(zhí)行布爾(位)”與“操作,并將結(jié)果保存在目的操作數(shù)中

格式:AND 目的操作數(shù) 源操作數(shù)

允許的操作數(shù)形式:

AND reg,reg AND reg,mem AND mem,reg AND reg,imm AND mem,imm

兩個(gè)操作數(shù)可以是8、16或32位的,但它們的尺寸必須相同

影響的標(biāo)志位:

  • 總是清除OF和CF
  • 根據(jù)結(jié)果修改SF、ZF、PF

主要用途:

  • 對(duì)特定的位清”0“,同時(shí)保留其他的位

    mov al,00111011b mov al,00001111b
  • 大寫字母與小寫字母的ASCII碼之間的關(guān)系:

    ‘a(chǎn)’:61h,即 01100001

    ‘A’:41h,即 01000001

    ;例:將字符轉(zhuǎn)換為大寫形式.data array BYTE 50 DUP(?) .codemov ecx,LENGTHOF arraymov esi,OFFSET array L1:and byte ptr [esi],11011111binc esiloop L1

?

2.OR指令

功能:按位取”或“

格式:與AND指令相同

主要用途:

  • 對(duì)特定的位置置”1“,并保留其它位

    mov al,00111011b or al,00001111b

    例:將0到9之間的整數(shù)轉(zhuǎn)換成對(duì)應(yīng)的ASCII碼數(shù)字

    方法:將位4和位5置為1

    mov dl,5 ; 二進(jìn)制值 or dl,30h ; 轉(zhuǎn)換到ASCII碼

    要調(diào)用操作系統(tǒng)的功能在屏幕上顯示必須得以ASCII碼的形式

    也可以用add dl,30h或add dl,'0'

?

3.XOR指令

功能:按位取”異或“

格式:與AND及OR指令相同

XOR指令的用途:

  • 對(duì)某些位取反,同時(shí)不影響其他的位

    0跟一個(gè)數(shù)異或還是那個(gè)數(shù),1跟一個(gè)數(shù)異或就是那個(gè)數(shù)的取反

  • 判斷16位或32位值的奇偶性

    mov ax,64C1h ; 0110 0100 1100 0001 xor ah,al ; PE,奇偶標(biāo)志被設(shè)置

    奇偶標(biāo)識(shí)位只反映運(yùn)算結(jié)果低8位里1的個(gè)數(shù)是否是偶數(shù)個(gè)

  • 簡(jiǎn)單數(shù)據(jù)加密

    將某個(gè)操作數(shù)與同樣的操作數(shù)執(zhí)行兩次異或運(yùn)算后,其值保持不變
    (X⊕Y)⊕Y=X(X\oplus Y)\oplus Y=X (XY)Y=X

4.NOT指令

功能:將操作數(shù)所有數(shù)據(jù)位取反,結(jié)果為反碼

格式:

NOT reg NOT mem

例:

mov al,11110000b not al ; AL = 00001111b

NOT指令不影響任何狀態(tài)標(biāo)志

?

布爾和比較指令

1.TEST指令

功能:兩操作數(shù)按位“與”,根據(jù)結(jié)果設(shè)置標(biāo)志位,但不回送結(jié)果(不修改目的操作數(shù))

格式:與AND指令相同

用途:測(cè)試操作數(shù)的某一位是“0”還是“1”

例子:測(cè)試多個(gè)位

想知道AL中第0位、第3位是否同時(shí)為“0”

test al,00001001b ;test bits 0 and 3

判斷ZF是否等于1

影響的標(biāo)志:清除OF、CF;修改SF、ZF、PF

?

2.CMP指令

格式:與AND指令相同。cmp 目的操作數(shù) 源操作數(shù)

功能:與減法指令一樣執(zhí)行減法操作,即目的操作數(shù)-源操作數(shù),但不回送結(jié)果,只影響標(biāo)志位

影響的標(biāo)志:根據(jù)相減結(jié)果修改OF、SF、ZF、CF、AF、PF

?

無(wú)符號(hào)操作數(shù)的比較:

有符號(hào)操作數(shù)的比較:

例:

mov ax,5 cmp ax,10 ; CF = 1mov si,105 cmp si,0 ; ZF=0,CF=0mov ax,1000 mov cx,1000 cmp cx,ax ; ZF = 1

?

條件跳轉(zhuǎn)

1.條件結(jié)構(gòu)

條件分支的實(shí)現(xiàn):

  • 使用CMP、TEST、AND之類的指令修改CPU標(biāo)志
  • 使用條件跳轉(zhuǎn)指令測(cè)試標(biāo)志值,以決定是否向新的分支轉(zhuǎn)移

例子:

cmp al,0jz L1 ;jump if ZF=1.. L1: and dl,10110000bjnz L2 ;jump if ZF=0.. L2:

?

2.跳轉(zhuǎn)指令的類型

mov al,7Fh ; (7Fh or +127) cmp al,80h ; (80h or -128) ja IsAbove ; no: 7F not > 80h jg IsGreater ; yes: +127 > -128

?

例:8位內(nèi)存操作數(shù)status中存放著同接口卡相連的外設(shè)的狀態(tài)信息

1.bit5為“1”時(shí)外設(shè)處于脫機(jī)狀態(tài),跳轉(zhuǎn)到某標(biāo)號(hào)處

mov al,status test al.00100000b jnz EquipOffline

2.bit0、bit1、bit4任何一位為“1”時(shí)跳轉(zhuǎn)到某標(biāo)號(hào)處

mov al,status test al,00010011b jnz InputDataByte

3.bit2、bit3、bit7全部為“1”時(shí)跳轉(zhuǎn)到某標(biāo)號(hào)處

mov al,status and al,10001100b cmp al,10001100b jz ResetMachine

?

例:比較V1、V2、V3三個(gè)無(wú)符號(hào)變量的值,將最小值送入AX寄存器

.data V1 WORD 23 V2 WORD 0 V3 WORD -1 .codemov ax,V1 ;assume V1 is smallestcmp ax,V2 ;if ax <= V2 thenjbe L1 ; jump to L1mov ax,V2 ;else move V2 to ax L1: cmp ax,V3 ;if ax <= V3 thenjbe L2 ; jump to L2mov ax,V3 ;else move V3 to ax L2: ......

?

然后推薦了https://godbolt.org,可以直接輸入C語(yǔ)言代碼,即時(shí)查看反匯編結(jié)果

?

整數(shù)算數(shù)指令

移位 (Shifting) 指令:

記住以下單詞:Shift, Left, Right, Arithmetic, Rotate, Carry

  • SHL 邏輯左移

  • SHR 邏輯右移

  • SAL 算術(shù)左移

  • SAR 算術(shù)右移

  • ROL 循環(huán)左移

  • ROR 循環(huán)右移

  • RCL 帶進(jìn)位的循環(huán)左移

  • RCR 帶進(jìn)位的循環(huán)右移

上述移位指令影響OF、CF

?

1.SHL指令:邏輯左移

格式:SHL 目的操作數(shù) 移位位數(shù)

SHL reg,imm8 SHL mem,imm8 SHL reg,CL SHL mem,CL

8088/8086要求imm8必須等于1。80286以上,imm8可為任意整數(shù)

CL方式可用于任何Intel x86處理器

上述格式也適用于SHR、SAL、SAR、ROR、ROL、RCR、RCL指令

源操作數(shù)可以是立即數(shù),如果是8088/8086,立即數(shù)只能是1。如果想左移多位,得把移位的次數(shù)先放到CL寄存器

?

例:無(wú)符號(hào)數(shù)與2的整數(shù)次冪做快速乘法

mov dl,5 shl dl,1 ;5*2 = 10 mob dl,10 shl dl,2 ;10*4 = 40

?

2.SAL指令:算術(shù)左移,與SHL指令等價(jià)

?

3.SHR指令:邏輯右移,最高位總是填0

格式:與SHL相同

?

例:無(wú)符號(hào)數(shù)與2的整數(shù)次冪做快速除法

mov dl,32 shr dl,1 ;32/2 = 16 mov dl,01000000b ;AL = 64 shr dl,3 ;64/8 = 8

?

4.SAR指令:算術(shù)右移,最高位填充原來(lái)的符號(hào)位

例1:

mov al,0F0h ; AL = 11110000b (-16) sar al,1 ; AL = 11111000b (-8); CF = 0

例2:有符號(hào)數(shù)的除法,-128/8=-16

mov dl,-128 ; DL = 10000000b sar dl,3 ; DL = 11110000b

?

5.ROL指令:循環(huán)左移

特點(diǎn):不丟失任何數(shù)據(jù)位

?

例1:

mov al,40h ;01000000 rol al,1 ;10000000, CF=0 rol al,1 ;00000001, CF=1 rol al,1 ;00000010, CF=0

例2:將一個(gè)字節(jié)的低4位與高4位進(jìn)行交換

mov al,26h rol al,4 ;AL = 62h

?

6.ROR指令:循環(huán)右移

例:

mov al,01h ;00000001 ror al,1 ;10000000, CF=1 ror al,1 ;01000000, CF=0

?

7.RCL和RCR

RCL指令:帶進(jìn)位的循環(huán)左移

RCR指令:帶進(jìn)位的循環(huán)右移

?

?

移位和循環(huán)移位的應(yīng)用:

  • 多雙字移位

    在數(shù)據(jù)段里定義3個(gè)元素的數(shù)組,數(shù)組元素的類型是32位雙字,這3個(gè)元素連到一塊組成96位的數(shù),小地址對(duì)應(yīng)低位數(shù)據(jù),大地址對(duì)應(yīng)高位數(shù)據(jù)。希望將其整體邏輯右移1位

    移位時(shí)從高位開(kāi)始移。邏輯右移最高位永遠(yuǎn)填0,最低位移走到CF。中間的數(shù)再移位就可以把剛才高位移走的數(shù)從CF再移到這個(gè)數(shù)里面去

  • 二進(jìn)制乘法:利用移位、相加實(shí)現(xiàn)

  • 顯示二進(jìn)制位

  • 分離位串

    例:MS-DOS的功能57h在DX中返回文件的修改時(shí)間,假設(shè)為2019年3月10日,則DX中的文件日期戳如下(年份是相對(duì)于1980年的):

    提取月可以將這個(gè)數(shù)整體地邏輯右移5位,然后再用AND指令將高12位清0只保留低4位

?

乘法和除法指令

1.MUL指令

格式(操作數(shù)為乘數(shù)):操作數(shù)可以是寄存器也可以是內(nèi)存變量,但不能是立即數(shù)。只跟一個(gè)操作數(shù),另外一個(gè)操作數(shù)是隱含的或者說(shuō)默認(rèn)的

MUL r/m8 MUL r/m16 MUL r/m32

功能:無(wú)符號(hào)乘法。將8位、16位或32位的操作數(shù)與AL、AX或EAX相乘

乘數(shù)和被乘數(shù)位數(shù)必須相等。兩個(gè)8位數(shù)相乘運(yùn)算結(jié)果用16位表示,兩個(gè)16位數(shù)相乘結(jié)果是32位,高16位在DX,低16位在AX。32位數(shù)相乘同理

作為高級(jí)語(yǔ)言來(lái)講,32位變量做各種運(yùn)算后運(yùn)算結(jié)果也會(huì)存到一個(gè)32位變量里面,但這實(shí)際上有溢出的可能,用匯編語(yǔ)言來(lái)寫可以更完備。兩個(gè)8位數(shù)相乘,運(yùn)算結(jié)果用8位表示不了,CF會(huì)置1。16位數(shù)和32位數(shù)相乘同理

例:

mov al,5h mov bl,10h mul bl ; CF = 0 ; 積在AX中,50h .data val1 WORD 2000h val2 WORD 0100h .code mov ax,val1 mul val2 ; CF = 1 ; 積在DX:AX中,00200000h

?

2.IMUL指令

有符號(hào)乘法,格式與MUL指令相同。認(rèn)為被乘數(shù)和乘數(shù)都是補(bǔ)碼,乘的結(jié)果也會(huì)用補(bǔ)碼來(lái)表示

如果積的高半部分不是低半部分的符號(hào)擴(kuò)展,置CF和OF

例:

mov al,48 ; 48D = 30H mov bl,4 imul bl ; AX = 00C0h, OF = 1mov al,-4 mov bl,4 imul bl ; AX = FFF0h, OF = 0mov ax,48 mov bx,4 imul bx ; DX:AX = 000000C0h, OF = 0

?

3.DIV指令

無(wú)符號(hào)除法

格式(操作數(shù)為除法):

DIV r/m8 DIV r/m16 DIV r/m32

功能:執(zhí)行8位、16位、32位無(wú)符號(hào)整數(shù)除法運(yùn)算

除數(shù)是8位,被除數(shù)必須是16位,商跟余數(shù)也得是8位。除數(shù)是16位和32位同理

?

例:

; 8003h/100h mov dx,0 ; clear dividend, high mov ax,8003h ; dividend, low mov cx,100h ; divisor div cx ; AX = 0080h, DX = 0003h .data dividend QWORD 0000000800300020h divisor DWORD 00000100h .code mov edx,DWORD PTR dividend + 4 ; high doubleword mov eax,DWORD PTR dividend ; low doubleword div divisor ; EAX = 08003000h, EDX = 00000020h

?

除法運(yùn)算指令可能溢出,乘法兩個(gè)n位數(shù)相乘運(yùn)算結(jié)果用2n位表示肯定不會(huì)溢出。如:

mov Ax,1000H mov BL,10H DIV BL

結(jié)果商為100H,用8位寄存器AL無(wú)法表示,除法溢出在CPU內(nèi)內(nèi)部產(chǎn)生0號(hào)中斷

有符號(hào)數(shù)的除法運(yùn)算指令為IDIV,下面幾個(gè)具體的例子會(huì)說(shuō)到

?

例1:以匯編語(yǔ)言實(shí)現(xiàn)下面的C++語(yǔ)句(使用32位無(wú)符號(hào)整數(shù)):

var4 = (var1 + var2) * var3;

?

mov eax,var1add eax,var2mul var3 ; EAX = EAX * var3jc tooBig ; unsigned overflow?mov var4,eaxjmp next tooBig: ; display error message

?

?

例2:使用32位有符號(hào)整數(shù)實(shí)現(xiàn)下面C++語(yǔ)句:

var4 = (var1 * -5) / (-var2 % var3);

?

mov eax,var2 ; begin right side neg eax ;有符號(hào)數(shù),需將被除數(shù)符號(hào)擴(kuò)展到EDX,然后用IDIV指令 cdq ; sign-extend dividend idiv var3 ; EDX = remainder mov ebx,edx ; EBX = right sidemov eax,-5 ; begin left side imul var1 ; EDX:EAX = left sideidiv ebx ; final division mov var4,eax ; quotient

cdq 把EAX的最高位符號(hào)位擴(kuò)展到EDX,x86還專門設(shè)計(jì)了類似的指令

cbw : 把AL寄存器里存的8位補(bǔ)碼擴(kuò)展到16位,存到AX

cwd : 把AX寄存器里存的6位補(bǔ)碼擴(kuò)展到32位。高16位存在DX,低16位存在AX

?

?

擴(kuò)展加法和減法

思考:用C++如何實(shí)現(xiàn)兩個(gè)128位整數(shù)相加?

1.ADC:帶進(jìn)位加

目的操作數(shù)+源操作數(shù)+進(jìn)位標(biāo)志→\to目的操作數(shù)

ADC reg,reg ADC mem,reg ADC reg,mem ADC mem,imm ADC reg,imm

?

2.SBB:帶進(jìn)位減

目的操作數(shù)-源操作數(shù)-進(jìn)位標(biāo)志→\to目的操作數(shù)

?

利用上述指令可方便地實(shí)現(xiàn)任意大小數(shù)字的減加法運(yùn)算

?

?

?

高級(jí)過(guò)程

高級(jí)語(yǔ)言如C語(yǔ)言的編譯器把參數(shù)傳遞給子程序需要借助堆棧,子程序如何把參數(shù)從堆棧里取出來(lái)?

?

堆棧框架

內(nèi)存模式:.MODEL偽指令

例:

.MODEL flat,stdcall

保護(hù)模式程序使用平坦內(nèi)存模式

?

STDCALL關(guān)鍵字:指定過(guò)程按照從右往左的順序壓入?yún)?shù)。例:

INVOKE ADDTwo,5,6

將生成如下匯編語(yǔ)言代碼:

push 6 push 5 call AddTwo

?

堆棧參數(shù)的顯式訪問(wèn):

.data sum DWORD ? .codepush 6 ; second argumentpush 5 ; first argumentcall AddTwo ; EAX = summov sum,eax ; save the sum...... AddTwo PROCpush ebp mov ebp,esp ; base of stack frame;把ESP的內(nèi)容賦值給EBP,這樣EBP和ESP同時(shí)指向當(dāng)前棧頂?shù)奈恢谩H绻竺孀映绦蚶镞€有;PUSH,POP這樣對(duì)堆棧的操作只會(huì)影響ESP的內(nèi)容,但EBP一旦賦值之后,在整個(gè)子程序范圍;內(nèi)就不會(huì)再修改mov eax,[ebp + 12] ; second argumentadd eax,[ebp + 8] ; first argumentpop ebpret 8 ; clean up the stack;首先從堆棧中彈出棧頂元素至指令指針寄存器,然后把ESP的內(nèi)容加上8,相當(dāng)于把2個(gè)參數(shù)占;用的堆棧空間也釋放了 AddTwo ENDP

?

?

子程序中定義的這些臨時(shí)變量存儲(chǔ)在堆棧中。在操作系統(tǒng)的角度來(lái)講,我們?cè)贑語(yǔ)言里寫的這個(gè)主程序也是子程序,所以主程序里定義的這些變量其實(shí)也是臨時(shí)變量,也存儲(chǔ)在堆棧中。這種情況下堆棧應(yīng)該如何管理?

在主程序之外定義的變量不在堆棧中

?

創(chuàng)建局部變量:

C++例子

void MySub() {char X = 'X';int Y = 10;char name[20];name[0] = 'B';double Z = 1.2; }

訪問(wèn)這些變量都通過(guò)EBP相對(duì)尋址

為了對(duì)齊,盡管第一個(gè)變量X是8位數(shù)據(jù),但實(shí)際上在堆棧里也會(huì)占用4個(gè)字節(jié)

?

用匯編語(yǔ)言實(shí)現(xiàn)

MySub PROCpush ebpmov ebp,espsub esp,36; create variablesmov BYTE PTR [ebp-4],'X' ; Xmov DWORD PTR [ebp-8],10 ; Ymov BYTE PTR [ebp-28],'B' ; name[0]mov DWORD PTR [ebp-32],3ff33333h ; Z(high)mov DWORD PTR [ebp-36],33333333h ; Z(low)…… ……mov esp,ebp ; destroy variablespop ebpret MySub ENDP

z采用IEEE754標(biāo)準(zhǔn)存儲(chǔ)

講了下緩沖區(qū)溢出攻擊,并解釋了在https://godbolt.org中查看該例子時(shí)存在的一些不同

?

字符串和數(shù)組

基本字符串操作指令

5組處理字節(jié)、字和雙字?jǐn)?shù)組的指令,成為基本字符串指令,但用法并不限于處理字符串?dāng)?shù)組

MOV : 數(shù)據(jù)傳送類 S : 串操作指令 B, W, D : 數(shù)組元素的類型是字節(jié),字,雙字

?

使用重復(fù)前綴

例:

main PROCmov ax,@data ;get addr of data segmov ds,ax ;initialize DSmov es,ax ;initialize ES cld ; clear direction flag mov si,OFFSET string1 ; SI points to source mov di,OFFSET string2 ; DI points to target mov cx,10 ; set counter to 10 rep movsb ; move 10 bytes

對(duì)于串操作指令。段寄存器必須用DS,指針寄存器必須用SI,這兩個(gè)寄存器指向源數(shù)組/源串。ES和DI指向目的數(shù)組/目的串

加了重復(fù)前綴rep后,這條指令會(huì)重復(fù)執(zhí)行好多次,重復(fù)次數(shù)要放在CX/ECX。指令每執(zhí)行一次首先會(huì)把CX/ECX的內(nèi)容減1,如果不為0則重復(fù)執(zhí)行這條指令。串操作指令從DS和SI指向的位置讀一個(gè)字節(jié)的數(shù)據(jù)然后把它寫入到ES和DI指向的位置。寫完了之后SI和DI的內(nèi)容加還是減由方向標(biāo)志位DF決定,DF=0則ESI、EDI自動(dòng)增加,DF=1則ESI、EDI自動(dòng)減少。加減多少取決于數(shù)組元素類型

數(shù)組元素的類型是字節(jié),并且里面存的是ASCII碼,那就是字符串

方向標(biāo)志可以通過(guò)CLD和STD指令改變:

CLD ; 清除方向標(biāo)志 STD ; 設(shè)置方向標(biāo)志

?

?

二維數(shù)組

1.基址變址操作數(shù)(基址+變址尋址)

基址變址 (base-index) 操作數(shù):將兩個(gè)寄存器的值相加(稱為基址寄存器、變址寄存器)來(lái)產(chǎn)生偏移地址

保護(hù)模式程序中,可使用任意32位通用寄存器

實(shí)地址模式下,基址寄存器訪問(wèn)數(shù)據(jù)段最好用BX(也可以用BP,但是BP一般是用來(lái)訪問(wèn)堆棧的,它的段寄存器默認(rèn)是SS)。變址寄存器可以用SI和DI

.data array WORD 1000h,2000h,3000h .codemov ebx,OFFSET arraymov esi,2 mov ax,[ebx+esi] ; AX = 2000h

?

表格的例子:

?

2.相對(duì)基址變址操作數(shù)(基址+變址+相對(duì)尋址)

相對(duì)基址變址操作數(shù):有效地址偏移=偏移+基址寄存器+變址寄存器

幾種常見(jiàn)的格式:[base + index + displacement], displacement[base + index], displacement[base][index]

偏移 (displacement) : 變量的名字;常量表達(dá)式

基址、變址:保護(hù)模式為任意32位寄存器,實(shí)地址模式為BX、BP和SI、DI

?

表格的例子:

?

結(jié)構(gòu)和宏

宏 (Macro)

命名的匯編語(yǔ)句塊。調(diào)用宏的時(shí)候,匯編語(yǔ)句塊的一份拷貝被直接插入到程序中

在程序代碼里要重復(fù)使用幾條指令,來(lái)來(lái)回回多次的寫會(huì)比較麻煩,就可以用宏來(lái)代替這幾條指令。在代碼里多次引用宏,編譯程序編譯到宏后會(huì)展開(kāi),用實(shí)際參數(shù)代替它的形式參數(shù)

宏的定義

macroname MACRO parameter-1,parameter-2...statement-list ENDM

?

例1:

?

?

?

使用I/O端口控制硬件

x86屬于獨(dú)立編址,要訪問(wèn)接口地址空間只能用IN指令和OUT指令。不管是8086還是32位、64位的CPU,接口地址都是16位的,端口地址范圍為0~\sim?FFFFh

?

IN和OUT指令

IN指令:從端口輸入一個(gè)字節(jié)、字或雙字

OUT指令:向端口輸出一個(gè)字節(jié)、字或雙字

?

指令格式:

端口地址:0~\simFFh之間的一個(gè)常量(立即數(shù)),或是包含0~\sim?FFFFh之間的值的DX寄存器

累加器:AL、AX或EAX

in al,3Ch ; input byte from port 003Ch out 3Ch,al ; output byte to port 003Ch mov dx,2A3Ch ; DX can contain a port number in ax,dx ; input word from port named in DX out dx,ax ; output word to the same port in eax,dx ; input doubleword from port out dx,eax ; output doubleword to same port

?

然后講解了PC聲音程序和實(shí)時(shí)鐘RTC兩個(gè)例子,并現(xiàn)場(chǎng)演示了一下

?

32位/64位處理器擴(kuò)展指令——多媒體/流媒體SIMD擴(kuò)展指令集

多媒體擴(kuò)展 (MMX) 指令集

SIMD : 單指令多數(shù)據(jù) Single Instruction Multiple Data

Pentium Ⅱ : 引入MMX (Multiple Media Extensions) 指令集,實(shí)現(xiàn)64位并行處理。引入8個(gè)64位MMX寄存器mm0~\simmm7

Pentium Ⅲ : 引入SSE (Streaming SIMD Extensions) 指令集,實(shí)現(xiàn)128位并行浮點(diǎn)運(yùn)算。引入8個(gè)128位MMX寄存器xmm0~\simxmm7

Pentium 4 : 引入SSE2指令集,實(shí)現(xiàn)128位并行定點(diǎn)運(yùn)算

如果要處理的是32位數(shù)據(jù),一個(gè)XXM寄存器可以存儲(chǔ)4個(gè)這樣的數(shù)據(jù),1條SSE2指令可以同時(shí)處理4對(duì)操作數(shù)得到4個(gè)結(jié)果,這就是所謂的單指令流多數(shù)據(jù)流

?

SSE2指令集

SSE2數(shù)據(jù)類型

一個(gè)XXM寄存器可以存放4個(gè)單精度浮點(diǎn)數(shù)、2個(gè)雙精度浮點(diǎn)數(shù)、16個(gè)8位整數(shù)、8個(gè)16位整數(shù)、4個(gè)32位整數(shù)、2個(gè)64位整數(shù)。SSE和SSE2指令的操作數(shù)就是XXM寄存器,因此可以實(shí)現(xiàn)單指令流多數(shù)據(jù)流,具有高并行度

?

?

匯編語(yǔ)言與高級(jí)語(yǔ)言的接口

在C語(yǔ)言中嵌入?yún)R編語(yǔ)言代碼

1.嵌入方法

//“__asm” 關(guān)鍵字//單句格式 main() {__asm MOV AH,2;__asm MOV BH,0;__asm MOV DL,20;__asm MOV DH,10; }//模塊格式 main() {__asm {MOV AH,2;MOV BH,0;MOV DL,20;MOV DH,10; } }

?

在Visual C++中使用嵌入?yún)R編的規(guī)定:

在用匯編編寫的函數(shù)中,不必保存EAX、EBX、ECX、EDX、ESI、EDI寄存器,但必須保存函數(shù)中使用的其他寄存器(如ESP、EBP、PSW等)

嵌入式匯編語(yǔ)言語(yǔ)句中,可以使用匯編語(yǔ)言格式表示整數(shù)常量(如378H),也可以采用C++的格式(如0x378)

嵌入式匯編中的標(biāo)號(hào)和C++的標(biāo)號(hào)相似,作用范圍是在定義它的函數(shù)中有效

?

?

2.程序舉例

例3:使用SSE2指令優(yōu)化程序運(yùn)行速度

已知矢量A=(a0,a1,...,aN?1)(a_0,a_1,...,a_{N-1})(a0?,a1?,...,aN?1?)?和矢量B=(b0,b1,...,bN?1)(b_0,b_1,...,b_{N-1})(b0?,b1?,...,bN?1?)?,兩個(gè)矢量的點(diǎn)乘定義為:A?B=∑i=0N?1aibiA\cdot B=\sum_{i=0}^{N-1}a_ib_iA?B=i=0N?1?ai?bi??

編寫采用SSE2指令實(shí)現(xiàn)求兩個(gè)矢量的點(diǎn)積的程序。設(shè)N=8N=8N=8?,矢量分量類型為字

采用SSE2指令中的PMADDWD(教材P83,表3.5)完成矢量的分類乘運(yùn)算和部分和,然后利用移位運(yùn)算一次求出最終結(jié)果

?

程序源代碼:

為了測(cè)試代碼運(yùn)行時(shí)間,使用了標(biāo)準(zhǔn)C提供的CLOCK函數(shù),該函數(shù)的原型和有關(guān)數(shù)據(jù)類型的聲明在 time.h 頭文件中。程序結(jié)尾希望調(diào)用操作系統(tǒng)的相關(guān)功能讓程序暫停,按任意鍵繼續(xù),因此需要包含 Window.h 頭文件。用CLOCK函數(shù)測(cè)量時(shí)間,精度只能達(dá)到毫秒級(jí),因此定義常量N讓被測(cè)試代碼執(zhí)行2億次

主程序中,start, stop變量記錄時(shí)間,其數(shù)據(jù)類型在time.h頭文件中定義。變量X存儲(chǔ)兩個(gè)向量點(diǎn)積的最終結(jié)果。i, j用于循環(huán)計(jì)數(shù)。兩個(gè)數(shù)組每個(gè)8個(gè)元素,元素的數(shù)據(jù)類型為16位短整型,用一個(gè)128位的XXM寄存器可以存儲(chǔ)整個(gè)數(shù)組。然后顯示數(shù)組A和數(shù)組B的內(nèi)容

調(diào)用CLOCK函數(shù)記錄開(kāi)始時(shí)間

然后令求向量點(diǎn)積的代碼重復(fù)執(zhí)行2億次。兩個(gè)下劃線跟asm關(guān)鍵字,大括號(hào)括起來(lái)的部分是匯編語(yǔ)言的代碼,這里大部分指令屬于SSE2指令集

分別取數(shù)組A和數(shù)組B的所有元素裝載至128位的XXM0和XXM1寄存器。PMADDWD乘法 - 累計(jì)指令的兩個(gè)操作數(shù)都是兩個(gè)128位的寄存器,也就是剛剛裝載的A和B兩個(gè)數(shù)組。這條指令的功能是兩個(gè)128位的XXM寄存器中相同位置的16位有符號(hào)整數(shù)相乘,相鄰的兩個(gè)乘積再求和。8對(duì)操作數(shù)經(jīng)過(guò)一定的運(yùn)算后得到4個(gè)結(jié)果。后面只需把這4個(gè)結(jié)果再求累加和即為2個(gè)向量的點(diǎn)積

將運(yùn)算結(jié)果寄存器的低32位也就是4個(gè)結(jié)果中的一個(gè)傳送至EAX,再右移4個(gè)字節(jié)取第二個(gè)結(jié)果傳送至EBX。普通加法指令執(zhí)行后EAX的內(nèi)容為2個(gè)結(jié)果之和。右移32位,取第三個(gè)結(jié)果至EBX,再加到EAX中。右移32位,取第4個(gè)結(jié)果至EBX,再加到EAX中。此時(shí)EAX的內(nèi)容即為兩個(gè)向量的點(diǎn)積,最終結(jié)果存入內(nèi)存的X單元

調(diào)用CLOCK函數(shù)記錄結(jié)束時(shí)間

顯示點(diǎn)積結(jié)果和代碼運(yùn)行2億次的時(shí)間(結(jié)束時(shí)間-開(kāi)始時(shí)間除以1000,時(shí)間單位為秒)

?

以下部分則是用C語(yǔ)言實(shí)現(xiàn)向量的點(diǎn)積。最后屏幕暫停,按任意鍵繼續(xù)

?

測(cè)試結(jié)果及運(yùn)行環(huán)境

可以發(fā)現(xiàn)同樣是求兩個(gè)向量的點(diǎn)積重復(fù)2億次,通過(guò)嵌入?yún)R編使用SSE2指令集實(shí)現(xiàn),可以針對(duì)特定的硬件,優(yōu)化程序的性能,其速度是用C語(yǔ)言實(shí)現(xiàn)的6.6倍。測(cè)試計(jì)算機(jī)的CPU是2008年第三季度推出的2核2線程的酷睿移動(dòng)處理器,主頻為2.26GHZ

換1臺(tái)計(jì)算機(jī)測(cè)試,這臺(tái)計(jì)算機(jī)的CPU是2007年第一季度推出的4核4線程的酷睿多面處理器,主頻為2.4GHZ,發(fā)現(xiàn)和前面的測(cè)試結(jié)果相差不大。同樣的程序?yàn)槭裁粗黝l差不多,在4核計(jì)算機(jī)上的運(yùn)行速度沒(méi)有明顯的提高?

因?yàn)檫@是一個(gè)單線程的程序,線程是操作系統(tǒng)調(diào)度的最小單位,一個(gè)線程只能在一個(gè)內(nèi)核上運(yùn)行,其運(yùn)行速度與CPU的總內(nèi)核數(shù)無(wú)關(guān)

再換一臺(tái)計(jì)算機(jī)測(cè)試,這臺(tái)計(jì)算機(jī)是2016年第一季度推出的10核20線程的至強(qiáng)處理器,主頻為2.2GHZ,與前2臺(tái)測(cè)試機(jī)的主頻相差不大,但是程序的運(yùn)行時(shí)間接近前2臺(tái)計(jì)算機(jī)運(yùn)行時(shí)間的一半,這是CPU內(nèi)部指令流水線進(jìn)一步優(yōu)化,引入了很多增強(qiáng)性能的新技術(shù)的結(jié)果。因此看一個(gè)CPU的單核性能,除了主頻之外,其體系結(jié)構(gòu)方面的改進(jìn)也非常關(guān)鍵

?

?

讓C語(yǔ)言從外部調(diào)用匯編

兩種實(shí)現(xiàn)方法:

1.嵌入?yún)R編——在C語(yǔ)言中嵌入?yún)R編語(yǔ)言代碼

優(yōu)點(diǎn):

  • 簡(jiǎn)單:無(wú)需考慮外部鏈接、命名、參數(shù)傳遞協(xié)議等問(wèn)題
  • 高效:不存在過(guò)程調(diào)用的開(kāi)銷

缺點(diǎn):不易維護(hù),不方便移植

2.模塊連接——讓C語(yǔ)言從外部調(diào)用匯編

可以采用模塊化的程序設(shè)計(jì)思路,必須用匯編語(yǔ)言實(shí)現(xiàn)的部分可以設(shè)計(jì)成一個(gè)函數(shù),存儲(chǔ)為后綴名為.asm的單獨(dú)文件,并將匯編程序文件加入到C語(yǔ)言項(xiàng)目中,在C語(yǔ)言代碼中直接調(diào)用這個(gè)用匯編語(yǔ)言實(shí)現(xiàn)的函數(shù)

?

例:

C++語(yǔ)言實(shí)現(xiàn)的主程序中需要調(diào)用外部的addem函數(shù),這個(gè)函數(shù)需要三個(gè)整型參數(shù),其功能為返回這三個(gè)參數(shù)之和。這里需要聲明一下這是一個(gè)外部的,C風(fēng)格的函數(shù),同時(shí)聲明了函數(shù)的原型

輸出字符串到屏幕,提示本程序的功能是求三個(gè)數(shù)之和。再調(diào)用addem函數(shù),傳入三個(gè)參數(shù),返回的累加和存入變量total。這條指令編譯后首先會(huì)產(chǎn)生3條壓棧指令,按照從右往左的順序分別把三個(gè)參數(shù)壓入堆棧,然后是一個(gè)子程序調(diào)用CALL指令調(diào)用函數(shù)addem,執(zhí)行時(shí)先將當(dāng)前指令指針寄存器的內(nèi)容也就是返回地址壓入堆棧,然后跳轉(zhuǎn)到用32位匯編實(shí)現(xiàn)的addem函數(shù)去執(zhí)行

.386偽指令告訴編譯程序產(chǎn)生32位的機(jī)器指令。.model偽指令定義內(nèi)存模型為平坦型。.public跟函數(shù)名稱說(shuō)明這個(gè)函數(shù)可以被外部的其他程序調(diào)用

然后是代碼段。“函數(shù)名稱 PROC”開(kāi)始,“函數(shù)名稱 ENDP”結(jié)束,最后是END偽指令,不跟程序入口點(diǎn)。注意到這里的函數(shù)名稱比主程序中引用的多了個(gè)下劃線,因?yàn)閂isual C++編譯器在編譯主程序代碼時(shí)會(huì)自動(dòng)給addem函數(shù)名稱左側(cè)加一個(gè)下劃線

將EBP原來(lái)的值壓入堆棧,將ESP的值賦給EBP,此時(shí)EBP和ESP同時(shí)指向棧頂?shù)奈恢谩:竺娴拇a如果有壓棧出棧指令只會(huì)影響ESP的內(nèi)容,EBP的內(nèi)容就此固定。通過(guò)EBP相對(duì)尋址就可以訪問(wèn)到堆棧中由主程序傳遞來(lái)的參數(shù)。取第一個(gè)參數(shù)至EAX,將第二和第三個(gè)參數(shù)加到EAX。最后恢復(fù)EBP原來(lái)的值,函數(shù)返回

在Visual C的函數(shù)調(diào)用規(guī)范中規(guī)定如果函數(shù)的返回值是一個(gè)32位整數(shù)就必須通過(guò)EAX返回

最后將函數(shù)的返回值,也就是三個(gè)參數(shù)之和顯示到屏幕上

?

通過(guò)程序調(diào)試界面的反匯編窗口,從中觀察到主程序的int total = addem( 19, 15, 25 )C++語(yǔ)句經(jīng)過(guò)編譯后產(chǎn)生6條機(jī)器指令,包括3個(gè)壓棧指令、1個(gè)子程序調(diào)用指令、1個(gè)加法指令和1個(gè)數(shù)據(jù)傳送指令。當(dāng)程序執(zhí)行到addem函數(shù)內(nèi)部求三個(gè)參數(shù)之和的代碼時(shí),堆棧的內(nèi)容如下圖所示。當(dāng)執(zhí)行出棧指令時(shí)EBP原來(lái)的值從堆棧中彈出,當(dāng)執(zhí)行子程序返回指令時(shí)返回地址被彈出,在執(zhí)行加法指令之前,堆棧的棧頂位置如下圖所示。這條加法指令將ESP的內(nèi)容加12,這就相當(dāng)于回收了三個(gè)參數(shù)占用的空間,最后把函數(shù)的返回值由EAX傳送至內(nèi)存的total變量

不同的C語(yǔ)言編譯器,其底層子程序調(diào)用的規(guī)范、參數(shù)傳遞的規(guī)則可能不同

?

高級(jí)語(yǔ)言編譯器在代碼優(yōu)化方面是卓有成效的。有些編譯器針對(duì)特有的處理器進(jìn)行了優(yōu)化,可極大提高被編譯程序的執(zhí)行速度

但是編譯器通常采用常規(guī)的優(yōu)化處理手段,對(duì)個(gè)別的特殊應(yīng)用和安裝的特殊硬件并不了解。而手動(dòng)編寫的匯編語(yǔ)言代碼可充分利用計(jì)算機(jī)系統(tǒng)的某些硬件(比如視頻顯示卡、聲卡等)的特性。在某些場(chǎng)合,匯編語(yǔ)言可以很方便地實(shí)現(xiàn)高級(jí)語(yǔ)言不提供或較難實(shí)現(xiàn)的功能

?

?

C語(yǔ)言調(diào)用匯編的其他例子

判斷有符號(hào)整數(shù)加法溢出

盡管結(jié)果顯然是錯(cuò)誤的,但C語(yǔ)言程序運(yùn)行時(shí)沒(méi)有任何警告和提示。C編譯器不會(huì)做任何有關(guān)運(yùn)算結(jié)果溢出的檢查。可以通過(guò)C嵌入?yún)R編設(shè)計(jì)一個(gè)函數(shù),來(lái)檢查兩個(gè)整型變量加法結(jié)果是否溢出。函數(shù)代碼如下:

函數(shù)接收兩個(gè)整型變量作為參數(shù)。相加后如果OF置位則跳轉(zhuǎn)返回1表示結(jié)果溢出。否則順序執(zhí)行令EAX清0,也就是函數(shù)返回0表示相加結(jié)果不溢出

匯編語(yǔ)言實(shí)現(xiàn)分支功能,前面分支的末尾必須加跳轉(zhuǎn)指令跳過(guò)后面的分支

修改一下原來(lái)做加法的C程序,增加對(duì)剛才函數(shù)的調(diào)用。然后運(yùn)行驗(yàn)證

總線技術(shù)

總線概述

總線

連接兩個(gè)以上數(shù)字系統(tǒng)元件的公共的信息通路

這是一般性的概念,實(shí)際上還有一種總線叫專用總線,總線上可能只需要連接兩個(gè)數(shù)字系統(tǒng)或兩個(gè)模塊

計(jì)算機(jī)組件間、計(jì)算機(jī)間、計(jì)算機(jī)與設(shè)備間連接的信號(hào)線和通信的公共通路

?

?

總線的分類——按連接的層次

CPU內(nèi)部有很多種不同的總線結(jié)構(gòu),比如說(shuō)單總線、雙總線、甚至是三總線結(jié)構(gòu)。這種芯片內(nèi)部的總線就叫片內(nèi)總線

一般用來(lái)連接電路板上各個(gè)芯片之間的非標(biāo)準(zhǔn)的總線叫元件級(jí)總線。比如說(shuō)早期的計(jì)算機(jī)內(nèi)存芯片是直接焊接到計(jì)算機(jī)主板上的,連接內(nèi)存芯片跟CPU芯片之間的這種總線就可以叫元件級(jí)總線

當(dāng)然最新的計(jì)算機(jī)內(nèi)存都是以內(nèi)存條的形式插到計(jì)算機(jī)主板上的,內(nèi)存條跟計(jì)算機(jī)主板之間的總線就屬于系統(tǒng)總線,指的是連接計(jì)算機(jī)系統(tǒng)內(nèi)部各個(gè)模塊之間,或者說(shuō)用來(lái)連接計(jì)算機(jī)主板跟各種插件板之間的標(biāo)準(zhǔn)的總線。因?yàn)橄到y(tǒng)總線通常在主機(jī)箱的內(nèi)部,所以也叫內(nèi)總線

通信總線用來(lái)連接計(jì)算機(jī)系統(tǒng)跟外設(shè),這種總線一般在主機(jī)箱外部,所以也叫外總線

也有一些特例,比如現(xiàn)在最普及的PCIe總線

現(xiàn)在CPU內(nèi)部通常會(huì)集成很多個(gè)CPU的內(nèi)核,還集成了內(nèi)存的控制器,包括一些高速的接口控制器。微處理器芯片內(nèi)部CPU內(nèi)核和內(nèi)存控制器還有高速的總線控制器之間的互聯(lián)通常也會(huì)采用PCIe總線。盡管最新的微處理器芯片內(nèi)部也會(huì)有PCIe總線,從制定PCIe總線規(guī)范的初衷來(lái)講,PCIe應(yīng)該屬于系統(tǒng)總線

輔存,如硬盤一般也會(huì)歸到外設(shè)里面。現(xiàn)在比較流行的固態(tài)硬盤有多種連接方式,有一種叫M.2和U.2接口,底層的通信協(xié)議仍然采用PCIe

?

?

總線的分類——按數(shù)據(jù)傳輸位數(shù)

1.并行總線

采用多條數(shù)據(jù)線對(duì)數(shù)據(jù)各位進(jìn)行同時(shí)傳輸

僅適宜計(jì)算機(jī)內(nèi)部高速部件近距離連接。高頻率使發(fā)送端原本同步的數(shù)據(jù)到達(dá)接收端時(shí)出現(xiàn)時(shí)鐘偏移,也會(huì)加劇空間距離很近的多條數(shù)據(jù)線間的串?dāng)_

典型的并行PCI總線,一般時(shí)鐘頻率就是33MHZ。后來(lái)在服務(wù)器或者工作站上采用66MHZ,頻率再高,以上這些問(wèn)題要解決起來(lái)就非常復(fù)雜

通信距離較長(zhǎng)則信號(hào)線線數(shù)比較多,也會(huì)增加總線的長(zhǎng)度進(jìn)而增加總線的成本

?

2.串行總線

采用一條數(shù)據(jù)線逐位傳輸各位數(shù)據(jù)

無(wú)需考慮時(shí)鐘偏移和串?dāng)_問(wèn)題,故可通過(guò)提高頻率來(lái)提高數(shù)據(jù)傳輸率

數(shù)據(jù)二進(jìn)制位采用差分的形式來(lái)傳遞的話就可以避免線跟線之間,或者說(shuō)外界對(duì)數(shù)據(jù)線的干擾

常用于長(zhǎng)距離通信及計(jì)算機(jī)網(wǎng)絡(luò)

在短距離應(yīng)用中性能也已超過(guò)并行總線

?

?

系統(tǒng)總線 (PCI, PCIe) 和通信總線 (USB) 一般都會(huì)有標(biāo)準(zhǔn)化的組織為它制定相應(yīng)的規(guī)范

標(biāo)準(zhǔn)化總線

由IEEE(美國(guó)電氣電子工程師協(xié)會(huì))或計(jì)算機(jī)廠商聯(lián)盟制定。對(duì)總線插槽尺寸、引腳分布、信號(hào)分布、時(shí)序控制、數(shù)據(jù)傳輸率、總線通信協(xié)議等有明確規(guī)定

顯卡電路板跟計(jì)算機(jī)主板之間相連一般采用標(biāo)準(zhǔn)的PCIe$\times$16系統(tǒng)總線

?

總線標(biāo)準(zhǔn)化的優(yōu)點(diǎn):

1.簡(jiǎn)化軟硬件設(shè)計(jì),簡(jiǎn)化系統(tǒng)結(jié)構(gòu) →\to模塊化

2.使系統(tǒng)易于擴(kuò)展、便于更新

3.便于調(diào)試、維修 →\to各插件板分別調(diào)試;一級(jí)維修

?

典型的標(biāo)準(zhǔn)化總線——內(nèi)總線

ISA總線

1981年,IBM PC/XT (8位ISA總線,基于8088)

內(nèi)存直接焊接在計(jì)算機(jī)主板上。要對(duì)計(jì)算機(jī)進(jìn)行功能擴(kuò)展,可以基于8位的ISA總線來(lái)擴(kuò)展插件板,把設(shè)計(jì)的板卡直接插到計(jì)算機(jī)主板8位的ISA總線插槽上,就相當(dāng)于對(duì)計(jì)算機(jī)系統(tǒng)的硬件進(jìn)行了一定的擴(kuò)展

1984年,IBM PC/AT (16位ISA總線,基于80286)

16位的ISA總線為了跟原來(lái)的8位兼容,在原來(lái)的8位ISA總線基礎(chǔ)上后面增加了一些相應(yīng)的信號(hào)。數(shù)據(jù)線從原來(lái)的8位擴(kuò)展到了16位,地址線從原來(lái)的20位擴(kuò)展到了24位

即設(shè)計(jì)的板卡如果基于8位的ISA總線,實(shí)際上也可以插,只不過(guò)只用到了插槽的前面這一半

1988年,以康柏 (Compaq) 公司為首,EISA (Extended ISA),32位

?

ISA總線可以簡(jiǎn)單地理解成就是8088/8086系統(tǒng)總線的延伸,16位的ISA總線也可以理解成是80286系統(tǒng)總線的延伸。常用的讀寫信號(hào),如地址線、數(shù)據(jù)線、讀寫控制信號(hào)ISA總線上面應(yīng)該都能找得到,電源、時(shí)鐘信號(hào)、跟中斷有關(guān)的信號(hào)也有

下圖的兩部分應(yīng)該在一條上,底下一截平移到了右邊顯示

?

?

PCI總線

特點(diǎn):

1.不依賴于處理器

PCI總線在制定規(guī)范時(shí)則并沒(méi)有參考任何一款處理器

ISA總線在制定規(guī)范的時(shí)候針對(duì)的就是Intel從8086到80286這一系列的微處理器,基于這樣的微處理器的系統(tǒng)總線信號(hào)定義到ISA總線上

?

2.擴(kuò)充性好

可以通過(guò)相應(yīng)的橋芯片擴(kuò)展出多條PCI總線,連接更多的外設(shè)部件

?

3.支持自動(dòng)配置

基于PCI總線的設(shè)備或板卡插到總線的擴(kuò)展插槽上,計(jì)算機(jī)啟動(dòng)時(shí)會(huì)自動(dòng)識(shí)別插接到擴(kuò)展插槽上的設(shè)備并且對(duì)設(shè)備內(nèi)部的各種資源比如占用的接口地址、內(nèi)存范圍進(jìn)行自動(dòng)配置

ISA總線通常不支持。事先要把ISA總線的板卡(上面一般會(huì)有一些撥動(dòng)開(kāi)關(guān),開(kāi)關(guān)撥到不同狀態(tài)占用的接口地址范圍是不同的)插接到計(jì)算機(jī)的主板上加電看能不能正常啟動(dòng)。不能則說(shuō)明ISA總線的板卡占用的資源跟主板資源沖突

?

4.支持多主控設(shè)備

如果某一個(gè)PCI總線上的設(shè)備成為主控設(shè)備之后,實(shí)際上它可以主動(dòng)去訪問(wèn)這個(gè)總線上的其他設(shè)備,甚至可以直接主動(dòng)去訪問(wèn)主存。不經(jīng)過(guò)CPU能夠?qū)崿F(xiàn)板卡與板卡之間,設(shè)備與設(shè)備之間或者說(shuō)設(shè)備與內(nèi)存之間的直接數(shù)據(jù)傳送

DMA就是基于這種所謂的多主控設(shè)備方式來(lái)實(shí)現(xiàn)的

?

PCI總線上究竟有哪些總線信號(hào),這些總線信號(hào)通過(guò)什么方式來(lái)實(shí)現(xiàn)PCI總線上兩個(gè)設(shè)備之間的可靠數(shù)據(jù)通信?下面通過(guò)時(shí)序來(lái)說(shuō)明,這是傳統(tǒng)的并行PCI總線上常用的信號(hào)

PCI總線屬于同步總線,所以總線信號(hào)里肯定應(yīng)該有一個(gè)CLK時(shí)鐘信號(hào)

PCI總線上的仲裁方式采用的是集中式的獨(dú)立請(qǐng)求方式。假設(shè)現(xiàn)在PCI總線上的某一個(gè)設(shè)備取得了總線的使用權(quán),成為了PCI總線上的主設(shè)備,想要選擇某一個(gè)從設(shè)備傳輸數(shù)據(jù),要從從設(shè)備里的存儲(chǔ)器里讀一些數(shù)據(jù)

主設(shè)備先把FRAME ̄\overline{FRAME}FRAME信號(hào)置低電平,告知總線上的其他設(shè)備做好準(zhǔn)備自己要進(jìn)行通信,同時(shí)會(huì)把它要訪問(wèn)的內(nèi)存地址放在[AD…0] 這32根地址數(shù)據(jù)復(fù)用的信號(hào)線上。在C/BE ̄[3..0]C/\overline{BE}[3..0]C/BE[3..0]這4根線上放一個(gè)命令,0110表示內(nèi)存讀命令。此時(shí)掛接在PCI總線上的其他設(shè)備要檢查一下主設(shè)備要訪問(wèn)的內(nèi)存地址是否落在自己的管轄范圍內(nèi)。被選中的從設(shè)備會(huì)把設(shè)備被選中信號(hào)DEVSEL ̄\overline{DEVSEL}DEVSEL置為低電平,告知主設(shè)備自己在哪并且已經(jīng)準(zhǔn)備就緒

實(shí)際上計(jì)算機(jī)的最大內(nèi)存尋址空間通常比較大。比如32位系統(tǒng)下內(nèi)存地址是32位,最大的內(nèi)存地址空間應(yīng)該是4GB,但實(shí)際上這4GB不可能全部分配給內(nèi)存條來(lái)用。通常在高端的地址要保留一部分給外設(shè)來(lái)用,相當(dāng)一部分要保留給PCI設(shè)備來(lái)用,所以PCI設(shè)備內(nèi)部存儲(chǔ)器通常容量也比較大,一般也會(huì)把它映射到內(nèi)存地址空間

中間隔一個(gè)時(shí)鐘周期實(shí)現(xiàn)總線傳輸信號(hào)方向的轉(zhuǎn)變以避免總線競(jìng)爭(zhēng)。經(jīng)過(guò)一個(gè)總線轉(zhuǎn)換周期后,后面理論上來(lái)講只要主設(shè)備和從設(shè)備都處于就緒狀態(tài),則每一個(gè)時(shí)鐘周期時(shí)鐘信號(hào)的上升沿就可以傳遞一個(gè)32位的數(shù)據(jù)。當(dāng)然傳遞的過(guò)程主設(shè)備和從設(shè)備內(nèi)部的地址會(huì)自增,所以地址只需要傳一次,后面可以連續(xù)傳輸很多的數(shù)據(jù),這種方式叫多發(fā)數(shù)據(jù)傳送方式

如果主設(shè)備或者從設(shè)備內(nèi)部有時(shí)可能內(nèi)部來(lái)不及處理需要等待一下呢?IRDY ̄\overline{IRDY}IRDY是主設(shè)備準(zhǔn)備好的信號(hào),TRDY ̄\overline{TRDY}TRDY是從設(shè)備準(zhǔn)備好的信號(hào),這2個(gè)信號(hào)同時(shí)為低電平就可以傳輸一個(gè)數(shù)據(jù),如在時(shí)鐘周期5時(shí)鐘信號(hào)的上升沿,從設(shè)備沒(méi)有準(zhǔn)備好,此時(shí)就不會(huì)傳輸數(shù)據(jù)

主設(shè)備把FRAME ̄\overline{FRAME}FRAME?信號(hào)置高電平,后面再傳輸一個(gè)數(shù)據(jù),整個(gè)傳輸過(guò)程就可以結(jié)束

?

通過(guò)這個(gè)時(shí)序可以了解到PCI總線一個(gè)時(shí)鐘周期就可以傳輸一個(gè)32位的數(shù)據(jù),通過(guò)這點(diǎn)可以算傳統(tǒng)的PCI總線理想情況下的多發(fā)數(shù)據(jù)傳輸率。如33MHZ PCI對(duì)應(yīng)數(shù)據(jù)傳輸率為33×106×32÷8=132MB/s33\times10^6\times 32\div8=132MB/s33×106×32÷8=132MB/s??

?

PCI總線的局限:

總線上的所有設(shè)備共享帶寬,只能分時(shí)使用

用并行單端信號(hào),一般通過(guò)提高總線位寬和頻率的方法增加總線帶寬。提高總線位寬會(huì)增加芯片引腳,影響芯片生產(chǎn)成本。提高總線頻率會(huì)產(chǎn)生時(shí)鐘偏移和串?dāng)_問(wèn)題,還會(huì)影響總線負(fù)載能力

高端的工作站或者服務(wù)器上PCI總線的數(shù)據(jù)線的位數(shù)一般相比個(gè)人計(jì)算機(jī)更大

?

PCIe總線

PCIe在計(jì)算機(jī)里面首先會(huì)有一個(gè)總的控制器根組件,根組件內(nèi)部通常會(huì)集成一個(gè)PCIe總線控制器和存儲(chǔ)器控制器,存儲(chǔ)器控制器主要用來(lái)實(shí)現(xiàn)PCIe總線地址空間跟內(nèi)存地址空間之間的映射,或者說(shuō)轉(zhuǎn)換。同樣根組件內(nèi)部還提供了多個(gè)PCIe端口

如果需要用到傳統(tǒng)的并行的PCI總線可以再接一個(gè)PCIe-PCI橋。橋可以實(shí)現(xiàn)兩種不同總線協(xié)議之間的轉(zhuǎn)換

如果需要接更多的基于PCIe總線的外設(shè),可以通過(guò)一個(gè)交換器(和網(wǎng)絡(luò)上的交換機(jī)類似)擴(kuò)展更多的端口

?

PCIe總線的特點(diǎn):

1.串行差分,一次只傳輸一個(gè)二進(jìn)制位

避免了時(shí)鐘偏移和串?dāng)_問(wèn)題,總線可達(dá)到很高的頻率,從而進(jìn)一步提高總線帶寬

每一條PCIe數(shù)據(jù)通路 (Lane) 由兩組串行差分信號(hào)(4根信號(hào)線,這4根線組成一個(gè)通道)構(gòu)成,可進(jìn)行全雙工數(shù)據(jù)傳輸,發(fā)送和接收各是一對(duì)信號(hào)線,發(fā)送和接收并行工作

?

2.直流平衡、內(nèi)嵌時(shí)鐘

PCIe1.0和PCIe2.0采用8/10b編碼,將每8位數(shù)據(jù)編碼成10位傳輸,編碼開(kāi)銷占總帶寬的20%開(kāi)銷

串行傳輸?shù)男盘?hào)如果傳輸?shù)臅r(shí)候連續(xù)0和連續(xù)1太多,電平長(zhǎng)時(shí)間沒(méi)有變化,很難從信號(hào)里把時(shí)鐘提取出來(lái)。8/10b編碼就是用10個(gè)二進(jìn)制位,從1024種組合里找出256種組合,這256種組合連續(xù)0和連續(xù)1的個(gè)數(shù)不會(huì)太多,且0的個(gè)數(shù)和1的個(gè)數(shù)基本均衡,用它來(lái)表示相應(yīng)的一個(gè)字節(jié)的信息

PCIe3.0采用128/130b編碼提高了帶寬利用率,編碼開(kāi)銷占總帶寬的1.538%開(kāi)銷

總線頻率2.5GHz則每秒鐘可以傳輸2500M個(gè)二進(jìn)制位,10個(gè)二進(jìn)制位用來(lái)表示一個(gè)字節(jié),所以×1\times1×1單向帶寬為250MB/s (1GT/s=1Gbit/s)。如果發(fā)送的同時(shí)還在接收的話,則總的帶寬在此基礎(chǔ)上可以再乘2

?

3.多通道

一條PCIe鏈路可以由多條數(shù)據(jù)通路組成,多通道并行工作提高總線帶寬

目前PCIe鏈路可以支持1、2、4、8、12、16和32個(gè)數(shù)據(jù)通路,即×1、×2、×4、×8、×16、×32\times1、\times2、\times4、\times8、\times16、\times32×1×2×4×8×16×32 數(shù)據(jù)帶寬

如獨(dú)立顯卡一般會(huì)通過(guò)PCIe×\times×?16的總線連接到主板上,指的就是有16個(gè)通道

通道之間不需要同步。比如說(shuō)這次要傳輸一大批數(shù)據(jù),采用PCIe$\times$16的總線傳輸。可以把這一大批數(shù)據(jù)平均分成16等份,每一等份用一個(gè)通道來(lái)傳輸,底層會(huì)一個(gè)個(gè)數(shù)據(jù)包打包之后再傳輸。具體數(shù)據(jù)包之間按照什么順序來(lái)組合內(nèi)部都有編號(hào)。接收方接收到這些數(shù)據(jù)之后按照數(shù)據(jù)包內(nèi)部規(guī)定跟順序有關(guān)的信息接收方再重新拼裝成原始數(shù)據(jù)

?

4.端到端(交換結(jié)構(gòu)),實(shí)現(xiàn)多模塊同時(shí)通信

傳統(tǒng)并行PCI總線所有設(shè)備共享帶寬。PCIe總線采用端到端(交換結(jié)構(gòu))的連接方式,每一條PCIe鏈路中只連接兩個(gè)設(shè)備

?

5.軟件向下兼容

不管是PCI還是PCIe總線對(duì)掛接在這個(gè)總線上的設(shè)備進(jìn)行讀寫和控制,軟件的接口是完全一樣的

?

下面這個(gè)主板上有很多PCI總線的插槽。為了兼容老的基于并行PCI總線的設(shè)備或者說(shuō)插卡,仍然保留了傳統(tǒng)的32位PCI總線

典型的標(biāo)準(zhǔn)化總線——外總線(通信總線)

通常把這種總線也叫做接口,比如說(shuō)USB接口

?

RS-232C串行通信接口

打開(kāi)設(shè)備管理器,在端口這一欄有一個(gè)通信端口 (COM1),這就是傳統(tǒng)的RS232串行接口。最新的計(jì)算機(jī)主板可能并沒(méi)有把這個(gè)接口作為一個(gè)插座引出,但是這個(gè)接口的資源在計(jì)算機(jī)主板上仍然存在。打開(kāi)COM1端口的屬性還可以設(shè)置這個(gè)端口在通信時(shí)的一些參數(shù)

早期國(guó)際互聯(lián)網(wǎng)還沒(méi)有出現(xiàn)時(shí)想實(shí)現(xiàn)遠(yuǎn)程的不同地方的計(jì)算機(jī)之間的通信要借助電話線,電話線上傳輸?shù)氖悄M信號(hào),調(diào)制解調(diào)器把計(jì)算機(jī)能夠接收的TTL電平轉(zhuǎn)換為模擬信號(hào),而調(diào)制解調(diào)器就是通過(guò)RS-232C連接到計(jì)算機(jī)上的

現(xiàn)在如果提到DTE,就理解成計(jì)算機(jī)。提到DCE就理解成外設(shè)

?

?

1.信號(hào)

傳送信息信號(hào):

RS-232C能夠?qū)崿F(xiàn)全雙工的通信,所以數(shù)據(jù)線有2根,一根用來(lái)發(fā)送一根用來(lái)接收

  • TxD : 發(fā)送數(shù)據(jù)線 (DTE →\to DCE)
  • RxD : 接收數(shù)據(jù)線 (DTE ←\leftarrow DCE)

?

聯(lián)絡(luò)信號(hào)

  • RTS : 請(qǐng)求發(fā)送,計(jì)算機(jī)告訴外設(shè)要發(fā)送數(shù)據(jù) (DTE →\to? DCE)
  • CTS : 清除發(fā)送,外設(shè)告訴計(jì)算機(jī)可以接收數(shù)據(jù) (DTE ←\leftarrow?? DCE)
  • DTR : DTE就緒,計(jì)算機(jī)告訴外設(shè)已經(jīng)準(zhǔn)備就緒 (DTE →\to DCE)
  • DSR : DCE就緒,外設(shè)告訴計(jì)算機(jī)已經(jīng)準(zhǔn)備就緒 (DTE ←\leftarrow DCE)
  • DCD : 數(shù)據(jù)載波檢測(cè)。調(diào)制解調(diào)器如果從電話線上接收到有數(shù)據(jù)來(lái)了就會(huì)把數(shù)據(jù)載波檢測(cè)置成有效告訴計(jì)算機(jī) (DTE ←\leftarrow? DCE)
  • RI (22) : 振鈴提示,跟電話線有關(guān) (DTE ←\leftarrow DCE)

?

2.電平

?

3.與TTL電平轉(zhuǎn)換

計(jì)算機(jī)希望接收發(fā)送的信號(hào)都是TTL電平,比如低電平就是0V,高電平就是5V。所以中間需要電平轉(zhuǎn)換

MAX232芯片只需要一個(gè)單5V電源供電,單5V電源內(nèi)部經(jīng)過(guò)升壓之后產(chǎn)生±10V\pm 10V±10V?的電壓。下圖即為該芯片的具體引腳

增壓電路需要一些電容,電容很難集成到芯片內(nèi)部,特別是一些容量大的電容,需要外接。計(jì)算機(jī)發(fā)送出來(lái)的TTL電平信號(hào)經(jīng)過(guò)它轉(zhuǎn)換成RS-232C串行接口所需要的±10V\pm 10V±10V的電平。從串行接口來(lái)的±10V\pm 10V±10V的電平信號(hào)通過(guò)它轉(zhuǎn)換成計(jì)算機(jī)能夠接受的TTL電平

?

接下來(lái)看一下RS-232串行接口具體的通信格式

首先總線處于空閑狀態(tài),一個(gè)啟動(dòng)位,接下來(lái)先傳低位后傳高位,最后是奇偶校驗(yàn)位和2個(gè)停止位

RS-232串行接口有的時(shí)候叫異步串行通信。因?yàn)樗鼪](méi)有時(shí)鐘信號(hào),所以不是同步總線而是異步總線。并且通信之前雙方事先要約定通信的波特率,兩邊設(shè)置的參數(shù)包括數(shù)據(jù)的格式必須要一樣,然后才可以通信

比如說(shuō)發(fā)送方要發(fā)送數(shù)據(jù),必須得從啟動(dòng)位開(kāi)始,接收方檢測(cè)到啟動(dòng)位就會(huì)從這個(gè)位置開(kāi)始計(jì)時(shí),因?yàn)殡p方約定了數(shù)據(jù)傳輸?shù)牟ㄌ芈?#xff0c;相鄰兩個(gè)數(shù)據(jù)之間的間隔可以計(jì)算得到。從這個(gè)啟動(dòng)位開(kāi)始,接收方每固定一段時(shí)間采樣一次數(shù)據(jù)線得到一位的二進(jìn)制數(shù)據(jù)

當(dāng)然發(fā)送方和接收方具體的定時(shí)不可能毫無(wú)誤差,但只要保證這一個(gè)數(shù)據(jù)(通常最多只傳輸一個(gè)字節(jié))在傳輸?shù)倪^(guò)程中哪怕每一次采樣時(shí)稍微有一點(diǎn)點(diǎn)錯(cuò)位,傳輸?shù)阶詈笠粋€(gè)數(shù)據(jù)能夠正常接收就可以了。傳輸下一個(gè)數(shù)據(jù)時(shí)又會(huì)再來(lái)一個(gè)啟動(dòng)位重新對(duì)齊

?

應(yīng)用:

1.使用Modem連接

電纜信號(hào)一一對(duì)應(yīng),共10線。

(保護(hù)地、信號(hào)地、…)

?

2.直接連接:計(jì)算機(jī) (DTE) ?\leftrightarrow? 計(jì)算機(jī) (DTE)

RS-232串行接口最大的優(yōu)點(diǎn)在于實(shí)現(xiàn)起來(lái)非常方便,成本也低。最簡(jiǎn)單的實(shí)現(xiàn)方式是三線經(jīng)濟(jì)方式 (三線制 RS-232)

計(jì)算機(jī)跟外設(shè)之間首先要共地。發(fā)送一根數(shù)據(jù)線,接收一根數(shù)據(jù)線,兩邊交叉著直接連

?

3.軟硬件系統(tǒng)調(diào)試:控制臺(tái)、超級(jí)終端

RS-232串行接口相對(duì)數(shù)據(jù)傳輸率較低,現(xiàn)在用的不是很多。最典型的應(yīng)用主要是硬件調(diào)試

比如說(shuō)現(xiàn)在有一塊嵌入式的開(kāi)發(fā)板,這個(gè)電路板在設(shè)計(jì)的時(shí)候?yàn)榱撕?jiǎn)化問(wèn)題,可能沒(méi)有那么多輸入輸出設(shè)備可以連接

為了觀察到電路板內(nèi)部CPU執(zhí)行程序的過(guò)程,或者說(shuō)發(fā)命令來(lái)控制它的工作過(guò)程,可以通過(guò)最簡(jiǎn)單的三根線實(shí)現(xiàn)的RS-232串行接口實(shí)現(xiàn)接口來(lái)和計(jì)算機(jī)連接。在計(jì)算機(jī)上運(yùn)行超級(jí)終端軟件,通過(guò)計(jì)算機(jī)的鍵盤在超級(jí)終端軟件里面直接輸入命令,那個(gè)命令就會(huì)通過(guò)RS-232串行接口傳輸?shù)诫娐钒鍍?nèi)部。電路板內(nèi)部接收到命令,做一定的運(yùn)算操作之后會(huì)把可能的相應(yīng)輸出信息的ASCII碼再通過(guò)串行接口傳輸?shù)接?jì)算機(jī)上運(yùn)行的超級(jí)終端軟件里面。超級(jí)終端軟件會(huì)把相應(yīng)的接收到的字符串顯示到計(jì)算機(jī)屏幕上

這樣其實(shí)就相當(dāng)于把計(jì)算機(jī)的顯示器和鍵盤給開(kāi)發(fā)板來(lái)用

?

USB總線

特點(diǎn):

每個(gè)USB總線支持127個(gè)外設(shè)

整個(gè)USB系統(tǒng)只用一個(gè)端口(接口地址)、一個(gè)中斷 →\to 節(jié)省系統(tǒng)資源

支持熱插拔、動(dòng)態(tài)加載驅(qū)動(dòng)程序:PnP,自動(dòng)配置。帶電拔出后自動(dòng)回收資源

傳輸距離:3~5米,電壓:5V

?

通過(guò)信號(hào)的名字可以觀察到USB總線采用串行差分的方式來(lái)傳送數(shù)據(jù)。USB1.0和USB2.0只有一對(duì)數(shù)據(jù)線,只能工作在半雙工狀態(tài)下,不能同時(shí)接收和發(fā)送

USB各版本向下兼容。USB3.0為了和USB2.0兼容,原來(lái)的+5V電源、+5V地、兩根差分形式傳輸?shù)臄?shù)據(jù)線仍然保留,另外又新增了兩對(duì)數(shù)據(jù)線。USB3.0如果工作在超速模式下,發(fā)送和接收分別各用一對(duì),采用差分的形式來(lái)傳輸信號(hào),支持全雙工的方式來(lái)進(jìn)行工作

?

?

Low-Speed 低速模式,Full-Speed 全速模式,High-Speed 高速模式,SuperSpeed 超速模式

現(xiàn)在一些低速的外設(shè),比如說(shuō)USB接口的鍵盤和鼠標(biāo),工作在低速模式下應(yīng)該也完全夠用

USB總線可以通過(guò)總線來(lái)給外設(shè)提供電源,即能夠?qū)崿F(xiàn)給外設(shè)直接供電。USB3.1從第2代開(kāi)始還支持快充模式,可以提供更大功率的輸出

再來(lái)看一下USB具體物理上的接口,計(jì)算機(jī)端和外設(shè)端有A、B、C類型。C類型接口從使用的角度來(lái)講最大的方便之處在于不分正反,正著插和反著插都可以。通過(guò)信號(hào)的分布會(huì)發(fā)現(xiàn)所有的這些總線信號(hào)都是根據(jù)中心點(diǎn)鏡像對(duì)稱的,不管是正插還是反插對(duì)應(yīng)的都是同一個(gè)位置

TX1+和TX1-是一對(duì)用來(lái)發(fā)送的差分信號(hào)線,RX1+和RX1-是一對(duì)用來(lái)接收的信號(hào)線

?

Type-C有兩個(gè)高速數(shù)據(jù)通道, (TX1+/TX1-,RX1+/RX1-) 和 (TX2+/TX2-,RX2+/RX2-)

USB3.1僅使用其中一個(gè)通道,另一個(gè)通道可用于備用模式

USB3.2可以充分使用這兩個(gè)高速通道,雙通道20Gbps。要能夠?qū)崿F(xiàn)最高的數(shù)據(jù)傳輸率必須得用C型接口

如果這兩個(gè)高速通道都用于備用模式,則速度就會(huì)下降成USB2.0的High-Speed

?

?

ATA總線

ATA總線連接存儲(chǔ)設(shè)備和計(jì)算機(jī)。早期采用并行的方式傳輸數(shù)據(jù),PATA即并行ATA接口,其總線電纜是40芯或者80芯的扁平電纜,線比較寬占主機(jī)箱空間,也影響散熱,也不可能過(guò)長(zhǎng)。后來(lái)出現(xiàn)了串行ATA接口,叫SATA或者SATA總線

?

ATA總線設(shè)計(jì)之初就是用來(lái)連接硬盤的,所以它在具體通信時(shí)的通信格式,包括邏輯塊地址用多少個(gè)二進(jìn)制位來(lái)表示在它的總線規(guī)范里有具體表示。比如最早的ATA總線,它在通信時(shí)規(guī)定邏輯塊地址用22位來(lái)表示,這樣硬盤的邏輯塊最多有222=4M2^{22}=4M222=4M?個(gè),一個(gè)邏輯塊對(duì)應(yīng)一個(gè)扇區(qū),而通常情況下一個(gè)扇區(qū)是512B,這樣就能算出理論上能支持的最大磁盤容量

1TB=1024TB,1TB=1024GB

?

SATA具有速度高、電壓低(功耗低)、線纜窄、支持熱拔插、傳輸距離長(zhǎng)的特點(diǎn),現(xiàn)已取代PATA

服務(wù)器一般配置好,通常是24小時(shí)不斷電工作。如果服務(wù)器磁盤陣列里的某一個(gè)硬盤出問(wèn)題會(huì)希望服務(wù)器不要關(guān)機(jī),直接帶電將其拆下來(lái),這就要求硬盤的接口必須支持熱插拔

?

總線的驅(qū)動(dòng)與控制

總線的競(jìng)爭(zhēng)與負(fù)載

?

總線競(jìng)爭(zhēng):同一總線上,同一時(shí)刻,有兩個(gè)或兩個(gè)以上的器件輸出其狀態(tài)

1.對(duì)TTL門

有兩個(gè)門同時(shí)將狀態(tài)輸出到信號(hào)線上,一個(gè)輸出低電平一個(gè)輸出高電平,此時(shí)總線上會(huì)是一種不高不低的非TTL電平,可能會(huì)丟失狀態(tài)。并且這種情況下可能有一個(gè)非常大的電流灌進(jìn)輸出低電平的引腳,嚴(yán)重時(shí)會(huì)燒壞電路

照著具體的門電路內(nèi)部看一下。如果這兩個(gè)門的輸出引腳接到一起,實(shí)際上就相當(dāng)于兩個(gè)門同時(shí)把狀態(tài)輸出到這一根線上

右邊的與非門只畫了輸出的這部分電路

比如一個(gè)輸出低電平一個(gè)輸出高電平,輸出低電平的引腳底下的晶體管處于飽和狀態(tài),即集電極和發(fā)射極之間導(dǎo)通。輸出高電平的引腳對(duì)應(yīng)的這個(gè)晶體管截止,集電級(jí)跟發(fā)射極之間斷開(kāi),上面上拉用的晶體管是導(dǎo)通的。這樣如下圖所示,從正電源到輸出低電平的輸出引腳,內(nèi)部的晶體管一直到地會(huì)有一個(gè)相對(duì)比較大的電流。長(zhǎng)時(shí)間維持這種狀態(tài),電流大功耗大,發(fā)熱熱量達(dá)到一定程度有可能會(huì)把這兩個(gè)器件的輸出引腳,即它內(nèi)部對(duì)應(yīng)的晶體管燒壞

這根線上究竟是高還是低呢?

實(shí)際上只要有一個(gè)引腳輸出為低電平,就相當(dāng)于把這根線通過(guò)這個(gè)輸出引腳內(nèi)部的下拉晶體管直接接地,所以上這根線上呈現(xiàn)的應(yīng)該是類似低電平的狀態(tài)

?

2.特例:集電極開(kāi)路/漏極開(kāi)路輸出

OC: Open Collector

有一種門電路,它的輸出引腳集電極開(kāi)路/漏極開(kāi)路,相當(dāng)于輸出引腳上面上拉的部分沒(méi)有,輸出引腳到正電源之間什么都沒(méi)連,處于開(kāi)路狀態(tài)

下圖只畫了輸出引腳有關(guān)的晶體管,內(nèi)部的其他部分省略

這樣的輸出引腳是可以接到一起的,外面必須加一個(gè)阻值相對(duì)較大的上拉電阻。如果這幾個(gè)引腳都想輸出高電平,每一個(gè)晶體管都處于截止?fàn)顟B(tài),集電極與發(fā)射極之間不導(dǎo)通,線上呈現(xiàn)高電平。若某一個(gè)輸出引腳想要輸出低電平,其三極管處于飽和狀態(tài),相當(dāng)于把這根線通過(guò)晶體管接地,會(huì)產(chǎn)生如下圖所示的電流,但因?yàn)樯侠娮枳柚递^大,所以這個(gè)電流比較小,不會(huì)燒壞器件,但B輸出的“1”信息會(huì)丟失

在數(shù)字電路中三極管當(dāng)作電子開(kāi)關(guān)來(lái)用,要么導(dǎo)通要么斷開(kāi)

只有所有的輸出引腳都輸出電平時(shí),這根線才會(huì)是高電平,任何一個(gè)輸出引腳只要輸出低電平,這根線就呈現(xiàn)低電平狀態(tài),這就是線與邏輯

?

?

3.用三態(tài)電路,嚴(yán)格控制邏輯

這根線接了兩個(gè)負(fù)載也就是兩個(gè)輸出引腳,都具有三態(tài)功能,可以控制是否能輸出。三態(tài)門的輸出狀態(tài)有高電平、低電平、高阻三種。高阻相當(dāng)于電阻無(wú)窮大,相當(dāng)于輸出引腳跟總線之間脫開(kāi)

?

?

總線的負(fù)載

1.直流負(fù)載

如果驅(qū)動(dòng)門輸出高電平時(shí),沒(méi)有能力提供負(fù)載需要吸收的電流,會(huì)導(dǎo)致高電平電壓高不上去。輸出低電平時(shí)如果吸收電流的能力不夠,會(huì)導(dǎo)致低電平電壓低不下來(lái)。都會(huì)造成邏輯上的問(wèn)題

2.交流負(fù)載

對(duì)MOS電路,IILI_{IL}IIL?IIHI_{IH}IIH?很小 →\to 主要考慮電容負(fù)載

所有的這些負(fù)載輸入引腳對(duì)地之間都有一個(gè)分布電容。接的負(fù)載多了后,這些電容是并聯(lián)關(guān)系,一端同時(shí)接到線上,另外一端同時(shí)接地,總電容越來(lái)越大,會(huì)產(chǎn)生較大的電容負(fù)載,濾掉高頻分量

且如果想從低電平變到高電平,電容電壓無(wú)法突變,充電需要過(guò)程,電容越大過(guò)程越緩慢,從高電平變到低電平也一樣。一些窄的正脈沖可能會(huì)被濾掉,產(chǎn)生邏輯問(wèn)題

?

所有的負(fù)載輸入引腳到地到會(huì)有一個(gè)電容。信號(hào)線在電路板上走,信號(hào)線本身到地之間也會(huì)有電容,這是元件級(jí)總線、內(nèi)總線帶來(lái)的電容。信號(hào)線要從一個(gè)電路板引到另外一個(gè)電路板上,或者連接到某一個(gè)外設(shè)上,傳輸線長(zhǎng)了也會(huì)用更大的分布電容

故要求輸出門的負(fù)載電容CPC_PCP?滿足如下條件:

?

驅(qū)動(dòng)門和負(fù)載的原始參數(shù)都可以通過(guò)查芯片手冊(cè)得到

?

總線驅(qū)動(dòng)設(shè)計(jì)

單向總線信號(hào)的驅(qū)動(dòng)設(shè)計(jì)

如果連接到總線上的模塊很多,也就是總線的負(fù)載很重,就需要加驅(qū)動(dòng)器。對(duì)于單向的總線控制信號(hào),比如地址、讀寫控制信號(hào),情況相對(duì)簡(jiǎn)單。雙向數(shù)據(jù)總線如果要加驅(qū)動(dòng),稍有不慎就會(huì)引起總線競(jìng)爭(zhēng)

?

比如要設(shè)計(jì)一個(gè)由兩塊電路板(主板CPU板,擴(kuò)展板電路板1)組成的產(chǎn)品。擴(kuò)展板上需要從CPU板引過(guò)來(lái)很多信號(hào),包括地址線的最低位A0。地址線實(shí)際上需要接很多負(fù)載,比如CPU板需要擴(kuò)展內(nèi)存,主板上可能會(huì)有很多內(nèi)存芯片,每個(gè)內(nèi)存芯片都有地址線,可能都要跟CPU的地址線相連,A0這根線本身在CPU板上就要接很多負(fù)載。現(xiàn)在這根線要引出來(lái)到擴(kuò)展板上,擴(kuò)展板很多地方也要用到這個(gè)信號(hào),又要有很多負(fù)載

最好不要直接把這根線引出來(lái)而是加一個(gè)驅(qū)動(dòng)器。經(jīng)過(guò)驅(qū)動(dòng)器再輸出,不管它輸出之后后面接了多少個(gè)負(fù)載,對(duì)CPU來(lái)講也只是增加了1個(gè)負(fù)載而已

把該信號(hào)引入后最好也不要直接用而是加緩沖器。下圖從驅(qū)動(dòng)器的角度來(lái)講它后面只接了3個(gè)負(fù)載,每個(gè)緩沖器后面又加了5個(gè)負(fù)載

緩沖器和驅(qū)動(dòng)器功能類似,只是叫法不一樣

驅(qū)動(dòng)器和緩沖器也能起到緩沖作用,保護(hù)硬件

?

74LS244可以當(dāng)驅(qū)動(dòng)器或者說(shuō)緩沖器來(lái)用,它主要用來(lái)實(shí)現(xiàn)單向的總線信號(hào)驅(qū)動(dòng)。其內(nèi)部有8個(gè)三態(tài)門,4個(gè)一組,總共2組,每組三態(tài)門的控制端接到一起引出來(lái),低電平有效。把允許信號(hào),即三態(tài)門的控制端接地令其永遠(yuǎn)有效,這樣8個(gè)輸入和8個(gè)輸出永遠(yuǎn)一樣

?

雙向總線信號(hào)的驅(qū)動(dòng)設(shè)計(jì)

雙向數(shù)據(jù)總線驅(qū)動(dòng)器可以選擇74LS245芯片實(shí)現(xiàn),通過(guò)控制允許信號(hào)和方向控制信號(hào)來(lái)避免總線競(jìng)爭(zhēng)。允許信號(hào)低電平,A邊和B邊導(dǎo)通。然后方向控制信號(hào)給高電平,信號(hào)傳遞的方向從A到B,給低電平則從B到A

注意74LS245不是一個(gè)開(kāi)關(guān),它是把一邊接收的信號(hào)原封不動(dòng)地復(fù)制到另一邊輸出

?

例3:某微型機(jī)電路板上有內(nèi)存C0000H~\simEFFFFH和接口A000H~\simBFFFH,試畫出該電路板板內(nèi)雙向數(shù)據(jù)總線驅(qū)動(dòng)與控制電路

1.防止總線競(jìng)爭(zhēng)原則:只有當(dāng)CPU讀板內(nèi)內(nèi)存或讀板內(nèi)接口時(shí),才允許雙向數(shù)據(jù)驅(qū)動(dòng)器指向系統(tǒng)總線的三態(tài)門是導(dǎo)通的

2.地址分析(內(nèi)存地址、接口地址)

設(shè)計(jì)的插件板板卡內(nèi)部有很多存儲(chǔ)器,插在計(jì)算機(jī)主板插槽上占用資源,希望占用一部分的內(nèi)存地址空間和接口地址空間。計(jì)算機(jī)主板CPU運(yùn)行某一程序時(shí)訪問(wèn)內(nèi)存或接口,訪問(wèn)的內(nèi)存或接口地址落在這個(gè)范圍之內(nèi),訪問(wèn)板卡內(nèi)部的存儲(chǔ)器,驅(qū)動(dòng)器74LS245的允許信號(hào)就應(yīng)該給低電平讓兩邊接通,然后根據(jù)讀板卡還是寫板卡控制方向信號(hào)。設(shè)計(jì)雙向數(shù)據(jù)總線驅(qū)動(dòng)時(shí),要設(shè)計(jì)相應(yīng)的內(nèi)存和接口地址譯碼電路判斷計(jì)算機(jī)主板要訪問(wèn)的內(nèi)存和接口是否在范圍內(nèi)

C0000H~\simEFFFFH低4位全0到全F所有的組合都包含在內(nèi),故只需分析從C到E的最高位。觀察高位地址發(fā)現(xiàn)A18、A17、A16是4、5、6這3種組合之一,如果該譯碼電路用3-8譯碼器實(shí)現(xiàn),那Y4、Y5、 Y6任何一個(gè)是低電平,這三根線肯定就是這三種狀態(tài)之一。此外A19必須是1。

對(duì)A000H~\sim???BFFFH的分析過(guò)程也類似,高三位地址只要是“101”地址就落在范圍內(nèi)

3.畫驅(qū)動(dòng)與控制電路

74LS138是3-8譯碼器

內(nèi)存地址譯碼電路限定了高位地址A19必須是1,A18、A17、A16必須是4、5、6三種組合之一,CPU此時(shí)正在訪問(wèn)內(nèi)存的條件

接口地址譯碼電路限定了A15、A14、A13分別是高電平、低電平、高電平,CPU此時(shí)正在訪問(wèn)接口地址空間,CPU此時(shí)正在控制總線不是DMA狀態(tài)(AEN信號(hào)給低電平)的條件

這兩部分任何一個(gè)條件全部滿足74LS245的兩邊就應(yīng)該接通

方向控制信號(hào)用讀信號(hào),內(nèi)存讀和接口讀信號(hào)任何一個(gè)給低電平經(jīng)過(guò)與門輸出就是低,方向從B到A。寫時(shí)讀信號(hào)肯定無(wú)效,兩個(gè)信號(hào)都是高電平,經(jīng)過(guò)與門輸出高電平,方向從A到B

存儲(chǔ)技術(shù)

常用存儲(chǔ)器芯片及連接使用

?

靜態(tài)隨機(jī)讀/寫存儲(chǔ)器 (SRAM) 及接口設(shè)計(jì)

SRAM的優(yōu)點(diǎn)是可以直接連接到系統(tǒng)總線上,有獨(dú)立的地址線,數(shù)據(jù)線,讀信號(hào),寫信號(hào)和片選,并且讀寫速度都很快。是易失性存儲(chǔ)器,掉電之后內(nèi)容就沒(méi)了,剛一加電內(nèi)容是隨機(jī)的

?

用單個(gè)SRAM芯片構(gòu)成8088的內(nèi)存

可以認(rèn)為這些信號(hào)都是8088工作在最大模式下的系統(tǒng)總線信號(hào),或者認(rèn)為這些信號(hào)都是8位ISA總線的信號(hào),反正都一樣

?

有的電路高位地址會(huì)留幾根不連,這樣連線較少但會(huì)浪費(fèi)內(nèi)存地址空間

?

用多片SRAM芯片構(gòu)成8088的內(nèi)存

存儲(chǔ)器的字?jǐn)U展:

1.地址線并聯(lián)

2.數(shù)據(jù)線并聯(lián)

3.OE― 并 → MEMR―,WE― 并 → MEMW―

4.CS― → 地址譯碼器(高位地址譯碼)的不同輸出

8088系統(tǒng)總線數(shù)據(jù)線有8根,要求內(nèi)存是8位的

如果SRAM芯片只有4根數(shù)據(jù)線,則不管構(gòu)成什么內(nèi)存都要進(jìn)行位擴(kuò)展,因?yàn)镃PU訪問(wèn)內(nèi)存最小內(nèi)存就是8位,不可能一次訪問(wèn)4位的數(shù)據(jù)

?

存儲(chǔ)器的位擴(kuò)展:

1.地址線并聯(lián)

2.數(shù)據(jù)線:1號(hào)芯片D0~D7,2號(hào)芯片D8~D15

3.OE― 并 → MEMR―,WE― 并 → MEMW―

4.CS―并聯(lián) → 地址譯碼器(高位地址譯碼)

8086要求內(nèi)存必須是16位的,下圖中SRAM芯片是8位的,要進(jìn)行位擴(kuò)展

連接地址線時(shí),SRAM芯片的A0~A10要連接到系統(tǒng)總線的A1~A11。因?yàn)?個(gè)8位存儲(chǔ)器位擴(kuò)展之后構(gòu)成1個(gè)16位存儲(chǔ)器,給16位存儲(chǔ)器地址要給字地址。x86按字節(jié)編址,如果給字的地址要從A1開(kāi)始。這兩個(gè)芯片可以同時(shí)被選中,同時(shí)被選中時(shí)CPU就對(duì)內(nèi)存進(jìn)行16位讀寫

?

若現(xiàn)在想用匯編語(yǔ)言編一個(gè)程序訪問(wèn)它里面的某一個(gè)單元,如從80002H地址讀一個(gè)16位數(shù)據(jù):

先初始化DS,將段的起始地址高16位傳送到DS。再將16位段內(nèi)偏移送到指針寄存器BX

然后寄存器間接尋址從指向的內(nèi)存單元讀一個(gè)數(shù)。默認(rèn)段寄存器為DS,CPU會(huì)從DS讀出段起始地址的高16位,末尾添4個(gè)0,再加上BX里存的16位段內(nèi)偏移,加的結(jié)果就是要訪問(wèn)的內(nèi)存地址

MOV AX,8000H MOV DS,AX MOV BX,2 MOV AX,[BX]

?

如要讀一個(gè)8位數(shù)據(jù),只需要把目標(biāo)寄存器改為8位

從偶地址讀BHE―為高電平,A0為低電平。從奇地址讀BHE―為低電平,A0為高電平

?

如要讀一個(gè)16位數(shù)據(jù),目的寄存器就應(yīng)該寫16位

從偶地址開(kāi)始讀,BHE―和A0均為低電平,連續(xù)讀2個(gè)字節(jié)傳送到目的寄存器,2個(gè)字節(jié)占2個(gè)地址,小地址傳送到低8位,大地址傳送到高8位

從奇地址開(kāi)始讀,必須分兩次來(lái)讀,先讓BHE―引腳為低電平,A0為高電平,讀8位數(shù)據(jù)傳送到目的寄存器的低8位。再讓BHE―為高電平,A0為低電平,讀8位數(shù)據(jù)傳送到目的寄存器的高8位

?

數(shù)據(jù)在內(nèi)存中要對(duì)齊存放,如果按字節(jié)編址,16位數(shù)據(jù)起始地址是2的整數(shù)倍,32位數(shù)據(jù)起始地址是4的整數(shù)倍,64位數(shù)據(jù)起始地址是8的整數(shù)倍

如果不對(duì)齊存放,像x86處理器,如8086,16位數(shù)據(jù)從奇地址開(kāi)始放照樣可以處理,只是速度會(huì)變慢,如果對(duì)齊一個(gè)總線周期就能夠完成,如果不對(duì)齊得花兩個(gè)總線周期。時(shí)間變長(zhǎng),但是功能照樣能實(shí)現(xiàn)

這里也體現(xiàn)出CISC結(jié)構(gòu)處理器對(duì)軟件要求不是很高,硬件能干的活盡量硬件都干了,有一些RISC結(jié)構(gòu)的處理器就要求數(shù)據(jù)在內(nèi)存里面必須對(duì)齊存放,不對(duì)齊指令就無(wú)法執(zhí)行,不同的CPU處理方式不一樣

現(xiàn)在計(jì)算機(jī)內(nèi)存并不是用SRAM來(lái)構(gòu)成的,包括最早的個(gè)人計(jì)算機(jī)內(nèi)存也是用DRAM構(gòu)成的。講課用SRAM是因?yàn)檫@個(gè)簡(jiǎn)單,因?yàn)樗鼜男盘?hào)上來(lái)講有獨(dú)立的地址線數(shù)據(jù)線讀寫信號(hào)和片選,可以直接連接到系統(tǒng)總線,電路包括控制方式最簡(jiǎn)單

用SRAM構(gòu)成單片機(jī)內(nèi)存完全夠用。如51單片機(jī)芯片內(nèi)部會(huì)集成一定容量的內(nèi)存,就存儲(chǔ)一些臨時(shí)變量用的,如果太小外面可能還要再擴(kuò)展內(nèi)存,擴(kuò)展內(nèi)存一般不大

?

如果用DRAM構(gòu)成內(nèi)存,進(jìn)行一次讀寫地址得分兩次來(lái)送,先送一個(gè)行地址,再送一個(gè)列地址,然后才能讀寫,還有定時(shí)刷新。DRAM后來(lái)發(fā)展出現(xiàn)了SDRAM(同步動(dòng)態(tài)隨機(jī)訪問(wèn)存儲(chǔ)器),再發(fā)展出現(xiàn)了雙倍速的SDRAM就是DDR的SRAM,現(xiàn)在主流用的比較多的是DDR4

這種雙倍速的SDRAM在讀寫時(shí)時(shí)序更復(fù)雜,對(duì)它進(jìn)行讀寫首先要發(fā)激活命令,同時(shí)送行地址。發(fā)激活命令相當(dāng)于把它里面的某一行打開(kāi),然后把這一行的所有內(nèi)容讀到行緩沖區(qū)中,然后再給它發(fā)相應(yīng)的讀寫命令,同時(shí)給它列地址,對(duì)打開(kāi)的行緩沖區(qū)進(jìn)行讀寫。在訪問(wèn)其他行之前要把當(dāng)前這一行關(guān)閉,也就是把行緩沖區(qū)的內(nèi)容回寫到原來(lái)的位置,這要給它發(fā)一個(gè)預(yù)充電命令

SDRAM存儲(chǔ)器在控制時(shí)涉及到很多比較復(fù)雜的命令,沒(méi)有辦法直接連接到系統(tǒng)總線。一般要設(shè)計(jì)一個(gè)比較復(fù)雜的電路現(xiàn)在都會(huì)有一些現(xiàn)成的芯片,或者說(shuō)現(xiàn)成的IP核可以直接用。你可以理解成CPU系統(tǒng)總線上必須要通過(guò)一個(gè)SDRAM控制器間接地才可以訪問(wèn)到SDAM。從這個(gè)角度來(lái)講,現(xiàn)在計(jì)算機(jī)的內(nèi)存其實(shí)和外設(shè)很像,CPU通過(guò)相應(yīng)的接口訪問(wèn),而不是直接訪問(wèn),實(shí)現(xiàn)的電路非常復(fù)雜

現(xiàn)在的內(nèi)存,如DDR的SDAM在進(jìn)行讀寫時(shí)采用突發(fā)的讀寫方式,一次突發(fā)讀寫傳送幾個(gè)數(shù)據(jù),并不是隨機(jī)訪問(wèn)。CPU內(nèi)核要取得某一個(gè)數(shù)據(jù)最終從CPU內(nèi)部的Cache得到,數(shù)據(jù)如果在內(nèi)存中對(duì)齊存放,最終以塊為單位裝載到Cache內(nèi),它在Cache內(nèi)也是對(duì)齊存放的。CPU內(nèi)核可以直接訪問(wèn)Cache,Cache就是用SRAM實(shí)現(xiàn)的

?

計(jì)算機(jī)的存儲(chǔ)器現(xiàn)在分層較細(xì),如果只算寄存器組,控制器和運(yùn)算器之外的那些存儲(chǔ)器,最頂層的是用SRAM構(gòu)成,可以直接訪問(wèn)的Cache,再往下是用DDR的SRAM實(shí)現(xiàn)的主存,再往下有一些計(jì)算機(jī)有如Intel的奧騰存儲(chǔ)器的介于主存和固態(tài)硬盤之間的層次,再往下是固態(tài)硬盤,再往下是機(jī)械硬盤

?

?

除了用基本的邏輯門和3-8譯碼器,也可以用ROM作譯碼器。ROM能根據(jù)輸入選中對(duì)應(yīng)存儲(chǔ)單元并輸出該存儲(chǔ)單元的內(nèi)容

?

現(xiàn)在要用4片6264構(gòu)成一個(gè)存儲(chǔ)容量為32KB的8位存儲(chǔ)器(字?jǐn)U展),其地址空間為E0000H~E7FFFH。用一塊512×4(即512個(gè)存儲(chǔ)單元,每個(gè)存儲(chǔ)單元為4位)的PROM芯片63S241作為ROM譯碼器

給單向信號(hào)(A0~A12,MEMR―,MEMW―)和雙向數(shù)據(jù)信號(hào)(D0~D7)加驅(qū)動(dòng)

CPU沒(méi)有訪問(wèn)內(nèi)存時(shí)MEMR―,MEMW―均為高電平,經(jīng)過(guò)與門之后輸出是高。ROM芯片片選和讀信號(hào)都是高電平,數(shù)據(jù)線輸出是高阻。高阻就是電阻無(wú)窮大,相當(dāng)于4片6264芯片的片選信號(hào)懸空哪都沒(méi)有接,輸入引腳是高電平還是低電平是不定的。加上拉電阻能保證這4根線輸出高阻時(shí)仍然會(huì)呈現(xiàn)高電平狀態(tài)

?

?

也可以用數(shù)據(jù)比較器作譯碼器

兩路8位輸入數(shù)據(jù)相等,輸出低電平。否則輸出高電平

?

一路輸入直接接開(kāi)關(guān)置于固定狀態(tài)。開(kāi)關(guān)斷開(kāi)時(shí)由于上拉電阻呈現(xiàn)高電平,閉合時(shí)相當(dāng)于把這根線通過(guò)開(kāi)關(guān)接地,這根線就是低電平

另一路接到系統(tǒng)總線的高位,不用的線也直接接高電平。高位地址和開(kāi)關(guān)撥的狀態(tài)一樣時(shí)才會(huì)輸出低電平選中這個(gè)芯片

數(shù)據(jù)線還是要加雙向驅(qū)動(dòng)

?

也可以用PLD作譯碼器。知道有這種辦法就可以了

?

SRAM設(shè)計(jì)舉例1:

現(xiàn)有容量為 8K×8bit 和 4K×8bit 的SRAM芯片。在8086系統(tǒng)中,

1.利用這樣的芯片構(gòu)成地址范圍為C2000H~C7FFFH的內(nèi)存,畫出最大模式下包括總線驅(qū)動(dòng)在內(nèi)的此芯片與系統(tǒng)總線的連接圖(譯碼器件自行選擇,盡量選擇容量大的芯片)

2.試編寫8086匯編語(yǔ)言程序,從地址C2000H開(kāi)始,依次寫入數(shù)據(jù),直到地址C7FFFH。要求數(shù)據(jù)從0開(kāi)始,每寫入一個(gè)字節(jié)后數(shù)據(jù)加1,即寫入數(shù)據(jù)依次為:00H、01H、02H、03H、… 、FEH、FFH、00H、01H、…… 。然后逐個(gè)單元讀出比較,若有錯(cuò),則在DL中寫入01H,退出檢測(cè);若每個(gè)單元均對(duì),則在DL寫入00H

順便介紹了下檢查內(nèi)存的幾種方法和原理

?

?

首先確定要用多少片芯片

C8000H-C2000H=6000H,即24K

盡量選擇容量大的芯片,首先要用8K×8bit的芯片。但考慮到要構(gòu)成8086的內(nèi)存,如果用8位的SRAM必須是偶數(shù)片,2片8位的SRAM位擴(kuò)展之后才能夠構(gòu)成1個(gè)16位的存儲(chǔ)器。折中一下:

需要8K×8bit芯片2片、4K×8bit芯片2片

8K×8bit芯片地址線:A0~A12,數(shù)據(jù)線:D0~D7

4K×8bit芯片地址線:A0~A11,數(shù)據(jù)線:D0~D7

?

考慮內(nèi)存地址譯碼電路應(yīng)該有幾個(gè)輸出

作為8086的內(nèi)存來(lái)講,每2片8位芯片位擴(kuò)展之后構(gòu)成1個(gè)16位的存儲(chǔ)器,各對(duì)應(yīng)地址譯碼電路的1個(gè)輸出。所以應(yīng)該有2個(gè)輸出

?

然后根據(jù)地址范圍分析內(nèi)存地址譯碼電路應(yīng)該怎么設(shè)計(jì)

C8000H-C2000H 16進(jìn)制地址的低3位從全0到全F,所有組合都有,可以不用考慮,直接分析高8位地址C2~C7

先看經(jīng)過(guò)位擴(kuò)展之后構(gòu)成一個(gè)16位存儲(chǔ)器的2片8K×8bit的芯片,它的內(nèi)部地址應(yīng)該是什么

8K×8bit芯片地址線是A0~A12,16位存儲(chǔ)器要給字的地址。所以連系統(tǒng)總線時(shí)從A1開(kāi)始連,連接系統(tǒng)總線的A1~A13。下圖的表格中每一行低12位地址A0~A11是任意的,對(duì)應(yīng)4KB,2片8KB的芯片位擴(kuò)展之后總?cè)萘渴?6KB,對(duì)應(yīng)前4行。前4行對(duì)應(yīng)內(nèi)存地址譯碼電路的1個(gè)輸出,用來(lái)選擇這2片8KB的芯片

后2行對(duì)應(yīng)另外一個(gè)輸出,選擇的是2片4KB芯片位擴(kuò)展之后的16位存儲(chǔ)器

內(nèi)存地址譯碼電路的輸入應(yīng)該是高位地址,A13雖然是SRAM內(nèi)部地址的高位,也要參與地址譯碼,這樣才能保證不參與地址譯碼的A0~A12能包含全0到全1的所有組合

?

然后畫具體電路

首先畫SRAM芯片

先畫2片8KB的芯片。第一片8KBSRAM芯片的引腳首先是數(shù)據(jù)線D0~D7,這8根線直接連8086系統(tǒng)總線的低8位D0′~D7′,這樣連它就是偶地址存儲(chǔ)體。然后地址線A0~A12連8086的系統(tǒng)總線A1′~A13′(注意從A1′開(kāi)始連)。讀信號(hào)OE―連內(nèi)存讀MEMR′―,寫信號(hào)WE―連內(nèi)存寫MEMW′―。最后一個(gè)是片選CS―,偶地址存儲(chǔ)體要被選中應(yīng)該有一個(gè)或門,或門的輸出是它的片選,或門的一個(gè)輸入是偶地址存儲(chǔ)體的選擇信號(hào)A0′,另外一根線接地址譯碼電路的第一個(gè)輸出

片選和地址譯碼電路的輸出有關(guān),可以留到最后畫

第二片8KBSRAM芯片作為奇地址存儲(chǔ)體,或門的輸出是它的片選,或門的輸入是奇地址存儲(chǔ)體的選擇信號(hào)BHE′―和和第一片相同的地址譯碼電路輸出,數(shù)據(jù)線D0~D7連接系統(tǒng)總線數(shù)據(jù)線高8位D8′~D15′,地址線,讀信號(hào)OE―,寫信號(hào)WE―的連法和第一片一樣

因?yàn)?個(gè)芯片是位擴(kuò)展的,這2個(gè)芯片受地址譯碼電路同一個(gè)輸出的控制。所以為了畫起來(lái)方便下圖把這個(gè)芯片的片選畫在上面2個(gè)挨著

再看2片4KB的芯片,畫法幾乎一樣。同樣數(shù)據(jù)線8根線D0~D7一個(gè)作為偶地址存儲(chǔ)體連系統(tǒng)總線的低8位D0′~D7′,一個(gè)作為奇地址存儲(chǔ)體連系統(tǒng)總線的高8位D8′~D15′。地址線12根線A0~A11連系統(tǒng)總線A1′~A12′。讀信號(hào)OE―和寫信號(hào)WE―所有芯片的連法都一樣。片選的套路也一樣,用或門輸出,輸入端是A0(偶地址存儲(chǔ)體)或BHE′―(奇地址存儲(chǔ)體)和地址譯碼電路的另外一路輸出

?

再畫內(nèi)存地址譯碼電路

限定高位地址要滿足的規(guī)律。按照剛才的分析,內(nèi)存地址譯碼電路的輸入應(yīng)該從A13′開(kāi)始一直到A19

上表中A15,A14,A13′這3根線一共就3種組合,用3-8譯碼器74LS138實(shí)現(xiàn)較方便,分別接C,B,A這3根線。2種組合對(duì)應(yīng)Y1―和Y2―,Y1―和Y2―任何一個(gè)輸出低電平,地址譯碼電路的第一路輸出都應(yīng)該是低令2片8KB芯片的片選有效,故Y1―和Y2―這2根線經(jīng)過(guò)一個(gè)與門之后合成一個(gè)信號(hào)輸出。Y3―是另外一路輸出,用來(lái)選中2片4KB的芯片

畫的時(shí)候如果不希望線連的太長(zhǎng),可以給輸出信號(hào)起名字(如下圖的CS8K表示8KB芯片的片選信號(hào)),另一邊起相同的名字,默認(rèn)兩根連在一起

高4位地址A16~A19限定上表的條件就可以。高2位地址A19,A18都得是高電平,用一個(gè)與門接到高有效的允許G1。A17,A16都得是低電平,用或門接到低有效的允許G2A。此外這是一個(gè)內(nèi)存地址譯碼電路,只有當(dāng)CPU訪問(wèn)內(nèi)存時(shí)它輸出才有可能是低電平,此時(shí)內(nèi)存讀MEMR′―和內(nèi)存寫MEMW′―必然有一個(gè)是低電平,經(jīng)過(guò)一個(gè)與門接到低有效的允許G2B

不用的Y―可以不畫

?

如果要求畫驅(qū)動(dòng),則還需要再增加一些東西驅(qū)動(dòng)那些接了好幾處的信號(hào)

驅(qū)動(dòng)單向信號(hào)A0~A13,BHE―,MEMR―,MEMW―用單向驅(qū)動(dòng)器74LS244,允許接地令其永遠(yuǎn)有效

驅(qū)動(dòng)雙向數(shù)據(jù)總線D0~D7用雙向驅(qū)動(dòng)器74LS245。需要2片,一片A邊接系統(tǒng)總線低8位D0~D7,B邊是驅(qū)動(dòng)后的D0′~D7′,把需要通過(guò)低8位數(shù)據(jù)線傳輸數(shù)據(jù)的芯片的片選信號(hào)CS1―和CS3―加一個(gè)與門接到其輸出允許OE―。一片A邊接系統(tǒng)總線高8位D8~D15,B邊是驅(qū)動(dòng)后的D8′~D15′,把需要通過(guò)高8位數(shù)據(jù)線傳輸數(shù)據(jù)的芯片的片選信號(hào)CS2―和CS4―加一個(gè)與門接到其輸出允許OE―。方向控制DIR都接內(nèi)存讀MEMR′―

經(jīng)過(guò)驅(qū)動(dòng)的信號(hào)可以加一撇

?

在這個(gè)基礎(chǔ)上編寫匯編程序

如果按8位字節(jié)來(lái)寫和比較。首先初始化段寄存器DS和指針寄存器DI,循環(huán)次數(shù)放到CX,每次寫入的數(shù)據(jù)內(nèi)容放在AL,初值為0。然后循環(huán),每寫一個(gè)數(shù)據(jù)DI和AL的內(nèi)容加1指向下一個(gè)字節(jié)。再循環(huán)比較,循環(huán)之前的準(zhǔn)備基本和上面一樣,初始化指針寄存器SI,循環(huán)次數(shù)放到SI,比較的數(shù)據(jù)內(nèi)容放在AL。比較過(guò)程中如果發(fā)現(xiàn)不一樣就跳轉(zhuǎn)到錯(cuò)誤程序,如果一樣則AL和SI加1繼續(xù)循環(huán),如果循環(huán)正常退出說(shuō)明所有單元正確,置一個(gè)正確標(biāo)志后跳到最后

如果按16位字,在剛才的基礎(chǔ)上稍微改一點(diǎn)。循環(huán)次數(shù)減半,每次寫入的數(shù)據(jù)內(nèi)容放在AX,初始低8位是全0高8位是全1。每次循環(huán)寫入后DI加2指向下一個(gè)字,AX低8位和高8位分別加2。比較時(shí)也類似

?

?

?

只讀存儲(chǔ)器 (ROM) 及接口設(shè)計(jì)

非易失性存儲(chǔ)器,掉電之后內(nèi)容不丟失

?

紫外線可擦除只讀存儲(chǔ)器EPROM

這里對(duì)一些應(yīng)該不太重要的硬件細(xì)節(jié)記得比較簡(jiǎn)略

?

若利用全地址譯碼將EPROM2764接在8088內(nèi)存首地址為A0000H的內(nèi)存區(qū),試畫連接圖

擦除時(shí)用紫外線照石英窗口15~20min,擦干凈時(shí)每單元里內(nèi)容均為FFH,編程寫入時(shí)把期望變成0的那些位變成0

?

?

例:利用2732(8K×8bit SRAM,A12~A0)和6264(4K×8bit EPROM,A11~A0)構(gòu)成從00000H~02FFFH的ROM存儲(chǔ)區(qū)和從03000H~06FFFH的RAM存儲(chǔ)區(qū)。畫出與8088系統(tǒng)總線的連接圖。(不考慮板內(nèi)總線驅(qū)動(dòng))

?

ROM區(qū):(2FFF+1) / 400 = C,共12KB → 需3片

RAM區(qū):4000 / 400 = 10,共16KB → 需2片

?

如果將SRAM芯片改成8K×4bit,則

?

?

電可擦除只讀存儲(chǔ)器EEPROM (E2PROM)

?

98C64寫之前不需要擦除,直接給寫的時(shí)序就能夠把原來(lái)的內(nèi)容覆蓋掉寫入新的數(shù)據(jù)

讀的時(shí)序和SRAM,EPROM都一樣,主要看怎么寫入

下圖是一個(gè)寫的時(shí)序,在整個(gè)寫的過(guò)程中讀信號(hào)OE―必須無(wú)效,首先A12~A0這13根地址線給地址選中內(nèi)部的某一單元,整個(gè)過(guò)程中片選信號(hào)CE―有效選中該芯片。然后D7~D0數(shù)據(jù)線上給要寫的數(shù)據(jù),地址數(shù)據(jù)穩(wěn)定后在寫信號(hào)WE―上給負(fù)脈沖,該負(fù)脈沖的最小寬度是100ns。在負(fù)脈沖的上升沿把地址還有數(shù)據(jù)寫入到芯片內(nèi)部的一個(gè)緩存,上升沿結(jié)束之后,芯片內(nèi)部才真正開(kāi)始把數(shù)據(jù)寫入到指定的單元,這個(gè)寫的過(guò)程是比較慢的,大概需要5~10ms,忙信號(hào)READY/BUSY―會(huì)輸出低電平,READY/BUSY―再次變成無(wú)效時(shí)數(shù)據(jù)才真正寫完

?

?

?

用98C64構(gòu)成8088的內(nèi)存

把芯片內(nèi)部所有的單元寫入55H

?

如果想要提高效率,可以設(shè)計(jì)一個(gè)輸入接口讀READY/BUSY―信號(hào)當(dāng)前的狀態(tài),如果為低電平忙則等待,如果為高電平不忙就馬上寫下一個(gè)數(shù)據(jù)。把READY/BUSY―信號(hào)通過(guò)一個(gè)三態(tài)門連接到數(shù)據(jù)線,CPU要查詢這根線時(shí)三態(tài)門才打開(kāi)把狀態(tài)輸出到數(shù)據(jù)線上,以防止總線競(jìng)爭(zhēng)

控制端控制這個(gè)三態(tài)門什么時(shí)候該打開(kāi),什么時(shí)候該關(guān)閉。如果把這個(gè)輸入接口映射到內(nèi)存地址空間就給內(nèi)存地址譯碼電路,要映射到接口地址空間就給接口地址譯碼電路。下圖顯然是接口地址譯碼電路

READY/BUSY―是一個(gè)漏極開(kāi)路的引腳,輸出應(yīng)該加上拉電阻。此外下圖還加了一個(gè)不太重要的濾波電容

這里和下一章有點(diǎn)關(guān)系。可以先看后面,回頭再看會(huì)比較好理解

這樣原來(lái)的延時(shí)程序就可以改成查詢方式。通過(guò)IN指令從內(nèi)存地址7000H讀進(jìn)8位數(shù)據(jù)到AL,最低位即反映READY/BUSY―信號(hào)的狀態(tài)。再用TEST指令將AL高7位清0(只影響標(biāo)志位,不回送結(jié)果),若結(jié)果為0,說(shuō)明READY/BUSY―信號(hào)為低電平,芯片正忙,則跳轉(zhuǎn)繼續(xù)循環(huán)等待。直到芯片真正把數(shù)據(jù)寫入到對(duì)應(yīng)單元,READY/BUSY―變?yōu)楦唠娖?#xff0c;結(jié)果為1時(shí)才不再跳轉(zhuǎn)順序執(zhí)行下面的指令

然后講了下為什么要把忙信號(hào)設(shè)計(jì)成漏極開(kāi)路

?

?

?

閃速E2PROM : Flash

對(duì)于E2PROM,需要快寫必須一次寫一頁(yè),按字節(jié)寫速度慢。編程時(shí)間長(zhǎng)、容量小

Flash : 容量大,編程速度快。成本低、密度大。應(yīng)用廣泛

本章后面的內(nèi)容都是了解性的,可以自己看對(duì)應(yīng)的錄播(10.18后半節(jié))和課件

?

輸入/輸出技術(shù)

程序查詢 I/O 方式

無(wú)條件傳送方式

有一些最簡(jiǎn)單的外設(shè)不需要查詢,可以隨時(shí)給它發(fā)命令,隨時(shí)讀它的狀態(tài),這種外設(shè)可以采用無(wú)條件傳送的方式

?

輸入:開(kāi)關(guān)、…

輸出:發(fā)光二極管、繼電器、步進(jìn)電機(jī)、…

?

輸入設(shè)備

下圖中外設(shè)是開(kāi)關(guān),10K的上拉電阻經(jīng)過(guò)開(kāi)關(guān)接地,電容起到消抖的作用。要讀該外設(shè)的狀態(tài),不能直接連接到系統(tǒng)總線,要經(jīng)過(guò)三態(tài)門以避免總線競(jìng)爭(zhēng)

CPU要訪問(wèn)該外設(shè)時(shí)才允許把這根線的狀態(tài)輸入到系統(tǒng)總線的某一根數(shù)據(jù)線上,否則這根線應(yīng)該和系統(tǒng)總線沒(méi)有任何關(guān)系

74LS244有8個(gè)三態(tài)門,我們只需要接到其中某一個(gè)的輸入,該三態(tài)門的輸出接到系統(tǒng)總線數(shù)據(jù)線的最低位D0

三態(tài)門的控制端,允許信號(hào)OE―接一個(gè)或門。或門的一個(gè)輸入端接接口讀信號(hào)IOR―,另外兩個(gè)輸入端接譯碼的輸出,譯碼的輸入是低16位地址線

下圖連的是8088的總線。但不管是8086還是8088訪問(wèn)接口都只需要用到低16位地址線

這里簡(jiǎn)化了AEN信號(hào),AEN應(yīng)為低電平表示CPU在控制總線而不是處在DMA狀態(tài)

?

不難得接口地址是FFF7H。有了該接口地址之后可以寫一段匯編程序。首先接口地址FFF7H傳送到DX,因?yàn)橥ǔ2还苁荌N指令還是OUT指令都要求接口地址得在DX,然后執(zhí)行IN指令,從地址為FFF7H的接口讀8位數(shù)據(jù)到AL,AL的最低位反映的就是開(kāi)關(guān)的狀態(tài)。接下來(lái)用AND指令將高7位清0,如果結(jié)果為0說(shuō)明A開(kāi)關(guān)閉合,跳轉(zhuǎn)到ON標(biāo)號(hào)執(zhí)行,否則說(shuō)明開(kāi)關(guān)斷開(kāi),跳轉(zhuǎn)到OFF標(biāo)號(hào)執(zhí)行

?

輸出設(shè)備

下圖中反相器加發(fā)光二極管加限流電阻是一個(gè)外設(shè),總共有8個(gè)外設(shè)。雖然直接連到系統(tǒng)總線的數(shù)據(jù)線不會(huì)造成總線競(jìng)爭(zhēng),但是系統(tǒng)總線是分時(shí)使用的公共信號(hào)線,故必須要接具有存儲(chǔ)能力的鎖存器

鎖存器74LS273的輸出Q0~Q7接8個(gè)外設(shè),輸入D0~D7分別接系統(tǒng)總線數(shù)據(jù)線的D0~D7

鎖存信號(hào)(寫信號(hào))CLK接一個(gè)或門。或門的一個(gè)輸入端接接口寫信號(hào)IOW―,另外兩個(gè)輸入端接接譯碼的輸出,譯碼的輸入是低16位地址線

?

不難得接口地址是0000H。具體的控制程序先把接口地址送到DX,然后把要往接口寫的數(shù)據(jù)送到AL,再執(zhí)行OUT指令把數(shù)據(jù)寫入鎖存器,其輸出在下次改寫前都保持不變

?

剛才針對(duì)的都是8088的8位總線,現(xiàn)在要設(shè)計(jì)16位總線的8086的接口

下圖中有16個(gè)外設(shè),用2片74LS273構(gòu)成一個(gè)16位的接口

上面的74LS273作為偶地址存儲(chǔ)體,輸入D0~D7連系統(tǒng)總線數(shù)據(jù)線的低8位D0~D7,譯碼時(shí)加A0必須為低電平的條件

下面的74LS273作為奇地址存儲(chǔ)體,輸入D0~D7連系統(tǒng)總線的高8位D8~D15,譯碼時(shí)加BHE―必須為低電平的條件

用3-8譯碼器做接口地址譯碼,輸入為地址A1~A15和IOW―

?

不難得偶地址存儲(chǔ)體的地址為3804H,奇地址存儲(chǔ)體的地址為3805H。程序首先做偶地址8位寫。把偶地址存儲(chǔ)體的地址放在DX,然后把要寫入的數(shù)據(jù)放在AL。再執(zhí)行OUT指令,該指令執(zhí)行時(shí)用的是8位的AL,是8位接口寫,并且接口地址是偶地址,會(huì)把數(shù)據(jù)寫入到上面的74LS273,不會(huì)影響到下面的74LS273

然后做奇地址8位寫和16位寫

?

?

?

查詢方式

查詢方式的基礎(chǔ)是必須要有能讀取外設(shè)當(dāng)前狀態(tài)的輸入接口,根據(jù)外設(shè)的不同狀態(tài)決定應(yīng)該對(duì)外設(shè)采取什么樣的操作

?

下圖中外設(shè)引腳有8根數(shù)據(jù)線D0~D7,鎖存信號(hào)(寫信號(hào))STB―,忙信號(hào)BUSY。忙信號(hào)為高電平則等待,忙信號(hào)為低電平則把要寫入的下一個(gè)數(shù)據(jù)放在8根數(shù)據(jù)線上,當(dāng)數(shù)據(jù)穩(wěn)定之后在STB―給一個(gè)寬度大于100μs的負(fù)脈沖,在負(fù)脈沖的上升沿把數(shù)據(jù)寫入到外設(shè)。寫入的數(shù)據(jù)內(nèi)部需要花一定時(shí)間處理,一旦寫完則BUSY馬上變?yōu)楦唠娖健.?dāng)忙信號(hào)再次變?yōu)榈碗娖?#xff0c;說(shuō)明上一個(gè)數(shù)據(jù)已經(jīng)處理完,然后再重復(fù)上面的過(guò)程

?

現(xiàn)在要設(shè)計(jì)基于該外設(shè)的接口

要設(shè)計(jì)輸出接口來(lái)給外設(shè)提供8位數(shù)據(jù)和鎖存信號(hào),輸入接口讀外設(shè)BUSY信號(hào)當(dāng)前的狀態(tài)。輸出接口用鎖存器實(shí)現(xiàn),輸入接口用三態(tài)門實(shí)現(xiàn)

第一個(gè)輸出接口要提供8位的數(shù)據(jù),需要一個(gè)74LS273,一邊D0~D7接系統(tǒng)總線數(shù)據(jù)線D0~D7,一邊Q0~Q7接外設(shè),CLK接一個(gè)或門,或門的一個(gè)輸入端接IOW―,另外一端接地址譯碼電路的一個(gè)輸出

另一個(gè)輸出接口的74LS273只用到其中的一位,其輸入接某一根系統(tǒng)總線數(shù)據(jù)線,輸出接STB―,CLK接一個(gè)或門,或門的一個(gè)輸入端接IOW―,另外一端接地址譯碼電路的一個(gè)輸出

輸入接口的74LS244只用到其中的一個(gè)三態(tài)門,其輸入接BUSY,輸出接某一根系統(tǒng)總線數(shù)據(jù)線。OE―接一個(gè)或門,或門的一個(gè)輸入端接IOR―,另外一端接地址譯碼電路的一個(gè)輸出

再用3-8譯碼器實(shí)現(xiàn)接口地址譯碼電路,需要的3個(gè)輸出為Y0―~Y2―,輸入為低16位地址A0~A15

?

不難得Y0―~Y2―對(duì)應(yīng)的接口地址分別為02F8H,02F9H,02FAH

?

編程首先把段的起始地址的高16位D200H通過(guò)通用寄存器傳到DS,然后用寄存器間接尋址就可以訪問(wèn)到內(nèi)存從這個(gè)單元開(kāi)始的這些數(shù)據(jù)。指針寄存器可以是BX,SI,DI,這里用BX,將BX初值置為0。循環(huán)次數(shù)1000放在CX

初始化STB―,STB―寫時(shí)給負(fù)脈沖,不寫時(shí)應(yīng)該是高電平。OUT指令把AL的內(nèi)容01H寫入到接口地址02F9H對(duì)應(yīng)的中間的74LS273令Q0=1,將STB―置為高電平為后面寫數(shù)據(jù)做準(zhǔn)備

判斷BUSY的狀態(tài)。IN指令讀地址為02FA的接口,讀取的數(shù)據(jù)放在AL。再用AND指令將低7位清0只保留最高位。如果結(jié)果不為0,說(shuō)明BUSY為高電平,就跳轉(zhuǎn)回上面再讀,一直循環(huán)到結(jié)果為0,BUSY變?yōu)榈碗娖讲彭樞驁?zhí)行后面的指令

數(shù)據(jù)輸出。利用寄存器間接尋址,DS為默認(rèn)段寄存器,BX存段內(nèi)偏移,從內(nèi)存D2000H取數(shù)據(jù)放在AL。OUT指令將該數(shù)據(jù)寫入接口地址02F8H對(duì)應(yīng)的上面的74LS273,給外設(shè)提供數(shù)據(jù)

數(shù)據(jù)已經(jīng)準(zhǔn)備好,將STB―置為低電平,延時(shí)100μs后再將STB―置為高電平。在STB―的上升沿將數(shù)據(jù)寫入到外設(shè)

寫完之后BX內(nèi)容加1指向內(nèi)存的下一個(gè)單元,然后繼續(xù)循環(huán)。總共循環(huán)1000次,每次都先判斷BUSY忙則等待,不忙再寫下一個(gè)數(shù)據(jù)

然后引申講了下輸出接口和輸入接口占用同一個(gè)接口地址等簡(jiǎn)化軟硬件的方法

?

多外設(shè)的查詢控制

這種方式不好。因?yàn)槿绻骋粋€(gè)外設(shè)壞了永遠(yuǎn)處于沒(méi)準(zhǔn)備好的狀態(tài),CPU就會(huì)老是等待,其他外設(shè)也永遠(yuǎn)得不到服務(wù)

?

這種方式有優(yōu)先級(jí)的概念,會(huì)偏向認(rèn)為先查詢的外設(shè)更重要

?

如果不需要優(yōu)先級(jí),機(jī)會(huì)均等。采用這種方式

?

中斷方式

x86處理器處理中斷的過(guò)程在第二章講CPU引腳時(shí)已經(jīng)介紹過(guò),可以查閱當(dāng)時(shí)的筆記。這里介紹來(lái)自INTR引腳的中斷請(qǐng)求,一般對(duì)應(yīng)的都是外設(shè)或接口的中斷請(qǐng)求

?

?

假設(shè)CPU執(zhí)行到某條指令,通過(guò)INTR引腳來(lái)一個(gè)中斷請(qǐng)求。這種情況下若滿足中斷響應(yīng)的條件:標(biāo)志寄存器中中斷允許標(biāo)志位IF為1處于開(kāi)中斷狀態(tài),當(dāng)前這條指令執(zhí)行完才會(huì)響應(yīng)中斷請(qǐng)求

首先要保護(hù)當(dāng)前的斷點(diǎn),依次將Flags,CS,IP的內(nèi)容壓入堆棧,并將標(biāo)志寄存器中的中斷允許標(biāo)志位IF和陷阱標(biāo)志位IF清0關(guān)中斷,這樣再?gòu)倪@個(gè)引腳來(lái)中斷請(qǐng)求CPU就不會(huì)響應(yīng)了

標(biāo)志寄存器教材叫程序狀態(tài)字PSW,即下圖的Flags。子程序調(diào)用則不需要保護(hù)Flags的內(nèi)容

1413:0105表示內(nèi)存地址,左側(cè)是段寄存器的內(nèi)容,右側(cè)是段內(nèi)偏移

然后CPU會(huì)通過(guò)INTA―連續(xù)送出兩個(gè)負(fù)脈沖。8259接收到第一個(gè)負(fù)脈沖就知道CPU正在響應(yīng)剛才的中斷請(qǐng)求,它會(huì)準(zhǔn)備好發(fā)出中斷請(qǐng)求的中斷源的8位中斷向量碼,等第二個(gè)負(fù)脈沖來(lái)時(shí)將其放在低8位數(shù)據(jù)線上讓CPU采樣得到

CPU會(huì)根據(jù)中斷向量查從內(nèi)存地址0開(kāi)始放的中斷向量表的對(duì)應(yīng)行,獲取對(duì)應(yīng)的中斷服務(wù)程序的入口地址。中斷向量表每一行4個(gè)字節(jié),前2個(gè)字節(jié)存段內(nèi)偏移賦值給IP,后2個(gè)字節(jié)存段寄存器的內(nèi)容賦值給CS,下一條指令就會(huì)跳轉(zhuǎn)到從中斷服務(wù)程序的第一條指令的地址開(kāi)始取并執(zhí)行

注意是小端存儲(chǔ),小地址對(duì)應(yīng)低字節(jié),大地址對(duì)應(yīng)高字節(jié)

中斷服務(wù)程序的結(jié)構(gòu)和子程序很像,也要保護(hù)現(xiàn)場(chǎng),將要修改的控制寄存器的內(nèi)容先壓入堆棧,用完之后再恢復(fù)現(xiàn)場(chǎng),然后再中斷返回。執(zhí)行中斷返回指令I(lǐng)RET時(shí)會(huì)從堆棧彈出3個(gè)數(shù)恢復(fù)Flags,CS,IP,返回到剛才被打斷的指令的下一條指令繼續(xù)執(zhí)行

CPU硬件在響應(yīng)中斷時(shí)會(huì)自動(dòng)關(guān)中斷。如果中斷服務(wù)程序允許中斷嵌套,在保護(hù)現(xiàn)場(chǎng)之后加開(kāi)中斷指令STI,恢復(fù)現(xiàn)場(chǎng)之前再用關(guān)中斷指令CLI

這里內(nèi)部中斷理解成中斷源在CPU內(nèi)部,跟調(diào)試無(wú)關(guān)的那些中斷,如除法錯(cuò)誤中斷。跟調(diào)試有關(guān)的那些中斷,如單步中斷和斷點(diǎn)中斷通常優(yōu)先級(jí)最低

?

?

?

可編程中斷控制器8259

可對(duì)8個(gè)中斷源實(shí)現(xiàn)優(yōu)先級(jí)控制

支持多片級(jí)聯(lián),一個(gè)主片可以有8個(gè)從片,可擴(kuò)展至對(duì)64個(gè)中斷源實(shí)現(xiàn)優(yōu)先級(jí)控制

可編程設(shè)置不同工作方式

根據(jù)中斷源向x86提供不同中斷類型碼

可編程就是該芯片內(nèi)部有一些寄存器,往寄存器里面寫入不同的內(nèi)容就可以具有不同的功能,可以工作在不同的模式下

?

8259內(nèi)部結(jié)構(gòu)

8259的引腳:

中斷源中斷請(qǐng)求輸入IR0~I(xiàn)R7

雙向數(shù)據(jù)總線D0~D7

中斷請(qǐng)求INTR,中斷應(yīng)答INTA―

讀信號(hào)RD―,寫信號(hào)WR― : 要對(duì)內(nèi)部寄存器進(jìn)行讀寫,讀寫時(shí)傳數(shù)據(jù)通過(guò)8根數(shù)據(jù)線

片選信號(hào)CS― : 支持多片級(jí)聯(lián),要看訪問(wèn)哪一片

地址A0 : 8259只有一根地址線,只需要占用2個(gè)接口地址

上圖中還有4個(gè)引腳,這幾個(gè)引腳和級(jí)聯(lián)有關(guān),如果只是單片使用用不上

?

需要了解3個(gè)寄存器:

中斷請(qǐng)求寄存器IRR (INTERRUPT REQUEST REG):保存從IR0~I(xiàn)R7來(lái)的中斷請(qǐng)求信號(hào),某位=1表示對(duì)應(yīng)的IRi有中斷請(qǐng)求

中斷屏蔽寄存器IMR (INTERRUPT MASK REG):存放中斷屏蔽字,某位=1表示對(duì)應(yīng)的IRi輸入被屏蔽

中斷服務(wù)寄存器ISR (IN - SERVICE REG):保存正在服務(wù)的中斷源,某位=1表示對(duì)應(yīng)的IRi中斷正在被服務(wù)

?

中斷優(yōu)先權(quán)判別電路 (PRIORITY RESOLVER): 確定是否向CPU發(fā)出中斷請(qǐng)求,中斷響應(yīng)時(shí)確定ISR的哪位應(yīng)置位及把相應(yīng)中斷的類型碼放到數(shù)據(jù)總線上

?

?

下圖中即表示8086/8088 CPU正在執(zhí)行IR6和IR4兩個(gè)引腳所對(duì)應(yīng)的中斷源的中斷服務(wù)程序,CPU同時(shí)執(zhí)行兩個(gè)中斷源的中斷服務(wù)程序,很顯然發(fā)生了中斷嵌套。引腳IR2,IR3,IR5同時(shí)發(fā)中斷請(qǐng)求,作為8259如果是固定優(yōu)先級(jí),編號(hào)小的優(yōu)先級(jí)高。考慮到IR2被屏蔽,且IR3優(yōu)先級(jí)高于IR6和IR4,8259會(huì)通過(guò)INT向CPU發(fā)一個(gè)IR3的中斷請(qǐng)求

CPU通過(guò)一系列過(guò)程響應(yīng)中斷,再通過(guò)INTA―給8259送連續(xù)2個(gè)負(fù)脈沖。8259接收到第一個(gè)負(fù)脈沖后,因?yàn)镃PU馬上要執(zhí)行到IR3對(duì)應(yīng)的中斷源的中斷服務(wù)程序,會(huì)將ISR的第3位置1,IRR的第3位清0

?

CPU在中斷服務(wù)程序執(zhí)行完之后通知8259可以將ISR的相應(yīng)位清0。在中斷服務(wù)程序的最后恢復(fù)現(xiàn)場(chǎng)之前要給8259發(fā)一個(gè)EOI中斷結(jié)束命令。要實(shí)現(xiàn)EOI功能可能需要3條指令,先將8259的偶地址(8259只有一根地址線,地址線給0是偶地址,給1是奇地址)放到DX,要寫入的內(nèi)容放在AL,再用OUT指令把AL的內(nèi)容寫入到DX所指向的接口

MOV DX,8259偶地址 MOV AL,20H OUT DX,AL

寫的數(shù)是20H,是一般EOI命令。允許中斷嵌套并且是正常優(yōu)先級(jí)的情況下就會(huì)在在中斷服務(wù)程序的末尾向8259發(fā)一個(gè)一般EOI命令。8259接收到命令后將ISR中優(yōu)先級(jí)最高的那一位清0,因?yàn)橛姓?yōu)先級(jí)概念的情況下,如果允許中斷嵌套,最先執(zhí)行完的中斷服務(wù)程序肯定是優(yōu)先級(jí)最高的

?

8259工作方式

緩沖方式可以設(shè)成非緩沖和緩沖。如果設(shè)置成工作在緩沖方式,雙向數(shù)據(jù)線需要加一個(gè)74LS245驅(qū)動(dòng)器,其OE―信號(hào)由8259的SP―/EN―作為輸出引腳提供。如果沒(méi)有工作在緩沖模式下,SP―/EN―作為輸入引腳讓多片級(jí)聯(lián)時(shí)8259可以知道自己是主片還是從片,其接到高電平為主片,接地為從片

書上后面的例子都沒(méi)有讓8259工作在緩沖模式下

?

中斷是否允許嵌套即中斷程序是否允許被優(yōu)先級(jí)更高的中斷源打斷。如果不允許中斷嵌套就設(shè)置中斷結(jié)束方式為自動(dòng)EOI方式。在接收到中斷應(yīng)答的第二個(gè)負(fù)脈沖時(shí)就會(huì)將ISR的內(nèi)容清0,此時(shí)可以簡(jiǎn)單地認(rèn)為ISR的內(nèi)容總是0,不會(huì)記錄CPU正在執(zhí)行哪一個(gè)中斷源的中斷服務(wù)程序,所以也就無(wú)法實(shí)現(xiàn)帶優(yōu)先級(jí)的各種中斷嵌套。這樣在編寫中斷服務(wù)程序時(shí)就不用加STL指令,末尾也不需要向8259發(fā)EOI命令

?

屏蔽方式可以設(shè)成一般屏蔽和特殊屏蔽。一般屏蔽就是正常優(yōu)先級(jí)的概念,即如果CPU正在執(zhí)行某一個(gè)中斷源的中斷服務(wù)程序,同級(jí)的和優(yōu)先級(jí)更低的中斷源是不能打斷當(dāng)前的中斷服務(wù)程序的,這樣在中斷服務(wù)程序的末尾要向8259發(fā)一個(gè)一般EOI命令。如果設(shè)置成特殊屏蔽方式就沒(méi)有優(yōu)先級(jí)的概念,只要不是同級(jí)的,任何一個(gè)其他的中斷源都可以打斷當(dāng)前的服務(wù)程序,究竟哪一個(gè)中斷服務(wù)程序最先執(zhí)行完不一定, 這樣在中斷服務(wù)程序的末尾要向8259發(fā)一個(gè)特殊EOI命令,里面包含清0的那一位的編號(hào),明確告訴8259應(yīng)該把ISR的哪一位清0

教材上后面的例子都讓8259工作在一般屏蔽方式

?

剛才舉的這些例子都默認(rèn)8259工作在固定優(yōu)先級(jí),優(yōu)先級(jí)順序從高到低為IR0~ IR7,還可以設(shè)置成循環(huán)優(yōu)先級(jí)

自動(dòng)循環(huán)優(yōu)先級(jí):

中斷源輪流處于最高優(yōu)先級(jí),即自動(dòng)中斷級(jí)循環(huán)

初始優(yōu)先級(jí)順序可由編程改變

某中斷請(qǐng)求IRi被處理后,其優(yōu)先級(jí)別自動(dòng)降為最低,原來(lái)比它低一級(jí)的優(yōu)先級(jí)上升為最高級(jí)

指定循環(huán)優(yōu)先級(jí):

優(yōu)先級(jí)排列順序可編程改變

加電后8259A的默認(rèn)方式,默認(rèn)優(yōu)先級(jí)順序從高到低為IR0~I(xiàn)R7

?

最后看8259是否需要多片級(jí)聯(lián)。如果不需要級(jí)聯(lián)單片工作設(shè)置成一般嵌套方式。如果是多片級(jí)聯(lián)主片設(shè)置成特殊嵌套方式,從片設(shè)置成一般嵌套方式

8259級(jí)聯(lián):

單片8259A可支持8個(gè)中斷源

采用多片8259A級(jí)連,可最多支持64個(gè)中斷源。n片8259A可支持7n+1 (n≤9) 個(gè)中斷源

級(jí)聯(lián)時(shí)只有一片8259A為從片,其余的均為從片。只有主片有能力向CPU發(fā)中斷請(qǐng)求。從片的中斷請(qǐng)求連到主片的某一個(gè)IRi引腳,從片所有引腳發(fā)的中斷請(qǐng)求都得從該引腳走,從片再向主片發(fā)中斷請(qǐng)求,主片再向CPU發(fā)中斷請(qǐng)求

涉及到的8259A引腳包括:CAS0?CAS2,SP―/EN―,IRi,INT

?

通過(guò)SP―/EN―引腳8259得知自己是主片還是從片,其接高電平是主片,接地是從片。ICW3寫什么內(nèi)容和級(jí)聯(lián)狀態(tài)下怎么連有關(guān)系,通過(guò)初始化過(guò)程向ICW3寫入適當(dāng)?shù)膬?nèi)容,讓主片知道IRi引腳接的是從片還是中斷源,讓從片知道接的是主片的IRi引腳

8259有4個(gè)初始化命令字ICW1~I(xiàn)CW4,還有3個(gè)操作命令字OCW1~OCW3。OCW1其實(shí)就是IMR,所以8259內(nèi)部總共有9個(gè)寄存器

連電路時(shí)INTA―接主片和從片,所有8259都能接收到CPU從INTA―發(fā)來(lái)的兩個(gè)連續(xù)負(fù)脈沖。主片通過(guò)INTA―接收到第一個(gè)負(fù)脈沖后會(huì)對(duì)ISR和IRR置位。主片替IRi向CPU發(fā)中斷請(qǐng)求,就會(huì)通過(guò)CAS0~CAS2這3根線送級(jí)聯(lián)地址i給兩個(gè)從片,兩個(gè)從片在中斷應(yīng)答的第一個(gè)負(fù)脈沖會(huì)檢查這3根線的狀態(tài)與ICW3內(nèi)容作比較,一致則對(duì)ISR和IRR置位,并在第二個(gè)負(fù)脈沖來(lái)時(shí)提供中斷向量

一般嵌套方式與特殊全嵌套方式的區(qū)別:

主片能夠區(qū)分引腳哪一個(gè)接中斷源,哪一個(gè)接從片。只有接從片的引腳才允許同級(jí)的中斷源打斷當(dāng)前的中斷服務(wù)程序

?

?

8259編程使用

內(nèi)部寄存器的尋址方式:

需要CS―,A0,RD―,WR―和D4,D3的配合。內(nèi)部寄存器的訪問(wèn)方法如下表

?

為了能夠區(qū)分內(nèi)部究竟訪問(wèn)的是哪一個(gè)寄存器,寫入數(shù)據(jù)的某一位在8259內(nèi)部也是當(dāng)?shù)刂穪?lái)用的

如8259要能正常工作必須要有初始化的過(guò)程,往4個(gè)ICW里寫入事先設(shè)計(jì)好的內(nèi)容。首先要寫ICW1,ICW1對(duì)應(yīng)的是8259的偶地址,即A0=0的情況。所以如果想要初始化8259,第一步就要往8259的偶地址里寫入D4位為1的一個(gè)數(shù)據(jù)

Icw1的結(jié)構(gòu)如下。D2和D5~D7這幾位沒(méi)有用到,LTIM表示IR0~I(xiàn)R7這8根線是高電平還是上升沿有效,SNGL表示是單片工作(級(jí)聯(lián)控制字ICW3不需要寫)還是多片級(jí)聯(lián),IC4表示是否要寫ICW4

一旦ICW1被寫就啟動(dòng)了一個(gè)初始化的過(guò)程,緊接著要馬上寫后面這幾個(gè)ICW,往奇地址里面連續(xù)寫入若干個(gè)數(shù):

若現(xiàn)在寫ICW1,將其配置成多片級(jí)聯(lián)并且要寫ICW4就要寫3個(gè)數(shù),分別自動(dòng)寫入到ICW2~I(xiàn)CW4

如果寫的內(nèi)容規(guī)定是單片工作且要寫ICW4,就要寫2個(gè)數(shù),分別自動(dòng)寫入到ICW2和ICW4

如果寫的內(nèi)容規(guī)定是單片工作且不要寫ICW4,就要寫1個(gè)數(shù),到ICW2

一旦初始化的過(guò)程完成之后,后面這些OCW隨時(shí)都可以寫,按什么順序?qū)懚紵o(wú)所謂,寫不寫都可以

電路連好后怎么檢查8259能否正常工作,或者說(shuō)它的寄存器能否正常讀寫?

OCW1是8259內(nèi)部唯一一個(gè)既可以寫又可以讀的寄存器,它對(duì)應(yīng)奇地址

初始化完之后往8259的奇地址里面寫入全0,再讀出來(lái)比較一下是否為全0。再寫入全1,讀出來(lái)比較一下是否為全1。如果都對(duì)就認(rèn)為8259內(nèi)部的這些寄存器能夠正常寫入,數(shù)據(jù)線和地址線的連法應(yīng)該也沒(méi)有問(wèn)題

?

ICW1:初始化字

上面已經(jīng)進(jìn)行了說(shuō)明

ICW2:中斷向量碼

ICW3:級(jí)聯(lián)控制字

ICW4:中斷結(jié)束方式字

?

OCW1:中斷屏蔽字

OCW2:中斷結(jié)束和優(yōu)先級(jí)循環(huán)

OCW3:屏蔽方式和讀出控制字

?

?

中斷方式實(shí)現(xiàn)方法

1.8259連接(硬件)

若要連接到8086的系統(tǒng)總線。8259地址線只有一根,占用2個(gè)接口地址,如果想把它映射到偶地址上,或者說(shuō)作為一個(gè)偶地址存儲(chǔ)體,其8根數(shù)據(jù)線要連接到系統(tǒng)總線數(shù)據(jù)線的低8位。A0是偶地址存儲(chǔ)體的選擇信號(hào),地址線從A1開(kāi)始,故這塊應(yīng)該連到A1上,A1作為芯片的內(nèi)部地址,高位地址從A2開(kāi)始

?

如果要映射到偶地址最好讓A0也參與譯碼,限定A0是0。下圖中因?yàn)锳0沒(méi)有參與譯碼其實(shí)應(yīng)該占用4個(gè)接口地址FF00H~FF03H,但實(shí)際上如FF00H和FF01H這兩個(gè)地址中只能用FF00H,因?yàn)镕F01H對(duì)8086來(lái)講是奇地址,8086不管是訪問(wèn)內(nèi)存還是接口,如果訪問(wèn)的是奇地址就會(huì)通過(guò)高8位的數(shù)據(jù)線來(lái)傳遞數(shù)據(jù)。所以如果你用FF01H這個(gè)地址讀8259的某一個(gè)寄存器,IN指令執(zhí)行時(shí)8086只會(huì)采樣數(shù)據(jù)線的高8位,雖然8259芯片已經(jīng)輸出了寄存器的內(nèi)容,但它放在了數(shù)據(jù)線的低8位,得不到數(shù)據(jù)

所以我們?cè)谶B數(shù)據(jù)線時(shí)這8根線連接到系統(tǒng)總線的低8位,8086在訪問(wèn)該8259芯片時(shí)就必須要用偶地址,用奇地址訪問(wèn)不到芯片內(nèi)部的寄存器。FF01H和FF03H這2個(gè)接口地址雖然被占用但是不能用,如果不想浪費(fèi),就應(yīng)該加限定A0是0的條件,這樣電路就只占用2個(gè)接口地址,對(duì)于8086來(lái)講這兩個(gè)都是偶地址,對(duì)于8259來(lái)講,FF00H是8偶地址,FF02H是奇地址

如果計(jì)算機(jī)中有DMA存在,應(yīng)該有限定AEN―是低電平的條件

?

2.編寫初始化程序:8259初始化,設(shè)置中斷向量表

在有了硬件的基礎(chǔ)上。計(jì)算機(jī)剛一加電啟動(dòng)的過(guò)程中,通常由BIOS程序負(fù)責(zé)對(duì)8259的ICW寫入事先設(shè)計(jì)好的內(nèi)容來(lái)進(jìn)行初始化讓它工作在期望的模式下

初始化8259:

SET59A:MOV DX,0FF00H ;8259的地址A0=0MOV AL,13H ;寫ICW1,邊沿觸發(fā),單片,需要ICW4OUT DX,ALMOV DX,0FF02H ;8259的地址A0=1MOV AL,48H ;寫ICW2,設(shè)置中斷向量碼OUT DX,ALMOV AL,03H ;寫ICW4,8086/88模式,自動(dòng)EOI;非緩沖,一般嵌套OUT DX,ALMOV AL,0E0H ;寫OCW1,屏蔽IR5、IR6、IR7;(假定這3個(gè)中斷輸入未用)OUT DX,AL

?

下例檢查硬件電路能否正常工作,可以認(rèn)為和前面的初始化沒(méi)有關(guān)系

;將00H與FFH分別寫入IMR,并將其讀出比較 MOV DX,0FF02H MOV AL,0 OUT DX,AL ;寫OCW1,將00H寫入IMR IN AL,DX ;讀IMR OR AL,AL ;判斷IMR內(nèi)容為00H否 JNZ IMRERR MOV AL,0FFH OUT DX,AL IN AL,DX ADD AL,1 JNZ IMRERR

?

設(shè)置中斷碼:

中斷向量碼初始化位48H,中斷處理程序入口地址的標(biāo)號(hào)為CLOCK,設(shè)置中斷向量表

法1 直接寫中斷向量表

INTITB: MOV AX,0MOV DS,AX ;將內(nèi)存段設(shè)置在最低端MOV SI,0120H ;n=48H, 4×n=120HMOV AX,OFFSET CLOCK ;獲取中斷處理程序首地址的段內(nèi)偏移地址MOV [SI],AX ;段內(nèi)偏移地址寫入中斷向量表4×n地址處MOV AX,SEG CLOCK ;獲取中斷處理程序首地址的段地址MOV [SI+2],AX ;段地址寫入中斷向量表4×n+2地址處

?

法2 利用DOS功能調(diào)用

MOV AH,25H ;功能號(hào) MOV AL,48H ;中斷向量碼 MOV DX,SEG CLOCK MOV DS,DX ;段地址→DS MOV DX,OFFSET CLOCK ;偏移地址→DX INT 21H

?

3.編寫中斷處理程序

中斷嵌套的實(shí)現(xiàn):

保護(hù)現(xiàn)場(chǎng) (PUSH reg’s)

開(kāi)中斷 (STI)

中斷服務(wù)

中斷服務(wù)

關(guān)中斷 (CLI)

產(chǎn)生EOI命令

恢復(fù)現(xiàn)場(chǎng) (POP reg’s)

中斷返回

?

產(chǎn)生EOI命令:

上例初始化時(shí)設(shè)置成自動(dòng)EOI模式,所以中斷服務(wù)程序的末尾沒(méi)有必要向8259發(fā)EOI命令。如果允許中斷嵌套,工作在一般EOI方式,往8259偶地址中寫入20H相當(dāng)于發(fā)一個(gè)一般EOI命令,8259會(huì)把ISR置1位中優(yōu)先級(jí)最高的那一位清0

中斷方式實(shí)現(xiàn)示例

初始化8259:SET59A

初始化中斷向量表:INTITB

?

中斷處理程序:CLOCK

假設(shè)在內(nèi)存中有連續(xù)這么幾個(gè)字節(jié)的數(shù)據(jù),第一個(gè)字節(jié)由標(biāo)號(hào)TIMER指向,存1/50秒的信息,下一個(gè)字節(jié)存秒的信息,再下一個(gè)字節(jié)存分鐘的信息,最后一個(gè)字節(jié)存小時(shí)的信息。并且后三個(gè)字節(jié)的內(nèi)容采用壓縮的BCD碼的形式存,1/50秒直接用二進(jìn)制的形式存

DAA指令會(huì)根據(jù)當(dāng)前標(biāo)志寄存器里面的一些信息決定要不要加6修正

?

DMA的過(guò)程之前講過(guò),DMA控制器8237不具體講

可編程8237芯片有4個(gè)通道,可以實(shí)現(xiàn)內(nèi)存到接口,內(nèi)存到內(nèi)存之間的數(shù)據(jù)傳送,但是不能實(shí)現(xiàn)接口到接口之間的數(shù)據(jù)傳送

?

到此這章的內(nèi)容就結(jié)束了。后面還講了下TSR時(shí)鐘顯示程序和比較新的計(jì)算機(jī)如何實(shí)現(xiàn)中斷和DMA

常用接口器件

思考:計(jì)算機(jī)和外設(shè)之間如何通過(guò)接口傳送數(shù)據(jù)(非DMA)?

最簡(jiǎn)單的方式是上一章講的程序查詢或者說(shuō)直接控制

想讀輸入設(shè)備當(dāng)前的狀態(tài),通過(guò)三態(tài)門實(shí)現(xiàn)接口。給三態(tài)門接口地址,只有用IN指令讀地址為這個(gè)的接口時(shí),三態(tài)門才打開(kāi)把外設(shè)的狀態(tài)輸出到系統(tǒng)總線數(shù)據(jù)線,IN指令最后采樣數(shù)據(jù)線把外設(shè)的狀態(tài)讀到CPU內(nèi)部寄存器

用OUT指令輸出數(shù)據(jù),數(shù)據(jù)只在OUT指令執(zhí)行的瞬間呈現(xiàn)在數(shù)據(jù)線上,所以輸出接口需要用鎖存器實(shí)現(xiàn)存儲(chǔ)功能

下圖中輸入接口只能讀不能寫,只需要IOR―信號(hào)參與地址譯碼。輸出接口只能寫不能讀,只需要IOW―信號(hào)參與地址譯碼

?

這種方式CPU利用率較低,大部分時(shí)間都花在不停地循環(huán)查詢外設(shè)。如果想要提高CPU的利用率,外設(shè)或者說(shuō)接口能夠引入中斷功能,外設(shè)不忙需要CPU參與時(shí)再給CPU發(fā)中斷請(qǐng)求

輸出接口里有可以暫存數(shù)據(jù)的緩沖寄存器,可以判斷該寄存器內(nèi)容是否為空,即數(shù)據(jù)是否已被外設(shè)取走。如果為空應(yīng)該向通過(guò)INTR―信號(hào)向CPU發(fā)中斷請(qǐng)求通知CPU緩存已空,能否寫入新的數(shù)據(jù)。CPU經(jīng)過(guò)一定過(guò)程響應(yīng)中斷,最終進(jìn)入中斷服務(wù)程序,中斷服務(wù)程序把要傳輸給外設(shè)的下一個(gè)數(shù)據(jù)寫入到接口內(nèi)部的緩沖寄存器,寫完直接返回。接口檢測(cè)到緩沖寄存器寫入新數(shù)據(jù),將OBF―信號(hào)置低通知外設(shè)拿走數(shù)據(jù),外設(shè)采樣數(shù)據(jù)線拿走數(shù)據(jù)處理完后通過(guò)ACK―信號(hào)發(fā)一個(gè)負(fù)脈沖通知接口數(shù)據(jù)已被取走。接口將OBF―信號(hào)置高,同時(shí)再次向CPU發(fā)中斷請(qǐng)求重復(fù)剛才的過(guò)程

輸入接口里也有可以暫存數(shù)據(jù)的寄存器,可以通知外設(shè)緩沖寄存器內(nèi)容為空可以寫下一個(gè)數(shù)據(jù)。外設(shè)通過(guò)數(shù)據(jù)線提供數(shù)據(jù),數(shù)據(jù)穩(wěn)定后通過(guò)STB―信號(hào)發(fā)一個(gè)負(fù)脈沖,在負(fù)脈沖的上升沿把數(shù)據(jù)寫入到接口的暫存器中。接口寫入新數(shù)據(jù)后把IBF信號(hào)置高表示輸入緩沖區(qū)滿,通過(guò)INTR―信號(hào)向CPU發(fā)中斷請(qǐng)求,CPU響應(yīng)中斷進(jìn)入到中斷服務(wù)程序,從接口把數(shù)據(jù)讀走。接口將IBF信號(hào)置低,重復(fù)剛才的過(guò)程

ACK―和STB―不是狀態(tài)信號(hào)而是脈沖信號(hào)

設(shè)計(jì)雙向的具有中斷功能的輸入/輸出接口,結(jié)合上述兩種情況

輸入/輸出接口內(nèi)部有2個(gè)寄存器,從CPU角度一個(gè)只能寫不能讀一個(gè)只能讀不能寫,可以占用同一個(gè)寄存器地址。CPU通過(guò)讀狀態(tài)寄存器得知產(chǎn)生中斷的原因并做相應(yīng)處理

?

要實(shí)現(xiàn)上述接口,可以直接用可編程并行接口8255

8255一共有3種工作方式:

工作在方式0的輸入相當(dāng)于三態(tài)門,工作在方式0的輸出相當(dāng)于鎖存器

工作在方式1的輸出相當(dāng)于具有中斷功能的輸出接口,工作在方式1的輸入相當(dāng)于具有中斷功能的輸入接口

工作在方式2相當(dāng)于雙向的輸入/輸出接口

?

8255:可編程并行接口

內(nèi)部結(jié)構(gòu)及外部引線

8255有A,B,C三個(gè)并行接口

每個(gè)并行接口都有8根線,A口為PA7~PA0,B口為PB7~PB0,C口分成相互獨(dú)立,可以分別配置的高4位PC7~PC4和低4位PC3~PC0

任何一個(gè)口都可以工作在方式0,A口還可以工作在方式1和方式2,B口還可以工作在方式1。方式0和方式1可以配置成輸入也可以配置成輸出

工作在方式1和方式2需要借用C口的信號(hào)線

若配置8255的A口工作在方式2。PA7~PA0這8根線跟外設(shè)之間是雙向的,此外構(gòu)成其他的一些握手信號(hào)STB―,IBF,ACK―,OBF―和INTR―還需要分別借用C口的信號(hào)線PC4~PC7和PC3。如果B口剛好工作在方式1,還可以借用C口的另外3根線

A口,B口,C口各有1個(gè)8位的緩沖寄存器,此外還有1個(gè)控制字,加電啟動(dòng)后通過(guò)寫控制字可以初始化8255,配置具體的哪一個(gè)口應(yīng)該工作在哪種方式下。對(duì)這些寄存器進(jìn)行讀寫和總線間要有地址線A0~A1,數(shù)據(jù)線D0~D7和讀信號(hào)RD―,寫信號(hào)WR―,片選信號(hào)CS―

另外還多了1個(gè)復(fù)位信號(hào)RESET,直接接到計(jì)算機(jī)主板的復(fù)位電路引腳。計(jì)算機(jī)剛一加電后復(fù)位電路工作產(chǎn)生負(fù)脈沖,將8255內(nèi)部的控制字自動(dòng)置成事先設(shè)置好的狀態(tài)即A,B,C口均為輸入以避免總線競(jìng)爭(zhēng)

?

8255的方式控制字及狀態(tài)字

8255的地址線有2根,A,B,C三個(gè)口的緩沖寄存器和控制字分別占用地址00,01,10和11

寫地址11,最高位用來(lái)區(qū)分現(xiàn)在是寫控制字還是將C口寄存器的某一位清0或置1

C口寄存器具體的某一位跟C口的引腳之間一般有對(duì)應(yīng)關(guān)系。如C口寄存器的第3位置1,則PC3輸出引腳直接輸出高電平

?

8255的工作方式

?

?

?

8255的尋址和連接使用

方式0:

易得A,B,C口寄存器和控制字的具體接口地址分別是380H,381H,382H,383H

看地址線A0,A1怎么連確定連的是8086還是8088。8259的A0,A1連系統(tǒng)總線的A0,A1連的是8088的系統(tǒng)總線。A0,A1連系統(tǒng)總線的A1,A2連的是8086的系統(tǒng)總線,數(shù)據(jù)線如果連到系統(tǒng)總線低8位必須要給偶地址,地址譯碼電路加偶地址存儲(chǔ)體選擇信號(hào)A0必須是低電平的條件

?

?

8255初始化及應(yīng)用舉例:方式0 - 打印機(jī)接口

除了數(shù)據(jù)線,外設(shè)還要求有鎖存信號(hào)STROBE―,要用B口或C口的某一根線提供(負(fù)脈沖寬度要求≥1us,無(wú)法直接通過(guò)較快的總線信號(hào)提供)。對(duì)外設(shè)來(lái)講STOROBE―信號(hào)是輸入,BUSY信號(hào)是輸出,而C口較為靈活,高4位和低4位可以分別配置。可以讓C口的高4位配置成輸出,只能寫不能讀,再隨便選一根線如PC6,C口的低4位配置成輸入,只能讀不能寫,再隨便選一根線如PC1,剛好既可以判斷BUSY信號(hào)的狀態(tài),又可以給它送STROBE―信號(hào)

?

8255地址:380H~383H

初始化程序:

?

利用8255方式0以程序控制(查詢)方式實(shí)現(xiàn)打印機(jī)接口

?

?

8255初始化及應(yīng)用舉例:方式1 - 打印機(jī)接口

單穩(wěn)觸發(fā)器將下降沿轉(zhuǎn)換為寬度為1us的負(fù)脈沖

同樣這種情況下PC6輸入引腳和C口寄存器的第6位沒(méi)有關(guān)系,C口寄存器的第6位是中斷允許位

8255地址:380H~383H

初始化程序:

?

利用8255方式1程序控制(查詢)方式實(shí)現(xiàn)打印機(jī)接口:

?

利用8255方式1以中斷方式實(shí)現(xiàn)打印機(jī)接口:

8253:可編程定時(shí)器

外部引線及功能

頻率已知的時(shí)鐘信號(hào),對(duì)時(shí)鐘信號(hào)進(jìn)行計(jì)數(shù)就能達(dá)到定時(shí)的效果,所以所謂的定時(shí)器還有另外一個(gè)名字:計(jì)數(shù)器。8253芯片內(nèi)有3個(gè)計(jì)數(shù)器,要求寫入計(jì)數(shù)初值,開(kāi)始計(jì)數(shù)后每來(lái)一個(gè)時(shí)鐘信號(hào)的下降沿計(jì)數(shù)值減1

?

3個(gè)計(jì)數(shù)器都有相應(yīng)的16位寄存器用于寫入計(jì)數(shù)初值。8根數(shù)據(jù)線D0~D7寫計(jì)數(shù)初值時(shí)分兩次寫,先寫的對(duì)應(yīng)低8位,后寫的對(duì)應(yīng)高8位

要區(qū)分讀或?qū)懙氖悄囊粋€(gè)寄存器還要有地址線A0~A1。系統(tǒng)總線可見(jiàn)或者說(shuō)可以訪問(wèn)的寄存器還有控制字,往控制字寫入不同的內(nèi)容就可以讓每一個(gè)計(jì)數(shù)器工作在不同的模式下。4個(gè)寄存器用2位地址訪問(wèn)。2根地址線4種組合。00,01,10,11分別對(duì)應(yīng)計(jì)數(shù)器0,1,2的1計(jì)數(shù)值寄存器和控制字。地址0,1,2這3個(gè)寄存器可寫可讀,地址3寄存器可寫不可讀

此外8253和系統(tǒng)總線這邊的信號(hào)還有讀寫信號(hào)RD―,WR―,片選信號(hào)CS―

?

計(jì)數(shù)器i有時(shí)鐘信號(hào)輸入引腳CLKi,用于通知計(jì)數(shù)值減到0的輸出引腳OUTi,用于暫停計(jì)數(shù)的門控信號(hào)GATEi。GATEi高電平正常計(jì)數(shù),低電平暫停計(jì)數(shù))

?

?

工作方式

每一個(gè)計(jì)數(shù)器可以工作在6種不同的模式下

?

方式0和方式1產(chǎn)生一個(gè)負(fù)脈沖

方式0:計(jì)數(shù)結(jié)束產(chǎn)生中斷

寫控制字規(guī)定某計(jì)數(shù)器工作在方式0下后OUT引腳馬上就變?yōu)榈碗娖健懭胗?jì)數(shù)初值n后開(kāi)始定時(shí)計(jì)數(shù),計(jì)數(shù)值減到0后OUT引腳變?yōu)楦唠娖健F渌绞街灰獙懣刂谱忠?guī)定工作方式后OUT引腳馬上變?yōu)楦唠娖?/p>

可將其接到8259的一個(gè)中斷請(qǐng)求輸入引腳,定時(shí)向CPU發(fā)出中斷請(qǐng)求

?

方式1:可編程單穩(wěn)

與方式0不同,方式1寫完計(jì)數(shù)初值后要等到GATE信號(hào)來(lái)一個(gè)上升沿后才開(kāi)始計(jì)數(shù)

可將一個(gè)上升沿轉(zhuǎn)換成一個(gè)寬度可編程的負(fù)脈沖

?

?

方式2和方式3產(chǎn)生周期信號(hào),方式2產(chǎn)生周期性負(fù)脈沖。方式3產(chǎn)生方波

方式2:頻率發(fā)生器

方式3:方波發(fā)生器

?

?

方式4和方式5隔一定時(shí)間后產(chǎn)生寬度為一個(gè)時(shí)間周期的負(fù)脈沖

方式4:軟件觸發(fā)旁通

方式5:硬件觸發(fā)旁通

?

?

8253的控制字

開(kāi)始計(jì)數(shù)時(shí),第一個(gè)時(shí)鐘下降沿會(huì)把計(jì)數(shù)值從計(jì)數(shù)值寄存器傳送到減1寄存器,此時(shí)不會(huì)判斷計(jì)數(shù)值是否為0。在下一個(gè)時(shí)鐘周期下降沿才把減1寄存器的內(nèi)容減1,然后判斷是否為0。故計(jì)數(shù)初值如果寫0對(duì)應(yīng)的是最大計(jì)數(shù)值

減1計(jì)數(shù)器的每次改變都會(huì)同步到計(jì)數(shù)鎖存器,正常工作時(shí)這兩個(gè)寄存器的內(nèi)容總是一樣的。計(jì)數(shù)值寄存器和計(jì)數(shù)鎖存器占用同一個(gè)地址,寫這個(gè)地址將計(jì)數(shù)初值寫入計(jì)數(shù)值寄存器,讀這個(gè)地址讀當(dāng)前計(jì)數(shù)鎖存器的內(nèi)容。減1計(jì)數(shù)器則不能讀也不能寫。讀之前要給計(jì)數(shù)器發(fā)鎖存命令 ,一旦發(fā)鎖存命令后減1計(jì)數(shù)器和計(jì)數(shù)鎖存器切斷聯(lián)系,計(jì)數(shù)鎖存器內(nèi)容不再變化

從系統(tǒng)總線的角度來(lái)講,每個(gè)計(jì)數(shù)器好像只有1個(gè)相應(yīng)的16位寄存器,但其實(shí)有3個(gè)

8253的地址3對(duì)應(yīng)控制字,看起來(lái)8253內(nèi)部好像也只有一個(gè)控制字,但實(shí)際上內(nèi)部對(duì)應(yīng)每一個(gè)計(jì)數(shù)器都有其專有的控制字

故每一個(gè)計(jì)數(shù)器內(nèi)部都有4個(gè)寄存器:計(jì)數(shù)值寄存器,減1計(jì)數(shù)器,計(jì)數(shù)鎖存器和控制字

?

8255的尋址及連接

?

8253的初始化及應(yīng)用

然后講了下以前CPU為8088時(shí)計(jì)算機(jī)主板上跟8253有關(guān)的部分電路和電源掉電檢測(cè)的例子

?

可編程定時(shí)/計(jì)數(shù)器8253的串聯(lián)使用

單個(gè)定時(shí)/計(jì)數(shù)器的限制:

?

多個(gè)定時(shí)/計(jì)數(shù)器串聯(lián)使用:

要求輸出為指定寬度的周期性負(fù)脈沖,如何設(shè)計(jì)?

方法1:

方法2:

?

基于總線的I/O接口設(shè)計(jì)

總結(jié)

以上是生活随笔為你收集整理的西电计科院微机原理与系统设计课程笔记(车向泉版)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。