
module xsvFunc (input clk48, input clk48x2, input rst, input[15:0] dout, output[15:0] din, 
	output[6:0] sl, output[6:0] sr, input urx0, 
	output ram_ce, output ram_oe, output ram_we, inout [15:0] d, output [18:0] a);
	
	reg [15:0] dwire;
	assign din = dwire;
	
	assign sl[0] = dout[0];
	assign sl[1] = dout[1];
	assign sl[2] = dout[2];
	assign sl[3] = dout[3];
	assign sl[4] = dout[4];
	assign sl[5] = dout[5];
	assign sl[6] = dout[6];
	assign sr[0] = dout[8];
	assign sr[1] = dout[9];
	assign sr[2] = dout[10];
	assign sr[3] = dout[11];
	assign sr[4] = dout[12];
	assign sr[5] = dout[13];
	assign sr[6] = dout[14];
	
	reg [15:0] temp1;
	reg [15:0] temp2;
	
	reg [7:0] low_temp1;
	reg [7:0] low_temp2;
	reg [7:0] high_temp1;
	reg [7:0] high_temp2;
	
	reg ram_doRead;
	reg ram_doWrite;
	reg [18:0] ram_readAddr;
	reg [18:0] ram_writeAddr;
	wire [15:0] ram_readData;
	reg [15:0] ram_writeData;
	wire ram_canRead;
	wire ram_canWrite; 
	
	reg [2:0] state;
	reg [2:0] next_state;
		
	reg [18:0] next_read_addr;
	reg [18:0] next_write_addr;
	reg [18:0] next_write_data;
	
	parameter [15:0] rst_addr = 16'h2222;
	parameter [15:0] do_noth = 16'h0000;
	parameter [15:0] read_inc = 16'hFFFF; 
	
	reg imageloaded; //ready to resize
	reg doneflag; //done resize
	parameter [18:0] num_pixels = 19200; //#pixels in old image
	
	parameter zero = 0, write0 = 1, write1 = 2, write2 = 3, read1 = 4, read2 = 5, read3 = 6;
		
	always @(posedge clk48x2) begin
    	if (rst) begin
			state <= zero;
			ram_readAddr <= 0;
			ram_writeAddr <= 0;
			ram_writeData <= 0;
			temp1 <= 0;
			temp2 <= 0;	  
			
			low_temp1 <= 0;
			low_temp2 <= 0;
			high_temp1 <= 0;
			high_temp2 <= 0;
			
			dwire <= 16'h0000;
			
			imageloaded <= 0; //resize
   		end else begin
			if(state == read2) begin
				dwire <= d;//ram_readData;
			end else begin
			 	dwire <= dwire;
			end
			state <= next_state;
			ram_readAddr <= next_read_addr;
			ram_writeAddr <= next_write_addr;
			ram_writeData <= next_write_data;
			temp1 <= dout;
			temp2 <= temp1;
			
			low_temp1 <= dout[7:0];
			low_temp2 <= low_temp1;
			high_temp1 <= dout[15:8];
			high_temp2 <= high_temp1;
			if (doneflag) begin
				imageloaded <= 0;
			end else if (ram_writeAddr == num_pixels && state == zero) begin//write2) begin	//resize
				imageloaded <= 1;
				ram_writeAddr <= 0;
			end
		end
	end
	
	always @(*) begin
		next_state = state;
		next_read_addr = ram_readAddr;
		next_write_addr = ram_writeAddr;
		next_write_data = ram_writeData;
		ram_doWrite = 0;
		ram_doRead = 0;
		case (state)
			zero: begin
				if(low_temp1 == low_temp2 && high_temp1 == high_temp2 && high_temp2 == low_temp2 && temp1 == temp2) begin
					if(temp2 == do_noth || imageloaded) begin	//resize
						next_state = zero;
					end else if (temp2 == read_inc) begin
						next_state = read1;
						next_read_addr  = ram_readAddr + 1;
					end else if (temp2 == rst_addr) begin
						next_read_addr = 0;
						next_write_addr = 0;
					end else begin
						next_state = write1;
						next_write_data = temp2;
						next_write_addr = ram_writeAddr + 1;
					end
				end
			end
			write1: begin
				if(ram_canWrite) begin
					ram_doWrite = 1;
					next_state = write2;
				end
			end
			write2: begin
				ram_doWrite = 0;
				if(temp1 == temp2) begin
					next_state = write2;
				end else begin 
					next_state = zero;
				end
			end
			read1: begin
				if(ram_canRead) begin
					ram_doRead = 1;
					next_state = read2;
				end
			end
			read2: begin
				next_state = read3;
			end
			read3: begin
				if(temp1 == temp2) begin
					next_state = read3;
				end else begin	  
					next_state = zero;
				end
			end			
		endcase
	end

	//ratio (old_num_pixels/new_num_pixels)*2^5
	parameter [15:0] s_oldnew_Rows = 16'b0000000010000000;
	parameter [15:0] s_oldnew_Cols = 16'b0000000010000000;
	//size of old image
	parameter [9:0] old_numRows = 160;
	parameter [9:0] old_numCols = 120;
	//size of new image
	parameter [9:0] new_numRows = 40;
	parameter [9:0] new_numCols = 30;
	
	// states
	reg [3:0] resize_state;
	reg [3:0] nextresize_state;
	parameter reset = 0, loop1 = 1, loop2 = 2, resize_read1 = 3, resize_read2 = 4, resize_write1 = 5, resize_write2 = 6, endloop2 = 7, endloop1 = 8, endloop1b = 9, donestate = 10;	 
	
	parameter shiftedby = 5;
	
	reg [15:0] s_cur_oldRow;
	reg [15:0] s_cur_oldCol;
	reg [15:0] s_prev_cur_oldRow;
	wire [15:0] cur_oldRow;
	wire [15:0] cur_oldCol;
	wire [15:0] prev_cur_oldRow;
	assign cur_oldRow = s_cur_oldRow >> shiftedby;
	assign cur_oldCol = s_cur_oldCol >> shiftedby;
	assign prev_cur_oldRow = s_prev_cur_oldRow >> shiftedby;
	
	wire [15:0] casewire = cur_oldRow - prev_cur_oldRow;
	
	reg [9:0] r;
	reg [9:0] c;
	
	reg [18:0] i;	 // new addr
	reg [18:0] addr; // old addr   
	reg [18:0] addr_offset;
	
	reg [15:0] resize_write_data;
	reg resize_doWrite;
	reg	resize_doRead;
	
	// should all be synthesized to wires
	reg nextdoneflag;
	reg [19:0] nexti;
	reg [9:0] nextr;
	reg [9:0] nextc;
	reg [18:0] nextaddr;	
	reg [18:0] nextaddr_offset;
	reg [15:0] nexts_cur_oldRow; 
	reg [15:0] nexts_prev_cur_oldRow;
	reg [15:0] nexts_cur_oldCol;
	
	always @(posedge clk48x2) begin 
		if (rst) begin
			resize_state <= reset;
			s_cur_oldRow <= 0;	
			s_prev_cur_oldRow <= 0;
			s_cur_oldCol <= 0;
			r <= 0;
			c <= 0;
			i <= 0;
			addr <= 0;		
			addr_offset <= 0;
			doneflag <= 0;
		end else begin
			if(resize_state == resize_read2) begin
				resize_write_data <= d;//ram_readData;
			end else begin
			 	resize_write_data <= resize_write_data;
			end
			resize_state <= nextresize_state;	 
			i <= nexti;
			r <= nextr;
			c <= nextc;
			addr <= nextaddr;	  
			addr_offset <= nextaddr_offset;
			s_cur_oldRow <= nexts_cur_oldRow; 
			s_prev_cur_oldRow <= nexts_prev_cur_oldRow;
			s_cur_oldCol <= nexts_cur_oldCol;
			doneflag <= nextdoneflag;
		end	
	end
	
	
	always @(*) begin
		// defaults
		nextresize_state = resize_state;
		nextdoneflag = 0;
		nexti = i;
		nextr = r;
		nextc = c;
		nextaddr = addr;  
		nextaddr_offset = addr_offset;
		nexts_cur_oldRow = s_cur_oldRow;
		nexts_prev_cur_oldRow = s_prev_cur_oldRow;
		nexts_cur_oldCol = s_cur_oldCol;
		resize_doWrite = 0;
		resize_doRead = 0;
		
		case(resize_state)
			reset: begin
				nexts_cur_oldRow = s_oldnew_Rows >> 1; 
				nextaddr_offset = 0;
				nexti = 0;
				nextr = 0;	 
				nextresize_state = (imageloaded) ? loop1 : reset;
			end
			loop1: begin	
				nexts_cur_oldCol = s_oldnew_Cols >> 1;
				nextc = 0;							   
				nextresize_state = loop2;
			end
			loop2: begin
				nextaddr = cur_oldCol + addr_offset;
				//nextaddr = addr + 1;//cur_oldCol + (old_numCols * cur_oldRow);
				nextresize_state = resize_read1;
			end
			resize_read1: begin
				if(ram_canRead) begin
					resize_doRead = 1;
					nextresize_state = resize_read2;
				end
			end
			resize_read2: begin
				nextresize_state = resize_write1;
			end
			resize_write1: begin
				if(ram_canWrite) begin
					resize_doWrite = 1;
					nextresize_state = resize_write2;
				end
			end
			resize_write2: begin
				resize_doWrite = 0;
				nextresize_state = endloop2;
			end
			endloop2: begin
				nexts_cur_oldCol = s_cur_oldCol + s_oldnew_Cols;
				nexti = i + 1;
				nextc = c + 1;						 
				nextresize_state = (nextc < new_numCols) ? loop2 : endloop1;
			end
			endloop1: begin			
				nexts_prev_cur_oldRow = s_cur_oldRow;
				nexts_cur_oldRow = s_cur_oldRow + s_oldnew_Rows;
				nextr = r + 1;	
				nextresize_state = endloop1b;
				//nextresize_state = (nextr < new_numRows) ? loop1 : donestate;
			end	
			endloop1b: begin		  
				case (casewire)
					1: nextaddr_offset = addr_offset + old_numCols;
					2: nextaddr_offset = addr_offset + (old_numCols << 1);
					3: nextaddr_offset = addr_offset + old_numCols + (old_numCols << 1);
					4: nextaddr_offset = addr_offset + (old_numCols << 2);
					default: nextaddr_offset = addr_offset + old_numCols;
				endcase
				nextresize_state = (nextr < new_numRows) ? loop1 : donestate;  
			end
			donestate: begin
				nextdoneflag = 1;
				if(imageloaded) begin
					nextresize_state = donestate; 
				end else begin
					nextresize_state = reset;
				end
			end
		endcase				  
	end
	
	wire [18:0] sram_readAddr;
	assign sram_readAddr = (imageloaded) ? addr : ram_readAddr;
	
	wire [18:0] sram_writeAddr;
	assign sram_writeAddr = (imageloaded) ? i : ram_writeAddr;
	
	wire [15:0] sram_writeData;
	assign sram_writeData = (imageloaded) ? resize_write_data : ram_writeData;
	
	wire sram_doRead;
	assign sram_doRead = (imageloaded) ? resize_doRead : ram_doRead;
	
	wire sram_doWrite;
	assign sram_doWrite = (imageloaded) ? resize_doWrite : ram_doWrite;
	
	sraminterface sram(.CLK(clk48x2),  	//clock signal
		.Resetn(~rst),				  	//Asynchronus reset
        .doRead(sram_doRead),			//Set this to make a read request.							
        .doWrite(sram_doWrite),			//Set this to make a write request.
        .readAddr(sram_readAddr),		//Address to read from (user-side).
        .writeAddr(sram_writeAddr),		//Address to write to (user-side).
        .readData(ram_readData),		//DON'T USE
        .writeData(sram_writeData),		//Data to write (user-side).
        .canRead(ram_canRead),			//Is '1' when a read request can be handled.							
        .canWrite(ram_canWrite),		//Is '1' when a write request can be handled.
        .CELeftn(ram_ce),				//CEn signal to left SRAM bank.
        .OELeftn(ram_oe),				//OEn signal to left SRAM bank.
        .WELeftn(ram_we),				//WEn signal to left SRAM bank.
        .SRAMLeftAddr(a),				//Address bus to left SRAM bank.
        .SRAMLeftData(d)				//Data bus to left SRAM bank.
    );
	
endmodule