mirror of
https://github.com/WangXuan95/FPGA-SDcard-Reader.git
synced 2025-01-13 20:02:53 +08:00
659 lines
28 KiB
Verilog
659 lines
28 KiB
Verilog
|
|
//--------------------------------------------------------------------------------------------------------
|
|
// Module : sd_fake
|
|
// Type : synthesizable, IP's top
|
|
// Standard: Verilog 2001 (IEEE1364-2001)
|
|
// Function: Imitate a SDHCv2 Read-Only SD card
|
|
//--------------------------------------------------------------------------------------------------------
|
|
|
|
module sd_fake (
|
|
input wire rstn_async,
|
|
// SD-card signals, connect to a SD-host, such as a SDcard Reader
|
|
input wire sdclk,
|
|
inout sdcmd,
|
|
output wire [ 3:0] sddat,
|
|
// data read interface, connect to a RAM which contains SD-card's data.
|
|
output reg rdreq,
|
|
output reg [39:0] rdaddr,
|
|
input wire [15:0] rddata,
|
|
// show status (optional)
|
|
output wire [ 7:0] show_status_bits,
|
|
// show parsed request command on sdcmd (optional)
|
|
output reg show_sdcmd_en,
|
|
output reg [ 5:0] show_sdcmd_cmd,
|
|
output reg [31:0] show_sdcmd_arg
|
|
);
|
|
|
|
|
|
initial rdreq = 1'b0;
|
|
initial rdaddr = 40'd0;
|
|
|
|
initial show_sdcmd_en = 1'b0;
|
|
initial show_sdcmd_cmd = 6'h0;
|
|
initial show_sdcmd_arg = 0;
|
|
|
|
|
|
// generate reset sync with posedge of sdclk
|
|
reg rstn_sdclk_p = 1'b0;
|
|
reg [1:0] rstn_sdclk_p_l = 2'b0;
|
|
|
|
always @ (posedge sdclk or negedge rstn_async)
|
|
if(~rstn_async)
|
|
{rstn_sdclk_p, rstn_sdclk_p_l} <= 3'b0;
|
|
else
|
|
{rstn_sdclk_p, rstn_sdclk_p_l} <= {rstn_sdclk_p_l, 1'b1};
|
|
|
|
|
|
// generate reset sync with negedge of sdclk
|
|
reg rstn_sdclk_n = 1'b0;
|
|
reg [1:0] rstn_sdclk_n_l = 2'b0;
|
|
|
|
always @ (negedge sdclk or negedge rstn_async)
|
|
if(~rstn_async)
|
|
{rstn_sdclk_n, rstn_sdclk_n_l} <= 3'b0;
|
|
else
|
|
{rstn_sdclk_n, rstn_sdclk_n_l} <= {rstn_sdclk_n_l, 1'b1};
|
|
|
|
|
|
|
|
reg sdcmdoe = 1'b0;
|
|
reg sdcmdout = 1'b1;
|
|
reg sddatoe = 1'b0;
|
|
reg [3:0] sddatout = 4'hF;
|
|
|
|
assign sdcmd = sdcmdoe ? sdcmdout : 1'bz;
|
|
assign sddat = sddatoe ? sddatout : 4'bz;
|
|
|
|
|
|
function [6:0] CalcCrcCMD;
|
|
input [6:0] crc;
|
|
input [0:0] inbit;
|
|
begin
|
|
CalcCrcCMD = {crc[5:0],crc[6]^inbit} ^ {3'b0,crc[6]^inbit,3'b0};
|
|
end
|
|
endfunction
|
|
|
|
|
|
function [15:0] CalcCrcDAT;
|
|
input [15:0] crc;
|
|
input [ 0:0] inbit;
|
|
begin
|
|
CalcCrcDAT = {crc[14:0],crc[15]^inbit} ^ {3'b0,crc[15]^inbit,6'b0,crc[15]^inbit,5'b0};
|
|
end
|
|
endfunction
|
|
|
|
|
|
localparam BLOCK_SIZE = 512; // 512B per block
|
|
localparam [ 15:0] RCA_REG = 16'h0013;
|
|
|
|
localparam [ 31:0] OCR_REG = {1'b1,1'b1,6'b0,9'h1ff,7'b0,1'b0,7'b0}; // not busy, CCS=1(SDHC card), all voltage, not dual-voltage card
|
|
|
|
localparam [119:0] CID_REG = 120'h02544d53_41303847_14394a67_c700e4;
|
|
|
|
localparam [119:0] CSD_REG = 120'h400e0032_50590000_39b73f80_000030; // 25MHz, SD-ROM card
|
|
// 120'h400e0032_5b590000_39b77f80_0a4000; // 25MHz, Normal card
|
|
|
|
localparam [ 64:0] SCR_REG = 64'h0005_0000_00000000;
|
|
// 64'h0201_0000_00000000; // SD-ROM card, disable 4-bit bus mode
|
|
// 64'h0205_0000_00000000; // SD-ROM card, enable 4-bit bus mode
|
|
// 64'h0231_0000_00000000; // Normal card, disable 4-bit bus mode
|
|
// 64'h0235_0000_00000000; // Normal card, enable 4-bit bus mode
|
|
|
|
reg last_is_acmd = 1'b0;
|
|
|
|
|
|
localparam [1:0] WAITINGCMD = 2'd0,
|
|
LOADRESP = 2'd1,
|
|
RESPING = 2'd2;
|
|
reg [1:0] respstate = WAITINGCMD;
|
|
|
|
|
|
reg [49:0] request = 50'h3ffffffffffff;
|
|
wire [ 3:0] request_pre_st;
|
|
wire [ 5:0] request_cmd;
|
|
wire [31:0] request_arg;
|
|
wire [ 6:0] request_crc;
|
|
wire request_stop;
|
|
assign {request_pre_st, request_cmd, request_arg, request_crc, request_stop} = request;
|
|
|
|
|
|
localparam [3:0] IDLE = 4'd0,
|
|
READY = 4'd1,
|
|
IDENT = 4'd2,
|
|
STBY = 4'd3,
|
|
TRAN = 4'd4,
|
|
DATA = 4'd5,
|
|
RCV = 4'd6,
|
|
PRG = 4'd7,
|
|
DIS = 4'd8;
|
|
//typedef enum logic [3:0] {IDLE, READY, IDENT, STBY, TRAN, DATA, RCV, PRG, DIS} current_state_t;
|
|
|
|
|
|
//struct packed{
|
|
reg cardstatus_out_of_range = 0;
|
|
reg cardstatus_address_error = 0;
|
|
reg cardstatus_block_len_error = 0;
|
|
reg cardstatus_erase_seq_error = 0;
|
|
reg cardstatus_erase_param = 0;
|
|
reg cardstatus_wp_violation = 0;
|
|
reg cardstatus_card_is_locked = 0;
|
|
reg cardstatus_lock_unlock_failed = 0;
|
|
reg cardstatus_com_crc_error = 0;
|
|
reg cardstatus_illegal_command = 0;
|
|
reg cardstatus_card_ecc_failed = 0;
|
|
reg cardstatus_cc_error = 0;
|
|
reg cardstatus_error = 0;
|
|
reg [1:0] cardstatus_rsvd1 = 0; // reserved
|
|
reg cardstatus_csd_overwrite = 0;
|
|
reg cardstatus_wp_erase_skip = 0;
|
|
reg cardstatus_card_ecc_disabled = 0;
|
|
reg cardstatus_erase_reset = 0;
|
|
reg [3:0] cardstatus_current_state = 0;
|
|
reg cardstatus_ready_for_data = 0;
|
|
reg [1:0] cardstatus_rsvd2 = 0;
|
|
reg cardstatus_app_cmd = 0;
|
|
reg cardstatus_rsvd3 = 0;
|
|
reg cardstatus_ake_seq_error = 0;
|
|
reg [2:0] cardstatus_rsvd4 = 0;
|
|
|
|
wire [31:0] cardstatus = {cardstatus_out_of_range, cardstatus_address_error, cardstatus_block_len_error, cardstatus_erase_seq_error, cardstatus_erase_param, cardstatus_wp_violation, cardstatus_card_is_locked, cardstatus_lock_unlock_failed, cardstatus_com_crc_error, cardstatus_illegal_command, cardstatus_card_ecc_failed, cardstatus_cc_error, cardstatus_error, cardstatus_rsvd1, cardstatus_csd_overwrite, cardstatus_wp_erase_skip, cardstatus_card_ecc_disabled, cardstatus_erase_reset, cardstatus_current_state, cardstatus_ready_for_data, cardstatus_rsvd2, cardstatus_app_cmd, cardstatus_rsvd3, cardstatus_ake_seq_error, cardstatus_rsvd4};
|
|
wire [15:0] cardstatus_short = {cardstatus[23:22], cardstatus[19], cardstatus[12:0]}; // for R6 (CMD3)
|
|
|
|
|
|
localparam HIGHZLEN = 1;
|
|
localparam WAITLEN = HIGHZLEN + 3;
|
|
|
|
reg [ 5:0] cmd = 6'd0;
|
|
reg [119:0] arg = 120'd0;
|
|
reg [ 6:0] crc = 7'd0;
|
|
|
|
reg response_end = 1'b0;
|
|
reg valid=1'b0, dummycrc=1'b0;
|
|
reg [31:0] idx = 0;
|
|
reg [ 7:0] arglen = 0;
|
|
|
|
|
|
task response_init;
|
|
input _valid;
|
|
input _dummycrc;
|
|
input [5:0] _cmd;
|
|
input [7:0] _arglen;
|
|
input [119:0] _arg;
|
|
begin
|
|
cmd = _cmd;
|
|
arg = _arg;
|
|
crc = 0;
|
|
valid = _valid;
|
|
dummycrc = _dummycrc;
|
|
idx = 0;
|
|
arglen = _arglen;
|
|
response_end = 1'b0;
|
|
end
|
|
endtask
|
|
|
|
|
|
task response_yield;
|
|
begin
|
|
response_end = 1'b0;
|
|
if ( ~valid) begin
|
|
sdcmdoe = 0;
|
|
sdcmdout = 1;
|
|
response_end = 1'b1;
|
|
end else if(idx<HIGHZLEN) begin
|
|
sdcmdoe = 0;
|
|
sdcmdout = 1;
|
|
end else if(idx<WAITLEN) begin
|
|
sdcmdoe = 1;
|
|
sdcmdout = 1;
|
|
end else if(idx<WAITLEN+2) begin
|
|
sdcmdoe = 1;
|
|
sdcmdout = 0;
|
|
crc = CalcCrcCMD(crc, sdcmdout);
|
|
end else if(idx<WAITLEN+2+6) begin
|
|
sdcmdoe = 1;
|
|
sdcmdout = cmd[ (WAITLEN+2+6)-1-idx ];
|
|
crc = CalcCrcCMD(crc, sdcmdout);
|
|
end else if(idx<WAITLEN+2+6+arglen) begin
|
|
sdcmdoe = 1;
|
|
sdcmdout = arg[ (WAITLEN+2+6+arglen)-1-idx ];
|
|
crc = CalcCrcCMD(crc, sdcmdout);
|
|
end else if(idx<WAITLEN+2+6+arglen+7) begin
|
|
sdcmdoe = 1;
|
|
sdcmdout = dummycrc ? 1'b1 : crc[ (WAITLEN+2+6+arglen+7)-1-idx ];
|
|
end else if(idx<WAITLEN+2+6+arglen+8) begin
|
|
sdcmdoe = 1;
|
|
sdcmdout = 1;
|
|
end else begin
|
|
sdcmdoe = 0;
|
|
sdcmdout = 1;
|
|
response_end = 1'b1;
|
|
end
|
|
if(~response_end) idx = idx + 1;
|
|
end
|
|
endtask
|
|
|
|
|
|
localparam DATAWAITLEN = HIGHZLEN + 16;
|
|
localparam DATASTARTLEN = DATAWAITLEN + 1;
|
|
|
|
reg read_task=0, read_continue=0, read_scr=0, read_sdstat=0, read_cmd6stat=0;
|
|
reg [31:0] read_idx = 0;
|
|
wire [31:0] read_byte_idx = (read_idx-DATASTARTLEN);
|
|
wire [ 3:0] readbyteidx = 4'hf - read_byte_idx[3:0];
|
|
wire [ 1:0] readquadidx = 2'h3 - read_byte_idx[1:0];
|
|
reg [15:0] read_crc = 0;
|
|
reg [15:0] read_crc_wide [0:3];
|
|
wire [15:0] rddata_reversed = {rddata[7:0], rddata[15:8]};
|
|
reg widebus = 1'b0; // 0:1bit Mode 1:4bit Mode
|
|
|
|
wire [511:0] SD_STAT = { widebus,1'b0, 1'b0, 13'h0, // bus-width, no security mode
|
|
16'h0001, // SD-ROM
|
|
32'h00000000,
|
|
8'h02, // speed class: class-4
|
|
8'hff,
|
|
4'h9,
|
|
428'h0 };
|
|
|
|
reg [ 5:0] cmd6_invalid = 6'h0;
|
|
wire [511:0] CMD6_RESP = { 12'h0, (~(|cmd6_invalid)), 3'h0, // 8mA when not invalid
|
|
16'h8001, 16'h8001, 16'h8001, 16'h8001, 16'h8001, 16'h8001,
|
|
{4{cmd6_invalid[5]}}, {4{cmd6_invalid[4]}}, {4{cmd6_invalid[3]}}, {4{cmd6_invalid[2]}}, {4{cmd6_invalid[1]}}, {4{cmd6_invalid[0]}},
|
|
376'h0 };
|
|
|
|
assign show_status_bits = { response_end, widebus, cardstatus_ready_for_data, cardstatus_app_cmd, cardstatus_current_state };
|
|
|
|
|
|
|
|
integer i;
|
|
|
|
|
|
task data_response_init;
|
|
input [31:0] _read_sector_no;
|
|
input [ 0:0] _read_continue;
|
|
begin
|
|
read_task = 1;
|
|
read_continue = _read_continue;
|
|
read_scr = 0;
|
|
read_sdstat = 0;
|
|
read_cmd6stat = 0;
|
|
rdaddr <= {_read_sector_no,8'h0};
|
|
read_idx = 0;
|
|
read_crc = 0;
|
|
for(i=0;i<4;i=i+1) read_crc_wide[i] = 0;
|
|
end
|
|
endtask
|
|
|
|
|
|
task data_response_sdstat_init;
|
|
begin
|
|
read_task = 1;
|
|
read_continue = 0;
|
|
read_scr = 0;
|
|
read_sdstat = 1;
|
|
read_cmd6stat = 0;
|
|
rdaddr <= 0;
|
|
read_idx = 0;
|
|
read_crc = 0;
|
|
for(i=0;i<4;i=i+1) read_crc_wide[i] = 0;
|
|
end
|
|
endtask
|
|
|
|
|
|
task data_response_cmd6stat_init;
|
|
begin
|
|
read_task = 1;
|
|
read_continue = 0;
|
|
read_scr = 0;
|
|
read_sdstat = 0;
|
|
read_cmd6stat = 1;
|
|
rdaddr <= 0;
|
|
read_idx = 0;
|
|
read_crc = 0;
|
|
for(i=0;i<4;i=i+1) read_crc_wide[i] = 0;
|
|
end
|
|
endtask
|
|
|
|
|
|
task data_response_scr_init;
|
|
begin
|
|
read_task = 1;
|
|
read_continue = 0;
|
|
read_scr = 1;
|
|
read_sdstat = 0;
|
|
read_cmd6stat = 0;
|
|
rdaddr <= 0;
|
|
read_idx = 0;
|
|
read_crc = 0;
|
|
for(i=0;i<4;i=i+1) read_crc_wide[i] = 0;
|
|
end
|
|
endtask
|
|
|
|
|
|
task data_response_stop;
|
|
begin
|
|
read_task = 0;
|
|
read_continue = 0;
|
|
read_scr = 0;
|
|
read_sdstat = 0;
|
|
read_cmd6stat = 0;
|
|
rdaddr <= 0;
|
|
read_idx = 0;
|
|
read_crc = 0;
|
|
for(i=0;i<4;i=i+1) read_crc_wide[i] = 0;
|
|
end
|
|
endtask
|
|
|
|
|
|
task data_response_yield;
|
|
begin
|
|
rdreq <=0;
|
|
sddatoe = 1'b1;
|
|
if(~read_task) begin
|
|
sddatoe = 1'b0;
|
|
sddatout = 4'hf;
|
|
end else if(read_idx< HIGHZLEN) begin
|
|
sddatoe = 1'b0;
|
|
sddatout = 4'hf;
|
|
end else if(read_idx< DATAWAITLEN) begin
|
|
sddatout = 4'hf;
|
|
end else if(read_idx<DATASTARTLEN) begin
|
|
sddatout = 4'h0;
|
|
read_crc = 0;
|
|
for(i=0;i<4;i=i+1) read_crc_wide[i] = 0;
|
|
rdreq <= ~ ( read_scr | read_sdstat | read_cmd6stat );
|
|
end else if( read_sdstat | read_cmd6stat ) begin // the read task is reading a SD_STAT register or CMD6_RESP
|
|
if(widebus) begin
|
|
if (read_idx<DATASTARTLEN+128) begin
|
|
if(read_cmd6stat)
|
|
sddatout = CMD6_RESP[ ((DATASTARTLEN+128)-1-read_idx)*4 +: 4 ];
|
|
else
|
|
sddatout = SD_STAT[ ((DATASTARTLEN+128)-1-read_idx)*4 +: 4 ];
|
|
for(i=0;i<4;i=i+1) read_crc_wide[i] = CalcCrcDAT(read_crc_wide[i],sddatout[i]);
|
|
end else if(read_idx<DATASTARTLEN+128+16) begin
|
|
for(i=0;i<4;i=i+1) sddatout[i] = read_crc_wide[i][ (DATASTARTLEN+128+16)-1-read_idx ];
|
|
end else begin
|
|
sddatout = 4'hf;
|
|
read_task = 0;
|
|
end
|
|
end else begin
|
|
if (read_idx<DATASTARTLEN+512) begin
|
|
if(read_cmd6stat)
|
|
sddatout = {3'b111, CMD6_RESP[ (DATASTARTLEN+512)-1-read_idx ] };
|
|
else
|
|
sddatout = {3'b111, SD_STAT[ (DATASTARTLEN+512)-1-read_idx ] };
|
|
read_crc = CalcCrcDAT(read_crc,sddatout[0]);
|
|
end else if(read_idx<DATASTARTLEN+512+16) begin
|
|
sddatout = {3'b111, read_crc[ (DATASTARTLEN+512+16)-1-read_idx ]};
|
|
end else begin
|
|
sddatout = 4'hf;
|
|
read_task = 0;
|
|
end
|
|
end
|
|
end else if(read_scr) begin // the read task is reading a SCR register
|
|
if(widebus) begin
|
|
if (read_idx<DATASTARTLEN+16) begin
|
|
sddatout = SCR_REG[ ((DATASTARTLEN+16)-1-read_idx)*4 +: 4 ];
|
|
for(i=0;i<4;i=i+1) read_crc_wide[i] = CalcCrcDAT(read_crc_wide[i], sddatout[i]);
|
|
end else if(read_idx<DATASTARTLEN+16+16) begin
|
|
for(i=0;i<4;i=i+1) sddatout[i] = read_crc_wide[i][ (DATASTARTLEN+16+16)-1-read_idx ];
|
|
end else begin
|
|
sddatout = 4'hf;
|
|
read_task = 0;
|
|
end
|
|
end else begin
|
|
if (read_idx<DATASTARTLEN+64) begin
|
|
sddatout = {3'b111, SCR_REG[ (DATASTARTLEN+64)-1-read_idx ] };
|
|
read_crc = CalcCrcDAT(read_crc,sddatout[0]);
|
|
end else if(read_idx<DATASTARTLEN+64+16) begin
|
|
sddatout = {3'b111, read_crc[ (DATASTARTLEN+64+16)-1-read_idx ]};
|
|
end else begin
|
|
sddatout = 4'hf;
|
|
read_task = 0;
|
|
end
|
|
end
|
|
end else begin // the read task is reading data sector(s)
|
|
if(widebus) begin
|
|
if (read_idx<DATASTARTLEN+(BLOCK_SIZE*2)) begin
|
|
if( readquadidx==2'h3 ) begin
|
|
rdreq<=1'b0; rdaddr <= rdaddr+40'h1;
|
|
end else if( readquadidx==2'h0 ) begin
|
|
if(read_idx<DATASTARTLEN+(BLOCK_SIZE*2)-1) rdreq<=1'b1;
|
|
end
|
|
sddatout = rddata_reversed[readquadidx*4+:4];
|
|
for(i=0;i<4;i=i+1) read_crc_wide[i] = CalcCrcDAT(read_crc_wide[i],sddatout[i]);
|
|
end else if(read_idx<DATASTARTLEN+(BLOCK_SIZE*2)+16) begin
|
|
for(i=0;i<4;i=i+1) sddatout[i] = read_crc_wide[i][ (DATASTARTLEN+(BLOCK_SIZE*2)+16)-1-read_idx ];
|
|
end else begin
|
|
sddatout = 4'hf;
|
|
if(read_continue)
|
|
read_idx = HIGHZLEN+1;
|
|
else
|
|
read_task = 0;
|
|
end
|
|
end else begin
|
|
if (read_idx<DATASTARTLEN+(BLOCK_SIZE*8)) begin
|
|
if( readbyteidx==4'hf ) begin
|
|
rdreq<=1'b0; rdaddr <= rdaddr+40'h1;
|
|
end else if( readbyteidx==4'h0 ) begin
|
|
if(read_idx<DATASTARTLEN+(BLOCK_SIZE*8)-1) rdreq<=1'b1;
|
|
end
|
|
sddatout = {3'b111, rddata_reversed[readbyteidx]};
|
|
read_crc = CalcCrcDAT(read_crc,sddatout[0]);
|
|
end else if(read_idx<DATASTARTLEN+(BLOCK_SIZE*8)+16) begin
|
|
sddatout = {3'b111, read_crc[ (DATASTARTLEN+(BLOCK_SIZE*8)+16)-1-read_idx ]};
|
|
end else begin
|
|
sddatout = 4'hf;
|
|
if(read_continue)
|
|
read_idx = HIGHZLEN+1;
|
|
else
|
|
read_task = 0;
|
|
end
|
|
end
|
|
end
|
|
if(read_task) begin
|
|
read_idx = read_idx + 1;
|
|
cardstatus_current_state = DATA;
|
|
end else if(cardstatus_current_state==DATA)
|
|
cardstatus_current_state = TRAN;
|
|
end
|
|
endtask
|
|
|
|
|
|
|
|
reg [6:0] cmdcrcval = 7'd0;
|
|
|
|
always @ (*) begin
|
|
cmdcrcval = 0;
|
|
for(i=47; i>0; i=i-1) cmdcrcval = CalcCrcCMD(cmdcrcval, request[i]);
|
|
end
|
|
|
|
|
|
always @ (posedge sdclk or negedge rstn_sdclk_p)
|
|
if(~rstn_sdclk_p) begin
|
|
respstate <= WAITINGCMD;
|
|
request <= 50'h3ffffffffffff;
|
|
end else begin
|
|
case(respstate)
|
|
WAITINGCMD:
|
|
if (request_pre_st==4'b1101 && request_stop) begin
|
|
if(cmdcrcval==7'd0)
|
|
respstate <= LOADRESP;
|
|
else
|
|
request <= 50'h3ffffffffffff;
|
|
end else begin
|
|
request <= {request[48:0], sdcmd};
|
|
end
|
|
LOADRESP :
|
|
respstate <= RESPING;
|
|
default : //RESPING :
|
|
if (response_end) begin
|
|
respstate <= WAITINGCMD;
|
|
request <= 50'h3ffffffffffff;
|
|
end
|
|
endcase
|
|
end
|
|
|
|
|
|
|
|
always @ (negedge sdclk or negedge rstn_sdclk_n)
|
|
if(~rstn_sdclk_n) begin
|
|
response_init( 0, 0, 0, 0, 0 );
|
|
data_response_stop;
|
|
response_yield;
|
|
data_response_yield;
|
|
last_is_acmd <= 1'b0;
|
|
{cardstatus_out_of_range, cardstatus_address_error, cardstatus_block_len_error, cardstatus_erase_seq_error, cardstatus_erase_param, cardstatus_wp_violation, cardstatus_card_is_locked, cardstatus_lock_unlock_failed, cardstatus_com_crc_error, cardstatus_illegal_command, cardstatus_card_ecc_failed, cardstatus_cc_error, cardstatus_error, cardstatus_rsvd1, cardstatus_csd_overwrite, cardstatus_wp_erase_skip, cardstatus_card_ecc_disabled, cardstatus_erase_reset, cardstatus_current_state, cardstatus_ready_for_data, cardstatus_rsvd2, cardstatus_app_cmd, cardstatus_rsvd3, cardstatus_ake_seq_error, cardstatus_rsvd4} = 0;
|
|
widebus = 0;
|
|
cmd6_invalid <= 6'h0;
|
|
end else begin
|
|
if(respstate==LOADRESP) begin
|
|
last_is_acmd <= 1'b0;
|
|
cardstatus_app_cmd = 1'b0;
|
|
cardstatus_block_len_error = 1'b0;
|
|
case (request_cmd)
|
|
0 : begin // GO_IDLE_STATE
|
|
response_init( 0, 0 , 0 , 0 , 0 ); // there is NO RESPONSE for CMD0
|
|
data_response_stop;
|
|
response_yield;
|
|
data_response_yield;
|
|
last_is_acmd <= 1'b0;
|
|
{cardstatus_out_of_range, cardstatus_address_error, cardstatus_block_len_error, cardstatus_erase_seq_error, cardstatus_erase_param, cardstatus_wp_violation, cardstatus_card_is_locked, cardstatus_lock_unlock_failed, cardstatus_com_crc_error, cardstatus_illegal_command, cardstatus_card_ecc_failed, cardstatus_cc_error, cardstatus_error, cardstatus_rsvd1, cardstatus_csd_overwrite, cardstatus_wp_erase_skip, cardstatus_card_ecc_disabled, cardstatus_erase_reset, cardstatus_current_state, cardstatus_ready_for_data, cardstatus_rsvd2, cardstatus_app_cmd, cardstatus_rsvd3, cardstatus_ake_seq_error, cardstatus_rsvd4} = 0;
|
|
cardstatus_ready_for_data = 1'b1;
|
|
widebus = 0;
|
|
cmd6_invalid <= 6'h0;
|
|
end
|
|
2 : begin // ALL_SEND_CID
|
|
response_init( 1, 0 , 6'b000000 , 120 , CID_REG ); // R2 TODO: why cmd=000000 instead of 111111 ???
|
|
cardstatus_current_state = IDENT;
|
|
cardstatus_illegal_command = 1'b0;
|
|
end
|
|
3 : begin // SEND_RELATIVE_ADDR(send RCA)
|
|
response_init( 1, 0 , request_cmd , 32 , {RCA_REG,cardstatus_short} ); // R6
|
|
cardstatus_current_state = STBY;
|
|
cardstatus_illegal_command = 1'b0;
|
|
end
|
|
4 : if(request_arg[15:0] == 16'h0) begin // SET_DSR
|
|
response_init( 0, 0 , 0 , 0 , 0 ); // there is NO RESPONSE for CMD4
|
|
cardstatus_illegal_command = 1'b0;
|
|
end
|
|
6 : if(last_is_acmd && cardstatus_current_state==TRAN) begin // SET_BUS_WIDTH
|
|
cardstatus_app_cmd = 1'b1;
|
|
response_init( 1, 0 , request_cmd , 32 , cardstatus );
|
|
widebus = request_arg[1];
|
|
cardstatus_illegal_command = 1'b0;
|
|
end else if(cardstatus_current_state==TRAN) begin // SWITCH_FUNC
|
|
response_init( 1, 0 , request_cmd , 32 , cardstatus );
|
|
cmd6_invalid[0] <= ( request_arg[0*4+:4]!=4'h0 && request_arg[0*4+:4]!=4'hf );
|
|
cmd6_invalid[1] <= ( request_arg[1*4+:4]!=4'h0 && request_arg[1*4+:4]!=4'hf );
|
|
cmd6_invalid[2] <= ( request_arg[2*4+:4]!=4'h0 && request_arg[2*4+:4]!=4'hf );
|
|
cmd6_invalid[3] <= ( request_arg[3*4+:4]!=4'h0 && request_arg[3*4+:4]!=4'hf );
|
|
cmd6_invalid[4] <= ( request_arg[4*4+:4]!=4'h0 && request_arg[4*4+:4]!=4'hf );
|
|
cmd6_invalid[5] <= ( request_arg[5*4+:4]!=4'h0 && request_arg[5*4+:4]!=4'hf );
|
|
data_response_cmd6stat_init;
|
|
cardstatus_illegal_command = 1'b0;
|
|
end
|
|
7 : if(request_arg[31:16] == RCA_REG) begin // SELECT_CARD
|
|
response_init( 1, 0 , request_cmd , 32 , cardstatus );
|
|
cardstatus_current_state = TRAN;
|
|
cardstatus_illegal_command = 1'b0;
|
|
end else begin // DESELECT_CARD
|
|
cardstatus_current_state = STBY;
|
|
cardstatus_illegal_command = 1'b0;
|
|
end
|
|
8 : begin // SEND_IF_COND
|
|
response_init( 1, 0 , request_cmd , 32 , {24'd1,request_arg[7:0]} );
|
|
cardstatus_illegal_command = 1'b0;
|
|
end
|
|
9 : if(request_arg[31:16]==RCA_REG) begin // SEND_CSD
|
|
response_init( 1, 0 , 6'b000000 , 120 , CSD_REG );
|
|
cardstatus_illegal_command = 1'b0;
|
|
end
|
|
10 : if(request_arg[31:16]==RCA_REG) begin // SEND_CID
|
|
response_init( 1, 0 , 6'b000000 , 120 , CID_REG );
|
|
cardstatus_illegal_command = 1'b0;
|
|
end
|
|
12 : if(cardstatus_current_state==DATA) begin // STOP_TRANSMISSION
|
|
response_init( 1, 0 , request_cmd , 32 , cardstatus );
|
|
data_response_stop;
|
|
cardstatus_illegal_command = 1'b0;
|
|
end
|
|
13 : if(last_is_acmd) begin // SEND_SD_STATUS
|
|
if(cardstatus_current_state==TRAN) begin
|
|
cardstatus_app_cmd = 1'b1;
|
|
response_init( 1, 0 , request_cmd , 32 , cardstatus );
|
|
data_response_sdstat_init;
|
|
cardstatus_illegal_command = 1'b0;
|
|
end
|
|
end else if(request_arg[31:16]==RCA_REG) begin // SEND_STATUS
|
|
response_init( 1, 0 , request_cmd , 32 , cardstatus );
|
|
cardstatus_illegal_command = 1'b0;
|
|
end
|
|
15 : if(request_arg[31:16]==RCA_REG) begin // GO_INACTIVE_STATE
|
|
response_init( 0, 0 , 0 , 0 , 0 );
|
|
cardstatus_current_state = IDLE;
|
|
cardstatus_illegal_command = 1'b0;
|
|
end
|
|
16 : if(cardstatus_current_state==TRAN) begin // SET_BLOCKLEN
|
|
if(request_arg > 512) cardstatus_block_len_error = 1'b1;
|
|
response_init( 1, 0 , request_cmd , 32 , cardstatus );
|
|
cardstatus_illegal_command = 1'b0;
|
|
end
|
|
17 : if(cardstatus_current_state==TRAN) begin // READ_SINGLE_BLOCK
|
|
response_init( 1, 0 , request_cmd , 32 , cardstatus );
|
|
data_response_init(request_arg, 0);
|
|
cardstatus_illegal_command = 1'b0;
|
|
end
|
|
18 : if(cardstatus_current_state==TRAN) begin // READ_MULTIPLE_BLOCK
|
|
response_init( 1, 0 , request_cmd , 32 , cardstatus );
|
|
data_response_init(request_arg, 1);
|
|
cardstatus_illegal_command = 1'b0;
|
|
end
|
|
55 : if(request_arg[31:16]==16'd0 || request_arg[31:16]==RCA_REG) begin // APP_CMD
|
|
last_is_acmd <= 1'b1;
|
|
cardstatus_app_cmd = 1'b1;
|
|
response_init( 1, 0 , request_cmd , 32 , cardstatus );
|
|
cardstatus_illegal_command = 1'b0;
|
|
end
|
|
41 : if(last_is_acmd) begin // SD_SEND_OP_COND
|
|
cardstatus_app_cmd = 1'b1;
|
|
response_init( 1, 1 , 6'b111111 , 32 , OCR_REG );
|
|
cardstatus_illegal_command = 1'b0;
|
|
end
|
|
42 : if(last_is_acmd) begin // SET_CLR_CARD_DETECT
|
|
cardstatus_app_cmd = 1'b1;
|
|
response_init( 1, 0 , request_cmd , 32 , cardstatus );
|
|
cardstatus_illegal_command = 1'b0;
|
|
end
|
|
51 : if(last_is_acmd && cardstatus_current_state==TRAN) begin // SEND_SCR
|
|
cardstatus_app_cmd = 1'b1;
|
|
response_init( 1, 0 , request_cmd , 32 , cardstatus );
|
|
data_response_scr_init;
|
|
cardstatus_illegal_command = 1'b0;
|
|
end
|
|
default : begin // undefined CMD
|
|
response_init( 0, 0 , 0 , 0 , 0 );
|
|
cardstatus_illegal_command = 1'b1;
|
|
end
|
|
endcase
|
|
end
|
|
response_yield;
|
|
data_response_yield;
|
|
end
|
|
|
|
|
|
always @ (posedge sdclk or negedge rstn_sdclk_p)
|
|
if(~rstn_sdclk_p) begin
|
|
show_sdcmd_en <= 1'b0;
|
|
show_sdcmd_cmd <= 0;
|
|
show_sdcmd_arg <= 0;
|
|
end else begin
|
|
show_sdcmd_en <= 1'b0;
|
|
if (respstate == LOADRESP) begin
|
|
show_sdcmd_en <= 1'b1;
|
|
show_sdcmd_cmd <= request_cmd;
|
|
show_sdcmd_arg <= request_arg;
|
|
end
|
|
end
|
|
|
|
endmodule
|