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

Subversion Repositories ao486

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /ao486/trunk/rtl/soc/driver_sd
    from Rev 7 to Rev 8
    Reverse comparison

Rev 7 → Rev 8

/avalon_master.v
0,0 → 1,85
/*
* 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 avalon_master(
input clk,
input rst_n,
//
output reg [31:0] avm_address,
input avm_waitrequest,
output reg avm_read,
input [31:0] avm_readdata,
input avm_readdatavalid,
output reg avm_write,
output reg [31:0] avm_writedata,
//
input [31:0] avalon_address_base,
//
input read_start,
input read_next,
output reg [31:0] read_data,
output reg read_done,
//
input write_start,
input write_next,
input [31:0] write_data,
output reg write_done
);
 
//------------------------------------------------------------------------------
 
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) avm_address <= 32'd0;
else if(read_start || write_start) avm_address <= avalon_address_base;
else if(read_next || write_next) avm_address <= avm_address + 32'd4;
end
 
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) avm_read <= 1'b0;
else if(read_start || read_next) avm_read <= 1'b1;
else if(~(avm_waitrequest)) avm_read <= 1'b0;
end
 
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) avm_write <= 1'b0;
else if(write_start || write_next) avm_write <= 1'b1;
else if(~(avm_waitrequest)) avm_write <= 1'b0;
end
 
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) avm_writedata <= 32'd0;
else if(write_start || write_next) avm_writedata <= write_data;
end
 
//------------------------------------------------------------------------------
 
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) read_data <= 32'd0;
else if(avm_readdatavalid) read_data <= avm_readdata;
end
 
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) read_done <= 1'b0;
else if(read_start || read_next) read_done <= 1'b0;
else read_done <= avm_readdatavalid;
end
 
//------------------------------------------------------------------------------
 
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) write_done <= 1'b0;
else if(write_start || write_next) write_done <= 1'b0;
else write_done <= ~(avm_waitrequest) && avm_write;
end
 
//------------------------------------------------------------------------------
 
endmodule
/card_init.v
0,0 → 1,217
/*
* 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 card_init(
input clk,
input rst_n,
//
input operation_init,
output operation_finished_ok,
output operation_finished_with_error,
//
output cmd_ready,
output [5:0] cmd_index,
output [31:0] cmd_arg,
output [7:0] cmd_resp_length,
output cmd_resp_has_crc7,
 
input reply_ready,
input [135:0] reply_contents,
input reply_error,
//
input current_dat0
);
 
//------------------------------------------------------------------------------
 
reg [23:0] initial_delay;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) initial_delay <= 24'd0;
else if(initial_delay[23] == 1'b0) initial_delay <= initial_delay + 24'd1;
end
 
assign operation_finished_with_error =
(reply_error && (state == S_CMD0 || state == S_CMD8 || state == S_CMD55_FOR_41 || state == S_ACMD41 || state == S_CMD2 || state == S_CMD3 || state == S_CMD7 || state == S_CMD55_FOR_6 || state == S_ACMD6)) ||
(state == S_CMD0 && reply_ready && ~(valid_cmd0)) ||
(state == S_CMD8 && reply_ready && ~(valid_cmd8)) ||
(state == S_CMD55_FOR_41 && reply_ready && ~(valid_cmd55)) ||
(state == S_ACMD41 && reply_ready && ~(valid_acmd41) && ~(valid_acmd41_but_busy)) ||
(state == S_CMD2 && reply_ready && ~(valid_cmd2)) ||
(state == S_CMD3 && reply_ready && ~(valid_cmd3)) ||
(state == S_CMD7 && reply_ready && ~(valid_cmd7) && ~(valid_cmd7_but_busy)) ||
(state == S_CMD55_FOR_6 && reply_ready && ~(valid_cmd55)) ||
(state == S_ACMD6 && reply_ready && ~(valid_acmd6));
 
assign operation_finished_ok = state == S_ACMD6 && reply_ready && valid_acmd6;
 
//------------------------------------------------------------------------------
 
wire prepare_cmd0 = state == S_IDLE && initial_delay[23] && operation_init;
wire valid_cmd0 = 1'b1; //always valid
 
wire prepare_cmd8 = state == S_CMD0 && reply_ready && valid_cmd0;
wire valid_cmd8 = reply_contents[45:40] == 6'd8 && reply_contents[19:16] == 4'b0001 && reply_contents[15:8] == 8'b11010010; //command index; accepted volage 2.7-3.6 V; check pattern echo
 
wire prepare_cmd55_for_41 = (state == S_CMD8 && reply_ready && valid_cmd8) || repeat_acmd41;
wire valid_cmd55 = reply_contents[45:40] == 6'd55 && reply_contents[39:27] == 13'd0 && reply_contents[24:21] == 4'b0; //command index; R1[31:19] no errors; R1[16:13] no errors
 
wire prepare_acmd41 = state == S_CMD55_FOR_41 && reply_ready && valid_cmd55;
wire valid_acmd41 = reply_contents[39:38] == 2'b11; //initialization complete and SDHC or SDXC;
wire valid_acmd41_but_busy = reply_contents[39] == 1'b0 && acmd41_busy_cnt < 20'hFFFFF; //initialization not complete
wire repeat_acmd41 = state == S_ACMD41 && reply_ready && valid_acmd41_but_busy;
 
wire prepare_cmd2 = state == S_ACMD41 && reply_ready && valid_acmd41;
wire valid_cmd2 = 1'b1; //always valid
 
wire prepare_cmd3 = state == S_CMD2 && reply_ready && valid_cmd2;
wire valid_cmd3 = reply_contents[45:40] == 6'd3 && reply_contents[23:21] == 3'b0; //command index; R1[23,22,19] no errors
wire [15:0] cmd3_new_rca = reply_contents[39:24];
 
wire prepare_cmd7 = state == S_CMD3 && reply_ready && valid_cmd3;
wire valid_cmd7_common = reply_contents[45:40] == 6'd7 && reply_contents[39:27] == 13'd0 && reply_contents[24:21] == 4'b0; //command index; R1[31:19] no errors; R1[16:13] no errors
wire valid_cmd7 = valid_cmd7_common && current_dat0;
wire valid_cmd7_but_busy = valid_cmd7_common && ~(current_dat0);
 
wire prepare_cmd55_for_6 = (state == S_CMD7 && reply_ready && valid_cmd7) || (state == S_WAIT_DAT0 && current_dat0);
 
wire prepare_acmd6 = state == S_CMD55_FOR_6 && reply_ready && valid_cmd55;
wire valid_acmd6 = reply_contents[45:40] == 6'd6 && reply_contents[39:27] == 13'd0 && reply_contents[24:21] == 4'b0; //command index; R1[31:19] no errors; R1[16:13] no errors
 
//------------------------------------------------------------------------------
 
reg [19:0] acmd41_busy_cnt;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) acmd41_busy_cnt <= 20'd0;
else if(prepare_cmd0) acmd41_busy_cnt <= 20'd0;
else if(repeat_acmd41) acmd41_busy_cnt <= acmd41_busy_cnt + 20'd1;
end
 
reg [15:0] rca;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) rca <= 16'd0;
else if(prepare_cmd7) rca <= cmd3_new_rca;
end
 
//------------------------------------------------------------------------------
 
localparam [3:0] S_IDLE = 4'd0;
localparam [3:0] S_CMD0 = 4'd1;
localparam [3:0] S_CMD8 = 4'd2;
localparam [3:0] S_CMD55_FOR_41 = 4'd3;
localparam [3:0] S_ACMD41 = 4'd4;
localparam [3:0] S_CMD2 = 4'd5;
localparam [3:0] S_CMD3 = 4'd6;
localparam [3:0] S_CMD7 = 4'd7;
localparam [3:0] S_WAIT_DAT0 = 4'd8;
localparam [3:0] S_CMD55_FOR_6 = 4'd9;
localparam [3:0] S_ACMD6 = 4'd10;
 
reg [3:0] state;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) state <= S_IDLE;
else if(operation_finished_with_error) state <= S_IDLE;
else if(prepare_cmd0) state <= S_CMD0;
else if(prepare_cmd8) state <= S_CMD8;
else if(prepare_cmd55_for_41) state <= S_CMD55_FOR_41;
else if(prepare_acmd41) state <= S_ACMD41;
else if(repeat_acmd41) state <= S_CMD55_FOR_41;
else if(prepare_cmd2) state <= S_CMD2;
else if(prepare_cmd3) state <= S_CMD3;
else if(prepare_cmd7) state <= S_CMD7;
else if(state == S_CMD7 && reply_ready && valid_cmd7_but_busy) state <= S_WAIT_DAT0;
else if(prepare_cmd55_for_6) state <= S_CMD55_FOR_6;
else if(prepare_acmd6) state <= S_ACMD6;
else if(operation_finished_ok) state <= S_IDLE;
end
 
//------------------------------------------------------------------------------
 
assign cmd_ready = prepare_cmd0 || prepare_cmd8 || prepare_cmd55_for_41 || prepare_acmd41 || prepare_cmd2 || prepare_cmd3 || prepare_cmd7 || prepare_cmd55_for_6 || prepare_acmd6;
assign cmd_index =
(prepare_cmd0)? 6'd0 :
(prepare_cmd8)? 6'd8 :
(prepare_cmd55_for_41)? 6'd55 :
(prepare_acmd41)? 6'd41 :
(prepare_cmd2)? 6'd2 :
(prepare_cmd3)? 6'd3 :
(prepare_cmd7)? 6'd7 :
(prepare_cmd55_for_6)? 6'd55 :
(prepare_acmd6)? 6'd6 :
6'd0;
 
assign cmd_arg =
(prepare_cmd0)? 32'd0 : //stuff bits
(prepare_cmd8)? { 20'b0, //reserved
4'b0001, //VHS voltage supplied 2.7-3.6 V
8'b11010010 } : //check pattern;
(prepare_cmd55_for_41)? { 16'd0, //RCA
16'd0 } : //stuff bits
(prepare_acmd41)? { 1'b0, //busy
1'b1, //Host Capacity Support (1=SDHC or SDXC)
1'b0, //reserved FB(0)
1'b0, //SDXC Power Control (0=power saving)
3'b0, //reserved
1'b0, //switching to 1.8V request
16'b0011000000000000, //voltage window field OCR[23:08]: 3.2-3.3 and 3.3-3.4
8'b0 } : //reseved;
(prepare_cmd2)? 32'd0 : //stuff bits
(prepare_cmd3)? 32'd0 : //stuff bits
(prepare_cmd7)? { cmd3_new_rca, //RCA
16'd0 } : //stuff bits
 
(prepare_cmd55_for_6)? { rca, //RCA
16'd0 } : //stuff bits
 
(prepare_acmd6)? { 30'd0, //stuff bits
2'b10 } : //4 bit bus
 
32'd0;
 
assign cmd_resp_length =
(prepare_cmd0)? 8'd0 :
(prepare_cmd8)? 8'd48 : //R7
(prepare_cmd55_for_41)? 8'd48 : //R1
(prepare_acmd41)? 8'd48 : //R3 OCR
(prepare_cmd2)? 8'd136 : //R2
(prepare_cmd3)? 8'd48 : //R6
(prepare_cmd7)? 8'd48 : //R1b
(prepare_cmd55_for_6)? 8'd48 : //R1
(prepare_acmd6)? 8'd48 : //R1
8'd0;
 
assign cmd_resp_has_crc7 =
(prepare_cmd0)? 1'b0 :
(prepare_cmd8)? 1'b1 :
(prepare_cmd55_for_41)? 1'b1 :
(prepare_acmd41)? 1'b0 :
(prepare_cmd2)? 1'b1 :
(prepare_cmd3)? 1'b1 :
(prepare_cmd7)? 1'b1 :
(prepare_cmd55_for_6)? 1'b1 :
(prepare_acmd6)? 1'b1 :
1'b1;
 
//------------------------------------------------------------------------------
// synthesis translate_off
wire _unused_ok = &{ 1'b0, reply_contents[135:46], reply_contents[20], reply_contents[7:0], 1'b0 };
// synthesis translate_on
//------------------------------------------------------------------------------
 
endmodule
/cmd.v
0,0 → 1,173
/*
* 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
/card_write.v
0,0 → 1,164
/*
* 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 card_write(
input clk,
input rst_n,
//
input operation_write,
input operation_sector_last,
output operation_sector_update,
output operation_finished_ok,
output operation_finished_with_error,
//
output cmd_ready,
output [5:0] cmd_index,
output [31:0] cmd_arg,
output [7:0] cmd_resp_length,
output cmd_resp_has_crc7,
input reply_ready,
input [135:0] reply_contents,
input reply_error,
//
output read_start,
output read_next,
input [31:0] read_data,
input read_done,
//
output reg wr_async_data_ready,
output reg [31:0] wr_async_data,
input wr_data_done,
input wr_data_last_in_sector,
input wr_error,
input wr_finished_sector,
//
input [31:0] sd_address,
//
input current_dat0,
//
output stop_sd_clk
);
 
//------------------------------------------------------------------------------
 
localparam [2:0] S_IDLE = 3'd0;
localparam [2:0] S_CMD25 = 3'd1;
localparam [2:0] S_WAIT_FOR_DATA = 3'd2;
localparam [2:0] S_WAIT_FOR_DAT0 = 3'd3;
localparam [2:0] S_CMD12 = 3'd4;
localparam [2:0] S_FAILED_CMD12 = 3'd5;
 
wire prepare_cmd25 = state == S_IDLE && operation_write;
wire valid_cmd25 = reply_contents[45:40] == 6'd25 && reply_contents[39:27] == 13'd0 && reply_contents[24:21] == 4'b0; //command index; R1[31:19] no errors; R1[16:13] no errors
 
wire stop_because_of_error = (state == S_CMD25 && (reply_error || (reply_ready && ~(valid_cmd25)))) || (state == S_WAIT_FOR_DATA && operation_sector_update && wr_error);
wire prepare_cmd12 = stop_because_of_error || (operation_sector_update && operation_sector_last);
wire valid_cmd12_common = reply_contents[45:40] == 6'd12 && reply_contents[39:27] == 13'd0 && reply_contents[24:21] == 4'b0; //command index; R1[31:19] no errors; R1[16:13] no errors
wire valid_cmd12 = valid_cmd12_common && current_dat0;
wire valid_cmd12_but_busy = valid_cmd12_common && ~(current_dat0);
 
wire prepare_failed_cmd12 = state == S_CMD12 && (reply_error || (reply_ready && ~(valid_cmd12_common)));
 
reg [2:0] state;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) state <= S_IDLE;
else if(operation_finished_with_error) state <= S_IDLE;
else if(prepare_cmd25) state <= S_CMD25;
else if(state == S_CMD25 && reply_ready && valid_cmd25) state <= S_WAIT_FOR_DATA;
 
else if(prepare_cmd12) state <= S_CMD12;
else if(state == S_CMD12 && reply_ready && valid_cmd12_but_busy) state <= S_WAIT_FOR_DAT0;
else if(prepare_failed_cmd12) state <= S_FAILED_CMD12;
else if(operation_finished_ok) state <= S_IDLE;
end
 
reg was_error;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) was_error <= 1'b0;
else if(prepare_cmd25) was_error <= 1'b0;
else if(stop_because_of_error || prepare_failed_cmd12) was_error <= 1'b1;
end
 
wire finishing = (state == S_CMD12 && reply_ready && valid_cmd12) || (state == S_WAIT_FOR_DAT0 && current_dat0) || state == S_FAILED_CMD12;
 
assign operation_finished_ok = finishing && ~(was_error);
assign operation_finished_with_error = finishing && was_error;
 
//------------------------------------------------------------------------------
 
reg first_read;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) first_read <= 1'b0;
else if(prepare_cmd25) first_read <= 1'b1;
else if(read_start) first_read <= 1'b0;
end
 
reg [3:0] read_cnt;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) read_cnt <= 4'd0;
else if(read_start || read_next) read_cnt <= 4'd1;
else if(read_done) read_cnt <= 4'd0;
else if(read_cnt > 4'd0 && read_cnt < 4'd14) read_cnt <= read_cnt + 4'd1;
end
 
assign stop_sd_clk = read_cnt == 4'd14;
 
assign operation_sector_update = wr_finished_sector;
 
wire read_condition = state == S_WAIT_FOR_DATA && ~(wr_async_data_ready) && read_cnt == 4'd0 && ~(read_finished);
assign read_start = read_condition && first_read;
assign read_next = read_condition && ~(first_read);
 
reg read_finished;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) read_finished <= 1'b0;
else if(wr_data_done && wr_data_last_in_sector) read_finished <= 1'b1;
else if(operation_sector_update) read_finished <= 1'b0;
end
 
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) wr_async_data_ready <= 1'b0;
else if(wr_data_done) wr_async_data_ready <= 1'b0;
else if(read_done) wr_async_data_ready <= 1'b1;
end
 
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) wr_async_data <= 32'b0;
else if(read_done) wr_async_data <= read_data;
end
 
//------------------------------------------------------------------------------
 
assign cmd_ready = prepare_cmd25 || prepare_cmd12;
 
assign cmd_index = (prepare_cmd25)? 6'd25 : 6'd12;
assign cmd_arg = (prepare_cmd25)? sd_address : 32'd0; //cmd25: sector address; cmd12: stuff bits
assign cmd_resp_length = 8'd48; //cmd25: R1; cmd12: R1b
assign cmd_resp_has_crc7 = 1'b1;
 
//------------------------------------------------------------------------------
 
//------------------------------------------------------------------------------
// synthesis translate_off
wire _unused_ok = &{ 1'b0, reply_contents[135:46], reply_contents[26:25], reply_contents[20:0], 1'b0 };
// synthesis translate_on
//------------------------------------------------------------------------------
 
endmodule
/card_read.v
0,0 → 1,147
/*
* 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 card_read(
input clk,
input rst_n,
//
input operation_read,
input operation_sector_last,
output operation_sector_update,
output operation_finished_ok,
output operation_finished_with_error,
//
output cmd_ready,
output [5:0] cmd_index,
output [31:0] cmd_arg,
output [7:0] cmd_resp_length,
output cmd_resp_has_crc7,
input reply_ready,
input [135:0] reply_contents,
input reply_error,
//
output write_start,
output write_next,
output [31:0] write_data,
input write_done,
//
output rd_async_start,
output rd_async_abort,
input rd_data_done,
input rd_data_last_in_sector,
input [31:0] rd_data,
input rd_error,
//
input [31:0] sd_address,
//
input current_dat0,
//
output stop_sd_clk
);
 
//------------------------------------------------------------------------------
 
localparam [2:0] S_IDLE = 3'd0;
localparam [2:0] S_CMD18 = 3'd1;
localparam [2:0] S_WAIT_FOR_DATA = 3'd2;
localparam [2:0] S_CMD12 = 3'd3;
localparam [2:0] S_WAIT_FOR_DAT0 = 3'd4;
localparam [2:0] S_FAILED_CMD12 = 3'd5;
 
wire prepare_cmd18 = state == S_IDLE && operation_read;
wire valid_cmd18 = reply_contents[45:40] == 6'd18 && reply_contents[39:27] == 13'd0 && reply_contents[24:21] == 4'b0; //command index; R1[31:19] no errors; R1[16:13] no errors
 
wire stop_because_of_error = (state == S_CMD18 && (reply_error || (reply_ready && ~(valid_cmd18)))) || ((state == S_CMD18 || state == S_WAIT_FOR_DATA) && rd_error);
wire prepare_cmd12 = stop_because_of_error || (operation_sector_update && operation_sector_last);
wire valid_cmd12_common = reply_contents[45:40] == 6'd12 && reply_contents[39:27] == 13'd0 && reply_contents[24:21] == 4'b0; //command index; R1[31:19] no errors; R1[16:13] no errors
wire valid_cmd12 = valid_cmd12_common && current_dat0;
wire valid_cmd12_but_busy = valid_cmd12_common && ~(current_dat0);
 
wire prepare_failed_cmd12 = state == S_CMD12 && (reply_error || (reply_ready && ~(valid_cmd12_common)));
 
reg [2:0] state;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) state <= S_IDLE;
else if(operation_finished_with_error) state <= S_IDLE;
else if(prepare_cmd18) state <= S_CMD18;
else if(state == S_CMD18 && reply_ready && valid_cmd18) state <= S_WAIT_FOR_DATA;
else if(prepare_cmd12) state <= S_CMD12;
else if(state == S_CMD12 && reply_ready && valid_cmd12_but_busy) state <= S_WAIT_FOR_DAT0;
else if(prepare_failed_cmd12) state <= S_FAILED_CMD12;
else if(operation_finished_ok) state <= S_IDLE;
end
 
reg was_error;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) was_error <= 1'b0;
else if(prepare_cmd18) was_error <= 1'b0;
else if(stop_because_of_error || rd_error || prepare_failed_cmd12) was_error <= 1'b1;
end
 
wire finishing = (state == S_CMD12 && reply_ready && valid_cmd12) || (state == S_WAIT_FOR_DAT0 && current_dat0) || state == S_FAILED_CMD12;
 
assign operation_finished_ok = finishing && ~(was_error);
assign operation_finished_with_error = finishing && was_error;
 
//------------------------------------------------------------------------------
 
reg first_write;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) first_write <= 1'b0;
else if(prepare_cmd18) first_write <= 1'b1;
else if(write_start) first_write <= 1'b0;
end
 
reg [3:0] write_cnt;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) write_cnt <= 4'd0;
else if(write_start || write_next) write_cnt <= 4'd1;
else if(write_done) write_cnt <= 4'd0;
else if(write_cnt > 4'd0 && write_cnt < 4'd14) write_cnt <= write_cnt + 4'd1;
end
 
assign stop_sd_clk = write_cnt == 4'd14;
 
assign write_start = first_write && rd_data_done && (state == S_CMD18 || state == S_WAIT_FOR_DATA);
assign write_next = ~(first_write) && rd_data_done && (state == S_CMD18 || state == S_WAIT_FOR_DATA);
assign write_data = rd_data;
 
assign rd_async_start = prepare_cmd18;
assign rd_async_abort = operation_finished_ok || operation_finished_with_error;
 
assign operation_sector_update = rd_data_done && rd_data_last_in_sector;
 
//------------------------------------------------------------------------------
 
assign cmd_ready = prepare_cmd18 || prepare_cmd12;
 
assign cmd_index = (prepare_cmd18)? 6'd18 : 6'd12;
assign cmd_arg = (prepare_cmd18)? sd_address : 32'd0; //cmd18: sector address; cmd12: stuff bits
assign cmd_resp_length = 8'd48; //cmd18: R1; cmd12: R1b
assign cmd_resp_has_crc7 = 1'b1;
 
//------------------------------------------------------------------------------
// synthesis translate_off
wire _unused_ok = &{ 1'b0, reply_contents[135:46], reply_contents[26:25], reply_contents[20:0], 1'b0 };
// synthesis translate_on
//------------------------------------------------------------------------------
 
endmodule
/dat.v
0,0 → 1,339
/*
* 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 dat(
input clk,
input rst_n,
//
input sd_clk_is_one,
//
input wr_async_data_ready,
input [31:0] wr_async_data,
output reg wr_data_done,
output reg wr_data_last_in_sector,
output reg wr_error,
output reg wr_finished_sector,
//
input rd_async_start,
input rd_async_abort,
output reg rd_data_done,
output reg rd_data_last_in_sector,
output reg [31:0] rd_data,
output reg rd_error,
//
output current_dat0,
//
inout [3:0] sd_dat
);
 
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
 
reg sd_dat_enable;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) sd_dat_enable <= 1'b0;
else if(sd_clk_is_one) sd_dat_enable <= wr_start || wr_cnt > 11'd0;
end
 
reg [3:0] sd_dat_output;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) sd_dat_output <= 4'hF;
else if(sd_clk_is_one) sd_dat_output <= (wr_start)? 4'h0 : (wr_cnt <= 11'd17 && wr_cnt >= 11'd2)? { wr_crc_3[0], wr_crc_2[0], wr_crc_1[0], wr_crc_0[0] } : { wr_val_3[7], wr_val_2[7], wr_val_1[7], wr_val_0[7] };
end
 
assign sd_dat = (sd_dat_enable)? sd_dat_output : 4'bZ;
 
reg [3:0] sd_dat_input;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) sd_dat_input <= 4'b1111;
else if(~(sd_clk_is_one)) sd_dat_input <= sd_dat;
end
 
assign current_dat0 = sd_dat_input[0];
 
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
 
/*
input wr_async_data_ready,
input [31:0] wr_async_data,
output reg wr_data_done,
output reg wr_error,
output reg wr_finished,
*/
 
