aboutsummaryrefslogblamecommitdiff
path: root/rtl/multiword/mw_comparator.v
blob: b97a6cf3200b83549674bc90ac0f3a9bc706ecf6 (plain) (tree)



























































































































































































































                                                                                                                                                                                                   
//------------------------------------------------------------------------------
//
// mw_comparator.v
// -----------------------------------------------------------------------------
// Multi-word comparator.
//
// Authors: Pavel Shatov
//
// Copyright (c) 2015-2016, NORDUnet A/S
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// - Redistributions of source code must retain the above copyright notice,
//   this list of conditions and the following disclaimer.
//
// - Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// - Neither the name of the NORDUnet nor the names of its contributors may be
//   used to endorse or promote products derived from this software without
//   specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
//------------------------------------------------------------------------------

module mw_comparator
	(
		clk, rst_n,
		ena, rdy,
		xy_addr, x_din, y_din,
		cmp_l, cmp_e, cmp_g
	);
	
		
		//
		// Parameters
		//
	parameter	WORD_COUNTER_WIDTH	= 3;
	parameter	OPERAND_NUM_WORDS		= 8;
	
	
		//
		// Handy Numbers
		//
	localparam	[WORD_COUNTER_WIDTH-1:0]	WORD_INDEX_ZERO	= 0;
	localparam	[WORD_COUNTER_WIDTH-1:0]	WORD_INDEX_LAST	= OPERAND_NUM_WORDS - 1;
	
	
		//
		// Handy Functions
		//
	function	[WORD_COUNTER_WIDTH-1:0]	WORD_INDEX_PREV_OR_LAST;
		input	[WORD_COUNTER_WIDTH-1:0]	WORD_INDEX_CURRENT;
		begin
			WORD_INDEX_PREV_OR_LAST = (WORD_INDEX_CURRENT > WORD_INDEX_ZERO) ?
				WORD_INDEX_CURRENT - 1'b1 : WORD_INDEX_LAST;
		end
	endfunction
	

		//
		// Ports
		//
	input		wire											clk;			// system clock
	input		wire											rst_n;		// active-low async reset
	
	input		wire											ena;			// enable input
	output	wire											rdy;			// ready output
		
	output	wire	[WORD_COUNTER_WIDTH-1:0]		xy_addr;		// address of current X and Y words
	input		wire	[                32-1:0]		x_din;		// current X word
	input		wire	[                32-1:0]		y_din;		// current Y word
	
	output	wire											cmp_l;		// X < Y ?
	output	wire											cmp_e;		// X = Y ?
	output	wire											cmp_g;		// X > Y ?
	
	
		//
		// Word Indices
		//
	reg	[WORD_COUNTER_WIDTH-1:0]	index_xy;
	
	reg										reg_cmp_l;
	reg										reg_cmp_e;
	reg										reg_cmp_g;
	
	
		//
		// Output Mapping
		//
	assign xy_addr	= index_xy;
	
	assign cmp_l = reg_cmp_l;
	assign cmp_e = reg_cmp_e;
	assign cmp_g = reg_cmp_g;


		//
		// FSM
		//
	localparam FSM_SHREG_WIDTH = 1 * OPERAND_NUM_WORDS + 3;
	
	reg	[FSM_SHREG_WIDTH-1:0]	fsm_shreg;
	
	assign rdy = fsm_shreg[0];
	
	wire [OPERAND_NUM_WORDS-1:0] fsm_shreg_dec_index_xy	= fsm_shreg[FSM_SHREG_WIDTH - (0 * OPERAND_NUM_WORDS + 1) : FSM_SHREG_WIDTH - (1 * OPERAND_NUM_WORDS + 0)];
	wire [OPERAND_NUM_WORDS-1:0] fsm_shreg_calc_leg			= fsm_shreg[FSM_SHREG_WIDTH - (0 * OPERAND_NUM_WORDS + 3) : FSM_SHREG_WIDTH - (1 * OPERAND_NUM_WORDS + 2)];
	wire                         fsm_shreg_calc_leg_last	= fsm_shreg[FSM_SHREG_WIDTH - (1 * OPERAND_NUM_WORDS + 2)];
	
	wire dec_index_xy		= |fsm_shreg_dec_index_xy;
	wire calc_leg			= |fsm_shreg_calc_leg;
	wire calc_leg_last	=  fsm_shreg_calc_leg_last;

	
	always @(posedge clk or negedge rst_n)
		//
		if (rst_n == 1'b0)
			//
			fsm_shreg <= {{FSM_SHREG_WIDTH-1{1'b0}}, 1'b1};
			//
		else begin
			//
			if (rdy)	fsm_shreg <= {ena, {FSM_SHREG_WIDTH-2{1'b0}}, ~ena};
			//
			else		fsm_shreg <= {1'b0, fsm_shreg[FSM_SHREG_WIDTH-1:1]};
			//
		end


		//
		// Word Index Increment Logic
		//
	always @(posedge clk)
		//
		if (rdy)						index_xy <= WORD_INDEX_LAST;
		else if (dec_index_xy)	index_xy <= WORD_INDEX_PREV_OR_LAST(index_xy);
		
		
		//
		// 32-bit Subtractor
		//	
	wire	[31: 0]	sub32_d_out;
	wire				sub32_b_in;
	wire				sub32_b_out;
	
	subtractor32_wrapper subtractor32_inst
	(
		.clk		(clk),
		
		.a			(x_din),
		.b			(y_din),
		
		.d			(sub32_d_out),
		
		.b_in		(sub32_b_in),
		.b_out	(sub32_b_out)
	);
	
	
		//
		// Borrow Masking Logic
		//
	reg	sub32_b_mask;
	
	always @(posedge clk)
		//
		sub32_b_mask <= (index_xy  == WORD_INDEX_LAST) ? 1'b1 : 1'b0;
		
	assign sub32_b_in = sub32_b_out & ~sub32_b_mask;
		
		//
		// Output Logic
		//
	wire	cmp_unresolved = !(cmp_l || cmp_g);
	
	wire	cmp_borrow_is_set				= (sub32_b_out ==  1'b1) ? 1'b1 : 1'b0;
	wire	cmp_difference_is_nonzero	= (sub32_d_out != 32'd0) ? 1'b1 : 1'b0;
	
	always @(posedge clk)
		//
		if (rdy) begin
			//
			if (ena) begin
				//
				reg_cmp_l	<= 1'b0;
				reg_cmp_e	<= 1'b0;
				reg_cmp_g	<= 1'b0;
				//
			end
			//
		end else if (cmp_unresolved && calc_leg) begin
			//
			if ( cmp_borrow_is_set)																	reg_cmp_l <= 1'b1;
			if (!cmp_borrow_is_set &&  cmp_difference_is_nonzero)							reg_cmp_g <= 1'b1;
			if (!cmp_borrow_is_set && !cmp_difference_is_nonzero && calc_leg_last)	reg_cmp_e <= 1'b1;
			//
		end
		
	
endmodule


//------------------------------------------------------------------------------
// End-of-File
//------------------------------------------------------------------------------