久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 2213|回復: 0
收起左側

32位和16位指令集模式自動切換機制

[復制鏈接]
ID:105323 發表于 2016-3-4 14:21 | 顯示全部樓層 |閱讀模式
    我們都知道MIPS架構體系是32位精簡指令集(MIPS32),事實上MIPS在進入控制器市場時還推出了MIPS16e指令集模式,號稱能夠使編譯后的代碼減少30%左右,類似于ARM架構中是arm32指令(32位)和thumb(16位)指令。內存資源緊缺型系統一般會使用MIPS16e模式進行編譯,以縮減內存使用量,達到降低成本的目的。
    ISAMODE是指令集運行模式的指示位,但這個比特位并不是固定在某個寄存器中。調試時可以發現,該比特位對應32位運行地址的最低比特位。為1時代表此時芯片運行的是MIPS16e模式,0即意味著MIPS32模式。指令運行過程中,兩種指令集的切換是自動、無縫地完成的。在ARM架構中是arm指令和thumb指令切換。
    本文說明兩種指令模式的切換機制,并用實例來詳細說明兩者之間是如何進行切換的。一、必須跑MIPS32指令集模式的場景
這是MIPS體系結構決定的:  
1. 中斷/異常。CPU響應中斷/異常之后就自動進入mips32模式。
  2. “sync”指令必須在mips32模式下使用。
3. 協處理器cp0的讀寫必須在mips32模式下。
4. 因為性能的考慮,某些算法有時追求高效率,應該運行在mips32模式下。


二、運行模式切換
1. 異常/中斷

    MIPS異常和中斷發生時會自動轉到32位模式,這時EPC寄存器記錄的是發生異常時的地址(該地址如果之前運行于MIPS16e模式,則是16位對齊,否則是32位對齊),其最低位就對應ISAMODE bit。中斷/異常處理過程可以保存EPC并切換到16e模式運行。
   在中斷/異常返回時,即調用ERET指令時,可以返回到EPC中保存的地址,并把EPC的最低位賦值給ISAMODE,恢復到原來的運行模式。
    2. 函數調用和返回

    運行模式協同工作的原理主要是在調用時將代表當前運行模式的ISAMODE BIT和返回地址一起放到RA或者某個指定的寄存器。因為mips16e/32的返回地址至少是2字節對齊,所以其最低位一定是0,ISA MODE BIT占用bit 0不會造成返回地址混亂。
    在返回時,根據RA或者RX的bit 0恢復運行模式,接著返回。
    1)JAL
    這條指令調用后,代碼運行模式不變,而且其是在256M的范圍內進行調用。在同樣的編譯模式下,調用函數時會產生JAL指令。
    2)JALX
    這條指令調用后,代碼運行模式反轉,同樣是在256M的范圍內進行調用。如果在16e的函數中調用32的函數,編譯器就會產生JALX調用;同樣,如果在32的函數中調用16e的函數,會產生JALX。
    3)JALR
    這條指令可以調用不同的運行模式的代碼,其可以在4G的范圍內進行調用。RX保護目標地址的運行模式和地址內容。
    4) JR
    利用這條指令返回,根據RA或者RX的bit0恢復運行模式,接著返回。
    3. 使用總結
    1) 雖然是用MIPS16E編譯,但代碼中同樣會出現32位擴展指令,上面這些跳轉指令和save 、restore等指令都是32位編碼的。CPU運行在16位模式時,如果碰到這些指令,也是先取16bit內容,但譯碼時發現其是32位指令,即停止譯碼,并把后面16bit取進來一起執行。其實16e模式的16bit指令在CPU內部一樣會翻譯為32bit指令。
    2) 開發人員應該明確自己負責開發的代碼以何種模式編譯,我們有兩種選擇決定函數的編譯模式。一種是命令行選項,一種是添加函數的屬性。
   編譯選項如下:
   GCC_MIPS16e = -g -c -G0 -Wall-Wno-unknown-pragmas $(INCLUDE) -msoft-float -fsigned-char -mtune=m4k-mips16e-nostdinc -nostdlib -fno-builtin $(OFORMAT) $(BUILD_MACRO)
   GCC_MIPS32 = -g -c -G0 -Wall-Wno-unknown-pragmas $(INCLUDE) -msoft-float -fsigned-char -mtune=m4k -mips32r2-nostdinc -nostdlib -fno-builtin $(OFORMAT) $(BUILD_MACRO)
   定義函數時添加屬性聲明__attribute__((mips16))是告訴編譯器以mips16e的模式去編譯該函數。__attribute__((nomips16))即表示以mips32的方式去編譯。對于C文件,我們一般用命令行選項去決定其使用何種模式進行編譯。但如果在一個文件中某個函數希望以另外的模式編譯時就要添加函數的屬性。這時命令行的編譯模式選項是不起作用的。
    匯編文件頭部一定要注明這個編譯屬性。Gcc命令行選項的mips16/mips32對匯編文件不起作用。
    3) 在調用外部函數時,一般要extern聲明被調用的函數,這時不需說明該函數的編譯屬性,說明了也不起作用。鏈接階段會根據函數定義時的編譯屬性生成相應的調用指令。

三、例證
    無論是同種模式的調用還是不同模式之間的調用,在256M空間內(默認為near)一律編譯出來為jal,在鏈接階段才確定是否需要修改為jalx。在超過256M的空間內(聲明被調用函數為far)一律編譯出來是jalr或者jalrc,在鏈接階段才確定是否要修改指令。

