OpenCores
URL https://opencores.org/ocsvn/ao486/ao486/trunk

Subversion Repositories ao486

[/] [ao486/] [trunk/] [rtl/] [soc/] [driver_sd/] [cmd.v] - Rev 8

Compare with Previous | Blame | View Log

/*
 * This file is subject to the terms and conditions of the BSD License. See
 * the file "LICENSE" in the main directory of this archive for more details.
 *
 * Copyright (C) 2014 Aleksander Osman
 */
 
module cmd(
    input               clk,
    input               rst_n,
 
    //
    input               sd_clk_is_one,
 
    //
    input               cmd_ready,
    input       [5:0]   cmd_index,
    input       [31:0]  cmd_arg,
    input       [7:0]   cmd_resp_length,
    input               cmd_resp_has_crc7,
 
    //
    output reg          reply_ready,
    output reg  [135:0] reply_contents,
    output              reply_error,
 
    //
    inout               sd_cmd
);
 
//------------------------------------------------------------------------------
 
reg sd_cmd_enable;
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)       sd_cmd_enable <= 1'b0;
    else if(sd_clk_is_one)  sd_cmd_enable <= cmd_start || cmd_cnt > 6'd0;
end
 
reg sd_cmd_output;
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)       sd_cmd_output <= 1'b1;
    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];
end
 
assign sd_cmd = (sd_cmd_enable)? sd_cmd_output : 1'bZ;
 
reg sd_cmd_input;
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)           sd_cmd_input <= 1'b1;
    else if(~(sd_clk_is_one))   sd_cmd_input <= sd_cmd;
end
 
//------------------------------------------------------------------------------
 
reg [3:0] cmd_start_delay_cnt;
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)                                     cmd_start_delay_cnt <= 4'd0;
    else if(reply_ready || reply_error)                   cmd_start_delay_cnt <= 4'd8;
    else if(sd_clk_is_one && cmd_start_delay_cnt > 4'd0)  cmd_start_delay_cnt <= cmd_start_delay_cnt - 4'd1;
end
 
reg cmd_start_waiting;
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)                                                       cmd_start_waiting <= 1'b0;
    else if(cmd_start)                                                      cmd_start_waiting <= 1'b0;
    else if(cmd_ready && (cmd_start_delay_cnt > 4'd0 || ~(sd_clk_is_one)))  cmd_start_waiting <= 1'b1;
end
 
wire cmd_start = sd_clk_is_one && (cmd_ready || cmd_start_waiting) && cmd_start_delay_cnt == 4'd0;
 
reg [5:0] cmd_cnt;
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)                           cmd_cnt <= 6'd0;
    else if(cmd_start)                          cmd_cnt <= 6'd47;
    else if(sd_clk_is_one && cmd_cnt > 6'd0)    cmd_cnt <= cmd_cnt - 6'd1;
end
 
reg [38:0] cmd_value;
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)                           cmd_value <= 39'h7FFFFFFFFF;
    else if(cmd_ready)                          cmd_value <= { 1'b1, cmd_index, cmd_arg };
    else if(sd_clk_is_one && cmd_cnt > 6'd0)    cmd_value <= { cmd_value[37:0], 1'b1 }; //fill with 1 important
end
 
reg [6:0] cmd_crc7;
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)                           cmd_crc7 <= 7'd0;
    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] };
    else if(sd_clk_is_one)                      cmd_crc7 <= { 1'b0, cmd_crc7[6:1] };
end
 
//------------------------------------------------------------------------------
 
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));
 
reg [7:0] resp_cnt;
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)       resp_cnt <= 8'd0;
    else if(reply_error)    resp_cnt <= 8'd0;
    else if(cmd_ready)      resp_cnt <= cmd_resp_length;
    else if(resp_active)    resp_cnt <= resp_cnt - 8'd1;
end
 
reg resp_has_crc7;
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)   resp_has_crc7 <= 1'b0;
    else if(cmd_ready)  resp_has_crc7 <= cmd_resp_has_crc7;
end
 
reg resp_awaiting;
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)                                               resp_awaiting <= 1'b0;
    else if(reply_error)                                            resp_awaiting <= 1'b0;
    else if(sd_clk_is_one && cmd_cnt == 6'd1 && resp_cnt > 8'd0)    resp_awaiting <= 1'b1;
    else if(sd_clk_is_one && resp_awaiting && sd_cmd_input == 1'b0) resp_awaiting <= 1'b0;
end
 
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)       reply_contents <= 136'd0;
    else if(resp_active)    reply_contents <= { reply_contents[134:0], sd_cmd_input };
end
 
reg [6:0] resp_crc7;
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)                                               resp_crc7 <= 7'd0;
    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] };
    else if(resp_active)                                            resp_crc7 <= { 1'b0, resp_crc7[6:1] };
end
 
//------------------------------------------------------------------------------
 
reg resp_next_is_trans_bit;
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)                       resp_next_is_trans_bit <= 1'b0;
    else if(resp_active && resp_awaiting)   resp_next_is_trans_bit <= 1'b1;
    else if(resp_active)                    resp_next_is_trans_bit <= 1'b0;
end
 
wire resp_now_in_error = resp_active && (
    (resp_next_is_trans_bit && sd_cmd_input == 1'b1) ||                                     //transmission bit is '1'
    (resp_cnt == 8'd1 && sd_cmd_input == 1'b0) ||                                           //end bit is '0'
    (resp_cnt <= 8'd8 && resp_cnt >= 8'd2 && resp_has_crc7 && sd_cmd_input != resp_crc7[0]) //crc7 invalid
);
 
reg resp_had_error;
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)           resp_had_error <= 1'b0;
    else if(reply_error)        resp_had_error <= 1'b0;
    else if(resp_now_in_error)  resp_had_error <= 1'b1;
end
 
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)   reply_ready <= 1'b0;
    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));
end
 
//------------------------------------------------------------------------------
 
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));
 
reg [6:0] error_delay_cnt;
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)                                               error_delay_cnt <= 7'd0;
    else if(sd_clk_is_one && resp_awaiting && sd_cmd_input == 1'b0) error_delay_cnt <= 7'd0;
    else if(error_start)                                            error_delay_cnt <= 7'd1;
    else if(sd_clk_is_one && error_delay_cnt > 7'd0)                error_delay_cnt <= error_delay_cnt + 7'd1;
end
 
assign reply_error = error_delay_cnt == 7'd127;
 
//------------------------------------------------------------------------------
 
endmodule
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.