CPU设计实战(汪文祥)第五章指令添加

踩坑记录

1、忘记修改无目的寄存器的信号

assign inst_no_dest  = inst_bne | inst_beq | inst_jr | inst_sw | inst_mult | inst_multu | 
                    inst_div | inst_divu | inst_mthi | inst_mtlo;
assign dest          = dst_is_r31   ? 5'd31 :
                       dst_is_rt    ? rt    : 
                       inst_no_dest ? 5'd0  : rd;

2、拉入reset信号初始化寄存器HI、LO

3、不同阶段间的bus宽度调整

4、除数、被除数赋值赋反了(愚蠢错误)

5、除法器状态机第一阶段需要考虑signed信号

不止op_div,src_is_signed也要考虑。因为实际上在div信号到来时,有符号除法器和无符号除法器都会收到信号。不区分符号会导致complete信号和div64_result信号的混乱。

op_div & src_is_signed
op_div & ~src_is_signed

6、HI、LO在不同指令下应该存储高32位还是低32位搞错了

代码改动

mycpu.h

    `define ALU_OP          18
    `define DS_TO_ES_BUS_WD 144

ID state

// Chapter5
wire        src2_is_0_imm;
wire        src_is_signed;

// Chapter 5 added insts
/* increase begin*/
wire        inst_add;
wire        inst_addi;
wire        inst_sub;

wire        inst_slti;
wire        inst_sltiu;

wire        inst_andi;
wire        inst_ori;
wire        inst_xori;

wire        inst_sllv;
wire        inst_srlv;
wire        inst_srav;

wire        inst_mult;
wire        inst_multu;
wire        inst_div;
wire        inst_divu;

wire        inst_mfhi;
wire        inst_mflo;
wire        inst_mthi;
wire        inst_mtlo;
/* increase end*/

assign inst_no_dest  = inst_bne | inst_beq | inst_jr | inst_sw | inst_mult | inst_multu | 
                    inst_div | inst_divu | inst_mthi | inst_mtlo;

// Chapter5 changed
assign ds_to_es_bus = {
                        src_is_signed,
                        src2_is_0_imm,  //1:1
                        alu_op       ,  //124+18:124 18
                        load_op      ,  //123:123
                        src1_is_sa   ,  //122:122
                        src1_is_pc   ,  //121:121
                        src2_is_imm  ,  //120: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
                        };

