module TempI2cMaster (
	i_clk,
	i_rst_n,
	i_addr,
	i_ptr,
	i_req,
	o_data,
	o_data_valid,
	SCK,
	SDA
);
parameter	CLK_DIV = 100;

parameter	CLK_DIV_HALF = CLK_DIV/2;
parameter	CLK_DIV_QUA  = CLK_DIV/4;
	
parameter	IDLE 		= 4'd0;	
parameter	START 		= 4'd1;
parameter	WR_ADDR		= 4'd2;
parameter	WR_ADDR_A 	= 4'd3;
parameter	RD_MSB		= 4'd4;
parameter	RD_MSB_A	= 4'd5;
parameter	RD_LSB		= 4'd6;
parameter	RD_LSB_A	= 4'd7;
parameter	STOP		= 4'd8;
parameter	DATA_VAL	= 4'd9;
input	wire		i_clk;
input	wire		i_rst_n;
input	wire[2:0]	i_addr;
input	wire[1:0]	i_ptr;
input	wire		i_req;
output	reg	[15:0]	o_data;
output	reg			o_data_valid;
output	wire		SCK;
inout	wire		SDA;

reg	[3:0]	present_state;
reg	[3:0]	next_state;

reg		sm_en_clk;
reg		sm_start;
reg		sm_transfer;
reg		sm_rd_tr;
reg		sm_stop;
reg		sm_data_valid;
reg		sm_no_ans;
//in data buf
reg	[2:0]	i_addr_reg;
reg			i_req_reg;


reg	[7:0]	data_clk_cnt;
reg	[7:0]	sck_clk_cnt;
reg	[7:0]	quad_clk_cnt;

reg			data_clk_reg;
reg			sck_clk_reg;
reg			quad_clk_reg;

reg			pos_data_clk;
reg			pos_data_clk_pipe;
reg			neg_data_clk;

reg			pos_sck_clk;
reg			neg_sck_clk;

reg			pos_quad_clk;
reg			neg_quad_clk;

reg			data_clk_cnt_flag;
reg			sck_clk_cnt_flag;
reg			quad_clk_cnt_flag;

reg			en_data_clk_cnt;
reg			en_sck_clk_cnt;

reg			sck_reg;
reg			sm_stop_pos_data;
reg	[7:0]	tx_data_sr;
reg	[2:0]	tr_bit_cnt;
reg		en_rd_tr;
reg		tr_bit_cnt_flag;
reg		stop_flag;
reg		rd_data_en;
reg		sm_en_clk_reg;
reg		sck_clk_reg_out;
assign	SCK = sck_clk_reg_out;
assign	SDA = ~en_rd_tr ? sck_reg : 1'bz;

always @(posedge i_clk or negedge i_rst_n) begin
	if(!i_rst_n) begin
		o_data_valid <= 1'b0;
		sm_en_clk_reg <= 1'b0;
		sck_clk_reg_out <= 1'b1;
		en_sck_clk_cnt <= 1'b0;
	end
	else begin
		o_data_valid  <= sm_data_valid;
		sm_en_clk_reg <= sm_en_clk;
		en_sck_clk_cnt <= sm_en_clk_reg;
		sck_clk_reg_out <= sck_clk_reg;
	end
end

always @(posedge i_clk or negedge i_rst_n) begin
	if(!i_rst_n) begin
		data_clk_reg 	<= 1'b0;
		sck_clk_reg  	<= 1'b1;
		quad_clk_reg 	<= 1'b0;	
		en_data_clk_cnt <= 1'b0;
		pos_quad_clk	<= 1'b0;
		neg_quad_clk	<= 1'b0;
	end
	else if(!sm_en_clk_reg) begin
		data_clk_reg 	<= 1'b0;
		sck_clk_reg  	<= 1'b1;
		quad_clk_reg 	<= 1'b0;	
		en_data_clk_cnt <= 1'b0;		
	end
	else begin
		pos_quad_clk <= ~quad_clk_reg & quad_clk_cnt_flag;
		neg_quad_clk <=  quad_clk_reg & quad_clk_cnt_flag;
		if(pos_quad_clk) begin
			en_data_clk_cnt <= 1'b1;
		end
		if(data_clk_cnt_flag) begin
			data_clk_reg <= ~data_clk_reg;
		end
		if(sck_clk_cnt_flag) begin
			sck_clk_reg <= ~sck_clk_reg;
		end
		if(quad_clk_cnt_flag) begin
			quad_clk_reg <= ~quad_clk_reg;
		end
	end
