//+FHDR--------------------------------------------------------------------------------------------------------
//  Company: 
//-----------------------------------------------------------------------------------------------------------------
//  File Name             :    IIR_Filter.v
//  Department            :    
//  Author                :    thfu
//  Author's Tel          :     
//-----------------------------------------------------------------------------------------------------------------
//  Relese History
//  Version     Date            Author          Description
//  0.4         2024-05-28      thfu
//2024-05-28 10:22:49 
//-----------------------------------------------------------------------------------------------------------------
//  Keywords            :       
//
//-----------------------------------------------------------------------------------------------------------------
//  Parameter
//
//-----------------------------------------------------------------------------------------------------------------
//  Purpose                 :
//                      
//-----------------------------------------------------------------------------------------------------------------
//  Target Device:        
//  Tool versions:        
//-----------------------------------------------------------------------------------------------------------------
//  Reuse Issues
//  Reset Strategy: 
//  Clock Domains: 
//  Critical Timing:
//  Asynchronous I/F:
//  Synthesizable (y/n): 
//  Other:
//-FHDR--------------------------------------------------------------------------------------------------------
module  IIR_Filter_p8 #(
 parameter  data_in_width       = 16 
,parameter  coef_width          = 32 
,parameter  frac_data_out_width = 20//X for in,5
,parameter  frac_coef_width     = 31//division
)
(
 input	 rstn
,input	 clk
,input	 en
,input   signed	[data_in_width-1:0]   dinp0
,input   signed	[data_in_width-1:0]   dinp1
,input   signed	[data_in_width-1:0]   dinp2
,input   signed	[data_in_width-1:0]   dinp3
,input   signed	[data_in_width-1:0]   dinp4
,input   signed	[data_in_width-1:0]   dinp5
,input   signed	[data_in_width-1:0]   dinp6
,input   signed	[data_in_width-1:0]   dinp7

,input   signed	[coef_width-1   :0]   a_re
,input   signed	[coef_width-1   :0]   a_im
,input   signed	[coef_width-1   :0]   ab_re
,input   signed	[coef_width-1   :0]   ab_im
,input   signed	[coef_width-1   :0]   abb_re
,input   signed	[coef_width-1   :0]   abb_im
,input   signed	[coef_width-1   :0]   ab_pow3_re
,input   signed	[coef_width-1   :0]   ab_pow3_im
,input   signed	[coef_width-1   :0]   ab_pow4_re
,input   signed	[coef_width-1   :0]   ab_pow4_im
,input   signed	[coef_width-1   :0]   ab_pow5_re
,input   signed	[coef_width-1   :0]   ab_pow5_im
,input   signed	[coef_width-1   :0]   ab_pow6_re
,input   signed	[coef_width-1   :0]   ab_pow6_im
,input   signed	[coef_width-1   :0]   ab_pow7_re
,input   signed	[coef_width-1   :0]   ab_pow7_im

,input   signed	[coef_width-1   :0]   b_pow8_re
,input   signed	[coef_width-1   :0]   b_pow8_im
,output  signed	[data_in_width-1:0]   dout
);


wire	signed	[data_in_width+frac_data_out_width:0] 	 x1_re;
wire	signed	[data_in_width+frac_data_out_width:0]	 x1_im;
mult_C
#(
 .A_width(data_in_width) 
