// 32 bit multiplier/divider module mult_div (ena, clk,a, b, y, reset, mult_div, signedop, done, status); input [31:0] a, b; // The input data values output [64:0] y; // Output output done; // 1 = computation complete output [3:0] status; // Status register data bits input ena, // 1 = ena new computation clk, // System clock reset; // Global (asynchronous) reset input signedop; input mult_div; reg [64:0] y; reg done; reg [3:0] status; reg [3:0] current_state_mult; reg [3:0] next_state_mult; reg temp_done; reg addsub_ena, add; reg shifter_ena; reg [31:0] bi; reg negative_output; wire [3:0] addsub_status; wire [31:0] temp_prodadd; wire [64:0] temp_prodshift; reg shifter_right; reg y_msb; parameter MSB = 31; parameter IDLE = 4'b0000; parameter MULT_ADD = 4'b0001; parameter MULT_SHIFT = 4'b0011; parameter MULT_WB = 4'b0010; parameter MULT_DONE = 4'b0100; parameter DIVIDE_SUB = 4'b0101; parameter DIVIDE_RESTORE= 4'b0110; parameter DIVIDE_SHIFT = 4'b0111; parameter DIVIDE_WB = 4'b1000; parameter DIVIDE_DONE = 4'b1001; `define FLAG_N 2'b00 `define FLAG_Z 2'b01 `define FLAG_V 2'b10 `define FLAG_C 2'b11 integer shiftindex; func ADDSUB(addsub_ena, clk, (y[64:33] & {32{mult_div}}) | (y[63:32] & {32{!mult_div}}), bi, temp_prodadd, {1'b0,add}, 1'b0, addsub_status); shifter_64 SHIFTER(shifter_ena, clk, y, 4'b0001, temp_prodshift, 1'b1, shifter_right); always @(negedge clk) case(current_state_mult) MULT_ADD: if (y[1:0]==2'b01 || y[1:0]==2'b10) y<={temp_prodadd,y[32:0]}; MULT_SHIFT: y<=temp_prodshift; MULT_DONE: y<=temp_prodshift; DIVIDE_SUB: y<={temp_prodadd[31],temp_prodadd,y[31:0]}; DIVIDE_RESTORE: y<={temp_prodadd[31],temp_prodadd,y[31:0]}; DIVIDE_SHIFT: y<={temp_prodshift[64:1], (y_msb==1'b0)}; DIVIDE_DONE: y<={temp_prodshift[64:32],y[31:0]}; endcase always @(negedge clk) y_msb <=y[64]; always @(posedge clk or negedge reset) begin if (reset == 1'b0) begin current_state_mult = IDLE; done = 1'b0; addsub_ena =1'b0; shifter_ena =1'b0; add =1'b0; end else begin current_state_mult = next_state_mult; done = temp_done; end end always @(negedge clk or negedge reset) begin if (reset == 1'b0) begin next_state_mult = IDLE; temp_done = 1'b0; shiftindex=0; addsub_ena =1'b0; shifter_ena =1'b0; add =1'b0; end else begin case(current_state_mult) IDLE : begin temp_done = 1'b0; shiftindex= 0; shifter_ena=0; if (ena == 1'b1) if (mult_div == 1'b1) begin y = 0; if (signedop) begin bi = (b[MSB]) ? (~b) + 1 : b; y[32:1] = (a[MSB]) ? (~a) +1 : a; negative_output = (a[MSB] ^ b[MSB] ); end else begin bi = b; y[32:1] = a; negative_output = 0; end next_state_mult = MULT_ADD; temp_done = 1'b0; shifter_right=1'b1; case (y[1:0]) 2'b00: addsub_ena=0; 2'b01: begin add = 1; //y[64:33] = y[64:33] + b; addsub_ena=1; end 2'b10: begin add = 0; //y[64:33] = y[64:33] - b; addsub_ena=1; end 2'b11: addsub_ena=0; endcase end else // do this if divide begin y = 0; if (signedop) begin bi = (b[MSB]) ? (~b) + 1 : b; y[32:1] = (a[MSB]) ? (~a) +1 : a; negative_output = (a[MSB] ^ b[MSB] ); end else begin bi = b; y[32:1] = a; negative_output = 0; end next_state_mult = DIVIDE_SUB; temp_done = 1'b0; addsub_ena=1; add=0; shifter_ena=0; shifter_right=0; end end MULT_ADD : begin addsub_ena=0; shifter_ena=1; next_state_mult = MULT_SHIFT; end MULT_SHIFT : begin shifter_ena=0; case (temp_prodshift[1:0]) 2'b00: addsub_ena=0; 2'b01: begin add = 1; //y[64:33] = y[64:33] + b; addsub_ena=1; end 2'b10: begin add = 0; //y[64:33] = y[64:33] - b; addsub_ena=1; end 2'b11: addsub_ena=0; endcase shiftindex = shiftindex+1; if (shiftindex==32) next_state_mult = MULT_WB; else next_state_mult = MULT_ADD; end MULT_WB : begin if (negative_output) y = ~(y) + 64'b1; temp_done = 1'b1; addsub_ena=0; shifter_ena=1; next_state_mult = MULT_DONE; end MULT_DONE : begin temp_done = 1'b0; addsub_ena=0; shifter_ena=0; next_state_mult = IDLE; status[`FLAG_N] = signedop ? negative_output : 1'b0; status[`FLAG_V] = 1'b0; status[`FLAG_C] = 1'b0; status[`FLAG_Z] = (y==0); end DIVIDE_SUB : begin if (temp_prodadd[31]==1'b1) //if remainder<0, restore the begin //orginal value by adding to addsub_ena=1; //the left half of the remainder reg add=1; end else addsub_ena=0; next_state_mult = DIVIDE_RESTORE; end DIVIDE_RESTORE : begin addsub_ena=0; shifter_ena=1; //shifting the remainder reg to left next_state_mult = DIVIDE_SHIFT; end DIVIDE_SHIFT : begin addsub_ena=1; add=0; shifter_ena=0; shifter_right=0; shiftindex = shiftindex+1; if (shiftindex==32) next_state_mult = DIVIDE_WB; else next_state_mult = DIVIDE_SUB; end DIVIDE_WB : begin if (negative_output) y[31:0] = ~(y[31:0]) + 32'b1; if (b[31]) y[64:32] = ~(y[64:32]) + 32'b1; temp_done = 1'b1; addsub_ena=0; shifter_ena=1; shifter_right=1; next_state_mult = DIVIDE_DONE; end DIVIDE_DONE : begin temp_done = 1'b0; addsub_ena=0; shifter_ena=0; next_state_mult = IDLE; status[`FLAG_N] = 1'b0; //signedop ? negative_output : 1'b0; status[`FLAG_V] = 1'b0; status[`FLAG_C] = 1'b0; status[`FLAG_Z] = (y==0); end endcase end end endmodule