Line 38... |
Line 38... |
`define SDSPI_CMD_ADDRESS 2'h0
|
`define SDSPI_CMD_ADDRESS 2'h0
|
`define SDSPI_DAT_ADDRESS 2'h1
|
`define SDSPI_DAT_ADDRESS 2'h1
|
`define SDSPI_FIFO_A_ADDR 2'h2
|
`define SDSPI_FIFO_A_ADDR 2'h2
|
`define SDSPI_FIFO_B_ADDR 2'h3
|
`define SDSPI_FIFO_B_ADDR 2'h3
|
//
|
//
|
|
// `define SDSPI_CMD_ID 3'h0
|
|
// `define SDSPI_CMD_A1 3'h1
|
|
// `define SDSPI_CMD_A2 3'h2
|
|
// `define SDSPI_CMD_A3 3'h3
|
|
// `define SDSPI_CMD_A4 3'h4
|
|
// `define SDSPI_CMD_CRC 3'h5
|
|
// `define SDSPI_CMD_FIFO 3'h6
|
|
// `define SDSPI_CMD_WAIT 3'h7
|
|
//
|
`define SDSPI_EXPECT_R1 2'b00
|
`define SDSPI_EXPECT_R1 2'b00
|
`define SDSPI_EXPECT_R1B 2'b01
|
`define SDSPI_EXPECT_R1B 2'b01
|
`define SDSPI_EXPECT_R3 2'b10
|
`define SDSPI_EXPECT_R3 2'b10
|
//
|
//
|
`define SDSPI_RSP_NONE 3'h0
|
`define SDSPI_RSP_NONE 3'h0 // No response yet from device
|
`define SDSPI_RSP_BSYWAIT 3'h1
|
`define SDSPI_RSP_BSYWAIT 3'h1 // R1b, wait for device to send nonzero
|
`define SDSPI_RSP_GETWORD 3'h2
|
`define SDSPI_RSP_GETWORD 3'h2 // Get 32-bit data word from device
|
`define SDSPI_RSP_GETTOKEN 3'h4
|
`define SDSPI_RSP_GETTOKEN 3'h4 // Write to device, read from FIFO, wait for completion token
|
`define SDSPI_RSP_READ 3'h5 // Read from device
|
`define SDSPI_RSP_WAIT_WHILE_BUSY 3'h5 // Read from device
|
`define SDSPI_RSP_RDCOMPLETE 3'h6
|
`define SDSPI_RSP_RDCOMPLETE 3'h6
|
`define SDSPI_RSP_WRITING 3'h7 // Write to the device
|
`define SDSPI_RSP_WRITING 3'h7 // Read from device, write into FIFO
|
//
|
//
|
module sdspi(i_clk,
|
module sdspi(i_clk,
|
// Wishbone interface
|
// Wishbone interface
|
i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data,
|
i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data,
|
o_wb_ack, o_wb_stall, o_wb_data,
|
o_wb_ack, o_wb_stall, o_wb_data,
|
Line 118... |
Line 127... |
// Current status, beyond state
|
// Current status, beyond state
|
reg r_have_resp, r_use_fifo, r_fifo_wr,
|
reg r_have_resp, r_use_fifo, r_fifo_wr,
|
ll_fifo_rd_complete, ll_fifo_wr_complete,
|
ll_fifo_rd_complete, ll_fifo_wr_complete,
|
r_fifo_id,
|
r_fifo_id,
|
ll_fifo_wr, ll_fifo_rd,
|
ll_fifo_wr, ll_fifo_rd,
|
r_have_start_token, r_have_data_token;
|
r_have_data_response_token,
|
|
r_have_start_token;
|
reg [7:0] fifo_byte;
|
reg [7:0] fifo_byte;
|
reg [7:0] r_last_r_one;
|
reg [7:0] r_last_r_one;
|
//
|
//
|
reg [31:0] r_data_reg;
|
reg [31:0] r_data_reg;
|
reg [1:0] r_data_fil, r_cmd_resp;
|
reg [1:0] r_data_fil, r_cmd_resp;
|
Line 160... |
Line 170... |
//
|
//
|
reg [3:0] r_lgblklen;
|
reg [3:0] r_lgblklen;
|
wire [3:0] max_lgblklen;
|
wire [3:0] max_lgblklen;
|
assign max_lgblklen = LGFIFOLN;
|
assign max_lgblklen = LGFIFOLN;
|
//
|
//
|
reg [23:0] r_watchdog;
|
reg [25:0] r_watchdog;
|
reg r_watchdog_err;
|
reg r_watchdog_err;
|
reg pre_cmd_state;
|
reg pre_cmd_state;
|
reg ready_to_leave_fifo_read_state;
|
|
|
|
initial r_cmd_busy = 1'b0;
|
initial r_cmd_busy = 1'b0;
|
initial r_data_reg = 32'h00;
|
initial r_data_reg = 32'h00;
|
initial r_last_r_one = 8'hff;
|
initial r_last_r_one = 8'hff;
|
initial ll_cmd_stb = 1'b0;
|
initial ll_cmd_stb = 1'b0;
|
initial ll_fifo_rd = 1'b0;
|
initial ll_fifo_rd = 1'b0;
|
initial ll_fifo_wr = 1'b0;
|
initial ll_fifo_wr = 1'b0;
|
initial r_have_data_token = 1'b0;
|
|
initial r_rsp_state = 3'h0;
|
initial r_rsp_state = 3'h0;
|
initial r_cmd_state = 3'h0;
|
initial r_cmd_state = 3'h0;
|
initial r_use_fifo = 1'b0;
|
initial r_use_fifo = 1'b0;
|
initial r_data_fil = 2'b00;
|
initial r_data_fil = 2'b00;
|
initial r_lgblklen = LGFIFOLN;
|
initial r_lgblklen = LGFIFOLN;
|
Line 185... |
Line 193... |
if (~ll_cmd_stb)
|
if (~ll_cmd_stb)
|
begin
|
begin
|
r_have_resp <= 1'b0;
|
r_have_resp <= 1'b0;
|
ll_fifo_wr <= 1'b0;
|
ll_fifo_wr <= 1'b0;
|
ll_fifo_rd <= 1'b0;
|
ll_fifo_rd <= 1'b0;
|
r_have_data_token <= 1'b0;
|
|
// r_rsp_state <= 3'h0;
|
// r_rsp_state <= 3'h0;
|
r_cmd_state <= 3'h0;
|
r_cmd_state <= 3'h0;
|
r_use_fifo <= 1'b0;
|
r_use_fifo <= 1'b0;
|
r_data_fil <= 2'b00;
|
r_data_fil <= 2'b00;
|
r_cmd_resp <= `SDSPI_EXPECT_R1;
|
r_cmd_resp <= `SDSPI_EXPECT_R1;
|
Line 229... |
Line 236... |
begin
|
begin
|
r_cmd_state <= r_cmd_state + 3'h1;
|
r_cmd_state <= r_cmd_state + 3'h1;
|
ll_cmd_dat <= cmd_crc;
|
ll_cmd_dat <= cmd_crc;
|
end else if (r_cmd_state == 3'h5)
|
end else if (r_cmd_state == 3'h5)
|
begin
|
begin
|
|
ll_cmd_dat <= 8'hff;
|
if (r_have_resp)
|
if (r_have_resp)
|
begin
|
begin
|
if (r_use_fifo)
|
if (r_use_fifo)
|
r_cmd_state <= r_cmd_state + 3'h1;
|
r_cmd_state <= r_cmd_state + 3'h1;
|
else
|
else
|
r_cmd_state <= r_cmd_state + 3'h2;
|
r_cmd_state <= r_cmd_state + 3'h2;
|
ll_fifo_rd <= (r_use_fifo)&&(r_fifo_wr);
|
ll_fifo_rd <= (r_use_fifo)&&(r_fifo_wr);
|
|
if ((r_use_fifo)&&(r_fifo_wr))
|
|
ll_cmd_dat <= 8'hfe;
|
end
|
end
|
ll_cmd_dat <= 8'hff;
|
|
end else if (r_cmd_state == 3'h6)
|
end else if (r_cmd_state == 3'h6)
|
begin
|
begin
|
ll_cmd_dat <= 8'hff;
|
ll_cmd_dat <= 8'hff;
|
if (ready_to_leave_fifo_read_state)
|
if (ll_fifo_rd_complete)
|
begin // If we've finished reading from the
|
begin // If we've finished reading from the
|
// FIFO, then move on
|
// FIFO, then move on
|
r_cmd_state <= r_cmd_state + 3'h1;
|
r_cmd_state <= r_cmd_state + 3'h1;
|
ll_fifo_rd <= 1'b0;
|
ll_fifo_rd <= 1'b0;
|
end else if (ll_fifo_rd)
|
end else if (ll_fifo_rd)
|
Line 292... |
Line 301... |
if (r_data_fil == 2'b11)
|
if (r_data_fil == 2'b11)
|
begin
|
begin
|
ll_cmd_stb <= (r_use_fifo);
|
ll_cmd_stb <= (r_use_fifo);
|
// r_rsp_state <= 3'h3;
|
// r_rsp_state <= 3'h3;
|
end
|
end
|
end else if (r_rsp_state == `SDSPI_RSP_READ)
|
end else if (r_rsp_state == `SDSPI_RSP_WAIT_WHILE_BUSY)
|
begin // Wait while device is busy writing
|
begin // Wait while device is busy writing
|
if (nonzero_out)
|
// if (nonzero_out)
|
begin
|
// begin
|
r_have_data_token <= 1'b1;
|
// r_data_reg[31:8] <= 24'h00;
|
r_data_reg[31:8] <= 24'h00;
|
// r_data_reg[7:0] <= ll_out_dat;
|
r_data_reg[7:0] <= ll_out_dat;
|
// // r_rsp_state <= 3'h6;
|
// r_rsp_state <= 3'h6;
|
// end
|
end
|
;
|
end else if (r_rsp_state == `SDSPI_RSP_RDCOMPLETE)
|
end else if (r_rsp_state == `SDSPI_RSP_RDCOMPLETE)
|
begin // Block write command has completed
|
begin // Block write command has completed
|
ll_cmd_stb <= 1'b0;
|
ll_cmd_stb <= 1'b0;
|
end else if (r_rsp_state == `SDSPI_RSP_WRITING)
|
end else if (r_rsp_state == `SDSPI_RSP_WRITING)
|
begin // We are reading from the device into
|
begin // We are reading from the device into
|
Line 373... |
Line 382... |
end
|
end
|
|
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
pre_cmd_state <= (ll_cmd_stb)&&(ll_idle);
|
pre_cmd_state <= (ll_cmd_stb)&&(ll_idle);
|
|
|
|
reg ready_for_response_token;
|
|
always @(posedge i_clk)
|
|
if (~r_cmd_busy)
|
|
ready_for_response_token <= 1'b0;
|
|
else if (ll_fifo_rd)
|
|
ready_for_response_token <= 1'b1;
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
ready_to_leave_fifo_read_state <= (ll_fifo_rd)&&(ll_fifo_rd_complete)&&(r_have_data_token);
|
if (~r_cmd_busy)
|
|
r_have_data_response_token <= 1'b0;
|
|
else if ((ll_out_stb)&&(ready_for_response_token)&&(~ll_out_dat[4]))
|
|
r_have_data_response_token <= 1'b1;
|
|
|
reg [2:0] second_rsp_state;
|
reg [2:0] second_rsp_state;
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if((r_cmd_resp == `SDSPI_EXPECT_R1)&&(r_use_fifo)&&(r_fifo_wr))
|
if((r_cmd_resp == `SDSPI_EXPECT_R1)&&(r_use_fifo)&&(r_fifo_wr))
|
second_rsp_state <= `SDSPI_RSP_GETTOKEN;
|
second_rsp_state <= `SDSPI_RSP_GETTOKEN;
|
Line 415... |
Line 433... |
begin // Have R1, waiting on all of R2/R3/R7
|
begin // Have R1, waiting on all of R2/R3/R7
|
if (r_data_fil == 2'b11)
|
if (r_data_fil == 2'b11)
|
r_rsp_state <= `SDSPI_RSP_RDCOMPLETE;
|
r_rsp_state <= `SDSPI_RSP_RDCOMPLETE;
|
end else if (r_rsp_state == `SDSPI_RSP_GETTOKEN)
|
end else if (r_rsp_state == `SDSPI_RSP_GETTOKEN)
|
begin // Wait on data token response
|
begin // Wait on data token response
|
if (~ll_out_dat[4])
|
if (r_have_data_response_token)
|
r_rsp_state <= `SDSPI_RSP_READ;
|
r_rsp_state <= `SDSPI_RSP_WAIT_WHILE_BUSY;
|
end else if (r_rsp_state == `SDSPI_RSP_READ)
|
end else if (r_rsp_state == `SDSPI_RSP_WAIT_WHILE_BUSY)
|
begin // Wait while device is busy writing
|
begin // Wait while device is busy writing
|
if (nonzero_out)
|
if (nonzero_out)
|
r_rsp_state <= `SDSPI_RSP_RDCOMPLETE;
|
r_rsp_state <= `SDSPI_RSP_RDCOMPLETE;
|
end
|
end
|
//else if (r_rsp_state == 3'h6)
|
//else if (r_rsp_state == 3'h6)
|
Line 517... |
Line 535... |
fifo_b_mem[{ fifo_wb_addr, 2'b10 }],
|
fifo_b_mem[{ fifo_wb_addr, 2'b10 }],
|
fifo_b_mem[{ fifo_wb_addr, 2'b11 }] };
|
fifo_b_mem[{ fifo_wb_addr, 2'b11 }] };
|
end
|
end
|
|
|
// Okay, now ... writing our FIFO ...
|
// Okay, now ... writing our FIFO ...
|
reg pre_fifo_addr_inc;
|
reg pre_fifo_addr_inc_rd;
|
initial pre_fifo_addr_inc = 1'b0;
|
reg pre_fifo_addr_inc_wr;
|
|
initial pre_fifo_addr_inc_rd = 1'b0;
|
|
initial pre_fifo_addr_inc_wr = 1'b0;
|
|
always @(posedge i_clk)
|
|
pre_fifo_addr_inc_wr <= ((ll_fifo_wr)&&(ll_out_stb)&&(r_have_start_token));
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
pre_fifo_addr_inc <=
|
pre_fifo_addr_inc_rd <= ((ll_fifo_rd)&&(ll_cmd_stb)&&(ll_idle));//&&(ll_fifo_pkt_state[2:0]!=3'b000));
|
((ll_fifo_wr)&&(ll_out_stb)&&(r_have_start_token))
|
|
||((ll_fifo_rd)&&(ll_cmd_stb)&&(ll_idle));
|
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
begin
|
begin
|
if ((write_stb)&&(i_wb_addr == `SDSPI_CMD_ADDRESS)&&(i_wb_data[11]))
|
// if ((write_stb)&&(i_wb_addr == `SDSPI_CMD_ADDRESS)&&(i_wb_data[11]))
|
|
// ll_fifo_addr <= {(LGFIFOLN+2){1'b0}};
|
|
if (~r_cmd_busy)
|
ll_fifo_addr <= {(LGFIFOLN+2){1'b0}};
|
ll_fifo_addr <= {(LGFIFOLN+2){1'b0}};
|
else if (pre_fifo_addr_inc)
|
else if ((pre_fifo_addr_inc_wr)||(pre_fifo_addr_inc_rd))
|
ll_fifo_addr <= ll_fifo_addr + 1;
|
ll_fifo_addr <= ll_fifo_addr + 1;
|
end
|
end
|
|
|
// Look for that start token
|
// Look for that start token
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
Line 626... |
Line 648... |
always @(posedge i_clk)
|
always @(posedge i_clk)
|
begin
|
begin
|
fifo_rd_crc_stb <= 1'b0;
|
fifo_rd_crc_stb <= 1'b0;
|
if (r_cmd_busy)
|
if (r_cmd_busy)
|
begin
|
begin
|
if (ll_fifo_pkt_state[2:1] == 2'b00)
|
if (ll_fifo_pkt_state[2:0] == 3'b000)
|
begin
|
begin
|
if((ll_fifo_rd)&&(ll_cmd_stb)&&(ll_idle))
|
if((ll_fifo_rd)&&(ll_cmd_stb)&&(ll_idle))
|
begin
|
begin
|
ll_fifo_pkt_state <= 3'b001;
|
ll_fifo_pkt_state <= ll_fifo_pkt_state + 3'b001;
|
|
end
|
|
end else if (ll_fifo_pkt_state[2:0] == 3'b001)
|
|
begin
|
|
if((ll_fifo_rd)&&(ll_cmd_stb)&&(ll_idle))
|
|
begin
|
|
ll_fifo_pkt_state <= ll_fifo_pkt_state + 3'b001;
|
fifo_byte <= (r_fifo_id)
|
fifo_byte <= (r_fifo_id)
|
? fifo_b_byte : fifo_a_byte;
|
? fifo_b_byte : fifo_a_byte;
|
fifo_rd_crc_stb <= (ll_fifo_pkt_state[0]);
|
fifo_rd_crc_stb <= 1'b1;
|
end
|
end
|
if (ll_fifo_addr == w_blklimit)
|
end else if (ll_fifo_pkt_state[2:0] == 3'b010)
|
ll_fifo_pkt_state <= 3'b010;
|
begin
|
end else if (ll_fifo_pkt_state == 3'b010)
|
if((ll_fifo_rd)&&(ll_cmd_stb)&&(ll_idle))
|
|
begin
|
|
fifo_byte <= (r_fifo_id)
|
|
? fifo_b_byte : fifo_a_byte;
|
|
fifo_rd_crc_stb <= 1'b1;
|
|
end
|
|
if (ll_fifo_addr == 0)
|
|
ll_fifo_pkt_state <= 3'b011;
|
|
end else if (ll_fifo_pkt_state == 3'b011)
|
begin // 1st CRC byte
|
begin // 1st CRC byte
|
if((ll_fifo_rd)&&(ll_cmd_stb)&&(ll_idle))
|
if((ll_fifo_rd)&&(ll_cmd_stb)&&(ll_idle))
|
begin
|
begin
|
fifo_byte <= fifo_rd_crc_reg[15:8];
|
fifo_byte <= fifo_rd_crc_reg[15:8];
|
ll_fifo_pkt_state <= 3'b011;
|
ll_fifo_pkt_state <= 3'b100;
|
end
|
end
|
end else if (ll_fifo_pkt_state == 3'b011)
|
end else if (ll_fifo_pkt_state == 3'b100)
|
begin // 2nd CRC byte
|
begin // 2nd CRC byte
|
if((ll_fifo_rd)&&(ll_cmd_stb)&&(ll_idle))
|
if((ll_fifo_rd)&&(ll_cmd_stb)&&(ll_idle))
|
begin
|
begin
|
fifo_byte <= fifo_rd_crc_reg[7:0];
|
fifo_byte <= fifo_rd_crc_reg[7:0];
|
ll_fifo_pkt_state <= 3'b100;
|
ll_fifo_pkt_state <= 3'b101;
|
end
|
end
|
end else if((ll_fifo_rd)&&(ll_cmd_stb)&&(ll_idle))
|
end else if((ll_fifo_rd)&&(ll_cmd_stb)&&(ll_idle))
|
|
begin
|
// Idle the channel
|
// Idle the channel
|
|
ll_fifo_rd_complete <= 1'b1;
|
fifo_byte <= 8'hff;
|
fifo_byte <= 8'hff;
|
|
end
|
end else if ((write_stb)&&(i_wb_addr == `SDSPI_CMD_ADDRESS))
|
end else if ((write_stb)&&(i_wb_addr == `SDSPI_CMD_ADDRESS))
|
begin
|
begin
|
ll_fifo_pkt_state <= 3'h0;
|
ll_fifo_pkt_state <= 3'h0;
|
fifo_byte <= 8'hfe; // Start packet token
|
|
ll_fifo_rd_complete <= 1'b0;
|
ll_fifo_rd_complete <= 1'b0;
|
|
fifo_byte <= (i_wb_data[12]) ? fifo_b_byte : fifo_a_byte;
|
|
fifo_rd_crc_stb <= 1'b1;
|
end else begin // Packet state is IDLE (clear the CRC registers)
|
end else begin // Packet state is IDLE (clear the CRC registers)
|
ll_fifo_pkt_state <= 3'b111;
|
ll_fifo_pkt_state <= 3'b111;
|
ll_fifo_rd_complete <= 1'b1;
|
ll_fifo_rd_complete <= 1'b1;
|
end
|
end
|
end
|
end
|
Line 686... |
Line 726... |
end
|
end
|
end
|
end
|
|
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
begin
|
begin
|
if (ll_fifo_pkt_state[2])
|
if (~r_cmd_busy)
|
fifo_rd_crc_reg <= 16'h00;
|
|
else if (ll_fifo_pkt_state == 3'b001)
|
|
begin
|
begin
|
if (fifo_rd_crc_stb)
|
fifo_rd_crc_reg <= 16'h00;
|
|
fifo_rd_crc_count <= 4'h0;
|
|
end else if (fifo_rd_crc_stb)
|
begin
|
begin
|
fifo_rd_crc_reg[15:8] <=fifo_rd_crc_reg[15:8]^fifo_byte;
|
fifo_rd_crc_reg[15:8] <=fifo_rd_crc_reg[15:8]^fifo_byte;
|
fifo_rd_crc_count <= 4'h8;
|
fifo_rd_crc_count <= 4'h8;
|
end else if (|fifo_rd_crc_count)
|
end else if (|fifo_rd_crc_count)
|
begin
|
begin
|
Line 704... |
Line 744... |
^ 16'h1021;
|
^ 16'h1021;
|
else
|
else
|
fifo_rd_crc_reg <= { fifo_rd_crc_reg[14:0], 1'b0 };
|
fifo_rd_crc_reg <= { fifo_rd_crc_reg[14:0], 1'b0 };
|
end
|
end
|
end
|
end
|
end
|
|
|
|
//
|
//
|
// Calculate a CRC for the command section of our output
|
// Calculate a CRC for the command section of our output
|
//
|
//
|
initial r_cmd_crc_ff = 1'b0;
|
initial r_cmd_crc_ff = 1'b0;
|
Line 740... |
Line 779... |
// Some watchdog logic for us. This way, if we are waiting for the
|
// Some watchdog logic for us. This way, if we are waiting for the
|
// card to respond, and something goes wrong, we can timeout the
|
// card to respond, and something goes wrong, we can timeout the
|
// transaction and ... figure out what to do about it later. At least
|
// transaction and ... figure out what to do about it later. At least
|
// we'll have an error indication.
|
// we'll have an error indication.
|
//
|
//
|
initial r_watchdog = 24'hfffff;
|
initial r_watchdog = 26'h3ffffff;
|
initial r_watchdog_err = 1'b0;
|
initial r_watchdog_err = 1'b0;
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if (~r_cmd_busy)
|
if (~r_cmd_busy)
|
r_watchdog_err <= 1'b0;
|
r_watchdog_err <= 1'b0;
|
else if (r_watchdog == 0)
|
else if (r_watchdog == 0)
|
r_watchdog_err <= 1'b1;
|
r_watchdog_err <= 1'b1;
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if (~r_cmd_busy)
|
if (~r_cmd_busy)
|
r_watchdog <= 24'hfffff;
|
r_watchdog <= 26'h3fffff;
|
else if (|r_watchdog)
|
else if (|r_watchdog)
|
r_watchdog <= r_watchdog - 24'h1;
|
r_watchdog <= r_watchdog - 26'h1;
|
|
|
assign o_debug = { ((ll_cmd_stb)&&(ll_idle))||(ll_out_stb),
|
assign o_debug = { ((ll_cmd_stb)&&(ll_idle))||(ll_out_stb),
|
ll_cmd_stb, ll_idle, ll_out_stb, // 4'h
|
ll_cmd_stb, ll_idle, ll_out_stb, // 4'h
|
o_cs_n, o_sck, o_mosi, i_miso, // 4'h
|
o_cs_n, o_sck, o_mosi, i_miso, // 4'h
|
r_cmd_state, i_bus_grant, // 4'h
|
r_cmd_state, i_bus_grant, // 4'h
|