`timescale 1ns / 1ps
module modinv_helper_invert_compare
(
clk, rst_n,
ena, rdy,
u_addr, u_din,
v_addr, v_din,
u_gt_v, v_eq_1,
u_is_even, v_is_even
);
//
// Parameters
//
parameter BUFFER_NUM_WORDS = 9;
parameter BUFFER_ADDR_BITS = 4;
//
// clog2
//
`include "..\modinv_clog2.v"
//
// Constants
//
localparam PROC_NUM_CYCLES = 1 * BUFFER_NUM_WORDS + 10;
localparam PROC_CNT_BITS = clog2(PROC_NUM_CYCLES);
//
// Ports
//
input wire clk;
input wire rst_n;
input wire ena;
output wire rdy;
output wire [BUFFER_ADDR_BITS-1:0] u_addr;
output wire [BUFFER_ADDR_BITS-1:0] v_addr;
input wire [ 32-1:0] u_din;
input wire [ 32-1:0] v_din;
output wire u_gt_v;
output wire v_eq_1;
output wire u_is_even;
output wire v_is_even;
//
// Counter
//
reg [PROC_CNT_BITS-1:0] proc_cnt;
wire [PROC_CNT_BITS-1:0] proc_cnt_max = PROC_NUM_CYCLES - 1;
wire [PROC_CNT_BITS-1:0] proc_cnt_zero = {PROC_CNT_BITS{1'b0}};
wire [PROC_CNT_BITS-1:0] proc_cnt_next = (proc_cnt < proc_cnt_max) ?
proc_cnt + 1'b1 : proc_cnt_zero;
//
// Addresses
//
reg [BUFFER_ADDR_BITS-1:0] addr_in;
wire [BUFFER_ADDR_BITS-1:0] addr_in_last = BUFFER_NUM_WORDS - 1;
wire [BUFFER_ADDR_BITS-1:0] addr_in_zero = {BUFFER_ADDR_BITS{1'b0}};
wire [BUFFER_ADDR_BITS-1:0] addr_in_prev = (addr_in > addr_in_zero) ?
addr_in - 1'b1 : addr_in_last;
assign u_addr = addr_in;
assign v_addr = addr_in;
//
// Ready Flag
//
assign rdy = (proc_cnt == proc_cnt_zero);
//
// Address Decrement Logic
//
wire dec_addr_in;
wire [PROC_CNT_BITS-1:0] cnt_dec_addr_in_start = 0 * BUFFER_NUM_WORDS + 1;
wire [PROC_CNT_BITS-1:0] cnt_dec_addr_in_stop = 1 * BUFFER_NUM_WORDS + 0;
assign dec_addr_in = (proc_cnt >= cnt_dec_addr_in_start) && (proc_cnt <= cnt_dec_addr_in_stop);
always @(posedge clk)
//
if (rdy) addr_in <= addr_in_last;
else if (dec_addr_in) addr_in <= addr_in_prev;
//
// Comparison Stage Flags
//
wire calc_leg;
wire calc_leg_final;
wire calc_parity;
wire [PROC_CNT_BITS-1:0] cnt_calc_leg_start = 0 * BUFFER_NUM_WORDS + 3;
wire [PROC_CNT_BITS-1:0] cnt_calc_leg_stop = 1 * BUFFER_NUM_WORDS + 2;
wire [PROC_CNT_BITS-1:0] cnt_calc_parity = 1 * BUFFER_NUM_WORDS + 1;
assign calc_leg = (proc_cnt >= cnt_calc_leg_start) && (proc_cnt <= cnt_calc_leg_stop);
assign calc_leg_final = (proc_cnt == cnt_calc_leg_stop);
assign calc_parity = (proc_cnt == cnt_calc_parity);
//
// Dummy Input
//
reg sub32_din_1_lsb;
wire [31: 0] sub32_din_1 = {{31{1'b0}}, sub32_din_1_lsb};
always @(posedge clk)
//
sub32_din_1_lsb <= (addr_in == addr_in_zero) ? 1'b1 : 1'b0;
//
// Subtractor (u - v)
//
wire [31: 0] sub32_u_minus_v_difference_out;
wire sub32_u_minus_v_borrow_in;
wire sub32_u_minus_v_borrow_out;
subtractor32_wrapper sub32_u_minus_v
(
.clk (clk),
.a (u_din),
.b (v_din),
.d (sub32_u_minus_v_difference_out),
.b_in (sub32_u_minus_v_borrow_in),
.b_out (sub32_u_minus_v_borrow_out)
);
//
// Subtractor (v - 1)
//
wire [31: 0] sub32_v_minus_1_difference_out;
wire sub32_v_minus_1_borrow_in;
wire sub32_v_minus_1_borrow_out;
subtractor32_wrapper sub32_v_minus_1
(
.clk (clk),
.a (v_din),
.b (sub32_din_1),
.d (sub32_v_minus_1_difference_out),
.b_in (sub32_v_minus_1_borrow_in),
.b_out (sub32_v_minus_1_borrow_out)
);
//
// Borrow Masking Logic
//
reg mask_borrow;
always @(posedge clk)
//
mask_borrow <= ((proc_cnt > cnt_dec_addr_in_start) && (proc_cnt <= cnt_dec_addr_in_stop)) ?
1'b0 : 1'b1;
assign sub32_u_minus_v_borrow_in = sub32_u_minus_v_borrow_out & ~mask_borrow;
assign sub32_v_minus_1_borrow_in = sub32_v_minus_1_borrow_out & ~mask_borrow;
//
// Comparison Logic
//
reg cmp_u_v_l;
reg cmp_u_v_e;
reg cmp_u_v_g;
reg cmp_v_1_l;
reg cmp_v_1_e;
reg cmp_v_1_g;
wire cmp_unresolved_u_v = !(cmp_u_v_l || cmp_u_v_g);
wire cmp_unresolved_v_1 = !(cmp_v_1_l || cmp_v_1_g);
wire cmp_u_v_borrow_is_set = (sub32_u_minus_v_borrow_out == 1'b1) ? 1'b1 : 1'b0;
wire cmp_u_v_difference_is_nonzero = (sub32_u_minus_v_difference_out != 32'd0) ? 1'b1 : 1'b0;
wire cmp_v_1_borrow_is_set = (sub32_v_minus_1_borrow_out == 1'b1) ? 1'b1 : 1'b0;
wire cmp_v_1_difference_is_nonzero = (sub32_v_minus_1_difference_out != 32'd0) ? 1'b1 : 1'b0;
reg u_is_even_reg;
reg v_is_even_reg;
always @(posedge clk)
//
if (rdy) begin
//
if (ena) begin
//
cmp_u_v_l <= 1'b0;
cmp_u_v_e <= 1'b0;
cmp_u_v_g <= 1'b0;
//
cmp_v_1_l <= 1'b0;
cmp_v_1_e <= 1'b0;
cmp_v_1_g <= 1'b0;
//
u_is_even_reg <= 1'bX;
v_is_even_reg <= 1'bX;
//
end
//
end else begin
//
// parity
//
if (calc_parity) begin
u_is_even_reg <= ~u_din[0];
v_is_even_reg <= ~v_din[0];
end
//
// u <> v
//
if (cmp_unresolved_u_v && calc_leg) begin
//
if (cmp_u_v_borrow_is_set)
cmp_u_v_l <= 1'b1;
//
if (!cmp_u_v_borrow_is_set && cmp_u_v_difference_is_nonzero)
cmp_u_v_g <= 1'b1;
//
if (!cmp_u_v_borrow_is_set && !cmp_u_v_difference_is_nonzero && calc_leg_final)
cmp_u_v_e <= 1'b1;
//
end
//
// v <> 1
//
if (cmp_unresolved_v_1 && calc_leg) begin
//
if (cmp_v_1_borrow_is_set)
cmp_v_1_l <= 1'b1;
//
if (!cmp_v_1_borrow_is_set && cmp_v_1_difference_is_nonzero)
cmp_v_1_g <= 1'b1;
//
if (!cmp_v_1_borrow_is_set && !cmp_v_1_difference_is_nonzero && calc_leg_final)
cmp_v_1_e <= 1'b1;
//
end
//
end
//
// Output Flags
//
assign u_gt_v = !cmp_u_v_l && !cmp_u_v_e && cmp_u_v_g;
assign v_eq_1 = !cmp_v_1_l && cmp_v_1_e && !cmp_v_1_g;
assign u_is_even = u_is_even_reg;
assign v_is_even = v_is_even_reg;
//
// Primary Counter Logic
//
always @(posedge clk or negedge rst_n)
//
if (rst_n == 1'b0) proc_cnt <= proc_cnt_zero;
else begin
if (!rdy) proc_cnt <= proc_cnt_next;
else if (ena) proc_cnt <= proc_cnt_next;
end
endmodule