// ========== Copyright Header Begin ==========================================
// 
// OpenSPARC T1 Processor File: spu_maaddr.v
// Copyright (c) 2006 Sun Microsystems, Inc.  All Rights Reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
// 
// The above named program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License version 2 as published by the Free Software Foundation.
// 
// The above named program is distributed in the hope that it will be 
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
// 
// You should have received a copy of the GNU General Public
// License along with this work; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
// 
// ========== Copyright Header End ============================================
////////////////////////////////////////////////////////////////////////
/*
//      Description:    adderss generator for MA.
// 			MPA,MA_ADDR,LENGTH,I_PTR,J_PTR...
*/
////////////////////////////////////////////////////////////////////////
// Global header file includes
////////////////////////////////////////////////////////////////////////

module spu_maaddr (

/*outputs*/
spu_maaddr_len_neqz,
spu_maaddr_mpa1maddr0,
spu_maaddr_memindx,
spu_maaddr_mamem_eveodd_sel_l,
spu_maaddr_iequtwolenplus2,
spu_maaddr_iequtwolenplus1,
spu_maaddr_jequiminus1,
spu_maaddr_jequlen,

spu_maaddr_halfpnt_set,

spu_maaddr_len_eqmax,

spu_maaddr_esmax,
spu_maaddr_esmod64,

spu_maaddr_nooddwr_on_leneq1,

spu_maaddr_mpa_addrinc,
spu_maaddr_mpa_wen,
spu_maaddr_mpa_incr_val,

spu_maaddr_len_cntr,

spu_maaddr_wrindx_0,
spu_maaddr_jptr_eqz_mared,

/*inputs*/

spu_mald_force_mpa_add16,

spu_mactl_iss_pulse_pre,
spu_mactl_iss_pulse,


//spu_mactl_mulop,
spu_mactl_ldop,
spu_madp_maaddr_reg_in,
spu_madp_mactl_reg,

spu_mald_maaddr_addrinc,
spu_mald_mpa_addrinc,
spu_mast_maaddr_addrinc,
spu_mast_mpa_addrinc,

spu_mamul_memwen,

spu_mamul_rst_iptr,
spu_mamul_rst_jptr,
spu_mamul_incr_iptr,
spu_mamul_incr_jptr,

spu_mamul_a_rd_oprnd_sel,
spu_mamul_ax_rd_oprnd_sel,
spu_mamul_b_rd_oprnd_sel,
spu_mamul_ba_rd_oprnd_sel,
spu_mamul_m_rd_oprnd_sel,
spu_mamul_n_rd_oprnd_sel,
spu_mamul_m_wr_oprnd_sel,

spu_mared_me_rd_oprnd_sel,
spu_mared_xe_wr_oprnd_sel,
spu_mamul_me_rd_oprnd_sel,
spu_mamul_me_wr_oprnd_sel,

spu_mamul_i_ptr_sel,
spu_mamul_iminus1_ptr_sel,
spu_mamul_j_ptr_sel,
spu_mamul_iminusj_ptr_sel,
spu_mamul_iminuslenminus1_sel,

spu_mamul_jjptr_wen,

spu_mared_m_rd_oprnd_sel,
spu_mared_nm_rd_oprnd_sel,
spu_mared_x_wr_oprnd_sel,
spu_mared_a_rd_oprnd_sel,
spu_mared_nr_rd_oprnd_sel,
spu_mared_r_wr_oprnd_sel,
spu_mared_memwen,
spu_mared_j_ptr_sel,
spu_mared_update_jptr,
spu_mared_rst_jptr,
spu_mared_maxlen_wen,
spu_mared_cin_set_4sub,

spu_mast_memren,
spu_mared_start_wen,
spu_mared_start_sel,

spu_maexp_incr_es_ptr,
spu_maexp_e_rd_oprnd_sel,
spu_maexp_es_max_init,
spu_maexp_es_e_ptr_rst,

spu_madp_mpa_addr_3,



spu_maaddr_jequiminus1rshft,
spu_maaddr_iequtwolen,
spu_maaddr_ieven,
spu_maaddr_ieq0,

spu_maaddr_aequb,

spu_maaeqb_memwen,
spu_maaeqb_irshft_sel,

spu_mared_update_redwr_jptr,
spu_mared_jjptr_wen,

spu_mamul_jjptr_sel,

mem_bypass,
sehold,

spu_mamul_rst,

se,
reset,
rclk);

// ---------------------------------------------------------------
input reset;
input rclk;
input se;


input spu_mald_force_mpa_add16;

input spu_mactl_ldop;
//input spu_mactl_mulop;
input [47:0] spu_madp_maaddr_reg_in;
input [5:0] spu_madp_mactl_reg;

input spu_mald_maaddr_addrinc;
input spu_mald_mpa_addrinc;
input spu_mast_maaddr_addrinc;
input spu_mast_mpa_addrinc;

input spu_mamul_memwen;
input spu_mamul_rst_iptr;
input spu_mamul_rst_jptr;
input spu_mamul_incr_iptr;
input spu_mamul_incr_jptr;

input spu_mamul_a_rd_oprnd_sel;
input spu_mamul_ax_rd_oprnd_sel;
input spu_mamul_b_rd_oprnd_sel;
input spu_mamul_ba_rd_oprnd_sel;
input spu_mamul_m_rd_oprnd_sel;
input spu_mamul_n_rd_oprnd_sel;
input spu_mamul_m_wr_oprnd_sel;

input spu_mared_me_rd_oprnd_sel;
input spu_mared_xe_wr_oprnd_sel;
input spu_mamul_me_rd_oprnd_sel;
input spu_mamul_me_wr_oprnd_sel;

input spu_mamul_i_ptr_sel;
input spu_mamul_iminus1_ptr_sel;
input spu_mamul_j_ptr_sel;
input spu_mamul_iminusj_ptr_sel;
input spu_mamul_iminuslenminus1_sel;

