4. Lab4:指令译码器的设计

4.1. 实验目的

  • 掌握 Vivado 集成开发环境

  • 掌握 Verilog 语言

  • 掌握 FPGA 编程方法及硬件调试手段

  • 深刻理解指令译码器的工作原理及其在处理器中的作用

4.2. 实验环境

  • Vivado 集成开发环境

  • 龙芯 Artix-7 实验平台

4.3. 实验内容

  • 到目前为止,你已经实现了基本的 ALU、寄存器堆、存储器,它们是你正在本课程构建的处理器的基础部件。这些基础部件需要依赖输入的特定控制信号才能够正常工作,然而,真正的处理器处理的输入是指令,处理器的操作都是由表示为几个字节的指令给出的。因此,处理器需要具备一个部件,将从存储器中取出的指令正确转换为 ALU 等部件的特定控制信号,这便是指令译码器。本实验要求设计并实现一个支持8种指令的指令译码器,将输入的指令转换为给定规格的控制信号。要求其可以通过所提供的自动测试环境

4.3.1. 指令系统定义

本实验要求的指令译码器需要支持对8种 RISC 指令(与 MIPS32 类似)的识别及译码,它们也将是本课程后续实验中你所构造的处理器所需支持的(尽管部分指令未在本实验要求范围内),因此你在本实验中实现的译码器将会成为后续实验的基础。

该指令系统定义了32个通用寄存器r0-r31,其中r0恒为常数0。其具有8条指令:ADDSUBANDORXORLWSWJ,每条指令都是一个32位字(4字节)。其中LWSW是字访存指令,所有的存储器访问都通过这两条指令完成;ADDSUBANDORXOR、是运算指令,他们都在处理器内部完成;J是无条件转移指令。

指令说明

关于汇编指令的说明:

  • rs意味着source register,rd意味着destination register;

  • rt有时(如运算指令)意味着第二个source register,有时(如访存指令)意味着target (source/destination) register;

  • 我们使用 [rs] 表示寄存器rs的内容;

运算指令

(1)加法指令 ADD rd, rs, rt

../_images/add.png

该指令将两个源寄存器内容相加,结果送回目的寄存器的操作。

具体为: [rd] <- [rs] + [rt]

(2)减法指令 SUB rd, rs, rt

../_images/sub.png

该指令将两个源寄存器内容相减,结果送回目的寄存器的操作。

具体为: [rd] <- [rs] - [rt]

(3)与运算指令 AND rd, rs, rt

../_images/and.png

该指令将两个源寄存器内容作按位与,结果送回目的寄存器。

具体为: [rd] <- [rs] & [rt]

(4)或运算指令 OR rd, rs, rt

../_images/or.png

该指令将两个源寄存器内容作按位或,结果送回目的寄存器。

具体为: [rd] <- [rs] | [rt]

(5)异或指令 XOR rd, rs, rt

../_images/xor.png

该指令将两个源寄存器内容作按位异或,结果送回目的寄存器。

具体为: [rd]<-[rs] ^ [rt]

访存指令

(1)存数指令 SW rt, offset(base)

../_images/sw.png

该指令将寄存器 rt的内容存于主存单元中,对应的地址由16位偏移地址 offset经符号拓展加上 base的内容生成。

具体操作为: Mem[[base] + offset] <- [rt]

(2)取数指令 LW rt, offset(base)

../_images/lw.png

该指令将主存单元中的内容存于寄存器 rt,对应的地址由16位偏移地址 offset经符号拓展加上 base内容生成。

具体操作为: [rt] <- Mem[[base] + offset]

转移指令

(1)无条件转移指令 J target

../_images/j.png

该指令改变下一条指令的地址,地址由指令中的26位形式地址instr_index左移2位作为低28位,和NPC(该指令的地址+4)的高4位拼接而成。

具体操作为: PC <- (NPC[31:28]) ## (instr_index << 2)

4.3.2. 接口及控制信号

你设计的指令译码器应该符合这样的接口:

名称

宽度

方向

描述

inst

32

IN

处理器待执行的指令

wen

1

OUT

指令是否写回寄存器

waddr

5

OUT

指令要写回的寄存器(如果wen=0,那么可以输出任意值)

rden1

1

OUT

指令是否要读寄存器1

raddr1

5

OUT

指令要读的寄存器1(如果rden1=0,那么可以输出任意值)

rden2

1

OUT

指令是否要读寄存器2

raddr2

5

OUT

指令要读的寄存器2(如果rden2=0,那么可以输出任意值)

alu_en

1

OUT

指令的结果是否为ALU的输出

alu_card

5

OUT

ALU的操作码(定义见实验2,如果alu_en=0,那么可以输出任意值)

mem_rd

1

OUT

指令是否需要读存储器

mem_wr

1

OUT

指令是否需要写存储器

jmp

1

OUT

指令是否会直接修改PC

invalid

1

