module NFINDR2_32bit
#(
	parameter	WIDTH				=32,
	parameter	ENDMEMBER		=21,
	parameter	PIXEL_NUMBER	=350*350,//350*350,
	parameter	LOG_DIM			=13
)
(
	input																	clk,rst,
	input																	init,new_data,
	input		[WIDTH*(ENDMEMBER-1)-1:0]							pixel,
	input		[16:0]													position,
	output	[(17)*ENDMEMBER-1:0]									position_endmember,
	output	reg														ack_pixel
);


reg 		move_matrix,save_pixel;
wire 		[4:0] id_matrix;
wire 		[ENDMEMBER*ENDMEMBER*WIDTH-1:0] matrix;
reg req_cal_det;
wire cero;
wire ack_cal_det;
wire [LOG_DIM-1:0] det_matrix;

reg move_pos,save_pos;
wire [ENDMEMBER*17-1:0] all_pos;
wire [4:0] id_pos;

reg [LOG_DIM-1:0]det_act;
reg new_comparison,rst_mayor;
wire [4:0] id_mayor;
wire ack_data_com,change;
reg rst_det,en_det;
wire [LOG_DIM-1:0]mayor;


localparam 	s_idle			=3'h0,
				s_init_matrix	=3'h1,
				s_comp_init		=3'h2,
				s_cal_det		=3'h3,
				s_comp_loop		=3'h4,
				s_cambiar		=3'h5,
				s_ack				=3'h6;

reg [2:0] state_reg,state_next;

endmembers_reg #(.WIDTH(WIDTH),.ENDMEMBER(ENDMEMBER)) state_matrix
(
	.clk(clk),
	.rst(rst),
	.fila_de_prueba(pixel),
	.move(move_matrix),
	.save(save_pixel),
	.matrix(matrix),
	.id(id_matrix)
);

cal_det_par_32bit #(.WIDTH(WIDTH),.ENDMEMBER(ENDMEMBER)) state_cal_det
(
	.clk(clk),
	.rst(rst),
	.req(req_cal_det),
	.matrix_nueva(matrix),
	.determinante(det_matrix),
	.ack(ack_cal_det)
);

registro_serie #(.WIDTH(17),.REGISTER_NUMBER(ENDMEMBER)) state_registro_de_posiciones
(
	.clk(clk),
	.rst(rst),
	.new_data(position),
	.move(move_pos),
	.save(save_pos),
	.registro(all_pos),
	.id(id_pos)
);

assign position_endmember=all_pos;

comparador #(.WIDTH(LOG_DIM),.NUMBER(ENDMEMBER)) stage_comparador
(
	.clk(clk),
	.rst(rst),
	.data(det_matrix),
	.actual(det_act),
	.new_data(new_comparison),
	.rst_mayor(rst_mayor),
	.id_in(id_matrix),
	.ack_data(ack_data_com),
	.change(change),
	.mayor(mayor),
	.id_out(id_mayor)
);

always@(posedge clk,posedge rst)
begin
if (rst)
	det_act <= 12'h000;
else
	begin
	if (rst_det)
		det_act <= 12'h000;
	else if(en_det)
		det_act <= mayor;
	end
end

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

wire id_matrix_cero,id_pos_cero,id_matrix_veinte,id_matrix_id_mayor;
assign id_matrix_cero=(id_matrix==3'h0)?1'b1:1'b0;
assign id_pos_cero=(id_pos==3'h0)?1'b1:1'b0;
assign id_matrix_veinte=(id_matrix==5'd20)?1'b1:1'b0;
assign id_matrix_id_mayor=(id_matrix==id_mayor)?1'b1:1'b0;
always@(*)
begin
move_matrix=1'b0;
save_pixel=1'b0;
req_cal_det=1'b0;
move_pos=1'b0;
save_pos=1'b0;
rst_det=1'b0;
en_det=1'b0;
new_comparison=1'b0;
rst_mayor=1'b0;
state_next=state_reg;
ack_pixel=1'b0;
casez(state_reg)
s_idle:
begin
if (id_matrix_cero)
begin
if(id_pos_cero)
	begin
		if (init)
			state_next=s_init_matrix;
		else
		begin
			if (new_data)
			begin
				rst_mayor = 1'b1;
				state_next = s_cal_det;
			end
		end
	end
	else
	begin
		move_pos=1'b1;
	end
end
else
begin
	move_matrix=1'b1;
end
end
s_init_matrix:
begin
if (new_data)
begin
	save_pixel=1'b1;
	move_matrix=1'b1;
	ack_pixel=1'b1;
	save_pos=1'b1;
	move_pos=1'b1;
	state_next=s_comp_init;
end
end
s_comp_init:
begin
if (~new_data)
begin
	if (id_matrix_cero)
	begin
		rst_det=1'b1;
		state_next=s_idle;
	end
	else
		state_next=s_init_matrix;
end
end
s_cal_det:
begin
req_cal_det=1'b1;
if (ack_cal_det)
	state_next=s_comp_loop;
end
s_comp_loop:
begin
new_comparison=1'b1;
if (ack_data_com)
begin
	move_matrix=1'b1;
	if(id_matrix_veinte)
		state_next=s_cambiar;
	else
		state_next=s_cal_det;
end
end
s_cambiar:
begin
if (change)
	begin
	if (id_matrix_id_mayor)
		begin
		en_det=1'b1;
		save_pixel=1'b1;
		save_pos=1'b1;
		state_next=s_ack;
		end
	else
		begin
		move_matrix=1'b1;
		move_pos=1'b1;
		end
	end
else
	begin
	state_next=s_ack;
	end
end
s_ack:
begin
ack_pixel=1'b1;
if (~new_data)
	state_next=s_idle;
end
default:
begin
move_matrix=1'b0;
save_pixel=1'b0;
req_cal_det=1'b0;
move_pos=1'b0;
save_pos=1'b0;
rst_det=1'b0;
en_det=1'b0;
new_comparison=1'b0;
rst_mayor=1'b0;
state_next=state_reg;
end
endcase
end

endmodule