input spu_mamul_jjptr_wen;

input spu_mactl_iss_pulse_pre;
input spu_mactl_iss_pulse;

input spu_mared_m_rd_oprnd_sel;
input spu_mared_nm_rd_oprnd_sel;
input spu_mared_x_wr_oprnd_sel;
input spu_mared_a_rd_oprnd_sel;
input spu_mared_nr_rd_oprnd_sel;
input spu_mared_r_wr_oprnd_sel;
input spu_mared_memwen;
input spu_mared_j_ptr_sel;
input spu_mared_update_jptr;
input spu_mared_rst_jptr;
input spu_mared_maxlen_wen;
input spu_mared_cin_set_4sub;

input spu_mast_memren;
input spu_mared_start_wen;
input spu_mared_start_sel;

input spu_maexp_incr_es_ptr;
input spu_maexp_e_rd_oprnd_sel;
input spu_maexp_es_max_init;
input spu_maexp_es_e_ptr_rst;


input spu_madp_mpa_addr_3;
input spu_maaeqb_memwen;
input spu_maaeqb_irshft_sel;

input spu_mared_update_redwr_jptr;
input spu_mared_jjptr_wen;

input spu_mamul_jjptr_sel;

input mem_bypass;
input sehold;

input spu_mamul_rst;
// ---------------------------------------------------------------
output spu_maaddr_len_neqz;

output spu_maaddr_mpa1maddr0;

output [7:1] spu_maaddr_memindx;
output [3:0] spu_maaddr_mamem_eveodd_sel_l;

output spu_maaddr_iequtwolenplus2;
output spu_maaddr_iequtwolenplus1;
output spu_maaddr_jequiminus1;
output spu_maaddr_jequlen;

output spu_maaddr_halfpnt_set;

output spu_maaddr_len_eqmax;

output spu_maaddr_esmod64;
output spu_maaddr_esmax;

output spu_maaddr_nooddwr_on_leneq1;

output spu_maaddr_mpa_addrinc;
output spu_maaddr_mpa_wen;
output [4:0] spu_maaddr_mpa_incr_val;




output spu_maaddr_jequiminus1rshft;
output spu_maaddr_iequtwolen;
output spu_maaddr_ieven;
output spu_maaddr_ieq0;

output spu_maaddr_aequb;

output [5:0] spu_maaddr_len_cntr;

output spu_maaddr_wrindx_0;
output spu_maaddr_jptr_eqz_mared;

// ---------------------------------------------------------------
// ---------------------------------------------------------------
// ---------------------------------------------------------------

wire reset_local = reset | spu_mactl_iss_pulse_pre;

// ---------------------------------------------------------------
// ---------------------------------------------------------------
// ---------------------------------------------------------------

wire [47:0] spu_madp_maaddr_reg;
wire [6:0] len_decr_val,len_ptr_sub_q,len_ptr_mx,len_ptr_sub;
wire incr_2wd;
wire [1:0] len_1or2_dec;

wire [7:0] maaddr_mx,maaddr_incr_val,spu_maaddr_maaddr_add,spu_maaddr_maaddr_q;
wire maaddr_wen;

wire [6:0] j_ptr_data;
// ---------------------------------------------------------------
// ---------------------------------------------------------------

dffe_s  #(48) maaddr_reg_ff  (
        .din(spu_madp_maaddr_reg_in[47:0]) ,
        .q(spu_madp_maaddr_reg[47:0]),
        .en(spu_mactl_iss_pulse_pre),
        .clk (rclk), .se(se), .si(), .so());


// ---------------------------------------------------------------
wire spu_maaddr_maaddr_addrinc = spu_mald_maaddr_addrinc | spu_mast_maaddr_addrinc;
assign spu_maaddr_mpa_addrinc = spu_mald_mpa_addrinc | spu_mast_mpa_addrinc;
// ---------------------------------------------------------------
// ***************** LEN *******************
// --------------------------------------------------------------

wire len_wen = spu_maaddr_maaddr_addrinc | spu_mactl_iss_pulse;