// Chapter5
/* increase begin*/
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];
assign inst_slti    = op_d[6'h0a];
assign inst_sltiu   = op_d[6'h0b];
assign inst_andi    = op_d[6'h0c];
assign inst_ori     = op_d[6'h0d];
assign inst_xori    = op_d[6'h0e];
assign inst_sllv    = op_d[6'h00] & func_d[6'h04] & sa_d[5'h00];
assign inst_srlv    = op_d[6'h00] & func_d[6'h06] & sa_d[5'h00];
assign inst_srav    = op_d[6'h00] & func_d[6'h07] & sa_d[5'h00];
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_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];
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];

/* increase end*/

// Chapter5
/* change begin*/
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 alu_op[ 2] = inst_slt | inst_slti;
assign alu_op[ 3] = inst_sltu | inst_sltiu;
assign alu_op[ 4] = inst_and | inst_andi;
assign alu_op[ 5] = inst_nor;
assign alu_op[ 6] = inst_or | inst_ori;
assign alu_op[ 7] = inst_xor | inst_xori;
assign alu_op[ 8] = inst_sll | inst_sllv;
assign alu_op[ 9] = inst_srl | inst_srlv;
assign alu_op[10] = inst_sra | inst_srav;
assign alu_op[11] = inst_lui;
assign alu_op[12] = inst_mult | inst_multu;
assign alu_op[13] = inst_div | inst_divu;
assign alu_op[14] = inst_mthi;
assign alu_op[15] = inst_mtlo;
assign alu_op[16] = inst_mfhi;
assign alu_op[17] = inst_mflo;
/* change end*/

// Chapter5 changed
assign load_op       = inst_lw;
assign src1_is_sa    = inst_sll   | inst_srl | inst_sra;
assign src1_is_pc    = inst_jal;
assign src2_is_imm   = inst_addiu | inst_lui | inst_lw | inst_sw | inst_addi | inst_slti | inst_sltiu;
assign src2_is_0_imm = inst_andi | inst_ori | inst_xori;
assign src2_is_8     = inst_jal;
assign res_from_mem  = inst_lw;
assign dst_is_r31    = inst_jal;
assign dst_is_rt     = inst_addiu | inst_lui | inst_lw | inst_addi | inst_slti | inst_sltiu | inst_andi | inst_ori | inst_xori;
assign gr_we         = ~inst_sw & ~inst_beq & ~inst_bne & ~inst_jr;
assign mem_we        = inst_sw;

// Chapter5 increase
assign src_is_signed = inst_mult | inst_div;

EXE state

reg     [31:0]  HI;
reg     [31:0]  LO;

assign {src_is_signed,
        src2_is_0_imm,
        es_alu_op      ,  //124+18:124
        es_load_op     ,  //123:123
        es_src1_is_sa  ,  //122:122
        es_src1_is_pc  ,  //121:121
        es_src2_is_imm ,  //120: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;

// Chapter5 increase
wire [63:0] result64;
wire        complete;
wire        op_div;
wire        op_mthi;
wire        op_mtlo;
wire        op_mfhi;
wire        op_mflo;

assign op_div  = es_alu_op[13];
assign op_mthi = es_alu_op[14];
assign op_mtlo = es_alu_op[15];
assign op_mfhi = es_alu_op[16];
assign op_mflo = es_alu_op[17];

// Chapter5 changed
assign es_ready_go    = ~op_div | complete;

// Chapter5 increase
assign es_alu_src2 = es_src2_is_imm ? {{16{es_imm[15]}}, es_imm[15:0]} : 
                     es_src2_is_8   ? 32'd8 :
                     src2_is_0_imm  ? {16'b0, es_imm[15:0]} :
                                      es_rt_value;

// Chapter5 increase
always @(posedge clk or negedge reset) begin
    if (reset) begin
        HI <= 32'b0;
        LO <= 32'b0;
    end else if (complete & op_div) begin
        {LO, HI} <= result64;
    end else if (complete) begin
        // mul
        {HI, LO} <= result64;
    end else if (op_mthi) begin
        HI <= es_rs_value;
    end else if (op_mtlo) begin
        LO <= es_rs_value;
    end
end

// Chapter5 increase
assign es_result       = op_mfhi ? HI :
                         op_mflo ? LO :
                         es_alu_result;

alu u_alu(
    .alu_op             (es_alu_op      ),
    .alu_src1           (es_alu_src1    ),
    .alu_src2           (es_alu_src2    ),
    .src_is_signed      (src_is_signed  ), 
    .clk                (clk            ),
    .reset              (reset          ),

    .result64           (result64       ),
    .complete           (complete       ),    
    .alu_result         (es_alu_result  )
    );

ALU

module alu(
    input  [`ALU_OP-1:0] alu_op,
    input  [31:0] alu_src1,
    input  [31:0] alu_src2,

    input         src_is_signed,
    input         clk,
    input         reset,

    output [31:0] alu_result,
    output [63:0] result64,
    output        complete
);

// Chapter5
wire op_mul;   //乘除法操作
wire op_div;

// Chapter5
assign op_mul  = alu_op[12];
assign op_div  = alu_op[13];

wire [63:0] mul64_result;
wire [63:0] div64_result;
wire [63:0] u_div64_result; 
wire [63:0] s_div64_result; 

// Chapter5
// wire [63:0] unsigned_prod;
// wire [63:0] signed_prod;
wire [32:0] src1;
wire [32:0] src2;

// MUL result
// assign unsigned_prod = alu_src1 * alu_src2;
// assign signed_prod   = $signed(alu_src1) * $signed(alu_src2);
// 33bits mul
assign src1 = src_is_signed ? {alu_src1[31], alu_src1} : {1'b0, alu_src1};
assign src2 = src_is_signed ? {alu_src2[31], alu_src2} : {1'b0, alu_src2};
assign mul64_result  = $signed(src1) * $signed(src2);

// DIV result
wire            complete_udiv;
wire            complete_sdiv;

u_div uut_u_div (
    .clk                     (clk                  ),
    .reset                   (reset                ),
    .src1                    (alu_src1       [31:0]),
    .src2                    (alu_src2       [31:0]),
    .op_div                  (op_div               ),
    .src_is_signed           (src_is_signed        ),
    .div64_result            (u_div64_result [63:0]),
    .complete                (complete_udiv        )
);

s_div uut_s_div (
    .clk                     (clk                  ),
    .reset                   (reset                ),
    .src1                    (alu_src1       [31:0]),
    .src2                    (alu_src2       [31:0]),
    .op_div                  (op_div               ),
    .src_is_signed           (src_is_signed        ),
    .div64_result            (s_div64_result [63:0]),
    .complete                (complete_sdiv        )
);

assign div64_result = src_is_signed  ? s_div64_result : u_div64_result;

assign result64 = op_mul == 1'b1 ? mul64_result :
                  op_div == 1'b1 ? div64_result :
                                   64'bz;

assign complete = op_mul ?          1'b1            : 
                  src_is_signed ?   complete_sdiv   : 
                  complete_udiv;

除法器模块

有符号数除法

module s_div (
    input                clk,
    input                reset,
    input        [31:0]  src1,
    input        [31:0]  src2,
    input                op_div,
    input                src_is_signed,
    output       [63:0]  div64_result,
    // output       [31:0]  s,
    // output       [31:0]  r,
    output               complete
);

// DIV result
reg              s_axis_divisor_tvalid;
wire             s_axis_divisor_tready;
wire     [31:0]  s_axis_divisor_tdata;
reg              s_axis_dividend_tvalid;
wire             s_axis_dividend_tready;
wire     [31:0]  s_axis_dividend_tdata;
wire             m_axis_dout_tvalid;
wire     [63:0]  m_axis_dout_tdata;

s_mydiv s_mydiv (
    .aclk(clk),
    .s_axis_divisor_tvalid  (s_axis_divisor_tvalid),
    .s_axis_divisor_tready  (s_axis_divisor_tready),
    .s_axis_divisor_tdata   (s_axis_divisor_tdata),

    .s_axis_dividend_tvalid (s_axis_dividend_tvalid),
    .s_axis_dividend_tready (s_axis_dividend_tready),
    .s_axis_dividend_tdata  (s_axis_dividend_tdata),

    .m_axis_dout_tvalid     (m_axis_dout_tvalid),
    .m_axis_dout_tdata      (m_axis_dout_tdata)
);

assign s_axis_divisor_tdata  = src2;
assign s_axis_dividend_tdata = src1;

parameter free      = 2'b00;
parameter load_data = 2'b01;
parameter begin_div = 2'b10;
// parameter end_div   = 2'b11;

reg [1:0]            st_cur  ;

always @(posedge clk or negedge reset) begin
    if (reset) begin
        st_cur <= free;
        s_axis_divisor_tvalid  <= 1'b0;
        s_axis_dividend_tvalid <= 1'b0;
    end else if (op_div) begin
        case (st_cur)
            free: 
            case (op_div & src_is_signed)
                1'b1: begin
                    st_cur <= load_data;
                    s_axis_divisor_tvalid  <= 1'b1;
                    s_axis_dividend_tvalid <= 1'b1;
                end            
                default: st_cur <= free;
            endcase

            load_data:
            case (s_axis_divisor_tready & s_axis_dividend_tready)
                1'b1: begin
                    st_cur <= begin_div;
                    s_axis_divisor_tvalid  <= 1'b0;
                    s_axis_dividend_tvalid <= 1'b0;
                end
                default: st_cur <= load_data;
            endcase

            begin_div:
            case (m_axis_dout_tvalid)
                1'b1: begin
                    st_cur <= free;
                end
                default: st_cur <= begin_div;
            endcase

            // end_div: begin
            //     st_cur <= free;
            // end 
            default: st_cur <= free;
        endcase
    end
end

assign complete = m_axis_dout_tvalid;
assign div64_result = m_axis_dout_tdata;
// assign div64_result = complete? m_axis_dout_tdata : 64'bz;

endmodule

无符号数除法

module u_div (
    input               clk,
    input               reset,
    input       [31:0]  src1,
    input       [31:0]  src2,
    input               op_div,
    input               src_is_signed,
    output      [63:0]  div64_result,
    output              complete
);

// DIV result
reg              us_axis_divisor_tvalid;
wire             us_axis_divisor_tready;
wire     [31:0]  us_axis_divisor_tdata;
reg              us_axis_dividend_tvalid;
wire             us_axis_dividend_tready;
wire     [31:0]  us_axis_dividend_tdata;
wire             um_axis_dout_tvalid;
wire     [63:0]  um_axis_dout_tdata;

u_mydiv u_mydiv (
    .aclk(clk),
    .s_axis_divisor_tvalid  (us_axis_divisor_tvalid),
    .s_axis_divisor_tready  (us_axis_divisor_tready),
    .s_axis_divisor_tdata   (us_axis_divisor_tdata),
    .s_axis_dividend_tvalid (us_axis_dividend_tvalid),
    .s_axis_dividend_tready (us_axis_dividend_tready),
    .s_axis_dividend_tdata  (us_axis_dividend_tdata),
    .m_axis_dout_tvalid     (um_axis_dout_tvalid),
    .m_axis_dout_tdata      (um_axis_dout_tdata)
);

assign us_axis_divisor_tdata  = src2;
assign us_axis_dividend_tdata = src1;

parameter free      = 2'b00;
parameter load_data = 2'b01;
parameter begin_div = 2'b10;
// parameter end_div   = 2'b11;

reg [1:0]            st_cur  ;

always @(posedge clk or negedge reset) begin
    if (reset) begin
        st_cur <= free;
        us_axis_divisor_tvalid  <= 1'b0;
        us_axis_dividend_tvalid <= 1'b0;
    end else if (op_div) begin
        case (st_cur)
            free: 
            case (op_div & ~src_is_signed)
                1'b1: begin
                    st_cur <= load_data;
                    us_axis_divisor_tvalid  <= 1'b1;
                    us_axis_dividend_tvalid <= 1'b1;
                end            
                default: st_cur <= free;
            endcase

            load_data:
            case (us_axis_divisor_tready & us_axis_dividend_tready)
                1'b1: begin
                    st_cur <= begin_div;
                    us_axis_divisor_tvalid  <= 1'b0;
                    us_axis_dividend_tvalid <= 1'b0;
                end
                default: st_cur <= load_data;
            endcase

            begin_div:
            case (um_axis_dout_tvalid)
                1'b1: begin
                    st_cur <= free;
                end
                default: st_cur <= begin_div;
            endcase

            // end_div: begin
            //     st_cur <= free;
            // end 
            
            default: st_cur <= free;
        endcase
    end
end

assign complete = um_axis_dout_tvalid;
assign div64_result = um_axis_dout_tdata;
// assign div64_result = complete? um_axis_dout_tdata : 64'bz;

endmodule

测试通过

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值