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