mux2ds  #(7) len_issorex_mx (
        .in0    (len_ptr_sub_q[6:0]), 
        .in1    ({1'b0,spu_madp_mactl_reg[5:0]}), 
        .sel0   (spu_maaddr_maaddr_addrinc),  
        .sel1   (~spu_maaddr_maaddr_addrinc),
        .dout   (len_ptr_mx[6:0])
);

// for memload decr by 16bytes(2words) and for memstore & mulop decr by
// 8bytes(1word) or when transferring one word rather than two from 
// ld buf to mamem.


mux2ds  #(2) len_1or2_mx (
        .in0    (2'b01), // already inverted
        .in1    (2'b10), 
        .sel0   (incr_2wd),
        .sel1   (~incr_2wd),
        .dout   (len_1or2_dec[1:0])
);


mux2ds  #(7) len_ptr_iss_mx (
        .in0    (7'b0000000), 
        .in1    ({5'b11111,len_1or2_dec[1:0]}), 
        .sel0   (spu_mactl_iss_pulse),  
        .sel1   (~spu_mactl_iss_pulse),
        .dout   (len_decr_val[6:0])
);

assign len_ptr_sub[6:0] = len_ptr_mx[6:0] + len_decr_val[6:0] + 
						7'b0000001; 

dffre_s  #(7) len_ptr_ff  (
        .din(len_ptr_sub[6:0]) ,
        .q(len_ptr_sub_q[6:0]),
        .en(len_wen),
        .rst(reset_local), .clk (rclk), .se(se), .si(), .so());

assign spu_maaddr_len_neqz = |len_ptr_sub_q[6:0];

// his for the case when the len has been decremented to 1 and there
// is possibilty the next decr will be -2 which makes the len be a
// neg number.

wire allow_incr_2wd = (|len_ptr_sub_q[6:1]) & spu_mactl_ldop;



// when mpa0maddr0 make sure the last write does not happen to 
// odd side when len has reached one. mpa=0 and maddr=0 are checked in
// spu_mactl.v.

assign spu_maaddr_nooddwr_on_leneq1 = ~(~allow_incr_2wd & len_ptr_sub_q[0]); 


wire [5:0] spu_maaddr_len_cntr_l;
assign spu_maaddr_len_cntr_l[5:0] = ~len_ptr_sub_q[5:0];
assign spu_maaddr_len_cntr[5:0] = ~spu_maaddr_len_cntr_l[5:0];

// --------------------------------------------------------------
// ***************** MPA *******************
// --------------------------------------------------------------

wire mpa_incr_2wd = incr_2wd | spu_mald_force_mpa_add16;


mux2ds  #(5) mpa_iss_mx (
        .in0    (5'b10000),
        .in1    (5'b01000),
        .sel0   (mpa_incr_2wd),  
        .sel1   (~mpa_incr_2wd),
        .dout   (spu_maaddr_mpa_incr_val[4:0])
);


assign spu_maaddr_mpa_wen = spu_maaddr_mpa_addrinc | spu_mactl_iss_pulse;

// --------------------------------------------------------------
// ***************** MA_ADDR *******************
// --------------------------------------------------------------

mux2ds  #(8) maaddr_issorex_mx (
        .in0    (spu_maaddr_maaddr_add[7:0]), 
        .in1    (spu_madp_maaddr_reg[7:0]), 
        .sel0   (spu_maaddr_maaddr_addrinc),  
        .sel1   (~spu_maaddr_maaddr_addrinc),
        .dout   (maaddr_mx[7:0])
);


mux2ds  #(8) maaddr_iss_mx (
        .in0    (8'b00000010),
        .in1    (8'b00000001), 
        .sel0   (incr_2wd),  
        .sel1   (~incr_2wd),
        .dout   (maaddr_incr_val[7:0])
);

assign spu_maaddr_maaddr_add[7:0] = spu_maaddr_maaddr_q[7:0] + maaddr_incr_val[7:0];

assign maaddr_wen = spu_maaddr_maaddr_addrinc | spu_mactl_iss_pulse;

dffre_s  #(8) maaadr_pa_mx  (
        .din(maaddr_mx[7:0]) ,
        .q(spu_maaddr_maaddr_q[7:0]),
	.en(maaddr_wen),
        .rst(reset_local), .clk (rclk), .se(se), .si(), .so());


// --------------------------------------------------------------
// ***************** INCR VALUE DECODE *******************
// --------------------------------------------------------------

// 16byte increments for load from L2 and 8byte increment for
// store to L2 or if its 8byte transfer from ld buff to mamem.


assign incr_2wd = ~spu_madp_mpa_addr_3 & ~spu_maaddr_maaddr_q[0] & spu_mactl_ldop &
				allow_incr_2wd;



assign spu_maaddr_mpa1maddr0 = spu_madp_mpa_addr_3 & ~spu_maaddr_maaddr_q[0] & 
					spu_mactl_ldop;


// --------------------------------------------------------------
// --------------------------------------------------------------
// ******************* A == B ******************
// --------------------------------------------------------------
// --------------------------------------------------------------

assign spu_maaddr_aequb = (spu_madp_maaddr_reg[7:0] == spu_madp_maaddr_reg[15:8]);

// --------------------------------------------------------------
// --------------------------------------------------------------
// ***************** MEMINDEX *******************
// --------------------------------------------------------------
// --------------------------------------------------------------

wire [7:0] memld_wroffset,x_mul_wroffset,m_mul_wroffset,r_red_wroffset,
		x_exp_wroffset,memst_rdoffset,mmx_mulredexp_rdoffset,nrn_mulredexp_rdoffset,
		bnm_mulredexp_rdoffset,aaa_mulredexp_rdoffset,e_exp_rdoffset;


assign memld_wroffset = spu_maaddr_maaddr_q[7:0];

assign x_mul_wroffset = spu_madp_maaddr_reg[39:32];
assign m_mul_wroffset = spu_madp_maaddr_reg[31:24];
assign r_red_wroffset = spu_madp_maaddr_reg[23:16];
assign x_exp_wroffset = spu_madp_maaddr_reg[31:24];

assign memst_rdoffset = spu_maaddr_maaddr_q[7:0];

assign mmx_mulredexp_rdoffset = spu_madp_maaddr_reg[31:24];
assign nrn_mulredexp_rdoffset = spu_madp_maaddr_reg[23:16];
assign bnm_mulredexp_rdoffset = spu_madp_maaddr_reg[15:8];
assign aaa_mulredexp_rdoffset = spu_madp_maaddr_reg[7:0];
assign e_exp_rdoffset = spu_madp_maaddr_reg[39:32];

// --------------- WR INDEX -------------------------------------

wire [7:0] wroffset_a,wroffset_b,wr_offset;
wire [7:0] rdoffset_a,rdoffset_b,rd_offset;

wire wr_a_sel = spu_mactl_ldop | spu_mamul_m_wr_oprnd_sel |
		spu_mared_x_wr_oprnd_sel;

/******
// converting muxes to AO logic to fix 0in problems.
mux3ds  #(8) wroffset_a_mx (
        .in0    (memld_wroffset[7:0]), 
        .in1    (x_mul_wroffset[7:0]), 
        .in2    (m_mul_wroffset[7:0]), 
        .sel0   (spu_mactl_ldop),  
        .sel1   (spu_mared_x_wr_oprnd_sel),
        .sel2   (spu_mamul_m_wr_oprnd_sel),
        .dout   (wroffset_a[7:0])
);

mux3ds  #(8) wroffset_b_mx (
        .in0    (r_red_wroffset[7:0]),
        .in1    (x_exp_wroffset[7:0]), 
        .in2    (spu_madp_maaddr_reg[15:8]), 
        .sel0   (spu_mared_r_wr_oprnd_sel),  
        .sel1   (spu_mared_xe_wr_oprnd_sel),
        .sel2   (spu_mamul_me_wr_oprnd_sel),
        .dout   (wroffset_b[7:0])
);

******/

assign wroffset_a[7:0] = 
			(memld_wroffset[7:0] & {8{spu_mactl_ldop}}) |
			(x_mul_wroffset[7:0] & {8{spu_mared_x_wr_oprnd_sel}}) |
			(m_mul_wroffset[7:0] & {8{spu_mamul_m_wr_oprnd_sel}}) ;

assign wroffset_b[7:0] =
			(r_red_wroffset[7:0] & {8{spu_mared_r_wr_oprnd_sel}}) |
			(x_exp_wroffset[7:0] & {8{spu_mared_xe_wr_oprnd_sel}}) |
			(spu_madp_maaddr_reg[15:8] & {8{spu_mamul_me_wr_oprnd_sel}}) ;




mux2ds  #(8) wroffset_mx (
        .in0    (wroffset_a[7:0]),
        .in1    (wroffset_b[7:0]), 
        .sel0   (wr_a_sel),  
        .sel1   (~wr_a_sel),
        .dout   (wr_offset[7:0])
);

// --------------- RD INDEX -------------------------------------
wire [2:0] rd_a_sel;
wire [2:0] rd_b_sel;

// sel for store needs to be added
wire rd_a_select = spu_mamul_m_rd_oprnd_sel | spu_mamul_n_rd_oprnd_sel |
		spu_mared_m_rd_oprnd_sel | spu_mared_nm_rd_oprnd_sel |
		spu_mamul_ax_rd_oprnd_sel | 
			spu_mast_memren; 

assign rd_a_sel[0] = spu_mast_memren;
assign rd_a_sel[1] = spu_mamul_m_rd_oprnd_sel | spu_mared_m_rd_oprnd_sel |
			spu_mamul_ax_rd_oprnd_sel ;
assign rd_a_sel[2] = spu_mamul_n_rd_oprnd_sel | spu_mared_nm_rd_oprnd_sel;

assign rd_b_sel[0] = spu_mamul_b_rd_oprnd_sel | spu_mared_nr_rd_oprnd_sel |
			spu_mared_me_rd_oprnd_sel | spu_mamul_me_rd_oprnd_sel;
assign rd_b_sel[1] = spu_mamul_a_rd_oprnd_sel | spu_mared_a_rd_oprnd_sel |
			spu_mamul_ba_rd_oprnd_sel;
assign rd_b_sel[2] = spu_maexp_e_rd_oprnd_sel;


/***************
mux3ds  #(8) rdoffset_a_mx (
        .in0    (memst_rdoffset[7:0]),
        .in1    (mmx_mulredexp_rdoffset[7:0]), 
        .in2    (nrn_mulredexp_rdoffset[7:0]), 
        .sel0   (rd_a_sel[0]),  
        .sel1   (rd_a_sel[1]),
        .sel2   (rd_a_sel[2]),
        .dout   (rdoffset_a[7:0])
);

mux3ds  #(8) rdoffset_b_mx (
        .in0    (bnm_mulredexp_rdoffset[7:0]),
        .in1    (aaa_mulredexp_rdoffset[7:0]), 
        .in2    (e_exp_rdoffset[7:0]), 
        .sel0   (rd_b_sel[0]),  
        .sel1   (rd_b_sel[1]),
        .sel2   (rd_b_sel[2]),
        .dout   (rdoffset_b[7:0])
);
****************/

assign rdoffset_a[7:0] =
			(memst_rdoffset[7:0] & {8{rd_a_sel[0]}}) |
			(mmx_mulredexp_rdoffset[7:0] & {8{rd_a_sel[1]}}) |
			(nrn_mulredexp_rdoffset[7:0] & {8{rd_a_sel[2]}}) ;

assign rdoffset_b[7:0] =
                        (bnm_mulredexp_rdoffset[7:0] & {8{rd_b_sel[0]}}) |
                        (aaa_mulredexp_rdoffset[7:0] & {8{rd_b_sel[1]}}) |
                        (e_exp_rdoffset[7:0] & {8{rd_b_sel[2]}}) ;




mux2ds  #(8) rdoffset_mx (
        .in0    (rdoffset_a[7:0]),
        .in1    (rdoffset_b[7:0]), 
        .sel0   (rd_a_select),  
        .sel1   (~rd_a_select),
        .dout   (rd_offset[7:0])
);


// --------------------------------------------------------------

// spu_mamul_memwen is true when m[i] operand is updated.
wire mem_wr_op = spu_mactl_ldop | spu_mamul_memwen | spu_mared_memwen |
				spu_maaeqb_memwen;

wire [7:0] memoffset;

mux2ds  #(8) memoffset_rd_wr (
        .in0    (wr_offset[7:0]),
        .in1    (rd_offset[7:0]), 
        .sel0   (mem_wr_op),  
        .sel1   (~mem_wr_op),
        .dout   (memoffset[7:0])
);


