module i2c_fifo
	(		
		input	wire			clock, reset,

		input	wire			bus_ssel, bus_wren,
		input	wire	[15:0]	bus_mosi,

		output	wire			bus_busy,

		inout	wire			i2c_sda,
		inout	wire			i2c_scl
	);

	wire			int_rdempty, int_wrfull, i2c_clk, start, stop;
	wire	[15:0]	int_q;

	reg				int_bus_busy;
	reg				int_rdreq, int_wrreq, int_clken, int_sdo, int_scl, int_ack;
	reg		[15:0]	int_bus_mosi;
	reg		[15:0]	int_data;
	reg		[9:0]	counter;
	reg		[4:0]	state;

	assign i2c_sda = int_sdo ? 1'bz : 1'b0;
	assign i2c_scl = int_scl | (int_clken ? counter[9] : 1'b0);	

	assign start = int_data[8];
	assign stop = int_data[9];

	scfifo #(
		.add_ram_output_register("OFF"),
		.intended_device_family("Cyclone III"),
		.lpm_numwords(16),
		.lpm_showahead("ON"),
		.lpm_type("scfifo"),
		.lpm_width(16),
		.lpm_widthu(4),
		.overflow_checking("ON"),
		.underflow_checking("ON"),
		.use_eab("OFF")) fifo_tx (
		.rdreq((~int_rdempty) & (int_rdreq) & (&counter)),
		.aclr(1'b0),
		.clock(clock),
		.wrreq(int_wrreq),
		.data(int_bus_mosi),
		.empty(int_rdempty),
		.q(int_q),
		.full(int_wrfull),
		.almost_empty(),
		.almost_full(),
		.sclr(),
		.usedw());
	
	always @ (posedge clock)
	begin
		int_bus_busy <= int_wrfull;

		if (bus_ssel)
		begin
			if (~int_wrfull & bus_wren)
			begin
				int_bus_mosi <= bus_mosi;
				int_wrreq <= 1'b1;
			end
		end
		
		if (~int_wrfull & int_wrreq)
		begin
			int_wrreq <= 1'b0;
		end

	end

	always @ (posedge clock)
	begin
		counter <= counter + 10'd1;
		if (&counter)
		begin
			case (state)
				0:
				begin
					int_ack <= 1'b0;
					int_sdo <= 1'b1;
					int_scl <= 1'b1;
					int_rdreq <= 1'b1;
					state <= 5'd1;
				end
	
				1: 
				begin
					if (~int_rdempty)
					begin
						int_data <= int_q;
						int_rdreq <= 1'b0;
						state <= 5'd2;
					end
				end
	
				2: 
				begin
					if (start)
					begin
						int_sdo <= 1'b1;
						int_scl <= 1'b1;
						state <= 5'd3;
					end
					else
					begin
						state <= 5'd5;
					end
				end
			
				3:
				begin // start
					int_sdo <= 1'b0;
					state <= 5'd4;
				end
	
				4:
				begin
					int_scl <= 1'b0;
					state <= 5'd5;
				end
			
				5:
				begin // data
					int_clken <= 1'b1;
					int_sdo <= int_data[7];
					state <= 5'd6;
				end
	
				6:
				begin
					int_sdo <= int_data[6];
					state <= 5'd7;
				end
	
				7:
				begin
					int_sdo <= int_data[5];
					state <= 5'd8;
				end
	
				8:
				begin
					int_sdo <= int_data[4];
					state <= 5'd9;
				end
	
				9:
				begin
					int_sdo <= int_data[3];
					state <= 5'd10;
				end
	
				10:
				begin
					int_sdo <= int_data[2];
					state <= 5'd11;
				end
	
				11:
				begin
					int_sdo <= int_data[1];
					state <= 5'd12;
				end
	
				12:
				begin
					int_sdo <= int_data[0];
					state <= 5'd13;
				end
				
				13:
				begin // ack
					int_sdo <= 1'b1;
					int_rdreq <= 1'b1;
					state <= 5'd14;
				end
	
				14:
				begin 
					int_ack <= i2c_sda;
					int_rdreq <= 1'b0;
					if (stop | int_rdempty)
					begin
						int_clken <= 1'b0;
						int_sdo <= 1'b0;
						int_scl <= 1'b0;
						state <= 5'd15;
					end
					else if (~int_rdempty)
					begin
						int_data <= int_q;
						int_sdo <= int_q[7];
						state <= 5'd6;
					end
				end
	
				15:
				begin // stop
					int_scl <= 1'b1;
					state <= 5'd16;
				end
	
				16:
				begin
					int_sdo <= 1'b1;
					state <= 5'd0;
				end
	
			endcase
		end
	end

	// output logic
	assign	bus_busy = int_bus_busy;

endmodule
