SOFA/BENCHMARK/sdc_controller/rtl/sdc_controller.v

412 lines
19 KiB
Verilog

//////////////////////////////////////////////////////////////////////
//// ////
//// WISHBONE SD Card Controller IP Core ////
//// ////
//// sdc_controller.v ////
//// ////
//// This file is part of the WISHBONE SD Card ////
//// Controller IP Core project ////
//// http://opencores.org/project,sd_card_controller ////
//// ////
//// Description ////
//// Top level entity. ////
//// This core is based on the "sd card controller" project from ////
//// http://opencores.org/project,sdcard_mass_storage_controller ////
//// but has been largely rewritten. A lot of effort has been ////
//// made to make the core more generic and easily usable ////
//// with OSs like Linux. ////
//// - data transfer commands are not fixed ////
//// - data transfer block size is configurable ////
//// - multiple block transfer support ////
//// - R2 responses (136 bit) support ////
//// ////
//// Author(s): ////
//// - Marek Czerski, ma.czerski@gmail.com ////
//// ////
//////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2013 Authors ////
//// ////
//// Based on original work by ////
//// Adam Edvardsson (adam.edvardsson@orsoc.se) ////
//// ////
//// Copyright (C) 2009 Authors ////
//// ////
//// This source file may be used and distributed without ////
//// restriction provided that this copyright statement is not ////
//// removed from the file and that any derivative work contains ////
//// the original copyright notice and the associated disclaimer. ////
//// ////
//// This source file is free software; you can redistribute it ////
//// and/or modify it under the terms of the GNU Lesser General ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any ////
//// later version. ////
//// ////
//// This source is distributed in the hope that it will be ////
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
//// PURPOSE. See the GNU Lesser General Public License for more ////
//// details. ////
//// ////
//// You should have received a copy of the GNU Lesser General ////
//// Public License along with this source; if not, download it ////
//// from http://www.opencores.org/lgpl.shtml ////
//// ////
//////////////////////////////////////////////////////////////////////
`include "sd_defines.h"
module sdc_controller(
// WISHBONE common
wb_clk_i,
wb_rst_i,
// WISHBONE slave
wb_dat_i,
wb_dat_o,
wb_adr_i,
wb_sel_i,
wb_we_i,
wb_cyc_i,
wb_stb_i,
wb_ack_o,
// WISHBONE master
m_wb_dat_o,
m_wb_dat_i,
m_wb_adr_o,
m_wb_sel_o,
m_wb_we_o,
m_wb_cyc_o,
m_wb_stb_o,
m_wb_ack_i,
m_wb_cti_o,
m_wb_bte_o,
//SD BUS
sd_cmd_dat_i,
sd_cmd_out_o,
sd_cmd_oe_o,
//card_detect,
sd_dat_dat_i,
sd_dat_out_o,
sd_dat_oe_o,
sd_clk_o_pad,
sd_clk_i_pad,
int_cmd,
int_data
);
input wb_clk_i;
input wb_rst_i;
input [31:0] wb_dat_i;
output [31:0] wb_dat_o;
//input card_detect;
input [7:0] wb_adr_i;
input [3:0] wb_sel_i;
input wb_we_i;
input wb_cyc_i;
input wb_stb_i;
output wb_ack_o;
output [31:0] m_wb_adr_o;
output [3:0] m_wb_sel_o;
output m_wb_we_o;
input [31:0] m_wb_dat_i;
output [31:0] m_wb_dat_o;
output m_wb_cyc_o;
output m_wb_stb_o;
input m_wb_ack_i;
output [2:0] m_wb_cti_o;
output [1:0] m_wb_bte_o;
input wire [3:0] sd_dat_dat_i;
output wire [3:0] sd_dat_out_o;
output wire sd_dat_oe_o;
input wire sd_cmd_dat_i;
output wire sd_cmd_out_o;
output wire sd_cmd_oe_o;
output sd_clk_o_pad;
input wire sd_clk_i_pad;
output int_cmd, int_data;
//SD clock
wire sd_clk_o; //Sd_clk used in the system
wire go_idle;
wire cmd_start_wb_clk;
wire cmd_start_sd_clk;
wire cmd_start;
wire [1:0] cmd_setting;
wire cmd_start_tx;
wire [39:0] cmd;
wire [119:0] cmd_response;
wire cmd_crc_ok;
wire cmd_index_ok;
wire cmd_finish;
wire d_write;
wire d_read;
wire [31:0] data_in_rx_fifo;
wire [31:0] data_out_tx_fifo;
wire start_tx_fifo;
wire start_rx_fifo;
wire tx_fifo_empty;
wire tx_fifo_full;
wire rx_fifo_full;
wire sd_data_busy;
wire data_busy;
wire data_crc_ok;
wire rd_fifo;
wire we_fifo;
wire data_start_rx;
wire data_start_tx;
wire cmd_int_rst_wb_clk;
wire cmd_int_rst_sd_clk;
wire cmd_int_rst;
wire data_int_rst_wb_clk;
wire data_int_rst_sd_clk;
wire data_int_rst;
//wb accessible registers
wire [31:0] argument_reg_wb_clk;
wire [`CMD_REG_SIZE-1:0] command_reg_wb_clk;
wire [15:0] timeout_reg_wb_clk;
wire [0:0] software_reset_reg_wb_clk;
wire [31:0] response_0_reg_wb_clk;
wire [31:0] response_1_reg_wb_clk;
wire [31:0] response_2_reg_wb_clk;
wire [31:0] response_3_reg_wb_clk;
wire [`BLKSIZE_W-1:0] block_size_reg_wb_clk;
wire [15:0] controll_setting_reg_wb_clk;
wire [`INT_CMD_SIZE-1:0] cmd_int_status_reg_wb_clk;
wire [`INT_DATA_SIZE-1:0] data_int_status_reg_wb_clk;
wire [`INT_CMD_SIZE-1:0] cmd_int_enable_reg_wb_clk;
wire [`INT_DATA_SIZE-1:0] data_int_enable_reg_wb_clk;
wire [`BLKCNT_W-1:0] block_count_reg_wb_clk;
wire [31:0] dma_addr_reg_wb_clk;
wire [7:0] clock_divider_reg_wb_clk;
wire [31:0] argument_reg_sd_clk;
wire [`CMD_REG_SIZE-1:0] command_reg_sd_clk;
wire [15:0] timeout_reg_sd_clk;
wire [0:0] software_reset_reg_sd_clk;
wire [31:0] response_0_reg_sd_clk;
wire [31:0] response_1_reg_sd_clk;
wire [31:0] response_2_reg_sd_clk;
wire [31:0] response_3_reg_sd_clk;
wire [`BLKSIZE_W-1:0] block_size_reg_sd_clk;
wire [15:0] controll_setting_reg_sd_clk;
wire [`INT_CMD_SIZE-1:0] cmd_int_status_reg_sd_clk;
wire [2:0] data_int_status_reg_sd_clk;
wire [`INT_CMD_SIZE-1:0] cmd_int_enable_reg_sd_clk;
wire [2:0] data_int_enable_reg_sd_clk;
wire [`BLKCNT_W-1:0] block_count_reg_sd_clk;
wire [31:0] dma_addr_reg_sd_clk;
wire [7:0] clock_divider_reg_sd_clk;
sd_clock_divider clock_divider0(
.CLK (sd_clk_i_pad),
.DIVIDER (clock_divider_reg_sd_clk),
.RST (wb_rst_i),
.SD_CLK (sd_clk_o)
);
assign sd_clk_o_pad = sd_clk_o ;
sd_cmd_master sd_cmd_master0(
.sd_clk (sd_clk_o),
.rst (wb_rst_i | software_reset_reg_sd_clk[0]),
.start_i (cmd_start_sd_clk),
.int_status_rst_i(cmd_int_rst_sd_clk),
.setting_o (cmd_setting),
.start_xfr_o (cmd_start_tx),
.go_idle_o (go_idle),
.cmd_o (cmd),
.response_i (cmd_response),
.crc_ok_i (cmd_crc_ok),
.index_ok_i (cmd_index_ok),
.busy_i (sd_data_busy),
.finish_i (cmd_finish),
//input card_detect,
.argument_i (argument_reg_sd_clk),
.command_i (command_reg_sd_clk),
.timeout_i (timeout_reg_sd_clk),
.int_status_o (cmd_int_status_reg_sd_clk),
.response_0_o (response_0_reg_sd_clk),
.response_1_o (response_1_reg_sd_clk),
.response_2_o (response_2_reg_sd_clk),
.response_3_o (response_3_reg_sd_clk)
);
sd_cmd_serial_host cmd_serial_host0(
.sd_clk (sd_clk_o),
.rst (wb_rst_i | software_reset_reg_sd_clk[0] | go_idle),
.setting_i (cmd_setting),
.cmd_i (cmd),
.start_i (cmd_start_tx),
.finish_o (cmd_finish),
.response_o (cmd_response),
.crc_ok_o (cmd_crc_ok),
.index_ok_o (cmd_index_ok),
.cmd_dat_i (sd_cmd_dat_i),
.cmd_out_o (sd_cmd_out_o),
.cmd_oe_o (sd_cmd_oe_o)
);
sd_data_master sd_data_master0(
.sd_clk (sd_clk_o),
.rst (wb_rst_i | software_reset_reg_sd_clk[0]),
.start_tx_i (data_start_tx),
.start_rx_i (data_start_rx),
.d_write_o (d_write),
.d_read_o (d_read),
.start_tx_fifo_o (start_tx_fifo),
.start_rx_fifo_o (start_rx_fifo),
.tx_fifo_empty_i (tx_fifo_empty),
.tx_fifo_full_i (tx_fifo_full),
.rx_fifo_full_i (rx_fifo_full),
.xfr_complete_i (!data_busy),
.crc_ok_i (data_crc_ok),
.int_status_o (data_int_status_reg_sd_clk),
.int_status_rst_i (data_int_rst_sd_clk)
);
sd_data_serial_host sd_data_serial_host0(
.sd_clk (sd_clk_o),
.rst (wb_rst_i | software_reset_reg_sd_clk[0]),
.data_in (data_out_tx_fifo),
.rd (rd_fifo),
.data_out (data_in_rx_fifo),
.we (we_fifo),
.DAT_oe_o (sd_dat_oe_o),
.DAT_dat_o (sd_dat_out_o),
.DAT_dat_i (sd_dat_dat_i),
.blksize (block_size_reg_sd_clk),
.bus_4bit (controll_setting_reg_sd_clk[0]),
.blkcnt (block_count_reg_sd_clk),
.start ({d_read, d_write}),
.sd_data_busy (sd_data_busy),
.busy (data_busy),
.crc_ok (data_crc_ok)
);
sd_fifo_filler sd_fifo_filler0(
.wb_clk (wb_clk_i),
.rst (wb_rst_i | software_reset_reg_sd_clk[0]),
.wbm_adr_o (m_wb_adr_o),
.wbm_we_o (m_wb_we_o),
.wbm_dat_o (m_wb_dat_o),
.wbm_dat_i (m_wb_dat_i),
.wbm_cyc_o (m_wb_cyc_o),
.wbm_stb_o (m_wb_stb_o),
.wbm_ack_i (m_wb_ack_i),
.en_rx_i (start_rx_fifo),
.en_tx_i (start_tx_fifo),
.adr_i (dma_addr_reg_sd_clk),
.sd_clk (sd_clk_o),
.dat_i (data_in_rx_fifo),
.dat_o (data_out_tx_fifo),
.wr_i (we_fifo),
.rd_i (rd_fifo),
.sd_empty_o (tx_fifo_empty),
.sd_full_o (rx_fifo_full),
.wb_empty_o (),
.wb_full_o (tx_fifo_full)
);
sd_data_xfer_trig sd_data_xfer_trig0 (
.sd_clk (sd_clk_o),
.rst (wb_rst_i | software_reset_reg_sd_clk[0]),
.cmd_with_data_start_i (cmd_start_sd_clk & (command_reg_sd_clk[`CMD_WITH_DATA] != 2'b00)),
.r_w_i (command_reg_sd_clk[`CMD_WITH_DATA] == 2'b01),
.cmd_int_status_i (cmd_int_status_reg_sd_clk),
.start_tx_o (data_start_tx),
.start_rx_o (data_start_rx)
);
sd_controller_wb sd_controller_wb0(
.wb_clk_i (wb_clk_i),
.wb_rst_i (wb_rst_i),
.wb_dat_i (wb_dat_i),
.wb_dat_o (wb_dat_o),
.wb_adr_i (wb_adr_i),
.wb_sel_i (wb_sel_i),
.wb_we_i (wb_we_i),
.wb_stb_i (wb_stb_i),
.wb_cyc_i (wb_cyc_i),
.wb_ack_o (wb_ack_o),
.cmd_start (cmd_start),
.data_int_rst (data_int_rst),
.cmd_int_rst (cmd_int_rst),
.argument_reg (argument_reg_wb_clk),
.command_reg (command_reg_wb_clk),
.response_0_reg (response_0_reg_wb_clk),
.response_1_reg (response_1_reg_wb_clk),
.response_2_reg (response_2_reg_wb_clk),
.response_3_reg (response_3_reg_wb_clk),
.software_reset_reg (software_reset_reg_wb_clk),
.timeout_reg (timeout_reg_wb_clk),
.block_size_reg (block_size_reg_wb_clk),
.controll_setting_reg (controll_setting_reg_wb_clk),
.cmd_int_status_reg (cmd_int_status_reg_wb_clk),
.cmd_int_enable_reg (cmd_int_enable_reg_wb_clk),
.clock_divider_reg (clock_divider_reg_wb_clk),
.block_count_reg (block_count_reg_wb_clk),
.dma_addr_reg (dma_addr_reg_wb_clk),
.data_int_status_reg (data_int_status_reg_wb_clk),
.data_int_enable_reg (data_int_enable_reg_wb_clk)
);
//clock domain crossing regiters
//assign cmd_start_sd_clk = cmd_start_wb_clk;
//assign data_int_rst_sd_clk = data_int_rst_wb_clk;
//assign cmd_int_rst_sd_clk = cmd_int_rst_wb_clk;
//assign argument_reg_sd_clk = argument_reg_wb_clk;
//assign command_reg_sd_clk = command_reg_wb_clk;
//assign response_0_reg_wb_clk = response_0_reg_sd_clk;
//assign response_1_reg_wb_clk = response_1_reg_sd_clk;
//assign response_2_reg_wb_clk = response_2_reg_sd_clk;
//assign response_3_reg_wb_clk = response_3_reg_sd_clk;
//assign software_reset_reg_sd_clk = software_reset_reg_wb_clk;
//assign timeout_reg_sd_clk = timeout_reg_wb_clk;
//assign block_size_reg_sd_clk = block_size_reg_wb_clk;
//assign controll_setting_reg_sd_clk = controll_setting_reg_wb_clk;
//assign cmd_int_status_reg_wb_clk = cmd_int_status_reg_sd_clk;
//assign cmd_int_enable_reg_sd_clk = cmd_int_enable_reg_wb_clk;
//assign clock_divider_reg_sd_clk = clock_divider_reg_wb_clk;
//assign block_count_reg_sd_clk = block_count_reg_wb_clk;
//assign dma_addr_reg_sd_clk = dma_addr_reg_wb_clk;
//assign data_int_status_reg_wb_clk = data_int_status_reg_sd_clk;
//assign data_int_enable_reg_sd_clk = data_int_enable_reg_wb_clk;
edge_detect cmd_start_edge(.rst(wb_rst_i), .clk(wb_clk_i), .sig(cmd_start), .rise(cmd_start_wb_clk), .fall());
edge_detect data_int_rst_edge(.rst(wb_rst_i), .clk(wb_clk_i), .sig(data_int_rst), .rise(data_int_rst_wb_clk), .fall());
edge_detect cmd_int_rst_edge(.rst(wb_rst_i), .clk(wb_clk_i), .sig(cmd_int_rst), .rise(cmd_int_rst_wb_clk), .fall());
monostable_domain_cross cmd_start_cross(wb_rst_i, wb_clk_i, cmd_start_wb_clk, sd_clk_o, cmd_start_sd_clk);
monostable_domain_cross data_int_rst_cross(wb_rst_i, wb_clk_i, data_int_rst_wb_clk, sd_clk_o, data_int_rst_sd_clk);
monostable_domain_cross cmd_int_rst_cross(wb_rst_i, wb_clk_i, cmd_int_rst_wb_clk, sd_clk_o, cmd_int_rst_sd_clk);
bistable_domain_cross #(32) argument_reg_cross(wb_rst_i, wb_clk_i, argument_reg_wb_clk, sd_clk_o, argument_reg_sd_clk);
bistable_domain_cross #(`CMD_REG_SIZE) command_reg_cross(wb_rst_i, wb_clk_i, command_reg_wb_clk, sd_clk_o, command_reg_sd_clk);
bistable_domain_cross #(32) response_0_reg_cross(wb_rst_i, sd_clk_o, response_0_reg_sd_clk, wb_clk_i, response_0_reg_wb_clk);
bistable_domain_cross #(32) response_1_reg_cross(wb_rst_i, sd_clk_o, response_1_reg_sd_clk, wb_clk_i, response_1_reg_wb_clk);
bistable_domain_cross #(32) response_2_reg_cross(wb_rst_i, sd_clk_o, response_2_reg_sd_clk, wb_clk_i, response_2_reg_wb_clk);
bistable_domain_cross #(32) response_3_reg_cross(wb_rst_i, sd_clk_o, response_3_reg_sd_clk, wb_clk_i, response_3_reg_wb_clk);
bistable_domain_cross software_reset_reg_cross(wb_rst_i, wb_clk_i, software_reset_reg_wb_clk, sd_clk_o, software_reset_reg_sd_clk);
bistable_domain_cross #(16) timeout_reg_cross(wb_rst_i, wb_clk_i, timeout_reg_wb_clk, sd_clk_o, timeout_reg_sd_clk);
bistable_domain_cross #(`BLKSIZE_W) block_size_reg_cross(wb_rst_i, wb_clk_i, block_size_reg_wb_clk, sd_clk_o, block_size_reg_sd_clk);
bistable_domain_cross #(16) controll_setting_reg_cross(wb_rst_i, wb_clk_i, controll_setting_reg_wb_clk, sd_clk_o, controll_setting_reg_sd_clk);
bistable_domain_cross #(`INT_CMD_SIZE) cmd_int_status_reg_cross(wb_rst_i, sd_clk_o, cmd_int_status_reg_sd_clk, wb_clk_i, cmd_int_status_reg_wb_clk);
bistable_domain_cross #(`INT_CMD_SIZE) cmd_int_enable_reg_cross(wb_rst_i, wb_clk_i, cmd_int_enable_reg_wb_clk, sd_clk_o, cmd_int_enable_reg_sd_clk);
bistable_domain_cross #(8) clock_divider_reg_cross(wb_rst_i, wb_clk_i, clock_divider_reg_wb_clk, sd_clk_i_pad, clock_divider_reg_sd_clk);
bistable_domain_cross #(`BLKCNT_W) block_count_reg_cross(wb_rst_i, wb_clk_i, block_count_reg_wb_clk, sd_clk_o, block_count_reg_sd_clk);
bistable_domain_cross #(32) dma_addr_reg_cross(wb_rst_i, wb_clk_i, dma_addr_reg_wb_clk, sd_clk_o, dma_addr_reg_sd_clk);
bistable_domain_cross #(`INT_DATA_SIZE) data_int_status_reg_cross(wb_rst_i, sd_clk_o, data_int_status_reg_sd_clk, wb_clk_i, data_int_status_reg_wb_clk);
bistable_domain_cross #(`INT_DATA_SIZE) data_int_enable_reg_cross(wb_rst_i, wb_clk_i, data_int_enable_reg_wb_clk, sd_clk_o, data_int_enable_reg_sd_clk);
assign m_wb_cti_o = 3'b000;
assign m_wb_bte_o = 2'b00;
assign int_cmd = |(cmd_int_status_reg_wb_clk & cmd_int_enable_reg_wb_clk);
assign int_data = |(data_int_status_reg_wb_clk & data_int_enable_reg_wb_clk);
assign m_wb_sel_o = 4'b1111;
endmodule