摘要:MAXQ內核是功能強大的、單周期、基于傳遞觸發的CPU。本文通過演示如何根據簡單的MOVE操作建立整個指令集來證明MAXQ的強大性能。
MAXQ處理器家族包括功能強大的8位、16位與32位單周期微控制器,能夠在一個時鐘周期內執行多個操作。本文探討了MAXQ20內核的工作機制,并展示了其強勁性能。
注意,對于一個基于MAXQ20內核的處理器來說,這些存儲器空間大部分是空的。另外,由于固定用途ROM與數據RAM位于代碼空間的高32kb內,訪問這一區域的用戶代碼需要用到專門的內核特性,本文不討論這一部分內容。
圖1. MAXQ20內核的程序員模型包括16個通用累加器,兩個循環計數器和一組數據指針。
圖2. 有效累加器通過AP寄存器指定,AP寄存器本身可通過累加器訪問指令來修改。
ticle/UploadPic/2009-4/2009423162616280.gif">
圖3. GR寄存器支持字節提取、字節交換以及16位符號擴展功能。
注意,數據存儲器通過這三個數據指針之一進行尋址,與此不同,代碼存儲器通過指令指針尋址。盡管所有MAXQ處理器都包含存儲器管理單元(MMU),允許將任意存儲器片段作為代碼或者數據來處理,但代碼與數據總線是分離的。采用獨立的總線來提取代碼與數據是MAXQ20內核的基本特點,允許在一個時鐘周期內同時訪問代碼和數據。
傳送-觸發技術能夠以簡單的MOVE指令完成CPU提供的各項功能。盡管MAXQ匯編器支持30條以上的指令操作碼,我們可以采用以下方式對MAXQ指令集包含的每條指令進行編程:
執行一條MAXQ指令時,會將源寄存器的值或一個立即數載入目的寄存器。此外,這個數據傳送操作還會觸發其它事件,如遞增或遞減一個指針、設置某些狀態位或者執行其它功能。因此,這種架構具有傳送-觸發特性。為實現這種架構,需要大量輔助寄存器的支持。在MAXQ20內核中,總計有512個寄存器地址,被劃分為兩大類:外設寄存器空間與系統寄存器空間(圖4)。
前六個寄存器模塊(模塊0到5)專門用作外設寄存器;后九個模塊(模塊7到F)用作系統寄存器(模塊6被保留)。盡管對應不同的MAXQ處理器類型其外設寄存器模塊各不相同,但所有MAXQ處理器的系統寄存器配置是相同的(圖5)。
圖4. MAXQ20內核中的寄存器劃分為兩大部分:寄存器組0到5是外設寄存器,不同的MAXQ器件會有所不同;寄存器組7到15是系統寄存器,在所有MAXQ器件中保持相對固定。
圖5. MAXQ系統寄存器分配表,包括所有MAXQ20處理器共有的寄存器和用來執行指令集的附加寄存器。
圖6. 一條MAXQ指令包含三個部分:一個源標識符、一個目的標識符和一個用來指明源標識符是立即操作數還是寄存器操作數的源格式位。
以指令操作碼0x0923為例,該指令的FORMAT位被清零,表示源標識符(23)應當被視作一個8位立即數來處理。目標模塊是模塊9,對應累加器陣列。該陣列中的寄存器0是累加器A[0]。所以,這條指令的作用是將值0x0023加載到寄存器A[0]。在本例當中,源標識符與目的標識符均不提供附加功能。
第二個例子可考慮操作碼0xBF09。在這條指令中,FORMAT位被置為1,表示源標識符應當被看作是一個寄存器。上文已對模塊9的寄存器0進行了分析:即表示累加器A[0]。在目的字段,模塊F是數據指針模塊,寄存器3 (指令中第12至14位)表示數據指針DP[0]。因此,這條指令將A[0]的內容傳送至DP[0]中。
注意,在某些情況下寄存器模塊中的個別位置并不一定對應實際的寄存器。或者,它們可以對應一個實際寄存器,但訪問這個寄存器時會實現一些附加功能。舉例來說,我們將前一個例子稍作修改,采用操作碼0xAF09。只是目的寄存器模塊中的寄存器子譯碼發生了變化。這條指令現在并不加載寄存器DP[0],而是使DP[0]遞減,并將源數據存儲到DP[0]所指向的新存儲器位置。也就是說,這條指令執行了一個預先遞減指針指向位置的間接存儲操作。在MAXQ匯編器中,這可以按照@ DP[0], A[0]的形式進行編程,但也可以簡單地編程為M15[2], M9[0]。
表1. 模塊8功能
值得特別注意的是AP與APC寄存器。AP寄存器確定哪個累加寄存器是有效的,也就是說,它指定了執行算術、邏輯與位運算的目標寄存器。它可以指向陣列中的任意累加器。
APC寄存器包含了一組位,它們定義了累加器操作完成后AP寄存器是如何改變的。因此,AP寄存器能夠以2的冪為模進行循環遞增或遞減,從而簡化了多倍精度運算。
表2. 模塊10作為源寄存器
如果源寄存器處于模塊10,而目的寄存器處于模塊10以外的任意模塊,則累加器的內容被傳送到目的寄存器。如果模塊10的子譯碼值為0,則根據APC寄存器的位對AP寄存器進行修改;如果子譯碼值為1,則AP寄存器值不變。
注意,當前版本的宏匯編器并不支持子譯碼1。這是因為沒有助記符或者修飾符表示子譯碼1。所以,指令move A[1], ACC生成的操作代碼永遠是0x990A,而絕不會是0x991A (表3)。
表3. 模塊10作為目的寄存器
當模塊10被指定為目的標識符,并且源標識符是一個立即數或者處于模塊10以外的任意模塊時,源信息會傳送到ALU;目的信息通過ALU的輸出來獲取,而不是直接來自源信息。算術與邏輯指令就是通過這種方式完成操作的。
注意,對于源寄存器的表示方式并沒有限制。它可以是一個立即數,一個間接存儲器位置,甚至可以是堆棧中的數值或一個外設寄存器(表4)。
表4. 模塊10既作為源寄存器、又作為目的寄存器
當源與目的標識符均為模塊10時,它或者是一個純累加器指令,或者是一個包含進位的位操作。在任何情況下,都使用源與目的寄存器來指示特定操作。
目的子譯碼0指定了所有的純累加器指令,包括取補碼、取反碼以及所有移位、循環與交換指令。目的子譯碼1、2、3、6與7涵蓋了按位加載與帶進位操作。最終,目的子譯碼5實現純進位操作:載入0和1與取補碼。
注意,目的子譯碼5的一個源子譯碼為指定的NOP指令。在任何情況下,對于既無附加功能又訪問空寄存器的操作都會視為NOP操作;MOVE M10[5], M10[3]命令特定用來保證在當前或將來的MAXQ器件中不執行操作。這條指令(0xDA3A)是所有當前匯編程序中的運行代碼,用于NOP助記符。
模塊12—指令指針
模塊12的獨特之處在于它包含了一些條件加載操作。如果模塊12被用作源模塊,只是簡單地將IP復制到目的標識符。但如果模塊12是目的模塊,則除非滿足指定的條件,否則不會執行任何操作(表5)。
表5. 模塊12子譯碼
模塊12還有一個獨特之處,也就是當加載8位立即數源時,源數值被解釋為一個有符號整型數,并加到指令指針中預先遞增的數據上。這個加法操作使得相對短跳轉更為簡單,進而大大節省了代碼尺寸。這也同樣意味著任意短或長跳轉指令都可以是有條件的。
這個模塊僅僅支持指令指針寄存器(IP)的簡單加載與存儲。CALL指令被當作一個可同樣加載IP的堆棧指令,而不是作為一個執行壓棧的IP指令。因此,CALL指令的傳送在堆棧指針模塊(模塊13)中實現。同樣,不存在直接RET指令,它由POP IP所代替。
表6. 模塊13子譯碼
子譯碼3、4和5用作IP寄存器的代理。將遞增后的指令指針壓棧之后,子譯碼3加載指令指針,從而實現一個傳統的CALL指令。子譯碼4和5將指定的循環計數器遞減后重新加載到循環計數器,并且如果預先遞減的循環計數器不為零,則將源操作數也加載到指令指針中。載入目的子譯碼的源可以是任意形式,例如,指令DJNZ LC[0], A[1]完全有效,該指令會遞減LC[0],當遞減結果不為零時跳轉至A[1]存儲的地址位置。
表7. 模塊14子譯碼
數據指針控制寄存器(DPC)說明了數據指針是如何發揮作用的。特別地,它為每一個數據指針提供了一個位,用來定義該指針是工作于字模式還是字節模式。它同樣包含了一個字段,用于定義哪個指針是當前的源指針。這一點非常必要,因為當源指針被加載后,訪問源時只有一條用于操作數的數據總線。
當需要按字節來訪問16位數據時,使用GR寄存器就會很方便。只要GR裝入了16位數據,就可以分別通過GRL和GRH寄存器提取低字節與高字節。GRS寄存器中包含GR數據字節交換后的結果;GRXL寄存器與GRL寄存器相同,區別僅在于它的高字節是低字節的符號擴展。
基址指針寄存器(BP)是MAXQ架構中三個數據存儲器指針寄存器之一,并且只有它支持偏移量寄存器。BP通常指向數據結構的基址,8位無符號偏移寄存器指向該結構的某一個數據單元。注意,該寄存器的遞增或遞減操作僅僅會修改偏移寄存器,絕不會修改基址寄存器的內容。
表8. 模塊15子譯碼
圖7. 模塊7的子譯碼指定了要提取或者替換的位,如果作為源標識符,則表示要加載的立即數位值。
作為目的標識符,BVM代理進位功能。源的一位數據被提取并復制到進位中。如果BVM是源標識符,子譯碼第3位(整個源標識符的第7位)的值將被復制到目的寄存器的指定位中。
需注意,BVM僅僅作用于外設寄存器的第0位至第7位。由于大多數外設寄存器(尤其是I/O端口)僅為8位長度,所以這種工作模式是可以接受的。但如果訪問16位外設寄存器,只有低8位是可用的。
有幾種解決方案來處理這種局限性,比如采用可變長度的指令和寄存器,并允許獨立訪問低字節和高字節(MAXQ中的GR寄存器就是這樣一個例子)。但這些方案都不盡完美,因為它們使得譯碼邏輯變得非常復雜,或者需要引入新的寄存器(圖8)。
圖8. 當前綴寄存器作為目的寄存器時,8位立即數源提供16位立即操作數的高字節;目的子譯碼則為源操作數和目的操作數提供附加位,以尋址每個模塊當中的所有32個寄存器。
前綴機制從兩方面改善了這一操作過程。首先,這種機制僅向那些需要附加位的特定指令添加前綴,從而節省了代碼空間與執行時間。其次,由于既可為立即數又可為寄存器標識符提供附加位,該機制在擴展寄存器空間的同時又保持了整體架構的性能。
前面提到,盡管每一個寄存器模塊都包含32個寄存器,但源寄存器只有4位標識符,目標寄存器只有3位標識符。前綴機制則可提供這些附加位。
前綴機制的鮮明特色表現為幾個方面。首先,前綴指令中目的部分的特定位被用作立即數源位,用來訪問子譯碼大于15的源地址寄存器,以及子譯碼大于7的目的地址寄存器。通過這種方式,單條前綴指令既能夠訪問任何寄存器或立即數,也能夠訪問任何寄存器子譯碼。
其次,前綴寄存器還有另一個獨特之處,即它載入的任意值僅能夠保持一個時鐘周期。在此之后,該寄存器會自動清零。也就是說,必須在緊靠被前綴寄存器修改的指令之前,向前綴寄存器傳送所需數據。這同樣意味著前綴指令是不可中斷的。如果緊隨一個前綴操作之后發生了一次中斷,則當中斷返回主函數時前綴信息會丟失。
如圖9所示,前綴寄存器中的位分別送至源標識符、目的標識符和立即數中。所以,盡管絕大多數指令可以在單周期內執行,以下指令仍然需要兩個周期:尋址子譯碼大于7的目標寄存器;尋址子譯碼大于15的源寄存器;或者加載大于255的立即數。
圖9. 前綴寄存器可提供附加位,以實現16位立即操作數,以及尋址每個模塊中所有32個源和目的寄存器。
為了說明這個過程,我們考慮指令move A[0], #010h。這條指令將一個立即數傳送到模塊9的寄存器0中,因此匯編器會生成如下的操作碼:0910。但如果指令是A[10], #0320h的話,匯編器會自動地插入一條前綴指令:2B03 2920。
如果沒有前綴指令,操作碼2920會被解釋為A[2], #020h。而前綴將一位添加到目的標識符,并將一些位添加到立即數中,從而允許處理器向任意寄存器子譯碼加載任意值,并且永遠不會超過兩個執行周期。
向量表中的最后一個入口地址用來重新初始化指針,并且任務調度器開始重新掃描向量表。
對于這個例子,假設該列表包含由標記、長度和數據串組成的數據對象。遍歷該列表的程序如下:
MAXQ處理器家族包括功能強大的8位、16位與32位單周期微控制器,能夠在一個時鐘周期內執行多個操作。本文探討了MAXQ20內核的工作機制,并展示了其強勁性能。
程序模型
MAXQ20內核是一個16位CPU,這意味著所有的累加器以及大多數工作寄存器(堆棧、數據指針和計數器)均為16位長度。MAXQ20能夠尋址64k字的代碼空間(也就是64kB指令)與64k字(128kB)的數據空間(圖1)。注意,對于一個基于MAXQ20內核的處理器來說,這些存儲器空間大部分是空的。另外,由于固定用途ROM與數據RAM位于代碼空間的高32kb內,訪問這一區域的用戶代碼需要用到專門的內核特性,本文不討論這一部分內容。
圖1. MAXQ20內核的程序員模型包括16個通用累加器,兩個循環計數器和一組數據指針。
累加器
十六個作為“累加器”的寄存器組成了一個通用寄存器陣列。累加器指針寄存器(AP)所指向的寄存器被指定為“有效累加器”,成為算術與邏輯運算的目標寄存器。因此,通過改變AP寄存器的值,這十六個寄存器當中的任意一個均可被指定為算術邏輯單元(ALU)的操作目標。無論何時訪問有效累加器,均可通過累加器指針控制寄存器(APC)實現累加器指針AP的自動增減,從而簡化多倍精度運算過程。在圖2中,A[0]是有效累加器,但是任何累加器訪問操作都可以使A[1]或者A[15]變為有效累加器,具體取決于APC寄存器的值。圖2. 有效累加器通過AP寄存器指定,AP寄存器本身可通過累加器訪問指令來修改。
GR寄存器
通用寄存器(GR)有助于從16位字中提取單獨字節。程序員可以使用GR將字節組裝為一個字:低字節加載到GRL (通用寄存器-低字節)內,高字節加載到GRH (通用寄存器-高字節)內,然后可從GR中讀取組裝完畢的字。反過來,程序員也可以使用GR將一個字分解為兩個字節。加載到GR的字可以在GRS (通用寄存器-字節交換)中以字節交換的形式讀出。最后,通過讀取GRXL (通用寄存器擴展低字節),可以將加載到GRL寄存器的字節擴展為有符號的字。參見圖3。ticle/UploadPic/2009-4/2009423162616280.gif">
圖3. GR寄存器支持字節提取、字節交換以及16位符號擴展功能。
循環計數器
提供兩個循環計數器:循環計數器0 (LC[0])與循環計數器1 (LC[1])。這些寄存器可以作為通用寄存器來使用,但主要用作循環計數器,從而在計數器值不為零時執行遞減和跳轉(DJNZ)操作。堆棧
MAXQ20內核具有一個專用的16級內部堆棧。一個堆棧指針指示下次使用的堆棧位置或者指示PUSH或CALL操作。數據存儲器指針
MAXQ微控制器有三個訪問數據存儲器的指針。DP[0]和DP[1]是兩個簡單的16位指針。通過一個基址指針(BP)與一個8位無符號偏移量(OFFS)相加獲得第三個指針。注意,數據存儲器通過這三個數據指針之一進行尋址,與此不同,代碼存儲器通過指令指針尋址。盡管所有MAXQ處理器都包含存儲器管理單元(MMU),允許將任意存儲器片段作為代碼或者數據來處理,但代碼與數據總線是分離的。采用獨立的總線來提取代碼與數據是MAXQ20內核的基本特點,允許在一個時鐘周期內同時訪問代碼和數據。
傳送-觸發架構
觀察程序員模型,有些人會認為該架構采用傳統的指令獲取-譯碼單元實現裝載指令、指令譯碼,隨后激活CPU的特定單元。然而,這卻是一個誤區。MAXQ架構與其它較為傳統的CPU相比,根本區別在于MAXQ內核的傳送-觸發特性。傳送-觸發技術能夠以簡單的MOVE指令完成CPU提供的各項功能。盡管MAXQ匯編器支持30條以上的指令操作碼,我們可以采用以下方式對MAXQ指令集包含的每條指令進行編程:
move Ma[b], Mc[d] or move Ma[b], #immediate_value其中,標識符Ma[b]指示寄存器模塊a與寄存器子譯碼b。簡而言之:包括ADD、位操作和尋址外部存儲器在內的每一條指令,都可編程為兩個寄存器之間的傳送操作,或將立即數傳送至寄存器的形式。
執行一條MAXQ指令時,會將源寄存器的值或一個立即數載入目的寄存器。此外,這個數據傳送操作還會觸發其它事件,如遞增或遞減一個指針、設置某些狀態位或者執行其它功能。因此,這種架構具有傳送-觸發特性。為實現這種架構,需要大量輔助寄存器的支持。在MAXQ20內核中,總計有512個寄存器地址,被劃分為兩大類:外設寄存器空間與系統寄存器空間(圖4)。
前六個寄存器模塊(模塊0到5)專門用作外設寄存器;后九個模塊(模塊7到F)用作系統寄存器(模塊6被保留)。盡管對應不同的MAXQ處理器類型其外設寄存器模塊各不相同,但所有MAXQ處理器的系統寄存器配置是相同的(圖5)。
圖4. MAXQ20內核中的寄存器劃分為兩大部分:寄存器組0到5是外設寄存器,不同的MAXQ器件會有所不同;寄存器組7到15是系統寄存器,在所有MAXQ器件中保持相對固定。
圖5. MAXQ系統寄存器分配表,包括所有MAXQ20處理器共有的寄存器和用來執行指令集的附加寄存器。
MAXQ指令譯碼
因為每條MAXQ指令實際上都是一個傳送操作,每條指令都可劃分為三個字段:源(SOURCE)指定數據從何處移出;目標(DESTINATION)指定數據傳送到何處;格式位則指明源是一個立即數(FORMAT == 0),還是一個寄存器標示符(FORMAT == 1) (圖6)。圖6. 一條MAXQ指令包含三個部分:一個源標識符、一個目的標識符和一個用來指明源標識符是立即操作數還是寄存器操作數的源格式位。
以指令操作碼0x0923為例,該指令的FORMAT位被清零,表示源標識符(23)應當被視作一個8位立即數來處理。目標模塊是模塊9,對應累加器陣列。該陣列中的寄存器0是累加器A[0]。所以,這條指令的作用是將值0x0023加載到寄存器A[0]。在本例當中,源標識符與目的標識符均不提供附加功能。
第二個例子可考慮操作碼0xBF09。在這條指令中,FORMAT位被置為1,表示源標識符應當被看作是一個寄存器。上文已對模塊9的寄存器0進行了分析:即表示累加器A[0]。在目的字段,模塊F是數據指針模塊,寄存器3 (指令中第12至14位)表示數據指針DP[0]。因此,這條指令將A[0]的內容傳送至DP[0]中。
注意,在某些情況下寄存器模塊中的個別位置并不一定對應實際的寄存器。或者,它們可以對應一個實際寄存器,但訪問這個寄存器時會實現一些附加功能。舉例來說,我們將前一個例子稍作修改,采用操作碼0xAF09。只是目的寄存器模塊中的寄存器子譯碼發生了變化。這條指令現在并不加載寄存器DP[0],而是使DP[0]遞減,并將源數據存儲到DP[0]所指向的新存儲器位置。也就是說,這條指令執行了一個預先遞減指針指向位置的間接存儲操作。在MAXQ匯編器中,這可以按照@ DP[0], A[0]的形式進行編程,但也可以簡單地編程為M15[2], M9[0]。
前綴寄存器
每個模塊包含32個寄存器,但只有四位用于選擇源寄存器,三位用于指定目的寄存器。乍一看,這似乎意味著無法讀取一半的源寄存器子譯碼,并且不能對四分之三的目的寄存器子譯碼進行寫操作。幸好MAXQ的架構設計解決了這個問題。每一款MAXQ處理器都提供一個前綴寄存器,用來提供這些額外的寄存器地址位,并提供按字傳送操作中的高字節數據。詳細信息請參閱模塊11—前綴一節。一次一個模塊地創建MAXQ指令集
以下各節詳細闡述了系統寄存器模塊,以及它們如何相互作用以創建所有列出和未列出的指令。我們首先來研究MAXQ20內核的核心:累加器陣列。模塊9—累加器
盡管大多數衍生器件只提供16個累加器,MAXQ架構可支持最多32個累加器。通過模塊9直接訪問這些累加器。該模塊內每個寄存器代表一個累加器。從概念上講,模塊9是最簡單的模塊,但是還有兩個模塊會影響累加器陣列。模塊8—系統控制
這個模塊包含一些管理系統操作的寄存器,比如中斷控制和程序狀態標志位。其中的許多寄存器超出了本文的討論范圍,若需了解更多信息請參考器件規格資料。表1列出了一部分寄存器模塊。表1. 模塊8功能
Sub | Function | S/D | Description |
0 | Accumulator Pointer Register | S/D | Designates the active accumulator, i.e., the accumulator that serves as the destination of ALU operations. |
1 | Accumulator Pointer Control Register | S/D | Tells the AP how to behave. For this discussion, it is a general-purpose 8-bit register. |
4 | Program Status Flags Register | S/D | Contains the flags (carry, zero, equal) that a user may wish to monitor in the main program. The register is usually used as a source, but can also serve as a destination. Note that some of the bits are read-only (e.g., the Z flag is the logical NOR of all the bits in the active accumulator). |
5 | Interrupt Control Register | S/D | Manages the interrupt subsystem. |
6 | Interrupt Mask Register | S/D | Typically contains bits that mask interrupts at the module level. |
7 | Comparator Register | DO | Write-only subdecode. Not really a register, since there is no actual memory behind it. When this subdecode is written, the Equal bit is set in the PSF if the source operand matches the contents of the current accumulator; otherwise, the Equal bit is cleared. |
8 | System Control Register | S/D | Contains bits that control aspects of system operation (read/write). |
11 | Interrupt Identification Register | SO | Contains a collection of bits that identify the source of an interrupt. |
14 | Clock Control Register | S/D | Contains bits pertaining to the system clock. In particular, controls the master clock divide ratio, as well as clock source if more than one source is present in the particular microcontroller. |
15 | Watchdog Control Register | S/D | Controls the operation of the watchdog timer. Most MAXQ parts contain a watchdog timer that can reset the processor if it becomes stuck in a program loop. |
值得特別注意的是AP與APC寄存器。AP寄存器確定哪個累加寄存器是有效的,也就是說,它指定了執行算術、邏輯與位運算的目標寄存器。它可以指向陣列中的任意累加器。
APC寄存器包含了一組位,它們定義了累加器操作完成后AP寄存器是如何改變的。因此,AP寄存器能夠以2的冪為模進行循環遞增或遞減,從而簡化了多倍精度運算。
模塊10—累加器功能
累加器的大部分實際工作是在模塊10中完成的。它能夠訪問傳統ALU功能以及有效累加器的數據位。模塊10非常獨特,它在作為源寄存器、目的寄存器或者既作為源寄存器又作為目的寄存器的情況下有著不同的行為(表2)。表2. 模塊10作為源寄存器
Sub | Function | Description |
0 | Active Accumulator | The contents of the active accumulator are moved to the destination and the AP is changed according to the APC. |
1 | Active Accumulator | The contents of the active accumulator are moved to the destination and the AP is unchanged. |
如果源寄存器處于模塊10,而目的寄存器處于模塊10以外的任意模塊,則累加器的內容被傳送到目的寄存器。如果模塊10的子譯碼值為0,則根據APC寄存器的位對AP寄存器進行修改;如果子譯碼值為1,則AP寄存器值不變。
注意,當前版本的宏匯編器并不支持子譯碼1。這是因為沒有助記符或者修飾符表示子譯碼1。所以,指令move A[1], ACC生成的操作代碼永遠是0x990A,而絕不會是0x991A (表3)。
表3. 模塊10作為目的寄存器
Sub | Function | Description |
0 | MOVE | The source is moved to the accumulator. |
1 | AND | The contents of the source are logically ANDed with the accumulator. |
2 | OR | The contents of the source are logically ORed with the accumulator. |
3 | XOR | The contents of the source are logically exclusive-ORed with the accumulator. |
4 | ADD | The contents of the source are arithmetically added to the accumulator. Overflow out of the MSB sets the carry bit. |
5 | SUB | The contents of the source are arithmetically subtracted from the accumulator. Underflow sets the carry bit. |
6 | ADDC | The contents of the source and the carry bit are added to the accumulator. |
7 | SUBB | The contents of the source and the carry bit are subtracted from the accumulator. |
當模塊10被指定為目的標識符,并且源標識符是一個立即數或者處于模塊10以外的任意模塊時,源信息會傳送到ALU;目的信息通過ALU的輸出來獲取,而不是直接來自源信息。算術與邏輯指令就是通過這種方式完成操作的。
注意,對于源寄存器的表示方式并沒有限制。它可以是一個立即數,一個間接存儲器位置,甚至可以是堆棧中的數值或一個外設寄存器(表4)。
表4. 模塊10既作為源寄存器、又作為目的寄存器
Dest Sub | SRC Sub | Function | Description |
0 | 0 | MOVE | The contents of the accumulator are moved to the accumulator; logically, an NOP. However, the AP register can be changed. |
1 | CPL | The accumulator is complemented bitwise. | |
2 | SLA | The accumulator is shifted left one bit; low-order bit is set to zero. High-order bit is copied to carry. | |
3 | SLA2 | The accumulator is shifted left two bits; low-order two bits are set to zero. Bit 14 is copied to carry. | |
4 | RL | Accumulator is rotated left by one bit, with bit 15 copied to bit 0. Bit 15 is also copied to carry. | |
5 | RLC | Accumulator is rotated left by one bit, with bit 15 copied to carry and carry copied to bit 0. | |
6 | SLA4 | Accumulator is shifted left four bits; low-order four bits are set to zero. Bit 12 is copied to carry. | |
7 | XCHN | The nibbles in each byte of the accumulator are reversed; 0x1234 becomes 0x2143. | |
8 | XCH | The bytes of the accumulator are reversed; 0x1234 becomes 0x3412. | |
9 | NEG | The accumulator is arithmetically negated. | |
10 | SR | The accumulator is shifted right one bit. Bit 15 is loaded with zero. Bit 0 is moved to carry. | |
11 | SRA4 | Accumulator is shifted right four bits; high-order four bits are set to zero. Bit 3 is copied to carry. | |
12 | RR | Accumulator is rotated right by one bit, with bit 0 copied to bit 15. Bit 0 is also copied to carry. | |
13 | RRC | Accumulator is rotated right by one bit, with bit 0 copied to carry and carry copied to bit 15. | |
14 | SRA2 | The accumulator is shifted right two bits; high-order two bits are set to zero. Bit 1 copied to carry. | |
15 | SRA | The accumulator is shifted right one bit; high-order bit is set to zero. Low-order bit copied to carry. | |
1 | Bit | AND C | The carry bit is logically ANDed with the designated bit in the accumulator. |
2 | Bit | OR C | The carry bit is logically ORed with the designated bit in the accumulator. |
3 | Bit | XOR C | The carry bit is logically XORed with the designated bit in the accumulator. |
5 | 0 | C ← 0 | The carry bit is set to zero. |
1 | C ← 1 | The carry bit is set to one. | |
2 | C ← C | The carry bit is complemented. | |
3 | NOP | Guaranteed NOP | |
6 | Bit | C ← ACC | The designated bit in the accumulator is loaded into carry. |
7 | Bit | ACC ← C | Carry is loaded into the designated bit in the accumulator. |
當源與目的標識符均為模塊10時,它或者是一個純累加器指令,或者是一個包含進位的位操作。在任何情況下,都使用源與目的寄存器來指示特定操作。
目的子譯碼0指定了所有的純累加器指令,包括取補碼、取反碼以及所有移位、循環與交換指令。目的子譯碼1、2、3、6與7涵蓋了按位加載與帶進位操作。最終,目的子譯碼5實現純進位操作:載入0和1與取補碼。
注意,目的子譯碼5的一個源子譯碼為指定的NOP指令。在任何情況下,對于既無附加功能又訪問空寄存器的操作都會視為NOP操作;MOVE M10[5], M10[3]命令特定用來保證在當前或將來的MAXQ器件中不執行操作。這條指令(0xDA3A)是所有當前匯編程序中的運行代碼,用于NOP助記符。
模塊12—指令指針
模塊12的獨特之處在于它包含了一些條件加載操作。如果模塊12被用作源模塊,只是簡單地將IP復制到目的標識符。但如果模塊12是目的模塊,則除非滿足指定的條件,否則不會執行任何操作(表5)。
表5. 模塊12子譯碼
Sub | Description |
0 | If source, load the destination from IP. If destination, load IP from the source. |
1 | If source, load the destination from IP. If destination, load IP from source only if ACC == 0. |
2 | If source, load the destination from IP. If destination, load IP from source only if C == 1. |
3 | If source, load the destination from IP. If destination, load IP from source only if the most recent CMP instruction set the EQ flag. |
4 | If source, load the destination from IP. If destination, load IP from source only if the high-order bit of the accumulator is set. |
5 | If source, load the destination from IP. If destination, load IP from source only if ACC == 0. |
6 | If source, load the destination from IP. If destination, load IP from source only if C == 0. |
7 | If source, load the destination from IP. If destination, load IP from source only if the most recent CMP instruction cleared the EQ flag. |
模塊12還有一個獨特之處,也就是當加載8位立即數源時,源數值被解釋為一個有符號整型數,并加到指令指針中預先遞增的數據上。這個加法操作使得相對短跳轉更為簡單,進而大大節省了代碼尺寸。這也同樣意味著任意短或長跳轉指令都可以是有條件的。
這個模塊僅僅支持指令指針寄存器(IP)的簡單加載與存儲。CALL指令被當作一個可同樣加載IP的堆棧指令,而不是作為一個執行壓棧的IP指令。因此,CALL指令的傳送在堆棧指針模塊(模塊13)中實現。同樣,不存在直接RET指令,它由POP IP所代替。
模塊13—堆棧指針
模塊13不僅包含與堆棧指針相關的寄存器,還包含循環計數器與中斷向量。注意,部分子譯碼僅僅作為目的時有效。子譯碼8只在作為源時才有效(表6)。表6. 模塊13子譯碼
Sub | Function | S/D | Description |
0 | PUSH/POP | S/D | If the destination, increment the stack pointer and store the source operand on the stack. If the source, load the value on the stack to the destination and decrement the stack pointer. |
1 | Stack Pointer | S/D | Points to the most recently used location on the internal dedicated stack. |
2 | Interrupt Vector | S/D | Points to the location in program memory where the interrupt service routine resides. |
3 | CALL | DO | Pushes the current IP to the stack, then loads IP from the source operand. Will cause unpredictable results if used as a source operand. |
4 | DJNZ LC[0] | DO | Decrements LC[0] and loads IP with the source IF LC[0] != 0. Will cause unpredictable results if used as a source operand. |
5 | DJNZ LC[1] | DO | Decrements LC[1] and loads IP with the source IF LC[1] != 0. Will cause unpredictable results if used as a source operand. |
6 | LC[0] | S/D | Data is moved to/from loop counter 0. |
7 | LC[1] | S/D | Data is moved to/from loop counter 1. |
8 | POPI | SO | The value on the stack is copied to the destination, the stack point is decremented, and the IN SERVICE bit is cleared. Primarily used to implement a RETI operation. |
子譯碼3、4和5用作IP寄存器的代理。將遞增后的指令指針壓棧之后,子譯碼3加載指令指針,從而實現一個傳統的CALL指令。子譯碼4和5將指定的循環計數器遞減后重新加載到循環計數器,并且如果預先遞減的循環計數器不為零,則將源操作數也加載到指令指針中。載入目的子譯碼的源可以是任意形式,例如,指令DJNZ LC[0], A[1]完全有效,該指令會遞減LC[0],當遞減結果不為零時跳轉至A[1]存儲的地址位置。
模塊14—GR、BP和DPC
模塊14包含DPC寄存器、GR寄存器和全部與基址指針和偏移寄存器相關的寄存器(表7)。表7. 模塊14子譯碼
Sub | Function | S/D | Description |
0 | @BP[offs] | S/D | Reads or writes the data memory location pointed to by BP+offs |
1 | @BP[offs++] | S/D | If source, reads the data memory location pointed to by BP+offs and then increments offs. If destination, increments offs and then stores the source data at BP+offs. |
2 | @BP[offs--] | S/D | If source, reads the data memory location pointed to by BP+offs and then decrements offs. If destination, decrements offs and then stores the source data at BP+offs. |
3 | offs | S/D | The 8-bit offset register |
4 | DPC | S/D | The data pointer control register defines which data pointer is the current source pointer and the word/byte status of each data pointer. |
5 | GR | S/D | The 16-bit general register |
6 | GRL | S/D | The low-order byte of the 16-bit general register |
7 | BP | S/D | The 16-bit base memory pointer |
8 | GRS | SO | The byte-swapped version of the GR |
9 | GRH | S/D | The high-order byte of the 16-bit general register |
10 | GRXL | SO | The sign-extended low byte of the GR |
11 | BP[offs] | SO | The sum of the base pointer and the offset |
數據指針控制寄存器(DPC)說明了數據指針是如何發揮作用的。特別地,它為每一個數據指針提供了一個位,用來定義該指針是工作于字模式還是字節模式。它同樣包含了一個字段,用于定義哪個指針是當前的源指針。這一點非常必要,因為當源指針被加載后,訪問源時只有一條用于操作數的數據總線。
當需要按字節來訪問16位數據時,使用GR寄存器就會很方便。只要GR裝入了16位數據,就可以分別通過GRL和GRH寄存器提取低字節與高字節。GRS寄存器中包含GR數據字節交換后的結果;GRXL寄存器與GRL寄存器相同,區別僅在于它的高字節是低字節的符號擴展。
基址指針寄存器(BP)是MAXQ架構中三個數據存儲器指針寄存器之一,并且只有它支持偏移量寄存器。BP通常指向數據結構的基址,8位無符號偏移寄存器指向該結構的某一個數據單元。注意,該寄存器的遞增或遞減操作僅僅會修改偏移寄存器,絕不會修改基址寄存器的內容。
模塊15—數據指針
模塊15包含了MAXQ架構中三個數據指針中的兩個。根據子譯碼的不同,訪問這個模塊將執行一個直接或間接加載,或者存儲操作,并可能在間接訪問后遞增或遞減數據指針。這些寄存器子譯碼既可以用作源寄存器又可以用作目的寄存器(表8)。表8. 模塊15子譯碼
Sub | Function | Description |
0 | @DP[0] | Reads or writes the data memory location pointed to by DP[0]. |
1 | @DP[0]++ | If source, reads the data memory location pointed to by DP[0] and then increments DP[0]. If destination, increments DP[0] and then stores the source data at DP[0]. |
2 | @DP[0]-- | If source, reads the data memory location pointed to by DP[0] and then decrements DP[0]. If destination, decrements DP[0] and then stores the source data at DP[0]. |
3 | DP[0] | Data pointer 0 |
4 | @DP[1] | Reads or writes the data memory location pointed to by DP[1] |
5 | @DP[1]++ | If source, reads the data memory location pointed to by DP[1] and then increments DP[1]. If destination, increments DP[1] and then stores the source data at DP[1]. |
6 | @DP[1]-- | If source, reads the data memory location pointed to by DP[1] and then decrements DP[1]. If destination, decrements DP[1]. and then stores the source data at DP[1]. |
7 | DP[1] | Data pointer 1 |
模塊7—布爾變量操作
借助布爾變量操作(BVM)模塊(模塊7),允許對典型MAXQ處理器中的許多寄存器進行按位提取和置位/清零(圖7)操作。需要注意,并不是所有模塊均與BVM模塊連接。通常情況下,只有外設模塊會與BVM相連;系統寄存器則不會。因此,在BVM與系統寄存器之間傳送數據可能產生不可預料的結果。圖7. 模塊7的子譯碼指定了要提取或者替換的位,如果作為源標識符,則表示要加載的立即數位值。
作為目的標識符,BVM代理進位功能。源的一位數據被提取并復制到進位中。如果BVM是源標識符,子譯碼第3位(整個源標識符的第7位)的值將被復制到目的寄存器的指定位中。
需注意,BVM僅僅作用于外設寄存器的第0位至第7位。由于大多數外設寄存器(尤其是I/O端口)僅為8位長度,所以這種工作模式是可以接受的。但如果訪問16位外設寄存器,只有低8位是可用的。
模塊11—前綴
前綴模塊是MAXQ架構獨有的特性,它解決了所有16位微控制器共同面臨的局限性。由于采用16位寄存器,立即數載入指令需要一個16位的操作數,這意味著一個有效的立即數載入指令需要多于16位的代碼。有幾種解決方案來處理這種局限性,比如采用可變長度的指令和寄存器,并允許獨立訪問低字節和高字節(MAXQ中的GR寄存器就是這樣一個例子)。但這些方案都不盡完美,因為它們使得譯碼邏輯變得非常復雜,或者需要引入新的寄存器(圖8)。
圖8. 當前綴寄存器作為目的寄存器時,8位立即數源提供16位立即操作數的高字節;目的子譯碼則為源操作數和目的操作數提供附加位,以尋址每個模塊當中的所有32個寄存器。
前綴機制從兩方面改善了這一操作過程。首先,這種機制僅向那些需要附加位的特定指令添加前綴,從而節省了代碼空間與執行時間。其次,由于既可為立即數又可為寄存器標識符提供附加位,該機制在擴展寄存器空間的同時又保持了整體架構的性能。
前面提到,盡管每一個寄存器模塊都包含32個寄存器,但源寄存器只有4位標識符,目標寄存器只有3位標識符。前綴機制則可提供這些附加位。
前綴機制的鮮明特色表現為幾個方面。首先,前綴指令中目的部分的特定位被用作立即數源位,用來訪問子譯碼大于15的源地址寄存器,以及子譯碼大于7的目的地址寄存器。通過這種方式,單條前綴指令既能夠訪問任何寄存器或立即數,也能夠訪問任何寄存器子譯碼。
其次,前綴寄存器還有另一個獨特之處,即它載入的任意值僅能夠保持一個時鐘周期。在此之后,該寄存器會自動清零。也就是說,必須在緊靠被前綴寄存器修改的指令之前,向前綴寄存器傳送所需數據。這同樣意味著前綴指令是不可中斷的。如果緊隨一個前綴操作之后發生了一次中斷,則當中斷返回主函數時前綴信息會丟失。
如圖9所示,前綴寄存器中的位分別送至源標識符、目的標識符和立即數中。所以,盡管絕大多數指令可以在單周期內執行,以下指令仍然需要兩個周期:尋址子譯碼大于7的目標寄存器;尋址子譯碼大于15的源寄存器;或者加載大于255的立即數。
圖9. 前綴寄存器可提供附加位,以實現16位立即操作數,以及尋址每個模塊中所有32個源和目的寄存器。
為了說明這個過程,我們考慮指令move A[0], #010h。這條指令將一個立即數傳送到模塊9的寄存器0中,因此匯編器會生成如下的操作碼:0910。但如果指令是A[10], #0320h的話,匯編器會自動地插入一條前綴指令:2B03 2920。
如果沒有前綴指令,操作碼2920會被解釋為A[2], #020h。而前綴將一位添加到目的標識符,并將一些位添加到立即數中,從而允許處理器向任意寄存器子譯碼加載任意值,并且永遠不會超過兩個執行周期。
實例
獨特的MAXQ20內核結構可以實現一些其它處理器不能完成的操作。向量中斷
MAXQ20內核僅具有一個中斷向量寄存器,一些用戶可能認為這是一個缺陷。但實際情況是:考慮到具有兩個外部中斷的系統,可將其中的設備A連接至端口0位0,設備B連接至端口0位1;對應的中斷選擇可以像跳轉PIO一樣操作簡單。在地址0上,編碼為:0000: IRET 0001: jump SERVICE_DEVICE_A 0002: jump SERVICE_DEVICE_B 0003: jump SERVICE_DEVICE_A該例中,設備A具有中斷服務優先權。也就是說,如果兩個中斷請求線同時有效(端口0上位0和位1均有效),先響應設備A。在中斷服務程序結束時,只有當設備A中斷不再有效時,才能夠響應設備B中斷。
任務管理器
在多數應用程序中,輪詢任務列表非常重要,以便產生一個多任務處理環境下的原始數據類型。這點在無需優先權限時非常有用(或不需要實時操作的情況)。MAXQ結構簡化了這種程序:task_wheel_init: move dp[0], #task_list task_wheel: move dp[0], dp[0] jump @dp[0]++ . . . task_list: dw task_01 dw task_02 dw task_03 dw task_wheel_init在該例子中,DP[0]指向任務列表。在task_wheel程序中,DP[0]被選中用來作為源指針,并接著從任務列表中加載指令指針。每當完成一個任務時,不是執行一個RET,而是簡單地跳轉至task_wheel程序即可。
向量表中的最后一個入口地址用來重新初始化指針,并且任務調度器開始重新掃描向量表。
遍歷列表
通常,為做好標記的入口快速搜索非標準大小的對象是非常有用的。但對于某些處理器結構來說實現此功能是有困難的,因為其存儲器訪問功能已從ALU刪除。在MAXQ中,這是一個非常簡單的任務。TAG | LEN | Data | |||||||||||||
3F | 09 | 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | ? | ? | ? | ? | ? |
17 | 0E | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 1A | 1B | 1C | 1D |
35 | 07 | 20 | 21 | 21 | 22 | 23 | 24 | 25 | ? | ? | ? | ? | ? | ? | ? |
對于這個例子,假設該列表包含由標記、長度和數據串組成的數據對象。遍歷該列表的程序如下:
item_seek: move acc, @dp[0]++ ;Get tag jump z, item_not_found ;Tag==0 means end of list cmp a[1] ;A[1] has target tag jump e, item_found ;If item==target, exit move acc, @dp[0]++ ;If no match, get data len add dp[0] ;Add to pointer move dp[0], acc ;Store pointer back jump item_seek ;...and seek next item.該程序8個指令遍歷列表,尋找匹配項或標記為零的項,以此來終止列表。采用8MHz MAXQ20內核時,該程序每秒遍歷一百萬次。
評論
查看更多