/*
 IIR biquad
 
 Copyright (c) 2009 Dimtel, Inc., All Rights Reserved

 $Id: iir.v,v 1.3 2010/10/05 16:13:50 dim Exp $
 $Date: 2010/10/05 16:13:50 $
 $Author: dim $
 $Revision: 1.3 $
 $Log: iir.v,v $
 Revision 1.3  2010/10/05 16:13:50  dim
 Updates prior to iGp12 release

 Revision 1.2  2009/08/29 19:53:53  dim
 Extensive timing optimization

 Revision 1.1  2009/06/02 20:04:07  dim
 Initial import


*/

`timescale 1ns/100ps

`include "bus_width.h"

module iir #(parameter iwidth=14, parameter owidth=14) (
  // Local bus interface
  input			clk,	// Bus clock
  input			strobe, // Bus strobe
  input			ce,	// Module select
  input			rd,	// Read/write direction
  output		ack,	// Bus ack
  input [3:0]		addr,	// Address
  input	[`IFACE-1:0]	din,	// Input data bus
  output [`IFACE-1:0]  	dout,	// Output data bus

  // Signal processing channel
  input			dspclk, // DSP clock
  input signed [iwidth-1:0] in,	// Filter input
  input			setsel,	// Coefficient set select
  input	[2:0]		sg,	// Shift gain
  output reg [owidth-1:0] out,	// output data stream
  output reg		sat	// saturation bits
);
  // Internal wiring and FFs
  wire [1:0] sat_iir;
  reg  [4:0] ce_cf;
  wire [4:0] ack_cf;
  wire [15:0] a1data, a2data, b0data, b1data, b2data;
  wire signed [15:0] a1, a2, b0, b1, b2, fir_in;

  // FIR data pipeline
  reg signed [13:0] fir_tap0 = 14'b0;
  // FIR tap products. 16 bit coeffs + 14 bit data -> 29 bits
  // (-32768 coeff not allowed).
  reg signed [28:0] tap0prod = 29'b0, tap1prod = 29'b0, tap2prod = 29'b0;
  // Two taps summed together, 30 bits
  reg signed [29:0] sum_fir = 30'b0;
  // Three taps - 31 bit wide
  reg signed [30:0] sum = 31'b0;
  // Intermediate output of the saturator between FIR and IIR
  wire [15:0] out_fir_c;
  // Register the output
  reg signed [15:0] out_fir = 16'b0;

  cfreg2 a1reg(.clk(clk), .strobe(strobe), .ce(ce_cf[0]), .rd(rd),
               .ack(ack_cf[0]), .addr(addr[0]), .din(din), .dout(a1data),
               .setsel(setsel), .cout(a1));
  cfreg2 a2reg(.clk(clk), .strobe(strobe), .ce(ce_cf[1]), .rd(rd),
               .ack(ack_cf[1]), .addr(addr[0]), .din(din), .dout(a2data),
               .setsel(setsel), .cout(a2));
  cfreg2 b0reg(.clk(clk), .strobe(strobe), .ce(ce_cf[2]), .rd(rd),
               .ack(ack_cf[2]), .addr(addr[0]), .din(din), .dout(b0data),
               .setsel(setsel), .cout(b0));
  cfreg2 b1reg(.clk(clk), .strobe(strobe), .ce(ce_cf[3]), .rd(rd),
               .ack(ack_cf[3]), .addr(addr[0]), .din(din), .dout(b1data),
               .setsel(setsel), .cout(b1));
  cfreg2 b2reg(.clk(clk), .strobe(strobe), .ce(ce_cf[4]), .rd(rd),
               .ack(ack_cf[4]), .addr(addr[0]), .din(din), .dout(b2data),
               .setsel(setsel), .cout(b2));

  // Address decoding
  always @(addr[3:1] or ce or ce_cf)
    case (addr[3:1])
      3'b000:  ce_cf = {4'b0, ce      };
      3'b001:  ce_cf = {3'b0, ce, 1'b0};
      3'b010:  ce_cf = {2'b0, ce, 2'b0};
      3'b011:  ce_cf = {1'b0, ce, 3'b0};
      default: ce_cf = {      ce, 4'b0};
    endcase
      
  busmux16 busmux(.cebus({11'b0, ce_cf}), .ackbus({11'b0, ack_cf}),
                .strobe(strobe), .ack(ack),
                .d4({16'b0, b2data}),
                .d3({16'b0, b1data}), .d2({16'b0, b0data}),
                .d1({16'b0, a2data}), .d0({16'b0, a1data}),
                .d15(`IFACE'b0), .d14(`IFACE'b0), .d13(`IFACE'b0),
                .d12(`IFACE'b0), .d11(`IFACE'b0), .d10(`IFACE'b0), 
                .d9(`IFACE'b0), .d8(`IFACE'b0), .d7(`IFACE'b0),
                .d6(`IFACE'b0), .d5(`IFACE'b0),
                .data(dout));

  // FIR section - first for gain control
  always @(posedge dspclk) begin
    fir_tap0 <= in;
    tap0prod <= in * b0;
    tap1prod <= in * b1;
    tap2prod <= fir_tap0 * b2;
    sum_fir  <= tap1prod + tap2prod;
    sum      <= sum_fir + tap0prod;
  end
      
  // IIR section
  reg signed [16:0] sum1 = 17'b0;
  wire signed [17:0] sum0_raw;
  wire signed [15:0] sum0;
  reg signed [15:0] sum_iir0;
  reg signed [30:0] a1prod = 31'b0, a2prod = 31'b0;
  wire signed [15:0] a2prod_sel = a2prod[30:15];
  wire signed [16:0] a1prod_sel = a1prod[30:14];

  // Adder/saturator
  assign sum0_raw     = a1prod_sel + sum1;
  sat #(.imsb(17), .omsb(15), .owidth(16)) sat_sum0(.ins(sum0_raw),
        .out(sum0), .sat(sat_iir[0]));

  always @(posedge dspclk) begin
    out_fir  <= sum[30:15];
    a1prod   <= a1 * sum0;
    a2prod   <= a2 * sum0;
    sum1     <= out_fir + a2prod_sel;
    sum_iir0 <= sum0;
  end

  // Saturation after the IIR
  wire [13:0] iir_out;
  sat #(.imsb(16), .omsb(13), .owidth(14)) sat_out(.ins({sum_iir0, 1'b0}),
        .out(iir_out), .sat(sat_iir[1]));

  // Generate output and registered sat
  always @(posedge dspclk) begin
      out <= iir_out;
      sat <= sat_iir[1] | sat_iir[0];
  end
endmodule /* iir */
