天天看點

自己動手寫CPU之第八階段(1)——轉移指令介紹

将陸續上傳本人寫的新書《自己動手寫CPU》,今天是第34篇,我盡量每周四篇

感興趣的朋友可以在亞馬遜、當當、京東等查找。

另外,開展曬書評送書活動,在亞馬遜、京東、當當三大圖書網站上,發表《自己動手寫CPU》書評的前十名讀者,均可獲贈《步步驚芯——軟核處理器内部設計分析》一書,大家踴躍參與吧!活動時間:2014-9-11至2014-10-20

      本章将為OpenMIPS處理器添加轉移指令,轉移指令包括跳轉、分支兩種,差別在于前者是絕對轉移,後者是相對轉移,但實作方法是相似的。轉移指令涉及延遲槽,是以首先在8.1節介紹了延遲槽的概念,接着在8.2節對MIPS32指令集架構中定義的所有轉移指令的格式、作用、用法進行了說明。在8.3節介紹了OpenMIPS實作轉移指令的思路,以及對資料流圖、系統結構的修改。8.4節通過修改代碼實作了轉移指令,最後通過兩個測試程式,驗證轉移指令是否實作正确。

8.1 延遲槽

      在實作轉移指令之前,先介紹一下延遲槽的概念。在第5章已經介紹了流水線中存在的三種相關:資料相關、結構相關、控制相關。其中控制相關是指流水線中的轉移指令或者其他需要改寫PC的指令造成的相關。這些指令改寫了PC的值,是以導緻後面已經進入流水線的幾條指令無效,比如:如果轉移指令在流水線的執行階段進行轉移條件判斷,在發生轉移時,會導緻目前處于取指、譯碼階段的指令無效,需要重新取指。如圖8-1所示。

自己動手寫CPU之第八階段(1)——轉移指令介紹

      也就是在流水線執行階段進行轉移判斷,并且轉移發生,那麼會有2條無效指令,導緻浪費了兩個時鐘周期。為了減少損失,規定轉移指令後面的指令位置為“延遲槽”,延遲槽中的指令被稱為“延遲指令”(也可稱之為“延遲槽指令”)。延遲指令總是被執行,與轉移發生與否沒有關系。引入延遲槽後的指令執行順序如圖8-2所示。OpenMIPS處理器就計劃使用延遲槽技術。

自己動手寫CPU之第八階段(1)——轉移指令介紹

      但是,即使引入延遲槽,在轉移發生時仍然會導緻已經進入取指階段的指令無效,也就是仍浪費一個時鐘周期,要解決這個問題,可以在譯碼階段進行轉移判斷,這樣就可以避免浪費時鐘周期。OpenMIPS處理器就設計為在譯碼階段進行轉移判斷。

8.2 轉移指令說明

      MIPS32指令集架構中定義的轉移指令共有14條,可分為如下兩類。

  •  跳轉指令: jr 、jalr 、j 、jal
  •  分支指令:b、bal、beq、bgez、bgezal、bgtz、blez、bltz、bltzal、bne

      其中,跳轉指令是絕對轉移,分支指令是相對轉移。本節分别介紹這兩類指令。

      1、跳轉指令

      跳轉指令的格式如圖8-3所示。

自己動手寫CPU之第八階段(1)——轉移指令介紹

      從圖8-3可知,j、jal指令可以通過指令碼進行判斷,jr、jalr指令的指令碼為SPECIAL,還需要依據功能碼進一步判斷。

  •  當指令中的指令碼為SPECIAL,功能碼為6'b001000時,表示是jr指令

      指令用法為:jr rs

      指令作用為:pc <- rs,将位址為rs的通用寄存器的值賦給寄存器PC,作為新的指令位址。

  •  當指令中的指令碼為SPECIAL,功能碼為6'b001001時,表示是jalr指令

      指令用法為:jalr rs 或者jalr rd, rs

      指令作用為:rd <- return_address, pc <- rs,将位址為rs的通用寄存器的值賦給寄存器PC,作為新的指令位址,同時将跳轉指令後面第2條指令的位址作為傳回位址儲存到位址為rd的通用寄存器,如果沒有在指令中指明rd,那麼預設将傳回位址儲存到寄存器$31。

  •  當指令中的指令碼為6'b000010時,表示是j指令

      指令用法為:j target

      指令作用為:pc <- (pc+4)[31,28] || target || ‘00’,轉移到新的指令位址,其中新指令位址的低28位是指令中的target(也就是圖8-3中的instr_index)左移兩位的值,新指令位址的高4位是跳轉指令後面延遲槽指令的位址高4位。

  •  當指令中的指令碼為6'b000011時,表示是jal指令

      指令用法為:jal target

      指令作用為:pc <- (pc+4)[31,28] || target || ‘00’,轉移到新的指令位址,新指令位址與指令j相同,不再解釋。但是,指令jal還要将跳轉指令後面第2條指令的位址作為傳回位址儲存到寄存器$31。

      j、jal、jr、jalr指令在轉移之前都要先執行延遲槽指令。

      2、分支指令

      分支指令的格式如圖8-4所示。

