PDU 框架使用手册
仅仅完成 CPU 的仿真是不够的,我们需要一些特别的工具检验并控制 CPU 在 FPGA 开发板上的运行情况,这就需要使用 PDU 框架上板测试。
如何判断是否使用的是最新的 PDU?
你可以查看 UART_TX.v 的第 52 行,如果为 if (counter == 2604) begin,则代表使用的是最新的 PDU。如果你下载的不是最新的 PDU,可以在清除浏览器缓存后重新下载。注意:不要通过私自修改文件的方式将 PDU 升级!
PDU 是为了本学期组成原理实验而开发设计的板上控制单元。它可以接收来自用户的串口指令,将其解码并完成对应的操作,同时也可以获取 CPU 运行时的数据,并通过串口反馈给用户。
可能存在的问题
目前在串口写入时,如果序列过长,可能导致串口崩溃。如果遇到这种情况,请通过 sw7 手动刷新串口。正常情况下,每一次命令最后都会以 User: 的提示符结尾。如果遇到了其他问题,欢迎在本界面的评论区或 QQ 群中指出。
简介
本次实验提供的上板框架基本结构如下:
项目的文件结构如下:
vsrc
├─ CPU <---------------------------------- 你只需要修改 CPU 目录下的内容
│ └─ CPU.v
├─ MEM <---------------------------------- 内存管理
│ ├─ MEM_BRIDGE.v
│ └─ MMIO.v
├─ PDU <---------------------------------- PDU 及其附属模块
│ ├─ PDU.v
│ ├─ RTL
│ │ ├─ BP_LIST_REG.v <------------------ 用于记录并处理断点
│ │ ├─ INFO_SENDER.v <------------------ 用于向串口输出提示信息
│ │ └─ PDU_decode.v <-------------------- 用于对串口数据进行译码
│ ├─ UART
│ │ ├─ UART_RX.v
│ │ └─ UART_TX.v
│ └─ UTILS
│ ├─ HEX2ASCII.v
│ ├─ HEX2UART.v
│ ├─ POSEDGE_GEN.v
│ ├─ QUEUE.v
│ └─ Segment.v
└─ TOP.v <-------------------------------- 项目的顶层文件
其中,我们在 TOP.v 文件中例化了指令存储器和数据存储器。为此,你需要在自己的项目中创建两个分布式存储器 IP 核,并按照下图所示的参数进行配置(注意将 IP 核命名为 INST_MEM 和 DATA_MEM,并且导入测试代码对应的 coe 文件):
完成后,在 Vivado 的项目中将 vsrc 文件夹导入,即可使用本次实验的上板框架。
CPU 顶层接口
提醒
无论是 RV32I 还是 LA32R,本次实验都需要使用下面的接口!
本次实验中 CPU 的顶层模块如下所示:
| CPU | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | |
其中:
-
global_en信号为来自 PDU 的控制信号。该信号在本次实验中会控制 PC 寄存器的写使能,从而控制 CPU 是否执行指令。我们可以使用下面的代码例化 PC 寄存器:1 2 3 4 5 6 7
PC my_pc ( .clk (clk ), .rst (rst ), .en (global_en ), // 当 global_en 为高电平时,PC 才会更新,CPU 才会执行指令。 .npc (cur_npc ), .pc (cur_pc ) ); -
Memory (inst)下的接口将连接到指令存储器。请注意程序段的地址范围:RV32I 指令集 0x00400000 ~ 0x0ffffffc、LA32R 指令集 0x1c000000~0x1c7ffffc; Memory (data)下的接口将连接到数据存储器。本次实验中,dmem_we、dmem_addr和dmem_wdata端口在 CPU 模块内部无需连接;Debug下的接口会用于仿真和上板框架,下面介绍了这些端口应当如何连接。
上板测试流程
在 FPGAOL 上,上传项目的 .bit 比特流文件进行测试。
-
拨上再拨下 sw7,看到
USTC COD Project则说明 PDU 在正常运行。 -
输入
RR 0 32;查看所有寄存器当前的值。 -
输入
R;连续运行命令。此时 CPU 将持续运行,直到达到断点、运行完成或用户中断。本次实验中预期现象是持续运行直到 HALT 指令。 -
输入
RR 0 32;查看所有寄存器当前的值。你可以在 RARS 或 LARS 上运行一遍测试的汇编代码,比对运行结束时板上寄存器的值是否符合预期。
PDU 支持的命令列表
串口读写命令
提示
在使用 RI、RD、RR 命令时,可以在命令后面添加一个换行符 \n,从而避免出现乱码。例如:读取 32 个寄存器堆,可以输入 RR 0 32;\n(这里的 \n 是换行符!)。
RI [base]_16 [length]_10;
该命令从 base 地址开始,从指令存储器中读取连续的 length 个存储单元,并将结果显示在串口上。
length 的长度不超过 64。
e.g.
RI 0 10;
将会显示 0x0~0x24 十个存储单元的数据
RD [base]_16 [length]_10;
该命令从 base 地址开始,从数据存储器中读取连续的 length 个存储单元,并将结果显示在串口上。
length 的长度不超过 64。
RR [base]_16 [length]_10;
该命令从 base 地址开始从寄存器堆中读取连续的 length 个存储单元,并将结果显示在串口上。
length 的长度不超过 64。
e.g.
RR 0 10;
将会显示 R0 ~ R9 十个寄存器的数据
WI [base]_16 [length]_10 [code]_16;
该命令从 base 开始写入指令存储器连续的 length 个存储单元。后续的 code 以空格或换行符作为分隔,以分号结束。如果 code 的数目小于 length 的数目,则剩下的地址自动写 0。
length 的长度无限制。
e.g.
WI 0 2 1234 1235;
写入操作为:
M[0x0] <- 0x1234
M[0x4] <- 0x1235
WI 4 3 1234;
写入操作为:
M[0x4] <- 0x1234
M[0x8] <- 0x0
M[0xC] <- 0x0
我们也可以使用换行代替空格。请注意:不能引入多余的空格,否则会导致解码器解码错误!
e.g.
WI 0 3
1234
1235
1236;
写入操作为:
M[0x0] <- 0x1234
M[0x4] <- 0x1235
M[0x8] <- 0x1236
WD [base]_16 [length]_10 [code]_16;
该命令从 base 开始写入数据存储器连续的 length 个存储单元。后续的 code 以空格或换行符作为分隔,以分号结束。如果 code 的数目小于 length 的数目,则剩下的地址自动写 0。
length 的长度无限制。
断点命令
断点实现的基本原理是:当 CPU 产生 commit 信号时,PDU 会将 CPU 的 commit_pc 与 PDU 内部存储的断点进行比对,从而判断是否达到了断点。
BS [addr0]_16 [addr1]_16 [addr2]_16;
该命令会设置断点,后两个参数是可选的。PDU 允许至多设置三个不同的断点,并始终侦测 CPU 是否运行到了 bp0 的地址。 断点无法被覆盖,只可以触发或删除。
e.g.
BS 1000 2000;
会设置断点为
bp0 <- 0x1000
bp1 <- 0x2000
如果此时再次输入
BS 3000 4000 5000;
此时前两个断点地址已经被占用,故会设置断点为
bp2 <- 0x3000
如果 CPU 到达了 bp0 的地址,则接下来 bp0 会自动变为 bp1,bp1 会自动变为 bp2,bp2 会被自动清除。
即:
bp0 <- bp1
bp1 <- bp2
bp2 <- invalid
BL;
该命令可以查询当前已设置的断点。
BC;
该命令会清除所有的断点。
CPU 命令
R;
连续运行命令。此时 CPU 将持续运行,直到达到断点、运行完成或用户中断。
S;
单步运行命令。
H;
强制停机命令。该命令将中断 CPU 的连续运行状态。
MMIO
PDU 还提供了 MMIO 的功能。相关地址映射规则如下:
- 0xFFFF0008:该地址单元的低 8 位对应 led[7:0]。




