CPU设计实战-汪文祥 邢金璋
第5章 实践任务一
实验环境 lab6.zip
文章目录
- 前言
- 一、实验内容
前言
在lab5的实验环境下,添加算术逻辑运算类指令,乘除运算类指令,以及乘数法配套的数据搬运指令。
一、实验内容
添加算术逻辑运算类指令:
1.1 ADD、ADDI、SUB
/*ID_stage增加代码*/
wire inst_add;
wire inst_addi;
wire inst_sub;
assign inst_add = op_d[6'h00] & func_d[6'h20] & sa_d[5'h00];
assign inst_addi = op_d[6'h08];
assign inst_sub = op_d[6'h00] & func_d[6'h22] & sa_d[5'h00];
/*ID_stage修改代码*/
assign alu_op[ 0] = inst_addu | inst_addiu | inst_lw | inst_sw | inst_jal | inst_add | inst_addi;
assign alu_op[ 1] = inst_subu | inst_sub;
assign src2_is_imm = inst_addiu | inst_lui | inst_lw | inst_sw | inst_addi;
assign dst_is_rt = inst_addiu | inst_lui | inst_lw | inst_addi;
assign src2_no_rt = inst_addiu | load_op | inst_jal | inst_lui | inst_addi;
1.2 SLTI、SLTIU
/*ID_stage增加代码*/
wire inst_slti;
wire inst_sltiu;
assign inst_slti = op_d[6'h0a];
assign inst_sltiu = op_d[6'h0b];
/*ID_stage修改代码*/
assign alu_op[ 2] = inst_slt | inst_slti;
assign alu_op[ 3] = inst_sltu | inst_sltiu;
assign src2_is_imm = inst_addiu | inst_lui | inst_lw | inst_sw | inst_addi | inst_slti | inst_sltiu;
assign dst_is_rt = inst_addiu | inst_lui | inst_lw | inst_addi | inst_slti | inst_sltiu;
assign src2_no_rt = inst_addiu | load_op | inst_jal | inst_lui | inst_addi | inst_slti | inst_sltiu;
1.3 ANDI、ORI、XORI
/*ID_stage增加代码*/
wire inst_andi;
wire inst_ori;
wire inst_xori;
assign inst_andi = op_d[6'h0c];
assign inst_ori = op_d[6'h0d];
assign inst_xori = op_d[6'h0e];
wire src2_is_imm_zero;
wire src2_is_imm_sign;
assign src2_is_imm_zero = inst_andi | inst_ori | inst_xori | inst_lui;
assign src2_is_imm_sign = inst_addiu | inst_lw | inst_sw | inst_addi
| inst_slti | inst_sltiu;
/*ID_stage修改代码*/
wire [ 1:0] src2_is_imm;
assign alu_op[ 4] = inst_and | inst_andi;
assign alu_op[ 6] = inst_or | inst_ori;
assign alu_op[ 7] = inst_xor | inst_xori;
assign src2_is_imm = src2_is_imm_zero ? 2'b01 :
src2_is_imm_sign ? 2'b10 : 2'b00;
assign dst_is_rt = inst_addiu | inst_lui | inst_lw | inst_addi | inst_slti | inst_sltiu | inst_andi | inst_ori | inst_xori;
assign src2_no_rt = inst_addiu | load_op | inst_jal | inst_lui | inst_addi | inst_slti | inst_sltiu | inst_andi | inst_ori | inst_xori;
/*EXE_stage修改代码*/
wire [ 1:0] es_src2_is_imm;
assign es_alu_src2 = es_src2_is_imm == 2'b10 ? {{16{es_imm[15]}}, es_imm[15:0]} :
es_src2_is_imm == 2'b01 ? {16'd0, es_imm[15:0]} :
es_src2_is_8 ? 32'd8 :
es_rt_value;
/*mycpu.h修改代码*/
`define DS_TO_ES_BUS_WD 137
1.4 SLLV、SRLV、SRAV
/*ID_stage增加代码*/
wire inst_sllv;
wire inst_srav;
wire inst_srlv;
assign inst_sllv = op_d[6'h00] & func_d[6'h04] & sa_d[5'h00];
assign inst_srav = op_d[6'h00] & func_d[6'h07] & sa_d[5'h00];
assign inst_srlv = op_d[6'h00] & func_d[6'h06] & sa_d[5'h00];
/*ID_stage修改代码*/
assign alu_op[ 8] = inst_sll | inst_sllv;
assign alu_op[ 9] = inst_srl | inst_srlv;
assign alu_op[10] = inst_sra | inst_srav;
添加乘除法运算类指令以及乘除法配套的数据搬运指令:
/*ID_stage增加代码*/
wire inst_mult;
wire inst_multu;
wire inst_div;
wire inst_divu;
wire inst_mfhi;
wire inst_mflo;
wire inst_mthi;
wire inst_mtlo;
assign inst_mult = op_d[6'h00] & func_d[6'h18] & rd_d[5'h00] & sa_d[5'h00];
assign inst_multu = op_d[6'h00] & func_d[6'h19] & rd_d[5'h00] & sa_d[5'h00];
assign inst_div = op_d[6'h00] & func_d[6'h1a] & rd_d[5'h00] & sa_d[5'h00];
assign inst_divu = op_d[6'h00] & func_d[6'h1b] & rd_d[5'h00] & sa_d[5'h00];
assign inst_mfhi = op_d[6'h00] & func_d[6'h10] & rs_d[5'h00] & rt_d[5'h00] & sa_d[5'h00];
assign inst_mflo = op_d[6'h00] & func_d[6'h12] & rs_d[5'h00] & rt_d[5'h00] & sa_d[5'h00];
assign inst_mthi = op_d[6'h00] & func_d[6'h11] & rt_d[5'h00] & rd_d[5'h00] & sa_d[5'h00];
assign inst_mtlo = op_d[6'h00] & func_d[6'h13] & rt_d[5'h00] & rd_d[5'h00] & sa_d[5'h00];
wire [ 3:0] mult_div;
wire [ 3:0] mf_mt;
assign mult_div = {inst_divu, inst_div, inst_multu, inst_mult};
assign mf_mt = {inst_mthi, inst_mtlo, inst_mfhi, inst_mflo};
/*ID_stage修改代码*/
assign ds_to_es_bus = {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
};
/*EXE_stage增加代码*/
wire [ 3:0] mult_div;
wire [ 3:0] mf_mt;
/*EXE_stage修改代码*/
assign {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;
/*mycpu.h修改代码*/
`define DS_TO_ES_BUS_WD 145
乘法部件:
/*乘法部件*/
wire [31:0] operater1_mult;
wire [31:0] operater2_mult;
wire [63:0] mult_temp;
reg [63:0] mult_result;
assign operater1_mult = ((mult_div[0] == 1'b1) && (es_alu_src1[31] == 1'b1)) ?
(~es_alu_src1 + 1) : es_alu_src1;
assign operater2_mult = ((mult_div[0] == 1'b1) && (es_alu_src2[31] == 1'b1)) ?
(~es_alu_src2 + 1) : es_alu_src2;
assign mult_temp = operater1_mult * operater2_mult;
always @ (*) begin
if(reset) begin
mult_result <= 64'd0;
end
else if(mult_div[0] == 1'b1) begin
if(es_alu_src1[31] ^ es_alu_src2[31] == 1'b1) begin
mult_result <= ~mult_temp + 1;
end
else begin
mult_result <= mult_temp;
end
end
else begin
mult_result <= mult_temp;
end
end
/*--------*/
除法部件:
/*除法部件*/
wire [63:0] div_result_i;
wire div_ready_i;
wire div_start_o;
wire signed_div_o;
assign div_start_o = ((mult_div[3:2] != 2'b00) && div_ready_i == 1'b0) ? 1'b1 : 1'b0;
assign signed_div_o = (mult_div[2] == 1'b1) ? 1'b1 :
(mult_div[3] == 1'b1) ? 1'b0 : 1'b0;
div SIGN_DIV (
.clk(clk),
.rst(~reset),
.signed_div_i(signed_div_o),
.opdata1_i(es_alu_src1),
.opdata2_i(es_alu_src2),
.start_i(div_start_o),
.annul_i(1'b0),
.result_o(div_result_i),
.ready_o(div_ready_i)
);
/*--------*/
5.LO/HI寄存器:
/*LO/HI寄存器*/
reg [31:0] hi;
reg [31:0] lo;
always @ (posedge clk) begin
if(mult_div != 4'b0000 | mf_mt[2] == 1'b1) begin
if(mult_div[1:0] != 2'b00) lo <= mult_result[31: 0];
else if(mult_div[3:2] != 2'b00) lo <= div_result_i[31: 0];
else if(mf_mt[2]) lo <= es_alu_src1;
end
if(mult_div != 4'b0000 | mf_mt[3] == 1'b1) begin
if(mult_div[1:0] != 2'b00) hi <= mult_result[63:32];
else if(mult_div[3:2] != 2'b00) hi <= div_result_i[63:32];
else if(mf_mt[3]) hi <= es_alu_src1;
end
end
/*-----------*/
其他修改细节:
/*EXE_stage增加代码*/
wire [31:0] es_result; //最终写回目的寄存器的值
assign es_result = mf_mt[0] == 1'b1 ? lo :
mf_mt[1] == 1'b1 ? hi : es_alu_result;
/*EXE_stage修改代码*/
assign EXE_result = es_result; //参与前递的数据也不再是alu计算的值了
assign es_to_ms_bus = {es_res_from_mem, //70:70
es_gr_we , //69:69
es_dest , //68:64
es_result , //63:32
es_pc //31:0
};
//由于是迭代除法,必须等除法完成
assign es_ready_go = es_valid & (mult_div[3:2] == 2'b00 | div_ready_i);
迭代除法div.v模块:
module div(
input wire clk,
input wire rst,
input wire signed_div_i,
input wire[31:0] opdata1_i,
input wire[31:0] opdata2_i,
input wire start_i,
input wire annul_i,
output reg[63:0] result_o,
output reg ready_o
);
wire[32:0] div_temp;
reg[5:0] cnt;
reg[64:0] dividend;
reg[1:0] state;
reg[31:0] divisor;
reg[31:0] temp_op1;
reg[31:0] temp_op2;
assign div_temp = {1'b0, dividend[63:32]} - {1'b0, divisor};
always @ (*) begin
if(signed_div_i == 1'b1 && opdata1_i[31] == 1'b1) begin
temp_op1 <= ~opdata1_i + 1;
end else begin
temp_op1 <= opdata1_i;
end
if(signed_div_i == 1'b1 && opdata2_i[31] == 1'b1) begin
temp_op2 <= ~opdata2_i + 1;
end else begin
temp_op2 <= opdata2_i;
end
end
always @ (posedge clk) begin
if (rst == 1'b0) begin
state <= 2'b00;
ready_o <= 1'b0;
result_o <= {32'h00000000, 32'h00000000};
end else begin
case (state)
2'b00: begin
if(start_i == 1'b1 && annul_i == 1'b0) begin
if(opdata2_i == 32'h00000000) begin
state <= 2'b01;
end else begin
state <= 2'b10;
cnt <= 6'b000000;
dividend <= {32'h00000000, 32'h00000000};
dividend[32:1] <= temp_op1;
divisor <= temp_op2;
end
end else begin
ready_o <= 1'b0;
result_o <= {32'h00000000, 32'h00000000};
end
end
2'b01: begin
dividend <= {32'h00000000, 32'h00000000};
state <= 2'b11;
end
2'b10: begin
if (annul_i == 1'b0) begin
if(cnt != 6'b100000) begin
if(div_temp[32] == 1'b1) begin
dividend <= {dividend[63:0], 1'b0};
end else begin
dividend <= {div_temp[31:0], dividend[31:0], 1'b1};
end
cnt <= cnt + 1;
end else begin
if((signed_div_i == 1'b1)
&& ((opdata1_i[31] ^ opdata2_i[31]) == 1'b1)) begin
dividend[31:0] <= (~dividend[31:0] + 1);
end
if((signed_div_i == 1'b1)
&& ((opdata1_i[31] ^ dividend[64]) == 1'b1)) begin
dividend[64:33] <= (~dividend[64:33] + 1);
end
state <= 2'b11;
cnt <= 6'b000000;
end
end else begin
state <= 2'b00;
end
end
2'b11: begin
result_o <= {dividend[64:33], dividend[31:0]};
ready_o <= 1'b1;
if (start_i == 1'b0) begin
state <= 2'b00;
ready_o <= 1'b0;
result_o <= {32'h00000000, 32'h00000000};
end
end
endcase
end
end
endmodule