第 8 章 AXI总线接口设计

从这一章开始,我们将进入一个新的阶段—为设计出的CPU增加AXI总线接口。在大多数真实的计算机系统中,CPU通过总线与系统中的内存、外设进行交互。没有总线,CPU就是个“光杆司令”,什么工作也做不了。总线接口可以自行定义,也可以遵照工业界的标准。显然,遵照工业界的标准有助于与大量第三方的IP进行集成。因此,本书选用AMBA AXI总线协议作为CPU总线接口的协议规范。

本章的设计任务有两个难点:一是CPU内部要如何调整以适应总线接口下的访存行为,二是如何设计出一个遵循AXI总线协议的接口。为了降低设计的难度,我们按照工程实践的经验,将这部分设计工作划分为三个阶段:

  • 阶段一:将原有CPU访问SRAM的接口调整为类SRAM总线接口。类SRAM总线只是在SRAM接口的基础上增加了握手信号,可以降低直接实现AXI总线的设计复杂度。
  • 阶段二:设计实现一个“类SRAM-AXI”的转接桥,拼接上阶段一完成的CPU,运行AXI固定延迟验证。读者将从这个阶段开始学习并实现AXI总线协议。
  • 阶段三:完善阶段二的CPU,完成AXI随机延迟验证。

【本章学习目标】

  • 理解片上总线的一般性原理。
  • 掌握总线接口与CPU内部流水线之间的交互设计。

【本章实践目标】

本章有三个实践任务(见本章8.1节)。读者可以在学习本章内容的基础上完成这些任务,两者之间的对应关系如下:

  • 本章??节和??节的内容对应实践任务14(8.1.1节)。
  • 本章??节和??节的内容对应实践任务15(8.1.2节)和实践任务16(8.1.3节)。

8.1 任务与实践

完成本章的学习后,希望读者能够完成以下3个实践任务:

  1. 添加类SRAM总线支持,参见下面第8.1.1小节。
  2. 添加AXI总线支持,参见下面第8.1.2小节。
  3. 完成AXI随机延迟验证,参见下面第8.1.3小节。

8.1.1 实践任务14:添加类SRAM总线支持

本实践任务要求在实践任务13实现的CPU基础上完成以下工作:

  1. 将CPU对外接口修改为类SRAM总线接口。
  2. 在采用握手机制的block RAM的SoC验证环境中完成exp14对应func的随机延迟功能验证。

请参照第2.3.1节中介绍的方式获取本次实践任务所需的实验开发环境。具体的实验环境仍位于 mycpu_env/ 目录下,不过验证时不再使用soc_bram/子目录,而应使用soc_hs_bram/子目录

伴随着CPU访问的指令RAM和数据RAM的实现形式从普通的block RAM更换为带握手机制的block RAM,实验开发环境需要进一步调整:仍然是mycpu_env实验环境,gettrace/、func/ 和 myCPU/ 子目录的位置和用途依然维持不变,只是 soc_verify/ 子目录下不再使用 soc_bram/ 子目录而是改为使用 soc_hs_bram/ 子目录,soc_hs_bram/ 子目录中的文件组织结构和用途与 soc_bram/ 子目录中的相似。调整后的实验开发环境的目录结构及各部分功能简介如下所示:

|--gettrace/                   生成参考trace的部分。
|--func/                       实验任务所用的功能验证测试程序。
|--myCPU/                      自己实现的CPU的RTL代码。
|--soc_verify/                 自己实现的CPU的SoC系统验证环境
   |--soc_hs_bram/             CPU对外连接handshaking block RAM接口时对应的验证环境。
   |  |--rtl/                  SoC_Lite设计代码目录。
   |  |  |--soc_lite_top.v     SoC_Lite的顶层文件。
   |  |  |--CONFREG/           confreg模块,用于访问CPU与开发板上数码管、拨码开关等外设。
   |  |  |--BRIDGE/            1×2的桥接模块, CPU的data sram接口同时访问confreg和data_ram。
   |  |  |--ram_wrap/          以类SRAM接口封装的RAM模块。
   |  |  |--xilinx_ip/         定制的Xilinx IP,包含clk_pll、inst_ram、data_ram。
   |  |--testbench/            功能仿真验证平台。
   |  |  |--mycpu_tb.v         功能仿真顶层,该模块会抓取debug信息与golden_trace.txt进行比对。
   |  |--run_vivado/           Vivado工程的运行目录。
   |     |--constraints/       Vivado工程的设计约束。
   |     |--mycpu_hs_bram_prj/ Vivado工程文件所在目录。

