Rocketchip RISC-V Debug调试硬件相关(一)

2019年10月份,RISCV发布了一版新的硬件代码,并对Debug调试部分进行了对应的升级修改,随后一直沿用2019年的版本至今,目前版本为0.13.2版本。本文重点研究对应的升级和修改意义,以及在后续SoC集成时的处理方法。阅读本文之前,请对RISCV的Debug调试有个基础的了解,比如JTAG五线或四线连接、调试软件openOCD、RISCV调试过程和基本流程。不了解也没关系,可先参考阅读下面这篇文章:

深入浅出RISC-V调试 | liangkangnan的博客 (gitee.io)https://liangkangnan.gitee.io/2020/03/21/%E6%B7%B1%E5%85%A5%E6%B5%85%E5%87%BARISC-V%E8%B0%83%E8%AF%95/RISCV官方Debug文档,也可以看下,不过很多细节并没有展开描述,所以要搞懂硬件实现还需要自己研究下代码,官方文档参考下面链接:

riscv-debug-spec/riscv-debug-release.pdf at release · riscv/riscv-debug-spec · GitHubhttps://github.com/riscv/riscv-debug-spec/blob/release/riscv-debug-release.pdf

一、总体硬件架构

上图是Rocket Chip的一个总体硬件架构,图中的实现是双核CPU,从图中可以看到Rocket Chip调试通路通过JTAG进入,首先会进入DTM模块。DTM模块完成了JTAG状态机TAP,内部将JTAG下发的命令转换成地址和数据的读写操作。DTM将转换好的读写操作通过DMI接口发送给DM。DM模块主要完成调试模式的进入,以及各种调试动作的完成,DM模块可以控制每个核(hart)发出指令,甚至控制每个核复位,完成上电后立即调试等功能。

DM模块内部又分为dmInner模块和dmOuter模块。dmOuter模块主要完成DM内部寄存器的实现,上位机可以通过调试通路读写dmOuter内部寄存器;dmInner模块主要完成dmOuter寄存器对核的控制操作,以及将dmOuter的控制转成TileLink总线的请求。

二、调试部分硬件架构

最新版本的DM硬件架构如上图所示,JTAG通过DTM模块进入,DTM和dmOuter通过一组io_dmi_*的DMI接口通信,dmOuter又通过auto_asource_out_*和io_innerCtrl_bits_*两组信号和dmInner通信。dmInner则通过auto_dmInner_tl_*的TileLink总线和控制总线Control Bus通信。图中黄颜色标注的是在TCK时钟域,绿色标注的是在内核时钟域或内核同步时钟域,第三小节再介绍。

dmOuter模块内部又分成五个部分:

  1. dmi2tl模块会将io_dmi_*的这组信号转成tilelink总线信号,再通过auto_out_*发起dmiXbar模块;
  2. dmiXbar模块类似于AXI的总线crossbar结构,实现了一个1TO2的总线结构;
  3. dmOuter模块是dm内部寄存器的所在位置,dmOuter接收TileLink auto_out_1_*总线,同时将寄存器的控制信号通过io_innerCtrl_bits_*连接到dmInner;除此以外,dmOuter还实现了对新增模块dmiBypass的控制信号,后续章节再详细介绍。
  4. dmiBypass模块为新版本新增加的功能,该模块的作用是当dmInner时钟无效时,或dmInner复位有效时,应答从JTAG调试通路发起的调试指令,dmiBypass内部会产生总线的读写请求应答;老版本没有该信号,因此当dmInner没有时钟或复位时,JTAG通路发起的读写请求无法得到应答。需要注意的是,该信号和DTM内部的JTAG Bypass功能不同,该功能会在后续章节进行详细介绍。
  5. asource模块接收另一组auto_out_0_*的总线请求,并将其异步处理后通过auto_asource_out_*送给dmInner。

图中DMI只是一个接口,并不是单独的模块。除此以外,dmInner实现了Program Buffer的功能,该功能虽然不是必须的,但是最好实现该功能,否则访问CSR和memory可能存在问题。

三、DM时钟复位

最新版的DM时钟复位关系如上图所示,JTAG TRST可以不接,但需要注意该复位控制DTM和DM模块的dmOuter部分,如果是四线JTAG,需要考虑dmOuter的复位由谁提供。图中黄色部分为TCK的时钟域,绿色部分为core clock时钟域。TCK时钟域下,JTAG调试通路可以一直访问到DM的dmOuter内部寄存器,但无法继续访问dmInner部分,原因是该部分时钟和内核时钟同步。