// --------------------------------------------------------------
// --------------------------------------------------------------
// --------------------------------------------------------------
// --------------------------------------------------------------
// --------------------------------------------------------------

wire [6:0] j_ptr,j_ptr_add;
wire [5:0] len;
wire [6:0] twolen,lenplus1,twolenplus2,iminus1_rshft,i_rshft,
		twolenplus1,iminus1_ptr,iminus_len,i_ptr_add,i_ptr;

wire i_equ_lenplus1,j_equ_iminus1rshft,
		j_equ_iminus1,
		i_ptr_rst;

//wire i_equ_zero;
		

// --------------------------------------------------------------
// --------------------------------------------------------------
// --------------------------------------------------------------
// ------------ FINAL ADDER & ADDVAL MUX FOR MEMINDEX -----------
// --------------------------------------------------------------
// --------------------------------------------------------------
// --------------------------------------------------------------
wire [6:0] jj_ptr;
wire [6:0] e_ptr;
wire [6:0] j_ptr_redwr_val;

wire [6:0] add_val,addval_a,addval_b;
wire [6:0] iminusj_ptr,iminus1_lenminus1;

wire add_a_sel = spu_mamul_iminuslenminus1_sel |
			spu_mamul_iminus1_ptr_sel | 
			spu_mamul_i_ptr_sel | spu_maaeqb_irshft_sel; 

