Project

General

Profile

« Previous | Next » 

Revision 224

Added by markw almost 11 years ago

SD card fixes, due to how spi_master released cs_n during command. Thanks Till!

View differences:

mist/sd_card.v
// set io_rd once read_state machine starts waiting (rising edge of req_io_rd)
// and clear it once io controller uploads something (io_ack==1)
wire req_io_rd = (read_state == 3'd1);
wire io_reset = io_ack || sd_cs;
always @(posedge req_io_rd or posedge io_reset) begin
if(io_reset) io_rd <= 1'b0;
else io_rd <= 1'b1;
wire req_io_rd = (read_state == RD_STATE_WAIT_IO);
always @(posedge req_io_rd or posedge io_ack) begin
if(io_ack) io_rd <= 1'b0;
else io_rd <= 1'b1;
end
wire req_io_wr = (write_state == 3'd6);
always @(posedge req_io_wr or posedge io_reset) begin
if(io_reset) io_wr <= 1'b0;
else io_wr <= 1'b1;
wire req_io_wr = (write_state == WR_STATE_BUSY);
always @(posedge req_io_wr or posedge io_ack) begin
if(io_ack) io_wr <= 1'b0;
else io_wr <= 1'b1;
end
wire [31:0] OCR = { 1'b0, io_sdhc, 30'h0 }; // bit30 = 1 -> high capaciry card (sdhc)
......
localparam NCR=4;
// 0=idle, 1=wait for io ctrl, 2=wait for byte start, 2=send token, 3=send data, 4/5=send crc[0..1]
reg [2:0] read_state;
// 0=idle, 1=wait for io ctrl, 2=wait for byte start, 3=send token, 4=send data, 5/6=send crc[0..1]
localparam RD_STATE_IDLE = 3'd0;
localparam RD_STATE_WAIT_IO = 3'd1;
localparam RD_STATE_WAIT_START = 3'd2;
localparam RD_STATE_SEND_TOKEN = 3'd3;
localparam RD_STATE_SEND_DATA = 3'd4;
localparam RD_STATE_SEND_CRC0 = 3'd5;
localparam RD_STATE_SEND_CRC1 = 3'd6;
reg [2:0] read_state = RD_STATE_IDLE;
// 0=idle
reg [2:0] write_state;
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_BUSY = 3'd6;
reg [2:0] write_state = WR_STATE_IDLE;
reg [6:0] sbuf;
reg cmd55;
reg new_cmd_rcvd;
reg [7:0] cmd;
reg [2:0] bit_cnt; // counts bits 0-7 0-7 ...
reg [7:0] byte_cnt; // counts bytes
reg [7:0] cmd_cnt; // counts command bytes
reg [2:0] bit_cnt; // counts bits 0-7 0-7 ...
reg [3:0] byte_cnt= 4'd15; // counts bytes
reg [7:0] lba0, lba1, lba2, lba3;
assign io_lba = io_sdhc?{ lba3, lba2, lba1, lba0 }:{9'd0, lba3, lba2, lba1[7:1]};
reg [31:0] lba;
assign io_lba = io_sdhc?lba:{9'd0, lba[31:9]};
// the command crc is actually never evaluated
reg [7:0] crc;
......
reg [7:0] reply0, reply1, reply2, reply3;
reg [3:0] reply_len;
reg io_ackD, io_ackD2;
// signals to address buffer on SD card write (data coming from SD spi)
reg write_strobe;
reg [7:0] write_data;
// falling edge of io_ack signals that a sector to be read has been written into
// the sector bufffer by the io controller. This signal is kept set as long
// as the read state machine is in the "wait for io controller" state (state 1)
wire rd_wait_io = (read_state == RD_STATE_WAIT_IO);
reg rd_io_ack = 1'b0 /* synthesis noprune */;
always @(negedge io_ack or negedge rd_wait_io) begin
if(!rd_wait_io) rd_io_ack <= 1'b0;
else rd_io_ack <= 1'b1;
end
wire wr_wait_io = (write_state == WR_STATE_BUSY);
reg wr_io_ack = 1'b0 /* synthesis noprune */;
always @(negedge io_ack or negedge wr_wait_io) begin
if(!wr_wait_io) wr_io_ack <= 1'b0;
else wr_io_ack <= 1'b1;
end
// ------------------------- SECTOR BUFFER -----------------------
// access to the sector buffer is multiplexed. When reading sectors
// the io controller writes into the buffer and the sd card implementation
// reads. And vice versa when writing sectors
wire reading = (read_state != 0);
wire writing = (write_state != 0);
wire reading = (read_state != RD_STATE_IDLE);
wire writing = (write_state != WR_STATE_IDLE);
// the buffer itself. Can hold one sector
reg [8:0] buffer_wptr;
......
always @(posedge buffer_read_latch)
buffer_byte <= buffer[buffer_rptr];
always @(posedge buffer_read_strobe or posedge sd_cs) begin
if(sd_cs == 1) buffer_rptr <= 9'd0;
else buffer_rptr <= buffer_rptr + 9'd1;
always @(posedge buffer_read_strobe or posedge new_cmd_rcvd) begin
if(new_cmd_rcvd == 1) buffer_rptr <= 9'd0;
else buffer_rptr <= buffer_rptr + 9'd1;
end
// ---------------- buffer write engine -----------------------
wire [7:0] buffer_din = reading?io_din:write_data;
wire buffer_din_strobe = reading?io_din_strobe:write_strobe;
always @(negedge buffer_din_strobe or posedge sd_cs) begin
if(sd_cs == 1) begin
always @(negedge buffer_din_strobe or posedge new_cmd_rcvd) begin
if(new_cmd_rcvd == 1) begin
buffer_wptr <= 9'd0;
end else begin
buffer[buffer_wptr] <= buffer_din;
......
wire [7:0] WRITE_DATA_RESPONSE = 8'h05;
// ------------------------- CSD/CID BUFFER ----------------------
assign io_conf = (csd_wptr == 0);
assign io_conf = (csd_wptr == 0); // csd_wptr still 0 -> configuration required
// the 32 bytes as sent from the io controller
reg [7:0] cid [15:0];
......
always @(posedge buffer_read_latch)
csd_byte <= csd[buffer_rptr];
// ----------------- spi transmitter --------------------
reg rd_io_ackD, wr_io_ackD;
// ----------------- spi transmitter --------------------
always@(negedge sd_sck or posedge sd_cs) begin
if(sd_cs == 1) begin
sd_sdo <= 1'b1;
read_state <= 3'd0;
// sd_sdo <= 1'b1;
// read_state <= RD_STATE_IDLE;
end else begin
core_buffer_read_strobe <= 1'b0;
// bring io ack in local clock domain
io_ackD <= io_ack;
io_ackD2 <= io_ackD;
// using rd_io_ack directly brings the read state machine into an
// non-existing state every now and then. For unknown reason
rd_io_ackD <= rd_io_ack;
// -------- catch read commmand and reset read state machine ------
if(bit_cnt == 7) begin
if(cmd_cnt == 5) begin
if(byte_cnt == 4) begin
// CMD17: READ_SINGLE_BLOCK
if(cmd == 8'h51)
read_state <= 3'd1; // start waiting for data from io controller
read_state <= RD_STATE_WAIT_IO; // start waiting for data from io controller
end
end
if(byte_cnt < 6+NCR) begin
if(byte_cnt < 5+NCR) begin
sd_sdo <= 1'b1; // reply $ff -> wait
end else begin
if(byte_cnt == 6+NCR) begin
if(byte_cnt == 5+NCR) begin
sd_sdo <= reply[~bit_cnt];
if(bit_cnt == 7) begin
// CMD9: SEND_CSD
// CMD10: SEND_CID
if((cmd == 8'h49)||(cmd == 8'h4a))
read_state <= 3'd3; // jump directly to data transmission
read_state <= RD_STATE_SEND_TOKEN; // jump directly to data transmission
end
end
else if((reply_len > 0) && (byte_cnt == 6+NCR+1))
else if((reply_len > 0) && (byte_cnt == 5+NCR+1))
sd_sdo <= reply0[~bit_cnt];
else if((reply_len > 1) && (byte_cnt == 6+NCR+2))
else if((reply_len > 1) && (byte_cnt == 5+NCR+2))
sd_sdo <= reply1[~bit_cnt];
else if((reply_len > 2) && (byte_cnt == 6+NCR+3))
else if((reply_len > 2) && (byte_cnt == 5+NCR+3))
sd_sdo <= reply2[~bit_cnt];
else if((reply_len > 3) && (byte_cnt == 6+NCR+4))
else if((reply_len > 3) && (byte_cnt == 5+NCR+4))
sd_sdo <= reply3[~bit_cnt];
else
sd_sdo <= 1'b1;
// falling edge of io_ack signals end of incoming data stream
if((read_state == 3'd1) && !io_ackD && io_ackD2)
read_state <= 3'd2;
if((read_state == RD_STATE_WAIT_IO) && rd_io_ackD)
read_state <= RD_STATE_WAIT_START;
// wait for begin of new byte
if((read_state == 3'd2) && (bit_cnt == 7))
read_state <= 3'd3;
else if((read_state == RD_STATE_WAIT_START) && (bit_cnt == 7))
read_state <= RD_STATE_SEND_TOKEN;
// send data token
if(read_state == 3'd3) begin
else if(read_state == RD_STATE_SEND_TOKEN) begin
sd_sdo <= READ_DATA_TOKEN[~bit_cnt];
if(bit_cnt == 7)
read_state <= 3'd4; // next: send data
read_state <= RD_STATE_SEND_DATA; // next: send data
end
// send data
if(read_state == 3'd4) begin
else if(read_state == RD_STATE_SEND_DATA) begin
if(cmd == 8'h51) // CMD17: READ_SINGLE_BLOCK
sd_sdo <= buffer_byte[~bit_cnt];
else if(cmd == 8'h49) // CMD9: SEND_CSD
......
// send 512 sector data bytes?
if((cmd == 8'h51) && (buffer_rptr == 511))
read_state <= 3'd5; // next: send crc
read_state <= RD_STATE_SEND_CRC0; // next: send crc
// send 16 cid/csd data bytes?
if(((cmd == 8'h49)||(cmd == 8'h4a)) && (buffer_rptr == 15))
read_state <= 3'd0; // return to idle state
read_state <= RD_STATE_IDLE; // return to idle state
end
end
// send crc[0]
if(read_state == 3'd5) begin
else if(read_state == RD_STATE_SEND_CRC0) begin
sd_sdo <= 1'b1;
if(bit_cnt == 7)
read_state <= 3'd6; // send second crc byte
read_state <= RD_STATE_SEND_CRC1; // send second crc byte
end
// send crc[1]
if(read_state == 3'd6) begin
else if(read_state == RD_STATE_SEND_CRC1) begin
sd_sdo <= 1'b1;
if(bit_cnt == 7)
read_state <= 3'd0; // return to idle state
read_state <= RD_STATE_IDLE; // return to idle state
end
// ------------------ write support ----------------------
// send write data response
if(write_state == 3'd5)
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 == 3'd6)
if(write_state == WR_STATE_BUSY)
sd_sdo <= 1'b0;
end
end
......
// cs is active low
if(sd_cs == 1) begin
bit_cnt <= 3'd0;
byte_cnt <= 8'd0;
cmd_cnt <= 8'd0;
write_state <= 3'd0;
write_strobe <= 1'b0;
// byte_cnt <= 4'd15;
// write_state <= WR_STATE_IDLE;
// write_strobe <= 1'b0;
end else begin
new_cmd_rcvd <= 1'b0;
write_strobe <= 1'b0;
sbuf[6:0] <= { sbuf[5:0], sd_sdi };
bit_cnt <= bit_cnt + 3'd1;
if((bit_cnt == 7)&&(byte_cnt != 255)) begin
byte_cnt <= byte_cnt + 8'd1;
if(cmd_cnt == 0) begin
// first byte of valid command is 01xxxxxx
if((write_state == 3'd0) && sbuf[6:5] == 2'b01) begin
cmd_cnt <= 8'd1;
byte_cnt <= 8'd1;
end
end else if(cmd_cnt < 6)
cmd_cnt <= cmd_cnt + 8'd1;
else
// command counting stops after last command byte.
cmd_cnt <= 8'd0;
end
// using wr_io_ack directly brings the write state machine into an
// non-existing state every now and then. For unknown reason
wr_io_ackD <= wr_io_ack;
// finished reading command byte
if(bit_cnt == 7) begin
if(bit_cnt == 7) begin
// byte counter runs against 15 byte boundary
if(byte_cnt != 15)
byte_cnt <= byte_cnt + 8'd1;
// byte_cnt > 6 -> complete command received
// first byte of valid command is 01xxxxxx
if((byte_cnt > 5) && (write_state == WR_STATE_IDLE) && sbuf[6:5] == 2'b01)
byte_cnt <= 4'd0;
// don't accept new commands once a write command has been accepted
if((write_state == 3'd0) && (cmd_cnt == 0)&&(sbuf[6:5] == 2'b01)) begin
if((write_state == WR_STATE_IDLE) && (byte_cnt > 5)&&(sbuf[6:5] == 2'b01)) begin
cmd <= { sbuf, sd_sdi};
new_cmd_rcvd <= 1'b1;
// set cmd55 flag if previous command was 55
cmd55 <= (cmd == 8'h77);
end
// parse additional command bytes
if(cmd_cnt == 1) lba3 <= { sbuf, sd_sdi};
if(cmd_cnt == 2) lba2 <= { sbuf, sd_sdi};
if(cmd_cnt == 3) lba1 <= { sbuf, sd_sdi};
if(cmd_cnt == 4) lba0 <= { sbuf, sd_sdi};
if(cmd_cnt == 5) crc <= { sbuf, sd_sdi};
if(byte_cnt == 0) lba[31:24] <= { sbuf, sd_sdi};
if(byte_cnt == 1) lba[23:16] <= { sbuf, sd_sdi};
if(byte_cnt == 2) lba[15:8] <= { sbuf, sd_sdi};
if(byte_cnt == 3) lba[7:0] <= { sbuf, sd_sdi};
// last byte received, evaluate
if(byte_cnt == 4) begin
// crc is currently unused
crc <= { sbuf, sd_sdi};
// last byte received, evaluate
if(cmd_cnt == 5) begin
// default:
reply <= 8'h04; // illegal command
reply_len <= 4'd0; // no extra reply bytes
// CMD0: GO_IDLE_STATE
if(cmd == 8'h40)
reply <= 8'h01; // ok, busy
......
// CMD24: WRITE_BLOCK
else if(cmd == 8'h58) begin
reply <= 8'h00; // ok
write_state <= 3'd1; // expect data token
write_state <= WR_STATE_EXP_DTOKEN; // expect data token
end
// ACMD41: APP_SEND_OP_COND
......
// ---------- handle write -----------
// waiting for data token
if(write_state == 3'd1) begin
if(write_state == WR_STATE_EXP_DTOKEN) begin
if({ sbuf, sd_sdi} == 8'hfe )
write_state <= 3'd2;
write_state <= WR_STATE_RECV_DATA;
end
// transfer 512 bytes
if(write_state == 3'd2) begin
if(write_state == WR_STATE_RECV_DATA) begin
// push one byte into local buffer
write_strobe <= 1'b1;
write_data <= { sbuf, sd_sdi};
if(buffer_wptr == 511)
write_state <= 3'd3;
write_state <= WR_STATE_RECV_CRC0;
end
// transfer 1st crc byte
if(write_state == 3'd3)
write_state <= 3'd4;
if(write_state == WR_STATE_RECV_CRC0)
write_state <= WR_STATE_RECV_CRC1;
// transfer 2nd crc byte
if(write_state == 3'd4)
write_state <= 3'd5;
if(write_state == WR_STATE_RECV_CRC1)
write_state <= WR_STATE_SEND_DRESP;
// send data response
if(write_state == 3'd5)
write_state <= 3'd6;
if(write_state == WR_STATE_SEND_DRESP)
write_state <= WR_STATE_BUSY;
end
// wait for io controller to accept data
// this happens outside the bit_cnt == 7 test as the
// transition may happen at any time
if(write_state == 3'd6 && !io_ackD && io_ackD2)
write_state <= 3'd0;
if(write_state == WR_STATE_BUSY && wr_io_ackD)
write_state <= WR_STATE_IDLE;
end
end
mist_5200/sd_card.v
// set io_rd once read_state machine starts waiting (rising edge of req_io_rd)
// and clear it once io controller uploads something (io_ack==1)
wire req_io_rd = (read_state == 3'd1);
wire io_reset = io_ack || sd_cs;
always @(posedge req_io_rd or posedge io_reset) begin
if(io_reset) io_rd <= 1'b0;
else io_rd <= 1'b1;
wire req_io_rd = (read_state == RD_STATE_WAIT_IO);
always @(posedge req_io_rd or posedge io_ack) begin
if(io_ack) io_rd <= 1'b0;
else io_rd <= 1'b1;
end
wire req_io_wr = (write_state == 3'd6);
always @(posedge req_io_wr or posedge io_reset) begin
if(io_reset) io_wr <= 1'b0;
else io_wr <= 1'b1;
wire req_io_wr = (write_state == WR_STATE_BUSY);
always @(posedge req_io_wr or posedge io_ack) begin
if(io_ack) io_wr <= 1'b0;
else io_wr <= 1'b1;
end
wire [31:0] OCR = { 1'b0, io_sdhc, 30'h0 }; // bit30 = 1 -> high capaciry card (sdhc)
......
localparam NCR=4;
// 0=idle, 1=wait for io ctrl, 2=wait for byte start, 2=send token, 3=send data, 4/5=send crc[0..1]
reg [2:0] read_state;
// 0=idle, 1=wait for io ctrl, 2=wait for byte start, 3=send token, 4=send data, 5/6=send crc[0..1]
localparam RD_STATE_IDLE = 3'd0;
localparam RD_STATE_WAIT_IO = 3'd1;
localparam RD_STATE_WAIT_START = 3'd2;
localparam RD_STATE_SEND_TOKEN = 3'd3;
localparam RD_STATE_SEND_DATA = 3'd4;
localparam RD_STATE_SEND_CRC0 = 3'd5;
localparam RD_STATE_SEND_CRC1 = 3'd6;
reg [2:0] read_state = RD_STATE_IDLE;
// 0=idle
reg [2:0] write_state;
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_BUSY = 3'd6;
reg [2:0] write_state = WR_STATE_IDLE;
reg [6:0] sbuf;
reg cmd55;
reg new_cmd_rcvd;
reg [7:0] cmd;
reg [2:0] bit_cnt; // counts bits 0-7 0-7 ...
reg [7:0] byte_cnt; // counts bytes
reg [7:0] cmd_cnt; // counts command bytes
reg [2:0] bit_cnt; // counts bits 0-7 0-7 ...
reg [3:0] byte_cnt= 4'd15; // counts bytes
reg [7:0] lba0, lba1, lba2, lba3;
assign io_lba = io_sdhc?{ lba3, lba2, lba1, lba0 }:{9'd0, lba3, lba2, lba1[7:1]};
reg [31:0] lba;
assign io_lba = io_sdhc?lba:{9'd0, lba[31:9]};
// the command crc is actually never evaluated
reg [7:0] crc;
......
reg [7:0] reply0, reply1, reply2, reply3;
reg [3:0] reply_len;
reg io_ackD, io_ackD2;
// signals to address buffer on SD card write (data coming from SD spi)
reg write_strobe;
reg [7:0] write_data;
// falling edge of io_ack signals that a sector to be read has been written into
// the sector bufffer by the io controller. This signal is kept set as long
// as the read state machine is in the "wait for io controller" state (state 1)
wire rd_wait_io = (read_state == RD_STATE_WAIT_IO);
reg rd_io_ack = 1'b0 /* synthesis noprune */;
always @(negedge io_ack or negedge rd_wait_io) begin
if(!rd_wait_io) rd_io_ack <= 1'b0;
else rd_io_ack <= 1'b1;
end
wire wr_wait_io = (write_state == WR_STATE_BUSY);
reg wr_io_ack = 1'b0 /* synthesis noprune */;
always @(negedge io_ack or negedge wr_wait_io) begin
if(!wr_wait_io) wr_io_ack <= 1'b0;
else wr_io_ack <= 1'b1;
end
// ------------------------- SECTOR BUFFER -----------------------
// access to the sector buffer is multiplexed. When reading sectors
// the io controller writes into the buffer and the sd card implementation
// reads. And vice versa when writing sectors
wire reading = (read_state != 0);
wire writing = (write_state != 0);
wire reading = (read_state != RD_STATE_IDLE);
wire writing = (write_state != WR_STATE_IDLE);
// the buffer itself. Can hold one sector
reg [8:0] buffer_wptr;
......
always @(posedge buffer_read_latch)
buffer_byte <= buffer[buffer_rptr];
always @(posedge buffer_read_strobe or posedge sd_cs) begin
if(sd_cs == 1) buffer_rptr <= 9'd0;
else buffer_rptr <= buffer_rptr + 9'd1;
always @(posedge buffer_read_strobe or posedge new_cmd_rcvd) begin
if(new_cmd_rcvd == 1) buffer_rptr <= 9'd0;
else buffer_rptr <= buffer_rptr + 9'd1;
end
// ---------------- buffer write engine -----------------------
wire [7:0] buffer_din = reading?io_din:write_data;
wire buffer_din_strobe = reading?io_din_strobe:write_strobe;
always @(negedge buffer_din_strobe or posedge sd_cs) begin
if(sd_cs == 1) begin
always @(negedge buffer_din_strobe or posedge new_cmd_rcvd) begin
if(new_cmd_rcvd == 1) begin
buffer_wptr <= 9'd0;
end else begin
buffer[buffer_wptr] <= buffer_din;
......
wire [7:0] WRITE_DATA_RESPONSE = 8'h05;
// ------------------------- CSD/CID BUFFER ----------------------
assign io_conf = (csd_wptr == 0);
assign io_conf = (csd_wptr == 0); // csd_wptr still 0 -> configuration required
// the 32 bytes as sent from the io controller
reg [7:0] cid [15:0];
......
always @(posedge buffer_read_latch)
csd_byte <= csd[buffer_rptr];
// ----------------- spi transmitter --------------------
reg rd_io_ackD, wr_io_ackD;
// ----------------- spi transmitter --------------------
always@(negedge sd_sck or posedge sd_cs) begin
if(sd_cs == 1) begin
sd_sdo <= 1'b1;
read_state <= 3'd0;
// sd_sdo <= 1'b1;
// read_state <= RD_STATE_IDLE;
end else begin
core_buffer_read_strobe <= 1'b0;
// bring io ack in local clock domain
io_ackD <= io_ack;
io_ackD2 <= io_ackD;
// using rd_io_ack directly brings the read state machine into an
// non-existing state every now and then. For unknown reason
rd_io_ackD <= rd_io_ack;
// -------- catch read commmand and reset read state machine ------
if(bit_cnt == 7) begin
if(cmd_cnt == 5) begin
if(byte_cnt == 4) begin
// CMD17: READ_SINGLE_BLOCK
if(cmd == 8'h51)
read_state <= 3'd1; // start waiting for data from io controller
read_state <= RD_STATE_WAIT_IO; // start waiting for data from io controller
end
end
if(byte_cnt < 6+NCR) begin
if(byte_cnt < 5+NCR) begin
sd_sdo <= 1'b1; // reply $ff -> wait
end else begin
if(byte_cnt == 6+NCR) begin
if(byte_cnt == 5+NCR) begin
sd_sdo <= reply[~bit_cnt];
if(bit_cnt == 7) begin
// CMD9: SEND_CSD
// CMD10: SEND_CID
if((cmd == 8'h49)||(cmd == 8'h4a))
read_state <= 3'd3; // jump directly to data transmission
read_state <= RD_STATE_SEND_TOKEN; // jump directly to data transmission
end
end
else if((reply_len > 0) && (byte_cnt == 6+NCR+1))
else if((reply_len > 0) && (byte_cnt == 5+NCR+1))
sd_sdo <= reply0[~bit_cnt];
else if((reply_len > 1) && (byte_cnt == 6+NCR+2))
else if((reply_len > 1) && (byte_cnt == 5+NCR+2))
sd_sdo <= reply1[~bit_cnt];
else if((reply_len > 2) && (byte_cnt == 6+NCR+3))
else if((reply_len > 2) && (byte_cnt == 5+NCR+3))
sd_sdo <= reply2[~bit_cnt];
else if((reply_len > 3) && (byte_cnt == 6+NCR+4))
else if((reply_len > 3) && (byte_cnt == 5+NCR+4))
sd_sdo <= reply3[~bit_cnt];
else
sd_sdo <= 1'b1;
// falling edge of io_ack signals end of incoming data stream
if((read_state == 3'd1) && !io_ackD && io_ackD2)
read_state <= 3'd2;
if((read_state == RD_STATE_WAIT_IO) && rd_io_ackD)
read_state <= RD_STATE_WAIT_START;
// wait for begin of new byte
if((read_state == 3'd2) && (bit_cnt == 7))
read_state <= 3'd3;
else if((read_state == RD_STATE_WAIT_START) && (bit_cnt == 7))
read_state <= RD_STATE_SEND_TOKEN;
// send data token
if(read_state == 3'd3) begin
else if(read_state == RD_STATE_SEND_TOKEN) begin
sd_sdo <= READ_DATA_TOKEN[~bit_cnt];
if(bit_cnt == 7)
read_state <= 3'd4; // next: send data
read_state <= RD_STATE_SEND_DATA; // next: send data
end
// send data
if(read_state == 3'd4) begin
else if(read_state == RD_STATE_SEND_DATA) begin
if(cmd == 8'h51) // CMD17: READ_SINGLE_BLOCK
sd_sdo <= buffer_byte[~bit_cnt];
else if(cmd == 8'h49) // CMD9: SEND_CSD
......
// send 512 sector data bytes?
if((cmd == 8'h51) && (buffer_rptr == 511))
read_state <= 3'd5; // next: send crc
read_state <= RD_STATE_SEND_CRC0; // next: send crc
// send 16 cid/csd data bytes?
if(((cmd == 8'h49)||(cmd == 8'h4a)) && (buffer_rptr == 15))
read_state <= 3'd0; // return to idle state
read_state <= RD_STATE_IDLE; // return to idle state
end
end
// send crc[0]
if(read_state == 3'd5) begin
else if(read_state == RD_STATE_SEND_CRC0) begin
sd_sdo <= 1'b1;
if(bit_cnt == 7)
read_state <= 3'd6; // send second crc byte
read_state <= RD_STATE_SEND_CRC1; // send second crc byte
end
// send crc[1]
if(read_state == 3'd6) begin
else if(read_state == RD_STATE_SEND_CRC1) begin
sd_sdo <= 1'b1;
if(bit_cnt == 7)
read_state <= 3'd0; // return to idle state
read_state <= RD_STATE_IDLE; // return to idle state
end
// ------------------ write support ----------------------
// send write data response
if(write_state == 3'd5)
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 == 3'd6)
if(write_state == WR_STATE_BUSY)
sd_sdo <= 1'b0;
end
end
......
// cs is active low
if(sd_cs == 1) begin
bit_cnt <= 3'd0;
byte_cnt <= 8'd0;
cmd_cnt <= 8'd0;
write_state <= 3'd0;
write_strobe <= 1'b0;
// byte_cnt <= 4'd15;
// write_state <= WR_STATE_IDLE;
// write_strobe <= 1'b0;
end else begin
new_cmd_rcvd <= 1'b0;
write_strobe <= 1'b0;
sbuf[6:0] <= { sbuf[5:0], sd_sdi };
bit_cnt <= bit_cnt + 3'd1;
if((bit_cnt == 7)&&(byte_cnt != 255)) begin
byte_cnt <= byte_cnt + 8'd1;
if(cmd_cnt == 0) begin
// first byte of valid command is 01xxxxxx
if((write_state == 3'd0) && sbuf[6:5] == 2'b01) begin
cmd_cnt <= 8'd1;
byte_cnt <= 8'd1;
end
end else if(cmd_cnt < 6)
cmd_cnt <= cmd_cnt + 8'd1;
else
// command counting stops after last command byte.
cmd_cnt <= 8'd0;
end
// using wr_io_ack directly brings the write state machine into an
// non-existing state every now and then. For unknown reason
wr_io_ackD <= wr_io_ack;
// finished reading command byte
if(bit_cnt == 7) begin
if(bit_cnt == 7) begin
// byte counter runs against 15 byte boundary
if(byte_cnt != 15)
byte_cnt <= byte_cnt + 8'd1;
// byte_cnt > 6 -> complete command received
// first byte of valid command is 01xxxxxx
if((byte_cnt > 5) && (write_state == WR_STATE_IDLE) && sbuf[6:5] == 2'b01)
byte_cnt <= 4'd0;
// don't accept new commands once a write command has been accepted
if((write_state == 3'd0) && (cmd_cnt == 0)&&(sbuf[6:5] == 2'b01)) begin
if((write_state == WR_STATE_IDLE) && (byte_cnt > 5)&&(sbuf[6:5] == 2'b01)) begin
cmd <= { sbuf, sd_sdi};
new_cmd_rcvd <= 1'b1;
// set cmd55 flag if previous command was 55
cmd55 <= (cmd == 8'h77);
end
// parse additional command bytes
if(cmd_cnt == 1) lba3 <= { sbuf, sd_sdi};
if(cmd_cnt == 2) lba2 <= { sbuf, sd_sdi};
if(cmd_cnt == 3) lba1 <= { sbuf, sd_sdi};
if(cmd_cnt == 4) lba0 <= { sbuf, sd_sdi};
if(cmd_cnt == 5) crc <= { sbuf, sd_sdi};
if(byte_cnt == 0) lba[31:24] <= { sbuf, sd_sdi};
if(byte_cnt == 1) lba[23:16] <= { sbuf, sd_sdi};
if(byte_cnt == 2) lba[15:8] <= { sbuf, sd_sdi};
if(byte_cnt == 3) lba[7:0] <= { sbuf, sd_sdi};
// last byte received, evaluate
if(byte_cnt == 4) begin
// crc is currently unused
crc <= { sbuf, sd_sdi};
// last byte received, evaluate
if(cmd_cnt == 5) begin
// default:
reply <= 8'h04; // illegal command
reply_len <= 4'd0; // no extra reply bytes
// CMD0: GO_IDLE_STATE
if(cmd == 8'h40)
reply <= 8'h01; // ok, busy
......
// CMD24: WRITE_BLOCK
else if(cmd == 8'h58) begin
reply <= 8'h00; // ok
write_state <= 3'd1; // expect data token
write_state <= WR_STATE_EXP_DTOKEN; // expect data token
end
// ACMD41: APP_SEND_OP_COND
......
// ---------- handle write -----------
// waiting for data token
if(write_state == 3'd1) begin
if(write_state == WR_STATE_EXP_DTOKEN) begin
if({ sbuf, sd_sdi} == 8'hfe )
write_state <= 3'd2;
write_state <= WR_STATE_RECV_DATA;
end
// transfer 512 bytes
if(write_state == 3'd2) begin
if(write_state == WR_STATE_RECV_DATA) begin
// push one byte into local buffer
write_strobe <= 1'b1;
write_data <= { sbuf, sd_sdi};
if(buffer_wptr == 511)
write_state <= 3'd3;
write_state <= WR_STATE_RECV_CRC0;
end
// transfer 1st crc byte
if(write_state == 3'd3)
write_state <= 3'd4;
if(write_state == WR_STATE_RECV_CRC0)
write_state <= WR_STATE_RECV_CRC1;
// transfer 2nd crc byte
if(write_state == 3'd4)
write_state <= 3'd5;
if(write_state == WR_STATE_RECV_CRC1)
write_state <= WR_STATE_SEND_DRESP;
// send data response
if(write_state == 3'd5)
write_state <= 3'd6;
if(write_state == WR_STATE_SEND_DRESP)
write_state <= WR_STATE_BUSY;
end
// wait for io controller to accept data
// this happens outside the bit_cnt == 7 test as the
// transition may happen at any time
if(write_state == 3'd6 && !io_ackD && io_ackD2)
write_state <= 3'd0;
if(write_state == WR_STATE_BUSY && wr_io_ackD)
write_state <= WR_STATE_IDLE;
end
end

Also available in: Unified diff