实验环境准备就绪后,请参考下列步骤完成本实践任务:

  1. 将所实现CPU的代码更新至mycpu_env/myCPU/目录中。
  2. 修改func配置文件——mycpu_env/func/include/test_config.h,选择exp14的配置,编译。(如果是通过压缩包exp14.zip获取实验开发环境的,请跳过该步骤。)
  3. 打开gettrace工程——mycpu_env/gettrace/gettrace.xpr。(该Vivado工程中的IP核是使用Vivado2019.2创建的,如果使用更高版本的Vivado打开,请参考附录D.4节进行IP核升级。)运行gettrace工程的仿真(进入仿真界面后,直接点击run all等待仿真运行完成),生成新的参考trace文件golden_trace.txt(mycpu_env/gettrace/golden_trace.txt)。要等仿真运行完成,golden_trace.txt才有完整的内容。(如果是通过压缩包exp14.zip获取实验开发环境的,请跳过该步骤。)
  4. 进入 mycpu_env/soc_verify/soc_hs_bram/run_vivado/ 目录下启动验证myCPU的工程。如果该目录下尚未创建工程,请参照附录D.2节介绍的步骤,利用该目录下的 create_project.tcl 文件创建工程。如需要,请参考附录D.4节进行IP核升级。
  5. 参考第44.2.5.2小节,对工程中的inst_ram重新定制。(如果是通过压缩包exp14.zip获取实验开发环境的,请跳过该步骤。)
  6. 在验证myCPU的工程中运行仿真(进入仿真界面后,直接点击run all),进行功能验证与调试,直至仿真测试通过。
  7. 在验证myCPU的工程中综合实现后生成bit流文件,进行上板验证。(如果无硬件实验平台,请跳过该步骤。)

1.上板验证的要求

上板验证时,要求“随意切换拨码开关后按复位键”,CPU能通过对应exp14的func中58个功能点的验证。

“随意切换拨码开关后按复位键”是为了设定初始的随机种子(随机种子用于生成inst/data ram访问时的随机延迟拍数),开始运行功能验证。由于功能验证程序里的指令较多,随机种子不同会导致取指或访存的随机延迟拍数不同,CPU执行状态也会大不相同,所以切换初始随机种子后出现错误是很常见的。

请注意上板验证的具体操作:将8个拨码开关切换为随意状态,按复位键;松开复位键后,数码管开始累加,此时可以切换开关来控制wait_1s的累加速度。

2.拨码开关的功能

从上面的内容可以看出,上板验证时,拨码开关有两个功能:

  • 功能一:复位期间,拨码开关控制初始随机种子,进而控制CPU取指及访存的随机延迟拍数的生成序列。
  • 功能二:复位后,拨码开关控制wait_1s的循环次数,也就是控制数码管累加的速度。

对于功能二,在58个功能点测试中,每两个功能点之间会穿插一个wait_1s函数,wait_1s通过一段循环完成计时的功能:wait_1s的循环次数由拨码开关控制,可设置循环次数为(0~0xaaaa) \(\times\) 29。上板验证时,建议在复位后,通过拨码开关选择合理的wait_1s 延时。

对于功能一,为尽可能验证myCPU的功能,CPU_CDE_SRAM里对访存延迟设定了一个随机机制:访存延迟拍数是通过一个32位的伪随机数发生器(在confreg.v文件里实现)生成的。在仿真验证时,该伪随机数发生器初始随机种子由confreg.v里的宏RANDOM_SEED指定;在上板验证时,其初始随机种子由复位期间采样到的拨码开关状态来指定。

实验箱上共有8个拨码开关,实际电平是:拨上为0,拨下为1。但是为了便于以下的描述,我们记作:拨上为1,拨下为0。16个LED单色灯的实际电平是:驱动0亮,驱动1灭。同样,我们记作:驱动1亮,驱动0灭。

上板验证时,按下复位键,会自动采样8个拨码开关的值作为初始随机种子,且会显示初始随机种子低16位到单色LED灯上。上板时随机种子与拨码开关的对应关系如图8.1所示,需要注意的是,延迟类型依据拨码开关的值分为三类:长延迟、短延迟和无延迟类型。在上板验证时,应当覆盖这三类延迟。

上板验证时初始随机种子设定

图 8.1: 上板验证时初始随机种子设定

3.“仿真通过,上板不过”的调试方法

【情况一】 上板验证时发现数码管没有任何累加。

