跳转至

2022 计算机组成原理问答

我在学习过程中遇到许多问题,有哪些方式可以向教学团队寻求帮助?

推荐的方式有:网络学堂的课程答疑;微信群;向老师或助教发邮件答疑;课后答疑;与老师或助教预约线下答疑;餐叙答疑。添加助教微信好友,或私聊助教微信答疑可能不会得到回复。

请问实验 1 的代码分析报告要细化到什么程度?

不需要逐行分析,但是最少要描述清楚核心的逻辑,主要的代码块之类的。shell 的命令也不必逐个分析,核心是理解 kernel 如何和 term 进行通讯的,而不是这些命令。在本实验中只需要分析基础版本的代码,不过建议同学们完整阅读并理解 kernel 的代码(不需要写到本实验的报告中),对后面实验很有帮助。

实验模板中的 `default_nettype none 是做什么的?

在 Vivado 中默认的 default nettype 是 wire,即所有未显式指定类型的信号均被认为是 wire 类型。这可能导致一些错误不易被发现,如有信号名拼写错误,Vivado 会隐式地认为错误的信号名为 wire 类型,也能通过综合。为了帮助同学们排查错误,实验模板设置 default nettype 为 none,在有信号未显式指定类型时(包括在模块的输入中使用 logic)会报错。

我的代码在仿真下得到的结果正确,但上板运行得到的结果错误,我该怎么办?

根据助教的经验,若在强度足够的测例下仿真正确,且代码符合规范,没有时序违约,则上板运行的结果一般都是正确的。在小实验中建议按照以下步骤排查问题:

  1. 确定自己完全理解了自己写出的代码,清楚地明白哪些部分应该用组合逻辑,哪些部分应该用时序逻辑,并能在代码中找到对应的部分。
  2. 检查代码中是否有不符合规范的地方,如在组合逻辑块中使用非阻塞赋值,在时序逻辑块中使用阻塞赋值等不应出现的写法;同时,检查 Vivado 给出的 Warning,若有 latch 一定要通过符合规范的写法消除。
  3. 确保没有时序违约,即实现后 Vivado 没有在右上角以醒目的红字给出 Failed Timing 的警告。
  4. 增大仿真测例强度,最好能保证仿真的测例与上板运行的测例一致。检查仿真波形图中是否有可能引起不确定行为的"X"信号。

我的代码中有写入 x0 时的特判,仿真环境下工作也正常,代码也符合规范,但上板实验结果仍然不正确,表现为读出的 x0 寄存器的值不为 0,可能是什么问题?

如果同学使用了“二维数组”作为寄存器堆,请同学检查自己在复位寄存器堆时是否直接对整个二维数组进行了赋值(如logic[15:0] mem[31:0]; mem[0:31] <= '{32{16'b0}};),Vivado 的综合器在这种情况下会出现 bug,导致综合出奇怪的结果。建议对每个寄存器分别初始化。

模块的输入和输出中,wire 和 reg 有什么区别?

模块的 input 只能是 wire,模块的 output 可以是 wire,也可以是 reg。如果是 wire 的话,那就只能在 assign 持续赋值语句中进行对 output 的赋值,综合的时候会被综合成一条信号线。如果是 reg 的话,可以在 always_comb 中进行赋值,也可以在 always_ff 中被赋值。如果是在 always_comb 中进行赋值,那么仍然会被综合成信号线。如果是在 always_ff 中进行赋值,那么会被综合成寄存器。(以及这个寄存器的输出)如果是 always 块中进行赋值的话,output 必须是 reg 类型。

我的代码无法通过 gitlab 的 CI / CD 成功生成比特流,应该如何排查问题?

同学可以检查 CI/CD -> Pipelines,点击右侧的 Download Artifacts 的按钮下载相关日志文件,解压查看 synth_1/runme.log,里面记录了一些综合和实现时的报错信息。

综合器在什么情况下会综合出 latch?

如果组合逻辑块 always_comb 中,有的信号在一定的条件下没有赋值,综合器就会认为在部分情况下需要“保留”之前的值,这样就会产生 latch。

实验 3 没有思考题,实验报告应该包含哪些内容?

没有强制要求,建议写一下自己的设计、思路、问题之类的,最好带上关键代码。

实验平台上与串口相关的注意事项有哪些?

请在实验平台上选择串口为直连串口,调整波特率为 115200,并记得开启串口。

更详细的说明可以参考指导书中实验 2实验 5 的相关章节。

我通过了实验 4 & 5 的测试,就能说明我的 Wishbone 实现完全符合规范吗?Wishbone 的实现有哪些需要注意的细节?

由于测试环境限制,通过测试也不能保证相关实现是完全符合规范的。请同学们严格按照实验指导书中的规范实现,不要过拟合 slave 来写 master,否则可能会在后续的实验中遇到问题。

一些常见的不符合规范的实现有(持续更新中):

认为 master 持续发送请求,所以将 stb 一直置为 1。规范的做法是在收到 slave 给出的 ack 后将 stb 置 0,之后需要时再置 1。

更加全面细致的规范,可以参考实验指导书中的相关章节,或者直接参考官方手册

实验 6 中如何权衡是实现多周期处理器还是流水线处理器?

实验 6 中实现多周期或流水线对本实验的最终成绩没有影响,但组队大实验要求必须实现流水线处理器。根据助教估计,综合考虑实现和调试难度,实现流水线处理器所需的工作量大约为实现多周期处理器的 3 倍。大家可以根据自己的实际情况进行选择。

另外,虽然实现完全正确的流水线比较困难,但是由于实验 6 的测试强度较小,实现能够通过实验 6 测例的流水线处理器并没有那么困难。值得注意的是,由于访存需要多个时钟周期,课上所讲的发生数据冲突的情况并不会全部发生,在本实验中可以简化考虑。当然,在最后的大实验中,大家可能会实现缓存或对 sram 的读写时序进行优化,这样就仍然需要完整考虑数据冲突的情形。

补交的作业或小实验的成绩如何评定?

教学团队会酌情考虑。一般情况下,除非到期末考试前还没有提交小实验(这有可能导致不能参加期末考试),其它情况下补交小实验/作业对成绩的影响是相当小的,同学们可以不用担心。

实验 6 中综合报错 multi driven / 从 sram 读取数据时最后一个字节是 x 可能是什么原因?

实验 6 的 top 仅仅是示例代码,请在理解代码的基础上,做任何你觉得合理和必要的更改。出现 multi driven 可能是因为没有删除 top 中的 async_transmitter 模块;从 sram 读取数据时最后一个字节是 x 可能是因为没有关闭 cpld 串口导致冲突,可以参考实验 5 的 top 文件。

实验 6 能够通过公开测例,不能通过隐藏测例。
实验 6 仿真通过,线上实验完全没有反应(不会写入 SRAM,没有串口输出)。

先检查一下自己是否符合以下状况: 上传完 bin 文件之后,检查 BaseRAM 中的代码数据是否仍然完整,即是否仍为写入的代码没有变。如果发现代码段有变化,则说明你的 CPU 对代码段的 BaseRAM 进行了写入,这是不应该发生的行为。

目前遇到的所有人都是在 reset 的时候出现的问题。注意在 vivado 的仿真当中,if(X) 内的逻辑是不会执行的,但在上板的时候不会出现 X 值, 只会有 0 或者 1,从而导致上板行为与仿真行为不一致的问题。请仔细检查每个寄存器信号是否需要 reset 以及是否正确的 reset。同时检查在 sys_rst 变为 0 之后的第一个周期,是否有关键信号的值为 X,并且将其随机地设置为 0 或 1 会导致问题(如 base_ram_ce_n )。

本地综合可以通过,提交到 CI 上报出 'ERROR: [Runs 36-527] DCP does not exist: xxx.dcp'。

线上平台有一个奇怪的特性。如果你在工程当中加入了一个 ip 核(如 pll),但是在你设置的 top 文件对应的设计文件中没有使用到的话就会产生这个错误。

有两种可能:

  1. 你使用了错误的 top 文件。这种时候设置改成正确的 top 文件就可以解决这个问题。

  2. 本来你使用了某些 ip 核,但在使用之后又将其从设计中移除,不想继续使用了。这种时候请右键这个 ip 核,把它删掉就可以了。

我已经尝试了我所有能够尝试的手段了,但是性能测试依旧有 30s 之内跑不完的项目,我该怎么办?

首先不要太过担心。由于今年有 Wishbone 总线的加入,CPU 确实会慢许多,性能测试有通过不了的项目相当正常。为此你可以有如下几种解决方案:

  1. 尝试优化 Wishbone 访存的周期数。可以参考 Wishbone SRAM 控制器 # 扩展 的内容。

  2. 编写 ICache, DCache, BTB, TLB 等,提高最优理论 IPC。

  3. 尝试提高 CPU 的主频。可以参考 实验平台的顶层项目 # 锁相环电路 的内容。但注意,在提高 CPU 主频之后,请不要出现时序违约。同时,你可能需要增加 SRAM 的访存周期以满足 SRAM 的读写时序要求,详见 内存器件手册。并注意请不要在你的设计当中尝试使用多个时钟。

应该如何仿真监控程序运行用户程序的情况呢?

有如下几种方法:

  1. 在实验 1 中大家应该都已经编写过监控程序和 term 的代码分析报告了。再读一遍自己写的报告,模拟 term 通过串口向监控程序发送数据。注意串口传输数据的速度很慢,并且监控程序需要初始化,因此请在发送第一个字节前,以及发送相邻两个字节的中间等待足够长的时间。

  2. 如果仅仅是为了测试中断,异常等功能,则可以仿照监控程序自己编写一个最小化的初始化和异常处理函数,并把你要测试的程序放进去一起编译得到 bin 文件,参考实验 6 的方法进行仿真即可。

  3. 可以尝试修改监控程序,仿照性能测试测例,将你要测试的程序添加进去,然后模拟的时候只需要模拟 G 命令,并传输地址就好了。详见监控程序的 test.S。注意观察你要测试的代码的地址。

我应该如何自己测试每个组特定的 RISC-V B 扩展中的 3 条指令?
我应该如何自己测试实验考试中的自定义指令?

有如下几种方法:

  1. 自己写一个 c++/python 程序生成 bin 文件用来测试

  2. 在汇编中使用 .word 宏,如下图:

    反汇编生成的 elf 之后,可以验证数据已经正确写入 bin 文件中:

    注意这种方法在监控程序的 term 中一样适用。

仿真仿到一半就卡住了,控制台中提示 "Iteration limit xxx is reached."
CRITICAL WARNING: [Synth 8-295] found timing loop.

说明你的设计中出现了组合回路。请尝试进行综合,然后查阅 xxx.runs/synth_1/runme.log。定位到上述的 CRITICAL WARNING。你应该能在附近找到出现环路的信号列表(如下图)。请检查你的设计,并在这些信号中间插入寄存器来断开这个回路。

监控程序在 M 特权态是否会发生中断?
为什么监控程序要忽略 M 态中断?
为什么不实现 mstatus.MIE 也会发生时钟中断?

请先仔细阅读 RISC-V privileged 3.1.6.1 Privilege and Global Interrupt-Enable Stack in mstatus register 一节仔细思考中断的发生条件。

注意,不需要实现 mstatus.MIE 的原因是它一直是 0。


最后更新: 2023年8月31日
作者:Jiajie Chen (1.44%), cuibst (46.04%), Shaofeng Ding (52.52%)