URL
https://opencores.org/ocsvn/mips789/mips789/trunk
Subversion Repositories mips789
[/] [mips789/] [trunk/] [core/] [EXEC_stage.v] - Rev 64
Compare with Previous | Blame | View Log
/****************************************************************** * * * Author: Liwei * * * * This file is part of the "mips789" project. * * Downloaded from: * * http://www.opencores.org/pdownloads.cgi/list/mips789 * * * * If you encountered any problem, please contact me via * * Email:mcupro@opencores.org or mcupro@163.com * * * ******************************************************************/ `include "mips789_defs.v" module exec_stage ( input clk, input rst, input spc_cls_i, input [4:0] alu_func, input [2:0] dmem_fw_ctl, input [31:0] ext_i, input [31:0] fw_alu, input [31:0] fw_dmem, input [1:0] muxa_ctl_i, input [2:0] muxa_fw_ctl, input [1:0] muxb_ctl_i, input [2:0] muxb_fw_ctl, input [31:0] pc_i, input [31:0] rs_i, input [31:0] rt_i, output [31:0] alu_ur_o, output [31:0] dmem_data_ur_o, output [31:0] zz_spc_o ); wire [31:0] BUS2332; wire [31:0] BUS2446; wire [31:0] BUS468; wire [31:0] BUS476; mips_alu MIPS_alu ( .a(BUS476), .b(BUS468), .c(alu_ur_o), .clk(clk), .ctl(alu_func), .rst(rst) ); add32 add4 ( .d_i(pc_i), .d_o(BUS2446) ); fwd_mux dmem_fw_mux ( .dout(dmem_data_ur_o), .fw_alu(fw_alu), .fw_ctl(dmem_fw_ctl), .fw_dmem(fw_dmem), .din(rt_i) ); alu_muxa i_alu_muxa ( .a_o(BUS476), .ctl(muxa_ctl_i), .ext(ext_i), .fw_alu(fw_alu), .fw_ctl(muxa_fw_ctl), .fw_mem(fw_dmem), .pc(BUS2332), .rs(rs_i), .spc(zz_spc_o) ); alu_muxb i_alu_muxb ( .b_o(BUS468), .ctl(muxb_ctl_i), .ext(ext_i), .fw_alu(fw_alu), .fw_ctl(muxb_fw_ctl), .fw_mem(fw_dmem), .rt(rt_i) ); r32_reg pc_nxt ( .clk(clk), .r32_i(BUS2446), .r32_o(BUS2332) ); r32_reg_cls spc ( .clk(clk), .cls(spc_cls_i), .r32_i(pc_i), .r32_o(zz_spc_o) ); endmodule module mips_alu(clk,rst,a,b,c,ctl); input clk,rst ; input [31:0] a,b ; output [31:0] c ; input [4:0]ctl ; wire [31:0] mul_div_c; wire [31:0] alu_c; wire [31:0] shift_c; `ifdef USE_MULDIV assign c = mul_div_c | alu_c | shift_c ; `else assign c = alu_c | shift_c ; `endif `ifdef USE_MULDIV muldiv_ff muldiv_ff( .clk_i(clk), .rst_i(rst),//sys signal .op_type(ctl), .op1(a), .op2(b), // .busy_o(busy), .res(mul_div_c) ); `endif shifter_tak mips_shifter( .a(b), .shift_out(shift_c), .shift_func(ctl), .shift_amount(a) ); alu mips_alu( .a(a), .b(b), .alu_out(alu_c), .alu_func(ctl) ); endmodule module alu_muxa( input [31:0]spc, input [31:0]pc, input [31:0]fw_mem, input [31:0]rs, input [31:0]fw_alu, input [31:0]ext, input [1:0] ctl, input [2:0] fw_ctl, output reg [31:0]a_o ); always @(*) begin case (ctl) `MUXA_RS: a_o = (fw_ctl ==`FW_ALU )?fw_alu:(fw_ctl==`FW_MEM)?fw_mem:rs; `MUXA_PC: a_o = pc; `MUXA_EXT: a_o = ext; `MUXA_SPC: a_o = spc; default : a_o = rs; endcase end endmodule module alu_muxb( input [31:0] rt, input [31:0]fw_alu, input [31:0]fw_mem, input [31:0]ext , input [1:0]ctl , input [2:0]fw_ctl , output reg [31:0] b_o ); always@(*) case (ctl) `MUXB_RT :b_o = (fw_ctl ==`FW_ALU )?fw_alu:(fw_ctl==`FW_MEM)?fw_mem:rt; `MUXB_EXT : b_o=ext; default b_o=rt; endcase endmodule //This file is based on YACC ->alu.v and UCORE ->alu.v module alu ( input [31:0] a, input [31:0]b, output reg [31:0] alu_out, input [4:0] alu_func ); reg [32:0] sum; always @(*) begin case (alu_func) `ALU_PA : alu_out=a; `ALU_PB : alu_out=b; `ALU_ADD : alu_out=a+b; `ALU_SUB , `ALU_SUBU : alu_out=a + (~b)+1; `ALU_OR : alu_out=a | b; `ALU_AND : alu_out=a & b; `ALU_XOR : alu_out=a ^ b; `ALU_NOR : alu_out=~(a | b); `ALU_SLTU : alu_out=(a < b)?1:0; `ALU_SLT : begin sum={a[31],a}+~{b[31],b}+33'h0_0000_0001; alu_out={31'h0000_0000,sum[32]}; end /* `ALU_SLL: alu_out = a<<b[4:0]; `ALU_SRL: alu_out = a>>b[4:0]; `ALU_SRA: alu_out=~(~a>>b[4:0]); //the three operations is done in shifter_tak or shift_ff */ default : alu_out=32'h0; endcase end endmodule module shifter_ff( input [31:0] a, output reg [31:0] shift_out, input [4:0] shift_func,//connect to alu_func_ctl input [31:0] shift_amount//connect to b ); always @ (*) begin case( shift_func ) `ALU_SLL: shift_out = a<<shift_amount; `ALU_SRL: shift_out = a>>shift_amount; `ALU_SRA: shift_out=~(~a>> shift_amount); default shift_out='d0; endcase end endmodule module shifter_tak( input [31:0] a, output reg [31:0] shift_out, input [4:0] shift_func,//connect to alu_func_ctl input [31:0] shift_amount//connect to b ); always @ (*) case( shift_func ) `ALU_SLL: begin case ( shift_amount[4:0] ) 5'b00000: shift_out=a; 5'b00001: shift_out={a[30:0],1'b0}; 5'b00010: shift_out={a[29:0],2'b0}; 5'b00011: shift_out={a[28:0],3'b0}; 5'b00100: shift_out={a[27:0],4'b0}; 5'b00101: shift_out={a[26:0],5'b0}; 5'b00110: shift_out={a[25:0],6'b0}; 5'b00111: shift_out={a[24:0],7'b0}; 5'b01000: shift_out={a[23:0],8'b0}; 5'b01001: shift_out={a[22:0],9'b0}; 5'b01010: shift_out={a[21:0],10'b0}; 5'b01011: shift_out={a[20:0],11'b0}; 5'b01100: shift_out={a[19:0],12'b0}; 5'b01101: shift_out={a[18:0],13'b0}; 5'b01110: shift_out={a[17:0],14'b0}; 5'b01111: shift_out={a[16:0],15'b0}; 5'b10000: shift_out={a[15:0],16'b0}; 5'b10001: shift_out={a[14:0],17'b0}; 5'b10010: shift_out={a[13:0],18'b0}; 5'b10011: shift_out={a[12:0],19'b0}; 5'b10100: shift_out={a[11:0],20'b0}; 5'b10101: shift_out={a[10:0],21'b0}; 5'b10110: shift_out={a[9:0],22'b0}; 5'b10111: shift_out={a[8:0],23'b0}; 5'b11000: shift_out={a[7:0],24'b0}; 5'b11001: shift_out={a[6:0],25'b0}; 5'b11010: shift_out={a[5:0],26'b0}; 5'b11011: shift_out={a[4:0],27'b0}; 5'b11100: shift_out={a[3:0],28'b0}; 5'b11101: shift_out={a[2:0],29'b0}; 5'b11110: shift_out={a[1:0],30'b0}; 5'b11111: shift_out={a[0],31'b0}; default shift_out =32'bx;//never in this case endcase end `ALU_SRL : begin case (shift_amount[4:0]) 5'b00000: shift_out=a; 5'b00001: shift_out={1'b0,a[31:1]}; 5'b00010: shift_out={2'b0,a[31:2]}; 5'b00011: shift_out={3'b0,a[31:3]}; 5'b00100: shift_out={4'b0,a[31:4]}; 5'b00101: shift_out={5'b0,a[31:5]}; 5'b00110: shift_out={6'b0,a[31:6]}; 5'b00111: shift_out={7'b0,a[31:7]}; 5'b01000: shift_out={8'b0,a[31:8]}; 5'b01001: shift_out={9'b0,a[31:9]}; 5'b01010: shift_out={10'b0,a[31:10]}; 5'b01011: shift_out={11'b0,a[31:11]}; 5'b01100: shift_out={12'b0,a[31:12]}; 5'b01101: shift_out={13'b0,a[31:13]}; 5'b01110: shift_out={14'b0,a[31:14]}; 5'b01111: shift_out={15'b0,a[31:15]}; 5'b10000: shift_out={16'b0,a[31:16]}; 5'b10001: shift_out={17'b0,a[31:17]}; 5'b10010: shift_out={18'b0,a[31:18]}; 5'b10011: shift_out={19'b0,a[31:19]}; 5'b10100: shift_out={20'b0,a[31:20]}; 5'b10101: shift_out={21'b0,a[31:21]}; 5'b10110: shift_out={22'b0,a[31:22]}; 5'b10111: shift_out={23'b0,a[31:23]}; 5'b11000: shift_out={24'b0,a[31:24]}; 5'b11001: shift_out={25'b0,a[31:25]}; 5'b11010: shift_out={26'b0,a[31:26]}; 5'b11011: shift_out={27'b0,a[31:27]}; 5'b11100: shift_out={28'b0,a[31:28]}; 5'b11101: shift_out={29'b0,a[31:29]}; 5'b11110: shift_out={30'b0,a[31:30]}; 5'b11111: shift_out={31'b0,a[31:31]}; default : shift_out = 32'bx;//never in this case endcase end `ALU_SRA: begin// SHIFT_RIGHT_SIGNED case ( shift_amount[4:0]) 5'b00000: shift_out=a; 5'b00001: shift_out={a[31],a[31:1]}; 5'b00010: shift_out={{2{a[31]}},a[31:2]}; 5'b00011: shift_out={{3{a[31]}},a[31:3]}; 5'b00100: shift_out={{4{a[31]}},a[31:4]}; 5'b00101: shift_out={{5{a[31]}},a[31:5]}; 5'b00110: shift_out={{6{a[31]}},a[31:6]}; 5'b00111: shift_out={{7{a[31]}},a[31:7]}; 5'b01000: shift_out={{8{a[31]}},a[31:8]}; 5'b01001: shift_out={{9{a[31]}},a[31:9]}; 5'b01010: shift_out={{10{a[31]}},a[31:10]}; 5'b01011: shift_out={{11{a[31]}},a[31:11]}; 5'b01100: shift_out={{12{a[31]}},a[31:12]}; 5'b01101: shift_out={{13{a[31]}},a[31:13]}; 5'b01110: shift_out={{14{a[31]}},a[31:14]}; 5'b01111: shift_out={{15{a[31]}},a[31:15]}; 5'b10000: shift_out={{16{a[31]}},a[31:16]}; 5'b10001: shift_out={{17{a[31]}},a[31:17]}; 5'b10010: shift_out={{18{a[31]}},a[31:18]}; 5'b10011: shift_out={{19{a[31]}},a[31:19]}; 5'b10100: shift_out={{20{a[31]}},a[31:20]}; 5'b10101: shift_out={{21{a[31]}},a[31:21]}; 5'b10110: shift_out={{22{a[31]}},a[31:22]}; 5'b10111: shift_out={{23{a[31]}},a[31:23]}; 5'b11000: shift_out={{24{a[31]}},a[31:24]}; 5'b11001: shift_out={{25{a[31]}},a[31:25]}; 5'b11010: shift_out={{26{a[31]}},a[31:26]}; 5'b11011: shift_out={{27{a[31]}},a[31:27]}; 5'b11100: shift_out={{28{a[31]}},a[31:28]}; 5'b11101: shift_out={{29{a[31]}},a[31:29]}; 5'b11110: shift_out={{30{a[31]}},a[31:30]}; 5'b11111: shift_out={{31{a[31]}},a[31:31]}; default shift_out=32'bx;//never in this case endcase end default shift_out='d0; endcase endmodule module muldiv(ready,rst,op1,op2,clk,dout,func); input clk,rst; wire sign; input [4:0] func ; input [31:0] op2, op1; output [31:0] dout; output ready; reg [31:0] quotient, quotient_temp; reg [63:0] dividend_copy, divider_copy, diff; reg negative_output; reg [63:0] product, product_temp; reg [31:0] multiplier_copy; reg [63:0] multiplicand_copy; reg [6:0] mul_bit,div_bit; wire ready = ((mul_bit==0)&&(div_bit==0)); wire [31:0] dividend, divider; wire [31:0] remainder; wire [31:0] multiplier,multiplicand; reg [31:0] hi,lo; assign dout = (func==`ALU_MFHI)?hi:(func==`ALU_MFLO)?lo:0; assign remainder = (!negative_output) ? dividend_copy[31:0] : ~dividend_copy[31:0] + 1'b1; assign multiplier=op2; assign multiplicand=op1; assign dividend=op1; assign divider = op2; assign sign = ((func==`ALU_MULT)||(func==`ALU_DIV)); initial begin hi=0; lo=0; end always @( posedge clk /*or negedge rst */) if (~rst) begin mul_bit=0; div_bit=0; /* hi=0; lo=0; */ negative_output = 0; end else begin if((ready)&&((func==`ALU_MULT)||(func==`ALU_MULTTU))) begin mul_bit = 33; product = 0; product_temp = 0; multiplicand_copy = (!sign || !multiplicand[31]) ? { 32'd0, multiplicand } : { 32'd0, ~multiplicand + 1'b1}; multiplier_copy = (!sign || !multiplier[31]) ?multiplier :~multiplier + 1'b1; negative_output = sign && ((multiplier[31] && !multiplicand[31]) ||(!multiplier[31] && multiplicand[31])); end if ( mul_bit > 1 ) begin if( multiplier_copy[0] == 1'b1 ) product_temp = product_temp +multiplicand_copy; product = (!negative_output) ? product_temp : ~product_temp + 1'b1; multiplier_copy = multiplier_copy >> 1; multiplicand_copy = multiplicand_copy << 1; mul_bit = mul_bit - 1'b1; end else if (mul_bit == 1) begin hi = product[63:32]; lo = product[31:0]; mul_bit=0; end if((ready)&&((func==`ALU_DIV)||(func==`ALU_DIVU))) begin div_bit = 33; quotient = 0; quotient_temp = 0; dividend_copy = (!sign || !dividend[31]) ? {32'd0,dividend} : {32'd0,~dividend + 1'b1}; divider_copy = (!sign || !divider[31]) ? {1'b0,divider,31'd0} : {1'b0,~divider + 1'b1,31'd0}; negative_output = sign && ((divider[31] && !dividend[31]) ||(!divider[31] && dividend[31])); end else if (div_bit > 1) begin diff = dividend_copy - divider_copy; quotient_temp = quotient_temp << 1; if( !diff[63] ) begin dividend_copy = diff; quotient_temp[0] = 1'd1; end quotient = (!negative_output) ?quotient_temp :~quotient_temp + 1'b1; divider_copy = divider_copy >> 1; div_bit = div_bit - 1'b1; end else if (div_bit == 1) begin lo = quotient; hi = remainder; div_bit=0; end end endmodule //creatied by Zhangfeifei //modified by Liwei module muldiv_ff ( clk_i,rst_i, op_type,op1,op2, rdy,res ); parameter OP_MULT = `ALU_MULT; parameter OP_MULTU = `ALU_MULTU; parameter OP_DIV = `ALU_DIV; parameter OP_DIVU = `ALU_DIVU; parameter OP_MFHI = `ALU_MFHI; parameter OP_MFLO = `ALU_MFLO; parameter OP_MTHI = `ALU_MTHI; parameter OP_MTLO = `ALU_MTLO; parameter OP_NONE = `ALU_NOP; input clk_i; input rst_i; input [4:0] op_type; input [31:0] op1; input [31:0] op2; output [31:0] res; output rdy; reg rdy; reg [64:0] hilo; reg [32:0] op2_reged; reg [5:0] count; reg op1_sign_reged; reg op2_sign_reged; reg sub_or_yn; wire [32:0] nop2_reged; assign nop2_reged = ~op2_reged +1; reg sign; reg mul; reg start; assign res = (op_type == OP_MFLO )?hilo[31:0]:((op_type == OP_MFHI))?hilo[63:32]:0;//op_type == OP_MFHI or other reg overflow; reg finish; reg add1; //if the quotient will add 1 at the end of the divide operation reg addop2; //if the remainder will add op2 at the end of the divide operation reg addnop2;//if the remainder will add ~op2+1 at the end of the divide operation always @( posedge clk_i /*or negedge rst_i*/) begin if(~rst_i) begin count = 6'bx; hilo = 65'b0; op2_reged = 33'bx; op1_sign_reged = 1'bx; op2_sign_reged = 1'bx; sub_or_yn = 1'bx; rdy = 1'b1; start = 1'bx; sign = 1'bx; mul = 1'bx; finish = 1'bx; add1 = 1'bx; addop2 = 1'bx; addnop2 = 1'bx; end else begin if(op_type == OP_MTHI || op_type == OP_MTLO) begin if(op_type == OP_MTHI) hilo[64:32] = {1'b0,op1}; if(op_type == OP_MTLO) hilo[31:0] = op1; rdy = 1; end else if(rdy) begin start = (op_type == OP_MULT) || (op_type == OP_MULTU) || (op_type == OP_DIV) || (op_type == OP_DIVU); mul = (op_type == OP_MULT) || (op_type == OP_MULTU); sign = (op_type == OP_MULT) || (op_type == OP_DIV); if(start) begin:START_SECTION reg [32:0] over; op2_reged = {sign ?op2[31] :1'b0 ,op2}; hilo = {~mul && sign?{33{op1[31]}}:33'b0,op1}; count = 6'b000000; rdy = 0; op1_sign_reged = sign?op1[31]:0; op2_sign_reged = sign?op2[31]:0; sub_or_yn = 0; over = ~op2_reged + {op1[31],op1}; overflow = sign && ~mul ? op1_sign_reged && op2_sign_reged && ~over[32] : 0; finish = 0; end end else if(start) begin if(overflow) begin hilo[63:0] = {hilo[31:0],32'b0}; rdy = 1; end else if(!count[5]) begin if(mul) begin if(sign) begin case({hilo[0],sub_or_yn}) 2'b10:hilo[64:32] = hilo[64:32] + nop2_reged; 2'b01:hilo[64:32] = hilo[64:32] + op2_reged; default:; endcase {hilo[63:0],sub_or_yn} = hilo[64:0]; end else begin if(hilo[0]) hilo[64:32] = hilo[64:32] + op2_reged; hilo = {1'b0,hilo[64:1]}; end end else begin sub_or_yn = hilo[64]== op2_sign_reged; hilo[64:1] = hilo[63:0]; hilo[64:32] = sub_or_yn ? hilo[64:32] + nop2_reged : hilo[64:32] + op2_reged; hilo[0] = hilo[64]== op2_sign_reged; end count = count + 1'b1; end else begin if(finish) begin if(add1) hilo[31:0] = hilo[31:0] + 1; case({addop2,addnop2}) 2'b10: hilo[64:32] = hilo[64:32] + op2_reged; 2'b01: hilo[64:32] = hilo[64:32] + nop2_reged; default: ; endcase rdy = 1; end else begin {add1,addop2,addnop2} = 3'b000; finish = 1; if(~mul) begin:LAST_CYCLE_DEAL_SECTION reg eqz,eqop2,eqnop2; eqz = hilo[64:32] == 0; eqop2 = hilo[64:32] == op2_reged; eqnop2 = hilo[64:32] == nop2_reged; casex({op1_sign_reged,op2_sign_reged,eqz,eqop2,eqnop2}) 5'b101xx : {add1,addop2,addnop2} = 3'b000; 5'b100x1 : {add1,addop2,addnop2} = 3'b010; 5'b111xx : {add1,addop2,addnop2} = 3'b100; 5'b1101x : {add1,addop2,addnop2} = 3'b101; default : begin:LAST_CYCLE_DEAL_SECTION_DEFAULT reg op1s_eq_op2s,op1s_eq_h64; op1s_eq_op2s = op1_sign_reged == op2_sign_reged; op1s_eq_h64 = op1_sign_reged == hilo[64]; add1 = ~op1s_eq_op2s; case({op1s_eq_op2s,op1s_eq_h64})//synthesis parallel_case 2'b00: {addop2,addnop2} = 2'b01; 2'b10: {addop2,addnop2} = 2'b10; default: {addop2,addnop2} = 2'b00; endcase end endcase end end end end end end endmodule