这可能是由于以下问题之一导致的:

  1. 多驱动。
  2. 模块的input/output端口接入的信号方向不对。
  3. 时钟复位信号接错。
  4. 代码不规范,阻塞赋值乱用,always语句随意使用。
  5. 仿真时控制信号有“X”。仿真时,有“X”调“X”,有“Z”调“Z”。特别要注意的是,设计的顶层接口上不要出现“X”和“Z”。
  6. 时序违约。
  7. 模块里的控制路径上的信号未进行复位。

【情况二】 上板验证时发现在某些随机种子下测试通过,在另一些随机种子情况下出错。

请按以下步骤进行调试:

  1. 确认上板验证时出错的初始随机种子,修改mycpu_env/soc_verify/soc_hs_bram/rtl/CONFREG/confreg.v文件中宏RANDOM_SEED的定义值,改为出错时的初始随机种子,随后进行仿真。如果有错,则进行调试;如果发现仿真没有出错,则在上板验证时寻找下一个出错的初始随机种子,同样设定好RANDOM_SEED后进行仿真,如果尝试多个初始随机种子后仿真都没有出错则转到步骤2。
  2. 当遇到“相同初始随机种子,仿真无法复现上板的错误”的情况时,请采取以下措施:排查列出的可能原因,复查代码和反思设计,也可以使用Vivado的逻辑分析仪进行在线调试(参考附录DD.5节)。

【情况三】 上板验证时发现任意随机种子下,都只有部分功能点测试通过。

这时可能以上两种情况的原因都存在,请依次排查。

8.1.2 实践任务15:添加AXI总线支持

本实践任务要求在实践任务14实现的CPU基础上完成以下工作:

  1. 将CPU顶层接口修改为AXI总线接口。CPU对外只有一个AXI接口,需在内部完成取指和数据访问的仲裁。推荐在本任务中实现一个类SRAM-AXI的2x1的转接桥,然后拼接上实践任务一完成的类SRAM接口的CPU,将myCPU封装为AXI接口。
  2. 在采用AXI总线的SoC验证环境里完成exp15对应func的固定延迟功能验证,要求成功通过仿真和上板验证。

请参照第2.3.1节中介绍的方式获取本次实践任务所需的实验开发环境。具体的实验环境仍位于 mycpu_env/ 目录下,不过验证时不再使用soc_hs_bram/子目录,而应使用soc_axi/子目录

伴随着CPU对外访问接口由带握手机制的block RAM更换为AXI总线接口,实验开发环境需要进一步调整:仍然是mycpu_env实验环境,gettrace/、func/ 和 myCPU/ 子目录的位置和用途依然维持不变,只是 soc_verify/ 子目录下不再使用 soc_hs_bram/ 子目录而是改为使用 soc_axi/ 子目录。调整后的实验开发环境的目录结构及各部分功能简介如下所示:

|--gettrace/                生成参考trace的部分。
|--func/                    实验任务所用的功能验证测试程序。
|--myCPU/                   自己实现的CPU的RTL代码。
|--soc_verify/              自己实现的CPU的SoC系统验证环境
   |--soc_axi/              CPU对外连接AXI接口时对应的验证环境。
   |  |--rtl/               SoC_Lite设计代码目录。
   |  |  |--soc_lite_top.v  SoC_Lite的顶层文件。
   |  |  |--CONFREG/        confreg模块,用于访问CPU与开发板上数码管、拨码开关等外设。
   |  |  |--ram_wrap/       以支持随机延迟访问封装的AXI RAM模块。
   |  |  |--axi_wrap/       AXI的1x1转接口,连接CPU和Crossbar,用于抹平仿真和上板的差异。
   |  |  |--xilinx_ip/      定制的Xilinx IP,包含clk_pll、axi_ram和axi_crossbar_1x2。
   |  |--testbench/         功能仿真验证平台。
   |  |  |--mycpu_tb.v      功能仿真顶层,该模块会抓取debug信息与golden_trace.txt进行比对。
   |  |--run_vivado/        Vivado工程的运行目录。
   |     |--constraints/    Vivado工程的设计约束。
   |     |--mycpu_axi_prj/  Vivado工程文件所在目录。

