module spi_fifo
	(		
		input	wire			clock, reset,

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

		output	wire			bus_busy,

		output	wire	[1:0]	spi_sel,
		output	wire			spi_sdo,
		output	wire			spi_clk
	);

	wire			int_rdempty, int_wrfull;
	wire	[31:0]	int_q;

	reg				int_bus_busy;
	reg				int_rdreq, int_wrreq;
	reg				int_clken, int_sdo;
	reg		[1:0]	int_sel;
	reg		[15:0]	int_bus_mosi;
	reg		[31:0]	int_data;
	reg		[2:0]	clk_cntr;
	reg		[4:0]	bit_cntr;
	reg		[1:0]	state;

	dcfifo_mixed_widths #(
		.intended_device_family("Cyclone III"),
		.lpm_numwords(16),
		.lpm_showahead("ON"),
		.lpm_type("dcfifo"),
		.lpm_width(16),
		.lpm_widthu(4),
		.lpm_width_r(32),
		.lpm_widthu_r(3),
		.rdsync_delaypipe(4),
		.wrsync_delaypipe(4),
		.overflow_checking("ON"),
		.underflow_checking("ON"),
		.use_eab("ON")) fifo_tx (
		.data(int_bus_mosi),
		.rdclk(clock),
		.rdreq((~int_rdempty) & (int_rdreq) & (&clk_cntr)),
		.wrclk(clock),
		.wrreq(int_wrreq),
		.q(int_q),
		.rdempty(int_rdempty),
		.wrfull(int_wrfull));
	
	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
		clk_cntr <= clk_cntr + 3'd1;
		if (&clk_cntr)
		begin
			case (state)
				0:
				begin
					int_sdo <= 1'b0;
					int_sel <= 2'b11;
					int_clken <= 1'b0;
					int_rdreq <= 1'b1;
					state <= 2'd1;
				end
	
				1: 
				begin
					if (~int_rdempty)
					begin
						int_rdreq <= 1'b0;
						int_data <= {int_q[15:0], int_q[31:16]};
						bit_cntr <= 5'd0;
						state <= 2'd2;
					end
				end
	

				2:
				begin // data
					int_clken <= 1'b1;
					int_sel <= int_data[25:24];
					int_sdo <= int_data[23];
					int_data[23:0] <= {int_data[22:0], 1'b0};
					bit_cntr <= bit_cntr + 5'd1;
					if (bit_cntr == 5'd23)
					begin
						state <= 2'd3;
					end
				end
	
				3:
				begin
					int_sdo <= 1'b0;
					int_clken <= 1'b0;
					state <= 2'd0;
				end
	
			endcase
		end
	end

	// output logic
	assign	bus_busy = int_bus_busy;
	assign 	spi_clk = (int_clken ? clk_cntr[2] : 1'b1);	
	assign 	spi_sdo = int_sdo;	
	assign 	spi_sel = int_sel;	

endmodule
