前面我們介紹了JTAG的基本知識,知道了JTAG的是如何通過操作IR,DR和TAP進(jìn)行數(shù)據(jù)交互的。這一篇就來繼續(xù)分享RISCV的DEBUG是如何使用JTAG進(jìn)行數(shù)據(jù)交互的。
我們參考官方的規(guī)格書《RISC-V Debug Specification Version 1.0-STABLE》,可以直接從github上下載https://github.com/riscv/riscv-debug-spec.
RISCV的整個(gè)DEBUG框架如下:

我們先來看幾個(gè)主要的組成部分。
其中(1)(2)是運(yùn)行在主機(jī)上的程序
(1)是調(diào)試程序,最常見的就是我們經(jīng)常使用的GDB,當(dāng)然很多是集成在IDE中的比如IAR的C-SPY 調(diào)試器。
(2)是調(diào)試服務(wù)程序。gdb等調(diào)試程序定義了一些基本的調(diào)試功能,需要將其翻譯成對具體仿真器硬件的操作。(2)就是做這個(gè)作用的。最常見的就是開源的OpenOCD,當(dāng)然一些芯片設(shè)計(jì)廠商可能會提供自己的服務(wù)程序做一些功能擴(kuò)展等,比如玄鐵的DebugServer,都是一樣的,一般都是基于開源的實(shí)現(xiàn)做的修改。
該程序會提供一組tcpi/ip服務(wù),Debugger就可以通過網(wǎng)絡(luò)連接到該服務(wù),兩者之間通過socket通訊,具體通訊內(nèi)容是gdb等規(guī)范的,比如設(shè)置斷點(diǎn),讀內(nèi)存等。
(3)是仿真器硬件部分,(2)和(3)一般通過USB通訊,很早期的仿真器是那種很大塊頭的并口的接口。(2)需要將(1)的需求轉(zhuǎn)為對(3)的硬件操作,(2)會支持很多種硬件仿真器,所以一般(2)會定義基本的需求,由(3)開發(fā)商提供DLL或者驅(qū)動(dòng),供(2)使用,這樣(2)就可以做到支持多種硬件。而(3)最終需要通過調(diào)試接口這里是JTAG來和TARGET的DEBUG模塊進(jìn)行交互。
(4)是TARGET中的DTM:Debug Transport Module調(diào)試傳輸模塊。即用于和(3)通訊,這是基于JTAG的TAP,Test Access Port測試訪問端口。即提供我們前面一篇文章說的IR,DR操作的能力。即(3)就是操作DTM的IR和DR來和DTM交互。
(5)DMI即Debug Module Interface調(diào)試模塊接口。(5)是(4)和(6)的接口橋梁,
因?yàn)?/span>(4)提供的操作能力有限,只能先選擇IR然對應(yīng)的操作DR,即前面介紹的IR選擇0x10和0x11,在選擇IR為0x11之后DR即對應(yīng)dmi的操作。然后進(jìn)一步的定義dmi操作的數(shù)據(jù)不同對應(yīng)不同功能,這樣就可以進(jìn)行更多復(fù)雜功能的擴(kuò)展。后面會繼續(xù)講到DMI的格式,以及DM定義一組寄存器空間用于通過DMI訪問。

(6)DM:Debug Module。這里才是TARGET的真正的調(diào)試模塊,DM模塊不能被DTM直接訪問,只能通過DMI,訪問DM的寄存器空間間接訪問。
(7)是RISC-V的core,DM對RISC-V core有復(fù)位/halt,讀寫寄存器,內(nèi)存等操作。
而讀寫寄存器,讀寫內(nèi)存有
Abstract Memory Access,Program Buffer,System Bus Access幾種方式,后文再講。
這一部分需要參考規(guī)格書的《Chapter 6 Debug Transport Module (DTM), non-ISA》章節(jié)。
從下表可看出支持JTAG的IR為0x01,0x10,0x11,其他都是BYPASS。
其中0x01是操作IDCODE獲取廠商版本信息。
0x10是直接控制dtm, 即dtm的控制和狀態(tài)寄存器。
0x11是操作dmi,通過dmi來間接操作dm。


從上面框圖可以看到,和DM交互,最重要的是DTM通過DMI訪問DM的過程,其中我們現(xiàn)在JTAG具備的直接能力是只能夠操作DTM的IR和DR。而通過DMI操作DM,需要指定IR=0x11,DR解析為dmi,不同的內(nèi)容代表不同的操作dm的寄存器的含義。
IR=0x00,0x12~0x17,0x1F時(shí),DR為1位寄存器值為0
用于表示DEBUGGER不與本TAP交互
IR=0x01,此時(shí)DR的值含義對應(yīng)為IDCODE,RISCV對IDCODE的定義如下,只能讀

IR=0x10,此時(shí)DR的值含義對應(yīng)為dtmcs, 定義如下

