最大公約數Stein演算法之verilog實現
阿新 • • 發佈:2019-02-19
module gcd(
input n_rst,clk,en,
input [7:0] Ain,Bin,
output reg [7:0] gcd_out='b0
);
localparam [1:0] init='b00,compare='b01,calculate='b11,finish='b10;
reg [1:0] cs='b0,ns='b0;
reg load='b0,comp_en='b0,cal_en='b0,out_en='b0,cal_over='b0;
reg [7:0] A_tmp='b0,B_tmp='b0,gcd_tmp='b0,shift_times='b0;
wire [1:0] A_B_LSB;
//three section FSM
//timing sequence part of FSM
always@(negedge n_rst,posedge clk)
if(!n_rst)
cs<=init;
else
if(en)
cs<=ns;
//combination part of FSM
always@(*)
case (cs)
init : ns<=compare;
compare : if (cal_over)
ns<=finish;
else
ns<=calculate;
calculate : ns<=compare;
finish : ns<=init;
default : ns<=init;
endcase
//register output part of FSM
always@(negedge n_rst,posedge clk)
if(!n_rst)
begin load<=1'b0;comp_en<=1'b0;cal_en<=1'b0; end
else
if(en)
case(ns)
init : begin load<=1'b1;comp_en<=1'b0;cal_en<=1'b0;out_en<=1'b0; end
compare : begin load<=1'b0;comp_en<=1'b1;cal_en<=1'b0;out_en<=1'b0; end
calculate : begin load<=1'b0;comp_en<=1'b0;cal_en<=1'b1;out_en<=1'b0; end
finish : begin load<=1'b0;comp_en<=1'b0;cal_en<=1'b0;out_en<=1'b1; end
default : begin load<=1'b0;comp_en<=1'b0;cal_en<=1'b0;out_en<=1'b0; end
endcase
// whether the value is zero or not
always @(negedge n_rst or posedge clk) begin
if (!n_rst) begin
cal_over <= 1'b0;
gcd_tmp <= 'b0;
end
else
if (en) begin
if (comp_en) begin
if (A_tmp=='b0) begin
cal_over <= 1'b1;
gcd_tmp <= B_tmp;
end
else begin
if (B_tmp=='b0) begin
cal_over <= 1'b1;
gcd_tmp <= A_tmp;
end
else begin
if (A_tmp==B_tmp) begin
cal_over <= 1'b1;
gcd_tmp <= A_tmp;
end
else begin
cal_over <= 1'b0;
gcd_tmp <= 'b0;
end
end
end
end
end
end
// calculate the gcd
assign A_B_LSB = {A_tmp[0],B_tmp[0]};//if A_tmp[0] = 0 , A_tmp is even and A_tmp >> 1,also as B_tmp;
always @(negedge n_rst or posedge clk) begin
if (!n_rst) begin
A_tmp <= 'b0;
B_tmp <= 'b0;
shift_times<='b0;
end
else
if (en) begin
if (load) begin// load the initialization values
A_tmp <= Ain;
B_tmp <= Bin;
shift_times<='b0;
end
else begin
if (cal_en) begin
case (A_B_LSB)
2'b00 : begin A_tmp<={1'b0,A_tmp[7:1]};B_tmp<={1'b0,B_tmp[7:1]};
shift_times<={shift_times[6:0],1'b1};end
2'b01 : begin A_tmp<={1'b0,A_tmp[7:1]};B_tmp<=B_tmp;
shift_times<=shift_times;end
2'b10 : begin A_tmp<=A_tmp;B_tmp<={1'b0,B_tmp[7:1]};
shift_times<=shift_times;end
2'b11 : begin if (A_tmp>B_tmp) begin
A_tmp <= A_tmp-B_tmp;B_tmp <= B_tmp;
end
else begin
B_tmp <= B_tmp-A_tmp;A_tmp <= A_tmp;
end
shift_times<=shift_times;
end
default : begin A_tmp<=A_tmp;B_tmp<=B_tmp;shift_times<=shift_times;end
endcase
end
end
end
end
// output result , if enable
always @(negedge n_rst or posedge clk) begin
if (!n_rst)
gcd_out <= 'b0;
else
if (en) begin
if (out_en)
if(cal_over)
case (shift_times)
8'h00 : gcd_out <= gcd_tmp;
8'h01 : gcd_out <= {gcd_tmp[6:0],1'b0};
8'h03 : gcd_out <= {gcd_tmp[5:0],2'b0};
8'h07 : gcd_out <= {gcd_tmp[4:0],3'b0};
8'h0f : gcd_out <= {gcd_tmp[3:0],4'b0};
8'h1f : gcd_out <= {gcd_tmp[2:0],5'b0};
8'h3f : gcd_out <= {gcd_tmp[1:0],6'b0};
8'h7f : gcd_out <= {gcd_tmp[0],7'b0};
default : gcd_out <= gcd_tmp;
endcase
else begin
gcd_out <= gcd_out;
end
end
end
endmodule
input n_rst,clk,en,
input [7:0] Ain,Bin,
output reg [7:0] gcd_out='b0
);
localparam [1:0] init='b00,compare='b01,calculate='b11,finish='b10;
reg [1:0] cs='b0,ns='b0;
reg load='b0,comp_en='b0,cal_en='b0,out_en='b0,cal_over='b0;
reg [7:0] A_tmp='b0,B_tmp='b0,gcd_tmp='b0,shift_times='b0;
wire [1:0] A_B_LSB;
//three section FSM
//timing sequence part of FSM
always@(negedge n_rst,posedge clk)
if(!n_rst)
cs<=init;
else
if(en)
cs<=ns;
//combination part of FSM
always@(*)
case (cs)
init : ns<=compare;
compare : if (cal_over)
ns<=finish;
else
ns<=calculate;
calculate : ns<=compare;
finish : ns<=init;
default : ns<=init;
endcase
//register output part of FSM
always@(negedge n_rst,posedge clk)
if(!n_rst)
begin load<=1'b0;comp_en<=1'b0;cal_en<=1'b0; end
else
if(en)
case(ns)
init : begin load<=1'b1;comp_en<=1'b0;cal_en<=1'b0;out_en<=1'b0; end
compare : begin load<=1'b0;comp_en<=1'b1;cal_en<=1'b0;out_en<=1'b0; end
calculate : begin load<=1'b0;comp_en<=1'b0;cal_en<=1'b1;out_en<=1'b0; end
finish : begin load<=1'b0;comp_en<=1'b0;cal_en<=1'b0;out_en<=1'b1; end
default : begin load<=1'b0;comp_en<=1'b0;cal_en<=1'b0;out_en<=1'b0; end
endcase
// whether the value is zero or not
always @(negedge n_rst or posedge clk) begin
if (!n_rst) begin
cal_over <= 1'b0;
gcd_tmp <= 'b0;
end
else
if (en) begin
if (comp_en) begin
if (A_tmp=='b0) begin
cal_over <= 1'b1;
gcd_tmp <= B_tmp;
end
else begin
if (B_tmp=='b0) begin
cal_over <= 1'b1;
gcd_tmp <= A_tmp;
end
else begin
if (A_tmp==B_tmp) begin
cal_over <= 1'b1;
gcd_tmp <= A_tmp;
end
else begin
cal_over <= 1'b0;
gcd_tmp <= 'b0;
end
end
end
end
end
end
// calculate the gcd
assign A_B_LSB = {A_tmp[0],B_tmp[0]};//if A_tmp[0] = 0 , A_tmp is even and A_tmp >> 1,also as B_tmp;
always @(negedge n_rst or posedge clk) begin
if (!n_rst) begin
A_tmp <= 'b0;
B_tmp <= 'b0;
shift_times<='b0;
end
else
if (en) begin
if (load) begin// load the initialization values
A_tmp <= Ain;
B_tmp <= Bin;
shift_times<='b0;
end
else begin
if (cal_en) begin
case (A_B_LSB)
2'b00 : begin A_tmp<={1'b0,A_tmp[7:1]};B_tmp<={1'b0,B_tmp[7:1]};
shift_times<={shift_times[6:0],1'b1};end
2'b01 : begin A_tmp<={1'b0,A_tmp[7:1]};B_tmp<=B_tmp;
shift_times<=shift_times;end
2'b10 : begin A_tmp<=A_tmp;B_tmp<={1'b0,B_tmp[7:1]};
shift_times<=shift_times;end
2'b11 : begin if (A_tmp>B_tmp) begin
A_tmp <= A_tmp-B_tmp;B_tmp <= B_tmp;
end
else begin
B_tmp <= B_tmp-A_tmp;A_tmp <= A_tmp;
end
shift_times<=shift_times;
end
default : begin A_tmp<=A_tmp;B_tmp<=B_tmp;shift_times<=shift_times;end
endcase
end
end
end
end
// output result , if enable
always @(negedge n_rst or posedge clk) begin
if (!n_rst)
gcd_out <= 'b0;
else
if (en) begin
if (out_en)
if(cal_over)
case (shift_times)
8'h00 : gcd_out <= gcd_tmp;
8'h01 : gcd_out <= {gcd_tmp[6:0],1'b0};
8'h03 : gcd_out <= {gcd_tmp[5:0],2'b0};
8'h07 : gcd_out <= {gcd_tmp[4:0],3'b0};
8'h0f : gcd_out <= {gcd_tmp[3:0],4'b0};
8'h1f : gcd_out <= {gcd_tmp[2:0],5'b0};
8'h3f : gcd_out <= {gcd_tmp[1:0],6'b0};
8'h7f : gcd_out <= {gcd_tmp[0],7'b0};
default : gcd_out <= gcd_tmp;
endcase
else begin
gcd_out <= gcd_out;
end
end
end
endmodule