1. mips32模式函數調用(mips16e或者mips32)模式函數

1) 使用命令行選項CC_OPTS_BASE進行編譯。
2) 舉例代碼:
//該函數在不同的文件中定義,鏈接地址在256M范圍內,并以mips16e模式編譯。
extern int test_16_fun_near(int a);
//該函數在不同的文件中定義,鏈接地址超過256M范圍內,并以mips16e模式編譯。
extern int test_16_fun_far(int a) __attribute__((far));
//該函數在本文件中定義,但以mips16e模式編譯。
int __attribute__((mips16))test_16_fun_inline(int a);
//該函數在本文件中定義,并以mips32編譯。
int test_32_fun_inline(int a);
//調用函數示例
int test_32_fun(int a)
{
   int b,c,d,e;
    b= test_32_fun_inline(88);
    d= test_16_fun_inline(77);
    c= test_16_fun_near(99);
    e= test_16_fun_far(66);
   return a + 100 + b + d;
}
3) 編譯及鏈接如下:
可見在編譯階段都是產生jal和jalr 指令,在鏈接階段才修正相關指令。
調用test_32_fun_inline最終生成jal指令,ISA MODE不變。
調用test_16_fun_inline最終生成jalx指令,ISA MODE反轉。
調用test_16_fun_near最終生成jalx指令,ISA MODE反轉
調用test_16_fun_far最終生成jalr指令,v0寄存器的值是
0x80000000+0x61(97是十進制)= 0x80000061,而test_16_fun_far的實際地址是0x80000060,bit0代表test_16_fun_far運行的是1,即mips16e的模式。
2. mips16e模式函數調用(mips16e或者mips32)模式函數
1)使用命令行選項CC_OPTS_BASE_16進行編譯.
2)舉例代碼:
//另外文件定義,32編譯,超過256M。
extern int test_32_fun_far(int a)__attribute__((far));
//另外文件定義,32編譯,256M范圍內。
extern int test_32_fun_near(int a);
//本文件定義,但以32編譯。
int __attribute__((nomips16))test_32_fun_inline_1(int a) ;
//本文定義,16e編譯。
int test_16_fun_inline(int a);
//調用示例代碼:
int test_16_main(int a)
{
   int b,c,d,e;
    b= test_16_fun_inline(88);
    d= test_32_fun_inline_1(77);
    c= test_32_fun_near(99);
    e= test_32_fun_far(66);
   return a + 100 + b + d;
}
3) 編譯和鏈接如下:

可見在編譯階段都是產生jal和jalrc 指令,在鏈接階段才修正相關指令。

調用test_16_fun_inline最終生成jal指令,ISA MODE不變。
調用test_32_fun_inline_1最終生成jalx指令,ISA MODE反轉。
調用test_32_fun_near最終生成jalx指令,ISA MODE反轉
調用test_32_fun_far最終生成jalrc,其寄存器所放的值是間接跳轉的。這條指令是根據對應的寄存器的值 來進行跳轉的。v0的值是0x80000284內存的值,即0x80000168。其bit0是0,所以jalrc到該地址后,其ISA MODE 為0,即從16e轉變為32模式。

對間接跳轉,我們進行特別的分析:
mips32調用mips16e:調用test_16_fun_far時,jalr v0前的指令是lui v0, 0x8000;
add v0,v0,XX。即對v0賦值是使用lui這種利用直接數進行賦值的指令。編譯階段是add v0,v0,0;鏈接階段 是add v0,v0,97進行了一次重定位。
mips16調用mips32:調用test_32_fun_far時,jalrc v0 前的指令是lw v0, 84 (b208),而且其編譯和鏈接 階段的指令碼都沒有變,變的是0x80000284這個內存。編譯階段是全0,鏈接后是test_32_fun_far的實際地址0x 80000168。Lw指令跟lui指令不同,其是取內存的值到v0,而不是把地址值直接賦給v0.
為什么在0x80000266的地方的指令碼為b208,取的內存卻是0x80000284呢?

0x80000284 = 0x80000266 & 0xfffffffc0 + 8 << 2

回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 日韩一区二区三区精品 | 国产一级免费在线观看 | 一区二区三区在线 | 欧美日韩一区二区在线播放 | 国产免费一区二区 | 综合国产 | 一级黄色片在线免费观看 | 精品国产乱码久久久久久蜜臀 | 逼逼网 | 日韩美女一区二区三区在线观看 | 欧美区日韩区 | 日本精品久久久久久久 | 澳门永久av免费网站 | 99福利视频| 美女视频. | 久久精品中文字幕 | 精品日韩一区 | 国产精品美女久久久久久不卡 | 一级片在线观看视频 | 日本精品久久久久 | 成人在线免费观看 | 成人国产精品久久 | 精品国产乱码久久久久久老虎 | 在线观看中文字幕视频 | 国产91在线播放精品91 | 日本高清视频在线播放 | 日韩精品成人免费观看视频 | 91精品国产日韩91久久久久久 | 欧美a区 | 天天干天天插 | 亚洲精品一区二区在线观看 | 欧美精品中文字幕久久二区 | 久久久久久久国产精品 | 在线a视频网站 | 国产精品久久久久久久久婷婷 | 亚洲精品一级 | 操操日 | www日本在线 | 精品欧美黑人一区二区三区 | 精品中文字幕久久 | 午夜小电影 |