From: Luke Kenneth Casson Leighton Date: Sat, 21 Jul 2018 10:52:58 +0000 (+0100) Subject: add verilog sd-wishbone X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=33f8a649562f120870000bcc96aece02b96c1ed7;p=pinmux.git add verilog sd-wishbone --- diff --git a/src/bsv/bsv_lib/sd/sd.tgz b/src/bsv/bsv_lib/sd/sd.tgz new file mode 100644 index 0000000..120aa40 Binary files /dev/null and b/src/bsv/bsv_lib/sd/sd.tgz differ diff --git a/src/bsv/bsv_lib/sd/sd_bus.sv b/src/bsv/bsv_lib/sd/sd_bus.sv new file mode 100644 index 0000000..220a31b --- /dev/null +++ b/src/bsv/bsv_lib/sd/sd_bus.sv @@ -0,0 +1,201 @@ +// Copyright 2017 University of Cambridge. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// See LICENSE for license details. + +`default_nettype none + + module sd_bus( + input msoc_clk, + input sd_clk, + input rstn, + input [31:0] core_lsu_addr, + input wire [31:0] core_lsu_wdata, + input core_sd_we, + input wire sd_detect, + input wire [3:0] fifo_status, + input wire [31:0] rx_fifo_status, + input wire [31:0] tx_fifo_status, + input wire [31:0] data_out_tx_fifo, + input sd_cmd_to_host, + input [3:0] sd_dat_to_host, + //---------------Output ports--------------- + output reg [31:0] sd_cmd_resp_sel, + output wire [31:0] data_in_rx_fifo, + output tx_rd_fifo, + output rx_wr_fifo, + output wire [12:0] sd_transf_cnt, + output reg sd_reset, + output reg [7:0] clock_divider_sd_clk, + output reg sd_data_rst, + output reg sd_clk_rst, + output reg sd_cmd_oe, + output reg sd_cmd_to_mem, + output reg sd_dat_oe, + output reg [3:0] sd_dat_to_mem, + output wire [31:0] sd_status + ); + wire sd_cmd_oe_pos; + wire sd_cmd_to_mem_pos; + wire sd_dat_oe_pos; + wire [3:0] sd_dat_to_mem_pos; + + reg sd_cmd_to_host_dly; + reg [3:0] sd_dat_to_host_dly; + + wire [133:0] sd_cmd_response; + wire [31:0] sd_cmd_wait, sd_data_wait; + wire [6:0] sd_cmd_crc_val; + wire [47:0] sd_cmd_packet; + wire sd_cmd_finish, sd_data_finish, sd_cmd_crc_ok, sd_cmd_index_ok; + wire [4:0] sd_data_crc_s; + wire [3:0] sd_data_crc_lane_ok; + wire [15:0] sd_crc_din[3:0]; + wire [15:0] sd_crc_calc[3:0]; + + reg [2:0] sd_data_start; + reg [11:0] sd_blksize; + + reg [2:0] sd_cmd_setting; + reg [5:0] sd_cmd_i; + reg [31:0] sd_cmd_arg; + reg [31:0] sd_cmd_timeout; + reg sd_cmd_start, sd_cmd_rst, dmy; + wire [5:0] sd_cmd_state; + wire [6:0] sd_data_state; + +always @(negedge sd_clk or negedge rstn) + if (rstn == 0) + begin + sd_cmd_oe <= 1'b0; + sd_cmd_to_mem <= 1'b0; + sd_dat_oe <= 1'b0; + sd_dat_to_mem <= 4'b0; + end + else + begin + sd_cmd_oe <= sd_cmd_oe_pos; + sd_cmd_to_mem <= sd_cmd_to_mem_pos; + sd_dat_oe <= sd_dat_oe_pos; + sd_dat_to_mem <= sd_dat_to_mem_pos; + end // else: !if(!rstn) + + always @(posedge msoc_clk or negedge rstn) + if (rstn == 0) + begin + sd_blksize <= 0; + sd_data_start <= 0; + clock_divider_sd_clk <= 0; + sd_cmd_i <= 0; + sd_cmd_arg <= 0; + sd_cmd_setting <= 0; + sd_cmd_start <= 0; + sd_reset <= 0; + sd_data_rst <= 0; + sd_cmd_rst <= 0; + sd_clk_rst <= 0; + sd_cmd_timeout <= 15; + end + else + begin + if (core_sd_we) + case(core_lsu_addr[5:2]) + 1: clock_divider_sd_clk <= core_lsu_wdata[7:0]; + 2: sd_cmd_arg <= core_lsu_wdata; + 3: sd_cmd_i <= core_lsu_wdata[5:0]; + 4: {sd_data_start,sd_cmd_setting} <= core_lsu_wdata[5:0]; + 5: sd_cmd_start <= core_lsu_wdata[0]; + 6: {sd_reset,sd_clk_rst,sd_data_rst,sd_cmd_rst} <= core_lsu_wdata[3:0]; + 8: sd_blksize <= core_lsu_wdata[11:0]; + 9: sd_cmd_timeout <= core_lsu_wdata; + endcase + end + + always_comb + case(core_lsu_addr[6:2]) + 0: sd_cmd_resp_sel = sd_cmd_response[38:7]; + 1: sd_cmd_resp_sel = sd_cmd_response[70:39]; + 2: sd_cmd_resp_sel = sd_cmd_response[102:71]; + 3: sd_cmd_resp_sel = {1'b0,sd_cmd_response[133:103]}; + 4: sd_cmd_resp_sel = sd_cmd_wait; + 5: sd_cmd_resp_sel = {sd_status[31:4],fifo_status[3:0]}; + 6: sd_cmd_resp_sel = sd_cmd_packet[31:0]; + 7: sd_cmd_resp_sel = {16'b0,sd_cmd_packet[47:32]}; + 8: sd_cmd_resp_sel = sd_data_wait; + 9: sd_cmd_resp_sel = {19'b0,sd_transf_cnt}; + 10: sd_cmd_resp_sel = rx_fifo_status; + 11: sd_cmd_resp_sel = tx_fifo_status; + 12: sd_cmd_resp_sel = {31'b0,sd_detect}; + 13: sd_cmd_resp_sel = {26'b0,sd_cmd_state}; + 14: sd_cmd_resp_sel = {25'b0,sd_data_state}; + 15: sd_cmd_resp_sel = {23'b0,sd_data_crc_s,sd_data_crc_lane_ok}; + 16: sd_cmd_resp_sel = {32'b0}; + 17: sd_cmd_resp_sel = {24'b0,clock_divider_sd_clk}; + 18: sd_cmd_resp_sel = sd_cmd_arg; + 19: sd_cmd_resp_sel = {26'b0,sd_cmd_i}; + 20: sd_cmd_resp_sel = {26'b0,sd_data_start,sd_cmd_setting[2:0]}; + 21: sd_cmd_resp_sel = {31'b0,sd_cmd_start}; + 22: sd_cmd_resp_sel = {28'b0,sd_reset,sd_clk_rst,sd_data_rst,sd_cmd_rst}; + 23: sd_cmd_resp_sel = {32'b1}; + 24: sd_cmd_resp_sel = {20'b0,sd_blksize}; + 25: sd_cmd_resp_sel = sd_cmd_timeout; + 26: sd_cmd_resp_sel = {sd_crc_din[1],sd_crc_din[0]}; + 27: sd_cmd_resp_sel = {sd_crc_din[3],sd_crc_din[2]}; + 28: sd_cmd_resp_sel = {sd_crc_calc[1],sd_crc_calc[0]}; + 29: sd_cmd_resp_sel = {sd_crc_calc[3],sd_crc_calc[2]}; + default: sd_cmd_resp_sel = 32'HDEADBEEF; + endcase // case (core_lsu_addr[6:2]) + + sd_top sdtop( + .sd_clk (sd_clk), + .cmd_rst (~(sd_cmd_rst&rstn)), + .data_rst (~(sd_data_rst&rstn)), + .setting_i (sd_cmd_setting), + .timeout_i (sd_cmd_timeout), + .cmd_i (sd_cmd_i), + .arg_i (sd_cmd_arg), + .start_i (sd_cmd_start), + .sd_data_start_i(sd_data_start), + .sd_blksize_i(sd_blksize), + .sd_data_i(data_out_tx_fifo), + .sd_dat_to_host(sd_dat_to_host), + .sd_cmd_to_host(sd_cmd_to_host), + .finish_cmd_o(sd_cmd_finish), + .finish_data_o(sd_data_finish), + .response0_o(sd_cmd_response[38:7]), + .response1_o(sd_cmd_response[70:39]), + .response2_o(sd_cmd_response[102:71]), + .response3_o(sd_cmd_response[133:103]), + .crc_ok_o (sd_cmd_crc_ok), + .index_ok_o (sd_cmd_index_ok), + .sd_transf_cnt(sd_transf_cnt), + .wait_o(sd_cmd_wait), + .wait_data_o(sd_data_wait), + .status_o(sd_status[31:4]), + .packet0_o(sd_cmd_packet[31:0]), + .packet1_o(sd_cmd_packet[47:32]), + .crc_val_o(sd_cmd_crc_val), + .crc_actual_o(sd_cmd_response[6:0]), + .sd_rd_o(tx_rd_fifo), + .sd_we_o(rx_wr_fifo), + .sd_data_o(data_in_rx_fifo), + .sd_dat_to_mem(sd_dat_to_mem_pos), + .sd_cmd_to_mem(sd_cmd_to_mem_pos), + .sd_dat_oe(sd_dat_oe_pos), + .sd_cmd_oe(sd_cmd_oe_pos), + .sd_cmd_state(sd_cmd_state), + .sd_data_state(sd_data_state), + .sd_data_crc_s(sd_data_crc_s), + .sd_data_crc_lane_ok(sd_data_crc_lane_ok), + .sd_crc_din(sd_crc_din), + .sd_crc_calc(sd_crc_calc) + ); + +endmodule // chip_top +`default_nettype wire diff --git a/src/bsv/bsv_lib/sd/sd_clock_divider.v b/src/bsv/bsv_lib/sd/sd_clock_divider.v new file mode 100644 index 0000000..147ff5d --- /dev/null +++ b/src/bsv/bsv_lib/sd/sd_clock_divider.v @@ -0,0 +1,81 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// WISHBONE SD Card Controller IP Core //// +//// //// +//// sd_clock_divider.v //// +//// //// +//// This file is part of the WISHBONE SD Card //// +//// Controller IP Core project //// +//// http://opencores.org/project,sd_card_controller //// +//// //// +//// Description //// +//// Control of sd card clock rate //// +//// //// +//// 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 //// +//// //// +////////////////////////////////////////////////////////////////////// + +module sd_clock_divider ( + input CLK, + input [7:0] DIVIDER, + input RST, + output SD_CLK + ); + + reg [7:0] ClockDiv; + reg SD_CLK_O; + + BUFG SD_CLK_buf_inst ( + .O(SD_CLK), // 1-bit output: Clock output + .I(SD_CLK_O) // 1-bit input: Clock input + ); + + always @(posedge CLK or posedge RST) + begin + if (RST) begin + ClockDiv <= 8'b0000_0000; + SD_CLK_O <= 0; + end + else if (ClockDiv == DIVIDER) begin + ClockDiv <= 0; + SD_CLK_O <= ~SD_CLK_O; + end else begin + ClockDiv <= ClockDiv + 8'h1; + SD_CLK_O <= SD_CLK_O; + end + end + +endmodule + + diff --git a/src/bsv/bsv_lib/sd/sd_cmd_serial_host.v b/src/bsv/bsv_lib/sd/sd_cmd_serial_host.v new file mode 100644 index 0000000..692b238 --- /dev/null +++ b/src/bsv/bsv_lib/sd/sd_cmd_serial_host.v @@ -0,0 +1,329 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// WISHBONE SD Card Controller IP Core //// +//// //// +//// sd_cmd_serial_host.v //// +//// //// +//// This file is part of the WISHBONE SD Card //// +//// Controller IP Core project //// +//// http://opencores.org/project,sd_card_controller //// +//// //// +//// Description //// +//// Module resposible for sending and receiving commands //// +//// through 1-bit sd card command interface //// +//// //// +//// 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 //// +//// //// +////////////////////////////////////////////////////////////////////// + +module sd_cmd_serial_host ( + sd_clk, + rst, + setting_i, + cmd_i, + start_i, + timeout_i, + response_o, + crc_ok_o, + index_ok_o, + finish_o, + wait_reg_o, + crc_val_o, + packet_o, + start_data_o, + cmd_dat_i, + cmd_out_o, + cmd_oe_o + ); + +//-------------Internal Constant------------- +parameter INIT_DELAY = 74; +parameter BITS_TO_SEND = 48; +parameter CMD_SIZE = 40; +parameter RESP_SIZE_LONG = 127; +parameter RESP_SIZE_SHORT = 39; +//---------------Input ports--------------- +input wire sd_clk; +input wire rst; +input [2:0] setting_i; +input [37:0] cmd_i; +input wire start_i; +input wire cmd_dat_i; +input [31:0] timeout_i; +//---------------Output ports--------------- +output reg [BITS_TO_SEND-1:0] packet_o; +output reg [RESP_SIZE_LONG+6:0] response_o; +output reg finish_o; +output reg crc_ok_o; +output reg index_ok_o; +output reg cmd_oe_o; +output reg cmd_out_o; +output reg start_data_o; +output wire [6:0] crc_val_o; +output reg [31:0] wait_reg_o; +//---------------Internal variable----------- + reg [CMD_SIZE-1:0] cmd_buff; + reg cmd_dat_reg; + reg [7:0] resp_len; + reg with_response, with_data; + +//CRC +reg crc_rst; +reg crc_enable; +reg crc_bit; +//-Internal Counterns +reg [7:0] counter; +//-State Machine +parameter STATE_SIZE = 6; +parameter + INIT = 6'h00, + IDLE = 6'h01, + SETUP_CRC = 6'h02, + WRITE = 6'h04, + READ_WAIT = 6'h08, + READ = 6'h10, + FINISH_RD_WR = 6'h20; +reg [STATE_SIZE-1:0] state; +reg [STATE_SIZE-1:0] next_state; + +//------------------------------------------ +sd_crc_7 CRC_7( + crc_bit, + crc_enable, + sd_clk, + crc_rst, + crc_val_o); + +//------------------------------------------ +always @(state or counter or start_i or with_response or cmd_dat_reg or resp_len or timeout_i or wait_reg_o) +begin: FSM_COMBO + case(state) + INIT: begin + if (counter >= INIT_DELAY) begin + next_state = IDLE; + end + else begin + next_state = INIT; + end + end + IDLE: begin + if (start_i) begin + next_state = SETUP_CRC; + end + else begin + next_state = IDLE; + end + end + SETUP_CRC: + next_state = WRITE; + WRITE: + if (counter >= BITS_TO_SEND && with_response) begin + next_state = READ_WAIT; + end + else if (counter >= BITS_TO_SEND) begin + next_state = FINISH_RD_WR; + end + else begin + next_state = WRITE; + end + READ_WAIT: + if ((wait_reg_o >= 3) && !cmd_dat_reg) begin // allow time for bus to change direction + next_state = READ; + end + else if (wait_reg_o >= timeout_i) begin // prevent hang if card did not respond + next_state = FINISH_RD_WR; + end + else begin + next_state = READ_WAIT; + end + READ: + if (counter >= resp_len+8) begin + next_state = FINISH_RD_WR; + end + else begin + next_state = READ; + end + FINISH_RD_WR: + if (start_i) + next_state = FINISH_RD_WR; + else + next_state = IDLE; + default: + next_state = INIT; + endcase +end + +always @(posedge sd_clk or posedge rst) +begin: COMMAND_DECODER + if (rst) begin + resp_len <= 0; + with_response <= 0; + with_data <= 0; + cmd_buff <= 0; + end + else begin + if (start_i == 1) begin + resp_len <= setting_i[1] ? RESP_SIZE_LONG : RESP_SIZE_SHORT; + with_response <= setting_i[0]; + with_data <= setting_i[2]; + cmd_buff <= {2'b01,cmd_i}; + end + end +end + +//----------------Seq logic------------ +always @(posedge sd_clk or posedge rst) +begin: FSM_SEQ + if (rst) begin + state <= INIT; + end + else begin + state <= next_state; + end +end + +//-------------OUTPUT_LOGIC------- +always @(posedge sd_clk or posedge rst) +begin: FSM_OUT + if (rst) begin + crc_enable <= 0; + cmd_oe_o = 1; + cmd_out_o = 1; + response_o <= 0; + finish_o <= 0; + crc_rst <= 1; + crc_bit <= 0; + index_ok_o <= 0; + crc_ok_o <= 0; + counter <= 0; + cmd_dat_reg <= 0; + packet_o <= 0; + start_data_o <= 0; + wait_reg_o <= 0; + end + else begin + case(state) + INIT: begin + counter <= counter+1; + cmd_oe_o = 1; + cmd_out_o = 1; + end + IDLE: begin + cmd_oe_o = 0; //Put CMD to Z + counter <= 0; + crc_rst <= 1; + crc_enable <= 0; + index_ok_o <= 0; + finish_o <= 0; + start_data_o <= 0; + end + SETUP_CRC: begin + crc_rst <= 0; + crc_enable <= 1; + response_o <= 0; + packet_o <= 0; + crc_bit <= cmd_buff[CMD_SIZE-1]; + end + WRITE: begin + cmd_dat_reg <= 1'b1; + if (counter < BITS_TO_SEND-8) begin // 1->40 CMD, (41 >= CNT && CNT <=47) CRC, 48 stop_bit + cmd_oe_o = 1; + cmd_out_o = cmd_buff[CMD_SIZE-1-counter]; + if (counter < BITS_TO_SEND-9) begin //1 step ahead + crc_bit <= cmd_buff[CMD_SIZE-2-counter]; + end else begin + crc_enable <= 0; + end + end + else if (counter < BITS_TO_SEND-1) begin + cmd_oe_o = 1; + crc_enable <= 0; + cmd_out_o = crc_val_o[BITS_TO_SEND-counter-2]; + end + else if (counter == BITS_TO_SEND-1) begin + cmd_oe_o = 1; + cmd_out_o = 1'b1; + end + else begin + cmd_oe_o = 0; + cmd_out_o = 1'b1; + end + counter <= counter+1; + wait_reg_o <= 0; + if (cmd_oe_o) packet_o <= {packet_o[BITS_TO_SEND-2:0],cmd_out_o}; + end + READ_WAIT: begin + cmd_dat_reg <= cmd_dat_i; + crc_enable <= 0; + crc_rst <= 1; + counter <= 1; + cmd_oe_o = 0; + wait_reg_o <= wait_reg_o + 1; + end + READ: begin + cmd_dat_reg <= cmd_dat_i; + crc_rst <= 0; + crc_enable <= (resp_len != RESP_SIZE_LONG || counter > 7); + cmd_oe_o = 0; + if (counter <= resp_len) + crc_bit <= cmd_dat_reg; + else + begin + crc_enable <= 0; + end + if (counter <= resp_len+7) begin + response_o <= {response_o[RESP_SIZE_LONG+5:0],cmd_dat_reg}; + end + else begin + crc_enable <= 0; + crc_ok_o <= (response_o[6:0] == crc_val_o); + start_data_o <= with_data; + end + counter <= counter + 1; + end + FINISH_RD_WR: begin + index_ok_o <= (cmd_buff[37:32] == response_o[125:120]); + finish_o <= 1; + crc_enable <= 0; + counter <= 0; + cmd_oe_o = 0; + end // case: FINISH_RD_WR + default:; + endcase + end +end + +endmodule + + diff --git a/src/bsv/bsv_lib/sd/sd_crc_16.v b/src/bsv/bsv_lib/sd/sd_crc_16.v new file mode 100644 index 0000000..5dbd439 --- /dev/null +++ b/src/bsv/bsv_lib/sd/sd_crc_16.v @@ -0,0 +1,43 @@ +// ========================================================================== +// CRC Generation Unit - Linear Feedback Shift Register implementation +// (c) Kay Gorontzi, GHSi.de, distributed under the terms of LGPL +// ========================================================================== +module sd_crc_16(BITVAL, ENABLE, BITSTRB, CLEAR, CRC); + input BITVAL; // Next input bit + input ENABLE; // Enable calculation + input BITSTRB; // Current bit valid (Clock) + input CLEAR; // Init CRC value + output [15:0] CRC; // Current output CRC value + + reg [15:0] CRC; // We need output registers + wire inv; + + assign inv = BITVAL ^ CRC[15]; // XOR required? + + always @(posedge BITSTRB or posedge CLEAR) begin + if (CLEAR) begin + CRC <= 0; // Init before calculation + end + else begin + if (ENABLE == 1) begin + CRC[15] <= CRC[14]; + CRC[14] <= CRC[13]; + CRC[13] <= CRC[12]; + CRC[12] <= CRC[11] ^ inv; + CRC[11] <= CRC[10]; + CRC[10] <= CRC[9]; + CRC[9] <= CRC[8]; + CRC[8] <= CRC[7]; + CRC[7] <= CRC[6]; + CRC[6] <= CRC[5]; + CRC[5] <= CRC[4] ^ inv; + CRC[4] <= CRC[3]; + CRC[3] <= CRC[2]; + CRC[2] <= CRC[1]; + CRC[1] <= CRC[0]; + CRC[0] <= inv; + end + end + end + +endmodule diff --git a/src/bsv/bsv_lib/sd/sd_crc_7.v b/src/bsv/bsv_lib/sd/sd_crc_7.v new file mode 100644 index 0000000..7cb5bae --- /dev/null +++ b/src/bsv/bsv_lib/sd/sd_crc_7.v @@ -0,0 +1,34 @@ +// ========================================================================== +// CRC Generation Unit - Linear Feedback Shift Register implementation +// (c) Kay Gorontzi, GHSi.de, distributed under the terms of LGPL +// ========================================================================== +module sd_crc_7(BITVAL, ENABLE, BITSTRB, CLEAR, CRC); + input BITVAL; // Next input bit + input ENABLE; // Enable calculation + input BITSTRB; // Current bit valid (Clock) + input CLEAR; // Init CRC value + output [6:0] CRC; // Current output CRC value + + reg [6:0] CRC; // We need output registers + wire inv; + + assign inv = BITVAL ^ CRC[6]; // XOR required? + + always @(posedge BITSTRB or posedge CLEAR) begin + if (CLEAR) begin + CRC <= 0; // Init before calculation + end + else begin + if (ENABLE == 1) begin + CRC[6] <= CRC[5]; + CRC[5] <= CRC[4]; + CRC[4] <= CRC[3]; + CRC[3] <= CRC[2] ^ inv; + CRC[2] <= CRC[1]; + CRC[1] <= CRC[0]; + CRC[0] <= inv; + end + end + end + +endmodule diff --git a/src/bsv/bsv_lib/sd/sd_data_serial_host.sv b/src/bsv/bsv_lib/sd/sd_data_serial_host.sv new file mode 100644 index 0000000..971dc38 --- /dev/null +++ b/src/bsv/bsv_lib/sd/sd_data_serial_host.sv @@ -0,0 +1,334 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// WISHBONE SD Card Controller IP Core //// +//// //// +//// sd_data_serial_host.v //// +//// //// +//// This file is part of the WISHBONE SD Card //// +//// Controller IP Core project //// +//// http://opencores.org/project,sd_card_controller //// +//// //// +//// Description //// +//// Module resposible for sending and receiving data through //// +//// 4-bit sd card data interface //// +//// //// +//// 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 sd_data_serial_host( + input sd_clk, + input rst, + //Tx Fifo + input [31:0] data_in, + output reg rd, + //Rx Fifo + output reg [31:0] data_out, + output reg we, + //tristate data + output reg DAT_oe_o, + output reg [3:0] DAT_dat_o, + input [3:0] DAT_dat_i, + //Control signals + input [`BLKSIZE_W-1:0] blksize, + input bus_4bit, + input [`BLKCNT_W-1:0] blkcnt, + input [1:0] start, + input [1:0] byte_alignment, + input [31:0] timeout_i, + output sd_data_busy, + output busy, + output crc_ok, + output reg finish_o, + output reg [31:0] wait_reg_o, + output reg [`BLKSIZE_W-1+4:0] transf_cnt_o + ); + +reg [4:0] crc_s; +reg [3:0] crc_lane_ok; +reg [15:0] crc_din[3:0]; +wire [15:0] crc_calc[3:0]; +reg [31:0] data_out0; +reg we0; +reg [3:0] DAT_dat_reg; +reg [`BLKSIZE_W-1+4:0] data_cycles; +reg bus_4bit_reg; +//CRC16 + reg [4:0] crc_in; +reg crc_rst; +parameter SIZE = 7; +reg [SIZE-1:0] state; +reg [SIZE-1:0] next_state; +parameter IDLE = 7'b0000001; +parameter WRITE_DAT = 7'b0000010; +parameter WRITE_CRC = 7'b0000100; +parameter WRITE_BUSY = 7'b0001000; +parameter READ_WAIT = 7'b0010000; +parameter READ_DAT = 7'b0100000; +parameter FINISH = 7'b1000000; +reg [2:0] crc_status; +reg busy_int; +reg [`BLKSIZE_W-1:0] blksize_reg; +reg [4:0] crc_c; + reg [3:0] crnt_din; +reg [4:0] data_index; + + integer k; +genvar i; +generate + for(i=0; i<4; i=i+1) begin: CRC_16_gen + sd_crc_16 CRC_16_i (crc_in[i], crc_in[4], ~sd_clk, crc_rst, crc_calc[i]); + end +endgenerate + +assign busy = (state != IDLE) && (state != FINISH); +assign sd_data_busy = !DAT_dat_reg[0]; +assign crc_ok = &crc_lane_ok; + +always @(posedge sd_clk or posedge rst) +begin: FSM_OUT + if (rst) begin + state <= IDLE; + DAT_oe_o <= 0; + crc_in <= 0; + crc_rst <= 1; + transf_cnt_o <= 0; + crc_c <= 15; + rd <= 0; + crc_c <= 0; + DAT_dat_o <= 0; + crc_status <= 0; + crc_lane_ok <= 0; + crc_s <= 0; + we0 <= 0; + we <= 0; + data_out0 <= 0; + busy_int <= 0; + data_index <= 0; + data_cycles <= 0; + bus_4bit_reg <= 0; + wait_reg_o <= 0; + finish_o <= 0; + DAT_dat_reg <= 0; + data_out <= 0; + transf_cnt_o <= 0; + end + else begin + // sd data input pad register + DAT_dat_reg <= DAT_dat_i; + crnt_din = 4'hf; + if (we0) data_out <= data_out0; + we <= we0; + case(state) + IDLE: begin + for (k = 0; k < 4; k=k+1) + crc_din[k] <= 0; + DAT_oe_o <= 0; + DAT_dat_o <= 4'b1111; + crc_in <= 0; + crc_rst <= 1; + transf_cnt_o <= 0; + crc_c <= 16; + crc_status <= 0; + crc_lane_ok <= 0; + crc_s <= 0; + we0 <= 0; + rd <= 0; + data_index <= 0; + blksize_reg <= blksize; + data_cycles <= (bus_4bit ? {2'b0,blksize,1'b0} + 'd2 : {blksize,3'b0} + 'd8); + bus_4bit_reg <= bus_4bit; + wait_reg_o <= 0; + finish_o <= 0; + data_out <= 0; + if (start == 2'b01) + state <= WRITE_DAT; + else if (start == 2'b10) + state <= READ_WAIT; + end + WRITE_DAT: begin + transf_cnt_o <= transf_cnt_o + 16'h1; + rd <= 0; + //special case + if (transf_cnt_o == 0) begin + crc_rst <= 0; + data_index <= 0; + crnt_din = bus_4bit_reg ? 4'h0 : 4'he; + rd <= 1; + DAT_oe_o <= 1; + DAT_dat_o <= crnt_din; + end + else if (transf_cnt_o < data_cycles+16) begin /* send the write data */ + if (bus_4bit_reg) begin + crnt_din = { + data_in[31-({data_index[2:0],2'b00})], + data_in[30-({data_index[2:0],2'b00})], + data_in[29-({data_index[2:0],2'b00})], + data_in[28-({data_index[2:0],2'b00})] + }; + if (data_index[2:0] == 3'h7 && transf_cnt_o < data_cycles-2) begin + begin + rd <= 1; + end + end + end + else begin + crnt_din = {3'h7, data_in[31-data_index]}; + if (data_index == 29/*not 31 - read delay !!!*/) begin + begin + rd <= 1; + end + end + end + data_index <= data_index + 5'h1; + if (transf_cnt_o < data_cycles-1) + begin + crc_in <= {1'b1,crnt_din}; + DAT_dat_o <= crnt_din; + end + else if (crc_c!=0) begin /* send the CRC */ + crc_in <= 0; + crc_c <= crc_c - 5'h1; + DAT_oe_o <= 1; + DAT_dat_o[0] <= crc_calc[0][crc_c-1]; + if (bus_4bit_reg) + DAT_dat_o[3:1] <= {crc_calc[3][crc_c-1], crc_calc[2][crc_c-1], crc_calc[1][crc_c-1]}; + else + DAT_dat_o[3:1] <= {3'h7}; + end + else /* send the stop bit */ + begin + crc_in <= 0; + DAT_oe_o <= 1; + DAT_dat_o <= 4'hf; + end + end + else begin /* wait for write ack */ + DAT_oe_o <= 0; + crc_s[4] <= DAT_dat_reg[0]; + if (!DAT_dat_reg[0]) + state <= WRITE_CRC; + end + end + WRITE_CRC: begin /* get write ack */ + DAT_oe_o <= 0; + crc_status <= crc_status + 3'h1; + crc_s[3-crc_status[1:0]] <= DAT_dat_reg[0]; + busy_int <= 1; + if (crc_status == 3) + state <= WRITE_BUSY; + end + WRITE_BUSY: begin /* wait for write completion */ + busy_int <= !DAT_dat_reg[0]; + if (!busy_int) + state <= FINISH; + end + READ_WAIT: begin /* wait for a start bit in read mode */ + DAT_oe_o <= 0; + crc_rst <= 0; + crc_in <= 0; + crc_c <= 15;// end + transf_cnt_o <= 0; + data_index <= 0; + wait_reg_o <= wait_reg_o + 1; + if ((wait_reg_o >= 3) && !DAT_dat_reg[0]) begin // allow time for bus to change direction + state <= READ_DAT; + end + else if (wait_reg_o >= timeout_i) begin // prevent hang if card did not respond + state <= FINISH; + end + end + READ_DAT: begin /* read the data and calculate CRC */ + we0 <= 0; + if (transf_cnt_o < data_cycles-2) begin + if (bus_4bit_reg) begin + if (&data_index[2:0]) + begin + we0 <= 1; + end; + data_out0[31-({data_index[2:0],2'b00})] <= DAT_dat_reg[3]; + data_out0[30-({data_index[2:0],2'b00})] <= DAT_dat_reg[2]; + data_out0[29-({data_index[2:0],2'b00})] <= DAT_dat_reg[1]; + data_out0[28-({data_index[2:0],2'b00})] <= DAT_dat_reg[0]; + end + else begin + if (&data_index) + begin + we0 <= 1; + end; + data_out0[31-data_index] <= DAT_dat_reg[0]; + end + data_index <= data_index + 5'h1; + crc_in <= {1'b1,DAT_dat_reg}; + transf_cnt_o <= transf_cnt_o + 16'h1; + end + else if (crc_c != 5'h1f) begin + for (k = 0; k < 4; k=k+1) + begin + crc_din[k][crc_c[3:0]] <= DAT_dat_reg[k]; + end + transf_cnt_o <= transf_cnt_o + 16'h1; + crc_in <= 0; + we0 <=0; + crc_c <= crc_c - 5'h1; + end + else + begin + for (k = 0; k < 4; k=k+1) + crc_lane_ok[k] <= crc_calc[k] == crc_din[k]; + state <= FINISH; + end + end // case: READ_DAT + FINISH: + begin + finish_o <= 1; + if (start == 2'b00) + state <= IDLE; + end + default: + state <= IDLE; + endcase; // case (state) + //abort + if (start == 2'b11) + state <= IDLE; + end +end + +endmodule + + + + + diff --git a/src/bsv/bsv_lib/sd/sd_defines.h b/src/bsv/bsv_lib/sd/sd_defines.h new file mode 100644 index 0000000..87d8133 --- /dev/null +++ b/src/bsv/bsv_lib/sd/sd_defines.h @@ -0,0 +1,105 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// WISHBONE SD Card Controller IP Core //// +//// //// +//// sd_defines.h //// +//// //// +//// This file is part of the WISHBONE SD Card //// +//// Controller IP Core project //// +//// http://opencores.org/project,sd_card_controller //// +//// //// +//// Description //// +//// Header file with common definitions //// +//// //// +//// 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 //// +//// //// +////////////////////////////////////////////////////////////////////// + +//global defines +`define BLKSIZE_W 12 +`define BLKCNT_W 16 +`define CMD_TIMEOUT_W 24 +`define DATA_TIMEOUT_W 24 + +//cmd module interrupts +`define INT_CMD_SIZE 5 +`define INT_CMD_CC 0 +`define INT_CMD_EI 1 +`define INT_CMD_CTE 2 +`define INT_CMD_CCRCE 3 +`define INT_CMD_CIE 4 + +//data module interrupts +`define INT_DATA_SIZE 5 +`define INT_DATA_CC 0 +`define INT_DATA_EI 1 +`define INT_DATA_CTE 2 +`define INT_DATA_CCRCE 3 +`define INT_DATA_CFE 4 + +//command register defines +`define CMD_REG_SIZE 14 +`define CMD_RESPONSE_CHECK 1:0 +`define CMD_BUSY_CHECK 2 +`define CMD_CRC_CHECK 3 +`define CMD_IDX_CHECK 4 +`define CMD_WITH_DATA 6:5 +`define CMD_INDEX 13:8 + +//register addreses +`define argument 8'h00 +`define command 8'h04 +`define resp0 8'h08 +`define resp1 8'h0c +`define resp2 8'h10 +`define resp3 8'h14 +`define data_timeout 8'h18 +`define controller 8'h1c +`define cmd_timeout 8'h20 +`define clock_d 8'h24 +`define reset 8'h28 +`define voltage 8'h2c +`define capa 8'h30 +`define cmd_isr 8'h34 +`define cmd_iser 8'h38 +`define data_isr 8'h3c +`define data_iser 8'h40 +`define blksize 8'h44 +`define blkcnt 8'h48 +`define dst_src_addr 8'h60 + +//wb module defines +`define RESET_BLOCK_SIZE 12'd511 +`define RESET_CLK_DIV 0 +`define SUPPLY_VOLTAGE_mV 3300 diff --git a/src/bsv/bsv_lib/sd/sd_top.sv b/src/bsv/bsv_lib/sd/sd_top.sv new file mode 100644 index 0000000..fad49e3 --- /dev/null +++ b/src/bsv/bsv_lib/sd/sd_top.sv @@ -0,0 +1,174 @@ +// +// (c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved. +// +// This file contains confidential and proprietary information +// of Xilinx, Inc. and is protected under U.S. and +// international copyright and other intellectual property +// laws. +// +// DISCLAIMER +// This disclaimer is not a license and does not grant any +// rights to the materials distributed herewith. Except as +// otherwise provided in a valid license issued to you by +// Xilinx, and to the maximum extent permitted by applicable +// law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND +// WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES +// AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING +// BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON- +// INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and +// (2) Xilinx shall not be liable (whether in contract or tort, +// including negligence, or under any other theory of +// liability) for any loss or damage of any kind or nature +// related to, arising under or in connection with these +// materials, including for any direct, or any indirect, +// special, incidental, or consequential loss or damage +// (including loss of data, profits, goodwill, or any type of +// loss or damage suffered as a result of any action brought +// by a third party) even if such damage or loss was +// reasonably foreseeable or Xilinx had been advised of the +// possibility of the same. +// +// CRITICAL APPLICATIONS +// Xilinx products are not designed or intended to be fail- +// safe, or for use in any application requiring fail-safe +// performance, such as life-support or safety devices or +// systems, Class III medical devices, nuclear facilities, +// applications related to the deployment of airbags, or any +// other applications that could lead to death, personal +// injury, or severe property or environmental damage +// (individually and collectively, "Critical +// Applications"). Customer assumes the sole risk and +// liability of any use of Xilinx products in Critical +// Applications, subject only to applicable laws and +// regulations governing limitations on product liability. +// +// THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS +// PART OF THIS FILE AT ALL TIMES. +// + +// Copyright 2015 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// See LICENSE for license details. + +`default_nettype none + +module sd_top( + input wire sd_clk, + input wire cmd_rst, + input wire data_rst, + input wire [2:0] setting_i, + input wire start_i, + input wire [31:0] arg_i, + input wire [5:0] cmd_i, + input wire [31:0] timeout_i, + input wire [2:0] sd_data_start_i, + input wire [1:0] sd_align_i, + input wire [15:0] sd_blkcnt_i, + input wire [11:0] sd_blksize_i, + input wire [31:0] sd_data_i, + input wire [3:0] sd_dat_to_host, + input wire sd_cmd_to_host, +//---------------Output ports--------------- + output wire [31:0] response0_o, + output wire [63:32] response1_o, + output wire [95:64] response2_o, + output wire [126:96] response3_o, + output wire [31:0] wait_o, + output wire [31:0] wait_data_o, + output wire [31:4] status_o, + output wire [31:0] packet0_o, + output wire [15:0] packet1_o, + output wire [6:0] crc_val_o, + output wire [6:0] crc_actual_o, + output wire finish_cmd_o, + output wire finish_data_o, + output wire crc_ok_o, + output wire index_ok_o, + output wire sd_rd_o, + output wire sd_we_o, + output wire [31:0] sd_data_o, + output wire [15:0] transf_cnt_o, + output wire [3:0] sd_dat_to_mem, + output wire sd_cmd_to_mem, + output wire sd_cmd_oe, + output wire sd_dat_oe, + output reg [8:0] sd_xfr_addr); + + reg sd_cmd_to_host_dly; + reg [3:0] sd_dat_to_host_dly; + + wire start_data; + wire data_crc_ok; + wire sd_busy, sd_data_busy; + + assign status_o = {1'b0,crc_val_o[6:0], + 1'b0,crc_actual_o[6:0], + 5'b0,finish_data_o,sd_data_busy,finish_cmd_o, + index_ok_o,crc_ok_o,data_crc_ok,sd_busy}; + +always @(negedge sd_clk) + begin + if (data_rst) + sd_xfr_addr <= 0; + else + begin + if (sd_rd_o|sd_we_o) + sd_xfr_addr <= sd_xfr_addr + 1; + end + sd_cmd_to_host_dly <= sd_cmd_to_host; + sd_dat_to_host_dly <= sd_dat_to_host; + end + +sd_cmd_serial_host cmd_serial_host0( + .sd_clk (sd_clk), + .rst (cmd_rst), + .setting_i (setting_i), + .cmd_i ({cmd_i,arg_i}), + .start_i (start_i), + .timeout_i (timeout_i), + .finish_o (finish_cmd_o), + .response_o ({response3_o,response2_o,response1_o,response0_o,crc_actual_o}), + .crc_ok_o (crc_ok_o), + .crc_val_o (crc_val_o), + .packet_o ({packet1_o,packet0_o}), + .index_ok_o (index_ok_o), + .wait_reg_o (wait_o), + .start_data_o(start_data), + .cmd_dat_i (sd_cmd_to_host_dly), + .cmd_out_o (sd_cmd_to_mem), + .cmd_oe_o (sd_cmd_oe) + ); + +sd_data_serial_host data_serial_host0( + .sd_clk (sd_clk), + .rst (data_rst), + .data_in (sd_data_i), + .rd (sd_rd_o), + .data_out (sd_data_o), + .we (sd_we_o), + .finish_o (finish_data_o), + .DAT_oe_o (sd_dat_oe), + .DAT_dat_o (sd_dat_to_mem), + .DAT_dat_i (sd_dat_to_host_dly), + .blksize (sd_blksize_i), + .bus_4bit (sd_data_start_i[2]), + .blkcnt (sd_blkcnt_i), + .start (start_data ? sd_data_start_i[1:0] : 2'b00), + .byte_alignment (sd_align_i), + .timeout_i (timeout_i), + .sd_data_busy (sd_data_busy), + .busy (sd_busy), + .wait_reg_o (wait_data_o), + .crc_ok (data_crc_ok), + .transf_cnt_o (transf_cnt_o) + ); + +endmodule // chip_top +`default_nettype wire