我想把第一個(gè)寫匯編教材的人痛扁一頓先。 在匯編語(yǔ)言中,尋址方式是我們學(xué)習(xí)的重點(diǎn)之一,也是難點(diǎn),讓人很容易犯迷糊。個(gè)人覺(jué)得吧,這個(gè)犯迷糊的原因,不在于你,而在于,教材中有關(guān)尋址方式的一套說(shuō)法,本身就很迷糊。下面,我們就尋址方式這一事,探究一下。 先說(shuō)兩點(diǎn)很基礎(chǔ)的概念:一,“尋址”的方式本身就只有兩大類:一是將一個(gè)具體的地址值給處理器,一個(gè)是在機(jī)器指令碼中已經(jīng)暗含了地址(寄存器);二,尋址,不應(yīng)只如教材中所說(shuō)的只針對(duì)源操作數(shù)(源數(shù)據(jù)),也應(yīng)包括目的操作數(shù)(目的地)。教材中說(shuō)的分類及解釋,反正本人覺(jué)得很那個(gè)。 提示一下,上一個(gè)貼子,是以舉例的形式,建立一些概念性的東西。 言歸正傳,下面我們展開了說(shuō): 一、“尋址”的內(nèi)涵及應(yīng)該做的前期工作 首先,我們弄清楚“尋址”這個(gè)概念的內(nèi)涵,就是說(shuō)要把一個(gè)源數(shù)據(jù)存放在存儲(chǔ)器中的地址,告訴處理器,這個(gè)就是尋址。萬(wàn)變不離其宗,我們只要牢記,所謂“尋址”只是把地址告訴別人,至于將告訴別人地址的方式稱乎成直接尋址、間接尋址、變址尋址之類的還是稱乎成其它什么的,我們可以不管它。 我們?cè)偻耙徊剑阂嬖V別人這個(gè)地址,首先你要知道這個(gè)地址,也就是說(shuō),你要“獲得”這個(gè)地址。 再往前推,我們要把這個(gè)數(shù)據(jù)(源數(shù)據(jù))送出去,說(shuō)明這個(gè)數(shù)據(jù)已經(jīng)存在某個(gè)單元中了,那么,為了“獲得”這個(gè)地址,我們就要弄明白,當(dāng)初這個(gè)數(shù)據(jù)存進(jìn)去的時(shí)候,它的地址是多少?是怎么確定的? 還有一點(diǎn),教材中所謂的尋址的對(duì)象,指的是對(duì)源數(shù)據(jù)(源操作數(shù))的地址的尋找,而不是目的操作數(shù),目的操作數(shù)的地址,都是由程序員在該條程序中直接、精準(zhǔn)地給出了的。 二、源數(shù)據(jù)存入時(shí)的地址選定方式 首先,所有源數(shù)據(jù)的存入,都是由程序員在程序中來(lái)規(guī)劃的,但是,51機(jī)芯片本身在這方面有些原則和規(guī)定,所以,我們至少應(yīng)從這兩方面來(lái)了解說(shuō)明。 另一方面,所有源數(shù)據(jù)存入時(shí)的地址,都是由程序員來(lái)選定的,但寫入時(shí)間分為兩種情況,一種是在程序運(yùn)行前就已寫入,這個(gè)情況指的是程序存儲(chǔ)器中的數(shù)據(jù);另一種情況是在程序運(yùn)行中寫入,這個(gè)指的是數(shù)據(jù)存儲(chǔ)器中的數(shù)據(jù),也就是中間數(shù)據(jù)和結(jié)果數(shù)據(jù)。 (一)程序存儲(chǔ)器中的數(shù)據(jù) 51機(jī)程序存儲(chǔ)器屬兩字節(jié)地址型,即每個(gè)單元的地址為16位二進(jìn)制數(shù)。 1、緊跟在機(jī)器指令碼后面的單元中 也即數(shù)據(jù)存在該機(jī)器指令碼之后的一系列單元中,有多少字節(jié)數(shù)據(jù)就占用多少個(gè)單元。這里面又分為三種:一字節(jié)立即數(shù)據(jù),如MOV Rn,#data,二字節(jié)立即數(shù)據(jù),一組數(shù)據(jù)的表數(shù)據(jù)。 屬于相對(duì)地址,基地址為該條指令的機(jī)器指令碼所在單元的地址。 2、另劃存儲(chǔ)區(qū)的表數(shù)據(jù) 這個(gè)就是在存儲(chǔ)區(qū),由程序員指定一個(gè)獨(dú)立的絕對(duì)起始地址,把一組數(shù)據(jù)順序?qū)戇M(jìn)去。我們常見的ORG偽指令,就是來(lái)指定絕對(duì)起始地址的。 這個(gè)屬于絕對(duì)地址,程序員在ORG中給出了一個(gè)絕對(duì)地址數(shù)值。 (二)數(shù)據(jù)存儲(chǔ)器中的數(shù)據(jù) 51機(jī)數(shù)據(jù)存儲(chǔ)器(內(nèi)部256B)屬單字節(jié)地址型,即每個(gè)單元的地址為8位二進(jìn)制數(shù)。 這個(gè)是在程序執(zhí)行中才會(huì)發(fā)生數(shù)據(jù)的存入,其存儲(chǔ)單元的地址,也是由程序員規(guī)劃的,可以在源程序中直接指出,也可以在運(yùn)行過(guò)程中通過(guò)計(jì)算得出。 源程序中直接指出地址的方式,也有幾種,一種是將其地址值寫在源程序中(燒寫后存在程序存儲(chǔ)器中);另一種,就是51機(jī)的指令規(guī)定了,它在機(jī)器指令碼中直接指向了存儲(chǔ)單元,即前面所說(shuō)的機(jī)器指令碼暗含地址,這個(gè)在51機(jī)的設(shè)計(jì)中,只針對(duì)部分寄存器,想了解哪些寄存器有這種設(shè)計(jì),看機(jī)器指令對(duì)照表就是了。 三、如何獲得源數(shù)據(jù)的地址 要想讓處理器找到地址,程序員必須讓處理先獲得地址。其實(shí),根據(jù)源數(shù)據(jù)存入時(shí)地址的選定方式,我們很容易想到如何獲得其地址。 這個(gè)在后面結(jié)合起來(lái)講。 四、地址值放在哪并如何告訴處理器 處理器根據(jù)地址值才能找到源數(shù)據(jù),但是,這個(gè)地址值,得先放在一個(gè)地方,讓處理器去取,所以,你得將地址值放在一個(gè)地方,并將這個(gè)地方告訴處理器。 (一)程序存儲(chǔ)器中的源數(shù)據(jù)的地址值(十六位地址值) 1、跟在機(jī)器指令碼后面的單個(gè)或兩個(gè)數(shù)據(jù) 這個(gè),機(jī)器指令碼自己就知道地址,也就是說(shuō),其源數(shù)據(jù)單元地址指向已在機(jī)器指令碼中明確,就不勞你另外費(fèi)心了。這個(gè)屬于立即尋址。 如MOV A,#data,這個(gè)是單個(gè)數(shù)據(jù),該指令的機(jī)器指令碼為74H,這個(gè)74H自己就知道要取的數(shù)據(jù)就在自己的屁股后面。 MOV DPTR,#data16,這個(gè)是兩個(gè)數(shù)據(jù)(兩字節(jié))。 2、跟在機(jī)器指令碼后面的表數(shù)據(jù) 這個(gè)地址的獲得,是以該機(jī)器指令碼的PC值作為基地址值,A中的值作為要取的源數(shù)據(jù)的順序值(偏離量),兩者相加,即為絕對(duì)地址值。這個(gè)絕對(duì)地址值放在什么地方我不知道(按51機(jī)設(shè)計(jì)者的尿性,多半在A中),這個(gè)也不重要,因?yàn)樘幚砥鞯玫竭@個(gè)值后直接就去取數(shù)據(jù)了,不需要你再另加指令。 匯編指令:MOVC A,@A+PC,查表指令之一 操作時(shí),源數(shù)據(jù)的順序值,必須先送入A中,這個(gè),就得用到其它指令。下面第3條也是一樣。 3、絕對(duì)地址表數(shù)據(jù) 這個(gè)地址的獲得,是以DPTR(前面ORG中給出的起始絕對(duì)地址值)中的值為基地址值,以A中的值作為要取用的源數(shù)據(jù)的順序值(偏移量),兩者相加,即為絕對(duì)地址。其它情況同上。這個(gè)屬于有的書上所說(shuō)的變址尋址。 匯編指令:MOVC A,@A+DPTR,查表指令之二。 PS1:說(shuō)明一下,51機(jī)的機(jī)器代碼指令集中,針對(duì)程序存儲(chǔ)器只設(shè)計(jì)了這三種地址獲得的方式,而且,對(duì)于程序存儲(chǔ)器中的表數(shù)據(jù),也是只設(shè)計(jì)了傳給A,想傳到其它地方?對(duì)不起,你只能先傳給A后再說(shuō)。為什么這樣設(shè)計(jì)?一個(gè)是因?yàn)?/font>8位機(jī)最多只能有256條機(jī)器指令,不夠用啊;二個(gè)是,你覺(jué)得這樣設(shè)計(jì)合理么?(這部分涉及到51機(jī)數(shù)據(jù)傳輸?shù)脑恚谶@里稍微提一下讓人有個(gè)概念) PS2:查表指令用起來(lái)真的很麻煩,可以考慮將小量的并常用的表數(shù)據(jù),在程序開始時(shí)復(fù)制到數(shù)據(jù)存儲(chǔ)器中,這樣運(yùn)行速度可能要快些。 (二)數(shù)據(jù)存儲(chǔ)器中源數(shù)據(jù)的地址值(八位地址值) 程序存儲(chǔ)器中的原數(shù)據(jù),屬于永久數(shù)據(jù),其地址也是永久的,哪怕是程序重啟后也不會(huì)改變。 但數(shù)據(jù)存儲(chǔ)器中的源數(shù)據(jù)不是這樣的,數(shù)據(jù)存儲(chǔ)器的特點(diǎn)之一就是可以復(fù)用,程序員在編程時(shí),對(duì)同一單元可以不斷更改其用途,也可以在整個(gè)程序運(yùn)行期內(nèi),指定部分單元存入固定用途(固定值)的數(shù)據(jù)。 所以,數(shù)據(jù)存儲(chǔ)器中的源數(shù)據(jù),其實(shí)都是程序運(yùn)行過(guò)程中的中間數(shù)據(jù)或結(jié)果。其地址值,都是由程序員在編程時(shí)確定的,也是或者直接指定,或者通過(guò)計(jì)算得出。 數(shù)據(jù)存儲(chǔ)器中的源數(shù)據(jù)的地址值,在傳輸開始前,放在以下幾種位置: 1、程序存儲(chǔ)器中 這個(gè)屬于直接指定類,也就是程序員在源程序中直接給出源數(shù)據(jù)的單元地址(絕對(duì)地址),其地址值則放在機(jī)器指令碼之后的一個(gè)程序存儲(chǔ)器單元中,如MOV A,direct,機(jī)器代碼為“E5 直接地址”,這個(gè)就是所謂的直接尋址,這種情況是目的地址已在機(jī)器指令碼中指出,如果要分個(gè)類,可以稱為寄存器對(duì)數(shù)據(jù)存儲(chǔ)器的直接尋址。 還有一種,就是MOV direct,direct,這個(gè)也是直接尋址,三字節(jié)指令,源地址與目的地址都是直接給出地址值,其機(jī)器代碼為“85 direct direct”,也可以說(shuō)直接地址到直接地址類的直接尋址。 2、工作寄存器中 源數(shù)據(jù)的地址值存放在工作寄存器中,處理器將工作寄存器中的值當(dāng)作源數(shù)據(jù)的地址值來(lái)取數(shù)據(jù)。如MOV A,@Ri,這個(gè)就屬于間接尋址,這個(gè)例子屬于單字節(jié)指令,源地址和目的地址均在機(jī)器指令碼中指出。需要說(shuō)明一下的是,工作寄存器的地址值不需另外給出,它一定已經(jīng)包括在機(jī)器指令碼中了。 這種方式一般用于需用具體數(shù)值來(lái)表示源數(shù)據(jù)地址值、但是其地址值并未在程序存儲(chǔ)器中給出的情況,對(duì)于計(jì)算出來(lái)的地址值,必須采用這種方式,這個(gè)跟程序存儲(chǔ)器中的查表法有點(diǎn)不一樣,計(jì)算得出的地址值一定要先放入寄存器中,而不是該指令在得出地址值后直接就去取數(shù)據(jù)了。 其實(shí)這種方式跟直接尋址差不多一回事,都是要有具體的地址值才能找到源數(shù)據(jù),區(qū)別在于一個(gè)的地址值在程序存儲(chǔ)器中,另一個(gè)在Ri中。 這里注意一點(diǎn),這個(gè)地址值只能送入R0或R1中,為什么不能送入其它R中?因?yàn)?/font>51機(jī)的設(shè)計(jì)者沒(méi)有這樣設(shè)計(jì)。為什么要這樣設(shè)計(jì)?見前所述。 千萬(wàn)注意:對(duì)于具有256B(不計(jì)入SFR)容量的數(shù)據(jù)存儲(chǔ)器的51機(jī),128B值以上的地址如果采用直接尋址方式,則它會(huì)在SFR中找數(shù)據(jù),如果采用間接尋址方式,則它會(huì)在用戶數(shù)據(jù)區(qū)找數(shù)據(jù)。也就是說(shuō),對(duì)于SFR的地址值,只能在程序存儲(chǔ)器中給出。 PS:個(gè)人覺(jué)得吧,SFR區(qū)也不是完全不能作為用戶數(shù)據(jù)區(qū),比如吧,對(duì)于電路上空置的端口,用了也不會(huì)有什么后果吧?要知道,它們也是可以位尋址的,更是可以直接尋址的。至于這樣做有沒(méi)有意義?這樣說(shuō)吧,至少思路有意義。 3、機(jī)器指令碼直接指定 也就是說(shuō)機(jī)器指令碼它自己就知道源數(shù)據(jù)在哪,也就是書上所說(shuō)的寄存器尋址,如MOV direct,A,這條語(yǔ)句具體應(yīng)用時(shí)的機(jī)器代碼是0F5H direct,兩字節(jié)指令,這里面的0F5H是機(jī)器指令碼,它已經(jīng)明確了源數(shù)據(jù)在A中(這個(gè)是由51機(jī)的設(shè)計(jì)者設(shè)計(jì)成這樣的)。 這種情況,只適用于部分寄存器,這部分包括A、Rn、Ri、DPTR,還有半個(gè)PC,一個(gè)位尋址C,其它的寄存器沒(méi)有設(shè)計(jì)這個(gè)功能(不會(huì)又問(wèn)為什么沒(méi)設(shè)計(jì)吧),包括把其當(dāng)作源地址以及當(dāng)作目的地址。你只要記住只有這幾個(gè)有所謂的寄存器尋址功能,不管是把它們當(dāng)全源地址還是目的地址,你就能很熟練地運(yùn)用了。 PS1:如果數(shù)據(jù)傳送的兩頭都是寄存器,51機(jī)設(shè)計(jì)者還給設(shè)計(jì)了一部分直通車,也就是在機(jī)器指令碼中直接指明了兩頭是誰(shuí),也就是單字節(jié)指令,如MOV A,R0,它直接一條機(jī)器指令碼0E8,就把數(shù)據(jù)從R0傳輸?shù)搅?/font>A。 PS2:從前面的說(shuō)明可以看出,所謂“寄存器尋址”的說(shuō)法,并不恰當(dāng),準(zhǔn)確的說(shuō)法,應(yīng)該是“機(jī)器指令碼定址尋址”,定址包括對(duì)源地址和目的地址(再重復(fù)一遍)。 五、說(shuō)明 以上所說(shuō),均只針對(duì)片內(nèi)的存儲(chǔ)器。 每一條機(jī)器指令碼,對(duì)應(yīng)著一套實(shí)現(xiàn)該指令功能的硬件邏輯電路。 匯編語(yǔ)言并不能說(shuō)難,至少,對(duì)于目前一些教材中所說(shuō)的實(shí)例,編程起來(lái)不會(huì)比C復(fù)雜。 匯編程序員的大量且復(fù)雜的工作,應(yīng)該是對(duì)存儲(chǔ)器的規(guī)劃。小程序還好說(shuō),大程序,真的是要好好規(guī)劃,不然的話,要么存儲(chǔ)器不夠用,要么數(shù)據(jù)發(fā)生沖突而無(wú)法達(dá)到目的。 題外PS:寫得蠻傷神,這些東西跟教材上的思路不一樣,也不知說(shuō)清楚沒(méi),更擔(dān)心有什么說(shuō)錯(cuò)了的害人,盼大蝦指正。
|