wire mulred_j_ptr_sel = spu_mamul_j_ptr_sel | spu_mared_j_ptr_sel;
wire add_b_sel = mulred_j_ptr_sel | spu_mamul_iminusj_ptr_sel |
				spu_maexp_e_rd_oprnd_sel | spu_mared_memwen;

//wire add_c_sel = ~(add_a_sel | add_b_sel);

/*****
mux4ds  #(7) addval_a_mux (
        .in0    (iminus1_lenminus1[6:0]),
        .in1    (iminus1_ptr[6:0]), 
        .in2    (i_rshft[6:0]), 
        .in3    (i_ptr[6:0]), 
        .sel0   (spu_mamul_iminuslenminus1_sel),  
        .sel1   (spu_mamul_iminus1_ptr_sel),
        .sel2   (spu_maaeqb_irshft_sel),
        .sel3   (spu_mamul_i_ptr_sel),
        .dout   (addval_a[6:0])
);

*******/

assign addval_a[6:0] = 
			(iminus1_lenminus1[6:0] & {7{spu_mamul_iminuslenminus1_sel}}) |
			(iminus1_ptr[6:0] & {7{spu_mamul_iminus1_ptr_sel}}) |
			(i_rshft[6:0] & {7{spu_maaeqb_irshft_sel}}) |
			(i_ptr[6:0] & {7{spu_mamul_i_ptr_sel}}) ;

/****** 
mux4ds  #(7) addval_b_mux (
        .in0    (jj_ptr[6:0]),
        .in1    (iminusj_ptr[6:0]),
        .in2    (e_ptr[6:0]),
        .in3    (j_ptr_redwr_val[6:0]),
        .sel0   (mulred_j_ptr_sel),
        .sel1   (spu_mamul_iminusj_ptr_sel),
        .sel2   (spu_maexp_e_rd_oprnd_sel),
        .sel3   (spu_mared_memwen),
        .dout   (addval_b[6:0])
);
**********/

assign addval_b[6:0] = 
			(jj_ptr[6:0] & {7{mulred_j_ptr_sel}}) |
			(iminusj_ptr[6:0] & {7{spu_mamul_iminusj_ptr_sel}}) |
			(e_ptr[6:0] & {7{spu_maexp_e_rd_oprnd_sel}}) |
			(j_ptr_redwr_val[6:0] & {7{spu_mared_memwen}}) ;
			

/*******
mux3ds  #(7) addval_mux (
        .in0    (addval_a[6:0]), 
        .in1    (addval_b[6:0]), 
        .in2    (7'b0000000),
        .sel0   (add_a_sel),  
        .sel1   (add_b_sel),
        .sel2   (add_c_sel),
        .dout   (add_val[6:0])
);

********/

assign add_val[6:0] =
			(addval_a[6:0] & {7{add_a_sel}}) |
			(addval_b[6:0] & {7{add_b_sel}}) ;

