笔试面试 求输入两个数的最大公因数和最小公倍数

一、原理

1.使用辗转相除法求最大公约数:两个数的最小公约数等于较小的数和两个数之差的最大公约数,因此可以让两个数相减,得到的结果与其中较小的数再相减,直到两个数相等为止;
2.最小公倍数等于两个数的乘积除以最大公约数。

二、代码

//Description:求最大公因数(gcd)和最小公倍数(lcm)
module gcd_lcm
              #(
                parameter DWIDTH=8
              )
              (
               input                            clk,
               input                            rst_n,
               input        [DWIDTH-1:0]        data_a,
               input        [DWIDTH-1:0]        data_b,
               input                            en,
               output  reg  [DWIDTH-1:0]        gcd,
               output  reg  [DWIDTH*2-1:0]      lcm,
               output                           ready,
               output                           data_valid
               );
               
reg     [2:0]           cs;
reg     [2:0]           ns;
reg     [DWIDTH-1:0]    a_buf; 
reg     [DWIDTH-1:0]    b_buf;
reg                     done;
reg     [DWIDTH*2-1:0]  mul;

parameter IDLE=3'b001,
          SUB=3'b010,
          END=3'b100;

always@(posedge clk or negedge rst_n)
if(!rst_n)
 begin
    cs<=IDLE;
 end
else 
 begin
    cs<=ns;
 end
 
always@(*)
 begin
    ns=IDLE;
    case(cs)
        IDLE:
         begin
            if(en)
             begin
                ns=SUB;
             end
            else
             begin
                ns=IDLE;
             end
         end
        SUB:
         begin
            if(a_buf!=b_buf)
             begin
                ns=SUB;
             end
            else
             begin
                ns=END;
             end
         end
         END:
          begin
             ns=IDLE;
          end
        default:ns=IDLE;
    endcase
 end
 
always@(posedge clk or negedge rst_n)
if(!rst_n)
 begin
    a_buf<=0;
    b_buf<=0;
    done<=0;
    gcd<=0;
    lcm<=0;
 end
else case(cs)
 IDLE:
  begin
      a_buf<=data_a;
      b_buf<=data_b;
      mul<=data_a*data_b; 
      done<=0;      
  end
  SUB:
   begin
      if(a_buf>b_buf)
        begin
            a_buf<=a_buf-b_buf;
            b_buf<=b_buf;
        end
      else if(a_buf<b_buf)
       begin
            b_buf<=b_buf-a_buf;
            a_buf<=a_buf;
       end
      else
       begin
            a_buf<=a_buf;
            b_buf<=b_buf;
       end
   end
  END:
    begin
        done<=1'b1;
        gcd<=a_buf;
        lcm<=mul/a_buf;
    end
  default:
    begin 
        a_buf<=0;
        b_buf<=0;
        done<=0;
    end
 endcase
 
 
assign data_valid=done;
assign ready=(cs==IDLE);



endmodule 

三、测试文件

`timescale 1ns/1ps      //时间单位、仿真精度
`define clock_period 20 //系统时钟周期

module gcd_lcm_tb;


//=============================<端口>=======================================
parameter DWIDTH=8;
reg                            clk;
reg                            rst_n;
reg        [DWIDTH-1:0]        data_a;
reg        [DWIDTH-1:0]        data_b;
reg                            en;
wire       [DWIDTH-1:0]        gcd;
wire       [DWIDTH*2-1:0]      lcm;
wire                           ready;
wire                           data_valid;


//=============================<模块例化>===================================

gcd_lcm
              #(
                .DWIDTH(DWIDTH)
              )
       GCD_LCM(
               .clk(clk),
               .rst_n(rst_n),
               .data_a(data_a),
               .data_b(data_b),
               .en(en),
               .gcd(gcd),
               .lcm(lcm),
               .ready(ready),
               .data_valid(data_valid)
               );
                
//==========================<时钟激励>=======================================
initial clk=1;
always# (`clock_period/2) clk=~clk;


//==========================<设计激励信号>===================================
initial begin
rst_n=0;data_a=0;data_b=0;en=0;
#201;rst_n=1;
#100;en=1;data_a=150;data_b=3;
#20;en=0;
@(posedge ready);
#101;en=1;data_a=252;data_b=105;
#20;en=0;
@(posedge ready);
#1000;
$stop;
end
        
endmodule 		


四、Modelsim Tcl脚本

quit -sim
.main clear

vlib ./lib/
vlib ./lib/design/

vmap design ./lib/design/

vlog -work design ./../*.v

vsim -t ns -voptargs=+acc  design.gcd_lcm_tb


add wave -divider {tb}
add wave gcd_lcm_tb/*
add wave -divider {gcd_lcm}
add wave gcd_lcm_tb/GCD_LCM/*

run -all
    原文作者:icrookie
    原文地址: https://blog.csdn.net/weixin_45912567/article/details/108089763
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