diff --git a/fw/SummerCart64.qsf b/fw/SummerCart64.qsf index 961c172..8135ea3 100644 --- a/fw/SummerCart64.qsf +++ b/fw/SummerCart64.qsf @@ -19,7 +19,7 @@ # # Quartus Prime # Version 20.1.1 Build 720 11/11/2020 SJ Lite Edition -# Date created = 23:45:19 July 29, 2020 +# Date created = 00:33:20 February 17, 2021 # # -------------------------------------------------------------------------- # # @@ -55,7 +55,6 @@ set_global_assignment -name QIP_FILE rtl/intel/ram/ram_n64_eeprom.qip set_global_assignment -name QSYS_FILE rtl/intel/flash/onchip_flash.qsys set_global_assignment -name SDC_FILE constraints.sdc set_global_assignment -name SIGNALTAP_FILE output_files/signal_tap_logic_analyzer.stp -set_global_assignment -name SLD_FILE db/signal_tap_logic_analyzer_auto_stripped.stp set_global_assignment -name SYSTEMVERILOG_FILE rtl/intel/gpio/gpio_ddro/altera_gpio_lite.sv -library gpio_ddro set_global_assignment -name VERILOG_FILE rtl/cart/cart_control.v set_global_assignment -name VERILOG_FILE rtl/cart/cart_led.v @@ -78,6 +77,7 @@ set_global_assignment -name VERILOG_FILE rtl/top.v set_global_assignment -name VERILOG_FILE rtl/usb/usb_ftdi_fsi.v set_global_assignment -name VERILOG_FILE rtl/usb/usb_pc.v set_global_assignment -name VERILOG_INCLUDE_FILE rtl/constants.vh +set_global_assignment -name SLD_FILE db/signal_tap_logic_analyzer_auto_stripped.stp # Pin & Location Assignments # ========================== diff --git a/fw/rtl/intel/fifo/fifo_sd.qip b/fw/rtl/intel/fifo/fifo_sd.qip index 02e3a48..fa5788f 100644 --- a/fw/rtl/intel/fifo/fifo_sd.qip +++ b/fw/rtl/intel/fifo/fifo_sd.qip @@ -1,4 +1,4 @@ -set_global_assignment -name IP_TOOL_NAME "FIFO" -set_global_assignment -name IP_TOOL_VERSION "20.1" -set_global_assignment -name IP_GENERATED_DEVICE_FAMILY "{MAX 10}" -set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "fifo_sd.v"] +set_global_assignment -name IP_TOOL_NAME "FIFO" +set_global_assignment -name IP_TOOL_VERSION "20.1" +set_global_assignment -name IP_GENERATED_DEVICE_FAMILY "{MAX 10}" +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "fifo_sd.v"] diff --git a/fw/rtl/intel/fifo/fifo_sd.v b/fw/rtl/intel/fifo/fifo_sd.v index 911501c..bb38987 100644 --- a/fw/rtl/intel/fifo/fifo_sd.v +++ b/fw/rtl/intel/fifo/fifo_sd.v @@ -1,169 +1,169 @@ -// megafunction wizard: %FIFO% -// GENERATION: STANDARD -// VERSION: WM1.0 -// MODULE: scfifo - -// ============================================================ -// File Name: fifo_sd.v -// Megafunction Name(s): -// scfifo -// -// Simulation Library Files(s): -// altera_mf -// ============================================================ -// ************************************************************ -// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! -// -// 20.1.1 Build 720 11/11/2020 SJ Lite Edition -// ************************************************************ - - -//Copyright (C) 2020 Intel Corporation. All rights reserved. -//Your use of Intel Corporation's design tools, logic functions -//and other software and tools, and any partner logic -//functions, and any output files from any of the foregoing -//(including device programming or simulation files), and any -//associated documentation or information are expressly subject -//to the terms and conditions of the Intel Program License -//Subscription Agreement, the Intel Quartus Prime License Agreement, -//the Intel FPGA IP License Agreement, or other applicable license -//agreement, including, without limitation, that your use is for -//the sole purpose of programming logic devices manufactured by -//Intel and sold by Intel or its authorized distributors. Please -//refer to the applicable agreement for further details, at -//https://fpgasoftware.intel.com/eula. - - -// synopsys translate_off -`timescale 1 ps / 1 ps -// synopsys translate_on -module fifo_sd ( - clock, - data, - rdreq, - sclr, - wrreq, - empty, - full, - q, - usedw); - - input clock; - input [31:0] data; - input rdreq; - input sclr; - input wrreq; - output empty; - output full; - output [31:0] q; - output [7:0] usedw; - - wire sub_wire0; - wire sub_wire1; - wire [31:0] sub_wire2; - wire [7:0] sub_wire3; - wire empty = sub_wire0; - wire full = sub_wire1; - wire [31:0] q = sub_wire2[31:0]; - wire [7:0] usedw = sub_wire3[7:0]; - - scfifo scfifo_component ( - .clock (clock), - .data (data), - .rdreq (rdreq), - .sclr (sclr), - .wrreq (wrreq), - .empty (sub_wire0), - .full (sub_wire1), - .q (sub_wire2), - .usedw (sub_wire3), - .aclr (), - .almost_empty (), - .almost_full (), - .eccstatus ()); - defparam - scfifo_component.add_ram_output_register = "ON", - scfifo_component.intended_device_family = "MAX 10", - scfifo_component.lpm_numwords = 256, - scfifo_component.lpm_showahead = "ON", - scfifo_component.lpm_type = "scfifo", - scfifo_component.lpm_width = 32, - scfifo_component.lpm_widthu = 8, - scfifo_component.overflow_checking = "ON", - scfifo_component.underflow_checking = "ON", - scfifo_component.use_eab = "ON"; - - -endmodule - -// ============================================================ -// CNX file retrieval info -// ============================================================ -// Retrieval info: PRIVATE: AlmostEmpty NUMERIC "0" -// Retrieval info: PRIVATE: AlmostEmptyThr NUMERIC "-1" -// Retrieval info: PRIVATE: AlmostFull NUMERIC "0" -// Retrieval info: PRIVATE: AlmostFullThr NUMERIC "-1" -// Retrieval info: PRIVATE: CLOCKS_ARE_SYNCHRONIZED NUMERIC "0" -// Retrieval info: PRIVATE: Clock NUMERIC "0" -// Retrieval info: PRIVATE: Depth NUMERIC "256" -// Retrieval info: PRIVATE: Empty NUMERIC "1" -// Retrieval info: PRIVATE: Full NUMERIC "1" -// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "MAX 10" -// Retrieval info: PRIVATE: LE_BasedFIFO NUMERIC "0" -// Retrieval info: PRIVATE: LegacyRREQ NUMERIC "0" -// Retrieval info: PRIVATE: MAX_DEPTH_BY_9 NUMERIC "0" -// Retrieval info: PRIVATE: OVERFLOW_CHECKING NUMERIC "0" -// Retrieval info: PRIVATE: Optimize NUMERIC "1" -// Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "0" -// Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" -// Retrieval info: PRIVATE: UNDERFLOW_CHECKING NUMERIC "0" -// Retrieval info: PRIVATE: UsedW NUMERIC "1" -// Retrieval info: PRIVATE: Width NUMERIC "32" -// Retrieval info: PRIVATE: dc_aclr NUMERIC "0" -// Retrieval info: PRIVATE: diff_widths NUMERIC "0" -// Retrieval info: PRIVATE: msb_usedw NUMERIC "0" -// Retrieval info: PRIVATE: output_width NUMERIC "32" -// Retrieval info: PRIVATE: rsEmpty NUMERIC "1" -// Retrieval info: PRIVATE: rsFull NUMERIC "0" -// Retrieval info: PRIVATE: rsUsedW NUMERIC "0" -// Retrieval info: PRIVATE: sc_aclr NUMERIC "0" -// Retrieval info: PRIVATE: sc_sclr NUMERIC "1" -// Retrieval info: PRIVATE: wsEmpty NUMERIC "0" -// Retrieval info: PRIVATE: wsFull NUMERIC "1" -// Retrieval info: PRIVATE: wsUsedW NUMERIC "0" -// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all -// Retrieval info: CONSTANT: ADD_RAM_OUTPUT_REGISTER STRING "ON" -// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "MAX 10" -// Retrieval info: CONSTANT: LPM_NUMWORDS NUMERIC "256" -// Retrieval info: CONSTANT: LPM_SHOWAHEAD STRING "ON" -// Retrieval info: CONSTANT: LPM_TYPE STRING "scfifo" -// Retrieval info: CONSTANT: LPM_WIDTH NUMERIC "32" -// Retrieval info: CONSTANT: LPM_WIDTHU NUMERIC "8" -// Retrieval info: CONSTANT: OVERFLOW_CHECKING STRING "ON" -// Retrieval info: CONSTANT: UNDERFLOW_CHECKING STRING "ON" -// Retrieval info: CONSTANT: USE_EAB STRING "ON" -// Retrieval info: USED_PORT: clock 0 0 0 0 INPUT NODEFVAL "clock" -// Retrieval info: USED_PORT: data 0 0 32 0 INPUT NODEFVAL "data[31..0]" -// Retrieval info: USED_PORT: empty 0 0 0 0 OUTPUT NODEFVAL "empty" -// Retrieval info: USED_PORT: full 0 0 0 0 OUTPUT NODEFVAL "full" -// Retrieval info: USED_PORT: q 0 0 32 0 OUTPUT NODEFVAL "q[31..0]" -// Retrieval info: USED_PORT: rdreq 0 0 0 0 INPUT NODEFVAL "rdreq" -// Retrieval info: USED_PORT: sclr 0 0 0 0 INPUT NODEFVAL "sclr" -// Retrieval info: USED_PORT: usedw 0 0 8 0 OUTPUT NODEFVAL "usedw[7..0]" -// Retrieval info: USED_PORT: wrreq 0 0 0 0 INPUT NODEFVAL "wrreq" -// Retrieval info: CONNECT: @clock 0 0 0 0 clock 0 0 0 0 -// Retrieval info: CONNECT: @data 0 0 32 0 data 0 0 32 0 -// Retrieval info: CONNECT: @rdreq 0 0 0 0 rdreq 0 0 0 0 -// Retrieval info: CONNECT: @sclr 0 0 0 0 sclr 0 0 0 0 -// Retrieval info: CONNECT: @wrreq 0 0 0 0 wrreq 0 0 0 0 -// Retrieval info: CONNECT: empty 0 0 0 0 @empty 0 0 0 0 -// Retrieval info: CONNECT: full 0 0 0 0 @full 0 0 0 0 -// Retrieval info: CONNECT: q 0 0 32 0 @q 0 0 32 0 -// Retrieval info: CONNECT: usedw 0 0 8 0 @usedw 0 0 8 0 -// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_sd.v TRUE -// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_sd.inc FALSE -// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_sd.cmp FALSE -// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_sd.bsf FALSE -// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_sd_inst.v FALSE -// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_sd_bb.v FALSE -// Retrieval info: LIB_FILE: altera_mf +// megafunction wizard: %FIFO% +// GENERATION: STANDARD +// VERSION: WM1.0 +// MODULE: scfifo + +// ============================================================ +// File Name: fifo_sd.v +// Megafunction Name(s): +// scfifo +// +// Simulation Library Files(s): +// altera_mf +// ============================================================ +// ************************************************************ +// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! +// +// 20.1.1 Build 720 11/11/2020 SJ Lite Edition +// ************************************************************ + + +//Copyright (C) 2020 Intel Corporation. All rights reserved. +//Your use of Intel Corporation's design tools, logic functions +//and other software and tools, and any partner logic +//functions, and any output files from any of the foregoing +//(including device programming or simulation files), and any +//associated documentation or information are expressly subject +//to the terms and conditions of the Intel Program License +//Subscription Agreement, the Intel Quartus Prime License Agreement, +//the Intel FPGA IP License Agreement, or other applicable license +//agreement, including, without limitation, that your use is for +//the sole purpose of programming logic devices manufactured by +//Intel and sold by Intel or its authorized distributors. Please +//refer to the applicable agreement for further details, at +//https://fpgasoftware.intel.com/eula. + + +// synopsys translate_off +`timescale 1 ps / 1 ps +// synopsys translate_on +module fifo_sd ( + clock, + data, + rdreq, + sclr, + wrreq, + empty, + full, + q, + usedw); + + input clock; + input [31:0] data; + input rdreq; + input sclr; + input wrreq; + output empty; + output full; + output [31:0] q; + output [7:0] usedw; + + wire sub_wire0; + wire sub_wire1; + wire [31:0] sub_wire2; + wire [7:0] sub_wire3; + wire empty = sub_wire0; + wire full = sub_wire1; + wire [31:0] q = sub_wire2[31:0]; + wire [7:0] usedw = sub_wire3[7:0]; + + scfifo scfifo_component ( + .clock (clock), + .data (data), + .rdreq (rdreq), + .sclr (sclr), + .wrreq (wrreq), + .empty (sub_wire0), + .full (sub_wire1), + .q (sub_wire2), + .usedw (sub_wire3), + .aclr (), + .almost_empty (), + .almost_full (), + .eccstatus ()); + defparam + scfifo_component.add_ram_output_register = "ON", + scfifo_component.intended_device_family = "MAX 10", + scfifo_component.lpm_numwords = 256, + scfifo_component.lpm_showahead = "ON", + scfifo_component.lpm_type = "scfifo", + scfifo_component.lpm_width = 32, + scfifo_component.lpm_widthu = 8, + scfifo_component.overflow_checking = "ON", + scfifo_component.underflow_checking = "ON", + scfifo_component.use_eab = "ON"; + + +endmodule + +// ============================================================ +// CNX file retrieval info +// ============================================================ +// Retrieval info: PRIVATE: AlmostEmpty NUMERIC "0" +// Retrieval info: PRIVATE: AlmostEmptyThr NUMERIC "-1" +// Retrieval info: PRIVATE: AlmostFull NUMERIC "0" +// Retrieval info: PRIVATE: AlmostFullThr NUMERIC "-1" +// Retrieval info: PRIVATE: CLOCKS_ARE_SYNCHRONIZED NUMERIC "0" +// Retrieval info: PRIVATE: Clock NUMERIC "0" +// Retrieval info: PRIVATE: Depth NUMERIC "256" +// Retrieval info: PRIVATE: Empty NUMERIC "1" +// Retrieval info: PRIVATE: Full NUMERIC "1" +// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "MAX 10" +// Retrieval info: PRIVATE: LE_BasedFIFO NUMERIC "0" +// Retrieval info: PRIVATE: LegacyRREQ NUMERIC "0" +// Retrieval info: PRIVATE: MAX_DEPTH_BY_9 NUMERIC "0" +// Retrieval info: PRIVATE: OVERFLOW_CHECKING NUMERIC "0" +// Retrieval info: PRIVATE: Optimize NUMERIC "1" +// Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "0" +// Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" +// Retrieval info: PRIVATE: UNDERFLOW_CHECKING NUMERIC "0" +// Retrieval info: PRIVATE: UsedW NUMERIC "1" +// Retrieval info: PRIVATE: Width NUMERIC "32" +// Retrieval info: PRIVATE: dc_aclr NUMERIC "0" +// Retrieval info: PRIVATE: diff_widths NUMERIC "0" +// Retrieval info: PRIVATE: msb_usedw NUMERIC "0" +// Retrieval info: PRIVATE: output_width NUMERIC "32" +// Retrieval info: PRIVATE: rsEmpty NUMERIC "1" +// Retrieval info: PRIVATE: rsFull NUMERIC "0" +// Retrieval info: PRIVATE: rsUsedW NUMERIC "0" +// Retrieval info: PRIVATE: sc_aclr NUMERIC "0" +// Retrieval info: PRIVATE: sc_sclr NUMERIC "1" +// Retrieval info: PRIVATE: wsEmpty NUMERIC "0" +// Retrieval info: PRIVATE: wsFull NUMERIC "1" +// Retrieval info: PRIVATE: wsUsedW NUMERIC "0" +// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all +// Retrieval info: CONSTANT: ADD_RAM_OUTPUT_REGISTER STRING "ON" +// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "MAX 10" +// Retrieval info: CONSTANT: LPM_NUMWORDS NUMERIC "256" +// Retrieval info: CONSTANT: LPM_SHOWAHEAD STRING "ON" +// Retrieval info: CONSTANT: LPM_TYPE STRING "scfifo" +// Retrieval info: CONSTANT: LPM_WIDTH NUMERIC "32" +// Retrieval info: CONSTANT: LPM_WIDTHU NUMERIC "8" +// Retrieval info: CONSTANT: OVERFLOW_CHECKING STRING "ON" +// Retrieval info: CONSTANT: UNDERFLOW_CHECKING STRING "ON" +// Retrieval info: CONSTANT: USE_EAB STRING "ON" +// Retrieval info: USED_PORT: clock 0 0 0 0 INPUT NODEFVAL "clock" +// Retrieval info: USED_PORT: data 0 0 32 0 INPUT NODEFVAL "data[31..0]" +// Retrieval info: USED_PORT: empty 0 0 0 0 OUTPUT NODEFVAL "empty" +// Retrieval info: USED_PORT: full 0 0 0 0 OUTPUT NODEFVAL "full" +// Retrieval info: USED_PORT: q 0 0 32 0 OUTPUT NODEFVAL "q[31..0]" +// Retrieval info: USED_PORT: rdreq 0 0 0 0 INPUT NODEFVAL "rdreq" +// Retrieval info: USED_PORT: sclr 0 0 0 0 INPUT NODEFVAL "sclr" +// Retrieval info: USED_PORT: usedw 0 0 8 0 OUTPUT NODEFVAL "usedw[7..0]" +// Retrieval info: USED_PORT: wrreq 0 0 0 0 INPUT NODEFVAL "wrreq" +// Retrieval info: CONNECT: @clock 0 0 0 0 clock 0 0 0 0 +// Retrieval info: CONNECT: @data 0 0 32 0 data 0 0 32 0 +// Retrieval info: CONNECT: @rdreq 0 0 0 0 rdreq 0 0 0 0 +// Retrieval info: CONNECT: @sclr 0 0 0 0 sclr 0 0 0 0 +// Retrieval info: CONNECT: @wrreq 0 0 0 0 wrreq 0 0 0 0 +// Retrieval info: CONNECT: empty 0 0 0 0 @empty 0 0 0 0 +// Retrieval info: CONNECT: full 0 0 0 0 @full 0 0 0 0 +// Retrieval info: CONNECT: q 0 0 32 0 @q 0 0 32 0 +// Retrieval info: CONNECT: usedw 0 0 8 0 @usedw 0 0 8 0 +// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_sd.v TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_sd.inc FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_sd.cmp FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_sd.bsf FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_sd_inst.v FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_sd_bb.v FALSE +// Retrieval info: LIB_FILE: altera_mf diff --git a/fw/rtl/sd/sd_dat.v b/fw/rtl/sd/sd_dat.v index a6998c3..10c0863 100644 --- a/fw/rtl/sd/sd_dat.v +++ b/fw/rtl/sd/sd_dat.v @@ -14,13 +14,16 @@ module sd_dat ( input i_dat_start, input i_dat_stop, output o_dat_busy, + output o_dat_write_busy, output reg o_dat_crc_error, + output reg o_dat_write_error, - output reg o_rx_fifo_push, input i_rx_fifo_overrun, + output reg o_rx_fifo_push, output reg [31:0] o_rx_fifo_data, - input i_tx_fifo_full, + input [8:0] i_tx_fifo_items, + input i_tx_fifo_underrun, output reg o_tx_fifo_pop, input [31:0] i_tx_fifo_data ); @@ -30,33 +33,48 @@ module sd_dat ( localparam STATE_IDLE = 0; localparam STATE_READ_WAIT = 1; localparam STATE_RECEIVING = 2; + localparam STATE_WRITE_WAIT = 3; + localparam STATE_SENDING = 4; + localparam STATE_STATUS = 5; + localparam STATE_BUSY = 6; - reg [2:0] r_state; + reg [6:0] r_state; + + assign o_dat_busy = !r_state[STATE_IDLE]; + assign o_dat_write_busy = r_state[STATE_SENDING] || r_state[STATE_STATUS] || r_state[STATE_BUSY]; // Bit counter logic reg [12:0] r_bit_counter; - reg r_bit_done; + reg r_bit_counter_done; - wire w_start_bit = !io_sd_dat[0] && i_sd_clk_strobe_rising && r_state[STATE_READ_WAIT]; - wire w_data_end = r_bit_done && r_state[STATE_RECEIVING]; + wire w_read_start = r_state[STATE_READ_WAIT] && !io_sd_dat[0] && i_sd_clk_strobe_rising; + wire w_write_start = r_state[STATE_WRITE_WAIT] && (i_tx_fifo_items == ({1'b0, i_dat_block_size} + 1)) && i_sd_clk_strobe_falling; + wire w_status_start = r_state[STATE_SENDING] && r_bit_counter_done; + wire w_status_done = r_state[STATE_STATUS] && r_bit_counter_done; + wire w_block_read_done = r_state[STATE_RECEIVING] && r_bit_counter_done; + wire w_block_write_done = r_state[STATE_SENDING] && r_bit_counter_done; + wire w_block_done = w_block_read_done || w_block_write_done; + wire w_block_write_busy_done = r_state[STATE_BUSY] && io_sd_dat[0]; - assign o_dat_busy = !r_state[STATE_IDLE]; + wire [12:0] w_block_bit_length = i_dat_width ? ({2'b00, {1'b0, i_dat_block_size} + 1'd1, 3'b000}) : ({{1'b0, i_dat_block_size} + 1'd1, 5'b00000}); always @(posedge i_clk) begin - if (w_start_bit) begin - r_bit_counter <= (i_dat_width ? ( - {2'b00, {1'b0, i_dat_block_size} + 1'd1, 3'b000} - ) : ( - {{1'b0, i_dat_block_size} + 1'd1, 5'b00000} - )) + 13'd16; - r_bit_done <= 1'b0; + if (w_read_start) begin + r_bit_counter <= w_block_bit_length + 13'd16; + r_bit_counter_done <= 1'b0; + end else if (w_write_start) begin + r_bit_counter <= w_block_bit_length + 13'd17; + r_bit_counter_done <= 1'b0; + end else if (w_status_start) begin + r_bit_counter <= 13'd6; + r_bit_counter_done <= 1'b0; end else if (i_sd_clk_strobe_rising) begin if (r_bit_counter > 13'd0) begin r_bit_counter <= r_bit_counter - 1'd1; end else begin - r_bit_done <= 1'b1; + r_bit_counter_done <= 1'd1; end end end @@ -66,13 +84,13 @@ module sd_dat ( reg [7:0] r_block_counter; - wire w_read_start = i_dat_start && r_state[STATE_IDLE]; - wire w_read_stop = r_block_counter == 8'd0; + wire w_block_start = i_dat_start && r_state[STATE_IDLE]; + wire w_block_stop = r_block_counter == 8'd0; always @(posedge i_clk) begin - if (w_read_start) begin + if (w_block_start) begin r_block_counter <= i_dat_num_blocks; - end else if (w_data_end) begin + end else if (w_block_done) begin if (r_block_counter > 8'd0) begin r_block_counter <= r_block_counter - 1'd1; end @@ -84,12 +102,12 @@ module sd_dat ( reg [15:0] r_crc_16_received [0:3]; - wire w_crc_shift_reset = !r_state[STATE_RECEIVING]; + wire w_crc_shift_reset = !(r_state[STATE_RECEIVING] || r_state[STATE_SENDING]); wire w_crc_shift_enabled = r_bit_counter > 13'd16; wire w_crc_shift = w_crc_shift_enabled && i_sd_clk_strobe_rising; wire [15:0] w_crc_16_calculated [0:3]; - wire w_crc_error = (r_bit_counter == 13'd0) && (i_dat_width ? ( + wire w_crc_read_error = (r_bit_counter == 13'd0) && (i_dat_width ? ( (w_crc_16_calculated[0] != r_crc_16_received[0]) && (w_crc_16_calculated[1] != r_crc_16_received[1]) && (w_crc_16_calculated[2] != r_crc_16_received[2]) && @@ -114,12 +132,25 @@ module sd_dat ( // Control signals + localparam [4:0] STATUS_NO_ERROR = 5'b00101; + localparam [4:0] STATUS_CRC_ERROR = 5'b01011; + localparam [4:0] STATUS_WRITE_ERROR = 5'b01101; + + reg [4:0] r_status; + + wire w_crc_write_error = r_status == STATUS_CRC_ERROR; + wire w_data_write_error = r_status == STATUS_WRITE_ERROR; + always @(posedge i_clk) begin if (i_reset) begin o_dat_crc_error <= 1'b0; end else begin - if (w_data_end) begin - o_dat_crc_error <= w_crc_error; + if (w_block_read_done) begin + o_dat_crc_error <= w_crc_read_error; + end + if (w_status_done) begin + o_dat_crc_error <= w_crc_write_error; + o_dat_write_error <= w_data_write_error; end end end @@ -131,7 +162,7 @@ module sd_dat ( if (i_reset) begin r_state <= (1'b1 << STATE_IDLE); end else begin - r_state <= 3'b000; + r_state <= 7'b0000000; if (i_dat_stop) begin r_state[STATE_IDLE] <= 1'b1; @@ -140,7 +171,7 @@ module sd_dat ( r_state[STATE_IDLE]: begin if (i_dat_start) begin if (i_dat_direction) begin - r_state[STATE_IDLE] <= 1'b1; // TODO: Sending + r_state[STATE_WRITE_WAIT] <= 1'b1; end else begin r_state[STATE_READ_WAIT] <= 1'b1; end @@ -150,7 +181,7 @@ module sd_dat ( end r_state[STATE_READ_WAIT]: begin - if (w_start_bit) begin + if (w_read_start) begin r_state[STATE_RECEIVING] <= 1'b1; end else begin r_state[STATE_READ_WAIT] <= 1'b1; @@ -158,10 +189,10 @@ module sd_dat ( end r_state[STATE_RECEIVING]: begin - if (w_crc_error || i_rx_fifo_overrun) begin + if (w_crc_read_error || i_rx_fifo_overrun) begin r_state[STATE_IDLE] <= 1'b1; - end else if (w_data_end) begin - if (w_read_stop) begin + end else if (w_block_read_done) begin + if (w_block_stop) begin r_state[STATE_IDLE] <= 1'b1; end else begin r_state[STATE_READ_WAIT] <= 1'b1; @@ -170,34 +201,66 @@ module sd_dat ( r_state[STATE_RECEIVING] <= 1'b1; end end + + r_state[STATE_WRITE_WAIT]: begin + if (w_write_start) begin + r_state[STATE_SENDING] <= 1'b1; + end else begin + r_state[STATE_WRITE_WAIT] <= 1'b1; + end + end + + r_state[STATE_SENDING]: begin + if (i_tx_fifo_underrun) begin + r_state[STATE_IDLE] <= 1'b1; + end else if (w_block_write_done) begin + r_state[STATE_STATUS] <= 1'b1; + end else begin + r_state[STATE_SENDING] <= 1'b1; + end + end + + r_state[STATE_STATUS]: begin + if (w_status_done) begin + r_state[STATE_BUSY] <= 1'b1; + end else begin + r_state[STATE_STATUS] <= 1'b1; + end + end + + r_state[STATE_BUSY]: begin + if (w_block_write_busy_done) begin + if (w_block_stop) begin + r_state[STATE_IDLE] <= 1'b1; + end else begin + r_state[STATE_WRITE_WAIT] <= 1'b1; + end + end else begin + r_state[STATE_BUSY] <= 1'b1; + end + end endcase end end end - // Shifting operation + // RX shifting operation - wire [31:0] w_shift_1_bit = {o_rx_fifo_data[30:0], io_sd_dat[0]}; - wire [31:0] w_shift_4_bit = {o_rx_fifo_data[27:0], io_sd_dat}; + wire w_rx_latch = r_state[STATE_RECEIVING] && i_sd_clk_strobe_rising; + wire w_rx_data_phase = r_bit_counter >= 13'd17; + wire w_rx_crc_phase = r_bit_counter >= 13'd1; + wire w_rx_fifo_push = i_dat_width ? (r_bit_counter[2:0] == 3'd1) : (r_bit_counter[4:0] == 5'd17); + wire [31:0] w_rx_fifo_shift = i_dat_width ? {o_rx_fifo_data[27:0], io_sd_dat} : {o_rx_fifo_data[30:0], io_sd_dat[0]}; always @(posedge i_clk) begin o_rx_fifo_push <= 1'b0; - if (i_sd_clk_strobe_rising && r_state[STATE_RECEIVING]) begin - if (r_bit_counter > 13'd16) begin - if (i_dat_width) begin - o_rx_fifo_data <= w_shift_4_bit; - if (r_bit_counter[2:0] == 3'd1) begin - o_rx_fifo_push <= 1'b1; - end - end else begin - o_rx_fifo_data <= w_shift_1_bit; - if (r_bit_counter[4:0] == 5'd17) begin - o_rx_fifo_push <= 1'b1; - end - end - end else if (r_bit_counter > 13'd0) begin + if (w_rx_latch) begin + if (w_rx_data_phase) begin + o_rx_fifo_data <= w_rx_fifo_shift; + o_rx_fifo_push <= w_rx_fifo_push; + end else if (w_rx_crc_phase) begin for (integer i = 0; i < 4; i = i + 1) begin r_crc_16_received[i] <= {r_crc_16_received[i][14:0], io_sd_dat[i]}; end @@ -205,4 +268,72 @@ module sd_dat ( end end + + // TX shifting operation + + wire w_tx_latch = r_state[STATE_SENDING] && i_sd_clk_strobe_falling; + wire w_tx_data_phase = r_bit_counter >= 13'd17; + wire w_tx_crc_phase = r_bit_counter >= 13'd1; + wire w_tx_fifo_pop = i_dat_width ? (r_bit_counter[2:0] == 3'd0) : (r_bit_counter[4:0] == 5'd16); + wire w_tx_shift_load = r_bit_counter[2:0] == 3'd0; + + reg [7:0] r_tx_shift [0:3]; + + always @(*) begin + io_sd_dat = 4'bZZZZ; + if (r_state[STATE_SENDING]) begin + io_sd_dat = i_dat_width ? ( + {r_tx_shift[3][7], r_tx_shift[2][7], r_tx_shift[1][7], r_tx_shift[0][7]} + ) : ( + {3'bZZZ, r_tx_shift[0][7]} + ); + end + end + + always @(posedge i_clk) begin + o_tx_fifo_pop <= 1'b0; + + if (w_write_start) begin + {r_tx_shift[3][7], r_tx_shift[2][7], r_tx_shift[1][7], r_tx_shift[0][7]} <= 4'b0000; + end else if (w_tx_latch) begin + if (w_tx_data_phase) begin + o_tx_fifo_pop <= w_tx_fifo_pop; + for (integer i = 0; i < 4; i = i + 1) begin + r_tx_shift[i] <= {r_tx_shift[i][6:0], 1'b0}; + end + if (w_tx_shift_load) begin + if (i_dat_width) begin + for (integer i = 0; i < 4; i = i + 1) begin + for (integer j = 0; j < 8; j = j + 1) begin + r_tx_shift[i][j] <= i_tx_fifo_data[((j * 4) + i)]; + end + end + end else begin + r_tx_shift[0] <= i_tx_fifo_data[{3'b000, r_bit_counter[4:3]} +: 8]; + end + end + end else if (w_tx_crc_phase) begin + for (integer i = 0; i < 4; i = i + 1) begin + r_tx_shift[i] <= {r_tx_shift[i][6:0], 1'b0}; + if (w_tx_shift_load) begin + r_tx_shift[i] <= !r_bit_counter[3] ? w_crc_16_calculated[i][15:8] : w_crc_16_calculated[i][7:0]; + end + end + end else begin + {r_tx_shift[3][7], r_tx_shift[2][7], r_tx_shift[1][7], r_tx_shift[0][7]} <= 4'b1111; + end + end + end + + + // Status shifting operation + + wire w_status_latch = r_state[STATE_STATUS] && i_sd_clk_strobe_rising; + + always @(posedge i_clk) begin + if (w_status_latch) begin + r_status <= {r_status[3:0], io_sd_dat[0]}; + end + end + endmodule diff --git a/fw/rtl/sd/sd_interface.v b/fw/rtl/sd/sd_interface.v index 07f5478..16c5742 100644 --- a/fw/rtl/sd/sd_interface.v +++ b/fw/rtl/sd/sd_interface.v @@ -156,7 +156,9 @@ module sd_interface ( wire w_dat_start; wire w_dat_stop; wire w_dat_busy; + wire w_dat_write_busy; wire w_dat_crc_error; + wire w_dat_write_error; sd_dat sd_dat_inst ( .i_clk(i_clk), @@ -174,13 +176,16 @@ module sd_interface ( .i_dat_start(w_dat_start), .i_dat_stop(w_dat_stop), .o_dat_busy(w_dat_busy), + .o_dat_write_busy(w_dat_write_busy), .o_dat_crc_error(w_dat_crc_error), + .o_dat_write_error(w_dat_write_error), - .o_rx_fifo_push(w_rx_fifo_push), .i_rx_fifo_overrun(w_rx_fifo_overrun), + .o_rx_fifo_push(w_rx_fifo_push), .o_rx_fifo_data(w_rx_fifo_i_data), - - .i_tx_fifo_full(w_tx_fifo_full), + + .i_tx_fifo_items(w_tx_fifo_items), + .i_tx_fifo_underrun(w_tx_fifo_underrun), .o_tx_fifo_pop(w_tx_fifo_pop), .i_tx_fifo_data(w_tx_fifo_o_data) ); @@ -259,7 +264,9 @@ module sd_interface ( .o_dat_start(w_dat_start), .o_dat_stop(w_dat_stop), .i_dat_busy(w_dat_busy), + .i_dat_write_busy(w_dat_write_busy), .i_dat_crc_error(w_dat_crc_error), + .i_dat_write_error(w_dat_write_error), .o_rx_fifo_flush(w_rx_fifo_flush), .o_rx_fifo_pop(w_rx_fifo_regs_pop), diff --git a/fw/rtl/sd/sd_regs.v b/fw/rtl/sd/sd_regs.v index 095c13c..02afded 100644 --- a/fw/rtl/sd/sd_regs.v +++ b/fw/rtl/sd/sd_regs.v @@ -22,7 +22,9 @@ module sd_regs ( output reg o_dat_start, output reg o_dat_stop, input i_dat_busy, + input i_dat_write_busy, input i_dat_crc_error, + input i_dat_write_error, output reg o_rx_fifo_flush, output reg o_rx_fifo_pop, @@ -202,7 +204,9 @@ module sd_regs ( SD_REG_DAT: begin o_data <= { - 6'd0, + 4'd0, + i_dat_write_error, + i_dat_write_busy, i_tx_fifo_items, i_tx_fifo_full, i_tx_fifo_empty,