wire spu_maaddr_memindx_0;
assign {spu_maaddr_memindx[7:1],spu_maaddr_memindx_0} = {1'b0,add_val[6:0]} + memoffset[7:0];


assign spu_maaddr_wrindx_0 = wr_offset[0] + add_val[0];


// ----------------------
// check for out of range
// ----------------------
wire spu_maaddr_memindx_outofrange_q;

wire spu_maaddr_memindx_outofrange = (spu_maaddr_memindx[7] & spu_maaddr_memindx[6]) | 
					(spu_maaddr_memindx[7] & spu_maaddr_memindx[5]) ;


wire spu_maaddr_memindx_outofrange_sehold = sehold ? spu_maaddr_memindx_outofrange_q :
							spu_maaddr_memindx_outofrange;

dff_s #(1) spu_maaddr_memindx_outofrange_ff (
        .din(spu_maaddr_memindx_outofrange_sehold) ,
        .q(spu_maaddr_memindx_outofrange_q),
        .clk (rclk), .se(1'b0),.si (),.so ()
        );

// ----------------------
wire spu_maaddr_memindx_0_q;

wire spu_maaddr_memindx_0_sehold = sehold ? spu_maaddr_memindx_0_q :
						spu_maaddr_memindx_0;

dff_s #(1) mem_indx_0_ff (
        .din(spu_maaddr_memindx_0_sehold) ,
        .q(spu_maaddr_memindx_0_q),
        .clk (rclk), .se(1'b0),.si (),.so ()
        );

wire [3:0] spu_maaddr_mamem_eveodd_sel;
assign spu_maaddr_mamem_eveodd_sel[0] = ~(mem_bypass | spu_maaddr_memindx_outofrange_q) & ~spu_maaddr_memindx_0_q;
assign spu_maaddr_mamem_eveodd_sel[1] = ~(mem_bypass | spu_maaddr_memindx_outofrange_q) & spu_maaddr_memindx_0_q;
assign spu_maaddr_mamem_eveodd_sel[2] = ~mem_bypass & spu_maaddr_memindx_outofrange_q;
assign spu_maaddr_mamem_eveodd_sel[3] =  mem_bypass;

assign spu_maaddr_mamem_eveodd_sel_l = ~spu_maaddr_mamem_eveodd_sel;

// --------------------------------------------------------
// --------------------------------------------------------
// --------------------------------------------------------
// --------------------------------------------------------
// --------------------------------------------------------
// ---------------- POINTERS ------------------------------
// --------------------------------------------------------
// --------------------------------------------------------
// --------------------------------------------------------
// --------------------------------------------------------


// ---------------------------------------------------------------

assign len[5:0] = spu_madp_mactl_reg[5:0];
assign twolen[6:0] = {spu_madp_mactl_reg[5],spu_madp_mactl_reg[4],
		    spu_madp_mactl_reg[3],spu_madp_mactl_reg[2],
		    spu_madp_mactl_reg[1],spu_madp_mactl_reg[0],1'b0};
assign lenplus1[6:0] = {1'b0,spu_madp_mactl_reg[5:0]} + 7'b0000001;
//assign lenminus1[5:0] = spu_madp_mactl_reg[5:0] - 1'b1;
assign twolenplus1[6:0] = twolen[6:0] + 7'b0000001;
assign twolenplus2[6:0] = twolen[6:0] + 7'b0000010;



assign iminus1_rshft[6:0] = {1'b0,iminus1_ptr[6],iminus1_ptr[5],
				iminus1_ptr[4],iminus1_ptr[3],
				iminus1_ptr[2],iminus1_ptr[1]};

assign i_rshft[6:0] = {1'b0,i_ptr[6],i_ptr[5],i_ptr[4],i_ptr[3],
				i_ptr[2],i_ptr[1]};

// ---------------------------------------------------------------
// ---------------------------------------------------------------
// start pointer comparisons.
// ---------------------------------------------------------------

//assign i_equ_len = (i_ptr_add[6:0] == {1'b0,len[5:0]}); 
assign i_equ_lenplus1 = (i_ptr[6:0] == lenplus1[6:0]); 

wire i_equ_twolenplus2_pre = (i_ptr_add[6:0] == twolenplus2[6:0]); 
wire i_equ_twolenplus1_pre = (i_ptr_add[6:0] == twolenplus1[6:0]); 

wire i_equ_twolen_pre = (i_ptr_add[6:0] == twolen[6:0]); 
wire i_equ_zero_pre = (i_ptr[6:0] == 7'b0000000); 

assign j_equ_iminus1rshft = (j_ptr[6:0] == iminus1_rshft[6:0]); 
//assign j_equ_iminuslen = (j_ptr[6:0] == iminus_len[6:0]); 
assign j_equ_iminus1 = (j_ptr[6:0] == iminus1_ptr[6:0]); 
//wire j_equ_iminus1_pre = (j_ptr_data[6:0] == i_ptr[6:0]); 
wire j_equ_len_pre = (j_ptr_data[6:0] == {1'b0,len[5:0]}); 

//assign spu_maaddr_iequtwolenplus2 = i_equ_twolenplus2;
//assign spu_maaddr_iequtwolenplus1 = i_equ_twolenplus1;
//assign spu_maaddr_iequtwolen = i_equ_twolen_pre;

//assign spu_maaddr_jequiminus1 = j_equ_iminus1;
//assign spu_maaddr_jequlen = j_equ_len;
//assign spu_maaddr_jequiminus1rshft = j_equ_iminus1rshft;

assign spu_maaddr_ieq0 = i_equ_zero_pre;
assign spu_maaddr_ieven = ~i_ptr[0];

// ***************************************************************
// start of pointers
// ***************************************************************
// ---------------------------------------------------------------

wire rst_halfpnt,halfpnt_set;

//assign rst_halfpnt = reset_local | spu_mamul_rst_iptr | ~spu_mactl_mulop;
assign rst_halfpnt = reset_local | spu_mamul_rst_iptr | spu_mamul_rst ;

dffre_s  #(1) halfpnt_ff (
        .din(1'b1) ,
        .q(halfpnt_set),
        .en(i_equ_lenplus1),
        .rst(rst_halfpnt), .clk (rclk), .se(se), .si(), .so());

assign spu_maaddr_halfpnt_set = halfpnt_set ;


// --------------------
  
wire halfpnt_set_pulse,halfpnt_set_q;

dff_s  #(1) halfpnt_set_pulse_ff (
        .din(halfpnt_set) ,
        .q(halfpnt_set_q),
        .clk (rclk), .se(se), .si(), .so());

assign halfpnt_set_pulse = ~halfpnt_set_q & halfpnt_set;
  
// ---------------------------------------------------------------
// J pointer (used for mamul and mared)
// ---------------------------------------------------------------

wire [6:0] jj_ptr_val;
wire [2:0] jptr_rst_sel;

wire j_ptr_wen = (spu_mamul_incr_jptr | spu_mamul_rst_jptr | halfpnt_set_pulse) |
		 (spu_mared_update_jptr | spu_mared_rst_jptr) |
			 spu_mared_start_wen;


// in the case of mamul we need to incr and for mared we
// need to start from msw and decr, and if we find that M is
// greater than N then we need to start from 0 and incr.

wire carryin = spu_mared_cin_set_4sub; 

wire [6:0] incr_decr_val;
mux2ds  #(7) incr_decr_val_mx2 (
        .in0    (7'b1111110),
        .in1    (7'b0000001), 
        .sel0   (carryin),  
        .sel1   (~carryin),
        .dout   (incr_decr_val[6:0])
);


assign j_ptr_add[6:0] = j_ptr[6:0] + incr_decr_val[6:0] + {6'b000000,carryin};

wire jptr_eqz_pre = ~(|j_ptr_data[6:0]);

wire jptr_eqz_q;
wire spu_maaddr_jequlen_q;

dffre_s  #(7) j_ptr_ff (
        .din(j_ptr_data[6:0]) ,
        .q(j_ptr[6:0]),
        .en(j_ptr_wen),
        .rst(reset_local), .clk (rclk), .se(se), .si(), .so());

dffre_s  #(2) j_ptr_b_ff (
        .din({jptr_eqz_pre, j_equ_len_pre}) ,
        .q({jptr_eqz_q, spu_maaddr_jequlen_q}),
        .en(j_ptr_wen),
        .rst(reset_local), .clk (rclk), .se(se), .si(), .so());

assign spu_maaddr_jequlen = spu_maaddr_jequlen_q;

assign spu_maaddr_jptr_eqz_mared = jptr_eqz_q;

//assign spu_maaddr_jptr_eqz = ~(|j_ptr[6:0]);

/*
assign jptr_rst_sel[0] = (spu_mamul_rst_jptr & spu_maaddr_halfpnt_set) | halfpnt_set_pulse ;
assign jptr_rst_sel[1] = (spu_mamul_rst_jptr & ~spu_maaddr_halfpnt_set) | spu_mared_rst_jptr;
assign jptr_rst_sel[2] = ~(halfpnt_set_pulse | spu_mamul_rst_jptr | spu_mared_rst_jptr |
				spu_mared_start_sel);
assign jptr_rst_sel[3] =  spu_mared_start_sel;
*/

assign jptr_rst_sel[0] = (spu_mamul_rst_jptr & spu_maaddr_halfpnt_set) | halfpnt_set_pulse ;
assign jptr_rst_sel[1] = ~(halfpnt_set_pulse | spu_mamul_rst_jptr | spu_mared_rst_jptr |
				spu_mared_start_sel);
assign jptr_rst_sel[2] =  spu_mared_start_sel;

/*
mux3ds  #(7) jptr_rst_mux (
        .in0    (iminus_len[6:0]), 
        .in1    (7'b0000000), 
        .in2    (j_ptr_add[6:0]), 
        .sel0   (jptr_rst_sel[0]),
        .sel1   (jptr_rst_sel[1]),
        .sel2   (jptr_rst_sel[2]),
        .dout   (j_ptr_data[6:0])
);*/

/*********
mux4ds  #(7) jptr_rst_mux (
        .in0    (iminus_len[6:0]),
        .in1    (7'b0000000),
        .in2    (j_ptr_add[6:0]),
        .in3    ({1'b0,spu_madp_mactl_reg[5:0]}),//when mared op starts,load the LEN into jptr.
        .sel0   (jptr_rst_sel[0]),
        .sel1   (jptr_rst_sel[1]),
        .sel2   (jptr_rst_sel[2]),
        .sel3   (jptr_rst_sel[3]),
        .dout   (j_ptr_data[6:0])
);
************/

assign j_ptr_data[6:0] =
			(iminus_len[6:0] & {7{jptr_rst_sel[0]}}) |
			(j_ptr_add[6:0] & {7{jptr_rst_sel[1]}}) |
			({1'b0,spu_madp_mactl_reg[5:0]} & {7{jptr_rst_sel[2]}}) ;
 
wire jj_ptr_update = spu_mamul_jjptr_wen | spu_mared_jjptr_wen;
dffre_s  #(7) jj_ptr_ff (
        .din(j_ptr_add[6:0]) ,
        .q(jj_ptr_val[6:0]),
        .en(jj_ptr_update),
        .rst(reset_local), .clk (rclk), .se(se), .si(), .so());

//wire jptr_oldnew_sel = spu_mamul_incr_jptr | spu_mared_update_jptr;
wire jptr_oldnew_sel = spu_mamul_jjptr_sel | spu_mared_update_jptr;
mux2ds  #(7) jptr_oldnew_mx2 (
        .in0    (jj_ptr_val[6:0]), 
        .in1    (j_ptr[6:0]),
        .sel0   (jptr_oldnew_sel),  
        .sel1   (~jptr_oldnew_sel),
        .dout   (jj_ptr[6:0])
);


dffre_s  #(7) j_ptr_redwr_ff (
        .din(j_ptr[6:0]) ,
        .q(j_ptr_redwr_val[6:0]),
        .en(spu_mared_update_redwr_jptr),
        .rst(reset_local), .clk (rclk), .se(se), .si(), .so());

// ----------------------
//saving the jptr this will be the maxlen
// for the mared subtract count.
wire [6:0] maxlen;
dffre_s  #(7) maxlen_ff (
        .din(j_ptr[6:0]) ,
        .q(maxlen[6:0]),
        .en(spu_mared_maxlen_wen),
        .rst(reset_local), .clk (rclk), .se(se), .si(), .so());

//assign spu_maaddr_len_eqmax = (j_ptr[6:0] == maxlen[6:0]);
wire spu_maaddr_len_eqmax_pre = (j_ptr_data[6:0] == maxlen[6:0]);


dffre_s  #(1) len_eqmax_ff (
        .din(spu_maaddr_len_eqmax_pre) ,
        .q(spu_maaddr_len_eqmax),
        .en(j_ptr_wen),
        .rst(reset_local), .clk (rclk), .se(se), .si(), .so());


// ---------------------------------------------------------------
// I pointer 
// ---------------------------------------------------------------

assign i_ptr_rst = reset_local | spu_mamul_rst_iptr;

assign i_ptr_add[6:0] = i_ptr[6:0] + 7'b0000001;

dffre_s  #(7) i_ptr_ff (
        .din(i_ptr_add[6:0]) ,
        .q(i_ptr[6:0]),
        .en(spu_mamul_incr_iptr),
        .rst(i_ptr_rst), .clk (rclk), .se(se), .si(), .so());

dffre_s  #(7) iminus1_ptr_ff (
        .din(i_ptr[6:0]) ,
        .q(iminus1_ptr[6:0]),
        .en(spu_mamul_incr_iptr),
        .rst(reset_local), .clk (rclk), .se(se), .si(), .so());