end

always @(posedge i_clk or negedge i_rst_n) begin
	if(!i_rst_n) begin
		quad_clk_cnt <= 0;
	end
	else if (!sm_en_clk_reg || quad_clk_cnt_flag) begin
		quad_clk_cnt <= 0;
	end
	else begin
		quad_clk_cnt <= quad_clk_cnt + 1;
	end
end

always @(posedge i_clk or negedge i_rst_n) begin
	if(!i_rst_n) begin
		sck_clk_cnt <= 0;
	end
	else if(!en_sck_clk_cnt || sck_clk_cnt_flag) begin
		sck_clk_cnt <= 0;
	end
	else begin
		sck_clk_cnt <= sck_clk_cnt + 1;
	end
end

always @(posedge i_clk or negedge i_rst_n) begin
	if(!i_rst_n) begin
		data_clk_cnt <= 0;
	end
	else if(!sm_en_clk_reg || data_clk_cnt_flag) begin
		data_clk_cnt <= 0;
	end
	else if(en_data_clk_cnt) begin
		data_clk_cnt <= data_clk_cnt + 1;
	end
end

always @(posedge i_clk or negedge i_rst_n) begin
	if(!i_rst_n) begin
		sm_stop_pos_data <= 1'b0;
	end
	else if(!sm_en_clk_reg) begin
		sm_stop_pos_data <= 1'b0;
	end
	else if(sm_stop && pos_data_clk) begin
		sm_stop_pos_data <= 1'b1;
	end
end

always @(posedge i_clk or negedge i_rst_n) begin
	if(!i_rst_n) begin
		stop_flag <= 1'b0;
	end
	else if(!sm_en_clk_reg) begin
		stop_flag <= 1'b0;
	end
	else if(pos_sck_clk & sm_stop_pos_data) begin
		stop_flag <= 1'b1;
	end
end

always @(posedge i_clk or negedge i_rst_n) begin
	if(!i_rst_n) begin
		sck_reg <= 1'b1;
	end
	else if(!sm_en_clk_reg || pos_data_clk_pipe && sm_no_ans) begin
		sck_reg <= 1'b1;
	end
	else if((pos_quad_clk && sm_start) || (sm_stop && pos_data_clk_pipe)) begin
		sck_reg <= 1'b0;
	end
	else if(pos_data_clk_pipe) begin
		sck_reg <= tx_data_sr[7];
	end
end

always @(posedge i_clk or negedge i_rst_n) begin
	if(!i_rst_n) begin
		rd_data_en <= 1'b0;
	end
	else if(pos_data_clk_pipe) begin
		rd_data_en <= sm_transfer & sm_rd_tr;
	end
end

always @(posedge i_clk or negedge i_rst_n) begin
	if(!i_rst_n) begin
		o_data <= 16'b0;
	end
	else if(rd_data_en & pos_sck_clk) begin
		o_data <= {o_data[14:0], SDA};
	end
end

always @(posedge i_clk or negedge i_rst_n) begin
	if(!i_rst_n) begin
		tr_bit_cnt_flag <= 1'b0;
	end
	else begin
		tr_bit_cnt_flag <= &tr_bit_cnt;
	end
end

always @(posedge i_clk or negedge i_rst_n) begin
	if(!i_rst_n) begin
		en_rd_tr <= 1'b0;
	end
	else if(sm_rd_tr && pos_data_clk_pipe) begin
		en_rd_tr <= 1'b1;
	end
	else if(pos_data_clk_pipe) begin
		en_rd_tr <= 1'b0;
	end
