mirror of https://github.com/lnis-uofu/SOFA.git
412 lines
19 KiB
Verilog
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
|