自己動手寫CPU之第八階段(1)——轉移指令介紹

      從圖8-4可知,前5條指令beq、b、bgtz、blez、bne可以直接依據指令中的指令碼進行判斷,确定是哪一條指令,而後5條指令bltz、bltzal、bgez、bgezal、bal的指令碼都是REGIMM,這是一個宏定義,值為6'b000001,需要根據指令中16-20bit的值進一步判斷,進而确定是哪一條指令。

      從圖8-4還可知,所有分支指令的0-15bit存儲的都是offset,如果發生轉移,那麼将offset左移2位,并符号擴充至32位,然後與延遲槽指令的位址相加,加法的結果就是轉移目的位址,從該位址取指令。

轉移目标位址 = (signed_extend)( offset || ‘00’ ) + (pc+4)

  •  當指令中的指令碼為6'b000100時,表示是beq指令

      指令用法為:beq rs, rt, offset

      指令作用為:if rs = rt then branch,将位址為rs的通用寄存器的值與位址為rt的通用寄存器的值進行比較,如果相等,那麼發生轉移。

  •  當指令中的指令碼為6'b000100,且16-25bit為0時,表示是b指令

      指令用法為:b offset

      指令作用為:無條件轉移,從圖8-4可知,b指令可以認為是beq指令的特殊情況,當beq指令的rs、rt都等于0時,即為b指令,是以在OpenMIPS實作的時候不需要特意實作b指令,隻需要實作beq指令即可。

  •  當指令中的指令碼為6'b000111時,表示是bgtz指令

      指令用法為:bgtz rs, offset

      指令作用為:if rs > 0 then branch,如果位址為rs的通用寄存器的值大于零,那麼發生轉移。

  •  當指令中的指令碼為6'b000110時,表示是blez指令

      指令用法為:blez rs, offset

      指令作用為:if rs ≤ 0 then branch,如果位址為rs的通用寄存器的值小于等于零,那麼發生轉移。

  •  當指令中的指令碼為6'b000101時,表示是bne指令

      指令用法為:bne rs, rt, offset

      指令作用為:if rs ≠ rt then branch,如果位址為rs的通用寄存器的值不等于位址為rt的通用寄存器的值,那麼發生轉移。

  •  當指令中的指令碼為REGIMM,且16-20bit為5'b00000時,表示是bltz指令

      指令用法為:bltz rs, offset

      指令作用為:if rs < 0 then branch,如果位址為rs的通用寄存器的值小于0,那麼發生轉移。

  •  當指令中的指令碼為REGIMM,且16-20bit為5'b10000時,表示是bltzal指令

      指令用法為:bltzal rs, offset

      指令作用為:if rs < 0 then branch,如果位址為rs的通用寄存器的值小于0,那麼發生轉移,并且将轉移指令後面第2條指令的位址作為傳回位址,儲存到通用寄存器$31。

  •  當指令中的指令碼為REGIMM,且16-20bit為5'b00001時,表示是bgez指令

      指令用法為:bgez rs, offset

      指令作用為:if rs ≥ 0 then branch,如果位址為rs的通用寄存器的值大于等于0,那麼發生轉移。

  •  當指令中的指令碼為REGIMM,且16-20bit為5'b10001時,表示是bgezal指令

      指令用法為:bgezal rs, offset

      指令作用為:if rs ≥ 0 then branch,如果位址為rs的通用寄存器的值大于等于0,那麼發生轉移,并且将轉移指令後面第2條指令的位址作為傳回位址,儲存到通用寄存器$31。

  •  當指令中的指令碼為REGIMM,且21-25bit為0,16-20bit為5'b10001時,表示是bal指令

      指令用法為:bal offset

      指令作用為:無條件轉移,并且将轉移指令後面第2條指令的位址作為傳回位址,儲存到通用寄存器$31。從圖8-4的指令格式可知,bal指令是bgezal指令的特殊情況,當bgezal指令的rs為0時,就是bal指令,是以在OpenMIPS實作時,不用特意考慮bal指令,隻要實作bgezal指令即可。

      綜上,b、bal指令不用單獨實作,需要OpenMIPS實作的分支指令隻有8條。

      所有的分支指令在轉移到目标位址前都要先執行延遲槽中的指令。

繼續閱讀