`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    20:38:19 12/18/2014 
// Design Name: 
// Module Name:    I2C 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
module I2C(
	input clk,
	input reset,
	output reg scl,
	inout sda,
	output reg[7:0]hour,
	output reg[7:0]minute,
	output reg[7:0]sec,
	output reset_start,
	output reset_state_w
    );
assign reset_start = startbit;
assign reset_state_w = reset_state;
////////////////////////////////////////////
/////scl generator
////////////////////////////////////////////
reg [15:0]clk_cnt = 0;
reg [7:0]clk_byte_cnt = 0;
reg [15:0]clk_reset = 0;
reg [7:0]clk_state = 0;
reg [7:0]clk_length = 0;
reg [7:0]byte8_trans_length = 0;
reg read_state_status = 0;
reg ack_r = 0;
reg restart =0;
reg dir =0; // tri state buffer con 1: output 0: input 
parameter [7:0]ontime_duty = 8'd200; //4 us
parameter [7:0]offtime_duty = 8'd235; //4.7 us
parameter [7:0]halftime_duty = 8'd117; //2.35 us 
parameter [15:0]delay = 16'd50000;

parameter [7:0]Sec_Reg = 8'h00;
parameter [7:0]Minute_Reg = 8'h01;
parameter [7:0]Hour_Reg = 8'h02;
parameter [7:0]Con_Reg = 8'h07;

parameter [7:0]RTC1307_Add = 8'hd0;
parameter [7:0]RTC1307_Add_Read = 8'hd1;


parameter [7:0]ControlReg = 8'h07;
//wire scl_w;
reg startbit_r = 0;
always@(posedge clk)
startbit_r <= startbit;
//////////////////////////////////////////////////////////////////////////////
//clk_state¿¡¼­ 9¹øÂ° ÆÐÅ¶ Áï,ack ½ÅÈ£°¡ µé¾î¿Ô´ÂÁö¸¦ ÆÇ´ÜÇÏ¿©, ¾Æ·¡ state_write_sda¿¡¼­ 
//Ã¼Å©ÇÏ¿© ´ÙÀ½¹ø µ¥ÀÌÅÍ ÆÐÅ¶À» Àü¼Û ÇÔ.
//////////////////////////////////////////////////////////////////////////////
reg start_flag_r = 0;
always@(posedge clk)
begin
	case(clk_state)
	0:
	begin
		
		if(clk_reset == 16'd50000)
		begin
			clk_state <= 8'd1;
			scl <= 1'b1;
			dir <= 1'b1;
			ack_r <= 1'b0;
			reset_state <= 1'b0;
			read_state_status <= 1'b0;
			restart <= 1'b0;
			clk_length <= 8'd0;
			clk_cnt <= 16'd0;
			clk_byte_cnt <= 8'd0;
			byte8_trans_length <= 8'd0;
		end 
		else clk_reset <= clk_reset + 1'b1;
	end
	1:
	begin
		if(start_flag_r)
		begin
		clk_state <= 8'd2;
		//start_flag_r <= 1'b1;
		//scl = 1'b0;
		end 	
	end 
	2:
	begin
	if(clk_cnt == offtime_duty) ///negedge scl
		begin
			clk_state <= 8'd3;
			clk_cnt <= 16'd0;
			scl <= 1'b0; //scl high!
		end 
		else clk_cnt <= clk_cnt + 1'b1;
	end 
	3:
	begin
		reset_state <= 1'b0; // reset state init!
		clk_length <= clk_length + 1'b1; ///Å¬·° ¹ß»ý È½¼ö Ä«¿îÆ® 
		clk_state <= 8'd4;
	end 
	4:
	begin
		if(clk_cnt == offtime_duty) ///negedge scl
		begin
			clk_state <= 8'd5;
			clk_cnt <= 16'd0;
			scl <= 1'b1; //scl high!
		end 
		else clk_cnt <= clk_cnt + 1'b1;
	end
////////////////////////////////////
///acknowloedge cechk sequence
////////////////////////////////////
	5:
	begin
		if(clk_length == 8'd9) // 8¹øÂ° Å¬·° ¹ß»ý ½Ã  adc ÀÔ·Â Á¶°Ç Ã¼Å© 
		begin
			clk_state <= 8'd6;
			dir <= 1'b0;
		end 
		else clk_state <= 8'd8; 
	end 
	6:
	begin
		if((read_state_status)&&(clk_byte_cnt == 8'd3))  //READ STATE ÈÄ Á¾·á½Ã¿¡´Â NOT Acknowledge 
		begin
			clk_state <= 8'd8;
		end
		else  clk_state <= 8'd7;
	end 
	7:
	begin
		if(sda == 1'b0) //ack ½ÅÈ£°¡ µé¾î ¿Ã¶§±îÁö ´ë±â 
		begin
		 clk_state <= 8'd8; 
		 ack_r <=1'b1;
		 dir <= 1'b1;
		end 
	end  
////////////////////////////////// 
	8:
	begin
		if(clk_cnt == ontime_duty)///
		begin
			scl <= 1'b0;	// scl low!
			clk_cnt <= 16'd0;
			clk_state <= 8'd9;
		end 
		else clk_cnt <= clk_cnt + 1'b1;
	end
////////////////////////////////////
///i2c µ¥ÀÌÅÍÆÐÅ¶À» °¡Á®¿À±â À§ÇÏ¿© restart ÆÐÅ¶À» °¡Á®¿Â´Ù. ÀÌ¶§ µ¥ÀÌÅÍ ¼ö½Å½Ã 
// sclÅ¬·° ¹ß»ýÀº 8¹ø¸¸ ¹ß»ý ÇÏ¸é µÈ´Ù. ÀÌ´Â ¸¶½ºÅÍ¿¡°Ô ¸¶Áö¸· ack´Â ¼ö½Å µÇÁö ¾Ê±â ¶§¹®ÀÌ´Ù.
//restart flag »óÅÂ¿©ºÎ¸¦ È®ÀÎ ÇÏ¿© length¸¦ º¯°æ 
////////////////////////////////////
	9:
	begin
		if(restart)
		begin
			clk_state <= 8'd11;	
		end 
		else clk_state <= 8'd10;
	
	end
	10:
	begin
		if(clk_length == 4'd9) //sent time
		begin
			clk_state <= 8'd12;
			clk_length <= 8'd0;
		end
		else clk_state <= 8'd3;
	end
	11:
	begin
		if(clk_length == 4'd8) //receive time
		begin
			clk_state <= 8'd12;
			clk_length <= 8'd0;
		end
		else clk_state <= 8'd3;
	end
//////////////////////////////////////////	
///select mode!
//////////////////////////////////////////
	12:
	begin
		if(read_state_status)
		begin
			clk_state <= 8'd13;
		end
		else clk_state <= 8'd16;
	end 
//////////////////////////////////////////	
///read mode!
//////////////////////////////////////////
	13: 
	begin
		clk_byte_cnt <= clk_byte_cnt + 1'b1;
		if(clk_byte_cnt == 8'd3) //pulse length 4ea ? i2c receive go!
		begin
			clk_state <= 8'd17;
			dir <= 1'b1; 
			clk_byte_cnt <= 8'd0;
			ack_r <=1'b0;
		end
		else clk_state <= 8'd14;
	end 
	14:
	begin
	  if(ack_r == 1'b1)
		begin
			clk_state <= 8'd15;
			reset_state <= 1'b1; ///reset squence
		end 
	end 
	15:
	begin
		if(clk_byte_cnt == 8'd2) //i2c restart
		begin
			clk_state <= 8'd23;
		//	scl <= 1'b1; //restart init!
		end 
		else if(clk_byte_cnt == 8'd3) //i2c slave address
		begin
			restart <= 1'b1;  //restart flag »óÅÂ¿©ºÎ¸¦ È®ÀÎ ÇÏ¿© length¸¦ º¯°æ 
			clk_state <= 8'd3;
			dir <= 1'b0;
		end 
		else clk_state <= 8'd3;
		ack_r <= 0;
	end 
//////////////////////////////////////////	
	23:
	begin
		if(clk_cnt == ontime_duty) ///negedge scl
		begin
		//	clk_state <= 8'd24;
			clk_state <= 8'd1;
			clk_cnt <= 16'd0;
			scl <= 1'b1;
		end 
		else clk_cnt <= clk_cnt + 1'b1;
	end
//	24:
//	begin
//		if(i2c_restart == 1'b1) //i2c start Á¶°Ç¤¤ÀÌ ¿Ï·á µÇ¾ú´ÂÁö È®ÀÎ ÈÄ!
//		begin
//		clk_state <= 8'd1;
//		end 
//	end 
///write mode!
//////////////////////////////////////////
	16: 
	begin
		clk_byte_cnt <= clk_byte_cnt + 1'b1;
		if(clk_byte_cnt == 8'd2)
		begin
			clk_state <= 8'd17;
			clk_byte_cnt <= 8'd0;
		end
		else if(ack_r == 1'b1)
		begin
			clk_state <= 8'd3;
			ack_r <= 0;
			reset_state <= 1'b1; ///reset squence
		end 
	end
//////////////////////////////////////////			
	17:
	begin
		if(clk_cnt == ontime_duty) ///negedge scl
		begin
			clk_state <= 8'd18;
			clk_cnt <= 16'd0;
			scl <= 1'b1;
			stop_state <= 1'b1; //stop bit 1 -> 0
		end 
		else clk_cnt <= clk_cnt + 1'b1;
	end

	18:
	begin
		stop_state <= 1'b0; //stop bit 1 -> 0
		clk_state <= 8'd19;
	end 
	19:
	begin
		if(clk_cnt == delay)
		begin
			clk_cnt <=16'd0;
			restart <= 1'b0;
			clk_state <= 8'd20;
		end 
		else clk_cnt <= clk_cnt + 1'b1;
	end 
	20:
	begin
		byte8_trans_length <= byte8_trans_length + 1'b1;
		clk_state <= 8'd21;
	end 
	21:
	begin
		if(byte8_trans_length == 8'd4)
		begin
			  clk_state <= 8'd1; //Read state Satart!
			  read_state_status <= 1'b1;
		end
		else clk_state <= 8'd1; //Read state Satart!
	
	end 
	endcase
end
reg reset_state = 1'b0;
reg stop_state = 1'b0;
reg [7:0]read_sda8_cnt = 8'd0;
wire tick_9_length_comp_state = (clk_state == 8'd12)? 1'b1: 1'b0;  //9°³ Å¬·° »ý¼º ¿Ï·á Tick flag
wire tick_end_clk_state = (clk_state == 8'd21)? 1'b1: 1'b0;  //Å¬·° Á¾·á Tick flag
//wire reset_state = (clk_length == 4'd0)? 1'b1: 1'b0; //´ÙÀ½ ÆÐÅ¶ ½ÃÀÛÁ¡ tick!
////////////////////////////////////////////
/////sda generator
////////////////////////////////////////////
wire scl_w = (scl==1'b1)? 1'b1: 1'b0;
reg scl_w_r=0;
reg sda_r =1;
reg [7:0]address_r = 0;
always@(posedge clk)
begin
scl_w_r <= scl_w;
end 

////////////////////////////////////////////
////Write State or Read State
////////////////////////////////////////////
reg [7:0]state_write_sda = 0;
reg [15:0]cnt_reset2 = 0;
reg [7:0]cnt_send = 0;
reg [15:0]cnt_delay = 0;
reg [7:0]packet_cnt = 0;
reg [7:0]receive_data = 0;
reg [3:0]receive_data_cnt = 0;
always@(posedge clk)
begin
	case(state_write_sda)
	0:
		begin
			if(cnt_reset2 == 16'd50000)
			begin
				state_write_sda <= 8'd1;
				packet_cnt <= 8'd0;
				address_r <= RTC1307_Add;
				sda_r <= 1'b1;
				start_flag_r <= 1'b0;
				receive_data <= 8'd0;
				cnt_delay <= 16'd0;
				cnt_send <=8'd0;
				receive_data_cnt <= 8'd0;
				read_sda8_cnt <= 8'd0;
				sec <= 8'd0;
				minute <= 8'd0;
				hour <= 8'd0;
				//test_sec <= 8'd0;
				//dir =1'b0;
			end 
			else cnt_reset2 <= cnt_reset2 + 1'b1;
		end
	1: //statrt bit check!
	begin
		if(startbit)
		begin
			state_write_sda <= 8'd2;
		end 
	end
	2:
	begin
		if(cnt_delay==offtime_duty) //scl medium time
		begin
			cnt_delay <= 16'd0;
			state_write_sda <= 8'd3;
			sda_r <= 1'b1;
		end 
		else cnt_delay <= cnt_delay + 1'b1;
	end 
	3:
	begin
		if(cnt_delay==offtime_duty) //scl medium time
		begin
			cnt_delay <= 16'd0;
			state_write_sda <= 8'd4;
			sda_r <= 1'b0;
			start_flag_r <= 1'b1;
		end 
		else cnt_delay <= cnt_delay + 1'b1;
	end 
	4:
	begin
		cnt_send <= cnt_send+ 1'b1;
		state_write_sda <= 8'd5;
	end 
	5:
	begin
		state_write_sda <= 8'd6;
	end 
	6:
	begin
		if(!scl_w_r)  //scl high?
		begin
			state_write_sda <= 8'd7;
		end
	end 
	7:
	begin
		if(address_r&8'h80)
		begin
			sda_r <= 1'b1;
		end 
		else sda_r <= 1'b0;
			state_write_sda <= 8'd8;
	end 
	8:
	begin
	if(scl_w_r)	//scl low?
		begin
			//sda_r <= 1'b0;
			state_write_sda <= 8'd9;
		end
	end
	9:
	begin
	if(!scl_w_r)
		begin
		state_write_sda <= 8'd10;
		end 
	end 
	10:
	begin
		address_r <= address_r<<1;
		if(cnt_send == 8'd8)
		begin
			state_write_sda <= 8'd11;
			cnt_send <= 8'd0;
		end
		else 	
		begin
		state_write_sda <= 8'd4; //restart sda output!
		end
	end
////////////////////////////////////////////////////////
///
	11: // sclk Å¬·° state¿¡¼­ ack°¡ µé¾î ¿Ô´Â Áö¸¦ Ã¼Å©ÇÑ´Ù. 
	begin
		if(cnt_delay == halftime_duty)
		begin
			cnt_delay <= 16'd0;
			state_write_sda <= 8'd12;
			sda_r <= 1'b0;
		end 
		else cnt_delay <= cnt_delay + 1'b1;
	end 
	12:
	begin
		if(ack_r) 
		begin
			state_write_sda <= 8'd13;
			//dir <= 1'b1;
		end
	end 
	13:
	begin
		packet_cnt <= packet_cnt + 1'b1;
		state_write_sda <= 8'd14;
	end 
	14:
	begin
		if(stop_state) //scl Å¬·°½ºÅ×ÀÌÆ®¿¡¼­ stop bit¸¦ Àü¼ÛÇÒ »óÅÂ¸¦ ¾Ë·ÁÁÜ, ÀÌ¸¦ ÅëÇØ sda ½ºÅ×ÀÌÆ®¿¡¼­ sdaÇÉ 0->1·Î ½ÅÈ£¸¦ Ãâ·Â 
		begin
			state_write_sda <= 8'd20;
		end 
		else if(reset_state) //sda pulse init!
		begin
			state_write_sda <= 8'd15;
		end
	end 
	15:
	begin
		if(read_state_status)
		begin
			state_write_sda <= 8'd17;
		end
		else state_write_sda <= 8'd16;
	end 
//////////////////////////////////////////	
////i2c write mode
//////////////////////////////////////////
	16: 
	begin
		case(packet_cnt)
		8'd1:
		begin
			address_r <= Sec_Reg;
		end
		8'd2:
		begin
			address_r <= 8'h00;  //1st end 
		end
		8'd3:
		begin
			address_r <= RTC1307_Add;
		end
		8'd4:
		begin
			address_r <= Minute_Reg;
		end
		8'd5:
		begin
			address_r <= 8'h25; //2nd end
		end
		8'd6:
		begin
			address_r <= RTC1307_Add;
		end
		8'd7:
		begin
			address_r <= Hour_Reg;
		end 
		8'd8:
		begin
			address_r <= 8'h02; //3rd end
		end 
		8'd9:
		begin
			address_r <= RTC1307_Add;
		end 
		8'd10:
		begin
			address_r <= Con_Reg;
		end 
		8'd11:
		begin
			address_r <= 8'h03; //4th end 
		end 
		endcase
		state_write_sda <= 8'd4;
	end
//////////////////////////////////////////	
///i2c read mode!
//////////////////////////////////////////
	17: 
	begin
	if(packet_cnt == 8'd1)
		begin		
			state_write_sda <= 8'd18;
			start_flag_r <= 1'b0;
		end
		else if(packet_cnt == 8'd2) //i2c restart 
		begin
			state_write_sda <= 8'd19;
		end 
		else if(packet_cnt == 8'd3)
		begin
			state_write_sda <= 8'd24;
			start_flag_r <= 1'b0;
		end 
	end 
	18:
	begin
		case(read_sda8_cnt)
		0:address_r <= 8'h00;
		1:address_r <= 8'h01;
		2:address_r <= 8'h02; 
		endcase
		state_write_sda <= 8'd4;
	end 
//////////////////////////////////////////
//i2c restart code
19:
begin
	if(i2c_restart)
	begin
			state_write_sda <= 8'd1;
			address_r <= 8'hd1;
			sda_r <= 1'b1; //sda init to low!
			start_flag_r <= 1'b0;
	end 
end
//////////////////////////////////////////	
	20://stop bit check!
	begin
		if(stopbit)
		begin
		state_write_sda <= 8'd21;
		end 
	end 
	21:
	begin
	if(cnt_delay == offtime_duty)
		begin
			cnt_delay <= 16'd0;
			state_write_sda <= 8'd22;
			sda_r <= 1'b1;
		end 
		else cnt_delay <= cnt_delay + 1'b1;
	end 
	22:
	begin
		if(tick_end_clk_state) //clk_state machine ¿Ï·á flag 
		begin
		state_write_sda <= 8'd23;
		sda_r <= 1'b1;
		address_r <= RTC1307_Add;
		start_flag_r <= 1'b0;
		end 
	end 
	23:
	begin
		if(packet_cnt>11)
		begin
		packet_cnt <= 8'd0;
		end 
		state_write_sda <= 8'd1;
	end 
//////////////////////////////////////////	
///receive i2c data packet for start
//////////////////////////////////////////	
	
	24:
	begin
		if(!scl_w_r)  //scl high?
		begin
			state_write_sda <= 8'd25;
		end
	
	end 
	25:
	begin
		if(scl_w_r)  //scl high?
		begin
			state_write_sda <= 8'd26;
		end
	end 
	26:
	begin
			if(sda == 1'b1)
			begin
				receive_data <= {receive_data,1'b1};
			end 
			else receive_data <= {receive_data,1'b0};
				state_write_sda <= 8'd27;
	end 
	27:
	begin
			if(!scl_w_r)  //scl high?
		begin
			state_write_sda <= 8'd28;
		end
	
	end 
	28:
	begin
			receive_data_cnt <= receive_data_cnt + 1'b1;
			state_write_sda <= 8'd29;
	end 
	29:
	begin
			if(receive_data_cnt == 4'd8)
			begin
				receive_data_cnt <= 4'd0;
				state_write_sda <= 8'd30;
			//	dir <= 1'b1;
			end 
			else state_write_sda <= 8'd24;
	end 
	30:
	begin
		case(read_sda8_cnt)
		0:sec <= receive_data;
		1:minute <= receive_data;
		2:hour <= receive_data;
		endcase 
		state_write_sda <= 8'd31;
	end 
	31:
	begin
		state_write_sda <= 8'd32;
		if(read_sda8_cnt == 8'd2)
		begin
		read_sda8_cnt <= 8'd0;
		end 
		else read_sda8_cnt <= read_sda8_cnt + 1'b1;
	end 
	32:
	begin
		if(stop_state)
		begin
			state_write_sda <= 8'd33;
		end 
	end 
	33://stop bit check!
	begin
		if(stopbit)
		begin
			state_write_sda <= 8'd34;

		end 
	end 
	34:
	begin
		if(cnt_delay == offtime_duty)
		begin
			cnt_delay <= 16'd0;
			state_write_sda <= 8'd35;
			start_flag_r <= 1'b0;
			sda_r <= 1'b1;
		end 
		else cnt_delay <= cnt_delay + 1'b1;
	end 
	35:
	begin
		if(tick_end_clk_state) 
		begin
			state_write_sda <= 8'd1;
			sda_r <= 1'b1;
			address_r <= RTC1307_Add;
			packet_cnt <= 8'd0;
		end 
	end
	
	endcase
end 
wire i2c_restart = (clk_state == 8'd1)? 1'b1: 1'b0;
wire stopbit = (scl & ~sda)? 1'b1: 1'b0;
wire startbit = ((scl & sda_r) && clk_state == 8'd1 && state_write_sda ==8'd1)? 1'b1: 1'b0;
assign sda = (dir == 1'b1)? sda_r: 1'bZ;

endmodule