实现存储器访问指令和简单IO接口

实验目的

(1)理解load和store访存指令的功能;

(2)进一步理解数据通路与指令功能的关联;

(3)理解存储器和输入输出接口的统一编址及地址译码;

(4)掌握简单IO接口的设计方法。

实验原理

前面实验的整数运算指令,运算数来自寄存器堆或指令代码中的立即数,运算结果也是保存在寄存器堆中。如果需要存储器中的运算数据,或者将运算结果保存到存储器,就需要取数/存数指令。RISC-V有10条访存指令,本实验只实现2条按字存取的lw和sw指令。

实现访存指令的数据通路如图 1

SingleCycleRISCV_07_SC4_300dpi
图 1. 访存指令的数据通路

RISC-V的IO接口采用与主存储器统一编址的方式,因此可以用访存指令进行输入输出操作。通常将主存地址空间中较高或较低的一部分地址空间划作输入输出接口的地址,本实验将0xFFFF800以上的地址空间作为输入输出接口的地址。增加输入输出之后的数据通路如图 2所示。

包含输入输出接口的数据通路
图 2. 包含输入输出接口的数据通路

实验材料中提供了简单输入输出接口的参考设计,输入设备是一组8位的拨动开关,输出设备是一组8位的LED指示灯。LED输出接口的原理如图 3,它的核心是一个寄存器,寄存器的输入数据来自CPU的写数据,寄存器的输出连接到LED指示灯。当CPU送出的数据地址是LED接口的地址时,地址译码器输出使能信号,如果CPU同时也发出了写信号,就会将写数据装入输出寄存器。

LED输出接口的原理图
图 3. LED输出接口的原理图

输入接口读回开关的状态,32个开关分为4组。此外,LED输出寄存器同时具有输入功能,可以读回写入输出寄存器的值。输入接口根据地址译码从多组输入中选择一组。

表 1给出了输入输出接口的名称和地址。参考设计只实现了开关输入接口A和LED 输出接口A,其余的留作实验任务。

表 1. 输入输出接口地址

输入输出接口

接口地址

位宽

拨动开关输入接口A

FFFFF800H

8位

拨动开关输入接口B

FFFFF804H

8位

拨动开关输入接口C

FFFFF808H

8位

拨动开关输入接口D

FFFFF80CH

8位

LED输出寄存器A

FFFFF810H

8位

LED输出寄存器B

FFFFF814H

8位

LED输出寄存器C

FFFFF818H

8位

LED输出寄存器D

FFFFF81CH

8位

数码管输出寄存器

FFFFF820H

32位

任务1:实现访存指令

1. 设计控制逻辑

修改Controller模块,增加load和store指令译码,产生MemWrite、MemToReg以及立即数类型等控制信号。

2. 实现数据通路

(1)SoC模块

前面存储器实验已经学习过RAM的描述,这里用它作为数据存储器;实验材料中的SoC模块实例化了数据存储器模块,并且连到了CPU模块的端口。

(2)ImmGen模块

增加S型立即数的生成。

(4)CPU模块

根据图 1数据通路连接各个部件,其中数据存储器在CPU外部,需要将端口上的相关信号连接到CPU模块的内部逻辑,下面是示例代码,自己代码中的变量名可能不同。

   wire [31:0] memReadData;
   assign oRD = cMemToReg;   //控制信号MemToReg连接到读使能端口
   assign oWR = cMemWrite;   //控制信号MemWrite连接到写使能端口
   assign oAB = aluOut;      //ALU的输出连接到数据存储器的地址端口
   assign oWriteData = regReadData2; //寄存器堆的RD2连接到写数据端口
   assign memReadData = iReadData;   //读数据端口连接到内部变量memReadData

3. 增加调试观察信号

根据虚拟面板添加观察信号和观察数据,对应关系如下示例。

    always_comb begin
        ws.WS5[3:0] = cALUop;
        ws.WS4[4:0] = cImm_type;
        ws.WS3      = cImmToALU;
        ws.WS2      = cMemWrite;
        ws.WS1      = cMemToReg;
        ws.WS0      = cRegWrite;
    end

    always_comb begin
        wd.WD11[31:0] = memReadData;
        wd.WD10[31:0] = aluOut;
        wd.WD9 [31:0] = immData;
        wd.WD8 [31:0] = regReadData2;
        wd.WD7 [31:0] = regReadData1;
        wd.WD6 [4:0]  = ra2;
        wd.WD5 [4:0]  = ra1;
        wd.WD4 [31:0] = regWriteData;
        wd.WD3 [4:0]  = wa;
        wd.WD2 [31:0] = instruction;
        wd.WD1 [31:0] = pc;
        wd.WD0 [31:0] = nextPC;
    end

4. 在实验平台验证设计

编写程序测试sw和lw指令。可以利用实验平台的功能独立验证lw和sw指令。如sw指令执行后,通过实验平台检查写入数据是否正确;【提示】实验平台的数据存储器窗口的内容不会主动变化,需要手动进行刷新操作。验证lw指令时,可以利用实验平台事先向某一存储单元写入已知的数据,再执行lw指令。

任务2:扩充数码管接口

理解参考设计,设计数码管输出接口。可同时输出32位二进制数在8个数码管上显示,显示内容只能是十六进制数,不带小数点;显示数据可读回。

在实验平台上验证设计,参考测试程序如下。

    addi s0, x0, -2048
    addi s1, x0, 0x100
    slli s1, s1, 20
    addi s3, x0, -1
    sw   s3, 0x20(s0)
    lw   s2, 0x00(s0)
    sw   s2, 8(s1)
    sw   s2, 0x10(s0)
    lw   s3, 8(s1)
    sw   s3, 0x20(s0)
    lw   s2, 0x20(s0)