/* Labkit project demonstrating SD controller use. */

`timescale 1ns / 1ps

// Be sure to enable SD_CD, SD_RESET, SD_SCK, SD_CMD, and SD_DAT in the
// constraints file.
module labkit(input CLK100MHZ, input SD_CD, output SD_RESET, output SD_SCK, output SD_CMD, 
	inout [3:0] SD_DAT, output [15:0] LED, input BTNC);

	// Clock the SD card at 25 MHz.
	wire clk_100mhz = CLK100MHZ;
	wire clk_50mhz;
	wire clk_25mhz;
	clock_divider div1(clk_100mhz, clk_50mhz);
	clock_divider div2(clk_50mhz, clk_25mhz);

	wire rst = BTNC;
	wire spiClk;
	wire spiMiso;
	wire spiMosi;
	wire spiCS;

	// MicroSD SPI/SD Mode/Nexys 4
	// 1: Unused / DAT2 / SD_DAT[2]
	// 2: CS / DAT3 / SD_DAT[3]
	// 3: MOSI / CMD / SD_CMD
	// 4: VDD / VDD / ~SD_RESET
	// 5: SCLK / SCLK / SD_SCK
	// 6: GND / GND / - 
	// 7: MISO / DAT0 / SD_DAT[0]
	// 8: UNUSED / DAT1 / SD_DAT[1]
	assign SD_DAT[2] = 1;
	assign SD_DAT[3] = spiCS;
	assign SD_CMD = spiMosi;
	assign SD_RESET = 0;
	assign SD_SCK = spiClk;
	assign spiMiso = SD_DAT[0];
	assign SD_DAT[1] = 1;
	
	reg rd = 0;
	reg wr = 0;
	reg [7:0] din = 0;
	wire [7:0] dout;
	wire byte_available;
	wire ready;
	wire ready_for_next_byte;
	reg [31:0] adr = 32'h00_00_00_00;
	
	reg [15:0] bytes = 0;
	reg [1:0] bytes_read = 0;
	
	wire [4:0] state;
	
	parameter STATE_INIT = 0;
	parameter STATE_START = 1;
	parameter STATE_WRITE = 2;
	parameter STATE_READ = 3;
	reg [1:0] test_state = STATE_INIT; 
	assign LED = {state, ready, test_state, bytes[15:8]};
	
	sd_controller sdcont(.cs(spiCS), .mosi(spiMosi), .miso(spiMiso),
			.sclk(spiClk), .rd(rd), .wr(wr), .reset(rst),
			.din(din), .dout(dout), .byte_available(byte_available),
			.ready(ready), .address(adr), 
			.ready_for_next_byte(ready_for_next_byte), .clk(clk_25mhz), 
			.status(state));
	

	always @(posedge clk_25mhz) begin
		if(rst) begin
			bytes <= 0;
			bytes_read <= 0;
			din <= 0;
			wr <= 0;
			rd <= 0;
			test_state <= STATE_INIT; 
		end
		else begin
			case (test_state)
				STATE_INIT: begin
					if(ready) begin
						test_state <= STATE_START;
						wr <= 1;
						din <= 8'hAA;
					end
				end
				STATE_START: begin
					if(ready == 0) begin
						test_state <= STATE_WRITE;
						wr <= 0;
					end
				end
				STATE_WRITE: begin
					if(ready) begin
						test_state <= STATE_READ;
						rd <= 1;
					end
					else if(ready_for_next_byte) begin
						din <= 8'hAA;
					end
				end
				STATE_READ: begin
					if(byte_available) begin
						rd <= 0;
						if(bytes_read == 0) begin
							bytes_read <= 1;
							bytes[15:8] <= dout;
						end
						else if(bytes_read == 1) begin
							bytes_read <= 2;
							bytes[7:0] <= dout;
							
						end
					end
				end
			endcase
		end
	end
endmodule

module clock_divider(input clk_in, output reg clk_out = 0);
	always @(posedge clk_in) begin
		clk_out <= ~clk_out;
	end
endmodule