module uwt_bior31
	#(
		parameter	L	=	1 // transform level
	)
	(
		input	wire			clock, frame, reset,
		input	wire	[23:0]	x,
		output	wire	[23:0]	d,
		output	wire	[23:0]	a,
		output	wire	[23:0]	peak,
		output	wire	[1:0]	flag
	);

	localparam	index1		=	1 << (L - 1);
	localparam	index2		=	2 << (L - 1);
	localparam	index3		=	3 << (L - 1);
	localparam	peak_index	=	((index3 + 1) >> 1) + 1;
	localparam	peak_shift	=	((L - 1) << 1) + (L - 1);
	localparam	zero		=	24'h800000;
	
	// Tapped delay line
	reg		[23:0]	tap_reg [index3:0];
	reg		[23:0]	tap_next [index3:0];
	
	reg		[23:0]	d_reg, d_next;
	reg		[23:0]	a_reg, a_next;
	reg		[23:0]	peak_reg, peak_next;

	reg		[23:0]	tmp1_reg, tmp1_next;
	reg		[23:0]	tmp2_reg, tmp2_next;

	reg				less_reg, less_next;
	reg				more_reg, more_next;

	reg		[1:0]	flag_reg, flag_next;

	reg				int_case_reg, int_case_next;

	integer			i;
	
	always @(posedge clock)
	begin
		if (reset)
		begin
			d_reg <= 0;
			a_reg <= 0;
			peak_reg <= 0;

			tmp1_reg <= 0;
			tmp2_reg <= 0;
			less_reg <= 1'b0;
			more_reg <= 1'b0;
			flag_reg <= 0;

			int_case_reg <= 1'b0;

			for(i = 0; i <= index3; i = i + 1)
			begin
				tap_reg[i] <= 0;
			end
		end
		else
		begin
			d_reg <= d_next;
			a_reg <= a_next;
			peak_reg <= peak_next;
			
			tmp1_reg <= tmp1_next;
			tmp2_reg <= tmp2_next;
			less_reg <= less_next;
			more_reg <= more_next;
			flag_reg <= flag_next;

			int_case_reg <= int_case_next;
			
			for(i = 0; i <= index3; i = i + 1)
			begin
				tap_reg[i] <= tap_next[i];
			end			
		end
	end
	
	always @*
	begin
		d_next = d_reg;
		a_next = a_reg;
		peak_next = peak_reg;
		
		tmp1_next = tmp1_reg;
		tmp2_next = tmp2_reg;
		less_next = less_reg;
		more_next = more_reg;
		flag_next = flag_reg;

		int_case_next = int_case_reg;
		
		for(i = 0; i <= index3; i = i + 1)
		begin
			tap_next[i] = tap_reg[i];
		end

		case (int_case_reg)

			0:
			begin
				if (frame)
				begin		
					// Tapped delay line: shift one
					for(i = 0; i < index3; i = i + 1)
					begin
						tap_next[i+1] = tap_reg[i];
					end
					
					// Input in register 0
					tap_next[0] = x;

					tmp1_next = tap_reg[index3] + {tap_reg[index2][22:0], 1'b0} + tap_reg[index2];
					tmp2_next = {tap_reg[index1][22:0], 1'b0} + tap_reg[index1] + tap_reg[0];

					more_next = (d_reg > zero);
					less_next = (d_reg < zero);
	
					flag_next[0] = (less_reg) & (~less_next);
					flag_next[1] = (more_reg) & (~more_next);

					peak_next = (tap_reg[peak_index] >> peak_shift);

					int_case_next = 1'b1;
				end
			end

			1:
			begin
				// Compute d and a with the filter coefficients.
				// The coefficients are [1, 3, -3, -1] and [1, 3, 3, 1]
				d_next = zero - tmp1_reg + tmp2_reg;
				a_next = tmp1_reg + tmp2_reg;
				int_case_next = 1'b0;
			end

		endcase
		
	end

	// output logic
	assign	d		=	d_reg;
	assign	a		=	a_reg;
	assign	peak	=	peak_reg;
	assign	flag	=	flag_reg;

endmodule
