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

实验目的

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

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

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

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

实验原理

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

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

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

RISC-V的IO接口采用与主存储器统一编址的方式,因此可以用访存指令进行输入输出操作。通常将主存地址空间中较高或较低的一部分地址空间划作输入输出接口的地址,本实验将0xFFFFF800以上的地址空间作为输入输出接口的地址。增加输入输出之后的数据通路如图 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模块的内部逻辑,例 1是示例代码。

例 1. CPU内部与数据存储器相关端口的连接
  // Data Memory
  assign oRD = cMemToReg;    (1)
  assign oWR = _____;        (2)
  assign oAB = _____;        (3)
  assign oWriteData = _____; (4)
  assign _____ = iReadData;  (5)
1 连接数据存储器的读使能端口;变量名 cMemToReg 仅为示例。
2 连接数据存储器的写使能端口。
3 连接数据存储器的地址端口。
4 连接数据存储器的写数据端口。
5 连接数据存储器的读数据端口。

3. 增加调试观察信号

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

    //送给调试器的观察信号,需要与虚拟面板的信号框相对应
    struct packed{
        logic [3:0] WS5;  //ALUop
        logic [4:0] WS4;  //Imm_type
        //以下观察信号用于电路测试,请勿修改!
        logic       WS3;  //ImmToALU
        logic       WS2;  //MemToReg
        logic       WS1;  //MemWrite
        logic       WS0;  //RegWrite
    }ws;

    //送给调试器的观察数据,需要与虚拟面板的数据框相对应
    struct packed{        
        logic [31:0] WD11;  //memReadData
        logic [31:0] WD10;  //aluOut
        logic [31:0] WD9;   //nextPC
        logic [31:0] WD8;   //regReadData2
        logic [4:0]  WD7;   //ra2
        logic [31:0] WD6;   //immData    
        //以下观察数据用于电路测试,请勿修改!
        logic [31:0] WD5;   //regWriteData
        logic [4:0]  WD4;   //wa
        logic [31:0] WD3;   //regReadData1
        logic [4:0]  WD2;   //ra1
        logic [31:0] WD1;   //instruction
        logic [31:0] WD0;   //pc
    }wd;

4. 在实验平台验证设计

例 2是参考测试程序。

例 2. 访存指令的测试程序
	.text
    addi x3, x0, 0x100 (1)
    slli x3, x3, 20    (2)
    lw   x18, 8(x3)    (3)
    xori x19, x18, -1  (4)
    sw   x19, 12(x3)   (5)

数据存储器的基地址为10000000H,因为目前尚未实现lui指令,测试程序中用语句①和②设置基地址。

语句③用lw指令从存储器中读出地址为10000008H的存储单元的数据。运行前需要利用实验平台的功能事先向该单元预设一个非零的32位数据,如5AA55AA5H,操作方法请看教学视频。

语句④将读出的数据按位取反,并通过语句⑤的sw指令将取反后的数据写入地址为1000000CH的存储单元。sw指令执行后,实验平台的数据存储器窗口的内容不会主动变化,需要手动进行刷新,以检查写入数据是否正确,具体操作方法可观看教学视频。

数据存储器硬件的地址自0起,程序中的地址10000000H对应数据存储器的硬件地址0。实验平台中界面显示的数据存储器地址与硬件地址对应,因为实验设计的数据存储器容量有限,一般不太可能超过64K,所以实验平台界面只显示地址的低16位。

任务2:扩充数码管接口

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

例 3是用于验证开关和指示灯接口的测试程序,修改该程序,增加对数码管接口的测试,在实验平台上运行,验证IO接口的设计。

例 3. 开关、指示灯接口的测试程序
	.text
    addi s0, x0, -2048 (1)
    lw   s2, 0x00(s0)  (2)
	sw   s2, 0x10(s0)  (3)
	lw   s3, 0x10(s0)  (4)
1 IO基地址0xFFFFF800
2 读开关输入接口
3 写LED输出寄存器
4 读LED输出寄存器