reg [1:0] wr_start_delay_cnt;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) wr_start_delay_cnt <= 2'd2;
else if(sd_clk_is_one && wr_async_data_ready && wr_cnt == 11'd0 && ~(wr_in_progress) && wr_start_delay_cnt > 2'd0) wr_start_delay_cnt <= wr_start_delay_cnt - 2'd1;
else if(wr_cnt > 11'd0) wr_start_delay_cnt <= 2'd2;
end
 
wire wr_start = sd_clk_is_one && wr_async_data_ready && wr_cnt == 11'd0 && ~(wr_in_progress) && wr_start_delay_cnt == 2'd0;
wire wr_load = wr_start || (sd_clk_is_one && wr_async_data_ready && wr_cnt >= 11'd26 && wr_cnt[2:0] == 3'b010) || (wr_missed && wr_async_data_ready);
 
reg wr_missed;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) wr_missed <= 1'b0;
else if(sd_clk_is_one && ~(wr_async_data_ready) && wr_cnt >= 11'd26 && wr_cnt[2:0] == 3'b010) wr_missed <= 1'b1;
else if(wr_async_data_ready) wr_missed <= 1'b0;
end
 
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) wr_data_done <= 1'b0;
else wr_data_done <= wr_load;
end
 
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) wr_data_last_in_sector <= 1'b0;
else wr_data_last_in_sector <= wr_load && (wr_cnt == 11'd26 || wr_cnt == 11'd25);
end
 
