最近risc-v真是火的不要不要的,開源的cpu也出了不少,正好想學習soc,果斷從risc-v開始搞起。

關於risc-v的介紹,網上到處都是了,簡單說來,就是ucb搞的一套完全開源並且可以自由擴展的isa,目前有用戶指令集和特權指令集兩個,不過我的計劃是先soc,再cpu,所以這些文檔都只是粗略掃了一眼,了解了一下而已,後續隨著學習的深入,估計會回頭一遍又一遍的翻看。

截至目前,risc-v的開源cpu跟配套soc,不說上百,十幾種反正是有了,本文及後續筆記(假如有空)都是基於蜂鳥e203開源cpu和部分修改後的soc,在此十分感謝蜂鳥作者胡振波,給我等菜鳥提供了這麼好的學習機會。

本文為學習筆記第一篇,內容關於蜂鳥的debug模塊的初步理解,由於都是基於自己的理解,難免有錯誤的地方,如果有錯誤,希望有好心人能幫忙指出來並糾正。

關於cpu的架構,只要是學過計算機體系結構都應該有所了解,一個基礎版5級流水線mips處理器充其量也就是本科生大作業的水平。不過關於cpu的debug模塊,說實話,我在本科和研究生的學習中都沒有涉及,直接導致我之前完全不理解soc的debug機制。

蜂鳥開源soc實現的debug模塊參考了sifive公司的0.11版本的debug spec,上圖是總體結構,整個debug模塊包含了dtm和dm兩個大模塊,其中dtm就是ieee 1149標準中所定義的jtag的邊界掃描模塊,而dm則是實現soc內部debug的核心模塊。

dtm模塊是依據ieee 1149標準實現的tap控制器,對邊界寄存器進行掃描輸入或輸出,對應的是蜂鳥開源soc裡面的sirv_jtag_dtm模塊。之前我一直以為dtm模塊應該去控制cpu周圍的寄存器,從而就可以對cpu進行debug。但這裡並不是這樣,這裡dtm僅僅是一個橋樑,將jtag端的信號轉為內部寄存器,然後輸入dm模塊,或是將dm的響應結果轉化成jtag信號返回上位機,dtm的設計則完全參照ieee標準即可。

dm模塊是debug模塊的核心,其包含控制邏輯、debug rom、debug ram跟硬體線程狀態。debug模塊包含一個slave匯流排埠,供cpu訪問debug rom和debug ram。當控制邏輯拉起cpu中斷後,cpu進入debug模式,此時pc應指向debug rom,dm模塊將佔據一個cpu核心。在debug rom內,cpu會根據當前狀態執行一段固定程序,程序入口包括entry、resume或exception,entry是的作用是將s0、s1寄存器存入對相應的狀態和控制寄存器(s1存入的地址為debug ram最後),之後進行狀態寄存器的檢查,並跳入debug ram。事實上,核心的調試均需要通過debug ram完成。例如想要對soc中的寄存器或內存進行寫入操作,就將如下程序和數據通過dtm寫入debug ram:

lw s1,data
lw s0,address
sw s1,0(s0)
j resume
address:.word address
data:.word data

這也是為什麼這個spec規定32位的risc-v至少需要28byte(7個word)的debug ram的原因,這裡需要4條指令、2個word的數據,以及1個word保存著進入debug模式前s1的數據。

resume和exception執行的指令相同,區別在於exception會將0xffffffff寫入debug ram最後一個word內,然後等待debug的中斷重新拉起,再次將s1保存到debug ram,跳入debug ram執行裡面的debug程序。我先前有一個疑惑,這裡是如何通過最後一個word為全0或全1來判斷是否有異常發生的?這裡我的理解是,jtag debugger會在拉起新的中斷前,先檢查debug ram內的內容,如果發現出現了0xffffffff,則進行相應的處理,如果沒有,再把新的debug程序寫進去,再拉起中斷,使得debug繼續進行下去,直到debug結束,退出debug模式。

debug模塊另一個關鍵之處是斷點,斷點是對cpu進行debug不可或缺的特性。spec0.11中對斷點的介紹只有軟體斷點,就是在需要斷點的地方插入一條斷點指令,ebreak。查看蜂鳥的代碼後發現,蜂鳥裡面也是通過ebreak的方式實現軟體斷點,似乎都沒有實現硬體斷點。這裡需要注意的是,在非debug模式下,如果debug模塊里的dcsr寄存器中ebreakm沒有置1,cpu執行ebreak指令只會直接跳入異常處理,只有當dcsr寄存器里ebreakm置1且執行到ebreak指令,cpu才會進入debug模式,然後進入異常處理,也就是實現斷點調試。

// The ebreak instruction will generated regular exception when the ebreakm
// bit of DCSR reg is not set
wire alu_excp_i_ebreak4excp = (alu_excp_i_ebreak & ((~dbg_ebreakm_r) | dbg_mode))
;
// The ebreak instruction will enter into the debug-mode when the ebreakm
// bit of DCSR reg is set
wire alu_excp_i_ebreak4dbg = alu_excp_i_ebreak
& (~alu_need_flush)// override by other alu exceptions
& dbg_ebreakm_r
& (~dbg_mode);//Not in debug mode

spec中還介紹了trace模塊,然而這個模塊sifive也還沒做,蜂鳥自然沒有實現。另外,debug模塊裡面還可以增加一個master匯流排埠,這樣的話某些讀寫soc中寄存器值的操作就不再需要佔用cpu來進行了,比如xilinx的ip:jtag to axi master,不過這個功能蜂鳥裡面也沒有實現,這裡就沒啥可討論的了。

看完spec0.11再結合蜂鳥的代碼算是對debug模塊有了初步的認識,不過很多細節還沒有深入研究,之後邊研究邊補充吧。

推薦閱讀:

相关文章