A descrição nada mais é do que uma implementação de GCD utilizando o algoritmo de Euclides, mas usando a diferença ao invés do módulo:
- Código: Selecionar todos
module gcd_engine (
input wire clk, reset,
input wire start,
input wire [8:0] a_in, b_in,
output wire gcd_done_tick, ready,
output wire [8:0] r
);
// symbolic state declaration:
localparam[1:0]
idle = 2'b01,
op = 2'b10;
// signal declaration:
reg [1:0] state_reg, state_next;
reg [8:0] a_reg, a_next, b_reg, b_next;
reg [4:0] n_reg, n_next;
reg gcd_done;
// Body:
// FSMD state and data registers:
always @(posedge clk, posedge reset) begin
if(reset) begin
state_reg <= idle;
a_reg <= 0;
b_reg <= 0;
n_reg <= 0;
end else begin
state_reg <= state_next;
a_reg <= a_next;
b_reg <= b_next;
n_reg <= n_next;
end
end
// next-state logic and data path functional unit:
always @(*) begin
a_next = a_reg;
b_next = b_reg;
n_next = n_reg;
state_next = state_reg;
gcd_done = 1'b0;
case(state_reg)
idle:
if(start) begin
a_next = a_in;
b_next = b_in;
n_next = 0;
state_next = op;
end
op:
if(a_reg == b_reg) begin
state_next = idle;
gcd_done = 1'b1;
a_next = a_reg << n_reg;
end else
if(~a_reg[0]) begin
a_next = {1'b0, a_reg[8:1]};
if(~b_reg[0]) begin
b_next = {1'b0, b_reg[8:1]};
n_next = n_reg + 1;
end
end else
if(~b_reg[0])
b_next = {1'b0, b_reg[8:1]};
else
if(a_reg > b_reg)
a_next = a_reg - b_reg;
else
b_next = b_reg - a_reg;
endcase
end
// output:
assign ready = (state_reg == idle);
assign r = a_reg;
assign gcd_done_tick = gcd_done;
endmodule
Tentei fazer um testbench mas o resultado não saiu como esperado:
- Código: Selecionar todos
// `timescale <unit>/<precision>
`timescale 1ns/100ps
module gcd_tb();
reg clk, rst, start;
reg [9:0]i,j;
wire [8:0]y;
wire done_tick, ready;
// Instantiate the Device Under Test (DUT):
gcd_engine gcd_engine_dut0(clk, rst, start, i, j, done_tick, ready, y);
// Clock:
always begin
#10 clk = ~clk;
end
// Initial sequential block simulation:
initial begin
rst = 1'b1;
clk = 1'b0;
#20 rst = 1'b0;
#5 start = 1'b1;
i = 10;
j = 14;
#5 start = 1'b0;
end
always @(posedge clk) begin
@(ready == 1'b1);
wait(ready == 1'b0);
#5 start = 1'b0;
j = j + 1;
if(j > 10) begin
i = i + 1;
j = 1;
if(i > 15) begin
i = 1;
$finish;
end
end
#5 start = 1'b1;
//wait(ready == 1'b0);
@(done_tick == 1'b1);
$display("%d %d %d", i, j, y);
end
initial begin
$dumpfile("gcd_tb.vcd");
$dumpvars;
end
endmodule
Sei que o algoritmo e a implementação do mesmo na descrição estão corretos, pois foi extraído do livro do Pong Chu. O que está errado é o meu TestBench.