reg [10:0] wr_cnt;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) wr_cnt <= 11'd0;
else if(wr_start) wr_cnt <= 11'd1041;
else if(sd_clk_is_one && wr_cnt > 11'd0) wr_cnt <= wr_cnt - 11'd1;
end
 
wire wr_resp_start = sd_clk_is_one && wr_cnt == 11'd1;
 
reg wr_resp_awaiting;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) wr_resp_awaiting <= 1'b0;
else if(wr_resp_start) wr_resp_awaiting <= 1'b1;
else if(sd_clk_is_one && wr_resp_awaiting && sd_dat_input[0] == 1'b0) wr_resp_awaiting <= 1'b0;
end
 
reg [2:0] wr_resp_cnt;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) wr_resp_cnt <= 3'd0;
else if(sd_clk_is_one && wr_resp_awaiting && sd_dat_input[0] == 1'b0) wr_resp_cnt <= 3'd4;
else if(sd_clk_is_one && wr_resp_cnt > 3'd0) wr_resp_cnt <= wr_resp_cnt - 3'd1;
end
 
wire wr_in_progress_end = wr_in_progress && ((sd_clk_is_one && wr_error_cnt == 27'h7FFFFFF) || (sd_clk_is_one && wr_cnt == 11'd0 && ~(wr_resp_awaiting) && wr_resp_cnt == 3'd0 && sd_dat_input[0] == 1'b1));
 
reg wr_in_progress;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) wr_in_progress <= 1'b0;
else if(wr_start) wr_in_progress <= 1'b1;
else if(wr_in_progress_end) wr_in_progress <= 1'b0;
end
 
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) wr_finished_sector <= 1'b0;
else wr_finished_sector <= wr_in_progress_end;
end
 
