module gcd_dpath #( parameter width = 16 )
( input clock,
input A_en, B_en, A_mux_sel, B_mux_sel, out_mux_sel,
input [width-1:0] A_in, B_in,
output B_zero, A_lt_B,
output [width-1:0] Y );
reg [width-1:0] A, B;
assign Y = A;
wire [width-1:0] out = ( out_mux_sel ) ? B : A - B;
wire [width-1:0] A_next = ( A_mux_sel ) ? out : A_in;
wire [width-1:0] B_next = ( B_mux_sel ) ? A : B_in;
wire B_zero = ( B == 0 );
wire A_lt_B = ( A < B );
always @( posedge clock )
begin
if ( A_en )
A <= A_next;
if ( B_en )
B <= B_next;
end
endmodule
module gcd_ctrl ( input clock, reset, go,
input B_zero, A_lt_B,
output A_en, B_en, A_mux_sel, B_mux_sel, out_mux_sel,
output done );
reg running = 0;
always @( posedge clock )
begin
if ( go )
running <= 1;
else if ( done )
running <= 0;
end
reg [5:0] ctrl_sig;
assign { A_en, B_en, A_mux_sel, B_mux_sel, out_mux_sel, done } = ctrl_sig;
always @(*)
begin
if ( !running ) ctrl_sig = 6'b11_00x_0;
else if ( A_lt_B ) ctrl_sig = 6'b11_111_0;
else if ( !B_zero ) ctrl_sig = 6'b10_1x0_0;
else ctrl_sig = 6'b00_xxx_1;
end
endmodule
module gcd_rtl #( parameter width = 16 )
( input clock,
input reset,
input go,
input [width-1:0] A_in, B_in,
output done,
output [width-1:0] Y );
wire B_zero, A_lt_B, A_en, B_en, A_mux_sel, B_mux_sel, out_mux_sel;
gcd_dpath #( .width(width) )
the_gcd_dpath( .clock(clock), .A_en(A_en), .B_en(B_en),
.A_mux_sel(A_mux_sel), .B_mux_sel(B_mux_sel),
.out_mux_sel(out_mux_sel),
.A_in(A_in), .B_in(B_in), .B_zero(B_zero),
.A_lt_B(A_lt_B), .Y(Y) );
gcd_ctrl the_gcd_ctrl( .clock(clock), .reset(reset), .go(go),
.B_zero(B_zero), .A_lt_B(A_lt_B),
.A_en(A_en), .B_en(B_en),
.A_mux_sel(A_mux_sel), .B_mux_sel(B_mux_sel),
.out_mux_sel(out_mux_sel),
.done(done) );
endmodule
module gcd_test;
parameter width = 32;
reg clock = 0;
reg reset = 0;
reg go = 0;
reg [width-1:0] A_in, B_in;
wire done;
wire [width-1:0] Y;
always #10 clock = ~clock;
gcd_rtl #(.width(width))
gcd_unit( .clock(clock), .reset(reset), .go(go),
.A_in(A_in), .B_in(B_in), .done(done), .Y(Y) );
initial
begin
$vcdpluson(0);
A_in = 27;
B_in = 15;
$value$plusargs("a-in=%d",A_in);
$value$plusargs("b-in=%d",B_in);
#5 reset = 1;
#20 reset = 0;
#20 go = 1;
#20 go = 0;
end
always @( done )
begin
if ( done )
begin
#15;
$display(" a-in = %d", A_in );
$display(" b-in = %d", B_in );
$display(" gcd-out = %d", Y );
$finish;
end
end
endmodule