OUT

输入的指令无法识别

注意:

  • 对于两个要读的寄存器,无论你以什么样的顺序输出它们,只要输出的是正确的寄存器即可。

  • 尽管“写回r0”的动作是没有意义的,但在本实验中,你还是应该令wen为1,毕竟这是在译码。

  • 如果输入的指令不属于这8种指令,你并不需要专门考虑它们的格式,你只需要将输出的invalid信号置1即可,此时其余输出可以为任意值。

    • 任意现代处理器在指令译码时都会像这样检查输入的指令是否不在合法的指令集中,以引发“指令无效”的异常。

4.4. 实验要求

4.4.1. 实验预习

  • 掌握指令译码器的工作原理,了解实验开发所需的软硬件平台。

  • 掌握8种指令运算操作的意义,完成这8种指令的编码。

4.4.2. 完成实验内容

按照实验内容完成指令译码器的设计与实现,在仿真上板两种环境下通过本实验所提供的自动测试环境,记录运行过程和结果,完成实验报告。

4.5. 自动测试环境

要求使用我们提供的自动测试环境对指令译码器进行测试,包括仿真测试和上板测试两部分。

4.5.1. 使用要求

要求每个同学的指令译码器对外暴露以下接口(信号名称与位数均不可改变):

module inst_decoder(
    input[31:0]     inst,
    output          wen,
    output[4:0]     waddr,
    output          rden1,
    output[4:0]     raddr1,
    output          rden2,
    output[4:0]     raddr2,
    output          alu_en,
    output[4:0]     alu_card,
    output          mem_rd,
    output          mem_wr,
    output          jmp,
    output          invalid
);

// TODO

endmodule

注意:

  • 只允许按照给定的接口格式去设计指令译码器,不允许更改接口格式

  • 实验提供的vivado项目顶层模块soc_top中已经例化了一个名为your_decoderinst_decoder模块(处于缺失状态),在你实现了inst_decoder模块后,将其添加至实验提供的 vivado 项目中即可自动填充your_decoder的空缺。你并不需要关心,更不可以修改项目中的其它模块或IP核,它们是用于测试你的指令译码器的。

  • 你实现的inst_decoder模块必须为组合逻辑,请不要在实现时使用阻塞赋值等用于时序逻辑的写法(当然,输入没有提供时钟信号,你也无法这样做)。

4.5.2. 测试用例

本实验测试所用指令序列如下:

add     r1, r2, r3
sub     r4, r5, r6
j       0x14
movz    r2, r3, r4      // 本实验无法识别
lw      r4, 0x18(r6)
or      r0, r1, r2
xor     r1, r2, r3
sw      r0, 0x18(r3)
and     r1, r1, r1
lw      r9, 0x0(r7)
sll     r1, r1, 2       // 本实验无法识别
add     r2, r3, r31
and     r31, r0, r2
sw      r31, 0x4(r9)

4.5.3. 仿真

在进行仿真时,若你实现的指令译码器功能正确,自动测试环境会在控制台打印 CORRECT ,如图所示:

../_images/console_correct.png

若指令译码器对某条输入的指令译码错误,自动测试环境会在控制台打印错误信息,如图所示:

../_images/console_wrong.png

注意:

  • 当发生错误时,你可以根据控制台上输出的“Detected error at XXX ns”在波形中定位到出错的时间点。

  • 由于打印提示信息的需要,本实验给出的测试环境在仿真时一般会在运行100~300us后自动停止,尽管你的译码器在仿真的第1us内就已经接受了所有测试指令。请确保仿真运行了足够长的时间(例如:仿真时设置运行1ms)。

4.5.4. 上板测试

你实现的指令译码器通过仿真验证后,需要将设计下载到 Artix-7 FPGA 开发板上验证设计正确性。当所实现的指令译码器功能正确时,LCD屏会显示和仿真时的控制台一样的信息,如图:

../_images/result_correct.jpg

当上板发生错误时,LCD屏会显示错误信息,如图:

../_images/result_error.jpg

注意:

  • 尽管上板输出的信息和仿真时的控制台是一样的,但这并不代表仿真成功就一定能够在上板时得到相同的正确结果(尽管这属于小概率事件)。请确保你的verilog代码确实是在描述硬件逻辑,而不是在描述仿真行为。在仿真时,请确保你模块接口及内部信号的波形中不会出现Z或X。

  • 上板前需要对整个项目进行综合(Synthesis)、实现(Implementation)、比特流生成(Generate Bitstream),你可以将它们理解为特殊的“编译”行为。其中综合步骤需要综合项目中所有使用的IP核,这些IP核只需要在最开始时被综合一次,即不需要参与后续的所有综合过程。实验提供的vivado项目中自带的少数IP核在某些特定机器上综合时间较长(可能达20~30min),请务必耐心等待。后续的没有IP核参与的综合-实现-比特流生成过程一般用时4~5min。