1 |
8 |
alfik |
/*
|
2 |
|
|
* This file is subject to the terms and conditions of the BSD License. See
|
3 |
|
|
* the file "LICENSE" in the main directory of this archive for more details.
|
4 |
|
|
*
|
5 |
|
|
* Copyright (C) 2014 Aleksander Osman
|
6 |
|
|
*/
|
7 |
|
|
|
8 |
|
|
module cmd(
|
9 |
|
|
input clk,
|
10 |
|
|
input rst_n,
|
11 |
|
|
|
12 |
|
|
//
|
13 |
|
|
input sd_clk_is_one,
|
14 |
|
|
|
15 |
|
|
//
|
16 |
|
|
input cmd_ready,
|
17 |
|
|
input [5:0] cmd_index,
|
18 |
|
|
input [31:0] cmd_arg,
|
19 |
|
|
input [7:0] cmd_resp_length,
|
20 |
|
|
input cmd_resp_has_crc7,
|
21 |
|
|
|
22 |
|
|
//
|
23 |
|
|
output reg reply_ready,
|
24 |
|
|
output reg [135:0] reply_contents,
|
25 |
|
|
output reply_error,
|
26 |
|
|
|
27 |
|
|
//
|
28 |
|
|
inout sd_cmd
|
29 |
|
|
);
|
30 |
|
|
|
31 |
|
|
//------------------------------------------------------------------------------
|
32 |
|
|
|
33 |
|
|
reg sd_cmd_enable;
|
34 |
|
|
always @(posedge clk or negedge rst_n) begin
|
35 |
|
|
if(rst_n == 1'b0) sd_cmd_enable <= 1'b0;
|
36 |
|
|
else if(sd_clk_is_one) sd_cmd_enable <= cmd_start || cmd_cnt > 6'd0;
|
37 |
|
|
end
|
38 |
|
|
|
39 |
|
|
reg sd_cmd_output;
|
40 |
|
|
always @(posedge clk or negedge rst_n) begin
|
41 |
|
|
if(rst_n == 1'b0) sd_cmd_output <= 1'b1;
|
42 |
|
|
else if(sd_clk_is_one) sd_cmd_output <= (cmd_start)? 1'b0 : (cmd_cnt <= 6'd8 && cmd_cnt >= 6'd2)? cmd_crc7[0] : cmd_value[38];
|
43 |
|
|
end
|
44 |
|
|
|
45 |
|
|
assign sd_cmd = (sd_cmd_enable)? sd_cmd_output : 1'bZ;
|
46 |
|
|
|
47 |
|
|
reg sd_cmd_input;
|
48 |
|
|
always @(posedge clk or negedge rst_n) begin
|
49 |
|
|
if(rst_n == 1'b0) sd_cmd_input <= 1'b1;
|
50 |
|
|
else if(~(sd_clk_is_one)) sd_cmd_input <= sd_cmd;
|
51 |
|
|
end
|
52 |
|
|
|
53 |
|
|
//------------------------------------------------------------------------------
|
54 |
|
|
|
55 |
|
|
reg [3:0] cmd_start_delay_cnt;
|
56 |
|
|
always @(posedge clk or negedge rst_n) begin
|
57 |
|
|
if(rst_n == 1'b0) cmd_start_delay_cnt <= 4'd0;
|
58 |
|
|
else if(reply_ready || reply_error) cmd_start_delay_cnt <= 4'd8;
|
59 |
|
|
else if(sd_clk_is_one && cmd_start_delay_cnt > 4'd0) cmd_start_delay_cnt <= cmd_start_delay_cnt - 4'd1;
|
60 |
|
|
end
|
61 |
|
|
|
62 |
|
|
reg cmd_start_waiting;
|
63 |
|
|
always @(posedge clk or negedge rst_n) begin
|
64 |
|
|
if(rst_n == 1'b0) cmd_start_waiting <= 1'b0;
|
65 |
|
|
else if(cmd_start) cmd_start_waiting <= 1'b0;
|
66 |
|
|
else if(cmd_ready && (cmd_start_delay_cnt > 4'd0 || ~(sd_clk_is_one))) cmd_start_waiting <= 1'b1;
|
67 |
|
|
end
|
68 |
|
|
|
69 |
|
|
wire cmd_start = sd_clk_is_one && (cmd_ready || cmd_start_waiting) && cmd_start_delay_cnt == 4'd0;
|
70 |
|
|
|
71 |
|
|
reg [5:0] cmd_cnt;
|
72 |
|
|
always @(posedge clk or negedge rst_n) begin
|
73 |
|
|
if(rst_n == 1'b0) cmd_cnt <= 6'd0;
|
74 |
|
|
else if(cmd_start) cmd_cnt <= 6'd47;
|
75 |
|
|
else if(sd_clk_is_one && cmd_cnt > 6'd0) cmd_cnt <= cmd_cnt - 6'd1;
|
76 |
|
|
end
|
77 |
|
|
|
78 |
|
|
reg [38:0] cmd_value;
|
79 |
|
|
always @(posedge clk or negedge rst_n) begin
|
80 |
|
|
if(rst_n == 1'b0) cmd_value <= 39'h7FFFFFFFFF;
|
81 |
|
|
else if(cmd_ready) cmd_value <= { 1'b1, cmd_index, cmd_arg };
|
82 |
|
|
else if(sd_clk_is_one && cmd_cnt > 6'd0) cmd_value <= { cmd_value[37:0], 1'b1 }; //fill with 1 important
|
83 |
|
|
end
|
84 |
|
|
|
85 |
|
|
reg [6:0] cmd_crc7;
|
86 |
|
|
always @(posedge clk or negedge rst_n) begin
|
87 |
|
|
if(rst_n == 1'b0) cmd_crc7 <= 7'd0;
|
88 |
|
|
else if(sd_clk_is_one && cmd_cnt >= 6'd9) cmd_crc7 <= { cmd_value[38] ^ cmd_crc7[0], cmd_crc7[6:5], cmd_crc7[4] ^ cmd_value[38] ^ cmd_crc7[0], cmd_crc7[3:1] };
|
89 |
|
|
else if(sd_clk_is_one) cmd_crc7 <= { 1'b0, cmd_crc7[6:1] };
|
90 |
|
|
end
|
91 |
|
|
|
92 |
|
|
//------------------------------------------------------------------------------
|
93 |
|
|
|
94 |
|
|
wire resp_active = sd_clk_is_one && resp_cnt > 8'd0 && cmd_cnt == 6'd0 && ~(cmd_start_waiting) && ((resp_awaiting && sd_cmd_input == 1'b0) || ~(resp_awaiting));
|
95 |
|
|
|
96 |
|
|
reg [7:0] resp_cnt;
|
97 |
|
|
always @(posedge clk or negedge rst_n) begin
|
98 |
|
|
if(rst_n == 1'b0) resp_cnt <= 8'd0;
|
99 |
|
|
else if(reply_error) resp_cnt <= 8'd0;
|
100 |
|
|
else if(cmd_ready) resp_cnt <= cmd_resp_length;
|
101 |
|
|
else if(resp_active) resp_cnt <= resp_cnt - 8'd1;
|
102 |
|
|
end
|
103 |
|
|
|
104 |
|
|
reg resp_has_crc7;
|
105 |
|
|
always @(posedge clk or negedge rst_n) begin
|
106 |
|
|
if(rst_n == 1'b0) resp_has_crc7 <= 1'b0;
|
107 |
|
|
else if(cmd_ready) resp_has_crc7 <= cmd_resp_has_crc7;
|
108 |
|
|
end
|
109 |
|
|
|
110 |
|
|
reg resp_awaiting;
|
111 |
|
|
always @(posedge clk or negedge rst_n) begin
|
112 |
|
|
if(rst_n == 1'b0) resp_awaiting <= 1'b0;
|
113 |
|
|
else if(reply_error) resp_awaiting <= 1'b0;
|
114 |
|
|
else if(sd_clk_is_one && cmd_cnt == 6'd1 && resp_cnt > 8'd0) resp_awaiting <= 1'b1;
|
115 |
|
|
else if(sd_clk_is_one && resp_awaiting && sd_cmd_input == 1'b0) resp_awaiting <= 1'b0;
|
116 |
|
|
end
|
117 |
|
|
|
118 |
|
|
always @(posedge clk or negedge rst_n) begin
|
119 |
|
|
if(rst_n == 1'b0) reply_contents <= 136'd0;
|
120 |
|
|
else if(resp_active) reply_contents <= { reply_contents[134:0], sd_cmd_input };
|
121 |
|
|
end
|
122 |
|
|
|
123 |
|
|
reg [6:0] resp_crc7;
|
124 |
|
|
always @(posedge clk or negedge rst_n) begin
|
125 |
|
|
if(rst_n == 1'b0) resp_crc7 <= 7'd0;
|
126 |
|
|
else if(resp_active && resp_cnt >= 8'd9 && resp_cnt <= 8'd128) resp_crc7 <= { sd_cmd_input ^ resp_crc7[0], resp_crc7[6:5], resp_crc7[4] ^ sd_cmd_input ^ resp_crc7[0], resp_crc7[3:1] };
|
127 |
|
|
else if(resp_active) resp_crc7 <= { 1'b0, resp_crc7[6:1] };
|
128 |
|
|
end
|
129 |
|
|
|
130 |
|
|
//------------------------------------------------------------------------------
|
131 |
|
|
|
132 |
|
|
reg resp_next_is_trans_bit;
|
133 |
|
|
always @(posedge clk or negedge rst_n) begin
|
134 |
|
|
if(rst_n == 1'b0) resp_next_is_trans_bit <= 1'b0;
|
135 |
|
|
else if(resp_active && resp_awaiting) resp_next_is_trans_bit <= 1'b1;
|
136 |
|
|
else if(resp_active) resp_next_is_trans_bit <= 1'b0;
|
137 |
|
|
end
|
138 |
|
|
|
139 |
|
|
wire resp_now_in_error = resp_active && (
|
140 |
|
|
(resp_next_is_trans_bit && sd_cmd_input == 1'b1) || //transmission bit is '1'
|
141 |
|
|
(resp_cnt == 8'd1 && sd_cmd_input == 1'b0) || //end bit is '0'
|
142 |
|
|
(resp_cnt <= 8'd8 && resp_cnt >= 8'd2 && resp_has_crc7 && sd_cmd_input != resp_crc7[0]) //crc7 invalid
|
143 |
|
|
);
|
144 |
|
|
|
145 |
|
|
reg resp_had_error;
|
146 |
|
|
always @(posedge clk or negedge rst_n) begin
|
147 |
|
|
if(rst_n == 1'b0) resp_had_error <= 1'b0;
|
148 |
|
|
else if(reply_error) resp_had_error <= 1'b0;
|
149 |
|
|
else if(resp_now_in_error) resp_had_error <= 1'b1;
|
150 |
|
|
end
|
151 |
|
|
|
152 |
|
|
always @(posedge clk or negedge rst_n) begin
|
153 |
|
|
if(rst_n == 1'b0) reply_ready <= 1'b0;
|
154 |
|
|
else reply_ready <= (sd_clk_is_one && cmd_cnt == 6'd1 && resp_cnt == 8'd0) || (resp_active && resp_cnt == 8'd1 && ~(resp_now_in_error || resp_had_error));
|
155 |
|
|
end
|
156 |
|
|
|
157 |
|
|
//------------------------------------------------------------------------------
|
158 |
|
|
|
159 |
|
|
wire error_start = (sd_clk_is_one && cmd_cnt == 6'd1 && resp_cnt > 8'd0) || (resp_active && resp_cnt == 8'd1 && (resp_now_in_error || resp_had_error));
|
160 |
|
|
|
161 |
|
|
reg [6:0] error_delay_cnt;
|
162 |
|
|
always @(posedge clk or negedge rst_n) begin
|
163 |
|
|
if(rst_n == 1'b0) error_delay_cnt <= 7'd0;
|
164 |
|
|
else if(sd_clk_is_one && resp_awaiting && sd_cmd_input == 1'b0) error_delay_cnt <= 7'd0;
|
165 |
|
|
else if(error_start) error_delay_cnt <= 7'd1;
|
166 |
|
|
else if(sd_clk_is_one && error_delay_cnt > 7'd0) error_delay_cnt <= error_delay_cnt + 7'd1;
|
167 |
|
|
end
|
168 |
|
|
|
169 |
|
|
assign reply_error = error_delay_cnt == 7'd127;
|
170 |
|
|
|
171 |
|
|
//------------------------------------------------------------------------------
|
172 |
|
|
|
173 |
|
|
endmodule
|