天天看点

CPU设计实战 第5章 实践任务前言一、实验内容

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