实现存储器访问指令和简单IO接口
实验原理
前面实验的整数运算指令,运算数来自寄存器堆或指令代码中的立即数,运算结果也是保存在寄存器堆中。如果需要存储器中的运算数据,或者将运算结果保存到存储器,就需要取数/存数指令。RISC-V有10条访存指令,本实验只实现2条按字存取的lw和sw指令。
实现访存指令的数据通路如图 1。
RISC-V的IO接口采用与主存储器统一编址的方式,因此可以用访存指令进行输入输出操作。通常将主存地址空间中较高或较低的一部分地址空间划作输入输出接口的地址,本实验将0xFFFF800以上的地址空间作为输入输出接口的地址。增加输入输出之后的数据通路如图 2所示。
实验材料中提供了简单输入输出接口的参考设计,输入设备是一组8位的拨动开关,输出设备是一组8位的LED指示灯。LED输出接口的原理如图 3,它的核心是一个寄存器,寄存器的输入数据来自CPU的写数据,寄存器的输出连接到LED指示灯。当CPU送出的数据地址是LED接口的地址时,地址译码器输出使能信号,如果CPU同时也发出了写信号,就会将写数据装入输出寄存器。
输入接口读回开关的状态,32个开关分为4组。此外,LED输出寄存器同时具有输入功能,可以读回写入输出寄存器的值。输入接口根据地址译码从多组输入中选择一组。
表 1给出了输入输出接口的名称和地址。参考设计只实现了开关输入接口A和LED 输出接口A,其余的留作实验任务。
输入输出接口 |
接口地址 |
位宽 |
拨动开关输入接口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:实现访存指令
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