end

always @(posedge i_clk or negedge i_rst_n) begin
	if(!i_rst_n) begin
		tr_bit_cnt <= 3'b0;
	end
	else if(!sm_transfer) begin
		tr_bit_cnt <= 3'b0;
	end
	else if(pos_data_clk) begin
		tr_bit_cnt <= tr_bit_cnt + 3'b1;
	end
end

always @(posedge i_clk or negedge i_rst_n) begin
	if(!i_rst_n) begin
		tx_data_sr <= 8'b0;
	end
	else if(sm_start) begin
		tx_data_sr[7:0] <= {4'b1001, i_addr_reg[2:0], 1'b1};
	end
	else if(pos_data_clk_pipe) begin
		tx_data_sr <= tx_data_sr << 1;
	end
end

always @(posedge i_clk or negedge i_rst_n) begin
	if(!i_rst_n) begin
		data_clk_cnt_flag 		<= 1'b0;
		quad_clk_cnt_flag 		<= 1'b0;
		pos_data_clk			<= 1'b0;
		neg_data_clk			<= 1'b0;
		pos_data_clk_pipe       <= 1'b0;
	end
	else begin
		data_clk_cnt_flag 		<= (data_clk_cnt == CLK_DIV_HALF-2);
		quad_clk_cnt_flag 		<= (quad_clk_cnt == CLK_DIV_QUA-2);
		pos_data_clk 			<= data_clk_cnt_flag & ~data_clk_reg;
		neg_data_clk 			<= data_clk_cnt_flag &  data_clk_reg;
		pos_data_clk_pipe       <= pos_data_clk;
	end
end

always @(posedge i_clk or negedge i_rst_n) begin
	if(!i_rst_n) begin
		sck_clk_cnt_flag 	<= 1'b0;
		pos_sck_clk			<= 1'b0;
	end
	else begin
		sck_clk_cnt_flag 	<= (sck_clk_cnt == CLK_DIV_HALF-2);
		pos_sck_clk 		<=  sck_clk_cnt_flag & ~sck_clk_reg;
	end
end
//
always @(posedge i_clk or negedge i_rst_n) begin
	if(!i_rst_n) begin
		i_addr_reg <= 3'b0;
	end
	else if(i_req) begin
		i_addr_reg <= i_addr;
	end
end

always @(posedge i_clk or negedge i_rst_n) begin
	if(!i_rst_n) begin
		i_req_reg <= 1'b0;
	end
	else begin
		i_req_reg <= i_req;
	end
end

always @(posedge i_clk or negedge i_rst_n) begin
	if(!i_rst_n) begin
		present_state <= IDLE;
	end
	else begin
		present_state <= next_state;
	end
end