位域 | 描述 | 訪問 | 復(fù)位值 |
dmihardreset | 寫1對DTM進(jìn)行硬復(fù)位,DTM丟棄所有未完成DMI事務(wù),并將所有寄存器和內(nèi)部狀態(tài)恢復(fù)到其復(fù)位值。 | W1 | - |
dmireset | 寫1清除錯(cuò)誤狀態(tài),不影響DMI事務(wù) | W1 | - |
idle | 告訴調(diào)試器在每次DMI掃描后應(yīng)在RunTest/IIdle狀態(tài)等待的最小周期數(shù),以避免dmistat返回3busy狀態(tài)。 以下條件時(shí)調(diào)試器仍須檢查dmistat: 0:無需進(jìn)入Run-Test/Idle狀態(tài)時(shí)。1:進(jìn)入Run-Test/Idle且立即離開時(shí)。2:進(jìn)入Run-Test/Idle只停留1個(gè)cycle時(shí)。? | R | Preset |
dmistat | 只讀,對應(yīng)IR=0x11時(shí)的dmi.op? | R | 0 |
abits | dmi.address.的位數(shù) | R | Preset |
version | DTM版本信息 0 (0.11):0.11. 1 (1.0):0.13 1.0. 15 (custom): 暫時(shí)未定義. | R | 1 |
IR=0x11,此時(shí)DR的值含義對應(yīng)為dmi, 定義如下

在Update DR時(shí),DTM將啟動(dòng)op中指定的操作,除非op中報(bào)告的當(dāng)前狀態(tài)是粘滯的。在Capture DR中,DTM使用該操作的結(jié)果更新數(shù)據(jù),如果當(dāng)前操作不具有粘性,則更新操作。
位域? | 描述 | 訪問 | 復(fù)位值 |
address | DMI訪問的地址空間地址. ?Update-DR 時(shí)通過DMI訪問DM。 | R/W | 0 |
data | Update-DR時(shí)通過DMI寫入DM的值, 通時(shí)返回上衣此操作DM的返回值. | R/W | 0 |
op | 操作碼,區(qū)分不同的操作 0(nop),忽略address和data 1 (read):從address處讀數(shù)據(jù),數(shù)據(jù)返回到data 2 (write):往address處寫數(shù)據(jù)data 3 (reserved):保留,debugger讀該位表示上一次操作的狀態(tài),0 表示(success),1 表示(reserved),2 表示(failed)。該狀態(tài)是遲滯的即沒有新的狀態(tài)覆蓋則一直在,可以通過寫 dtmcs的dmireset清除。 3表示(busy),如果出現(xiàn)該狀態(tài)則需要UpdateDR和Capture-DR之間增加Run-Test/Idle狀態(tài)的時(shí)間,以等待。清除該狀態(tài)和failed一樣。 | R/W | 0 |
上一節(jié)可以看到,對DM的寄存器的操作轉(zhuǎn)換為了,IR=0x11,DR映射為dmi的基本操作。
DR只要按照dmi如下定義指定address,data和op即可操作對應(yīng)的DM寄存器。

支持的DM寄存器有哪些,參考規(guī)格書的3.15 Debug Module Registers章節(jié)。
現(xiàn)在就以讀寫Abstract Command為例,用邏輯分析儀抓取信號,來看下整個(gè)過程
首先是IR操作


然后中間是RUN-TEST/IDLE等待過程

然后是DR過程,對應(yīng)的DR(TDI)值為0x5C00000001,按照dmi解析
Address=0x17即Abstract Command
Data=0x00
Op=0x01即read



此時(shí)的TDO輸出的是上一次操作的值,所以還需要繼續(xù)來一次IR和DR。第二次的tdi即DR的值為0x00,按照dmi解析是nop,這次操作的目的是讀出上一次的操作的返回值,此時(shí)的tdo,dr就是返回值。


整個(gè)過程由IR-DR-IR-DR組成

這里假設(shè)寫值為0x55.
第一次IR-DR的dr(tdi)對應(yīng)dmi為0x5c00000156即
Address=0x17
Data= 0x55
Op=10 即write
第二次IR-DR的dr(tdi)對應(yīng)dmi為x0即
Nop操作。

然后后面工具自動(dòng)跟了一次回讀操作IR-DR-IR-DR(見前面讀Abstract Command)

所以以上寫實(shí)際過程是
IR-DR-IR-DR寫
IR-DR-IR-DR回讀(非必須,調(diào)試工具自動(dòng)加的)。
更復(fù)雜的操作無非也就是上述DM寄存器的讀寫操作而已,可以參考規(guī)格書的
B.2 External Debugger Implementation和3.15 Debug Module Registers
后文再分享一些關(guān)鍵操作。
以上分享了RISCV的DEBUG基于JTAG的數(shù)據(jù)流,以實(shí)例抓波形的方式介紹了DM寄存器的讀寫過程,至此可以根據(jù)波形分析DEBUGGER到底讀寫了哪些DM寄存器,具備調(diào)試分析DEBUG模塊的能力了。至于更細(xì)節(jié)一些的具體操作,我們后文再分享,也可以直接參考規(guī)格書。