Модуль считывает с SD карты указанный в LBA сектор. При busy=0 строб 1 такт COMMAND=1 запускает выполнение считывания данных с SD-карты (если пин RW=0).
Пины A,I,O,W должны быть подключены к блочной памяти объемом 512 байт (размер сектора).
module sd
(
input clock,
input reset_n,
output reg sclk,
output reg cs,
input miso,
output reg mosi,
input command,
input rw,
input [31:0] lba,
output reg busy,
output reg done,
output reg [ 3:0] error,
output reg [ 1:0] card,
output reg [ 9:0] a,
output [ 7:0] i,
output reg [ 7:0] o,
output reg w
);
localparam
WAIT = 0, ENSPI = 1,
INIT = 2, COMMAND = 3,
FETCH = 4, READ = 5,
WRITE = 6;
reg [ 4:0] t, r1, r2;
reg [ 7:0] c0, c1;
reg [ 1:0] c2;
reg [ 2:0] c3;
reg [11:0] c4, c5;
reg [17:0] timeout;
reg [31:0] arg;
reg [ 5:0] cmd;
reg [ 7:0] dw;
always @(posedge clock)
if (reset_n == 0) begin
t <= 0;
busy <= 0;
card <= 0;
`ifdef ICARUS
timeout <= 1;
`else
timeout <= 0;
`endif
end else begin
w <= 0;
done <= 0;
case (t)
WAIT: begin
cs <= 1;
mosi <= 0;
busy <= 0;
sclk <= 0;
{c0, c1, c2, c3, c4} <= 0;
timeout <= timeout ? timeout - 1 : 0;
if (command) begin
busy <= 1;
error <= 0;
t <= timeout ? (rw ? WRITE : READ) : ENSPI;
timeout <= 250000;
end
end
ENSPI: begin
if (c0 == (250 >> 1) - 1) begin
c0 <= 0;
c1 <= c1 + 1;
sclk <= ~sclk;
if (c1 == 2*80-1) begin {c1, sclk} <= 0; t <= INIT; end
end else c0 <= c0 + 1;
end
FETCH: case (c2)
0: begin c2 <= 1; sclk <= 0; end
1: begin c2 <= 2; mosi <= dw[7]; end
2: begin c2 <= 3; sclk <= 1; end
3: begin
c2 <= 0;
c3 <= c3 + 1;
dw <= {dw[6:0], miso};
mosi <= 0;
if (c3 == 7) begin t <= r2; sclk <= 0; end
end
endcase
COMMAND: case (c1)
0: begin c1 <= 1; cs <= 0; r2 <= COMMAND; c4 <= 4095; end
1: begin c1 <= 2; dw <= 8'hFF; t <= FETCH; end
2: begin
c1 <= dw == 8'hFF ? 3 : 1;
c4 <= c4 - 1;
if (c4 == 0) begin error <= 1; t <= WAIT; end
end
3: begin t <= FETCH; dw <= {2'b01, cmd}; c1 <= 4; end
4, 5, 6, 7: begin
t <= FETCH;
dw <= arg[31:24];
arg <= {arg[23:0], arg[31:24]};
c1 <= c1 + 1;
end
8: begin
t <= FETCH;
c1 <= 9;
c4 <= 255;
case (cmd) 0: dw <= 8'h95; 8: dw <= 8'h87; default: dw <= 8'hFF; endcase
end
9: begin c1 <= 10; dw <= 8'hFF; t <= FETCH; end
10: begin
c1 <= dw[7] ? 9 : 0;
c4 <= c4 - 1;
if (c4 == 0) begin t <= WAIT; error <= 2; end
else if (!dw[7]) t <= r1;
end
endcase
INIT: case (c0)
0: begin c0 <= 1; r1 <= INIT; t <= COMMAND; {card, cmd, arg} <= 0; end
1: begin
c0 <= 2;
cmd <= 8;
arg <= 32'h01AA;
if (dw != 8'h01) begin t <= WAIT; error <= 3; end
else begin t <= COMMAND; end
end
2: begin
r2 <= INIT;
c5 <= 4095;
dw <= 8'hFF;
if (dw[2])
begin c0 <= 7; card <= 1; end
else begin c0 <= 3; t <= FETCH; end
end
3,4,5: begin c0 <= c0 + 1; dw <= 8'hFF; t <= FETCH; end
6: begin if (dw != 8'hAA) begin error <= 4; t <= WAIT; end else c0 <= 7; card <= 2; end
7: begin c0 <= 8; t <= COMMAND; cmd <= 8'h37; arg <= 32'h0; end
8: begin c0 <= 9; t <= COMMAND; cmd <= 8'h29; arg <= {card == 2 ? 8'h40 : 8'h00, 24'h0}; end
9: begin c0 <= dw ? 7 : 10; if (c5 == 0) begin error <= 5; t <= WAIT; end else c5 <= c5 - 1; end
10: begin
if (card == 2) begin c0 <= 11; t <= COMMAND; cmd <= 8'h3A; arg <= 0; end
else begin c0 <= 0; t <= rw ? WRITE : READ; end
end
11: begin c0 <= 12; dw <= 8'hFF; t <= FETCH; r2 <= INIT; end
12: begin c0 <= 13; dw <= 8'hFF; t <= FETCH; if (dw[7:6] == 2'b11) card <= 3; end
13, 14: begin c0 <= c0 + 1; dw <= 8'hFF; t <= FETCH; end
15: begin c0 <= 0; t <= rw ? WRITE : READ; end
endcase
READ: case (c0)
0: begin c0 <= 1; r1 <= READ; t <= COMMAND; arg <= lba; cmd <= 17; end
1: begin c0 <= 2; r2 <= READ; c4 <= 4095; end
2: begin c0 <= 3; dw <= 8'hFF; t <= FETCH; end
3: begin
if (dw == 8'hFE) begin c0 <= 4; c4 <= 0; end
else if (dw != 8'hFF) begin error <= 6; t <= WAIT; end
else if (c4 == 8'h00) begin error <= 7; t <= WAIT; end
else begin c0 <= 2; c4 <= c4 - 1; end
end
4: begin c0 <= 5; dw <= 8'hFF; t <= FETCH; end
5: begin
a <= c4;
w <= 1;
o <= dw;
c0 <= 4;
c4 <= c4 + 1;
if (c4 == 511) begin done <= 1; t <= WAIT; end
end
endcase
endcase
end
endmodule