访存指令的添加
一.加载指令
首先我们先对LB、LBU、LH、LHU、LWL、LWR指令的功能进行分析。
LB
LBU
LH
LHU
LWL
LWR
LB、LBU、LH、LHU与LW指令的差异在于从内存取回的数据位宽不同,因为数据RAM的位宽是32位的,所以这些指令访问数据RAM的地址都是用指令访存地址(data_sram_addr)去掉最低两位得到的,这四条指令在译码、执行、回写阶段的数据通路、控件逻辑可以复用LW指令的设计实现。除此之外,需要从数据RAM返回值中选取需要的内容以及将内容扩展至32位的数据通路都是要增加的,这里我们将此数据通路增加到访存阶段,数据通路的具体细节如下:
1. 从数据RAM输出结果中选取所需内容
既然数据RAM的宽度是4个字节,那么LB和LBU访问的内容可以出现在这四个字节的任一个中,LH和LHU访问的内容可以是其中的低2字节或是高2字节。也就是说,这些指令需要的数据并不总出现在数据 RAM输出数据的最低位置上。因此,我们需要引入一个多路选择器。这个选择器的选择信号是通过指令访存地址的最低两位以及访存操作的类型信息共同生成的。访存操作的类型信息是没有从译码级或执行级传递到访存级的,需要在数据通路中予以添加。
2. 将选取内容扩展至32位
LB、LBU、LH和LHU指令从数据RAM取回的数据宽度比通用寄存器的宽度要小,所以这些数据需要扩展到32位才能成为最终写入寄存器的结果。进行有符号扩展还是无符号扩展是根据指令来确定的,LB、LH是有符号扩展,LBU、LHU是无符号扩展。这里还要特别注意,由于从数据RAM输出结果中选取的内容不固定,所以进行有符号扩展时符号位也要通过访存地址的最低两位来决定。
对于非对齐加载指令LWL、LWR,需要根据访存地址最低两位的情况用从数据RAM取出的字内容的一部分与rt号寄存器的一部分原值拼接后更新rt号目的寄存器的值。其数据通路的实现方式是读取rt号目的寄存器的旧值,与待写入的新值拼接为32位的最终结果,作为写入目的寄存器的最终结果。由于rt号寄存器的值没有传递到访存阶段,所以也要添加新的数据通路。
二.存储指令的添加
共添加4条加载指令,分别为SB、SH、SWL、SWR,指令格式及功能分析如下:
SB
SH
SWL
SWR
存储指令与上述加载指令的实现机制类似,这里就不再分析其具体的数据通路实现了。对各个模块增加以及修改的数据通路代码如下。
ID_stage.v
wire [11:0] mem_control;//用于标志12条访存指令的具体类型
wire inst_lb;
wire inst_lbu;
wire inst_lh;
wire inst_lhu;
wire inst_sb;
wire inst_sh;
wire inst_lwl;
wire inst_lwr;
wire inst_swl;
wire inst_swr;
assign inst_lb = op_d[6'h20];
assign inst_lbu = op_d[6'h24];
assign inst_lh = op_d[6'h21];
assign inst_lhu = op_d[6'h25];
assign inst_sb = op_d[6'h28];
assign inst_sh = op_d[6'h29];
assign inst_lwl = op_d[6'h22];
assign inst_lwr = op_d[6'h26];
assign inst_swl = op_d[6'h2a];
assign inst_swr = op_d[6'h2e];
assign mem_control = {inst_swr,inst_swl,inst_sh,inst_sb,inst_lwr,inst_lwl,
inst_lhu,inst_lh,inst_lbu,inst_lb,inst_sw,inst_lw};
//需要进行修改的数据通路
assign load_op = inst_lw | inst_lb | inst_lbu | inst_lh | inst_lhu | inst_lwl | inst_lwr;
assign ds_to_es_bus = {
mem_control , //156:145
mf_mt , //144:141
mult_div , //140:137
alu_op , //136:125
load_op , //124:124
src1_is_sa , //123:123
src1_is_pc , //122:122
src2_is_imm , //121:120
src2_is_8 , //119:119
gr_we , //118:118
mem_we , //117:117
dest , //116:112
imm , //111:96
rs_value , //95 :64
rt_value , //63 :32
ds_pc //31 :0
};
assign alu_op[ 0] = inst_addu | inst_addiu | inst_lw | inst_sw | inst_jal |
inst_add | inst_addi|inst_bltzal | inst_bgezal |
inst_jalr | inst_lb | inst_lbu | inst_lh | inst_lhu |
inst_sb | inst_sh | inst_lwr | inst_lwl | inst_swl |
inst_swr;
assign src2_is_imm_sign = inst_addi | inst_addiu | inst_lw | inst_sw |
inst_slti | inst_sltiu | inst_lb | inst_lbu |
inst_lh | inst_lhu |inst_sb | inst_sh | inst_lwl |
inst_lwr | inst_swl | inst_swr;
assign inst_no_dest = inst_beq | inst_bne | inst_jr | inst_sw | inst_bgez |
inst_bgtz | inst_blez | inst_bltz | inst_j | inst_sb |
inst_sh | inst_swl | inst_swr ;
assign res_from_mem = inst_lw| inst_lb | inst_lbu | inst_lh |
inst_lhu | inst_lwl | inst_lwr;
assign dst_is_rt = inst_addiu | inst_lui | inst_lw | inst_addi |
inst_slti | inst_sltiu | inst_andi | inst_ori |
inst_xori | inst_lb | inst_lbu | inst_lh |
inst_lhu | inst_lwl | inst_lwr;
assign gr_we = ~inst_sw & ~inst_beq & ~inst_bne & ~inst_jr &
~inst_j & ~inst_mthi & ~inst_mtlo & ~inst_mult &
~inst_multu & ~inst_div & ~inst_divu & ~inst_bgez &
~inst_bgtz & ~inst_blez & ~inst_bltz & ~inst_swl &
~inst_swr & ~inst_sb & ~inst_sh;//不需要在回写阶段将结果写回到寄存器堆的指令
assign mem_we = inst_sw | inst_swl | inst_swr | inst_sb | inst_sh;
EXE_stage.v
wire [11:0] es_mem_control;
wire [31:0] write_sram_data;//写数据RAM的值
wire [3:0] sram_wen;//数据RAM字节使能信号
wire inst_is_swr;
wire inst_is_swl;
wire inst_is_sh;
wire inst_is_sb;
wire inst_is_sw;
assign inst_is_swr = es_mem_control == 12'b100000000000;
assign inst_is_swl = es_mem_control == 12'b010000000000;
assign inst_is_sh = es_mem_control == 12'b001000000000;
assign inst_is_sb = es_mem_control == 12'b000100000000;
assign inst_is_sw = es_mem_control == 12'b000000000010;
assign {
es_mem_control , //156:145
mf_mt , //144:141
mult_div , //140:137
es_alu_op , //136:125
es_load_op , //124:124
es_src1_is_sa , //123:123
es_src1_is_pc , //122:122
es_src2_is_imm , //121:120
es_src2_is_8 , //119:119
es_gr_we , //118:118
es_mem_we , //117:117
es_dest , //116:112
es_imm , //111:96
es_rs_value , //95 :64
es_rt_value , //63 :32
es_pc //31 :0
} = ds_to_es_bus_r;
assign es_to_ms_bus = {
es_rt_value , //114:83
es_mem_control , //82:71
es_res_from_mem, //70:70
es_gr_we , //69:69
es_dest , //68:64
es_result , //63:32
es_pc //31:0
};
assign write_sram_data = inst_is_sb ? (es_alu_result[1:0] == 2'b00 ? {24'd0 , es_rt_value[7:0]}:
es_alu_result[1:0] == 2'b01 ? {16'd0, es_rt_value[7:0] , 8'd0}:
es_alu_result[1:0] == 2'b10 ? {8'd0 , es_rt_value[7:0], 16'd0}:
{es_rt_value[7:0] , 24'd0}
):
inst_is_sh ? (es_alu_result[1:0] == 2'b00 ? {16'd0,es_rt_value[15:0]}:
{es_rt_value[15:0],16'd0}):
inst_is_swl ? (es_alu_result[1:0] == 2'b00 ? {24'd0 , es_rt_value[31:24]}:
es_alu_result[1:0] == 2'b01 ? {16'd0 , es_rt_value[31:16]}:
es_alu_result[1:0] == 2'b10 ? {8'd0 , es_rt_value[31:8] }:
es_rt_value):
inst_is_swr ? (es_alu_result[1:0] == 2'b00 ? es_rt_value :
es_alu_result[1:0] == 2'b01 ? {es_rt_value[23:0] , 8'd0}:
es_alu_result[1:0] == 2'b10 ? {es_rt_value[15:0] , 16'd0}:
{es_rt_value[7:0] , 24'd0}):
es_rt_value;
assign sram_wen = inst_is_sb ? (es_alu_result[1:0] == 2'b00 ? 4'b0001:
es_alu_result[1:0] == 2'b01 ? 4'b0010:
es_alu_result[1:0] == 2'b10 ? 4'b0100:
4'b1000):
inst_is_sh ? (es_alu_result[1:0] == 2'b00 ? 4'b0011:
4'b1100):
inst_is_swl ? (es_alu_result[1:0] == 2'b00 ? 4'b0001:
es_alu_result[1:0] == 2'b01 ? 4'b0011:
es_alu_result[1:0] == 2'b10 ? 4'b0111:
4'b1111):
inst_is_swr ? (es_alu_result[1:0] == 2'b00 ? 4'b1111:
es_alu_result[1:0] == 2'b01 ? 4'b1110:
es_alu_result[1:0] == 2'b10 ? 4'b1100:
4'b1000):
4'b1111;
assign data_sram_wen = es_mem_we&&es_valid ? sram_wen : 4'h0;//写回到数据寄存器
assign data_sram_addr = {es_alu_result[31:2],2'b0};
assign data_sram_wdata = write_sram_data & {32{es_valid}};
MEM_stage.v
wire [11:0] ms_mem_control;
wire [31:0] ms_rt_value;//用于将rt寄存器的数据与访存数据的拼接用
wire [31:0] mem_result_lb;
wire [31:0] mem_result_lbu;
wire [31:0] mem_result_lh;
wire [31:0] mem_result_lhu;
wire [31:0] mem_result_lwr;
wire [31:0] mem_result_lwl;
wire load_sign_lb;
wire load_sign_lh;
assign load_sign_lb = ms_alu_result[1:0] == 2'b00 ? data_sram_rdata[7] :
ms_alu_result[1:0] == 2'b01 ? data_sram_rdata[15]:
ms_alu_result[1:0] == 2'b10 ? data_sram_rdata[23]:
data_sram_rdata[31];
assign mem_result_lb[7:0] = ms_alu_result[1:0] == 2'b00 ? data_sram_rdata[7:0] :
ms_alu_result[1:0] == 2'b01 ? data_sram_rdata[15:8] :
ms_alu_result[1:0] == 2'b10 ? data_sram_rdata[23:16]:
data_sram_rdata[31:24];
assign mem_result_lb[31:8] = {24{load_sign_lb}};
assign mem_result_lbu = {24'd0,mem_result_lb[7:0]};
assign load_sign_lh = ms_alu_result[1:0] == 2'b00 ? data_sram_rdata[15]:
ms_alu_result[1:0] == 2'b10 ? data_sram_rdata[31]:
1'b0;
assign mem_result_lh[15:0] = ms_alu_result[1:0] == 2'b00 ? data_sram_rdata[15:0]:
ms_alu_result[1:0] == 2'b10 ? data_sram_rdata[31:16]:
16'd0;
assign mem_result_lh[31:16] = {16{load_sign_lh}};
assign mem_result_lhu = {16'd0, mem_result_lh[15:0]};
assign mem_result_lwr = ms_alu_result[1:0] == 2'b00 ? data_sram_rdata[31:0] :
ms_alu_result[1:0] == 2'b01 ? {ms_rt_value[31:24],data_sram_rdata[31:8]}:
ms_alu_result[1:0] == 2'b10 ? {ms_rt_value[31:16],data_sram_rdata[31:16]}:
{ms_rt_value[31:8] ,data_sram_rdata[31:24]};
assign mem_result_lwl = ms_alu_result[1:0] == 2'b00 ? {data_sram_rdata[7:0] ,ms_rt_value[23:0]}:
ms_alu_result[1:0] == 2'b01 ? {data_sram_rdata[15:0],ms_rt_value[15:0]}:
ms_alu_result[1:0] == 2'b10 ? {data_sram_rdata[23:0],ms_rt_value[7:0]}:
data_sram_rdata[31:0];
assign mem_result = (ms_mem_control == 12'b000000000100) ? mem_result_lb :
(ms_mem_control == 12'b000000001000) ? mem_result_lbu:
(ms_mem_control == 12'b000000010000) ? mem_result_lh :
(ms_mem_control == 12'b000000100000) ? mem_result_lhu:
(ms_mem_control == 12'b000010000000) ? mem_result_lwr:
(ms_mem_control == 12'b000001000000) ? mem_result_lwl:
data_sram_rdata;
assign {
ms_rt_value , //114:83
ms_mem_control , //82:71
ms_res_from_mem, //70:70
ms_gr_we , //69:69
ms_dest , //68:64
ms_alu_result , //63:32
ms_pc //31:0
} = es_to_ms_bus_r;
mycpu.h
`define DS_TO_ES_BUS_WD 157
`define ES_TO_MS_BUS_WD 115
三.实验结果
测试点全部通过