module log_sum2_32bit

#(
	parameter WIDTH = 32,
	parameter ENDMEMBER = 21
)

(
	// Input Ports
	input clk,rst,
	input [(WIDTH*ENDMEMBER-1):0] fila,
	input req,
	// Output Ports
	output [12:0]result,
	output reg ack
);

reg [(WIDTH*ENDMEMBER-1):0] diagonal_reg,diagonal_next;
wire [WIDTH-1:0] cero;
wire [7:0] log_result;
assign cero = 3'b000;
wire [WIDTH-1:0]abs_result;
reg [2:0]state_reg,state_next;
reg en_diagonal,nuevo;
reg [12:0] acumulador_reg,acumulador_next;
reg en_acumulador,rst_sync;
wire segundo_termino_cero;

localparam 	state_idle 		= 	3'h1,
				state_op			=	3'h2,
				state_fin		=	3'h4;

always@(posedge clk,posedge rst)
begin
	if (rst)
		diagonal_reg <= 3'b000;
	else
		diagonal_reg <= diagonal_next;
end

always@(*)
begin
	if (en_diagonal)
		if (nuevo)
			diagonal_next= fila;
		else
			diagonal_next= {{diagonal_reg[(WIDTH*(ENDMEMBER-1)-1):0]},{cero}};
	else
		diagonal_next= diagonal_reg;
end

abs #(.WIDTH(WIDTH)) stage_abs
(
	.number(diagonal_reg[WIDTH*ENDMEMBER-1:WIDTH*(ENDMEMBER-1)]),
	.result(abs_result)
);

log_32bit #(.WIDTH(WIDTH)) stage_log
(
	.number(abs_result),
	.result(log_result)
);

always@(posedge clk,posedge rst)
begin
	if (rst)
		acumulador_reg <= 3'b000;
	else
		acumulador_reg <= acumulador_next;
end

always@(*)
begin
acumulador_next= acumulador_reg;
if (en_acumulador)
	if (rst_sync)
		acumulador_next = 3'b000;
	else
		acumulador_next = acumulador_reg + log_result;
else
acumulador_next= acumulador_reg;
end

assign segundo_termino_cero = (diagonal_reg[WIDTH*(ENDMEMBER-1)-1:WIDTH*(ENDMEMBER-2)]==3'b00)?1'b1:1'b0;

always@(posedge clk,posedge rst)
begin
	if (rst)
		state_reg <= state_idle;
	else 
		state_reg <= state_next;
end

always@(*)
begin
state_next=state_reg;
en_acumulador=1'b0;
en_diagonal=1'b0;
rst_sync=1'b0;
nuevo=1'b0;
ack=1'b0;
case (state_reg)
state_idle:
begin
rst_sync=1'b1;
en_acumulador=1'b1;
if(req)
begin
	state_next=state_op;
	en_diagonal=1'b1;
	nuevo=1'b1;
end
end
state_op:
begin
en_diagonal=1'b1;
en_acumulador=1'b1;
if (segundo_termino_cero)
begin
	state_next=state_fin;
end
end
state_fin:
begin
ack=1'b1;
if (~req)
begin
	ack=1'b0;
	state_next=state_idle;
end
end
default:
begin
state_next=state_idle;
en_acumulador=1'b0;
en_diagonal=1'b0;
rst_sync=1'b0;
nuevo=1'b0;
end
endcase
end

assign result= acumulador_reg;

endmodule