最新版的dmInner的时钟由外部提供,debug_clock和debug_reset组成一对,该时钟虽然官方将其作为输入由user logic处理,但官方对该时钟的要求是和内核时钟同步,同时复位保持和debug_clock 1:1的关系。

对于新版的改动,官方的原话为:

There is now a 1:1 relationship required between resets and clocks. dmOuter uses dmi_clock and dmi_reset and dmInner uses new inputs debug_clock and debug_reset. A portion of SBA is in the TileLink clock / reset domain.

也就是说最新版的改动基于时钟复位1:1的关系实现,dmOuter使用dmi_clock和dmi_reset,这两个时钟和复位在内部连接到了TCK和TRST的对外输入引脚,一组新的debug_clock和debug_reset用于给dmInner提供时钟和复位。

四、新版本修改的地方说明

新版本的修改,官方对其进行了解释和说明,参考下面链接可以了解详细的说明:

Convert Debug Module to abstract reset by ernie-sifive · Pull Request #2237 · chipsalliance/rocket-chip · GitHubhttps://github.com/chipsalliance/rocket-chip/pull/2237其中有几个较为重要的修改,将在后续文章中进行深入研究,这里对该原文内容翻译一下,不一定都对,有疑问可评论留言,一起探讨。

  • debug_clock must be synchronous to clock. The clock gate formerly in dmInnerAsync now resides outside the debug module in customer logic. Customer logic can call connectDebugClockAndReset to achieve the same functionality as before.

      debug_clock和core clock必须同步,clock gate之前在dmInner内部实现,现在需要外围  wrapper逻辑customer logic实现该功能。Customer logic可以调用connectDebugClockAndReseto achieve 来实现和之前版本一致的功能(但clock gate的std cell还是需要根据不同工艺库进行替换)

  • A new input dmactiveAck is returned from customer logic and is used to indicate when dmInner is able to accept DMI transactions (i.e. debug_clock is running and debug_reset is negated). When dmactiveAck is negated, a bus blocker returns denied for transactions to dmInner. The current version of OpenOCD is tolerant of this blocker, but other software may need to be updated.

       一个新的输入信号dmactiveAck需要customer logic处理,该信号用来指示dmInner是否有能力接受DMI传输请求(也就是说debug_clock有效,且debug_reset释放复位)。当dmactiveAck无效时(1’b0),总线blocker会返回“拒绝”请求dmInner命令。当前版本的OpenOCD能够兼容该blocker的行为,但其他的软件需要升级更新。

  • dmi_reset must be asynchronous. debug_reset may be either synchronous or asynchronous but its deassertion must always occur either when debug_clock is stopped or synchronously to debug_clock.

       dmi_reset必须要是异步的,debug_reset可以异步或者同步,但其复位释放必须总是在debug_clock无效的时候(异步),或者和debug_clock同步的时候(同步)。

  • hart-reset and halt-on-reset functions have been changed to simple I/O and require customer logic involvement. The two signals are grouped in a new ResetCtrlIO bundle. hartIsInReset is a logical equivalent of core_reset and is synchronous to core_clock. For debug module halt-on-reset function, this signal must remain asserted for at least 4 debug_clock cycles for the DM to assert debug interrupt plus 3 core_clock cycles for the debug interrupt to reach the core prior to the core_reset signal being deasserted. Halt-on-reset will not work if either clock or core_clock is not running.

       hart-reset和halt-on-reset功能现在移到了输入引脚,并且要求custom logic处理该引脚信号。该信号由ResetCtrlIO前缀组成一组,hartIsInReset信号在逻辑上等同于core reset,并且和core clock同步。该信号影响DM halt-on-reset功能,如果需要使用该功能,必须在core reset复位释放之前,保持该信号至少4个debug_clock周期(为了DM有效拉起debug中断)+3个core_clock周期(为了让debug中断得到内核的响应)有效。如果core clock不工作,那么halt-on-reset也不会工作。该功能也非常重要,将在后续章节介绍。

 除此之外,还有ndreset和dmactive信号,在SoC集成时需要注意信号的连接和实现。有相关问题和疑问,可以留言一起讨论,有不懂的也可以留言一起解决。

猜你喜欢

转载自blog.csdn.net/heyuming20062007/article/details/125594822