//------------------------------------------------------------------------------
 
wire wr_resp_now_in_error = sd_clk_is_one && (
(wr_resp_cnt == 3'd4 && sd_dat_input[0] == 1'b1) || //crc status invalid
(wr_resp_cnt == 3'd3 && sd_dat_input[0] == 1'b0) || //crc status invalid
(wr_resp_cnt == 3'd2 && sd_dat_input[0] == 1'b1) || //crc status invalid
(wr_resp_cnt == 3'd1 && sd_dat_input[0] == 1'b0) //end bit is '0'
);
 
reg [26:0] wr_error_cnt;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) wr_error_cnt <= 27'd0;
else if(~(wr_in_progress)) wr_error_cnt <= 27'd0;
else if(wr_resp_start) wr_error_cnt <= 27'd1;
else if(sd_clk_is_one && wr_error_cnt > 27'd0) wr_error_cnt <= wr_error_cnt + 27'd1;
end
 
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) wr_error <= 1'b0;
else if(wr_start) wr_error <= 1'b0;
else if(wr_resp_now_in_error) wr_error <= 1'b1;
else if(sd_clk_is_one && wr_error_cnt == 27'h7FFFFFF) wr_error <= 1'b1;
end
 
//------------------------------------------------------------------------------
 
reg [7:0] wr_val_0;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) wr_val_0 <= 8'd0;
else if(wr_load) wr_val_0 <= { wr_async_data[4], wr_async_data[0], wr_async_data[12], wr_async_data[8], wr_async_data[20], wr_async_data[16], wr_async_data[28], wr_async_data[24] };
else if(sd_clk_is_one) wr_val_0 <= { wr_val_0[6:0], 1'b1 }; //fill with 1 important
end
 
reg [7:0] wr_val_1;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) wr_val_1 <= 8'd0;
else if(wr_load) wr_val_1 <= { wr_async_data[5], wr_async_data[1], wr_async_data[13], wr_async_data[9], wr_async_data[21], wr_async_data[17], wr_async_data[29], wr_async_data[25] };
else if(sd_clk_is_one) wr_val_1 <= { wr_val_1[6:0], 1'b1 }; //fill with 1 important
end
 
reg [7:0] wr_val_2;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) wr_val_2 <= 8'd0;
else if(wr_load) wr_val_2 <= { wr_async_data[6], wr_async_data[2], wr_async_data[14], wr_async_data[10], wr_async_data[22], wr_async_data[18], wr_async_data[30], wr_async_data[26] };
else if(sd_clk_is_one) wr_val_2 <= { wr_val_2[6:0], 1'b1 }; //fill with 1 important
end
 
reg [7:0] wr_val_3;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) wr_val_3 <= 8'd0;
else if(wr_load) wr_val_3 <= { wr_async_data[7], wr_async_data[3], wr_async_data[15], wr_async_data[11], wr_async_data[23], wr_async_data[19], wr_async_data[31], wr_async_data[27] };
else if(sd_clk_is_one) wr_val_3 <= { wr_val_3[6:0], 1'b1 }; //fill with 1 important
end
 
reg [15:0] wr_crc_0;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) wr_crc_0 <= 16'd0;
else if(sd_clk_is_one && wr_cnt >= 11'd18) wr_crc_0 <= { wr_val_0[7] ^ wr_crc_0[0], wr_crc_0[15:12], wr_crc_0[11] ^ wr_val_0[7] ^ wr_crc_0[0], wr_crc_0[10:5], wr_crc_0[4] ^ wr_val_0[7] ^ wr_crc_0[0], wr_crc_0[3:1] };
else if(sd_clk_is_one) wr_crc_0 <= { 1'b0, wr_crc_0[15:1] }; //fill with 0 important
end
 
reg [15:0] wr_crc_1;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) wr_crc_1 <= 16'd0;
else if(sd_clk_is_one && wr_cnt >= 11'd18) wr_crc_1 <= { wr_val_1[7] ^ wr_crc_1[0], wr_crc_1[15:12], wr_crc_1[11] ^ wr_val_1[7] ^ wr_crc_1[0], wr_crc_1[10:5], wr_crc_1[4] ^ wr_val_1[7] ^ wr_crc_1[0], wr_crc_1[3:1] };
else if(sd_clk_is_one) wr_crc_1 <= { 1'b0, wr_crc_1[15:1] }; //fill with 0 important
end
 
reg [15:0] wr_crc_2;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) wr_crc_2 <= 16'd0;
else if(sd_clk_is_one && wr_cnt >= 11'd18) wr_crc_2 <= { wr_val_2[7] ^ wr_crc_2[0], wr_crc_2[15:12], wr_crc_2[11] ^ wr_val_2[7] ^ wr_crc_2[0], wr_crc_2[10:5], wr_crc_2[4] ^ wr_val_2[7] ^ wr_crc_2[0], wr_crc_2[3:1] };
else if(sd_clk_is_one) wr_crc_2 <= { 1'b0, wr_crc_2[15:1] }; //fill with 0 important
end
 
reg [15:0] wr_crc_3;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) wr_crc_3 <= 16'd0;
else if(sd_clk_is_one && wr_cnt >= 11'd18) wr_crc_3 <= { wr_val_3[7] ^ wr_crc_3[0], wr_crc_3[15:12], wr_crc_3[11] ^ wr_val_3[7] ^ wr_crc_3[0], wr_crc_3[10:5], wr_crc_3[4] ^ wr_val_3[7] ^ wr_crc_3[0], wr_crc_3[3:1] };
else if(sd_clk_is_one) wr_crc_3 <= { 1'b0, wr_crc_3[15:1] }; //fill with 0 important
end
 
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
 
/*
input rd_async_start,
input rd_async_abort,
output reg rd_data_done,
output reg rd_data_last_in_sector,
output reg [31:0] rd_data,
output reg rd_error,
*/
 
wire rd_start = sd_clk_is_one && rd_async_in_progress && ~(rd_now_in_error) && ~(rd_error) && ~(rd_awaiting) && rd_cnt <= 11'd1;
wire rd_start_block = sd_clk_is_one && rd_awaiting && sd_dat_input == 4'h0;
wire rd_active = sd_clk_is_one && rd_cnt > 11'd0;
wire rd_load = sd_clk_is_one && rd_cnt >= 11'd18 && rd_cnt[2:0] == 3'b010 && ~(rd_async_abort);
 
reg rd_async_in_progress;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) rd_async_in_progress <= 1'b0;
else if(rd_async_abort) rd_async_in_progress <= 1'b0;
else if(rd_async_start) rd_async_in_progress <= 1'b1;
end
 
reg rd_awaiting;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) rd_awaiting <= 1'b0;
else if(rd_async_abort) rd_awaiting <= 1'b0;
else if(rd_start) rd_awaiting <= 1'b1;
else if(rd_start_block) rd_awaiting <= 1'b0;
end
 
reg [10:0] rd_cnt;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) rd_cnt <= 11'd0;
else if(rd_async_abort) rd_cnt <= 11'd0;
else if(rd_start_block) rd_cnt <= 11'd1041;
else if(rd_active) rd_cnt <= rd_cnt - 11'd1;
end
 
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) rd_data_done <= 1'b0;
else rd_data_done <= rd_load;
end
 
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) rd_data_last_in_sector <= 1'b0;
else rd_data_last_in_sector <= rd_load && rd_cnt == 11'd18;
end
 
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) rd_data <= 32'b0;
else if(rd_load) rd_data <= { rd_val[3:0], sd_dat_input, rd_val[11:4], rd_val[19:12], rd_val[27:20] };
end
 
