module DMA
#(
	parameter ENDMEMBER=21,
	parameter WIDTH_MEMORY=16,
	parameter NUMBER_OF_PIXEL=350*350
)
(
	input		clk,rst,
	input		req,
	output	reg ack,
	
	input		[clog2(NUMBER_OF_PIXEL-1)-1:0] 					id_pixel,
	output	[clog2(NUMBER_OF_PIXEL*(ENDMEMBER-1)-1)-1:0]	address,
	output	[(ENDMEMBER-1)*WIDTH_MEMORY-1:0]					pixel,
	
	input		[WIDTH_MEMORY-1:0]									memory_data
);

function integer clog2;
input integer value;
begin 
value = value-1;
for (clog2=0; value>0; clog2=clog2+1)
value = value>>1;
end 
endfunction

reg [clog2(NUMBER_OF_PIXEL*ENDMEMBER-1)-1:0] id_memoria_reg,id_memoria_next;
reg sel_address,en_address;

reg [clog2(NUMBER_OF_PIXEL-1)-1:0] id_pixel_reg;
reg en_pixel;

reg ack_21;

reg [clog2(NUMBER_OF_PIXEL*ENDMEMBER-1)-1:0] id_pixel21,init_address;

reg move,save;
wire comp;
wire [4:0] counter;

reg [2:0]state_reg,state_next;

localparam	s_idle=3'd0,
				s_wait=3'd1,
				s_read=3'd2,
				s_save=3'd3,
				s_ack =3'd4;

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

registro_serie #(.WIDTH(WIDTH_MEMORY),.REGISTER_NUMBER(ENDMEMBER-1)) registro_serie_pixel
(
	.clk(clk),
	.rst(rst),
	.new_data(memory_data),
	.move(move),
	.save(save),
	.registro(pixel),
	.id(counter)
);

always@(*)
id_pixel21 = {id_pixel_reg,{4'b0000}}+{id_pixel_reg,{2'b00}};

//always@(posedge rst,posedge clk)
//begin
//if (rst)
//	init_address <= 3'b000;
//else 
//	init_address <= id_pixel21;
//end

always@(*)
begin
init_address = id_pixel21;
end

always@(posedge rst,posedge clk)
begin
if (rst)
	id_pixel_reg <= 3'b000;
else if (en_pixel)
	id_pixel_reg <= id_pixel;
end

always@(posedge rst,posedge clk)
begin
if (rst)
	ack_21 <= 1'b0;
else if (en_pixel)
	ack_21 <= en_pixel;
end

always@(posedge rst,posedge clk)
begin
if (rst)
	id_memoria_reg <= 3'b000;
else if (en_address)
	id_memoria_reg <= id_memoria_next;
end

always@(*)
begin
if (sel_address)
	id_memoria_next = init_address;
else
	id_memoria_next = id_memoria_reg+1'b1;
end

always@(*)
begin
state_next=state_reg;
en_pixel=1'b0;
en_address=1'b0;
sel_address=1'b0;
move=1'b0;
save=1'b0;
ack=1'b0;
casez(state_reg)
s_idle:
begin
if (req)
	begin
	en_pixel=1'b1;
	state_next=s_wait;
	end
end
s_wait:
begin
if (ack_21)
	begin
	en_address=1'b1;
	sel_address=1'b1;
	state_next=s_read;
	end
end
s_read:
begin
state_next=s_save;
end
s_save:
begin
save=1'b1;
move=1'b1;
en_address=1'b1;
if (comp)
	state_next=s_ack;
else
	state_next=s_read;
end
s_ack:
begin
ack=1'b1;
if (~req)
	state_next=s_idle;
end
endcase
end

assign comp=(counter==ENDMEMBER-2)?1'b1:1'b0;
assign address = id_memoria_reg;

endmodule 