跳转至

2021 计算机组成原理问答

本页面是这学期的已经整理出的常见问题。新的问题请更新至腾讯文档

请问实验二 ddl 可以延长一点吗?

答:没有这个打算。之后会开一个作业,所有晚交的作业(包括实验)都交到那个迟交作业的网络学堂作业上。实验可以继续正常提交,但是会算晚交。

如何创建库,提交代码?

答:

  1. 在这个位置创建一个 gitlab 库 https://lab.cs.tsinghua.edu.cn/thinpad/

  2. 从这个位置 https://git.tsinghua.edu.cn/cod-ta/cod21-xxxxxxxx clone 到本地的代码。(创建 access token) \ 创建完 access token 之后用下面的方法 clone 到本地 \ git clone https://oauth2:xxxxxxxxtoken@git.tsinghua.edu.cn/cod-ta/cod21-xxxxxxxx

  3. 编写本地的代码,通过 vivado 综合,仿真,上传到 thinpad 云平台上测试通过

  4. git add, git commit, git push 提交代码。

另外,也可以使用 ssh key 的方式来使用。往 git.tsinghua.edu.cn 平台上上传公钥就行。这种方式更加安全。

以上两种方法都可以。使用 ssh key 的配置方法参考下面的网址:

https://git-scm.com/book/zh/v2/%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8A%E7%9A%84-Git-%E7%94%9F%E6%88%90-SSH-%E5%85%AC%E9%92%A5

各位同学务必要抽出一点时间学习一下 git 的最基本的用法。

在 bilibili 上面搜索“git 教程”就可以搜到一堆教学视频。

Multiple Driven Nets?

答:

这是常见的错误。在不同的 always 语句块中对相同的输出信号进行赋值。这样在实现的时候,就会导致错误。

always 1    -------------
​                            |    (0)
​                                -------------> output
​                            |    (1)
always 2    --------------

就像上面这种情况,上面的 always 块给了 0,下面的 always 块给了 1,那么 output 就不知道怎么办了。

所以,只能在一个 always 语句块中给 output 赋值。

always @() 为什么不会导致死循环呢?

答:

always@() 描述的是一个组合电路,当输入变了输出就变了。这里的 always 说的意思是下面描述一个模块的功能。@() 的意思是下面的电路涉及到的输入的任何信号发生变化,那么下面描述的就是我的输出发生什么样的变化。它不是不停工作的,是说通电的时候,在输入端发生的任何变化,电信号都按照 always 语句块的描述进行传播,传播到输出端。

for 循环,while 循环?

答:

建议在描述真正硬件的时候不要使用。只有简单的循环语句才能够被综合器综合出来。并且,什么样的循环语句能被综合,什么样的不能被综合都是很难说的,在不同的综合器下面表现情况不一样。所以,不要用 for 循环,while 循环等。

常用的组合逻辑器件包括加法器(全加器,半加器),编码器,译码器,数据选择器,比较器等都不需要循环来实现。

网上提交需要检查什么?

答:

  1. vivado 版本必须是 2019.2,就是实验指导书指定的版本,任何一个其他版本都不能正常工作。
  2. 正常的通过 gitlab clone 到本地的项目(见上面如何在 gitlab 里面创建文件)
  3. 都是通过 vivado 加进去模块的,不是直接拷贝进去的(会设计到项目配置文件,例如 xpr)
  4. 所有的文件都是在项目目录下(如果添加外部文件的话,必须保证文件拷贝到项目目录下,万一是链接进来的话就不对了)
  5. 本地 bitstream 生成成功
  6. 通过网络测例测试成功
  7. git add. git commit git push
  8. 然后去网上看一下综合的情况。有的时候需要等一下。因为之前你 commit 的前面一个正在综合。

如果网上综合出现错误,查看一下 https://git.tsinghua.edu.cn/ 上面的综合与实现的日志。

CI/CD --> Pipelines --> 右边有一个 download artifacts,然后里面综合和实现目录下的 runme.log,这里面指出了在线综合和实现的错误情况。

仿真时遇到如下错误类型:

ERROR: [VRFC 10-3818] variable 'xxx' is driven by invalid combination of procedural drivers
WARNING: [VRFC 10-2921] 'yyy' driven by this always_ff block should not be driven by any other process
WARNING: [VRFC 10-2921] 'zzz' driven by this always_comb block should not be driven by any other process

答:

不要在 initial 块和 always_ff 里面对同一个信号赋值,既然已经有 reset 的判断了,initial 是没有意义的,而且 initial 也不能综合,不应该出现在代码里面。如果已经写了正确的 reset 逻辑的话,直接去掉 initial 块就好了,寄存器不是变量,不需要声明的时候给初值。 这句话是错误的,在少数一些情况下,即使有了 reset,还是有 initial 的必要,部分 initial 是可以综合的,可以出现在代码里面。

常见的错误 multi driven 写法:

// Example 1
// https://support.xilinx.com/s/article/60013?language=en_US
wire [45:0] io_i = 46'd0; 
assign io_i = io; 

// Example 2
// https://www.reddit.com/r/FPGA/comments/7z90uv/vivadosynth_83352_multi_driven_net_i_must_admit_i/
always @ (*) begin
    work_done = 1;