//------------------------------------------------------------------------------
 
reg [26:0] rd_error_cnt;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) rd_error_cnt <= 27'd0;
else if(rd_async_abort) rd_error_cnt <= 27'd0;
else if(rd_start_block) rd_error_cnt <= 27'd0;
else if(rd_start) rd_error_cnt <= 27'd1;
else if(sd_clk_is_one && rd_error_cnt > 27'd0) rd_error_cnt <= rd_error_cnt + 27'd1;
end
 
wire rd_now_in_error = rd_active && (
(rd_cnt == 11'd1 && sd_dat_input != 4'hF) || //end bit is '0'
(rd_cnt <= 11'd17 && rd_cnt >= 11'd2 && sd_dat_input != { rd_3[0], rd_2[0], rd_1[0], rd_0[0] }) //crc16 invalid
);
 
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) rd_error <= 1'b0;
else if(rd_async_abort) rd_error <= 1'b0;
else if(rd_now_in_error) rd_error <= 1'b1;
else if(sd_clk_is_one && rd_error_cnt == 27'h7FFFFFF) rd_error <= 1'b1;
end
 
//------------------------------------------------------------------------------
 
reg [27:0] rd_val;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) rd_val <= 28'd0;
else if(rd_active) rd_val <= { rd_val[23:0], sd_dat_input };
end
 