wire spu_maaddr_jequiminus1_q;
wire spu_maaddr_jequiminus1rshft_q;
dffre_s  #(2) j_equ_iminus1_ff (
        .din({j_equ_iminus1, j_equ_iminus1rshft}) ,
        .q({spu_maaddr_jequiminus1_q, spu_maaddr_jequiminus1rshft_q}),
        .en(1'b1),
        .rst(reset_local), .clk (rclk), .se(se), .si(), .so());

assign spu_maaddr_jequiminus1 = spu_maaddr_jequiminus1_q;
assign spu_maaddr_jequiminus1rshft = spu_maaddr_jequiminus1rshft_q;


	// added this to fix timing path.
dffre_s  #(3) i_equ_stuff_pre_ff (
        .din({i_equ_twolenplus2_pre,i_equ_twolenplus1_pre,i_equ_twolen_pre}) ,
        .q({spu_maaddr_iequtwolenplus2,spu_maaddr_iequtwolenplus1,spu_maaddr_iequtwolen}),
        .en(spu_mamul_incr_iptr),
        .rst(i_ptr_rst), .clk (rclk), .se(se), .si(), .so());

// ---------------------------------------------------------------
// I-J pointer 
// ---------------------------------------------------------------

wire [6:0] iminusj_ptr_pre;
assign iminusj_ptr_pre[6:0] = i_ptr[6:0] + ~jj_ptr[6:0] + 7'b0000001;