实验环境准备就绪后,请参考下列步骤完成本实践任务:

  1. 将所实现CPU的代码更新至mycpu_env/myCPU/目录中。
  2. 修改func配置文件——mycpu_env/func/include/test_config.h,选择exp15的配置,编译。(如果是通过压缩包exp15.zip获取实验开发环境的,请跳过该步骤。)
  3. 打开gettrace工程——mycpu_env/gettrace/gettrace.xpr。(该Vivado工程中的IP核是使用Vivado2019.2创建的,如果使用更高版本的Vivado打开,请参考附录D.4节进行IP核升级。)运行gettrace工程的仿真(进入仿真界面后,直接点击run all等待仿真运行完成),生成新的参考trace文件golden_trace.txt(mycpu_env/gettrace/golden_trace.txt)。要等仿真运行完成,golden_trace.txt才有完整的内容。(如果是通过压缩包exp15.zip获取实验开发环境的,请跳过该步骤。)
  4. 进入 mycpu_env/soc_verify/soc_axi/run_vivado/ 目录下启动验证myCPU的工程。如果该目录下尚未创建工程,请参照附录D.2节介绍的步骤,利用该目录下的 create_project.tcl 文件创建工程。如需要,请参考附录D.4节进行IP核升级。
  5. 参考第44.2.5.2小节,对工程中的axi_ram重新定制。(如果是通过压缩包exp15.zip获取实验开发环境的,请跳过该步骤。)
  6. 在验证myCPU的工程中运行仿真(进入仿真界面后,直接点击run all),进行功能验证与调试,直至仿真测试通过。
  7. 在验证myCPU的工程中综合实现后生成bit流文件,进行上板验证。在上板验证时,要求8个拨码开关处于“高4个拨下,低4个拨上”的状态(对应访存随机延迟类型为无延迟),能正确运行func。(如果无硬件实验平台,请跳过该步骤。)

8.1.3 实践任务16:完成AXI随机延迟验证

本实践任务要求在实践任务15实现的CPU基础上完成以下工作:

  1. 完善AXI总线接口设计使其在采用AXI总线的SoC验证环境里完成exp16对应func的随机延迟功能验证,要求成功通过仿真和上板验证。

请参照第2.3.1节中介绍的方式获取本次实践任务所需的实验开发环境。具体的实验环境仍位于 mycpu_env/ 目录下,且仍使用 soc_axi/ 子目录。

实验环境准备就绪后,请参考下列步骤完成本实践任务:

  1. 将所实现CPU的代码更新至mycpu_env/myCPU/目录中。
  2. 修改func配置文件——mycpu_env/func/include/test_config.h,选择exp16的配置,编译。(如果是通过压缩包exp16.zip获取实验开发环境的,请跳过该步骤。)
  3. 打开gettrace工程——mycpu_env/gettrace/gettrace.xpr。(该Vivado工程中的IP核是使用Vivado2019.2创建的,如果使用更高版本的Vivado打开,请参考附录D.4节进行IP核升级。)运行gettrace工程的仿真(进入仿真界面后,直接点击run all等待仿真运行完成),生成新的参考trace文件golden_trace.txt(mycpu_env/gettrace/golden_trace.txt)。要等仿真运行完成,golden_trace.txt才有完整的内容。(如果是通过压缩包exp16.zip获取实验开发环境的,请跳过该步骤。)
  4. 进入 mycpu_env/soc_verify/soc_axi/run_vivado/ 目录下启动验证myCPU的工程。如果该目录下尚未创建工程,请参照附录D.2节介绍的步骤,利用该目录下的 create_project.tcl 文件创建工程。如需要,请参考附录D.4节进行IP核升级。如果该目录下已有前一实践任务创建过的工程,可以在打开工程后,参照附录D.3节介绍的步骤,更新项目中CPU实现文件的列表。
  5. 参考第44.2.5.2小节,对工程中的axi_ram重新定制。(如果是通过压缩包exp16.zip获取实验开发环境的,请跳过该步骤。)
  6. 修改mycpu_env/soc_verify/soc_axi/rtl/CONFREG/confreg.v文件中宏RANDOM_SEED为不同值,在验证myCPU的工程中运行仿真(进入仿真界面后,直接点击run all),进行功能验证与调试,直至仿真测试通过。
  7. 重复上一步骤多次,要求宏RANDOM_SEED的修改值能覆盖本章前面介绍的三种随机延迟类型。
  8. 在验证myCPU的工程中综合实现后生成bit流文件,进行上板验证。在上板验证时,要求“随意切换拨码开关后按复位键”,均能正确运行func。如果出现“仿真通过,上板不过”的现象,请按照前面8.1.1小节介绍的方法进行调试。(如果无硬件实验平台,请跳过该步骤。)