reg [15:0] rd_0;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) rd_0 <= 16'd0;
else if(sd_clk_is_one && rd_cnt >= 11'd18) rd_0 <= { sd_dat_input[0] ^ rd_0[0], rd_0[15:12], rd_0[11] ^ sd_dat_input[0] ^ rd_0[0], rd_0[10:5], rd_0[4] ^ sd_dat_input[0] ^ rd_0[0], rd_0[3:1] };
else if(sd_clk_is_one) rd_0 <= { 1'b0, rd_0[15:1] }; //fill with 0 important
end
 
reg [15:0] rd_1;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) rd_1 <= 16'd0;
else if(sd_clk_is_one && rd_cnt >= 11'd18) rd_1 <= { sd_dat_input[1] ^ rd_1[0], rd_1[15:12], rd_1[11] ^ sd_dat_input[1] ^ rd_1[0], rd_1[10:5], rd_1[4] ^ sd_dat_input[1] ^ rd_1[0], rd_1[3:1] };
else if(sd_clk_is_one) rd_1 <= { 1'b0, rd_1[15:1] }; //fill with 0 important
end
 
reg [15:0] rd_2;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) rd_2 <= 16'd0;
else if(sd_clk_is_one && rd_cnt >= 11'd18) rd_2 <= { sd_dat_input[2] ^ rd_2[0], rd_2[15:12], rd_2[11] ^ sd_dat_input[2] ^ rd_2[0], rd_2[10:5], rd_2[4] ^ sd_dat_input[2] ^ rd_2[0], rd_2[3:1] };
else if(sd_clk_is_one) rd_2 <= { 1'b0, rd_2[15:1] }; //fill with 0 important
end
 
reg [15:0] rd_3;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) rd_3 <= 16'd0;
else if(sd_clk_is_one && rd_cnt >= 11'd18) rd_3 <= { sd_dat_input[3] ^ rd_3[0], rd_3[15:12], rd_3[11] ^ sd_dat_input[3] ^ rd_3[0], rd_3[10:5], rd_3[4] ^ sd_dat_input[3] ^ rd_3[0], rd_3[3:1] };
else if(sd_clk_is_one) rd_3 <= { 1'b0, rd_3[15:1] }; //fill with 0 important
end
 
//------------------------------------------------------------------------------
 
endmodule
/avalon_slave.v
0,0 → 1,119
/*
* 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 avalon_slave(
input clk,
input rst_n,
//
input [1:0] avs_address,
input avs_read,
output [31:0] avs_readdata,
input avs_write,
input [31:0] avs_writedata,
//
output reg operation_init,
output reg operation_read,
output reg operation_write,
input operation_sector_update,
output operation_sector_last,
input operation_finished_ok,
input operation_finished_with_error,
//
output reg [31:0] sd_address,
output reg [31:0] avalon_address_base
);
 
//------------------------------------------------------------------------------
 
assign avs_readdata = (avs_address == 2'd0)? {29'd0, status[2:0]} : { 29'd0, mutex };
 
reg [2:0] mutex;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) mutex <= 3'd0;
else if(mutex == 3'd0 && avs_address == 2'd1 && avs_read) mutex <= 3'd1;
else if(mutex == 3'd0 && avs_address == 2'd2 && avs_read) mutex <= 3'd2;
else if(mutex == 3'd0 && avs_address == 2'd3 && avs_read) mutex <= 3'd3;
else if(mutex < 3'd4 && (operation_init || operation_read || operation_write)) mutex <= 3'd4;
else if(operation_finished_ok || operation_finished_with_error) mutex <= 3'd0;
end
 
//------------------------------------------------------------------------------
 
wire operation_idle = ~(operation_init) && ~(operation_read) && ~(operation_write);
 
localparam [1:0] CONTROL_IDLE = 2'd0; //not used
localparam [1:0] CONTROL_INIT = 2'd1;
localparam [1:0] CONTROL_READ = 2'd2;
localparam [1:0] CONTROL_WRITE = 2'd3;
 
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) operation_init <= 1'b1;
else if(operation_finished_ok || operation_finished_with_error) operation_init <= 1'b0;
else if(operation_idle && avs_write && avs_address == 2'd3 && avs_writedata[1:0] == CONTROL_INIT) operation_init <= 1'b1;
end
 
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) operation_read <= 1'b0;
else if(operation_finished_ok || operation_finished_with_error) operation_read <= 1'b0;
else if(operation_idle && avs_write && avs_address == 2'd3 && avs_writedata[1:0] == CONTROL_READ) operation_read <= 1'b1;
end
 
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) operation_write <= 1'b0;
else if(operation_finished_ok || operation_finished_with_error) operation_write <= 1'b0;
else if(operation_idle && avs_write && avs_address == 2'd3 && avs_writedata[1:0] == CONTROL_WRITE) operation_write <= 1'b1;
end
 
//------------------------------------------------------------------------------
 
localparam [2:0] STATUS_INIT = 3'd0;
localparam [2:0] STATUS_INIT_ERROR = 3'd1;
localparam [2:0] STATUS_IDLE = 3'd2;
localparam [2:0] STATUS_READ = 3'd3;
localparam [2:0] STATUS_WRITE = 3'd4;
localparam [2:0] STATUS_ERROR = 3'd5;
 
reg [2:0] status;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) status <= STATUS_INIT;
else if(operation_idle && avs_write && avs_address == 2'd3 && avs_writedata[1:0] == CONTROL_INIT) status <= STATUS_INIT;
else if(operation_idle && avs_write && avs_address == 2'd3 && avs_writedata[1:0] == CONTROL_READ) status <= STATUS_READ;
else if(operation_idle && avs_write && avs_address == 2'd3 && avs_writedata[1:0] == CONTROL_WRITE) status <= STATUS_WRITE;
else if(operation_init && operation_finished_with_error) status <= STATUS_INIT_ERROR;
else if(operation_finished_with_error) status <= STATUS_ERROR;
else if(operation_finished_ok) status <= STATUS_IDLE;
end
 
//------------------------------------------------------------------------------
 
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) avalon_address_base <= 32'd0;
else if(operation_idle && avs_write && avs_address == 2'd0) avalon_address_base <= avs_writedata;
end
 
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) sd_address <= 32'd0;
else if(operation_idle && avs_write && avs_address == 2'd1) sd_address <= avs_writedata;
end
 
reg [31:0] sd_block_count;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) sd_block_count <= 32'd0;
else if(operation_sector_update) sd_block_count <= sd_block_count - 32'd1;
else if(operation_idle && avs_write && avs_address == 2'd2) sd_block_count <= avs_writedata;
end
 
assign operation_sector_last = sd_block_count == 32'd1;
 
//------------------------------------------------------------------------------
 
endmodule

powered by: WebSVN 2.1.0

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