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
|