RISC-V 访存级
RISCV MEM Stage 设计
Data Memory(DM)
DM 采用 DTCM,其访问的数据类型必须按照对应的地址对齐,否则就是 misaligned data address。例如 LW,SW,其地址最低两位必须是 00.
输入端口
Port Name Source Description addr[DMEMLEN:0] aluResult dMemory 输入地址 dMemInput[31:0] DMIC 寄存器 rs2 读出的数据 dMemWrEn EXE/MEM pipeline dMemory 写入使能 byteMask[3:0] DMIC dMemory byteMask mvalid DMIC DMIC 输入数据有效 mready DMOC DMOC 空闲,可以输出数据 输出端口
Port Name Target Description dMemOutput[31:0] DMOC 输出到 WB stage 的 Mux svalid DMOC MEM 数据有效 sready DMIC MEM 空闲,可以进行读写操作
Data Memory Input Control(DMIC)
根据指令的格式,生成输入到 Data Memory 的 32bits 数据
输入端口
Port Name Source Description dMemType[3:0] EXE/MEM pipeline 访存指令的格式 RD2[31:0] EXE/MEM pipeline 寄存器 rs2 读出的数据 aluResult[31:0] EXE ALU alu 计算得到的 dMemory 地址| ready DM Dta Memory 空闲 byte_addr=aluResult[1:0]
输出端口
Port Name Target description dMemInput[31:0] DM 根据 dmemtype 生成的 32bitsdata,输出到 DM byteMask[3:0] DM dMemory write byteMask byteMask=aluResult[1:0]
dMemType byte_addr dMemInput MEM_LB 00
01
10
11dMemInput={24{1'b0},RD2[7:0]}
dMemInput={16{1'b0},RD2[15:8],8{1'b0}}
dMemInput={8{1'b0},RD2[23:16],16{1'b0}}
dMemInput={RD2[31:24], 24{1'b0}}
MEM_LH 00
10dMemInput={16{1'b0},RD2[15:0]}
dMemInput={RD2[31:16], 16{1'b0}}
MEM_LW dMemInput=RD2[31:0]
Data Memory Output Control(DMOC)
接收 DM 的输出数据,并且根据指令格式产生对应的数据,输入给 WB Stage
输入端口
Port Name Source Description dMemType[3:0] EXE/MEM pipeline 访存指令的格式 dMemOutput[31:0] DM 从 DM 中读入的 32bits 数据 aluResult[31:0] EXE ALU alu 计算得到的 dMemory 地址| 输出端口
Port Name Target Description dMemReadData[31:0] WB stage 根据 dMemType 选择 DM 输入的数据,生成 32bits 的读出数据 dMemType byte_addr dMemReadData MEM_LB 00
01
10
11dMemReadData={24{dMemOutput[7]}, dMemOutput[7:0]}
dMemReadData={24{dMemOutput[15]}, dMemOutput[15:8]}
dMemReadData={24{dMemOutput[23]}, dMemOutput[23:16]}
dMemReadData={24{dMemOutput[31]}, dMemOutput[31:24]}
MEM_LH 00
10dMemReadData={16{dMemOutput[15]}, dMemOutput[15:0]}
dMemReadData={16{dMemOutput[31]}, dMemOutput[31:16]}
MEM_LW dMemReadData=dMemOutput[31:0]
MEM_LBU 00
01
10
11dMemReadData={24{1'b0}, dMemOutput[7:0]}
dMemReadData={24{1'b0}, dMemOutput[15:8]}
dMemReadData={24{1'b0}, dMemOutput[23:16]}
dMemReadData={24{1'b0}, dMemOutput[31:24]}
MEM_LHU 00
10dMemReadData={16{1b'0}, dMemOutput[15:0]}
dMemReadData={16{1'b0}, dMemOutput[31:16]}
MEM 和 EXE 需要 resetn 信号,否则系统 reset 之后,MEM Stage 输出的
reg_wb_en
会是 x,传输给 ID Stage 之后,会导致第一次读取 RF 时读出的也是 x
访存级 Load/Store 指令设计
信号定义
输入到 D-Memory 的信号
信号 描述 dmem_addr[31:0] D-Memory 访存地址 dmem_write_data[31:0] D-Memory 写入的数据 dmem_write_mask[3:0] D-Memory 写入时的掩码 dmem_rw 读写选择,0:读,1:写 valid/ready 握手信号
如果指令不需要访问 D-Memory,可以令 RW=1, dmem_write_mask=0000
Q: D-Memory 是否需要 reset 信号?有一些项目里有这个信号、有些项目里没有
来自 D-Memory 的信号
- dmem_read_data[31:0]: data read from D-Memory, this data may need be future modified
- valid/ready: valid when memory is ready to get address and contorl, ready when memory response data is ready
- error: memory access error
信号 描述 dmem_read_data[31:0] D-Memory 读出的数据 valid/ready 握手信号 error 访存失败时的反馈信号
访存失败的时候,需要告知 EXE Stage 的 CSR 进入访存失败的异常处理程序
由于当前设计的 D-Memory 只是 MEM Stage 的一块内存,因此 valid, ready, error 信号都没有启用
来自 EXE Stage 的流水线输入
信号 描述 rs1_e_i[31:0] D-Memory 的写入数据(wire) dmem_type_e_i[3:0] D-Memory 的访存类型(wire) alu_result_e_i[31:0] ALU 计算的结果(wire) extended_imm_e_i[31:0] 拓展为 32bits 的立即数部分,LUI 指令的写回数据 pc_plus_e_i[31:0] next pc 的数据,JAL, JALR 指令的写回数据 result_src_e_i[1:0] 寄存器写回数据来源选择信号 rd_idx_e_i[4:0] 被写回的寄存器的下标 reg_write_en_e_i 寄存器写回使能 由于 D-Memory 访存有一个 cycle 延迟,所以 alu_result_e_i, dmem_type_e_i 都是 wire 类型
到 WB stage 的流水线输出
信号 描述 alu_result_m_o[31:0] ALU 计算的结果(wire), alu_result_e_i 寄存 2 拍的结果 extended_imm_m_o[31:0] 拓展为 32bits 的立即数部分,LUI 指令的写回数据 pc_plus_m_o[31:0] next pc 的数据,JAL, JALR 指令的写回数据 🌟mem_read_data_m_o[31:0] 从 D-Memory 中读出的数据,Load 指令的写回数据 result_src_m_o[1:0] 寄存器写回数据来源选择信号 rd_idx_m_o[4:0] 被写回的寄存器的下标 reg_write_en_m_o 寄存器写回使能 alu_result_e_i 作为写回数据的时候,需要多暂存一拍以跟其他写回信号同步
访存逻辑
本部分主要介绍 Load/Store 指令在 MEM Stage 具体的实现逻辑。
由于 CSR 模块放到 MEM Stage 会导致流水线刷新逻辑涉及到更多一个 Stage,导致刷新逻辑变得复杂, 因此考虑将 CSR 模块放到 EXE Stage,并且在 EXE Stage 对访存指令地址不对齐的情况触发 exception
- LB, LBU, SB 指令由于其操作的是 1B 的数据,因此不会出现 address misaligned exception
- LH, LHU, SH 指令,
addr[0]!=0
时,会出现 address misaligned exception - LW, SW 指令,
addr[1:0]!=00
时,会出现 address misaligned exception
Load 指令
涉及到的指令:
LB, LBU, LH, LHU, LW
D-Memory 写入地址:dmem_addr = alu_result_e_i;
读写类型:dmem_rw = 1'b0;
从 D-Memory 读出的数据
dmem_read_data
跟输出到 WB Stage 数据mem_read_data_m_o
的关系根据 Load 指令的类型及访存地址最后两位的地址,扩展 D-Memory 的输出数据,如下表所示:
mem_read_data_m_o mem_type addr[1:0] {{24{dmem_read_data[7]}}, dmem_read_data[7:0]}
MEM_LB 00 {{24{dmem_read_data[15]}},dmem_read_data[15:8]}
MEM_LB 01 {{24{dmem_read_data[23]}},dmem_read_data[23:16]}
MEM_LB 10 {{24{dmem_read_data[31]}},dmem_read_data[31:24]}
MEM_LB 11 {{24{1'b0} ,dmem_read_data[7:0]}` | MEM_LBU | 00 | | `{{24{1'b0} ,dmem_read_data[15:8]}` | MEM_LBU | 01 | | `{{24{1'b0} ,dmem_read_data[23:16]}` | MEM_LBU | 10 | | `{{24{1'b0} ,dmem_read_data[31:24]}` | MEM_LBU | 11 | | `{{16{dmem_read_data[15]}}, dmem_read_data[15: 0]}
MEM_LH 00 {{16{dmem_read_data[31]}}, dmem_read_data[31:16]}
MEM_LH 10 {{16{1'b0}, dmem_read_data[15:0]}` | MEM_LHU | 00 | | `{{16{1'b0}, dmem_read_data[31:16]}` | MEM_LHU | 10 | | dmem_read_data | MEM_LW | 00 | #### Store 指令 1. 涉及到的指令:`SB, SH, SW` 2. D-Memory 写入地址:dmem_addr = alu_result_e_i; 3. 读写类型:dmem_rw = 1'b1; 4. 写入掩码: dmem_write_mask > 写入掩码主要根据 Load 指令类型和访存地址,来控制写入到 D-Memory 的哪些 byte。 > D-Memory 需要支持掩码操作。 | dmem_write_mask | mem_type | addr[1:0] | | --------------- | --------------- | --------- | | 0001 | MEM_SB, MEM_SBU | 00 | | 0010 | MEM_SB, MEM_SBU | 01 | | 0100 | MEM_SB, MEM_SBU | 10 | | 1000 | MEM_SB, MEM_SBU | 11 | | 0011 | MEM_SH, MEM_SHU | 0x | | 1100 | MEM_SH, MEM_SHU | 1x | | 1111 | MEM_SW | xx | 5. 写入到 D-Memory 的数据:dmem_write_data `dmem_write_data[31:0]`是写入到 D-Memory 中的数据, `rs1_e_i` 是 EXE Stage 输入的代写入到 D-Memory 的数据 | dmem_write_data | mem_type | addr[1:0] | | --------------------------------------- | -------- | --------- | | `{{24{1'b0}}, rs1_e_i[7:0]}
MEM_SB 00 {{16{1'b0}}, rs1_e_i[7:0], {8{1'b0}}}
MEM_SB 01 {{8{1'b0}}, rs1_e_i[7:0], {16{1'b0}}}
MEM_SB 10 {rs1_e_i[7:0], {24{1'b0}}}
MEM_SB 11 {{16{1'b0}}, rs1_e_i[15:0]}
MEM_SH 0x {rs1_e_i[15:0], {16{1'b0}}}
MEM_SH 1x rs1_e_i MEM_SW xx
非访存指令
- 读写类型:dmem_rw = 1'b1;
- 写入掩码: dmem_write_mask=4'b0000;
测试的情况有:
- LW, SW: 4B 对齐时写入和读出
- SH, LH, LHU: 2B 对齐时写入、读出
- SB, LB, LBU: 1B 对齐时写入、读出