aboutsummaryrefslogblamecommitdiff
path: root/rtl/modular/modular_invertor/helper/modinv_helper_invert_update.v
blob: ede2fc100b379181f29d4cc3647b81062e8751f8 (plain) (tree)
































































































































































































































































                                                                                                                                                   
`timescale 1ns / 1ps

module modinv_helper_invert_update
  (
   clk, rst_n,
   ena, rdy,

   u_gt_v, v_eq_1,
   u_is_even, v_is_even,

   r_addr, r_wren, r_dout,
   s_addr, s_wren, s_dout,
   u_addr, u_wren, u_dout,
   v_addr, v_wren, v_dout,

   r_dbl_addr,          r_dbl_din,
   s_dbl_addr,          s_dbl_din,
   r_plus_s_addr,       r_plus_s_din,
   u_half_addr,         u_half_din,
   v_half_addr,         v_half_din,
   u_minus_v_half_addr, u_minus_v_half_din,
   v_minus_u_half_addr, v_minus_u_half_din
   );


   //
   // Parameters
   //
   parameter BUFFER_NUM_WORDS		= 9;
   parameter BUFFER_ADDR_BITS		= 4;


   //
   // clog2
   //
`include "../modinv_clog2.v"


   //
   // Constants
   //
   localparam PROC_NUM_CYCLES	= BUFFER_NUM_WORDS + 3;
   localparam PROC_CNT_BITS	= clog2(PROC_NUM_CYCLES);


   //
   // Ports
   //
   input		wire									clk;
   input		wire									rst_n;
   input		wire									ena;
   output	wire 										rdy;

   input		wire									u_gt_v;
   input		wire									v_eq_1;
   input		wire									u_is_even;
   input		wire									v_is_even;

   output	wire [BUFFER_ADDR_BITS-1:0] 							r_addr;
   output	wire [BUFFER_ADDR_BITS-1:0] 							s_addr;
   output	wire [BUFFER_ADDR_BITS-1:0] 							u_addr;
   output	wire [BUFFER_ADDR_BITS-1:0] 							v_addr;

   output	wire 										r_wren;
   output	wire 										s_wren;
   output	wire 										u_wren;
   output	wire 										v_wren;

   output	wire [              32-1:0] 							r_dout;
   output	wire [              32-1:0] 							s_dout;
   output	wire [              32-1:0] 							u_dout;
   output	wire [              32-1:0] 							v_dout;

   output	wire [BUFFER_ADDR_BITS-1:0] 							r_dbl_addr;
   output	wire [BUFFER_ADDR_BITS-1:0] 							s_dbl_addr;
   output	wire [BUFFER_ADDR_BITS-1:0] 							r_plus_s_addr;
   output	wire [BUFFER_ADDR_BITS-1:0] 							u_half_addr;
   output	wire [BUFFER_ADDR_BITS-1:0] 							v_half_addr;
   output	wire [BUFFER_ADDR_BITS-1:0] 							u_minus_v_half_addr;
   output	wire [BUFFER_ADDR_BITS-1:0] 							v_minus_u_half_addr;

   input		wire [              32-1:0] 						r_dbl_din;
   input		wire [              32-1:0] 						s_dbl_din;
   input		wire [              32-1:0] 						r_plus_s_din;
   input		wire [              32-1:0] 						u_half_din;
   input		wire [              32-1:0] 						v_half_din;
   input		wire [              32-1:0] 						u_minus_v_half_din;
   input		wire [              32-1:0] 						v_minus_u_half_din;


   //
   // 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_max		= 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_next	= (addr_in < addr_in_max) ?
												addr_in + 1'b1 : addr_in_zero;

   reg [BUFFER_ADDR_BITS-1:0] 									addr_out;

   wire [BUFFER_ADDR_BITS-1:0] 									addr_out_max	= BUFFER_NUM_WORDS - 1;
   wire [BUFFER_ADDR_BITS-1:0] 									addr_out_zero	= {BUFFER_ADDR_BITS{1'b0}};
   wire [BUFFER_ADDR_BITS-1:0] 									addr_out_next	= (addr_out < addr_out_max) ?
												addr_out + 1'b1 : addr_out_zero;

   assign r_addr					= addr_out;
   assign s_addr					= addr_out;
   assign u_addr					= addr_out;
   assign v_addr					= addr_out;

   assign r_dbl_addr				= addr_in;
   assign s_dbl_addr				= addr_in;
   assign r_plus_s_addr			= addr_in;
   assign u_half_addr			= addr_in;
   assign v_half_addr			= addr_in;
   assign u_minus_v_half_addr	= addr_in;
   assign v_minus_u_half_addr	= addr_in;


   //
   // Ready Flag
   //
   assign rdy = (proc_cnt == proc_cnt_zero);


   //
   // Address Increment Logic
   //
   wire 											inc_addr_in;
   wire 											inc_addr_out;

   wire [PROC_CNT_BITS-1:0] 									cnt_inc_addr_in_start	= 1;
   wire [PROC_CNT_BITS-1:0] 									cnt_inc_addr_in_stop		= BUFFER_NUM_WORDS;

   wire [PROC_CNT_BITS-1:0] 									cnt_inc_addr_out_start	= 2;
   wire [PROC_CNT_BITS-1:0] 									cnt_inc_addr_out_stop	= BUFFER_NUM_WORDS + 1;

   assign inc_addr_in  = (proc_cnt >= cnt_inc_addr_in_start)  && (proc_cnt <= cnt_inc_addr_in_stop);
   assign inc_addr_out = (proc_cnt >= cnt_inc_addr_out_start) && (proc_cnt <= cnt_inc_addr_out_stop);

   always @(posedge clk) begin
      //
      if (inc_addr_in)	addr_in <= addr_in_next;
      else					addr_in <= addr_in_zero;
      //
      if (inc_addr_out)	addr_out <= addr_out_next;
      else					addr_out <= addr_out_zero;
      //
   end

   //
   // Write Enable Logic
   //
   wire	wren_out;

   wire [PROC_CNT_BITS-1:0] cnt_wren_out_start	= 2;
   wire [PROC_CNT_BITS-1:0] cnt_wren_out_stop		= BUFFER_NUM_WORDS + 1;

   assign wren_out = (proc_cnt >= cnt_wren_out_start) && (proc_cnt <= cnt_wren_out_stop);

   reg 			    r_wren_allow;
   reg 			    s_wren_allow;
   reg 			    u_wren_allow;
   reg 			    v_wren_allow;

   assign r_wren = wren_out && r_wren_allow && !v_eq_1 && !rdy;
   assign s_wren = wren_out && s_wren_allow && !v_eq_1 && !rdy;
   assign u_wren = wren_out && u_wren_allow && !v_eq_1 && !rdy;
   assign v_wren = wren_out && v_wren_allow && !v_eq_1 && !rdy;


   //
   // Data Logic
   //
   reg [31: 0] 		    r_dout_mux;
   reg [31: 0] 		    s_dout_mux;
   reg [31: 0] 		    u_dout_mux;
   reg [31: 0] 		    v_dout_mux;

   assign r_dout = r_dout_mux;
   assign s_dout = s_dout_mux;
   assign u_dout = u_dout_mux;
   assign v_dout = v_dout_mux;

   always @(*) begin
      //
      // r, s, u, v
      //
      if (u_is_even) begin
	 //
	 u_dout_mux		= u_half_din;
	 v_dout_mux		= {32{1'bX}};
	 r_dout_mux		= {32{1'bX}};
	 s_dout_mux		= s_dbl_din;
	 //
	 u_wren_allow	= 1'b1;
	 v_wren_allow	= 1'b0;
	 r_wren_allow	= 1'b0;
	 s_wren_allow	= 1'b1;
	 //
      end else begin
	 //
	 if (v_is_even) begin
	    //
	    u_dout_mux		= {32{1'bX}};
	 v_dout_mux		= v_half_din;
	 r_dout_mux		= r_dbl_din;
	 s_dout_mux		= {32{1'bX}};
	 //
	 u_wren_allow	= 1'b0;
	 v_wren_allow	= 1'b1;
	 r_wren_allow	= 1'b1;
	 s_wren_allow	= 1'b0;
	 //
      end else begin
	 //
	 u_dout_mux		=  u_gt_v ? u_minus_v_half_din : {32{1'bX}};
	  v_dout_mux		=  u_gt_v ? {32{1'bX}}         : v_minus_u_half_din;
	  r_dout_mux		=  u_gt_v ? r_plus_s_din       : r_dbl_din;
	  s_dout_mux		=  u_gt_v ? s_dbl_din          : r_plus_s_din;
	  //
	  u_wren_allow	=  u_gt_v;
	  v_wren_allow	= !u_gt_v;
	  r_wren_allow	=  1'b1;
	  s_wren_allow	=  1'b1;
	  //
       end
	 //
      end
      //
   end


   //
   // 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