首先可以采用辗转相除法或者相减法求解最大公约数MCD;
然后利用A* B=MCD* LCM,求解最小公倍数;
其中辗转相减法和除法运算可采用状态机的方式实现。
除法部分原理参见前面的博客
module lcm_mcd #(
parameter DATA = 8
)(
input clk,
input rst_n,
input [DATA-1:0] A,
input [DATA-1:0] B,
input vld_in,
output wire [DATA*2-1:0] lcm_out,
output wire [DATA-1:0] mcd_out,
output wire vld_out,
output wire readr
);
reg [DATA*2-1:0] mcd,a_buf,b_buf;
reg [DATA*2-1:0] mul_buf;
reg mcd_vld;
reg [1:0] cur_st,nxt_st;
parameter IDLE = 2'b00;
parameter S0 = 2'b01;
parameter S1 = 2'b10;
parameter S2 = 2'b11;
//assign ready = (cur_st==IDLE) ? 1'b1 : 1'b0;
always @ (posedge clk or negedge rst_n) begin
if(!rst) begin
cur_st <= IDLE;
end
else begin
cur_st <= nxt_st;
end
end
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
nxt_st <= IDLE;
mcd <= 'd0;
mcd_vld <= 'd0;
a_buf <= 'd0;
b_buf <= 'd0;
mul_buf <= 'd0;
end
else begin
case(cur_st)
ILDE : if(vld_in) begin
a_buf <= A;
b_buf <= B;
nxt_st <= S0;
mul_buf <= A*B;
mcd <= 'd0;
mcd_vld <= 'd0;
end
else begin
nxt_st <= IDLE;
mcd_vld <= 'd0;
end
S0 : if(a_buf!=b_buf) begin
if(a_buf>b_buf) begin
a_buf <= a_buf - b_buf;
b_buf <= b_buf;
end
else begin
b_buf <= b_buf - a_buf;
a_buf <= a_buf;
end
nxt_st <= S0;
end
else begin
nxt_st <= S1;
end
S1 : begin
mcd <= b_buf;
mcd_vld <= 1'b1;
nxt_st <= IDLE;
end
default : nxt_st <= IDLE;
endcase
end
end
div #(
.DATA(DATA*2)
)div_inst (
.clk(clk),
.rst_n(rst_n),
.vld_in(mcd_vld),
.ready(ready),
.dividend(mul_buf),
.divisor(mcd),
.quotient(lcm_out),
.remainder(),
.vld_out(vld_out)
);
assign mcd_out = mcd;
endmodule
module div #(
parameter DATA = 8
)(
input clk,
input rst,
input vld_in,
output wire ready,
input [DATA-1:0] dividend,
input [DATA-1:0] divisor,
output wire [DATA-1:0] quotient,
output wire [DATA-1:0] remainder,
output wire vld_out
);
reg [DATA*2-1:0] dividend_e;
reg [DATA*2-1:0] divisor_e;
reg [DATA-1:0] quotient;
reg [DATA-1:0] remainder_e;
reg [DATA-1:0] count;
reg [1:0] cur_st,nxt_st;
parameter IDLE = 2'b00,
SUB = 2'b01,
SHIFT = 2'b10,
DONE = 2'b11;
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
dividend_e <= 'd0;
divisor_e <= 'd0;
quotient_e <= 'd0;
remainder <= 'd0;
count <= 'd0;
cur_st <= IDLE;
end
else begin
case(cur_st)
IDLE : begin
dividend_e <= {{DATA{1'b0}},dividend};
divisor_e <= {divisor,{DATA{1'b0}}};
if(vld_in)
cur_st <= SUB;
else
cur_st <= IDLE;
end
SUB : begin
if(dividend_e>=divisor_e) begin
quotiend_e <= {quotiend_e[DATA-2],1'b1};
dividend_e <= dividend_e - divisor_e;
end
else begin
quotient_e <= {quotient_e[DATA_W-2:0],1'b0};
dividend_e <= dividend_e;
end
cur_st <= SHIFT;
end
SHIFT : begin
if(count<DATA) begin
cur_st <= SUB;
dividend_e <= dividend_e << 1;
count <= count + 1'b1;
end
else begin
cur_St <= DONE;
remainder_e <= dividend_e[DATA*2-1:DATA];
end
end
DONE : begin
count <= 0;
cur_st <= IDLE;
end
default : begin
count <= 0;
cur_st <= IDLE;
end
endcase
end
end
assign quotient = quotient_e;
assign remainder = remainder_e;
assign ready=(cur_st==IDLE)?1'b1:1'b0;
assign vld_out=(cur_st==DONE)?1'b1:1'b0;
endmodule