1. 程式人生 > >最大公約數Stein演算法之verilog實現

最大公約數Stein演算法之verilog實現

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