Apple1_MiST/rtl/mist-modules/sd_card.v

620 lines
21 KiB
Verilog

//
// sd_card.v
//
// This file implelents a sd card for the MIST board since on the board
// the SD card is connected to the ARM IO controller and the FPGA has no
// direct connection to the SD card. This file provides a SD card like
// interface to the IO controller easing porting of cores that expect
// a direct interface to the SD card.
//
// Copyright (c) 2014 Till Harbaum <till@harbaum.org>
//
// This source file is free software: you can redistribute it and/or modify
// it under the terms of the Lesser GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// http://elm-chan.org/docs/mmc/mmc_e.html
module sd_card (
input clk_sys,
// link to user_io for io controller
output reg[31:0] sd_lba,
output reg sd_rd,
output reg sd_wr,
input sd_ack,
input sd_ack_conf,
output sd_conf,
output sd_sdhc,
input img_mounted,
input [63:0] img_size,
output reg sd_busy = 0,
// data coming in from io controller
input [7:0] sd_buff_dout,
input sd_buff_wr,
// data going out to io controller
output [7:0] sd_buff_din,
input [8:0] sd_buff_addr,
// configuration input
// in case of a VHD file, this will determine the SD Card type returned to the SPI master
// in case of a pass-through, the firmware will display a warning if SDHC is not allowed,
// but the card inserted is SDHC
input allow_sdhc,
input sd_cs,
input sd_sck,
input sd_sdi,
output reg sd_sdo
);
wire [31:0] OCR = { 1'b1, sdhc, 6'h0, 9'h1f, 15'h0 }; // bit31 = finished powerup
// bit30 = 1 -> high capaciry card (sdhc)
// 15-23 supported voltage range
wire [7:0] READ_DATA_TOKEN = 8'hfe;
// number of bytes to wait after a command before sending the reply
localparam NCR=4;
localparam RD_STATE_IDLE = 3'd0;
localparam RD_STATE_WAIT_BUSY = 3'd1;
localparam RD_STATE_WAIT_IO = 3'd2;
localparam RD_STATE_SEND_TOKEN = 3'd3;
localparam RD_STATE_SEND_DATA = 3'd4;
localparam RD_STATE_DELAY = 3'd5;
reg [2:0] read_state = RD_STATE_IDLE;
localparam WR_STATE_IDLE = 3'd0;
localparam WR_STATE_EXP_DTOKEN = 3'd1;
localparam WR_STATE_RECV_DATA = 3'd2;
localparam WR_STATE_RECV_CRC0 = 3'd3;
localparam WR_STATE_RECV_CRC1 = 3'd4;
localparam WR_STATE_SEND_DRESP = 3'd5;
localparam WR_STATE_WRITE = 3'd6;
localparam WR_STATE_BUSY = 3'd7;
reg [2:0] write_state = WR_STATE_IDLE;
reg card_is_reset = 1'b0; // flag that card has received a reset command
reg [6:0] sbuf;
reg cmd55;
reg terminate_cmd = 1'b0;
reg [7:0] cmd = 8'h00;
reg [2:0] bit_cnt = 3'd0; // counts bits 0-7 0-7 ...
reg [3:0] byte_cnt= 4'd15; // counts bytes
reg [4:0] delay_cnt;
reg wr_first;
reg [39:0] args;
reg [7:0] reply;
reg [7:0] reply0, reply1, reply2, reply3;
reg [3:0] reply_len;
// ------------------------- SECTOR BUFFER -----------------------
// the buffer itself. Can hold two sectors
reg [9:0] buffer_ptr;
wire [7:0] buffer_dout;
reg [7:0] buffer_din;
reg buffer_write_strobe;
reg sd_buff_sel;
sd_card_dpram #(8, 10) buffer_dpram
(
.clock_a (clk_sys),
.address_a ({sd_buff_sel, sd_buff_addr}),
.data_a (sd_buff_dout),
.wren_a (sd_buff_wr & sd_ack & read_state != RD_STATE_IDLE),
.q_a (sd_buff_din),
.clock_b (clk_sys),
.address_b (buffer_ptr),
.data_b (buffer_din),
.wren_b (buffer_write_strobe),
.q_b (buffer_dout)
);
wire [7:0] WRITE_DATA_RESPONSE = 8'h05;
// ------------------------- CSD/CID BUFFER ----------------------
reg [7:0] conf;
assign sd_conf = sd_configuring;
reg sd_configuring = 1;
reg [4:0] conf_buff_ptr;
reg [7:0] conf_byte_orig;
reg[255:0] csdcid;
reg vhd = 0;
reg [40:0] vhd_size;
// conf[0]==1 -> io controller is using an sdhc card
wire sd_has_sdhc = conf[0];
assign sd_sdhc = (allow_sdhc & sd_has_sdhc) | vhd; // report to user_io
wire sdhc = allow_sdhc & (sd_has_sdhc | vhd); // used internally
always @(posedge clk_sys) begin
reg old_mounted;
if (sd_buff_wr & sd_ack_conf) begin
if (sd_buff_addr == 32) begin
conf <= sd_buff_dout;
sd_configuring <= 0;
end
else csdcid[(31-sd_buff_addr) << 3 +:8] <= sd_buff_dout;
end
conf_byte_orig <= csdcid[(31-conf_buff_ptr) << 3 +:8];
old_mounted <= img_mounted;
if (~old_mounted & img_mounted) begin
vhd <= |img_size;
vhd_size <= img_size[40:0];
end
end
// CSD V1.0 no. of blocks = c_size ** (c_size_mult + 2)
wire [127:0] csd_sd = {
8'h00, // CSD_STRUCTURE + reserved
8'h2d, // TAAC
8'd0, // NSAC
8'h32, // TRAN_SPEED
12'h5b5, // CCC
4'h9, // READ_BL_LEN
1'b1, 1'b0, 1'b0, 1'b0, // READ_BL_PARTIAL, WRITE_BLK_MISALIGN, READ_BLK_MISALIGN, DSR_IMP
2'd0, vhd_size[29:18], // reserved + C_SIZE
3'b111, // VDD_R_CURR_MIN
3'b110, // VDD_R_CURR_MAX
3'b111, // VDD_W_CURR_MIN
3'b110, // VDD_W_CURR_MAX
3'd7, // C_SIZE_MULT
1'b1, // ERASE_BLK_EN
7'd127, // SECTOR_SIZE
7'd0, // WP_GRP_SIZE
1'b0, // WP_GRP_ENABLE,
2'b00, // reserved,
3'd5, // R2W_FACTOR,
4'h9, // WRITE_BL_LEN,
1'b0, // WRITE_BL_PARTIAL,
5'd0, // reserved,
8'd0,
7'h67, // CRC (wrong, but usually not checked)
1'b1 };
// CSD V2.0 size = (c_size + 1) * 512K
wire [127:0] csd_sdhc = {
8'h40, // CSD_STRUCTURE + reserved
8'h0e, // TAAC
8'd0, // NSAC
8'h32, // TRAN_SPEED
12'h5b5, // CCC
4'h9, // READ_BL_LEN
1'b0, 1'b0, 1'b0, 1'b0, // READ_BL_PARTIAL, WRITE_BLK_MISALIGN, READ_BLK_MISALIGN, DSR_IMP
6'd0, // reserved
vhd_size[40:19] - 1'd1, // C_SIZE
1'b0, // reserved
1'b1, // ERASE_BLK_EN
7'd127, // SECTOR_SIZE
7'd0, // WP_GRP_SIZE
1'b0, // WP_GRP_ENABLE,
2'b00, // reserved,
3'd2, // R2W_FACTOR,
4'h9, // WRITE_BL_LEN,
1'b0, // WRITE_BL_PARTIAL,
5'd0, // reserved,
8'd0,
7'h78, // CRC (wrong, but usually not checked)
1'b1 };
wire [7:0] conf_byte = (!conf_buff_ptr[4] | !vhd) ? conf_byte_orig : // CID or CSD if not VHD
sdhc ? csd_sdhc[(15-conf_buff_ptr[3:0]) << 3 +:8] :
csd_sd[(15-conf_buff_ptr[3:0]) << 3 +:8];
always@(posedge clk_sys) begin
reg old_sd_sck;
reg [5:0] ack;
ack <= {ack[4:0], sd_ack};
if(ack[5:4] == 'b01) { sd_rd, sd_wr } <= 2'b00;
if(ack[5:4] == 'b10) sd_busy <= 0;
buffer_write_strobe <= 0;
if (buffer_write_strobe) buffer_ptr <= buffer_ptr + 1'd1;
old_sd_sck <= sd_sck;
// advance transmitter state machine on falling sck edge, so data is valid on the
// rising edge
// ----------------- spi transmitter --------------------
if(sd_cs == 0 && old_sd_sck && ~sd_sck) begin
sd_sdo <= 1'b1; // default: send 1's (busy/wait)
if(byte_cnt == 5+NCR) begin
sd_sdo <= reply[~bit_cnt];
if(bit_cnt == 7) begin
// these three commands all have a reply_len of 0 and will thus
// not send more than a single reply byte
// CMD9: SEND_CSD
// CMD10: SEND_CID
if((cmd == 8'h49)||(cmd == 8'h4a))
read_state <= RD_STATE_SEND_TOKEN; // jump directly to data transmission
// CMD17: READ_SINGLE_BLOCK
// CMD18: READ_MULTIPLE_BLOCK
if((cmd == 8'h51 || cmd == 8'h52) && !terminate_cmd)
read_state <= RD_STATE_WAIT_BUSY; // start waiting for data from io controller
end
end
else if((reply_len > 0) && (byte_cnt == 5+NCR+1))
sd_sdo <= reply0[~bit_cnt];
else if((reply_len > 1) && (byte_cnt == 5+NCR+2))
sd_sdo <= reply1[~bit_cnt];
else if((reply_len > 2) && (byte_cnt == 5+NCR+3))
sd_sdo <= reply2[~bit_cnt];
else if((reply_len > 3) && (byte_cnt == 5+NCR+4))
sd_sdo <= reply3[~bit_cnt];
// ---------- read state machine processing -------------
case(read_state)
RD_STATE_IDLE: ;
// don't do anything
// wait until the IO controller is free and issue a read
RD_STATE_WAIT_BUSY:
if (~sd_busy) begin
sd_buff_sel <= 0;
sd_lba <= sdhc?args[39:8]:{9'd0, args[39:17]};
sd_rd <= 1; // trigger request to io controller
sd_busy <= 1;
read_state <= RD_STATE_WAIT_IO;
end
// waiting for io controller to return data
RD_STATE_WAIT_IO: begin
buffer_ptr <= 0;
if(~sd_busy) begin
if (terminate_cmd) begin
cmd <= 0;
read_state <= RD_STATE_IDLE;
end else if (bit_cnt == 7)
read_state <= RD_STATE_SEND_TOKEN;
end
end
// send data token
RD_STATE_SEND_TOKEN: begin
if(~sd_busy) begin
sd_sdo <= READ_DATA_TOKEN[~bit_cnt];
if(bit_cnt == 7) begin
read_state <= RD_STATE_SEND_DATA; // next: send data
conf_buff_ptr <= (cmd == 8'h4a) ? 5'h0 : 5'h10;
end
end
end
// send data
RD_STATE_SEND_DATA: begin
if(cmd == 8'h51 || (cmd == 8'h52 && !terminate_cmd)) // CMD17: READ_SINGLE_BLOCK, CMD18: READ_MULTIPLE_BLOCK
sd_sdo <= buffer_dout[~bit_cnt];
else if(cmd == 8'h49 || cmd == 8'h4a) // CMD9: SEND_CSD, CMD10: SEND CID
sd_sdo <= conf_byte[~bit_cnt];
if(bit_cnt == 7) begin
// sent 512 sector data bytes?
if((cmd == 8'h51) && &buffer_ptr[8:0])
read_state <= RD_STATE_IDLE; // next: send crc. It's ignored so return to idle state
if (cmd == 8'h52) begin
if (terminate_cmd) begin
read_state <= RD_STATE_IDLE;
cmd <= 0;
end else if (buffer_ptr[8:0] == 10) begin
// prefetch the next sector into the other buffer
sd_lba <= sd_lba + 1'd1;
sd_rd <= 1;
sd_busy <= 1;
sd_buff_sel <= !sd_buff_sel;
end else if (&buffer_ptr[8:0]) begin
delay_cnt <= 20;
read_state <= RD_STATE_DELAY;
end
end
// sent 16 cid/csd data bytes?
if(((cmd == 8'h49)||(cmd == 8'h4a)) && conf_buff_ptr[3:0] == 4'h0f) // && (buffer_rptr == 16))
read_state <= RD_STATE_IDLE; // return to idle state
buffer_ptr <= buffer_ptr + 1'd1;
conf_buff_ptr<= conf_buff_ptr+ 1'd1;
end
end
RD_STATE_DELAY:
if(bit_cnt == 7) begin
if (delay_cnt == 0) begin
read_state <= RD_STATE_SEND_TOKEN;
end else begin
delay_cnt <= delay_cnt - 1'd1;
end
end
endcase
// ------------------ write support ----------------------
// send write data response
if(write_state == WR_STATE_SEND_DRESP)
sd_sdo <= WRITE_DATA_RESPONSE[~bit_cnt];
// busy after write until the io controller sends ack
if(write_state == WR_STATE_WRITE || write_state == WR_STATE_BUSY)
sd_sdo <= 1'b0;
end
// spi receiver
// cs is active low
if(sd_cs == 1) begin
bit_cnt <= 3'd0;
terminate_cmd <= 0;
cmd <= 0;
read_state <= RD_STATE_IDLE;
reply_len <= 0;
end else if (~old_sd_sck & sd_sck) begin
bit_cnt <= bit_cnt + 3'd1;
// assemble byte
if(bit_cnt != 7)
sbuf[6:0] <= { sbuf[5:0], sd_sdi };
else begin
// finished reading one byte
// byte counter runs against 15 byte boundary
if(byte_cnt != 15)
byte_cnt <= byte_cnt + 4'd1;
// byte_cnt > 6 -> complete command received
// first byte of valid command is 01xxxxxx
// don't accept new commands (except STOP TRANSMISSION) once a write or read command has been accepted
if((byte_cnt > (reply_len == 0 ? 5 : (5+NCR+reply_len))) &&
(write_state == WR_STATE_IDLE) &&
(read_state == RD_STATE_IDLE || (read_state != RD_STATE_IDLE && { sbuf, sd_sdi} == 8'h4c)) &&
sbuf[6:5] == 2'b01)
begin
byte_cnt <= 4'd0;
terminate_cmd <= 0;
if ({ sbuf, sd_sdi } == 8'h4c) begin
terminate_cmd <= 1;
end else
cmd <= { sbuf, sd_sdi};
end
// parse additional command bytes
if(byte_cnt == 0) args[39:32] <= { sbuf, sd_sdi};
if(byte_cnt == 1) args[31:24] <= { sbuf, sd_sdi};
if(byte_cnt == 2) args[23:16] <= { sbuf, sd_sdi};
if(byte_cnt == 3) args[15:8] <= { sbuf, sd_sdi};
if(byte_cnt == 4) args[7:0] <= { sbuf, sd_sdi};
// last byte received, evaluate
if(byte_cnt == 5) begin
// default:
reply <= 8'h04; // illegal command
reply_len <= 4'd0; // no extra reply bytes
cmd55 <= 0;
// CMD0: GO_IDLE_STATE
if(cmd == 8'h40) begin
card_is_reset <= 1'b1;
reply <= 8'h01; // ok, busy
end
// every other command is only accepted after a reset
else if(card_is_reset) begin
// CMD12: STOP_TRANSMISSION
if (terminate_cmd)
reply <= 8'h00; // ok
else case(cmd)
// CMD1: SEND_OP_COND
8'h41: reply <= 8'h00; // ok, not busy
// CMD8: SEND_IF_COND (V2 only)
8'h48: begin
reply <= 8'h01; // ok, busy
reply0 <= 8'h00;
reply1 <= 8'h00;
reply2 <= { 4'b0, args[19:16] };
reply3 <= args[15:8];
reply_len <= 4'd4;
end
// CMD9: SEND_CSD
8'h49: reply <= 8'h00; // ok
// CMD10: SEND_CID
8'h4a: reply <= 8'h00; // ok
// CMD13: SEND_STATUS
8'h4d: begin
reply <= 8'h00; // ok
reply0 <=8'h00;
reply_len <= 4'd1;
end
// CMD16: SET_BLOCKLEN
8'h50:
// we only support a block size of 512
if(args[39:8] == 32'd512)
reply <= 8'h00; // ok
else
reply <= 8'h40; // parmeter error
// CMD17: READ_SINGLE_BLOCK
8'h51: reply <= 8'h00; // ok
// CMD18: READ_MULTIPLE_BLOCK
8'h52: reply <= 8'h00; // ok
// CMD24: WRITE_BLOCK
// CMD25: WRITE_MULTIPLE_BLOCKS
8'h58, 8'h59: begin
reply <= 8'h00; // ok
buffer_ptr <= 0;
wr_first <= 1;
write_state <= WR_STATE_EXP_DTOKEN; // expect data token
end
// ACMD41: APP_SEND_OP_COND
8'h69: if(cmd55) begin
reply <= 8'h00; // ok, not busy
end
// CMD55: APP_COND
8'h77: begin
reply <= 8'h01; // ok, busy
cmd55 <= 1;
end
// CMD58: READ_OCR
8'h7a: begin
reply <= 8'h00; // ok
reply0 <= OCR[31:24]; // bit 30 = 1 -> high capacity card
reply1 <= OCR[23:16];
reply2 <= OCR[15:8];
reply3 <= OCR[7:0];
reply_len <= 4'd4;
end
endcase
end
end
end
end
// ---------- handle write -----------
case(write_state)
// don't do anything in idle state
WR_STATE_IDLE: ;
// waiting for data token
WR_STATE_EXP_DTOKEN:
if (sd_cs) write_state <= WR_STATE_IDLE;
else if (~old_sd_sck && sd_sck && bit_cnt == 7) begin
if({ sbuf, sd_sdi} == 8'hfd && cmd == 8'h59)
// stop multiple write (and wait until the last write finishes)
write_state <= WR_STATE_BUSY;
else
if({ sbuf, sd_sdi} == ((cmd == 8'h59) ? 8'hfc : 8'hfe))
write_state <= WR_STATE_RECV_DATA;
end
// transfer 512 bytes
WR_STATE_RECV_DATA:
if (sd_cs) write_state <= WR_STATE_IDLE;
else if (~old_sd_sck && sd_sck && bit_cnt == 7) begin
// push one byte into local buffer
buffer_write_strobe <= 1'b1;
buffer_din <= { sbuf, sd_sdi };
// all bytes written?
if(&buffer_ptr[8:0])
write_state <= WR_STATE_RECV_CRC0;
end
// transfer 1st crc byte
WR_STATE_RECV_CRC0:
if (sd_cs) write_state <= WR_STATE_IDLE;
else if (~old_sd_sck && sd_sck && bit_cnt == 7) write_state <= WR_STATE_RECV_CRC1;
// transfer 2nd crc byte
WR_STATE_RECV_CRC1:
if (sd_cs) write_state <= WR_STATE_IDLE;
else if (~old_sd_sck && sd_sck && bit_cnt == 7) write_state <= WR_STATE_SEND_DRESP;
// send data response
WR_STATE_SEND_DRESP:
if (sd_cs) write_state <= WR_STATE_IDLE;
else if (~old_sd_sck && sd_sck && bit_cnt == 7) write_state <= WR_STATE_WRITE;
WR_STATE_WRITE:
if (~sd_busy) begin
if (wr_first) begin
sd_buff_sel <= 0;
sd_lba <= sdhc?args[39:8]:{9'd0, args[39:17]};
wr_first <= 0;
end else begin
sd_buff_sel <= !sd_buff_sel;
sd_lba <= sd_lba + 1'd1;
end
sd_wr <= 1; // trigger write request to io controller
sd_busy <= 1;
if (sd_cs || cmd == 8'h58)
write_state <= WR_STATE_BUSY;
else
write_state <= WR_STATE_EXP_DTOKEN; // multi-sector writes
end
WR_STATE_BUSY:
if (~sd_busy) write_state <= WR_STATE_IDLE;
default: ;
endcase
end
endmodule
module sd_card_dpram #(parameter DATAWIDTH=8, ADDRWIDTH=9)
(
input clock_a,
input [ADDRWIDTH-1:0] address_a,
input [DATAWIDTH-1:0] data_a,
input wren_a,
output reg [DATAWIDTH-1:0] q_a,
input clock_b,
input [ADDRWIDTH-1:0] address_b,
input [DATAWIDTH-1:0] data_b,
input wren_b,
output reg [DATAWIDTH-1:0] q_b
);
reg [DATAWIDTH-1:0] ram[0:(1<<ADDRWIDTH)-1];
always @(posedge clock_a) begin
q_a <= ram[address_a];
if(wren_a) begin
q_a <= data_a;
ram[address_a] <= data_a;
end
end
always @(posedge clock_b) begin
q_b <= ram[address_b];
if(wren_b) begin
q_b <= data_b;
ram[address_b] <= data_b;
end
end
endmodule