From e291609c8440138d4d2ca1a170047f2fcc87336c Mon Sep 17 00:00:00 2001 From: Jacob Pease Date: Tue, 10 Jan 2023 11:19:28 -0600 Subject: [PATCH] Initial commit for the boot process. --- pipelined/config/fpga/wally-config.vh | 4 + .../src/uncore/newsdc/axi_sdc_controller.v | 661 ++++++++++++++++++ pipelined/src/uncore/newsdc/license.txt | 502 +++++++++++++ pipelined/src/uncore/newsdc/sd_cmd_master.v | 152 ++++ .../src/uncore/newsdc/sd_cmd_serial_host.v | 263 +++++++ pipelined/src/uncore/newsdc/sd_data_master.v | 150 ++++ .../src/uncore/newsdc/sd_data_serial_host.v | 311 ++++++++ pipelined/src/uncore/newsdc/sd_defines.h | 91 +++ pipelined/src/uncore/uncore.sv | 2 + tests/custom/boot/Makefile | 112 +++ tests/custom/boot/boot.c | 370 ++++++++++ 11 files changed, 2618 insertions(+) create mode 100644 pipelined/src/uncore/newsdc/axi_sdc_controller.v create mode 100644 pipelined/src/uncore/newsdc/license.txt create mode 100644 pipelined/src/uncore/newsdc/sd_cmd_master.v create mode 100644 pipelined/src/uncore/newsdc/sd_cmd_serial_host.v create mode 100644 pipelined/src/uncore/newsdc/sd_data_master.v create mode 100644 pipelined/src/uncore/newsdc/sd_data_serial_host.v create mode 100644 pipelined/src/uncore/newsdc/sd_defines.h create mode 100644 tests/custom/boot/Makefile create mode 100644 tests/custom/boot/boot.c diff --git a/pipelined/config/fpga/wally-config.vh b/pipelined/config/fpga/wally-config.vh index c786950d..b16721d3 100644 --- a/pipelined/config/fpga/wally-config.vh +++ b/pipelined/config/fpga/wally-config.vh @@ -122,6 +122,10 @@ `define SDC_BASE 56'h00012100 `define SDC_RANGE 56'h0000001F +// Temporary Boot Process Stuff +`define SDC2_BASE 56'h00013000 +`defube SDC2_RANGE 56'h0000007F + // Bus Interface width `define AHBW 64 diff --git a/pipelined/src/uncore/newsdc/axi_sdc_controller.v b/pipelined/src/uncore/newsdc/axi_sdc_controller.v new file mode 100644 index 00000000..989c0588 --- /dev/null +++ b/pipelined/src/uncore/newsdc/axi_sdc_controller.v @@ -0,0 +1,661 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2013-2022 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 https://www.gnu.org/licenses/ //// +//// //// +////////////////////////////////////////////////////////////////////// + +module sdc_controller #( + parameter dma_addr_bits = 32, + parameter fifo_addr_bits = 7, + parameter sdio_card_detect_level = 1, + parameter voltage_controll_reg = 3300, + parameter capabilies_reg = 16'b0000_0000_0000_0011 +) ( + input wire async_resetn, + + (* X_INTERFACE_INFO = "xilinx.com:signal:clock:1.0 clock CLK" *) + (* X_INTERFACE_PARAMETER = "ASSOCIATED_BUSIF M_AXI:S_AXI_LITE, FREQ_HZ 100000000" *) + input wire clock, + + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI_LITE AWADDR" *) + (* X_INTERFACE_PARAMETER = "CLK_DOMAIN clock, ID_WIDTH 0, PROTOCOL AXI4LITE, DATA_WIDTH 32" *) + input wire [15:0] s_axi_awaddr, + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI_LITE AWVALID" *) + input wire s_axi_awvalid, + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI_LITE AWREADY" *) + output wire s_axi_awready, + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI_LITE WDATA" *) + input wire [31:0] s_axi_wdata, + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI_LITE WVALID" *) + input wire s_axi_wvalid, + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI_LITE WREADY" *) + output wire s_axi_wready, + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI_LITE BRESP" *) + output reg [1:0] s_axi_bresp, + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI_LITE BVALID" *) + output reg s_axi_bvalid, + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI_LITE BREADY" *) + input wire s_axi_bready, + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI_LITE ARADDR" *) + input wire [15:0] s_axi_araddr, + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI_LITE ARVALID" *) + input wire s_axi_arvalid, + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI_LITE ARREADY" *) + output wire s_axi_arready, + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI_LITE RDATA" *) + output reg [31:0] s_axi_rdata, + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI_LITE RRESP" *) + output reg [1:0] s_axi_rresp, + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI_LITE RVALID" *) + output reg s_axi_rvalid, + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 S_AXI_LITE RREADY" *) + input wire s_axi_rready, + + (* X_INTERFACE_PARAMETER = "CLK_DOMAIN clock, ID_WIDTH 0, PROTOCOL AXI4, DATA_WIDTH 32" *) + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 M_AXI AWADDR" *) + output reg [dma_addr_bits-1:0] m_axi_awaddr, + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 M_AXI AWLEN" *) + output reg [7:0] m_axi_awlen, + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 M_AXI AWVALID" *) + output reg m_axi_awvalid, + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 M_AXI AWREADY" *) + input wire m_axi_awready, + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 M_AXI WDATA" *) + output wire [31:0] m_axi_wdata, + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 M_AXI WLAST" *) + output reg m_axi_wlast, + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 M_AXI WVALID" *) + output reg m_axi_wvalid, + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 M_AXI WREADY" *) + input wire m_axi_wready, + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 M_AXI BRESP" *) + input wire [1:0] m_axi_bresp, + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 M_AXI BVALID" *) + input wire m_axi_bvalid, + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 M_AXI BREADY" *) + output wire m_axi_bready, + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 M_AXI ARADDR" *) + output reg [dma_addr_bits-1:0] m_axi_araddr, + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 M_AXI ARLEN" *) + output reg [7:0] m_axi_arlen, + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 M_AXI ARVALID" *) + output reg m_axi_arvalid, + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 M_AXI ARREADY" *) + input wire m_axi_arready, + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 M_AXI RDATA" *) + input wire [31:0] m_axi_rdata, + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 M_AXI RLAST" *) + input wire m_axi_rlast, + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 M_AXI RRESP" *) + input wire [1:0] m_axi_rresp, + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 M_AXI RVALID" *) + input wire m_axi_rvalid, + (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 M_AXI RREADY" *) + output wire m_axi_rready, + + // SD BUS + inout wire sdio_cmd, + inout wire [3:0] sdio_dat, + (* X_INTERFACE_INFO = "xilinx.com:signal:clock:1.0 sdio_clk CLK" *) + (* X_INTERFACE_PARAMETER = "FREQ_HZ 50000000" *) + output reg sdio_clk, + (* X_INTERFACE_INFO = "xilinx.com:signal:reset:1.0 sdio_reset RST" *) + (* X_INTERFACE_PARAMETER = "POLARITY ACTIVE_HIGH" *) + output reg sdio_reset, + input wire sdio_cd, + + // Interrupts + output wire interrupt +); + +`include "sd_defines.h" + +wire reset; + +wire go_idle; +reg 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 en_tx_fifo; +wire en_rx_fifo; +wire sd_data_busy; +wire data_busy; +wire data_crc_ok; +wire tx_fifo_re; +wire rx_fifo_we; + +reg data_start_rx; +reg data_start_tx; +reg data_prepare_tx; +reg cmd_int_rst; +reg data_int_rst; +reg ctrl_rst; + +// AXI accessible registers +reg [31:0] argument_reg; +reg [`CMD_REG_SIZE-1:0] command_reg; +reg [`CMD_TIMEOUT_W-1:0] cmd_timeout_reg; +reg [`DATA_TIMEOUT_W-1:0] data_timeout_reg; +reg [0:0] software_reset_reg; +wire [31:0] response_0_reg; +wire [31:0] response_1_reg; +wire [31:0] response_2_reg; +wire [31:0] response_3_reg; +reg [`BLKSIZE_W-1:0] block_size_reg; +reg [1:0] controller_setting_reg; +wire [`INT_CMD_SIZE-1:0] cmd_int_status_reg; +wire [`INT_DATA_SIZE-1:0] data_int_status_reg; +wire [`INT_DATA_SIZE-1:0] data_int_status; +reg [`INT_CMD_SIZE-1:0] cmd_int_enable_reg; +reg [`INT_DATA_SIZE-1:0] data_int_enable_reg; +reg [`BLKCNT_W-1:0] block_count_reg; +reg [dma_addr_bits-1:0] dma_addr_reg; +reg [7:0] clock_divider_reg = 124; // 400KHz + +// ------ Clocks and resets + +(* ASYNC_REG="true" *) +reg [2:0] reset_sync; +assign reset = reset_sync[2]; + +always @(posedge clock) + reset_sync <= {reset_sync[1:0], !async_resetn}; + +reg [7:0] clock_cnt; +reg clock_state; +reg clock_posedge; +reg clock_data_in; +wire fifo_almost_full; +wire fifo_almost_empty; + +always @(posedge clock) begin + if (reset) begin + clock_posedge <= 0; + clock_data_in <= 0; + clock_state <= 0; + clock_cnt <= 0; + end else if (clock_cnt < clock_divider_reg) begin + clock_posedge <= 0; + clock_data_in <= 0; + clock_cnt <= clock_cnt + 1; + end else if (clock_cnt < 124 && data_busy && en_rx_fifo && fifo_almost_full) begin + // Prevent Rx FIFO overflow + clock_posedge <= 0; + clock_data_in <= 0; + clock_cnt <= clock_cnt + 1; + end else if (clock_cnt < 124 && data_busy && en_tx_fifo && fifo_almost_empty) begin + // Prevent Tx FIFO underflow + clock_posedge <= 0; + clock_data_in <= 0; + clock_cnt <= clock_cnt + 1; + end else begin + clock_state <= !clock_state; + clock_posedge <= !clock_state; + if (clock_divider_reg == 0) + clock_data_in <= !clock_state; + else + clock_data_in <= clock_state; + clock_cnt <= 0; + end + sdio_clk <= sdio_reset || clock_state; + + if (reset) sdio_reset <= 0; + else if (clock_posedge) sdio_reset <= controller_setting_reg[1]; +end + +// ------ SD IO Buffers + +wire sd_cmd_i; +wire sd_cmd_o; +wire sd_cmd_oe; +reg sd_cmd_reg_o; +reg sd_cmd_reg_t; +wire [3:0] sd_dat_i; +wire [3:0] sd_dat_o; +wire sd_dat_oe; +reg [3:0] sd_dat_reg_o; +reg sd_dat_reg_t; + +IOBUF IOBUF_cmd (.O(sd_cmd_i), .IO(sdio_cmd), .I(sd_cmd_reg_o), .T(sd_cmd_reg_t)); +IOBUF IOBUF_dat0 (.O(sd_dat_i[0]), .IO(sdio_dat[0]), .I(sd_dat_reg_o[0]), .T(sd_dat_reg_t)); +IOBUF IOBUF_dat1 (.O(sd_dat_i[1]), .IO(sdio_dat[1]), .I(sd_dat_reg_o[1]), .T(sd_dat_reg_t)); +IOBUF IOBUF_dat2 (.O(sd_dat_i[2]), .IO(sdio_dat[2]), .I(sd_dat_reg_o[2]), .T(sd_dat_reg_t)); +IOBUF IOBUF_dat3 (.O(sd_dat_i[3]), .IO(sdio_dat[3]), .I(sd_dat_reg_o[3]), .T(sd_dat_reg_t)); + +always @(negedge clock) begin + // Output data delayed by 1/2 clock cycle (5ns) to ensure + // required hold time: default speed - min 5ns, high speed - min 2ns (actual 5ns) + if (sdio_reset) begin + sd_cmd_reg_o <= 0; + sd_dat_reg_o <= 0; + sd_cmd_reg_t <= 0; + sd_dat_reg_t <= 0; + end else begin + sd_cmd_reg_o <= sd_cmd_o; + sd_dat_reg_o <= sd_dat_o; + sd_cmd_reg_t <= !sd_cmd_oe; + sd_dat_reg_t <= !(sd_dat_oe || (cmd_start_tx && (command_reg == 0))); + end +end + +// ------ SD card detect + +reg [25:0] sd_detect_cnt; +wire sd_insert_int = sd_detect_cnt[25]; +wire sd_remove_int = !sd_detect_cnt[25]; +reg sd_insert_ie; +reg sd_remove_ie; + +always @(posedge clock) begin + if (sdio_cd != sdio_card_detect_level) begin + sd_detect_cnt <= 0; + end else if (!sd_insert_int) begin + sd_detect_cnt <= sd_detect_cnt + 1; + end +end + +// ------ AXI Slave Interface + +reg [15:0] read_addr; +reg [15:0] write_addr; +reg [31:0] write_data; +reg rd_req; +reg [1:0] wr_req; + +assign s_axi_arready = !rd_req && !s_axi_rvalid; +assign s_axi_awready = !wr_req[0] && !s_axi_bvalid; +assign s_axi_wready = !wr_req[1] && !s_axi_bvalid; + +always @(posedge clock) begin + if (reset) begin + s_axi_rdata <= 0; + s_axi_rresp <= 0; + s_axi_rvalid <= 0; + s_axi_bresp <= 0; + s_axi_bvalid <= 0; + rd_req <= 0; + wr_req <= 0; + read_addr <= 0; + write_addr <= 0; + write_data <= 0; + cmd_start <= 0; + data_int_rst <= 0; + cmd_int_rst <= 0; + ctrl_rst <= 0; + argument_reg <= 0; + command_reg <= 0; + cmd_timeout_reg <= 0; + data_timeout_reg <= 0; + block_size_reg <= `RESET_BLOCK_SIZE; + controller_setting_reg <= 0; + cmd_int_enable_reg <= 0; + data_int_enable_reg <= 0; + software_reset_reg <= 0; + clock_divider_reg <= `RESET_CLOCK_DIV; + block_count_reg <= 0; + sd_insert_ie <= 0; + sd_remove_ie <= 0; + dma_addr_reg <= 0; + end else begin + if (clock_posedge) begin + cmd_start <= 0; + data_int_rst <= 0; + cmd_int_rst <= 0; + ctrl_rst <= software_reset_reg[0]; + end + if (s_axi_arready && s_axi_arvalid) begin + read_addr <= s_axi_araddr; + rd_req <= 1; + end + if (s_axi_rvalid && s_axi_rready) begin + s_axi_rvalid <= 0; + end else if (!s_axi_rvalid && rd_req) begin + s_axi_rdata <= 0; + if (read_addr[15:8] == 0) begin + case (read_addr[7:0]) + `argument : s_axi_rdata <= argument_reg; + `command : s_axi_rdata <= command_reg; + `resp0 : s_axi_rdata <= response_0_reg; + `resp1 : s_axi_rdata <= response_1_reg; + `resp2 : s_axi_rdata <= response_2_reg; + `resp3 : s_axi_rdata <= response_3_reg; + `controller : s_axi_rdata <= controller_setting_reg; + `blksize : s_axi_rdata <= block_size_reg; + `voltage : s_axi_rdata <= voltage_controll_reg; + `capa : s_axi_rdata <= capabilies_reg | (dma_addr_bits << 8); + `clock_d : s_axi_rdata <= clock_divider_reg; + `reset : s_axi_rdata <= { cmd_start, data_int_rst, cmd_int_rst, ctrl_rst }; + `cmd_timeout : s_axi_rdata <= cmd_timeout_reg; + `data_timeout : s_axi_rdata <= data_timeout_reg; + `cmd_isr : s_axi_rdata <= cmd_int_status_reg; + `cmd_iser : s_axi_rdata <= cmd_int_enable_reg; + `data_isr : s_axi_rdata <= data_int_status_reg; + `data_iser : s_axi_rdata <= data_int_enable_reg; + `blkcnt : s_axi_rdata <= block_count_reg; + `card_detect : s_axi_rdata <= { sd_remove_int, sd_remove_ie, sd_insert_int, sd_insert_ie }; + `dst_src_addr : s_axi_rdata <= dma_addr_reg[31:0]; + `dst_src_addr_high : if (dma_addr_bits > 32) s_axi_rdata <= dma_addr_reg[dma_addr_bits-1:32]; + endcase + end + s_axi_rresp <= 0; + s_axi_rvalid <= 1; + rd_req <= 0; + end + if (s_axi_awready && s_axi_awvalid) begin + write_addr <= s_axi_awaddr; + wr_req[0] <= 1; + end + if (s_axi_wready && s_axi_wvalid) begin + write_data <= s_axi_wdata; + wr_req[1] <= 1; + end + if (s_axi_bvalid && s_axi_bready) begin + s_axi_bvalid <= 0; + end else if (!s_axi_bvalid && wr_req == 2'b11) begin + if (write_addr[15:8] == 0) begin + case (write_addr[7:0]) + `argument : begin argument_reg <= write_data; cmd_start <= 1; end + `command : command_reg <= write_data; + `reset : software_reset_reg <= write_data; + `cmd_timeout : cmd_timeout_reg <= write_data; + `data_timeout : data_timeout_reg <= write_data; + `blksize : block_size_reg <= write_data; + `controller : controller_setting_reg <= write_data; + `cmd_isr : cmd_int_rst <= 1; + `cmd_iser : cmd_int_enable_reg <= write_data; + `clock_d : clock_divider_reg <= write_data; + `data_isr : data_int_rst <= 1; + `data_iser : data_int_enable_reg <= write_data; + `blkcnt : block_count_reg <= write_data; + `card_detect : begin sd_remove_ie <= write_data[2]; sd_insert_ie <= write_data[0]; end + `dst_src_addr : dma_addr_reg[31:0] <= write_data; + `dst_src_addr_high : if (dma_addr_bits > 32) dma_addr_reg[dma_addr_bits-1:32] <= write_data; + endcase + end + s_axi_bresp <= 0; + s_axi_bvalid <= 1; + wr_req <= 0; + end + end +end + +// ------ Data FIFO + +reg [31:0] fifo_mem [(1<= (1 << fifo_addr_bits) / 2; +wire [31:0] fifo_din = en_rx_fifo ? data_in_rx_fifo : m_bus_dat_i; +wire fifo_we = en_rx_fifo ? rx_fifo_we && clock_posedge : m_axi_rready && m_axi_rvalid; +wire fifo_re = en_rx_fifo ? m_axi_wready && m_axi_wvalid : tx_fifo_re && clock_posedge; +reg [31:0] fifo_dout; + +assign fifo_almost_full = fifo_data_len > (1 << fifo_addr_bits) * 3 / 4; +assign fifo_almost_empty = fifo_free_len > (1 << fifo_addr_bits) * 3 / 4; + +wire tx_stb = en_tx_fifo && fifo_free_len >= (1 << fifo_addr_bits) / 3; +wire rx_stb = en_rx_fifo && m_axi_bresp_cnt != 3'b111 && (fifo_data_len >= (1 << fifo_addr_bits) / 3 || (!fifo_empty && !data_busy)); + +always @(posedge clock) + if (reset || ctrl_rst || !(en_rx_fifo || en_tx_fifo)) begin + fifo_inp_pos <= 0; + fifo_out_pos <= 0; + end else begin + if (fifo_we && !fifo_full) begin + fifo_mem[fifo_inp_pos] <= fifo_din; + fifo_inp_pos <= fifo_inp_nxt; + if (fifo_empty) fifo_dout <= fifo_din; + end + if (fifo_re && !fifo_empty) begin + if (fifo_we && !fifo_full && fifo_out_nxt == fifo_inp_pos) fifo_dout <= fifo_din; + else fifo_dout <= fifo_mem[fifo_out_nxt]; + fifo_out_pos <= fifo_out_nxt; + end + end + +// ------ AXI Master Interface + +// AXI transaction (DDR access) is over 80 clock cycles +// Must use burst to achive required throughput + +reg m_axi_cyc; +wire m_axi_write = en_rx_fifo; +reg [7:0] m_axi_wcnt; +reg [dma_addr_bits-1:2] m_bus_adr_o; +wire [31:0] m_bus_dat_i; +reg [2:0] m_axi_bresp_cnt; +reg m_bus_error; + +assign m_axi_bready = m_axi_bresp_cnt != 0; +assign m_axi_rready = m_axi_cyc & !m_axi_write; +assign m_bus_dat_i = {m_axi_rdata[7:0],m_axi_rdata[15:8],m_axi_rdata[23:16],m_axi_rdata[31:24]}; +assign m_axi_wdata = {fifo_dout[7:0],fifo_dout[15:8],fifo_dout[23:16],fifo_dout[31:24]}; + +// AXI burst cannot cross a 4KB boundary +wire [fifo_addr_bits-1:0] tx_burst_len; +wire [fifo_addr_bits-1:0] rx_burst_len; +assign tx_burst_len = m_bus_adr_o[11:2] + fifo_free_len >= m_bus_adr_o[11:2] ? fifo_free_len - 1 : ~m_bus_adr_o[fifo_addr_bits+1:2]; +assign rx_burst_len = m_bus_adr_o[11:2] + fifo_data_len >= m_bus_adr_o[11:2] ? fifo_data_len - 1 : ~m_bus_adr_o[fifo_addr_bits+1:2]; + +assign data_int_status_reg = { data_int_status[`INT_DATA_SIZE-1:1], + !en_rx_fifo && !en_tx_fifo && !m_axi_cyc && m_axi_bresp_cnt == 0 && data_int_status[0] }; + +always @(posedge clock) begin + if (reset | ctrl_rst) begin + m_axi_arvalid <= 0; + m_axi_awvalid <= 0; + m_axi_wvalid <= 0; + m_axi_cyc <= 0; + end else if (m_axi_cyc) begin + if (m_axi_awvalid && m_axi_awready) begin + m_axi_awvalid <= 0; + end + if (m_axi_arvalid && m_axi_arready) begin + m_axi_arvalid <= 0; + end + if (m_axi_wvalid && m_axi_wready) begin + if (m_axi_wlast) begin + m_axi_wvalid <= 0; + m_axi_cyc <= 0; + end else begin + m_axi_wlast <= m_axi_wcnt + 1 == m_axi_awlen; + m_axi_wcnt <= m_axi_wcnt + 1; + end + end + if (m_axi_rvalid && m_axi_rready && m_axi_rlast) begin + m_axi_cyc <= 0; + end + end else if (tx_stb || rx_stb) begin + m_axi_cyc <= 1; + m_axi_wcnt <= 0; + if (m_axi_write) begin + m_axi_awaddr <= { m_bus_adr_o, 2'b00 }; + m_axi_awlen <= rx_burst_len < 8'hff ? rx_burst_len : 8'hff; + m_axi_wlast <= rx_burst_len == 0; + m_axi_awvalid <= 1; + m_axi_wvalid <= 1; + end else begin + m_axi_araddr <= { m_bus_adr_o, 2'b00 }; + m_axi_arlen <= tx_burst_len < 8'hff ? tx_burst_len : 8'hff; + m_axi_arvalid <= 1; + end + end + if (reset | ctrl_rst) begin + m_bus_adr_o <= 0; + end else if ((m_axi_wready && m_axi_wvalid) || (m_axi_rready && m_axi_rvalid)) begin + m_bus_adr_o <= m_bus_adr_o + 1; + end else if (!m_axi_cyc && !en_rx_fifo && !en_tx_fifo) begin + m_bus_adr_o <= dma_addr_reg[dma_addr_bits-1:2]; + end + if (reset | ctrl_rst) begin + m_axi_bresp_cnt <= 0; + end else if ((m_axi_awvalid && m_axi_awready) && !(m_axi_bvalid && m_axi_bready)) begin + m_axi_bresp_cnt <= m_axi_bresp_cnt + 1; + end else if (!(m_axi_awvalid && m_axi_awready) && (m_axi_bvalid && m_axi_bready)) begin + m_axi_bresp_cnt <= m_axi_bresp_cnt - 1; + end + if (reset | ctrl_rst | cmd_start) begin + m_bus_error <= 0; + end else if (m_axi_bvalid && m_axi_bready && m_axi_bresp) begin + m_bus_error <= 1; + end else if (m_axi_rvalid && m_axi_rready && m_axi_rresp) begin + m_bus_error <= 1; + end + if (reset | ctrl_rst) begin + data_start_tx <= 0; + data_start_rx <= 0; + data_prepare_tx <= 0; + end else if (clock_posedge) begin + data_start_tx <= 0; + data_start_rx <= 0; + if (cmd_start) begin + data_prepare_tx <= 0; + if (command_reg[`CMD_WITH_DATA] == 2'b01) data_start_rx <= 1; + else if (command_reg[`CMD_WITH_DATA] != 2'b00) data_prepare_tx <= 1; + end else if (data_prepare_tx) begin + if (cmd_int_status_reg[`INT_CMD_CC]) begin + data_prepare_tx <= 0; + data_start_tx <= 1; + end else if (cmd_int_status_reg[`INT_CMD_EI]) begin + data_prepare_tx <= 0; + end + end + end +end + +// ------ SD Card Interface + +sd_cmd_master sd_cmd_master0( + .clock (clock), + .clock_posedge (clock_posedge), + .reset (reset | ctrl_rst), + .start (cmd_start), + .int_status_rst (cmd_int_rst), + .setting (cmd_setting), + .start_xfr (cmd_start_tx), + .go_idle (go_idle), + .cmd (cmd), + .response (cmd_response), + .crc_error (!cmd_crc_ok), + .index_ok (cmd_index_ok), + .busy (sd_data_busy), + .finish (cmd_finish), + .argument (argument_reg), + .command (command_reg), + .timeout (cmd_timeout_reg), + .int_status (cmd_int_status_reg), + .response_0 (response_0_reg), + .response_1 (response_1_reg), + .response_2 (response_2_reg), + .response_3 (response_3_reg) + ); + +sd_cmd_serial_host cmd_serial_host0( + .clock (clock), + .clock_posedge (clock_posedge), + .clock_data_in (clock_data_in), + .reset (reset | ctrl_rst | go_idle), + .setting (cmd_setting), + .cmd (cmd), + .start (cmd_start_tx), + .finish (cmd_finish), + .response (cmd_response), + .crc_ok (cmd_crc_ok), + .index_ok (cmd_index_ok), + .cmd_i (sd_cmd_i), + .cmd_o (sd_cmd_o), + .cmd_oe (sd_cmd_oe) + ); + +sd_data_master sd_data_master0( + .clock (clock), + .clock_posedge (clock_posedge), + .reset (reset | ctrl_rst), + .start_tx (data_start_tx), + .start_rx (data_start_rx), + .timeout (data_timeout_reg), + .d_write (d_write), + .d_read (d_read), + .en_tx_fifo (en_tx_fifo), + .en_rx_fifo (en_rx_fifo), + .fifo_empty (fifo_empty), + .fifo_ready (fifo_ready), + .fifo_full (fifo_full), + .bus_cycle (m_axi_cyc || m_axi_bresp_cnt != 0), + .xfr_complete (!data_busy), + .crc_error (!data_crc_ok), + .bus_error (m_bus_error), + .int_status (data_int_status), + .int_status_rst (data_int_rst) + ); + +sd_data_serial_host sd_data_serial_host0( + .clock (clock), + .clock_posedge (clock_posedge), + .clock_data_in (clock_data_in), + .reset (reset | ctrl_rst), + .data_in (fifo_dout), + .rd (tx_fifo_re), + .data_out (data_in_rx_fifo), + .we (rx_fifo_we), + .dat_oe (sd_dat_oe), + .dat_o (sd_dat_o), + .dat_i (sd_dat_i), + .blksize (block_size_reg), + .bus_4bit (controller_setting_reg[0]), + .blkcnt (block_count_reg), + .start ({d_read, d_write}), + .byte_alignment (dma_addr_reg[1:0]), + .sd_data_busy (sd_data_busy), + .busy (data_busy), + .crc_ok (data_crc_ok) + ); + +assign interrupt = + |(cmd_int_status_reg & cmd_int_enable_reg) || + |(data_int_status_reg & data_int_enable_reg) || + (sd_insert_int & sd_insert_ie) || + (sd_remove_int & sd_remove_ie); + +endmodule diff --git a/pipelined/src/uncore/newsdc/license.txt b/pipelined/src/uncore/newsdc/license.txt new file mode 100644 index 00000000..4362b491 --- /dev/null +++ b/pipelined/src/uncore/newsdc/license.txt @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library 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 library 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/pipelined/src/uncore/newsdc/sd_cmd_master.v b/pipelined/src/uncore/newsdc/sd_cmd_master.v new file mode 100644 index 00000000..6b46c786 --- /dev/null +++ b/pipelined/src/uncore/newsdc/sd_cmd_master.v @@ -0,0 +1,152 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2013-2022 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 https://www.gnu.org/licenses/ //// +//// //// +////////////////////////////////////////////////////////////////////// +`include "sd_defines.h" + +module sd_cmd_master( + input clock, + input clock_posedge, + input reset, + input start, + input int_status_rst, + output [1:0] setting, + output reg start_xfr, + output reg go_idle, + output reg [39:0] cmd, + input [119:0] response, + input crc_error, + input index_ok, + input finish, + input busy, // direct signal from data sd data input (data[0]) + //input card_detect, + input [31:0] argument, + input [`CMD_REG_SIZE-1:0] command, + input [`CMD_TIMEOUT_W-1:0] timeout, + output [`INT_CMD_SIZE-1:0] int_status, + output reg [31:0] response_0, + output reg [31:0] response_1, + output reg [31:0] response_2, + output reg [31:0] response_3 +); + +reg expect_response; +reg long_response; +reg [`INT_CMD_SIZE-1:0] int_status_reg; +reg [`CMD_TIMEOUT_W-1:0] watchdog; +reg watchdog_enable; + +reg [2:0] state; +parameter IDLE = 3'b001; +parameter EXECUTE = 3'b010; +parameter BUSY_CHECK = 3'b100; + +assign setting[1:0] = {long_response, expect_response}; +assign int_status = state == IDLE ? int_status_reg : 5'h0; + +always @(posedge clock) begin + if (reset) begin + response_0 <= 0; + response_1 <= 0; + response_2 <= 0; + response_3 <= 0; + int_status_reg <= 0; + expect_response <= 0; + long_response <= 0; + cmd <= 0; + start_xfr <= 0; + watchdog <= 0; + watchdog_enable <= 0; + go_idle <= 0; + state <= IDLE; + end else if (clock_posedge) begin + case (state) + IDLE: begin + go_idle <= 0; + if (command[`CMD_RESPONSE_CHECK] == 2'b10 || command[`CMD_RESPONSE_CHECK] == 2'b11) begin + expect_response <= 1; + long_response <= 1; + end else if (command[`CMD_RESPONSE_CHECK] == 2'b01) begin + expect_response <= 1; + long_response <= 0; + end else begin + expect_response <= 0; + long_response <= 0; + end + cmd[39:38] <= 2'b01; + cmd[37:32] <= command[`CMD_INDEX]; + cmd[31:0] <= argument; + watchdog <= 0; + watchdog_enable <= timeout != 0; + if (start) begin + start_xfr <= 1; + int_status_reg <= 0; + state <= EXECUTE; + end + end + EXECUTE: begin + start_xfr <= 0; + if (watchdog_enable && watchdog >= timeout) begin + int_status_reg[`INT_CMD_CTE] <= 1; + int_status_reg[`INT_CMD_EI] <= 1; + go_idle <= 1; + state <= IDLE; + end else if (finish) begin + if (command[`CMD_CRC_CHECK] && crc_error) begin + int_status_reg[`INT_CMD_CCRCE] <= 1; + int_status_reg[`INT_CMD_EI] <= 1; + end + if (command[`CMD_IDX_CHECK] && !index_ok) begin + int_status_reg[`INT_CMD_CIE] <= 1; + int_status_reg[`INT_CMD_EI] <= 1; + end + int_status_reg[`INT_CMD_CC] <= 1; + if (expect_response) begin + response_0 <= response[119:88]; + response_1 <= response[87:56]; + response_2 <= response[55:24]; + response_3 <= {response[23:0], 8'h00}; + end + if (command[`CMD_BUSY_CHECK]) state <= BUSY_CHECK; + else state <= IDLE; + end else if (watchdog_enable) begin + watchdog <= watchdog + 1; + end + end + BUSY_CHECK: begin + if (!busy) state <= IDLE; + end + endcase + if (int_status_rst) + int_status_reg <= 0; + end +end + +endmodule diff --git a/pipelined/src/uncore/newsdc/sd_cmd_serial_host.v b/pipelined/src/uncore/newsdc/sd_cmd_serial_host.v new file mode 100644 index 00000000..0cebb4f2 --- /dev/null +++ b/pipelined/src/uncore/newsdc/sd_cmd_serial_host.v @@ -0,0 +1,263 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2013-2022 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 https://www.gnu.org/licenses/ //// +//// //// +////////////////////////////////////////////////////////////////////// + +module sd_cmd_serial_host ( + //---------------Input ports--------------- + input clock, + input clock_posedge, + input clock_data_in, + input reset, + input [1:0] setting, + input [39:0] cmd, + input start, + input cmd_i, + //---------------Output ports--------------- + output reg [119:0] response, + output reg finish, + output reg crc_ok, + output reg index_ok, + output reg cmd_oe, + output reg cmd_o +); + +//-------------Internal Constant------------- +parameter INIT_DELAY = 4; +parameter BITS_TO_SEND = 48; +parameter CMD_SIZE = 40; +parameter RESP_SIZE = 128; + +//---------------Internal variable----------- +reg cmd_dat_reg; +integer resp_len; +reg with_response; +reg [CMD_SIZE-1:0] cmd_buff; +reg [RESP_SIZE-1:0] resp_buff; +integer resp_idx; +//CRC +reg crc_rst; +reg [6:0]crc_in; +wire [6:0] crc_val; +reg crc_enable; +reg crc_bit; +reg crc_match; +//-Internal Counterns +integer counter; +//-State Machine +parameter + STATE_SIZE = 8, + INIT = 8'b00000001, + IDLE = 8'b00000010, + SETUP_CRC = 8'b00000100, + WRITE = 8'b00001000, + READ_WAIT = 8'b00010000, + READ = 8'b00100000, + FINISH_WR = 8'b01000000, + FINISH_WO = 8'b10000000; +reg [STATE_SIZE-1:0] state; + +//Misc +`define cmd_idx (CMD_SIZE-1-counter) + +//sd cmd input pad register +always @(posedge clock) begin + if (clock_data_in) cmd_dat_reg <= cmd_i; +end + +//------------------------------------------ +sd_crc_7 CRC_7( + crc_bit, + crc_enable & clock_posedge, + clock, + crc_rst, + crc_val); + +//------------------------------------------ + +always @(posedge clock) begin + if (reset) begin + resp_len <= 0; + with_response <= 0; + cmd_buff <= 0; + crc_enable <= 0; + resp_idx <= 0; + cmd_oe <= 1; + cmd_o <= 1; + resp_buff <= 0; + finish <= 0; + crc_rst <= 1; + crc_bit <= 0; + crc_in <= 0; + response <= 0; + index_ok <= 0; + crc_ok <= 0; + crc_match <= 0; + counter <= 0; + state <= INIT; + end else if (clock_posedge) begin + case (state) + INIT: begin + counter <= counter+1; + // Pull cmd line up + cmd_oe <= 1; + cmd_o <= 1; + if (counter >= INIT_DELAY) state <= IDLE; + end + IDLE: begin + cmd_oe <= 0; + counter <= 0; + crc_rst <= 1; + crc_enable <= 0; + response <= 0; + resp_idx <= 0; + crc_ok <= 0; + index_ok <= 0; + finish <= 0; + if (start) begin + resp_len <= setting[1] ? 127 : 39; + with_response <= setting[0]; + cmd_buff <= cmd; + state <= SETUP_CRC; + end + end + SETUP_CRC: begin + crc_rst <= 0; + crc_enable <= 1; + crc_bit <= cmd_buff[`cmd_idx]; + state <= WRITE; + end + WRITE: begin + if (counter < BITS_TO_SEND-8) begin // 1->40 CMD, (41 >= CNT && CNT <=47) CRC, 48 stop_bit + cmd_oe <= 1; + cmd_o <= cmd_buff[`cmd_idx]; + if (counter < BITS_TO_SEND-9) begin //1 step ahead + crc_bit <= cmd_buff[`cmd_idx-1]; + end else begin + crc_enable <= 0; + end + end else if (counter < BITS_TO_SEND-1) begin + cmd_oe <= 1; + crc_enable <= 0; + cmd_o <= crc_val[BITS_TO_SEND-counter-2]; + end else if (counter == BITS_TO_SEND-1) begin + cmd_oe <= 1; + cmd_o <= 1'b1; + end else begin + cmd_oe <= 0; + cmd_o <= 1'b1; + end + counter <= counter + 1; + if (counter >= BITS_TO_SEND && with_response) state <= READ_WAIT; + else if (counter >= BITS_TO_SEND) state <= FINISH_WO; + end + READ_WAIT: begin + crc_enable <= 0; + crc_rst <= 1; + counter <= 1; + cmd_oe <= 0; + resp_buff[RESP_SIZE-1] <= cmd_dat_reg; + if (!cmd_dat_reg) state <= READ; + end + FINISH_WO: begin + finish <= 1; + crc_enable <= 0; + crc_rst <= 1; + counter <= 0; + cmd_oe <= 0; + state <= IDLE; + end + READ: begin + crc_rst <= 0; + crc_enable <= (resp_len != RESP_SIZE-1 || counter > 7); + cmd_oe <= 0; + if (counter <= resp_len) begin + if (counter < 8) //1+1+6 (S,T,Index) + resp_buff[RESP_SIZE-1-counter] <= cmd_dat_reg; + else begin + resp_idx <= resp_idx + 1; + resp_buff[RESP_SIZE-9-resp_idx] <= cmd_dat_reg; + end + crc_bit <= cmd_dat_reg; + end else if (counter-resp_len <= 7) begin + crc_in[(resp_len+7)-(counter)] <= cmd_dat_reg; + crc_enable <= 0; + end else begin + crc_enable <= 0; + crc_match <= crc_in == crc_val; + end + counter <= counter + 1; + if (counter >= resp_len+8) state <= FINISH_WR; + end + FINISH_WR: begin + index_ok <= cmd_buff[37:32] == resp_buff[125:120]; + crc_ok <= crc_match; + finish <= 1; + crc_enable <= 0; + crc_rst <= 1; + counter <= 0; + cmd_oe <= 0; + response <= resp_buff[119:0]; + state <= IDLE; + end + default: + state <= INIT; + endcase + end +end + +endmodule + +module sd_crc_7( + input BITVAL, // Next input bit + input ENABLE, // Enable calculation + input BITSTRB, // Current bit valid (Clock) + input CLEAR, // Init CRC value + output reg [6:0] CRC // Current output CRC value +); + +wire inv; +assign inv = BITVAL ^ CRC[6]; + +always @(posedge BITSTRB or posedge CLEAR) begin + if (CLEAR) begin + CRC <= 0; + end else 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 + +endmodule diff --git a/pipelined/src/uncore/newsdc/sd_data_master.v b/pipelined/src/uncore/newsdc/sd_data_master.v new file mode 100644 index 00000000..c85d7ea7 --- /dev/null +++ b/pipelined/src/uncore/newsdc/sd_data_master.v @@ -0,0 +1,150 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2013-2022 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 https://www.gnu.org/licenses/ //// +//// //// +////////////////////////////////////////////////////////////////////// +`include "sd_defines.h" + +module sd_data_master ( + input clock, + input clock_posedge, + input reset, + input start_tx, + input start_rx, + input [`DATA_TIMEOUT_W-1:0] timeout, + // Output to SD-Host Reg + output reg d_write, + output reg d_read, + // To fifo filler + output reg en_tx_fifo, + output reg en_rx_fifo, + input fifo_empty, + input fifo_ready, + input fifo_full, + input bus_cycle, + // SD-DATA_Host + input xfr_complete, + input crc_error, + input bus_error, + // status output + output reg [`INT_DATA_SIZE-1:0] int_status, + input int_status_rst +); + +reg [3:0] state; +localparam IDLE = 4'b0001; +localparam START_TX_FIFO = 4'b0010; +localparam START_RX_FIFO = 4'b0100; +localparam DATA_TRANSFER = 4'b1000; + +reg [`DATA_TIMEOUT_W-1:0] watchdog; +reg watchdog_enable; + +always @(posedge clock) begin + if (reset) begin + en_tx_fifo <= 0; + en_rx_fifo <= 0; + d_write <= 0; + d_read <= 0; + int_status <= 0; + watchdog <= 0; + watchdog_enable <= 0; + state <= IDLE; + end else if (clock_posedge) begin + case (state) + IDLE: begin + en_tx_fifo <= 0; + en_rx_fifo <= 0; + d_write <= 0; + d_read <= 0; + watchdog <= 0; + watchdog_enable <= timeout != 0; + if (start_tx) state <= START_TX_FIFO; + else if (start_rx) state <= START_RX_FIFO; + end + START_RX_FIFO: begin + en_rx_fifo <= 1; + en_tx_fifo <= 0; + d_read <= 1; + if (!xfr_complete) state <= DATA_TRANSFER; + end + START_TX_FIFO: begin + en_rx_fifo <= 0; + en_tx_fifo <= 1; + if (fifo_ready) begin + d_write <= 1; + if (!xfr_complete) state <= DATA_TRANSFER; + end + end + DATA_TRANSFER: begin + d_read <= 0; + d_write <= 0; + if (en_tx_fifo && fifo_empty) begin + int_status[`INT_DATA_CFE] <= 1; + int_status[`INT_DATA_EI] <= 1; + state <= IDLE; + // stop sd_data_serial_host + d_write <= 1; + d_read <= 1; + end else if (en_rx_fifo && fifo_full) begin + int_status[`INT_DATA_CFE] <= 1; + int_status[`INT_DATA_EI] <= 1; + state <= IDLE; + // stop sd_data_serial_host + d_write <= 1; + d_read <= 1; + end else if (watchdog_enable && watchdog >= timeout) begin + int_status[`INT_DATA_CTE] <= 1; + int_status[`INT_DATA_EI] <= 1; + state <= IDLE; + // stop sd_data_serial_host + d_write <= 1; + d_read <= 1; + end else if (xfr_complete && !bus_cycle && (en_tx_fifo || fifo_empty)) begin + state <= IDLE; + if (crc_error) begin + int_status[`INT_DATA_CCRCE] <= 1; + int_status[`INT_DATA_EI] <= 1; + end + if (bus_error) begin + int_status[`INT_DATA_CBE] <= 1; + int_status[`INT_DATA_EI] <= 1; + end + int_status[`INT_DATA_CC] <= 1; + end else if (watchdog_enable) begin + watchdog <= watchdog + 1; + end + end + endcase + if (int_status_rst) + int_status <= 0; + end +end + +endmodule diff --git a/pipelined/src/uncore/newsdc/sd_data_serial_host.v b/pipelined/src/uncore/newsdc/sd_data_serial_host.v new file mode 100644 index 00000000..9a35e5a8 --- /dev/null +++ b/pipelined/src/uncore/newsdc/sd_data_serial_host.v @@ -0,0 +1,311 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2013-2022 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 https://www.gnu.org/licenses/ //// +//// //// +////////////////////////////////////////////////////////////////////// +`include "sd_defines.h" + +module sd_data_serial_host( + input clock, + input clock_posedge, + input clock_data_in, + input reset, + // 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, + output reg[3:0] dat_o, + input [3:0] dat_i, + // Controll 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, + output sd_data_busy, + output busy, + output reg crc_ok +); + +reg [3:0] DAT_dat_reg; +reg bus_4bit_reg; +reg crc_en; +reg crc_rst; +wire [15:0] crc_out [3:0]; +reg [`BLKSIZE_W+4-1:0] data_cycles; +reg [`BLKSIZE_W+4-1:0] transf_cnt; +reg [3:0] drt_bit; +reg [3:0] drt_reg; +reg [`BLKCNT_W-1:0] blkcnt_reg; +reg [1:0] byte_alignment_reg; +reg [3:0] crc_bit; +reg [3:0] last_din; +reg [4:0] data_index; + +reg [6:0] state; +parameter IDLE = 7'b0000001; +parameter WRITE_DAT = 7'b0000010; +parameter WRITE_WAIT = 7'b0000100; +parameter WRITE_DRT = 7'b0001000; +parameter WRITE_BUSY = 7'b0010000; +parameter READ_WAIT = 7'b0100000; +parameter READ_DAT = 7'b1000000; + +// sd data input pad register +always @(posedge clock) begin + if (clock_data_in) DAT_dat_reg <= dat_i; +end + +genvar i; +generate + for (i=0; i<4; i=i+1) begin: CRC_16_gen + sd_crc_16 CRC_16_i (last_din[i], crc_en & clock_posedge, clock, crc_rst, crc_out[i]); + end +endgenerate + +assign busy = (state != IDLE); +assign sd_data_busy = !DAT_dat_reg[0]; + +always @(posedge clock) begin + if (reset) begin + state <= IDLE; + dat_oe <= 0; + crc_en <= 0; + crc_rst <= 1; + transf_cnt <= 0; + rd <= 0; + last_din <= 0; + crc_bit <= 0; + dat_o <= 4'b1111; + drt_bit <= 0; + drt_reg <= 0; + we <= 0; + data_out <= 0; + crc_ok <= 0; + data_index <= 0; + blkcnt_reg <= 0; + byte_alignment_reg <= 0; + data_cycles <= 0; + bus_4bit_reg <= 0; + end else if (clock_posedge) begin + case (state) + IDLE: begin + dat_oe <= 0; + dat_o <= 4'b1111; + transf_cnt <= 0; + crc_en <= 0; + crc_rst <= 1; + crc_bit <= 15; + we <= 0; + rd <= 0; + data_index <= 0; + blkcnt_reg <= blkcnt; + byte_alignment_reg <= byte_alignment; + data_cycles <= (bus_4bit ? {3'b000, blksize, 1'b0} + 2 : {1'b0, blksize, 3'b000} + 8); + bus_4bit_reg <= bus_4bit; + if (start == 2'b01) state <= WRITE_DAT; + else if (start == 2'b10) state <= READ_WAIT; + end + WRITE_DAT: begin + rd <= 0; + transf_cnt <= transf_cnt + 16'h1; + if (transf_cnt == 0) begin + crc_ok <= 0; + crc_bit <= 15; + end else if (transf_cnt == 1) begin + crc_rst <= 0; + crc_en <= 1; + if (bus_4bit_reg) begin + last_din <= { + data_in[31-(byte_alignment_reg << 3)], + data_in[30-(byte_alignment_reg << 3)], + data_in[29-(byte_alignment_reg << 3)], + data_in[28-(byte_alignment_reg << 3)] + }; + end else begin + last_din <= {3'h7, data_in[31-(byte_alignment_reg << 3)]}; + end + dat_oe <= 1; + dat_o <= bus_4bit_reg ? 4'h0 : 4'he; + data_index <= bus_4bit_reg ? {2'b00, byte_alignment_reg, 1'b1} : {byte_alignment_reg, 3'b001}; + end else if (transf_cnt <= data_cycles+1) begin + if (bus_4bit_reg) begin + last_din <= { + data_in[31-(data_index[2:0]<<2)], + data_in[30-(data_index[2:0]<<2)], + data_in[29-(data_index[2:0]<<2)], + data_in[28-(data_index[2:0]<<2)] + }; + if (data_index[2:0] == 3'h6 && transf_cnt <= data_cycles-1) rd <= 1; + end else begin + last_din <= {3'h7, data_in[31-data_index]}; + if (data_index == 30) rd <= 1; + end + data_index <= data_index + 5'h1; + dat_o <= last_din; + if (transf_cnt == data_cycles+1) crc_en <= 0; + end else if (transf_cnt <= data_cycles+17) begin + crc_en <= 0; + dat_o[0] <= crc_out[0][crc_bit]; + if (bus_4bit_reg) + dat_o[3:1] <= {crc_out[3][crc_bit], crc_out[2][crc_bit], crc_out[1][crc_bit]}; + crc_bit <= crc_bit - 1; + end else if (transf_cnt == data_cycles+18) begin + dat_o <= 4'hf; + end else if (transf_cnt == data_cycles+19) begin + dat_oe <= 0; + end else begin + state <= WRITE_WAIT; + end + end + WRITE_WAIT: begin + drt_bit <= 0; + if (!DAT_dat_reg[0]) state <= WRITE_DRT; + end + WRITE_DRT: begin + // See 7.3.3.1 Data Response Token + if (drt_bit <= 3) begin + drt_reg[drt_bit] <= DAT_dat_reg[0]; + end else if (drt_bit == 15) begin + crc_ok <= drt_reg[3:0] == 4'b1010; + state <= WRITE_BUSY; + end + drt_bit <= drt_bit + 1; + end + WRITE_BUSY: begin + if (DAT_dat_reg[0]) begin + if (blkcnt_reg != 0 && crc_ok) begin + transf_cnt <= 0; + blkcnt_reg <= blkcnt_reg - 1; + byte_alignment_reg <= byte_alignment_reg + blksize[1:0] + 2'b1; + crc_rst <= 1; + state <= WRITE_DAT; + end else begin + state <= IDLE; + end + end + end + READ_WAIT: begin + dat_oe <= 0; + crc_bit <= 15; + last_din <= 0; + transf_cnt <= 0; + data_index <= bus_4bit_reg ? (byte_alignment_reg << 1) : (byte_alignment_reg << 3); + if (!DAT_dat_reg[0]) begin + crc_rst <= 0; + crc_en <= 1; + state <= READ_DAT; + end + end + READ_DAT: begin + last_din <= DAT_dat_reg; + transf_cnt <= transf_cnt + 16'h1; + if (transf_cnt < data_cycles) begin + if (bus_4bit_reg) begin + we <= (data_index[2:0] == 7 || (transf_cnt == data_cycles-1 && !blkcnt_reg)); + data_out[31-(data_index[2:0]<<2)] <= DAT_dat_reg[3]; + data_out[30-(data_index[2:0]<<2)] <= DAT_dat_reg[2]; + data_out[29-(data_index[2:0]<<2)] <= DAT_dat_reg[1]; + data_out[28-(data_index[2:0]<<2)] <= DAT_dat_reg[0]; + end else begin + we <= (data_index == 31 || (transf_cnt == data_cycles-1 && !blkcnt_reg)); + data_out[31-data_index] <= DAT_dat_reg[0]; + end + data_index <= data_index + 5'h1; + crc_ok <= 1; + end else if (transf_cnt == data_cycles) begin + crc_en <= 0; + we <= 0; + end else if (transf_cnt <= data_cycles+16) begin + if (crc_out[0][crc_bit] != last_din[0]) crc_ok <= 0; + if (bus_4bit_reg) begin + if (crc_out[1][crc_bit] != last_din[1]) crc_ok <= 0; + if (crc_out[2][crc_bit] != last_din[2]) crc_ok <= 0; + if (crc_out[3][crc_bit] != last_din[3]) crc_ok <= 0; + end + if (crc_bit == 0) begin + byte_alignment_reg <= byte_alignment_reg + blksize[1:0] + 2'b1; + crc_rst <= 1; + end else begin + crc_bit <= crc_bit - 1; + end + end else if (blkcnt_reg != 0 && crc_ok) begin + blkcnt_reg <= blkcnt_reg - 1; + state <= READ_WAIT; + end else begin + state <= IDLE; + end + end + default: + state <= IDLE; + endcase + if (start == 2'b11) state <= IDLE; // Abort + end +end + +endmodule + +module sd_crc_16( + input BITVAL, // Next input bit + input ENABLE, // Enable calculation + input BITSTRB, // Current bit valid (Clock) + input CLEAR, // Init CRC value + output reg [15:0] CRC // Current output CRC value +); + +assign inv = BITVAL ^ CRC[15]; + +always @(posedge BITSTRB) begin + if (CLEAR) begin + CRC <= 0; + end else 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 + +endmodule diff --git a/pipelined/src/uncore/newsdc/sd_defines.h b/pipelined/src/uncore/newsdc/sd_defines.h new file mode 100644 index 00000000..9afbde47 --- /dev/null +++ b/pipelined/src/uncore/newsdc/sd_defines.h @@ -0,0 +1,91 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2013-2022 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 https://www.gnu.org/licenses/ //// +//// //// +////////////////////////////////////////////////////////////////////// + +// global defines +`define BLKSIZE_W 12 +`define BLKCNT_W 16 +`define CMD_TIMEOUT_W 25 +`define DATA_TIMEOUT_W 28 + +// 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 6 +`define INT_DATA_CC 0 +`define INT_DATA_EI 1 +`define INT_DATA_CTE 2 // Timeout +`define INT_DATA_CCRCE 3 // CRC error +`define INT_DATA_CFE 4 // FIFO error +`define INT_DATA_CBE 5 // Bus error + +// 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 card_detect 8'h4c +`define dst_src_addr 8'h60 +`define dst_src_addr_high 8'h64 + +// register contents +`define RESET_BLOCK_SIZE 12'd511 +`define RESET_CLOCK_DIV 124 diff --git a/pipelined/src/uncore/uncore.sv b/pipelined/src/uncore/uncore.sv index 34c33426..3cde211c 100644 --- a/pipelined/src/uncore/uncore.sv +++ b/pipelined/src/uncore/uncore.sv @@ -31,6 +31,8 @@ `include "wally-config.vh" +// *** need idiom to map onto cache RAM with byte writes +// *** and use memread signal to reduce power when reads aren't needed module uncore ( // AHB Bus Interface input logic HCLK, HRESETn, diff --git a/tests/custom/boot/Makefile b/tests/custom/boot/Makefile new file mode 100644 index 00000000..6dec9c79 --- /dev/null +++ b/tests/custom/boot/Makefile @@ -0,0 +1,112 @@ +CEXT := c +CPPEXT := cpp +AEXT := s +SEXT := S +SRCEXT := \([$(CEXT)$(AEXT)$(SEXT)]\|$(CPPEXT)\) +OBJEXT := o +DEPEXT := d +SRCDIR := . +BUILDDIR := OBJ + +SOURCES ?= $(shell find $(SRCDIR) -type f -regex ".*\.$(SRCEXT)" | sort) +OBJECTS := $(SOURCES:.$(CEXT)=.$(OBJEXT)) +OBJECTS := $(OBJECTS:.$(AEXT)=.$(OBJEXT)) +OBJECTS := $(OBJECTS:.$(SEXT)=.$(OBJEXT)) +OBJECTS := $(OBJECTS:.$(CPPEXT)=.$(OBJEXT)) +OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(OBJECTS)) + +TARGETDIR := bin +TARGET := $(TARGETDIR)/fpga-test-sdc +ROOT := .. +LIBRARY_DIRS := +LIBRARY_FILES := + +MARCH :=-march=rv64imfdc +MABI :=-mabi=lp64d +LINK_FLAGS :=$(MARCH) $(MABI) -nostartfiles +LINKER :=linker.x + + +AFLAGS =$(MARCH) $(MABI) -W +CFLAGS =$(MARCH) $(MABI) -mcmodel=medany -O2 +AS=riscv64-unknown-elf-as +CC=riscv64-unknown-elf-gcc +AR=riscv64-unknown-elf-ar + + +#Default Make +all: directories $(TARGET).memfile + +#Remake +remake: clean all + +#Make the Directories +directories: + @mkdir -p $(TARGETDIR) + @mkdir -p $(BUILDDIR) + +clean: + rm -rf $(BUILDDIR) $(TARGETDIR) *.memfile *.objdump + + +#Needed for building additional library projects +ifdef LIBRARY_DIRS +LIBS+=${LIBRARY_DIRS:%=-L%} ${LIBRARY_FILES:%=-l%} +INC+=${LIBRARY_DIRS:%=-I%} + +${LIBRARY_DIRS}: + make -C $@ -j 1 + +.PHONY: $(LIBRARY_DIRS) $(TARGET) +endif + + +#Pull in dependency info for *existing* .o files +-include $(OBJECTS:.$(OBJEXT)=.$(DEPEXT)) + +#Link +$(TARGET): $(OBJECTS) $(LIBRARY_DIRS) + $(CC) $(LINK_FLAGS) -g -o $(TARGET) $(OBJECTS) ${LIBS} -T ${LINKER} + + +#Compile +$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(CEXT) + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) $(INC) -c -o $@ $< > $(BUILDDIR)/$*.list + @$(CC) $(CFLAGS) $(INC) -MM $(SRCDIR)/$*.$(CEXT) > $(BUILDDIR)/$*.$(DEPEXT) + @cp -f $(BUILDDIR)/$*.$(DEPEXT) $(BUILDDIR)/$*.$(DEPEXT).tmp + @sed -e 's|.*:|$(BUILDDIR)/$*.$(OBJEXT):|' < $(BUILDDIR)/$*.$(DEPEXT).tmp > $(BUILDDIR)/$*.$(DEPEXT) + @sed -e 's/.*://' -e 's/\\$$//' < $(BUILDDIR)/$*.$(DEPEXT).tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $(BUILDDIR)/$*.$(DEPEXT) + @rm -f $(BUILDDIR)/$*.$(DEPEXT).tmp + +# gcc won't output dependencies for assembly files for some reason +# most asm files don't have dependencies so the echo will work for now. +$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(AEXT) + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) -c -o $@ $< > $(BUILDDIR)/$*.list + @echo $@: $< > $(BUILDDIR)/$*.$(DEPEXT) + +$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SEXT) + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) $(INC) -c -o $@ $< > $(BUILDDIR)/$*.list + @echo $@: $< > $(BUILDDIR)/$*.$(DEPEXT) + +# C++ +$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(CPPEXT) + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) $(INC) -c -o $@ $< > $(BUILDDIR)/$*.list + @$(CC) $(CFLAGS) $(INC) -MM $(SRCDIR)/$*.$(CPPEXT) > $(BUILDDIR)/$*.$(DEPEXT) + @cp -f $(BUILDDIR)/$*.$(DEPEXT) $(BUILDDIR)/$*.$(DEPEXT).tmp + @sed -e 's|.*:|$(BUILDDIR)/$*.$(OBJEXT):|' < $(BUILDDIR)/$*.$(DEPEXT).tmp > $(BUILDDIR)/$*.$(DEPEXT) + @sed -e 's/.*://' -e 's/\\$$//' < $(BUILDDIR)/$*.$(DEPEXT).tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $(BUILDDIR)/$*.$(DEPEXT) + @rm -f $(BUILDDIR)/$*.$(DEPEXT).tmp + +# convert to hex +$(TARGET).memfile: $(TARGET) + @echo 'Making object dump file.' + @riscv64-unknown-elf-objdump -D $< > $<.objdump + @echo 'Making memory file' + riscv64-unknown-elf-elf2hex --bit-width 64 --input $^ --output $@ + extractFunctionRadix.sh $<.objdump + mkdir -p ../../imperas-riscv-tests/work/rv64BP/ + cp -f $(TARGETDIR)/* ../../imperas-riscv-tests/work/rv64BP/ diff --git a/tests/custom/boot/boot.c b/tests/custom/boot/boot.c new file mode 100644 index 00000000..71f22534 --- /dev/null +++ b/tests/custom/boot/boot.c @@ -0,0 +1,370 @@ + + +/* Card type flags (card_type) */ +#define CT_MMC 0x01 /* MMC ver 3 */ +#define CT_SD1 0x02 /* SD ver 1 */ +#define CT_SD2 0x04 /* SD ver 2 */ +#define CT_SDC (CT_SD1|CT_SD2) /* SD */ +#define CT_BLOCK 0x08 /* Block addressing */ + +#define CMD0 (0) /* GO_IDLE_STATE */ +#define CMD1 (1) /* SEND_OP_COND */ +#define CMD2 (2) /* SEND_CID */ +#define CMD3 (3) /* RELATIVE_ADDR */ +#define CMD4 (4) +#define CMD5 (5) /* SLEEP_WAKE (SDC) */ +#define CMD6 (6) /* SWITCH_FUNC */ +#define CMD7 (7) /* SELECT */ +#define CMD8 (8) /* SEND_IF_COND */ +#define CMD9 (9) /* SEND_CSD */ +#define CMD10 (10) /* SEND_CID */ +#define CMD11 (11) +#define CMD12 (12) /* STOP_TRANSMISSION */ +#define CMD13 (13) +#define CMD15 (15) +#define CMD16 (16) /* SET_BLOCKLEN */ +#define CMD17 (17) /* READ_SINGLE_BLOCK */ +#define CMD18 (18) /* READ_MULTIPLE_BLOCK */ +#define CMD19 (19) +#define CMD20 (20) +#define CMD23 (23) +#define CMD24 (24) +#define CMD25 (25) +#define CMD27 (27) +#define CMD28 (28) +#define CMD29 (29) +#define CMD30 (30) +#define CMD32 (32) +#define CMD33 (33) +#define CMD38 (38) +#define CMD42 (42) +#define CMD55 (55) /* APP_CMD */ +#define CMD56 (56) +#define ACMD6 (0x80+6) /* define the data bus width */ +#define ACMD41 (0x80+41) /* SEND_OP_COND (ACMD) */ + +// Capability bits +#define SDC_CAPABILITY_SD_4BIT 0x0001 +#define SDC_CAPABILITY_SD_RESET 0x0002 +#define SDC_CAPABILITY_ADDR 0xff00 + +// Control bits +#define SDC_CONTROL_SD_4BIT 0x0001 +#define SDC_CONTROL_SD_RESET 0x0002 + +// Card detect bits +#define SDC_CARD_INSERT_INT_EN 0x0001 +#define SDC_CARD_INSERT_INT_REQ 0x0002 +#define SDC_CARD_REMOVE_INT_EN 0x0004 +#define SDC_CARD_REMOVE_INT_REQ 0x0008 + +// Command status bits +#define SDC_CMD_INT_STATUS_CC 0x0001 // Command complete +#define SDC_CMD_INT_STATUS_EI 0x0002 // Any error +#define SDC_CMD_INT_STATUS_CTE 0x0004 // Timeout +#define SDC_CMD_INT_STATUS_CCRC 0x0008 // CRC error +#define SDC_CMD_INT_STATUS_CIE 0x0010 // Command code check error + +// Data status bits +#define SDC_DAT_INT_STATUS_TRS 0x0001 // Transfer complete +#define SDC_DAT_INT_STATUS_ERR 0x0002 // Any error +#define SDC_DAT_INT_STATUS_CTE 0x0004 // Timeout +#define SDC_DAT_INT_STATUS_CRC 0x0008 // CRC error +#define SDC_DAT_INT_STATUS_CFE 0x0010 // Data FIFO underrun or overrun + +#define ERR_EOF 30 +#define ERR_NOT_ELF 31 +#define ERR_ELF_BITS 32 +#define ERR_ELF_ENDIANNESS 33 +#define ERR_CMD_CRC 34 +#define ERR_CMD_CHECK 35 +#define ERR_DATA_CRC 36 +#define ERR_DATA_FIFO 37 +#define ERR_BUF_ALIGNMENT 38 + +struct sdc_regs { + volatile uint32_t argument; + volatile uint32_t command; + volatile uint32_t response1; + volatile uint32_t response2; + volatile uint32_t response3; + volatile uint32_t response4; + volatile uint32_t data_timeout; + volatile uint32_t control; + volatile uint32_t cmd_timeout; + volatile uint32_t clock_divider; + volatile uint32_t software_reset; + volatile uint32_t power_control; + volatile uint32_t capability; + volatile uint32_t cmd_int_status; + volatile uint32_t cmd_int_enable; + volatile uint32_t dat_int_status; + volatile uint32_t dat_int_enable; + volatile uint32_t block_size; + volatile uint32_t block_count; + volatile uint32_t card_detect; + volatile uint32_t res_50; + volatile uint32_t res_54; + volatile uint32_t res_58; + volatile uint32_t res_5c; + volatile uint64_t dma_addres; +}; + +static struct sdc_regs * const regs __attribute__((section(".rodata"))) = (struct sdc_regs *)0x00013100; + +static int errno __attribute__((section(".bss"))); +static DSTATUS drv_status __attribute__((section(".bss"))); +static BYTE card_type __attribute__((section(".bss"))); +static uint32_t response[4] __attribute__((section(".bss"))); +static FATFS fatfs __attribute__((section(".bss"))); +static int alt_mem __attribute__((section(".bss"))); +static FIL fd __attribute__((section(".bss"))); + +extern unsigned char _fbss[]; +extern unsigned char _ebss[]; + +static const char * errno_to_str(void) { + switch (errno) { + case FR_OK: return "No error"; + case FR_DISK_ERR: return "Disk I/O error"; + case FR_INT_ERR: return "Assertion failed"; + case FR_NOT_READY: return "Disk not ready"; + case FR_NO_FILE: return "File not found"; + case FR_NO_PATH: return "Path not found"; + case FR_INVALID_NAME: return "Invalid path"; + case FR_DENIED: return "Access denied"; + case FR_EXIST: return "Already exist"; + case FR_INVALID_OBJECT: return "The FS object is invalid"; + case FR_WRITE_PROTECTED: return "The drive is write protected"; + case FR_INVALID_DRIVE: return "The drive number is invalid"; + case FR_NOT_ENABLED: return "The volume has no work area"; + case FR_NO_FILESYSTEM: return "Not a valid FAT volume"; + case FR_MKFS_ABORTED: return "The f_mkfs() aborted"; + case FR_TIMEOUT: return "Timeout"; + case FR_LOCKED: return "Locked"; + case FR_NOT_ENOUGH_CORE: return "Not enough memory"; + case FR_TOO_MANY_OPEN_FILES: return "Too many open files"; + case ERR_EOF: return "Unexpected EOF"; + case ERR_NOT_ELF: return "Not an ELF file"; + case ERR_ELF_BITS: return "Wrong ELF word size"; + case ERR_ELF_ENDIANNESS: return "Wrong ELF endianness"; + case ERR_CMD_CRC: return "Command CRC error"; + case ERR_CMD_CHECK: return "Command code check error"; + case ERR_DATA_CRC: return "Data CRC error"; + case ERR_DATA_FIFO: return "Data FIFO error"; + case ERR_BUF_ALIGNMENT: return "Bad buffer alignment"; + } + return "Unknown error code"; +} + +static void usleep(unsigned us) { + uintptr_t cycles0; + uintptr_t cycles1; + asm volatile ("csrr %0, 0xB00" : "=r" (cycles0)); + for (;;) { + asm volatile ("csrr %0, 0xB00" : "=r" (cycles1)); + if (cycles1 - cycles0 >= us * 100) break; + } +} + +static int sdc_cmd_finish(unsigned cmd) { + while (1) { + unsigned status = regs->cmd_int_status; + if (status) { + // clear interrupts + regs->cmd_int_status = 0; + while (regs->software_reset != 0) {} + if (status == SDC_CMD_INT_STATUS_CC) { + // get response + response[0] = regs->response1; + response[1] = regs->response2; + response[2] = regs->response3; + response[3] = regs->response4; + return 0; + } + errno = FR_DISK_ERR; + if (status & SDC_CMD_INT_STATUS_CTE) errno = FR_TIMEOUT; + if (status & SDC_CMD_INT_STATUS_CCRC) errno = ERR_CMD_CRC; + if (status & SDC_CMD_INT_STATUS_CIE) errno = ERR_CMD_CHECK; + break; + } + } + return -1; +} + +static int sdc_data_finish(void) { + int status; + + while ((status = regs->dat_int_status) == 0) {} + regs->dat_int_status = 0; + while (regs->software_reset != 0) {} + + if (status == SDC_DAT_INT_STATUS_TRS) return 0; + errno = FR_DISK_ERR; + if (status & SDC_DAT_INT_STATUS_CTE) errno = FR_TIMEOUT; + if (status & SDC_DAT_INT_STATUS_CRC) errno = ERR_DATA_CRC; + if (status & SDC_DAT_INT_STATUS_CFE) errno = ERR_DATA_FIFO; + return -1; +} + +static int send_data_cmd(unsigned cmd, unsigned arg, void * buf, unsigned blocks) { + unsigned command = (cmd & 0x3f) << 8; + switch (cmd) { + case CMD0: + case CMD4: + case CMD15: + // No responce + break; + case CMD11: + case CMD13: + case CMD16: + case CMD17: + case CMD18: + case CMD19: + case CMD23: + case CMD24: + case CMD25: + case CMD27: + case CMD30: + case CMD32: + case CMD33: + case CMD42: + case CMD55: + case CMD56: + case ACMD6: + // R1 + command |= 1; // 48 bits + command |= 1 << 3; // resp CRC + command |= 1 << 4; // resp OPCODE + break; + case CMD7: + case CMD12: + case CMD20: + case CMD28: + case CMD29: + case CMD38: + // R1b + command |= 1; // 48 bits + command |= 1 << 2; // busy + command |= 1 << 3; // resp CRC + command |= 1 << 4; // resp OPCODE + break; + case CMD2: + case CMD9: + case CMD10: + // R2 + command |= 2; // 136 bits + command |= 1 << 3; // resp CRC + break; + case ACMD41: + // R3 + command |= 1; // 48 bits + break; + case CMD3: + // R6 + command |= 1; // 48 bits + command |= 1 << 2; // busy + command |= 1 << 3; // resp CRC + command |= 1 << 4; // resp OPCODE + break; + case CMD8: + // R7 + command |= 1; // 48 bits + command |= 1 << 3; // resp CRC + command |= 1 << 4; // resp OPCODE + break; + } + + if (blocks) { + command |= 1 << 5; + if ((intptr_t)buf & 3) { + errno = ERR_BUF_ALIGNMENT; + return -1; + } + regs->dma_addres = (uint64_t)(intptr_t)buf; + regs->block_size = 511; + regs->block_count = blocks - 1; + regs->data_timeout = 0xFFFFFF; + } + + regs->command = command; + regs->cmd_timeout = 0xFFFFF; + regs->argument = arg; + + if (sdc_cmd_finish(cmd) < 0) return -1; + if (blocks) return sdc_data_finish(); + + return 0; +} + +#define send_cmd(cmd, arg) send_data_cmd(cmd, arg, NULL, 0) + +static int ini_sd(void) { + unsigned rca; + + /* Reset controller */ + regs->software_reset = 1; + while ((regs->software_reset & 1) == 0) {} + regs->clock_divider = 0x7c; + regs->software_reset = 0; + while (regs->software_reset) {} + usleep(5000); + + card_type = 0; + drv_status = STA_NOINIT; + + if (regs->capability & SDC_CAPABILITY_SD_RESET) { + /* Power cycle SD card */ + regs->control |= SDC_CONTROL_SD_RESET; + usleep(1000000); + regs->control &= ~SDC_CONTROL_SD_RESET; + usleep(100000); + } + + /* Enter Idle state */ + send_cmd(CMD0, 0); + + card_type = CT_SD1; + if (send_cmd(CMD8, 0x1AA) == 0) { + if ((response[0] & 0xfff) != 0x1AA) { + errno = ERR_CMD_CHECK; + return -1; + } + card_type = CT_SD2; + } + + /* Wait for leaving idle state (ACMD41 with HCS bit) */ + while (1) { + /* ACMD41, Set Operating Conditions: Host High Capacity & 3.3V */ + if (send_cmd(CMD55, 0) < 0 || send_cmd(ACMD41, 0x40300000) < 0) return -1; + if (response[0] & (1 << 31)) { + if (response[0] & (1 << 30)) card_type |= CT_BLOCK; + break; + } + } + + /* Enter Identification state */ + if (send_cmd(CMD2, 0) < 0) return -1; + + /* Get RCA (Relative Card Address) */ + rca = 0x1234; + if (send_cmd(CMD3, rca << 16) < 0) return -1; + rca = response[0] >> 16; + + /* Select card */ + if (send_cmd(CMD7, rca << 16) < 0) return -1; + + /* Clock 25MHz */ + regs->clock_divider = 3; + usleep(10000); + + /* Bus width 1-bit */ + regs->control = 0; + if (send_cmd(CMD55, rca << 16) < 0 || send_cmd(ACMD6, 0) < 0) return -1; + + /* Set R/W block length to 512 */ + if (send_cmd(CMD16, 512) < 0) return -1; + + drv_status &= ~STA_NOINIT; + return 0; +}