dff_s  #(7) iminusj_ff (
        .din(iminusj_ptr_pre[6:0]) ,
        .q(iminusj_ptr[6:0]),
        .clk (rclk), .se(se), .si(), .so());

// assign iminusj_ptr = iminusj_ptr_pre;

// ---------------------------------------------------------------
// I-LEN-1 pointer 
// ---------------------------------------------------------------

// assign iminus_lenminus1 = i_ptr[6:0] + {1'b1,~lenminus1[5:0]} + 1'b1;
//assign iminus_lenminus1[6:0] = (i_ptr[6:0] + {1'b1,~len[5:0]} + 1'b1) - 1'b1;
assign iminus1_lenminus1[6:0] = (iminus1_ptr[6:0] + {1'b1,~len[5:0]} + 7'b0000001) - 
							7'b0000001;

// ---------------------------------------------------------------
// I-LEN pointer
// ---------------------------------------------------------------

assign iminus_len[6:0] = i_ptr[6:0] + {1'b1,~len[5:0]} + 7'b0000001;

// ---------------------------------------------------------------

/*
always @(posedge clk) begin

$display ("%t iminus1_ptr",$time);
end
*/

// ---------------------------------------------------------------
// ---------------------------------------------------------------
// --------------------- MA EXP ----------------------------------
// ---------------------------------------------------------------
// ---------------------------------------------------------------

// ---------------------------------------------------------------
// ^^^^^^^^^^^^^^ ES COUNTER ^^^^^^^^^^^
// ---------------------------------------------------------------

wire [10:0] es_add,es_ptr;

assign es_add = es_ptr  + 11'b00000000001;

dffre_s  #(11) es_ptr_ff (
        .din(es_add[10:0]) ,
        .q(es_ptr[10:0]),
        .en(spu_maexp_incr_es_ptr),
        .rst(spu_maexp_es_e_ptr_rst), .clk (rclk), .se(se), .si(), .so());

// ---------------------------------------------------------------
// ^^^^^^^^^ ES_MAX_MINUS1 & COMPARE ^^^^^^^^^
// ---------------------------------------------------------------
wire [10:0] es_max_minus1_q,es_max_minus1;
//wire [8:0] es_max_plus1;
wire [7:0] es_max_plus1;

//assign es_max_plus1[8:0] = {1'b0,spu_madp_maaddr_reg[47:40]} + 9'b000000001;
assign es_max_plus1[7:0] = spu_madp_maaddr_reg[47:40] + 8'b00000001;

// vlint error:left size: 11,  right size: 12
//assign es_max_minus1[10:0] = {es_max_plus1[8:0],3'b000} - 11'b00000000001;
assign es_max_minus1[10:0] = {es_max_plus1[7:0],3'b000} - 11'b00000000001;

dffre_s  #(11) esmax_minus1_ptr_ff (
        .din(es_max_minus1[10:0]) ,
        .q(es_max_minus1_q[10:0]),
        .en(spu_maexp_es_max_init),//save es_max at start of maexp_op
        .rst(spu_maexp_es_e_ptr_rst), .clk (rclk), .se(se), .si(), .so());

assign spu_maaddr_esmax = (es_max_minus1_q[10:0] == es_ptr[10:0]);


// ---------------------------------------------------------------
// ^^^^^^^^^^^^^^ MOD64 CHECK ^^^^^^^^^^^
// ---------------------------------------------------------------

wire max_mod64_reached;
wire max_mod64_reached_q;
wire max_mod64_reached_pulse;


assign max_mod64_reached = &es_ptr[5:0];

assign spu_maaddr_esmod64 = max_mod64_reached;

dff_s  #(1) mod64_pulse_ff (
        .din(max_mod64_reached) ,
        .q(max_mod64_reached_q),
        .clk (rclk), .se(se), .si(), .so());

assign max_mod64_reached_pulse = ~max_mod64_reached_q & max_mod64_reached;

// ---------------------------------------------------------------
// ^^^^^^^^^^^^^^ E PTR ^^^^^^^^^^^
// ---------------------------------------------------------------
// E ptr 
wire [6:0] e_add;

assign e_add = e_ptr + 7'b0000001;

dffre_s  #(7) e_ptr_ff (
        .din(e_add[6:0]) ,
        .q(e_ptr[6:0]),
        .en(max_mod64_reached_pulse),
        .rst(spu_maexp_es_e_ptr_rst), .clk (rclk), .se(se), .si(), .so());


endmodule

