/* FIR Filter
* Steve Harwood, PSU EE572, Fall 1999
* This module is the top level of the FIR filter for the spread spectrum
* modulator project.  
*
* The filter is an upsampling (by four) FIR lowpass filter.  So, for every
* one data input sample, there are four output samples.  Further, to make
* use of the higher clock frequency capablities of the Xilinx FPGA's, both 
* the I and Q channel FIR filters are implemented in a single, multiplexed,
* filter (the filters are identical). This pushes the filter to operate at
* a higher data rate, but makes up for it in cost savings.
*
* Due to the multiplexing and upsampling operations, several small state 
* machines are required for desired operation.
*/

module fir12(clk,we,idin,qdin,coeff,
	     rst,dval,iout_reg,qout_reg,iqclko,
	     prog, paddr);

  input clk,rst,dval;
  input [11:0] idin,qdin,coeff, we;
  input prog;
  input [3:0] paddr;

  parameter OUT_WIDTH = 18;

  output [OUT_WIDTH-1:0] iout_reg, qout_reg;
  output iqclko;

  reg [OUT_WIDTH-1: 0] iout_reg, qout_reg;
  reg iqclko, fsinc, fti;
  reg [11:0] hen, fidata;
  reg ireg_en, qreg_en, iqsel;

  wire [OUT_WIDTH-1:0] filt_out;
  wire adce, acen, ld ;
  wire [1:0] fstate, asel;

// I/Q input data MUX and register, filt out reg CE
  always @ (posedge clk or posedge rst)
   begin
    if (rst) 
     begin
       fidata <= 12'h0;
       iqsel <= 1'b0;
       ireg_en <= 1'b0;
       qreg_en <= 1'b0;
     end
    else
     begin
      iqsel <= (adce ? !iqsel : iqsel);

      if(adce)
        fidata <= (iqsel ? qdin : idin);

      ireg_en <= ld & iqsel;
      qreg_en <= ld & !iqsel;
     end
   end

// input data register clock enable
// The reset parameter to the ring counter is overridden here to force 
// to 5'b00001 at startup
  j5ctr1 #(1) jadce(.clk(clk), .rst(rst), .en(1'b1), .q(adce) );

// Filter State controller, Interpolation Tap enable
  j5ctr1 jld(.clk(clk), .rst(rst), .en(1'b1), .q(ld) );
  cnt2 cfstate(.clk(clk), .rst(rst), .en(fsinc), .cnt(fstate));

  //Fstate Increment control, tap enable
  always @(posedge clk or posedge rst)
   begin
    if (rst) 
     begin
       fti <= 1'b0;
       fsinc <= 1'b0;
       hen <= 12'h0;
     end
    else
     begin
       fti <= fti ^ (asel == 2'b11);
       fsinc <= fti & adce;

       if (!iqsel && (fstate == 2'b11) )
	 begin
	   hen[0] <= dval;
	   hen[11:1] <= hen[10:0];
	 end
     end
   end

// Accumulator state controller
  cnt2 casel(.clk(clk), .rst(rst), .en(!ld), .cnt(asel) );

// Accumulator output register controller
  j5ctr1 jacen(.clk(clk),.rst(rst),.en(1'b1),.q(acen) );

// Instantiate the filter
  bbfilt  fir(.clk(clk),.rst(rst),.idata(fidata),
	      .coeff(coeff),.we(we),.filt_out(filt_out),
	      .acsel(asel),.acld(ld),.acclk(clk),.ac_reg_en(acen),
	      .hen(hen),.fstate(fstate), .paddr(paddr), .prog(prog) );


//I and Q output registers
 always @(posedge clk or posedge rst)
  begin
   if (rst)
    begin
       iout_reg <= 0;
       qout_reg <= 0;
    end
   else
    begin
       if (ireg_en) iout_reg <= filt_out;
       if (qreg_en) qout_reg <= filt_out;
    end
  end

/* I and Q output clock, TFF: as it comes out of reset, 
*  ireg_en clears, qreg_en sets */

 always @(posedge clk or posedge rst)
  begin
   if (rst) 
      iqclko <= 1'b1;
   else
      iqclko <= (ireg_en | qreg_en) ? !iqclko:iqclko;
  end

endmodule

/* 2-bit counter for fstate and asel control */
module cnt2(clk,rst,en,cnt);
 input clk,rst,en;
 output [1:0] cnt;

 reg [1:0] cnt;

 always @(posedge clk or posedge rst)
  begin
    if (rst)
     cnt <= 2'b00;
    else 
     begin
      if(en)
	cnt <= cnt+1;
     end
  end
endmodule

// 5-bit Ring counter
module j5ctr1(clk,rst,en,q);
 input clk,rst,en;
 output q;

 reg [4:0] jctr;
 reg q;
 parameter JRST = 4;

 always @(posedge clk or posedge rst)
  begin
   if (rst) jctr <= JRST; 
   else
     if(en)
      begin
       jctr[0] <= jctr[4];
       jctr <= jctr << 1;
      end
  end
 
 always @(jctr[4]) q = jctr[4];
  
endmodule
