`timescale 1ns / 1ps module sdio_to_spi ( input wire sd_clk, inout wire sd_cmd, inout wire [3:0] sd_dat, output reg sd_cmd_dir, output reg [3:0] sd_dat_dir, input wire clk_sys, input wire rst_n, output reg [7:0] cmd_opcode, output reg [31:0] cmd_address, output reg [15:0] cmd_length, output reg cmd_valid, input wire cmd_ready, output reg [7:0] data_out, output reg data_out_valid, input wire data_out_ready, input wire [7:0] data_in, input wire data_in_valid, output reg data_in_ready, output reg [3:0] sdio_state, output reg [3:0] status_reg ); localparam CMD0_GO_IDLE_STATE = 6'h00; localparam CMD2_ALL_SEND_CID = 6'h02; localparam CMD3_SEND_RELATIVE_ADDR = 6'h03; localparam CMD7_SELECT_CARD = 6'h07; localparam CMD8_SEND_IF_COND = 6'h08; localparam CMD9_SEND_CSD = 6'h09; localparam CMD12_STOP_TRANSMISSION = 6'h0C; localparam CMD16_SET_BLOCKLEN = 6'h10; localparam CMD17_READ_SINGLE_BLOCK = 6'h11; localparam CMD18_READ_MULTIPLE_BLOCK = 6'h12; localparam CMD24_WRITE_BLOCK = 6'h18; localparam CMD25_WRITE_MULTIPLE_BLOCK = 6'h19; localparam CMD55_APP_CMD = 6'h37; localparam ACMD41_SD_SEND_OP_COND = 6'h29; localparam STATE_IDLE = 4'h0; localparam STATE_CMD_RX = 4'h1; localparam STATE_CMD_PROCESS = 4'h2; localparam STATE_RESP_TX = 4'h3; localparam STATE_DATA_RX = 4'h4; localparam STATE_DATA_TX = 4'h5; localparam STATE_WAIT_SPI = 4'h6; localparam STATE_ERROR = 4'h7; localparam SPI_READ = 8'h03; localparam SPI_FAST_READ = 8'h0B; localparam SPI_PP = 8'h02; localparam SPI_SE = 8'h20; localparam SPI_BE = 8'hD8; localparam SPI_CE = 8'hC7; localparam SPI_RDSR = 8'h05; localparam SPI_WREN = 8'h06; localparam SPI_RDID = 8'h9F; reg [47:0] cmd_reg; reg [5:0] cmd_index; reg cmd_start; reg cmd_done; reg [135:0] resp_reg; reg [6:0] resp_bit_count; reg resp_start; reg resp_done; reg [31:0] block_size; reg [31:0] rca; reg card_selected; reg [3:0] dat_bus_width; reg [15:0] data_counter; reg [7:0] crc7; reg [15:0] crc16; always @(posedge sd_clk or negedge rst_n) begin if (!rst_n) begin cmd_reg <= 48'h0; cmd_index <= 6'd0; cmd_start <= 1'b0; cmd_done <= 1'b0; sd_cmd_dir <= 1'b1; sdio_state <= STATE_IDLE; end else begin case (sdio_state) STATE_IDLE: begin cmd_start <= 1'b0; cmd_done <= 1'b0; sd_cmd_dir <= 1'b1; if (sd_cmd === 1'b0) begin sdio_state <= STATE_CMD_RX; cmd_index <= 6'd1; cmd_reg <= 48'h0; end end STATE_CMD_RX: begin if (cmd_index < 6'd48) begin cmd_reg[47] <= sd_cmd; cmd_reg <= cmd_reg << 1; cmd_index <= cmd_index + 1; end else begin sdio_state <= STATE_CMD_PROCESS; cmd_start <= 1'b1; cmd_done <= 1'b0; end end STATE_CMD_PROCESS: begin cmd_start <= 1'b0; if (cmd_ready && cmd_valid) begin sdio_state <= STATE_RESP_TX; resp_start <= 1'b1; end end STATE_RESP_TX: begin resp_start <= 1'b0; sd_cmd_dir <= 1'b0; if (resp_done) begin if (cmd_reg[45:40] == CMD17_READ_SINGLE_BLOCK || cmd_reg[45:40] == CMD18_READ_MULTIPLE_BLOCK) begin sdio_state <= STATE_DATA_TX; end else if (cmd_reg[45:40] == CMD24_WRITE_BLOCK || cmd_reg[45:40] == CMD25_WRITE_MULTIPLE_BLOCK) begin sdio_state <= STATE_DATA_RX; end else begin sdio_state <= STATE_IDLE; end end end STATE_DATA_RX: begin end STATE_DATA_TX: begin end STATE_WAIT_SPI: begin end STATE_ERROR: begin end endcase end end always @(*) begin cmd_valid = 1'b0; cmd_opcode = 8'h00; cmd_address = 32'h0; cmd_length = 16'h0; if (cmd_start && !cmd_done) begin case (cmd_reg[45:40]) CMD17_READ_SINGLE_BLOCK: begin cmd_valid = 1'b1; cmd_opcode = SPI_READ; cmd_address = cmd_reg[39:8]; cmd_length = block_size; end CMD24_WRITE_BLOCK: begin cmd_valid = 1'b1; cmd_opcode = SPI_PP; cmd_address = cmd_reg[39:8]; cmd_length = block_size; end CMD9_SEND_CSD: begin cmd_valid = 1'b0; end CMD2_ALL_SEND_CID: begin cmd_valid = 1'b0; end default: begin cmd_valid = 1'b0; end endcase end end always @(posedge sd_clk) begin if (resp_start) begin case (cmd_reg[45:40]) CMD0_GO_IDLE_STATE: begin resp_reg <= {136{1'b1}}; end CMD8_SEND_IF_COND: begin resp_reg <= {8'hAA, 24'h0, 8'h01}; end CMD17_READ_SINGLE_BLOCK, CMD24_WRITE_BLOCK: begin resp_reg <= {8'h00, 120'h0}; end default: begin resp_reg <= {136{1'b1}}; end endcase end end always @(posedge sd_clk) begin if (!rst_n) begin data_out_valid <= 1'b0; data_in_ready <= 1'b0; sd_dat_dir <= 4'b1111; end else begin end end initial begin block_size = 32'd512; rca = 32'h00010000; card_selected = 1'b0; dat_bus_width = 4'b0001; status_reg = 4'b0000; end endmodule