题目如上
解题思路:先利用辗转相除法求这个两个数的最大公约数,然后最小公倍数=两数乘积/最大公约数
所以问题的核心就转换为:
1.Verilog实现辗转相除法
2.Verilog实现除法
程序如下
求最小公倍数的程序如下:
module LCM_cal(a,b,en,clk,rst_n,lcm,lcm_val);
input [7:0] a,b;
input en;
input clk,rst_n;
output [15:0]lcm;
output reg lcm_val;
wire [7:0] gcd;
wire gcd_valid;
GCD_cal my_gcd_cal(.en(en),.rst_n(rst_n),.clk(clk),.daA(a),.daB(b),.gcd(gcd),.gcd_valid(gcd_valid));
reg [15:0] gcd_reg;
always@(posedge clk or negedge rst_n)
begin
if(rst_n==1'b0)
gcd_reg<=16'b0;
else if(gcd_valid==1'b1)
gcd_reg<={{8{1'b0}},gcd};
end
always@(posedge clk or negedge rst_n)
begin
if(rst_n==1'b0)
lcm_val<=1'b0;
else if(gcd_valid==1'b1)
lcm_val<=1'b1;
else
lcm_val<=1'b0;
end
reg [15:0] product;
wire [15:0] non;
always@(posedge clk or negedge rst_n)
begin
if(rst_n==1'b0)
product<=16'b0;
else if(en==1'b1)
product<=a*b;
else
product<=product;
end
div_cal #(.width(16)) my_div_cal
(.a(product),
.b(gcd_reg),
.shang(lcm),
.yushu(non)
);
endmodule
仿真结果如下:
verilog 实现除法的程序如下:
module div_cal
#(
parameter width = 8
)
(
input[width-1:0] a,
input[width-1:0] b,
output reg [width-1:0] shang,
output reg [width-1:0] yushu
);
reg[width-1:0] tempa;
reg[width-1:0] tempb;
reg[2*width-1:0] temp_a;
reg[2*width-1:0] temp_b;
integer i;
always @(*)
begin
temp_a = {{width{1'b0}},a};
temp_b = {b,{width{1'b0}}};
for(i = 0;i < width;i = i + 1)
begin
temp_a = temp_a<<1'b1;
if(temp_a[2*width-1:width] >= b)
temp_a = temp_a - temp_b + 1'b1;
else
temp_a = temp_a;
end
shang <= temp_a[width-1:0];
yushu <= temp_a[2*width-1:width];
end
endmodule
verilog实现辗转相除法的程序如下:
module GCD_cal(en,rst_n,clk,daA,daB,gcd,gcd_valid);
input en; //数据有效,开始计算最小公约数
input clk;
input rst_n;
input [7:0]daA;
input [7:0]daB;
output reg [7:0]gcd;
output reg gcd_valid;
parameter idle=2'b00,div=2'b01,cal=2'b10,out=2'b11;
reg [1:0] state;
reg [7:0] tempa,tempb;
reg en_reg;
always@(posedge clk or negedge rst_n)
begin
if(rst_n==1'b0)
begin
tempa<=8'b0000_0000;
tempb<=8'b0000_0000;
end
else if(en==1'b1)
begin
if(daA>daB)
begin
tempa<=daA;
tempb<=daB;
end
else
begin
tempa<=daB;
tempb<=daA;
end
end
else
begin
tempa<=tempa;
tempb<=tempb;
end
end
reg en_test;
always@(posedge clk or negedge rst_n)
begin
if(rst_n==1'b0)
begin
en_reg<=1'b0;
en_test<=1'b0;
end
else
begin
en_reg<=en;
en_test<=en_reg;
end
end
reg[7:0] a,b;
wire [7:0] yushu,shang;
always@(posedge clk or negedge rst_n)
begin
if(rst_n==1'b0)
begin
gcd<=8'b0000_0000;
a<=8'b0000_0000;
b<=8'b0000_0000;
state<=idle;
gcd_valid<=1'b0;
end
else
begin
case (state)
idle: begin
gcd_valid<=1'b0;
if(en_test==1'b1)
state<=div;
else
state<=idle;
end
div: begin
state<=cal;
a<=tempa;
b<=tempb;
end
cal: begin
if(yushu==8'b0000_0000)
state<=out;
else
begin
a<=b;
b<=yushu;
state<=cal;
end
end
out: begin
state<=idle;
gcd<=b;
gcd_valid<=1'b1;
end
default: state<=idle;
endcase
end
end
div_cal #(.width(8)) inst(.a(a), .b(b),.shang(shang),.yushu(yushu));
endmodule