,.B_width(data_in_width) 
,.C_width(coef_width+frac_data_out_width) 
,.D_width(coef_width+frac_data_out_width) 
,.frac_coef_width(frac_coef_width) 
)
inst_c1         (
                                            .clk	(clk    	),
                                            .rstn	(rstn   	),
                                            .en		(en     	),
                                            .a		(dinp0		),
                                            .b		(16'b0		),
                                            .c		({a_re,{frac_data_out_width{1'b0}}}),
                                            .d		({a_im,{frac_data_out_width{1'b0}}}),
                                            .Re		(x1_re   	),//a*x*dinp0
                                            .Im		(x1_im   	)
	        );

wire	signed	[data_in_width+frac_data_out_width:0]  x2_re;
wire	signed	[data_in_width+frac_data_out_width:0]  x2_im;
mult_C	
#(
 .A_width(data_in_width) 
,.B_width(data_in_width) 
,.C_width(coef_width+frac_data_out_width) 
,.D_width(coef_width+frac_data_out_width) 
,.frac_coef_width(frac_coef_width) 
)
inst_c2         (
                                            .clk	(clk    	),
                                            .rstn	(rstn   	),
                                            .en		(en     	),
                                            .a		(dinp1		),
                                            .b		(16'd0		),
                                            .c		({ab_re,{frac_data_out_width{1'b0}}}	  	),
                                            .d		({ab_im,{frac_data_out_width{1'b0}}}	  	),
                                            .Re		(x2_re     	),//a*b*dinp1
                                            .Im		(x2_im     	)
		);

wire	signed	[data_in_width+frac_data_out_width:0]  x3_re;
wire	signed	[data_in_width+frac_data_out_width:0]  x3_im;
mult_C	
#(
 .A_width(data_in_width) 
,.B_width(data_in_width) 
,.C_width(coef_width+frac_data_out_width) 
,.D_width(coef_width+frac_data_out_width) 
,.frac_coef_width(frac_coef_width) 
)
inst_c3         (
                                            .clk	(clk    	),
                                            .rstn	(rstn   	),
                                            .en		(en     	),
                                            .a		(dinp2		),
                                            .b		(16'd0		),
                                            .c		({abb_re,{frac_data_out_width{1'b0}}}	  	),
                                            .d		({abb_im,{frac_data_out_width{1'b0}}}	  	),
                                            .Re		(x3_re     	),//a*b*b*dinp2
                                            .Im		(x3_im     	)
		);
wire	signed	[data_in_width+frac_data_out_width:0]  x4_re;
wire	signed	[data_in_width+frac_data_out_width:0]  x4_im;
mult_C	
#(
 .A_width(data_in_width) 
,.B_width(data_in_width) 
,.C_width(coef_width+frac_data_out_width) 
,.D_width(coef_width+frac_data_out_width) 
,.frac_coef_width(frac_coef_width) 
)
inst_c4         (
                                            .clk	(clk    	),
                                            .rstn	(rstn   	),
                                            .en		(en     	),
                                            .a		(dinp3		),
                                            .b		(16'd0		),
                                            .c		({ab_pow3_re,{frac_data_out_width{1'b0}}}	  	),
                                            .d		({ab_pow3_im,{frac_data_out_width{1'b0}}}	  	),
                                            .Re		(x4_re     	),//a*b^3*dinp3
                                            .Im		(x4_im     	)
		);
wire	signed	[data_in_width+frac_data_out_width:0]  x5_re;
wire	signed	[data_in_width+frac_data_out_width:0]  x5_im;
mult_C	
#(
 .A_width(data_in_width) 
,.B_width(data_in_width) 
,.C_width(coef_width+frac_data_out_width) 
,.D_width(coef_width+frac_data_out_width) 
,.frac_coef_width(frac_coef_width) 
)
inst_c5         (
                                            .clk	(clk    	),
                                            .rstn	(rstn   	),
                                            .en		(en     	),
                                            .a		(dinp4		),
                                            .b		(16'd0		),
                                            .c		({ab_pow4_re,{frac_data_out_width{1'b0}}}	  	),
                                            .d		({ab_pow4_im,{frac_data_out_width{1'b0}}}	  	),
                                            .Re		(x5_re     	),//a*b^4*dinp4
                                            .Im		(x5_im     	)
		);
wire	signed	[data_in_width+frac_data_out_width:0]  x6_re;
wire	signed	[data_in_width+frac_data_out_width:0]  x6_im;
mult_C	
#(
 .A_width(data_in_width) 
,.B_width(data_in_width) 
,.C_width(coef_width+frac_data_out_width) 
,.D_width(coef_width+frac_data_out_width) 
,.frac_coef_width(frac_coef_width) 
)
inst_c6         (
                                            .clk	(clk    	),
                                            .rstn	(rstn   	),
                                            .en		(en     	),
                                            .a		(dinp5		),
                                            .b		(16'd0		),
                                            .c		({ab_pow5_re,{frac_data_out_width{1'b0}}}	  	),
                                            .d		({ab_pow5_im,{frac_data_out_width{1'b0}}}	  	),
                                            .Re		(x6_re     	),//a*b^5*dinp5
                                            .Im		(x6_im     	)
		);
wire	signed	[data_in_width+frac_data_out_width:0]  x7_re;
wire	signed	[data_in_width+frac_data_out_width:0]  x7_im;
mult_C	
#(
 .A_width(data_in_width) 
,.B_width(data_in_width) 
,.C_width(coef_width+frac_data_out_width) 
,.D_width(coef_width+frac_data_out_width) 
,.frac_coef_width(frac_coef_width) 
)
inst_c7         (
                                            .clk	(clk    	),
                                            .rstn	(rstn   	),
                                            .en		(en     	),
                                            .a		(dinp6		),
                                            .b		(16'd0		),
                                            .c		({ab_pow6_re,{frac_data_out_width{1'b0}}}	  	),
                                            .d		({ab_pow6_im,{frac_data_out_width{1'b0}}}	  	),
                                            .Re		(x7_re     	),//a*b^6*dinp6
                                            .Im		(x7_im     	)
		);
wire	signed	[data_in_width+frac_data_out_width:0]  x8_re;
wire	signed	[data_in_width+frac_data_out_width:0]  x8_im;
mult_C	
#(
 .A_width(data_in_width) 
,.B_width(data_in_width) 
,.C_width(coef_width+frac_data_out_width) 
,.D_width(coef_width+frac_data_out_width) 
,.frac_coef_width(frac_coef_width) 
)
inst_c8         (
                                            .clk	(clk    	),
                                            .rstn	(rstn   	),
                                            .en		(en     	),
                                            .a		(dinp7		),
                                            .b		(16'd0		),
                                            .c		({ab_pow7_re,{frac_data_out_width{1'b0}}}	  	),
                                            .d		({ab_pow7_im,{frac_data_out_width{1'b0}}}	  	),
                                            .Re		(x8_re     	),//a*b^7*dinp7
                                            .Im		(x8_im     	)
		);

wire	signed	[data_in_width+frac_data_out_width+1:0]  v_re;
wire	signed	[data_in_width+frac_data_out_width+1:0]	 v_im;

assign	v_re       =   x1_re + x2_re + x3_re + x4_re + x5_re + x6_re + x7_re + x8_re;
assign	v_im       =   x1_im + x2_im + x3_im + x4_im + x5_im + x6_im + x7_im + x8_im;

reg	signed	[data_in_width+frac_data_out_width+1:0]  v1_re;
reg	signed	[data_in_width+frac_data_out_width+1:0]	 v1_im;

always @(posedge clk or negedge rstn) 
  	if (!rstn)
		 begin
                v1_re    <=    'h0;
                v1_im    <=    'h0;
 		 end 
	 else if(en)
		 begin
                v1_re    <=    v_re;
                v1_im    <=    v_im;
		  end
	 else
		 begin
                v1_re    <=    v1_re;
                v1_im    <=    v1_im;
		  end

wire    signed	[data_in_width+frac_data_out_width+1:0]	 y_re;
wire    signed	[data_in_width+frac_data_out_width+1:0]	 y_im;
reg     signed	[data_in_width+frac_data_out_width+2:0]	 y1_re;
reg     signed	[data_in_width+frac_data_out_width+2:0]	 y1_im;

reg 	signed	[data_in_width-1:0]   dout_re;

mult_C
#(
 .A_width(data_in_width+frac_data_out_width+2) 
,.B_width(data_in_width+frac_data_out_width+2) 
,.C_width(coef_width) 
,.D_width(coef_width) 
,.frac_coef_width(frac_coef_width) 
)
inst_c9         (
                                            .clk	(clk    	),
                                            .rstn	(rstn   	),
                                            .en		(en     	),
                                            .a		(y_re		),
                                            .b		(y_im		),
                                            .c		(b_pow8_re	),
                                            .d		(b_pow8_im	),
                                            .Re		(y1_re     	),//b^8*y(n-1)
                                            .Im		(y1_im     	)
		);

assign	y_re       =   v1_re + y1_re;
assign	y_im       =   v1_im + y1_im;

wire signed	[data_in_width+frac_data_out_width+1:0] dout_round;

FixRound #(data_in_width+frac_data_out_width+2,frac_data_out_width) u_round1 (clk, rstn, en, y_re, dout_round);

always @(posedge clk or negedge rstn) 
  	if (!rstn)
		 begin
		    dout_re  <= 'h0;
		 end 
	 else if(en)
		 begin
		    dout_re  <= dout_round[frac_data_out_width+15:frac_data_out_width];
		  end
	 else
		 begin
		    dout_re  <= dout_re;
		  end

reg 	signed	[data_in_width-1:0]   dout_clip;

always @(posedge clk or negedge rstn) 
  	if (!rstn)
		 begin
		    dout_clip <= 'h0;
		 end 
	 else if(en)
		 begin
	         if(dout_round[frac_data_out_width+16:frac_data_out_width+15]==2'b01)
			dout_clip	<=	16'd32767;
		 else if(dout_round[frac_data_out_width+16:frac_data_out_width+15]==2'b10)
			dout_clip	<=	-16'd32768;
		 else
			dout_clip	<=	dout_re;		 
		 end
	 else
		 begin
		    dout_clip  <= dout_clip;
		  end

assign	dout = dout_clip;

endmodule

