module iir (clk, reset, start, din, params, dout, ready,iir_start,iir_done);
input clk, reset, start;
input [7:0] din;
input [15:0] params;
output [7:0] dout;
reg [7:0] dout;
output ready;
wire ready;
reg [6:0] finite_counter;
wire count0;
input iir_start;
output iir_done;
wire iir_done;
reg del_count0;
 
function [31:0] mul_tc_16_16;
input [15:0] A;
input [15:0] B;
input CLK;
reg sgn;
begin
sgn = A[15] ^ B[15];
if (A[15] == 1'b1) A = ~A + 1'b1;
if (B[15] == 1'b1) B = ~B + 1'b1;
mul_tc_16_16 = A * B;
if (sgn == 1'b1) mul_tc_16_16 = ~mul_tc_16_16 + 1'b1;
end
endfunction
 
function [23:0] mul_tc_8_16;
input [7:0] A;
input [15:0] B;
input CLK;
reg sgn;
begin
sgn = A[7] ^ B[15];
if (A[7] == 1'b1) A = ~A + 1'b1;
if (B[15] == 1'b1) B = ~B + 1'b1;
mul_tc_8_16 = A * B;
if (sgn == 1'b1) mul_tc_8_16 = ~mul_tc_8_16 + 1'b1;
end
endfunction
 
reg [15:0] a1, a2, b0, b1, b2, yk1, yk2;
reg [7:0] uk, uk1, uk2 ;
reg [28:0] ysum ;
reg [26:0] yk ;
reg [22:0] utmp;
reg [3:0] wait_counter ;
// temporary variable
wire [31:0] yo1, yo2;
wire [23:0] b0t, b1t, b2t;
 
 
reg [3:0] state, next_state ;
parameter
idle = 0 ,
load_a2 = 2 ,
load_b0 = 3 ,
load_b1 = 4 ,
load_b2 = 5 ,
wait4_start = 6 ,
latch_din = 7 ,
compute_a = 8 ,
compute_b = 9 ,
compute_yk = 10 ,
wait4_count = 11 ,
latch_dout = 12 ;
 
// STATE MACHINE
always @(posedge clk ) begin
if (reset || ~iir_start)
state <= idle ;
else
state <= next_state ;
end
 
always @(state or start or din or wait_counter or iir_start or count0)
begin
case (state )
idle : if (iir_start)
next_state <= load_a2 ;
else
next_state <= idle;
load_a2 : next_state <= load_b0 ;
load_b0 : next_state <= load_b1 ;
load_b1 : next_state <= load_b2 ;
load_b2 : next_state <= wait4_start ;
wait4_start : if (start)
next_state <= latch_din ;
else
next_state <= wait4_start ;
latch_din : next_state <= compute_a ;
compute_a : next_state <= compute_b ;
compute_b : next_state <= compute_yk ;
compute_yk : next_state <= wait4_count ;
wait4_count : if (wait_counter==0 )
next_state <= latch_dout ;
else
next_state <= wait4_count ;
 
latch_dout : if (count0)
next_state <= idle;
else
next_state <= wait4_start ;
default : next_state <= idle;
endcase
end
// END OF STATE MACHINE
 
 
 
assign yo1 = mul_tc_16_16(yk1, a1, clk);
assign yo2 = mul_tc_16_16(yk2, a2, clk);
assign b0t = mul_tc_8_16(uk, b0, clk);
assign b1t = mul_tc_8_16(uk1, b1, clk);
assign b2t = mul_tc_8_16(uk2, b2, clk);
assign ready = (state==wait4_start) ;
// A COEFFICENTS
always @(posedge clk or posedge reset) begin
if (reset ) begin
uk <= 0 ;
uk1 <= 0 ;
uk2 <= 0 ;
yk1 <= 0 ;
yk2 <= 0 ;
yk <= 0 ;
ysum <= 0 ;
utmp <= 0 ;
a1 <= 0 ;
a2 <= 0 ;
b0 <= 0 ;
b1 <= 0 ;
b2 <= 0 ;
dout <= 0 ;
end
else begin
if (state==compute_yk ) begin
uk1 <= uk ;
uk2 <= uk1 ;
yk <= ysum[26:0] + {utmp[22], utmp[22], utmp[22], utmp[22], utmp};
end
else begin
uk1 <= uk1 ;
uk2 <= uk2 ;
yk <= yk ;
end
 
if (state==wait4_start & start ) uk <= din ; else uk <= uk ;
if (state==idle ) a1 <= params ; else a1 <= a1 ;
if (state==load_a2 ) a2 <= params ; else a2 <= a2 ;
if (state==load_b0 ) b0 <= params ; else b0 <= b0 ;
if (state==load_b1 ) b1 <= params ; else b1 <= b1 ;
if (state==load_b2 ) b2 <= params ; else b2 <= b2 ;
 
if (state==compute_a )
ysum <= yo1[31:3] + yo2[31:3];
else
ysum <= ysum ;
 
if (state==compute_b )
utmp <= b0t[22:0] + b1t[22:0] + b2t[22:0];
else
utmp <= utmp ;
 
if (state==wait4_count && wait_counter==0) begin
dout <= yk[26:19];
yk1 <= yk[26:11] ;
yk2 <= yk1 ;
end
else begin
dout <= dout ;
yk1 <= yk1 ;
yk2 <= yk2 ;
end
end
end
 
 
// wait counter, count 4 clock after sum is calculated, to
// time outputs are ready, and filter is ready to accept next
// input
always @(posedge clk or posedge reset ) begin
if (reset )
wait_counter <= 0 ;
else begin
if (state==compute_yk )
wait_counter <= 4 ;
else if (state==wait4_count)
wait_counter <= wait_counter - 1;
else
wait_counter <= wait_counter ;
end
end
 
always @(posedge clk) begin
if (reset)
finite_counter<=100;
else
if (iir_start)
finite_counter<=finite_counter -1;
else
finite_counter<=finite_counter;
end
 
assign count0=finite_counter==7'b0;
 
always @(posedge clk) begin
del_count0 <= count0;
end
 
assign iir_done = (count0 && ~del_count0);
 
endmodule