end

always @ (posedge clock) begin
    work_done <= 0;
end

实验三的实现要点:

答:

写的时候,数据和地址先准备好,we_n 拉低足够长时间(拉低一个时钟周期其实够了,你可以拉长成 2 个也行,然后数据就写进去了。读的时候:地址先准备好,数据线设置成高阻态 Z,然后拉低 oe_n 足够长的时间(拉低一个时钟周期也够了,拉长成多个也行)让后就可以把数据读出来了。

出现问题先把后仿真时序的波形贴出来。

以过测试为准。

尽量提前做实验,不要等到最后一天。

ucore 实验的一些提示信息

答:

计算机组成原理 uCore 挑战实验说明

这里有个大概的提示。

https://github.com/chyyuu/os_kernel_lab/tree/x86-32

这是 x86 下面的 32 位的操作系统。

https://chyyuu.gitbooks.io/ucore_os_docs/content/

这个是操作系统实验的内容。

按照 qq 文档里面的内容,先跑起来,看看有哪些指令。一条一条实现。

先把系统在 qemu 里面跑起来,这样就有基础对照着做了。

SRAM 实验中多次查看后发现 RAM 中的数据丢失?

现象 首次查看数据成功写入,二次查看后发现数据丢失(以地址 0x0 为例,复位后数据变为 0x0)

分析 在查看内存时,如果仍对 FPGA 进行内存操作,将会造成冲突,因此这个时候会对 FPGA 进行重置,然而并不会对内存进行任何更改!

排错 通过读操作读取字节发现没有问题,按下 reset_btn 后再次读取出现问题,确认是 0x0 单元被重新写入

解答 当 FPGA 重置 或 reset_btn == `RstEnable 时,直接调转到 给地址阶段,这时读取的地址自然为空,再次按下 push_btn 时输入的也为空(零字),表现为数据清空

错误(伪)代码如下所示:

//sram.v,为个人测试实现
module sram (...);
    ...
    reg [1:0] phase;
    always @ (posedge clk or posedge rst) begin
        if (rst == `RstEnable) begin
                phase <= `AddrPhase; // ! 直接跳转到给地址阶段
            end else begin
                ...
            end
        end
    end
    ...
endmodule

UART 和 SRAM 联合中给出时序正确但仍无法写入 BaseRAM?

现象 将 base_ram_data 传入模块中后,即使仿真后确认对 UART 和 SRAM 的操作时序和信号正确,仍无法写入 BaseRAM

原因:

  1. 没开字节使能 assign sram_be = 4'b0000; (非主要原因)

  2. 错误的理解了 inout wire 能通 output wire 一样通过关联到寄存器进行赋值操作(主因)

// uart_sram.v
module uart_sram (..., inout wire [31:0] base_ram_data, ...)
    reg [31:0] data;
    assign base_ram_data = data;
    ...
endmodule

这样做 只会将 inout wire 变成 output wire 来操作,即只能输出不能输入

SRAM 实验中每次都是第一组数据无法写入/失配/无法读出?

现象 只有第一组数据出问题

原因 STATE_IDLE(根据康总的 ppt)中没有“人为特地”禁用所有使能,在仿真时不难其有一定概率会处于低电平(使能态),建议在 STATE_IDLE 中全部"拉高"

请问可以安排(参与龙芯杯的)助教们进行 例常技术经验分享会吗?想了解一些技术细节(例:分支跳转预测,多发射)的实现

答:可以,我们尽快安排。

关于多个时钟的问题

答: 发现有同学给内存接了 50Mhz 的时钟,给串口接了 11M0592 的时钟。这个是不对的。我们设计的电路只在一个频率下面运行,不能在两个或者多个频率下面运行。(在多个时钟频率下运行当然是可以的,但是是高级设计技巧,必须要做同步,现阶段没学,也没必要学)。所以,所设计的电路只能在一个时钟域下运行,这一点务必注意。11M0592 是用来直接分频到直连串口的,不是 CPLD 的。

准确地说,你都用 50M 或者都用 11M0592 是可以的,但是不要混用。

UART 和 SRAM 实验中,FPGA 发到串口的数据一直不对

现象:评测中 Received、Data Sent 和 Data in RAM 不一致

解决:地址算错了,要么是写的时候地址算错了,要么是读的时候地址不对。在 tb.sv 中设置 dip_sw 为非零值,更容易找到问题。

经验:如果发现评测的时候哪组数据不对,就在 tb.sv 里试着自己复现一次实验的流程

请问如果汇编读到串口写状态位空闲,但这时候离真正的 sb 指令还有几条,在这几条之间串口忽然 dataready 开始读发生的小概率冲突在设计 CPU 时需要考虑么?

答: 这个冲突可以在 sram_uart_controller 里面解决。

可以先读,读到一个寄存器里面,然后接收用户的写。

先写,放到一个写寄存器里面,告诉上面说写完了。然后再读串口,放到一个读寄存器里面。然后再真正开始写。

有很多种写法,硬件怎么做,上层的汇编语言就是驱动硬件去工作。


最后更新: 2023年11月5日
作者:Jiajie Chen (30.12%), Youyou Lu (64.86%), gaoyichuan (3.86%), Youyou Lu (1.16%)