always @(present_state or i_req_reg or pos_data_clk or neg_data_clk or tr_bit_cnt_flag or stop_flag) begin
	sm_en_clk 		= 1'b0;
	sm_start		= 1'b0;
	sm_transfer		= 1'b0;
	sm_rd_tr		= 1'b0;
	sm_stop     	= 1'b0;
	sm_data_valid 	= 1'b0;
	sm_no_ans		= 1'b0;
	next_state 	= IDLE;
	case(present_state)
		IDLE : begin
			sm_en_clk 		= 1'b0;
			sm_start		= 1'b0;
			sm_transfer 	= 1'b0;
			sm_rd_tr		= 1'b0;
			sm_stop     	= 1'b0;
			sm_data_valid 	= 1'b0;
			sm_no_ans		= 1'b0;
			if(i_req_reg) begin
				next_state = START;
			end
			else begin
				next_state 	= present_state;
			end
		end
		START : begin
			sm_en_clk 		= 1'b1;
			sm_start  		= 1'b1;
			sm_transfer 	= 1'b0;
			sm_rd_tr		= 1'b0;
			sm_stop     	= 1'b0;
			sm_data_valid 	= 1'b0;
			sm_no_ans		= 1'b0;
			if(pos_data_clk) begin
				next_state = WR_ADDR;
			end
			else begin
				next_state = START;
			end
		end
		WR_ADDR : begin
			sm_en_clk 		= 1'b1;
			sm_start  		= 1'b0;
			sm_transfer 	= 1'b1;
			sm_rd_tr		= 1'b0;
			sm_stop     	= 1'b0;
			sm_data_valid 	= 1'b0;
			sm_no_ans		= 1'b0;
			if(tr_bit_cnt_flag && pos_data_clk) begin
				next_state = WR_ADDR_A;
			end
			else begin 
				next_state = WR_ADDR;
			end
		end
		WR_ADDR_A : begin
			sm_en_clk 		= 1'b1;
			sm_start  		= 1'b0;
			sm_transfer 	= 1'b0;
			sm_rd_tr		= 1'b1;
			sm_stop     	= 1'b0;
			sm_data_valid 	= 1'b0;
			sm_no_ans		= 1'b0;
			if(pos_data_clk) begin
				next_state = RD_MSB;
			end
			else begin
				next_state = WR_ADDR_A;
			end
		end
		RD_MSB : begin
			sm_en_clk 		= 1'b1;
			sm_start  		= 1'b0;
			sm_transfer 	= 1'b1;
			sm_rd_tr		= 1'b1;
			sm_stop     	= 1'b0;
			sm_data_valid 	= 1'b0;
			sm_no_ans		= 1'b0;
			if(pos_data_clk && tr_bit_cnt_flag) begin
				next_state = RD_MSB_A;
			end
			else begin
				next_state  = RD_MSB;
			end	
		end
		RD_MSB_A : begin
			sm_en_clk 		= 1'b1;
			sm_start  		= 1'b0;
			sm_transfer 	= 1'b0;
			sm_rd_tr		= 1'b0;//1;
			sm_stop     	= 1'b0;
			sm_data_valid 	= 1'b0;
			sm_no_ans		= 1'b0;
			if(pos_data_clk) begin
				next_state = RD_LSB;
			end
			else begin
				next_state  = RD_MSB_A;
			end	
		end
		RD_LSB : begin
			sm_en_clk 		= 1'b1;
			sm_start  		= 1'b0;
			sm_transfer 	= 1'b1;
			sm_rd_tr		= 1'b1;
			sm_stop     	= 1'b0;
			sm_data_valid 	= 1'b0;
			sm_no_ans		= 1'b0;
			if(pos_data_clk && tr_bit_cnt_flag) begin
				next_state = RD_LSB_A;
			end
			else begin
				next_state  = RD_LSB;
			end	
		end
		RD_LSB_A : begin
			sm_en_clk 		= 1'b1;
			sm_start  		= 1'b0;
			sm_transfer 	= 1'b0;
			sm_rd_tr		= 1'b0;
			sm_stop     	= 1'b0;
			sm_data_valid 	= 1'b0;
			sm_no_ans		= 1'b1;
			if(pos_data_clk) begin
				next_state = STOP;
			end
			else begin
				next_state  = RD_LSB_A;
			end			
		end
		STOP : begin
			sm_en_clk 		= 1'b1;
			sm_start  		= 1'b0;
			sm_transfer 	= 1'b0;
			sm_rd_tr		= 1'b0;
			sm_stop     	= 1'b1;
			sm_data_valid 	= 1'b0;
			sm_no_ans		= 1'b0;
			if(neg_data_clk) begin
				next_state = DATA_VAL;
			end
			else begin
				next_state  = STOP;
			end		
		end
		DATA_VAL : begin
			sm_en_clk 		= 1'b0;
			sm_start  		= 1'b0;
			sm_transfer 	= 1'b0;
			sm_rd_tr		= 1'b0;
			sm_stop     	= 1'b0;
			sm_data_valid 	= 1'b1;
			sm_no_ans		= 1'b0;
			next_state  	= IDLE;
		end
	endcase
end

endmodule