8.乗除算ユニット
符号あり・なし16x16,8x8、の乗除算ユニットです。除算は、オリジナルと同程度の23クロックかかります。
筆算と同じようにして計算します。
乗算は、3クロックで実行します。(オリジナルは、24クロック) クロックは、34MHz程度可能なのでオリジナル16MHzに対し2倍強ですから、これだけを見ると、最大24/3x2=16倍に性能がアップします。
別段変わったところはありません。それなりにゲートを投入しているだけです。
//Jun.2.2004 // mul/div 演算モジュール // mul 符号あり/なし。 8x8 1clock (CPU命令としては3Clock,Fetch,Decode,Execute) // 16x16 1clock (CPU命令としてはClock) // div 16/8 8 clock (CPU命令としては、15CLOCK) // 32/16 16 clock (CPU命令としては、23CLOCK) // // a[31:0] /b[15:0] => // mul_div_out[15:0] <=a/b // mul_div_out[31:16] <=a%b // オーバフローの検出なし。 // 割り算のアルゴリズム // answer_reg = (answer_reg << 1); // if (a_reg >= b_reg) { // answer_reg += 1; // a_reg -= b_reg; // } // b_reg = b_reg >> 1; `include "define.h" module mul_div(clock,sync_reset,a,b,mul_div_out,mul_div_sign,mul_div_word,mul_div_mode,state,stop_state,mul_div_enable); input clock,sync_reset; input [31:0] a,b; input [7:0] state; input mul_div_enable,mul_div_sign,mul_div_word,mul_div_mode; output stop_state; output [31:0] mul_div_out; reg [31:0] a_reg; reg [31:0] b_reg; reg [15:0] answer_reg; reg stop_state_reg;// For state control reg [4:0] counter; reg mul_div_sign_ff,mul_div_word_ff,mul_div_mode_ff; wire finish_operation; wire pre_stop; wire [32:0] sum; wire [15:0] answer_inc; wire [31:0] aminus=-a; wire [31:0] p1,p2,p3,p4; wire [15:0] p1b,p2b,p3b,p4b; wire [31:0] mul_out32; wire [15:0] mul_out16; wire [31:0] mul_func; wire [14:0] temp_p2,temp_p3; //mul function assign p1={1'b0,a_reg[15] & b_reg[15],30'h00_0000_00}; // assign p2={1'b0,{15{a_reg[15]}} & b_reg[14:0],16'h0000}; // assign p3={1'b0,{15{b_reg[15]}} & a_reg[14:0],16'h0000}; assign temp_p2={{15{a_reg[15]}} & b_reg[14:0]}; assign temp_p3={{15{b_reg[15]}} & a_reg[14:0]}; assign p2={2'b00,temp_p2,15'h0000}; assign p3={2'b00,temp_p3,15'h0000}; assign p4=a_reg[14:0] *b_reg[14:0]; assign mul_out32=p4;//mul_div_sign_ff ? p1-p2-p3+p4 : p1+p2+p3+p4; assign p1b={1'b0,a_reg[7] & b_reg[7],14'h0000}; assign p2b={2'b0,{7{a_reg[7]}} & b_reg[6:0],7'h00}; assign p3b={2'b0,{7{b_reg[7]}} & a_reg[6:0],7'h00}; assign p4b=a_reg[6:0] *b_reg[6:0]; assign mul_out16=p4b;//mul_div_sign_ff ? p1b-p2b-p3b+p4b : p1b+p2b+p3b+p4b; assign mul_func=mul_div_word_ff ==`MUL_DIV_WORD_ACCESS ? mul_out32 : {16'h0000,mul_out16}; assign mul_div_out=mul_div_mode_ff==`MUL_DIV_MUL_SEL ? mul_func : { a_reg[15:0] ,answer_reg}; //input FFs always @(posedge clock) begin if (sync_reset) begin mul_div_sign_ff<=0; mul_div_word_ff<=0; mul_div_mode_ff<=0; end else if (pre_stop) begin mul_div_sign_ff<=mul_div_sign; mul_div_word_ff<=mul_div_word; mul_div_mode_ff<=mul_div_mode; end end //state_machine assign pre_stop=mul_div_enable && state==8'b0000_0001; assign finish_operation=counter==17 && (mul_div_word_ff ==`MUL_DIV_WORD_ACCESS) || counter==9 && (mul_div_word_ff ==`MUL_DIV_BYTE_ACCESS); always @(posedge clock) begin if (sync_reset) stop_state_reg <=0; else if (pre_stop && !stop_state_reg && mul_div_mode !=`MUL_DIV_MUL_SEL) stop_state_reg<=1; else if (stop_state_reg && finish_operation) stop_state_reg<=0; end assign stop_state=mul_div_enable && mul_div_mode !=`MUL_DIV_MUL_SEL && ( stop_state_reg); always @(posedge clock) begin if (sync_reset) counter <=0; else if (!stop_state_reg) counter <=0; else if (stop_state_reg ) counter <=counter+1; end //a_reg always @(posedge clock) begin if(mul_div_mode==`MUL_DIV_MUL_SEL && pre_stop) a_reg <=a;//掛け算ならラッチするだけ else begin//ここから割り算 if (!stop_state_reg ) a_reg <=a_reg;//Operationが終わっているなら保持 else if (counter==0 ) begin //最初は、 if (mul_div_sign_ff) begin//符号付なら if (mul_div_word_ff ==`MUL_DIV_WORD_ACCESS && a[31]) a_reg <=aminus;//負数なら正数にする else if (mul_div_word_ff ==`MUL_DIV_BYTE_ACCESS && a[15]) a_reg <=aminus ;//[15:0] <=aminus[15:0]; //負数なら正数にする else a_reg <=a; end else a_reg <=a;//符号なしならそのままラッチ end else begin//div 実行中 if (mul_div_word_ff ==`MUL_DIV_WORD_ACCESS && !sum[32]) begin//if (a_reg >=b_reg) if ( finish_operation && mul_div_sign_ff && a[31] ) a_reg <=-sum;//最後は非除数符号にあわせる else a_reg <=sum;//sum[15:0];// a_reg -= b_reg end else if (mul_div_word_ff ==`MUL_DIV_BYTE_ACCESS && !sum[16]) begin//if (a_reg >=b_reg) if ( finish_operation && mul_div_sign_ff && a[15] ) a_reg <=-sum;//最後は非除数符号にあわせる else a_reg <=sum;//sum[7:0];// a_reg -=b_reg end else begin if ( finish_operation && mul_div_word_ff ==`MUL_DIV_WORD_ACCESS && mul_div_sign_ff && a[31] ) a_reg <=-a_reg;//最後は非除数符号にあわせる else if (finish_operation &&mul_div_word_ff !=`MUL_DIV_WORD_ACCESS && mul_div_sign_ff && a[15] ) a_reg <=-a_reg; //最後は非除数符号にあわせる else a_reg <=a_reg; end end end end //b_reg always @(posedge clock) begin if(mul_div_mode==`MUL_DIV_MUL_SEL && pre_stop) b_reg <={16'h0000,b[15:0]};//掛け算ならラッチするだけ else begin//ここから割り算 if (!stop_state_reg ) b_reg <=b_reg;//Operationが終わっているなら保持 else if (counter==0 ) begin //最初は、 if (mul_div_sign_ff) begin//符号付なら if (mul_div_word_ff ==`MUL_DIV_WORD_ACCESS && b[15]) b_reg <={-b[15:0],16'h0000};//負数なら正数にして桁合わせ else if (mul_div_word_ff ==`MUL_DIV_BYTE_ACCESS && b[7]) b_reg <={16'h0000, -b[7:0],8'h00}; //負数なら正数にして桁合わせ else if (mul_div_word_ff ==`MUL_DIV_WORD_ACCESS) b_reg <={b[15:0],16'h0000};//符号なしなら桁合わせのみ else b_reg<= {16'h00,b[7:0],8'h00};//符号なしなら桁合わせのみ end else begin if (mul_div_word_ff ==`MUL_DIV_WORD_ACCESS) b_reg <={b[15:0],16'h0000};//符号なしなら桁合わせのみ else b_reg<= {16'h00,b[7:0],8'h00};//符号なしなら桁合わせのみ end end else begin//div 実行中 b_reg <={1'b0,b_reg[31:1]};// b_reg >>=1; end end end //answer_reg always @(posedge clock) begin if(mul_div_mode_ff==`MUL_DIV_MUL_SEL && pre_stop) answer_reg <=0;//掛け算ならラッチするだけ else begin//ここから割り算 if (!stop_state_reg ) answer_reg <=answer_reg;//Operationが終わっているなら保持 else if (counter==0 ) answer_reg<=0; //最初は、ゼロクリア else begin//div 実行中 if (mul_div_word_ff ==`MUL_DIV_WORD_ACCESS && !sum[32] ) begin//if (a_reg >=b_reg) if (finish_operation && (a[31] ^ b[15]) && mul_div_sign_ff ) answer_reg <=-{answer_inc};//商が負なら最後に反転 else if (finish_operation) answer_reg <={answer_inc}; else answer_reg <={answer_inc,1'b0}; // a_reg -= b_reg end else if (mul_div_word_ff ==`MUL_DIV_BYTE_ACCESS && !sum[16] ) begin//if (a_reg >=b_reg) if (finish_operation && (a[15] ^ b[7] ) && mul_div_sign_ff) answer_reg <=0- {answer_inc};//商が負なら最後に反転 else if (finish_operation) answer_reg <=answer_inc; else answer_reg <={answer_inc,1'b0}; end else begin if (finish_operation ) begin if ( (a[31] ^ b[15]) && mul_div_sign_ff && mul_div_word_ff ==`MUL_DIV_WORD_ACCESS) //商が負なら最後に反転 answer_reg <=0-answer_reg; else if ( (a[15] ^ b[7] ) && mul_div_sign_ff && mul_div_word_ff !=`MUL_DIV_WORD_ACCESS)//商が負なら最後に反転 answer_reg <=0-answer_reg; else answer_reg <=answer_reg; end else answer_reg <={answer_reg,1'b0}; // answer_reg <<=1; end end end end assign sum=a_reg-b_reg;//sum はcarry 込み assign answer_inc=answer_reg+1; endmodule |