123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371 |
- module sdcard
- #(
- parameter [0:0] with_crc7 = 1'b1,
- parameter [6:0] crc7_poly = 7'b000_1001,
- parameter [0:0] with_crc16 = 1'b1,
- parameter [15:0] crc16_poly = 16'b0001_0000_0010_0001,
- parameter [7:0] with_irq_mask = 8'b0000_0000
- )
- (
- input rst_n,
- input clk,
- output sd_cs_n,
- output sd_di,
- output sd_sclk,
- input sd_do,
- input sd_cd_n,
- input sd_irq_n,
- input [31:0] wdata,
- output reg [31:0] rdata,
- input valid,
- input [3:0] wstrb,
- input [4:0] addr,
- output wait_n,
- output irq
- );
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- reg [31:0] sd_shr_out;
- reg [31:0] sd_shr_in;
- reg [31:0] sd_shr_in_q;
- reg [4:0] sd_out_ctr;
- reg sd_active;
- reg sd_active_neg;
- reg sd_crcstb;
- reg sd_cs_reg;
- wire sd_data_out = sd_shr_out[31];
- reg sd_clk_out;
-
- assign sd_di = ~sd_cd_n ? sd_data_out : 1'bz;
- assign sd_sclk = ~sd_cd_n ? sd_clk_out : 1'bz;
- assign sd_cs_n = ~sd_cd_n ? ~sd_cs_reg : 1'bz;
-
-
-
-
-
-
-
-
-
-
-
- wire valid_blocking = valid & (addr[4:2] != 3'b000);
- wire sd_cmd = valid_blocking & ~sd_active;
-
- reg sd_cmd_ok;
- always @(negedge rst_n or posedge clk)
- if (~rst_n)
- sd_cmd_ok <= 1'b0;
- else
- sd_cmd_ok <= valid_blocking & (~sd_active | sd_cmd_ok);
-
- assign wait_n = 1'b1;
-
- wire sd_cmd_nonblock = valid & (addr[4:2] == 3'b000);
-
- reg [6:0] sd_clk_div;
- reg [6:0] sd_clk_ctr;
- reg sd_clk_stb;
- reg sd_clk_pol;
- wire sd_clk_pos;
- wire sd_clk_neg;
- always @(posedge clk)
- begin
- if (|sd_clk_ctr)
- begin
- sd_clk_stb <= 1'b0;
- sd_clk_ctr <= sd_clk_ctr - 1'b1;
- end
- else
- begin
- sd_clk_stb <= 1'b1;
- sd_clk_pol <= ~sd_clk_pol;
- sd_clk_ctr <= sd_clk_div;
- end
- end
-
- assign sd_clk_pos = sd_active & sd_clk_stb & sd_clk_pol;
- assign sd_clk_neg = sd_active_neg & sd_clk_stb & ~sd_clk_pol;
- always @(negedge rst_n or posedge clk)
- if (~rst_n)
- sd_clk_out <= 1'b0;
- else
- sd_clk_out <= (sd_clk_out | sd_clk_pos) & ~sd_clk_neg;
-
- reg [7:0] irq_status;
- always @(posedge clk)
- begin
- irq_status <= with_irq_mask &
- {
- 5'b0,
- ~sd_irq_n,
- ~sd_cd_n,
- ~sd_active
- };
- end
- reg [7:0] irq_en;
- assign irq = |(irq_status & irq_en & with_irq_mask);
-
-
-
- reg [1:0] clear_crc;
- always @(negedge rst_n or posedge clk)
- if (~rst_n)
- begin
- sd_shr_out <= 32'hffff_ffff;
- sd_cs_reg <= 1'b0;
- sd_clk_div <= 7'h7f;
- sd_active <= 1'b0;
- sd_active_neg <= 1'b0;
- sd_out_ctr <= 5'h0;
- sd_crcstb <= 1'b0;
- sd_shr_in <= 32'hffff_ffff;
- sd_shr_in_q <= 32'hffff_ffff;
- clear_crc <= 2'b11;
- irq_en <= 8'b0;
- end
- else
- begin
- if (sd_clk_pos)
- begin
- sd_shr_in <= {sd_shr_in[30:0], sd_do};
- sd_out_ctr <= sd_out_ctr + 1'b1;
- sd_active_neg <= 1'b1;
- end
- if (sd_clk_neg)
- begin
- sd_shr_out <= {sd_shr_out[30:0], 1'b1};
- sd_active <= |sd_out_ctr;
- sd_active_neg <= |sd_out_ctr;
- if (~|sd_out_ctr)
- sd_shr_in_q <= sd_shr_in;
- end
- clear_crc <= 2'b00;
- sd_crcstb <= sd_clk_pos;
- if (sd_cmd_nonblock)
- casez(addr[1:0])
- 2'b00: begin
- if (wstrb[0]) {sd_cs_reg, sd_clk_div} <= wdata[7:0];
- if (wstrb[1]) irq_en <= wdata[15:8] & with_irq_mask;
- if (wstrb[2]) clear_crc <= wdata[23:22];
- end
- default: begin
-
- end
- endcase
- if (sd_cmd)
- begin
- if (addr[4:3] == 2'b11)
- clear_crc <= {|wstrb, ~|wstrb};
- casez (addr)
- 5'b?10??: begin
-
- if (wstrb[3]) sd_shr_out[ 7: 0] <= wdata[31:24];
- if (wstrb[2]) sd_shr_out[15: 8] <= wdata[23:16];
- if (wstrb[1]) sd_shr_out[23:16] <= wdata[15: 8];
- if (wstrb[0]) sd_shr_out[31:24] <= wdata[ 7: 0];
- end
- 5'b?11??: begin
-
- if (wstrb[3]) sd_shr_out[31:24] <= wdata[31:24];
- if (wstrb[2]) sd_shr_out[23:16] <= wdata[23:16];
- if (wstrb[1]) sd_shr_out[15: 8] <= wdata[15: 8];
- if (wstrb[0]) sd_shr_out[ 7: 0] <= wdata[ 7: 0];
- end
- default: begin
-
- end
- endcase
-
-
- if (addr[3])
- case (addr[1:0])
- 2'b01: begin
-
- sd_active <= 1'b1;
- sd_out_ctr <= 5'b11_000;
- end
- 2'b10: begin
-
- sd_active <= 1'b1;
- sd_out_ctr <= 5'b10_000;
- end
- 2'b11: begin
-
- sd_active <= 1'b1;
- sd_out_ctr <= 5'b00_000;
- end
- default: begin
-
- end
- endcase
- end
- end
-
-
-
-
-
- wire [1:0] sd_crcbit = { sd_data_out, sd_shr_in[0] };
- reg [6:0] sd_crc7 [0:1];
- reg [15:0] sd_crc16[0:1];
- always @(negedge rst_n or posedge clk)
- if (~rst_n)
- for (int i = 0; i < 2; i = i+1)
- begin
- sd_crc7[i] <= 7'hxx;
- sd_crc16[i] <= 16'hxxxx;
- end
- else
- for (int i = 0; i < 2; i = i+1)
- begin
- if (clear_crc[i])
- begin
- sd_crc7[i] <= 7'h00;
- sd_crc16[i] <= 16'h0000;
- end
- else if (sd_crcstb)
- begin
- if (with_crc7)
- sd_crc7[i] <= { sd_crc7[i][5:0], 1'b0 }
- ^ ({7{sd_crcbit[i] ^ sd_crc7[i][6]}}
- & crc7_poly);
- if (with_crc16)
- sd_crc16[i] <= { sd_crc16[i][14:0], 1'b0 }
- ^ ({16{sd_crcbit[i] ^ sd_crc16[i][15]}}
- & crc16_poly);
- end
- end
-
- always_comb
- begin
- casez (addr)
- 5'b0_0000: begin
- rdata[31:16] = { irq_status, 7'b0, sd_active };
- rdata[15: 0] = { irq_en, sd_cs_reg, sd_clk_div };
- end
- 5'b0_0100: begin
- rdata[31:16] = with_crc16 ? sd_crc16[0] : 16'b0;
- rdata[15: 8] = 8'b0;
- rdata[ 7: 0] = with_crc7 ? { sd_crc7[0], 1'b1 } : 8'b0;
- end
- 5'b0_0101: begin
- rdata[31:16] = with_crc16 ? sd_crc16[1] : 16'b0;
- rdata[15: 8] = 8'b0;
- rdata[ 7: 0] = with_crc7 ? { sd_crc7[1], 1'b1 } : 8'b0;
- end
- 5'b?_10??: begin
- rdata = { sd_shr_in_q[7:0], sd_shr_in_q[15:8],
- sd_shr_in_q[23:16], sd_shr_in_q[31:24] };
- end
- 5'b?_11??: begin
- rdata = sd_shr_in_q;
- end
- default: begin
- rdata = 32'hxxxx_xxxx;
- end
- endcase
- end
- endmodule
|