OpenCores
URL https://opencores.org/ocsvn/sd_mmc_emulator/sd_mmc_emulator/trunk

Subversion Repositories sd_mmc_emulator

[/] [sd_mmc_emulator/] [trunk/] [rtl/] [mmc_test_pack.vhd] - Rev 2

Compare with Previous | Blame | View Log

--------------------------------------------------------------------------
--------------------------------------------------------------------------
-- Package containing SD Card interface modules,
-- and related support modules.
--
-- 15-Aug-2017 RMR Backdoor opcodes not needed, SPI debugger still at 3000040
-- xx-Jun-2017 RMR Changed SPI debugger to 'w 03000040' so backdoor opcode could use 3000030 
-- 31-Mar-2017 RMR Added SPI debug capability to 'w 03000030'
--
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
library work;
use work.sd_card_pack.all;
use work.sd_host_pack.all;
 
package mmc_test_pack is
 
  component mmc_test_cmd_rx
  port(
    -- Asynchronous reset
    sys_rst_n   : in  std_logic;
    -- SD/MMC card command signals
    sd_clk_i    : in  std_logic;
    sd_cmd_i    : in  std_logic;
    -- Command outputs
    cmd_raw_o   : out unsigned(47 downto 0);
    -- Status and done indicator
    cmd_done_o  : out std_logic;
    crc_err_o   : out std_logic;
    stop_err_o  : out std_logic
  );
  end component;
 
  component mmc_tester
  generic (
    SYS_CLK_RATE        : real; -- The clock rate at which the FPGA runs
    SYS_LEDS            : natural; -- Number of LED outputs on the board
    SYS_SWITCHES        : natural; -- Number of Switch inputs on the board
    EXT_CSD_INIT_FILE   : string; -- Initial contents of EXT_CSD
    HOST_RAM_ADR_BITS   : natural; -- Determines amount of BRAM in MMC host
    MMC_FIFO_DEPTH      : integer;
    MMC_FILL_LEVEL_BITS : integer; -- Should be at least int(floor(log2(FIFO_DEPTH))+1.0)
    RSP_FILL_LEVEL_BITS : integer; 
    MMC_RAM_ADR_BITS    : integer
  );
  port (
 
    -- Asynchronous reset
    sys_rst_n      : in  std_logic;
    sys_clk        : in  std_logic;
 
    -- Asynchronous serial interface
    cmd_i          : in  std_logic;
    resp_o         : out std_logic;
 
    -- Board related
    switch_i       : in  unsigned(SYS_SWITCHES-1 downto 0);
    led_o          : out unsigned(SYS_LEDS-1 downto 0);
 
    -- Interface for SD/MMC traffic logging
    -- via asynchronous serial transmission
    tlm_send_i     : in  std_logic;
    tlm_o          : out std_logic;
 
    -- Tester Function Enables
    slave_en_i     : in  std_logic; -- OR with register bit
    host_en_i      : in  std_logic; -- OR with register bit
 
    -- SD/MMC card signals
    mmc_clk_i      : in  std_logic;
    mmc_clk_o      : out std_logic;
    mmc_clk_oe_o   : out std_logic;
    mmc_cmd_i      : in  std_logic;
    mmc_cmd_o      : out std_logic;
    mmc_cmd_oe_o   : out std_logic;
    mmc_dat_i      : in  unsigned(7 downto 0);
    mmc_dat_o      : out unsigned(7 downto 0);
    mmc_dat_oe_o   : out std_logic;
    mmc_od_mode_o  : out std_logic; -- Open drain mode
    mmc_dat_siz_o  : out unsigned(1 downto 0);
 
    dbg_spi_data0_o     : out unsigned(7 downto 0);
    dbg_spi_data1_o     : out unsigned(7 downto 0);
    dbg_spi_data2_o     : out unsigned(7 downto 0);
    dbg_spi_data3_o     : out unsigned(7 downto 0);
    dbg_spi_data4_o     : out unsigned(7 downto 0);
    dbg_spi_data5_o     : out unsigned(7 downto 0);
    dbg_spi_data6_o     : out unsigned(7 downto 0);
    dbg_spi_data7_o     : out unsigned(7 downto 0);
    dbg_spi_data8_o     : out unsigned(7 downto 0);
    dbg_spi_data9_o     : out unsigned(7 downto 0);
    dbg_spi_dataA_o     : out unsigned(7 downto 0);
    dbg_spi_dataB_o     : out unsigned(7 downto 0);
    dbg_spi_dataC_o     : out unsigned(7 downto 0);
    dbg_spi_dataD_o     : out unsigned(7 downto 0);
    dbg_spi_bytes_io    : inout unsigned(3 downto 0); --bytes to send
    dbg_spi_start_o     : out std_logic;
    dbg_spi_device_o    : out unsigned(2 downto 0); --1=VGA, 2=SYN, 3=DDS, 4=ZMON
    dbg_spi_busy_i      : in  std_logic;
    dbg_enables_o       : out unsigned(15 downto 0);  --toggle various enables/wires
 
    ------ Connect MMC fifos to opcode processor ----------
    -- Read from MMC fifo connections
    opc_fif_dat_o       : out unsigned( 7 downto 0);    -- MMC opcode fifo
    opc_fif_ren_i       : in  std_logic;                -- mmc fifo read enable
    opc_fif_mt_o        : out std_logic;                -- mmc opcode fifo empty
    opc_rd_cnt_o        : out unsigned(MMC_FILL_LEVEL_BITS-1 downto 0); -- mmc opcode fifo fill level 
    opc_rd_reset_i      : in  std_logic;                -- Synchronous mmc opcode fifo reset
    -- Write to MMC fifo connections
    opc_rspf_dat_i      : in  unsigned( 7 downto 0);    -- MMC response fifo
    opc_rspf_we_i       : in  std_logic;                -- response fifo write line             
    opc_rspf_mt_o       : out std_logic;                -- response fifo empty
    opc_rspf_fl_o       : out std_logic;                -- response fifo full
    opc_rspf_reset_i    : in std_logic;                 -- Synchronous mmc response fifo reset
    opc_rspf_cnt_o      : out unsigned(MMC_FILL_LEVEL_BITS-1 downto 0); -- mmc response fifo fill level 
 
    -- UART debugger can show these values
    opc_oc_cnt_i        : in  unsigned(31 downto 0);    -- count of opcodes processed
    opc_status1_i       : in  unsigned(31 downto 0);    -- LS 16 bits=opc status, MS 16-bits=opc_state
    opc_status2_i       : in  unsigned(31 downto 0);    -- rsp_fifo_count__opc_fifo_count    
    opc_status3_i       : in  unsigned(31 downto 0);    -- LS 16 bits=MS 8 bits=RSP fifo level, LS 8 bits=OPC fifo level
    sys_status4_i       : in  unsigned(31 downto 0);    -- system frequency setting in Hertz
    sys_status5_i       : in  unsigned(31 downto 0);    -- MS 16 bits=SYN_STAT pin,1=PLL_LOCK, 0=not, LS 12 bits=system power, dBm x 10
    sys_status6_i       : in  unsigned(31 downto 0)     -- LS 16 bits: PTN_Status__PTN_Busy(running) 
  );
  end component;
 
end mmc_test_pack;
 
package body mmc_test_pack is
end mmc_test_pack;
 
-------------------------------------------------------------------------------
-- SD/MMC Testing Command Receiver
-------------------------------------------------------------------------------
--
-- Author: John Clayton
-- Update: July 29, 2016 Copied code from sd_card_cmd_rx, and modified
--                       the description and interface to better suit
--                       test needs, e.g. capturing commands and replies
--                       on an SD/MMC bus.
--
-- Description
-------------------------------------------------------------------------------
-- This module is meant to be part of a system that tests, or snoops on
-- an SD/MMC card.
--
-- This module clocks incoming serial bits from the cmd signal into a 48 bit
-- shift register.  It starts when a '0' (start) bit is found, and then shifts
-- in 47 additional bits.  The expected format of the command is:
--
-- 0 x [index] [arg] [crc] 1
--
-- Where:
--   x     = direction bit. '1'=host to card, '0'=reply from card.
--   index = 6 bits
--   arg   = 32 bits
--   crc   = 7  bits
--
-- The test command receiver checks that the last bit is a '1' (stop) bit,
-- in the expected position (bit 47; start bit is bit 0).
-- The seven bits immediately prior to the stop bit are
-- checked using a CRC-7 code.
--
-- If any of the checks does not pass, the associated error bits are set.
-- Regardless of errors, however, the received data bits are presented
-- at the cmd_raw_o output.  The cmd_rx_done_o output is pulsed high for
-- one clock cycle to notify the downstream entities that newly received
-- data is available.
--
-- In the interest of simplicity and in an effort to remain practical,
-- only 48 bit responses are captured correctly by this unit.  For R2
-- responses, which are 136 bits long, only the first 48 bits are presented.
-- Because the R2 type responses are 136 bits long, specific logic is
-- included to try and detect them, and prevent errors from being flagged
-- by their occurrence.  The first eight bits of an R2 response are
-- "00111111".  Unfortunately, the first eight bits of a 48 bit R3
-- response are also "00111111".  Fortunately, the CRC field of an R3
-- response is always set to "1111111".  So, the logic checks for these
-- conditions and behaves accordingly.  In the case of an R2 response, that
-- includes ignoring further activity on the command line for another 88
-- clocks after the initial 48 bits are received...
--
-- Note that this receiver runs entirely within the sd_clk_i clock domain.
-- Therefore, care must be taken when using the outputs.  A FIFO can form
-- a natural "clock domain boundary crossing" or the user may need to
-- implement other special handshaking to safely transfer signals into a
-- different clock domain.
--
 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
library work;
use work.ucrc_pack.all;
 
entity mmc_test_cmd_rx is
  port (
    -- Asynchronous reset
    sys_rst_n   : in  std_logic;
    -- SD/MMC card command signals
    sd_clk_i    : in  std_logic;
    sd_cmd_i    : in  std_logic;
    -- Command outputs
    cmd_raw_o   : out unsigned(47 downto 0);
    -- Status and done indicator
    cmd_done_o  : out std_logic;
    crc_err_o   : out std_logic;
    stop_err_o  : out std_logic
  );
end mmc_test_cmd_rx;
 
architecture beh of mmc_test_cmd_rx is
 
  -- CRC related
signal crc_clk        : std_logic;
signal crc_clr        : std_logic;
signal crc_match      : std_logic;
signal crc_val        : unsigned(6 downto 0);
  -- Related to the incoming command
signal sd_cmd_r1      : std_logic;
signal counter        : unsigned(5 downto 0);
signal rx_sr          : unsigned(47 downto 0);
signal cmd_raw_l      : unsigned(47 downto 0);
signal ignore_counter : unsigned(6 downto 0);
 
begin
 
--------------------------------------------
-- CRC generator
 
  crc0 : ucrc_ser
  generic map (
    POLYNOMIAL => "0001001",
    INIT_VALUE => "0000000"
  )
  port map (
    -- System clock and asynchronous reset
    sys_clk    => crc_clk,
    sys_rst_n  => sys_rst_n,
    sys_clk_en => '1',
 
    -- Input and Control
    clear_i    => crc_clr,
    data_i     => rx_sr(0),
    flush_i    => '0',
 
    -- Output
    match_o    => crc_match,
    crc_o      => crc_val
  );
  -- Falling edge was used for a while...
  -- Rising edge is now being used, per the specification.
  --crc_clk <= not sd_clk_i;
  crc_clk <= sd_clk_i;
  crc_clr <= '1' when counter=0 else '0';
 
 
--------------------------------------------
-- Command receiver
 
command_rx_proc : process(sys_rst_n, sd_clk_i)
begin
  if (sys_rst_n='0') then
    ignore_counter <= (others=>'0');
    counter <= (others=>'0');
    rx_sr <= (others=>'0');
    sd_cmd_r1 <= '1';
    cmd_raw_l <= (others=>'1');
    cmd_done_o  <= '0';
    crc_err_o   <= '0';
    stop_err_o  <= '0';
--  elsif (sd_clk_i'event and sd_clk_i='0') then -- falling edge is used, when data is stable.
  elsif (sd_clk_i'event and sd_clk_i='1') then -- rising edge is used, per the specification.
    -- Default values
    cmd_done_o  <= '0';
    crc_err_o   <= '0';
    stop_err_o  <= '0';
 
    -- Metastability mitigation (synchronization) flip flops
    sd_cmd_r1 <= sd_cmd_i;
    -- The shift register is the second synchronization flip flop
    rx_sr(0)  <= sd_cmd_r1;
    rx_sr(47 downto 1) <= rx_sr(46 downto 0);
    -- Decrement the counter when it is non-zero
    if (counter>0) then
      counter <= counter-1;
    end if;
    -- Decrement the ignore counter when it is non-zero
    if (ignore_counter>0) then
      ignore_counter <= ignore_counter-1;
    end if;
    -- Load the counter when a start bit is seen
    if (ignore_counter=0 and counter=0 and sd_cmd_r1='0') then
      counter <= to_unsigned(48,counter'length);
    end if;
    -- Store the output when the counter is expiring
    if (counter=1) then
      cmd_raw_l <= rx_sr;
      cmd_done_o <= '1';
      -- Determine if this is a long R2 type response
      if (rx_sr(47 downto 40)="00111111" and rx_sr(7 downto 1)/="1111111") then
        ignore_counter <= to_unsigned(88,ignore_counter'length);
        -- No errors are generated for long R2 responses
      else
        -- Perform error checks
        if (rx_sr(0)='0') then
          stop_err_o <= '1';
        end if;
        if (crc_match='0') then
          crc_err_o <= '1';
        end if;
      end if;
    end if;
  end if;
end process;
 
-- Split out fields of the command
cmd_raw_o   <= cmd_raw_l;
 
end beh;
 
 
 
---------------------------------------------------------------------------------------
--
-- Author: John Clayton
-- Date  : May 16, 2016
-- Update: 05/16/16 Wrote the description, began writing code
--
-- Description
---------------------------------------------------------------------------------------
-- This is a collection of modules put together which allow testing of an MMC system.
-- In particular, this module contains an MMC host, plus an "MMC data pipe" which
-- impersonates an MMC.  
--
-- In order to interact with this collection of MMC modules in hardware, an 
-- "async_syscon" serial terminal command interpreter is provided, having a 32-bit
-- address and a 32-bit data bus.  There is an automatic baud rate synchronization
-- unit, which synchronizes by looking for the 0x0D character, so that simply
-- pressing "Enter" in a serial terminal program should bring up the link at the
-- correct speed, anything in the range 19200 to 921600 Baud should work.
-- The parity setting is "None" and hardware handshaking is not supported.
--
-- Because of the different modules present in this MMC tester, it is helpful to
-- summarize the memory map here:
--
-- Address          Length     Function
-- --------------   --------   --------------------------------------------
-- 0x0300_0000      0x10       MMC host registers
-- 0x0300_0010      0x10       MMC slave registers
-- 0x0300_0020      0x10       MMC tester registers
-- 0x0400_0000      0x4000     MMC host RAM
-- 0x0500_0000      0x10000    MMC slave RAM
--
-- Note that the size of the MMC slave RAM can be modified by setting the
-- constant MMC_RAM_ADR_BITS within this module.  Similarly, the size of the
-- MMC host RAM can be modified by setting the constant HOST_RAM_ADR_BITS.
--
-- For a description of the MMC host registers, please refer to the
-- description given in the sd_controller_8bit_bram entity.
-- The code is contained in the "sd_host_pack.vhd" file.
--
-- For a description of the MMC slave registers, please refer to the
-- description given in the sd_card_emulator, which is an entity instantiated
-- inside the mmc_data_pipe unit.
-- The code is contained in the "sd_card_pack.vhd" file.
--
-- A detailed description of the local registers is given here, below.
--
-- Wouldn't it be nice to have a block diagram showing all of the modules
-- or cores instantiated within this one?  Yes, I believe it would be nice.
-- However, in lieu of a nice ASCII-art pictorial drawing, a few lines of
-- descriptive text will be better than nothing.  Here goes!
------------------------------------------------------------------------------
-- Brief Description of local test functions:
--
--   Within this unit, there is steering logic that selects how the SD/MMC bus
--   is driven and used, with regard to the tri-state output enables.  Actual
--   tri-state buffers are to be implemented at the top level of the FPGA
--   by means of the output enable signals.
--
--   The steering logic allows the SD/MMC host to communicate directly with
--   the sd_card_emulator and RAM/FIFOs contained in the mmc_data_pipe, or it
--   can also be set up to route the signals from the MMC controller host to
--   an external SD/MMC card.
--
--   In like manner, it can be set up so that an external SD/MMC host can talk
--   to the local mmc_data_pipe unit.
--
--   A third option is to disable both the local sd_controller_8bit_bram
--   and the local mmc_data_pipe unit from the bus.  In this configuration,
--   the user of this MMC tester is enabled to "snoop" on the activity and
--   traffic occurring between an external SD/MMC host and its attached card.
--   This requires, of course, some appropriate "interposer" cabling to give
--   the FPGA access to monitor the signals passing along the external SD/MMC
--   bus being monitored.
--
--   In order to keep track of commands on the SD/MMC bus for test and debug,
--   there is a dedicated, stand alone command receiver separate from the MMC
--   host and slave units.  This receiver looks for start bits on the SD/MMC
--   cmd line, and then captures the contents of the transfer, whether it be
--   from the host to the card, or a cmd response from the card to the host.
--   Some responses from an SD/MMC card are 136 bits long, but most responses
--   are 48 bits long.  In the interest of expediency, this special receiver
--   only captures the first 48 bits of a command transfer.  It does, however,
--   refrain from generating error flags for 136 bit long responses, by
--   checking the command index field, which is "111111b" for 136 bit long
--   responses.
--
--   For test and debug purposes, there are some counters, and data capture
--   mechanisms:
--
--     1. A counter that counts command transfer events, filtered based on
--        register settings.
--     2. A data transfer counter, which simply increments each time a data
--        transfer is started.  It is reset whenever a new host to card
--        command transfer of the selected command index type is detected.
--        In reality there are two such counters, a 32 bit one that is
--        accessible via registers, and an 8-bit one ("tlm_d_count") that is
--        used in the telemetry output.  The telemetry one is a relative
--        count; it gets cleared at every command transfer event.
--     3. An SD/MMC traffic reporting "telemetry sender" that emits a stream
--        of information meant to be used as a timestamped archive record
--        of SD/MMC activity.  A new record is emitted each time the command
--        transfer counter increments.  The telemetry records are 12 byte
--        bursts meant to be captured in a FIFO external to this module, or
--        sent out via a UART.
--
--   The format of the telemetry record burst is:
--      Byte Number     Contents       Purpose
--      -----------     --------       -----------------------------------------
--           0          0xEB           Synchronization character
--           1          frame ID       A modulo-256 incrementing value
--           2          tlm_d_count    Data transfers completed, modulo 256
--          3-5         time           time, in microseconds
--          6-11        cmd            48 bits of command or reply
--
------------------------------------------------------------------------------
-- Local Registers
--
-- 0x0300_0020  R0   LED outputs register (READ/WRITE)
--                   This register contains a number of bits meant for
--                   controlling LEDs on the test board, just for fun.  The
--                   number of bits implemented in this register is set by
--                   the SYS_LEDS generic, which should be set in the range
--                   [1..32].  For SYS_LEDS settings less than 32, the unused
--                   bits are the most significant bits, which read as '0'.
--
-- 0x0300_0021  R1   Switch inputs register (READ ONLY)
--                   This register allows reading the status of the switch_i
--                   inputs on the test board.  The number of bits implemented
--                   in this register is set by the SYS_SWITCHES generic,
--                   which should be set in the range [1..32].  For
--                   SYS_SWITCHES settings less than 32, the unused bits are
--                   the most significant bits, which read as '0'.
--
-- 0x0300_0022  R2   MMC Tester Mode (READ/WRITE)
--                   Bit [0] = Slave Enable Reg.  Setting this bit causes the
--                             internal MMC_data_pipe slave to be active
--                             on the SD/MMC bus.
--                   Bit [1] = Host Enable Reg.  Setting this bit causes the
--                             internal sd_controller_8bit_bram unit to
--                             be active on the SD/MMC bus.
--                   Bits [3..2] = "00" (Reserved)
--                   Bit [4] = Slave Enabled (READ ONLY).  This bit is the
--                             logical OR of bit[0] and the slave_en_i input.
--                             Thus we see that the MMC_data_pipe slave can
--                             be made active by the signal input, or the
--                             register bit.
--                   Bit [5] = Host Enabled (READ ONLY).  This bit is the
--                             logical OR of bit[1] and the host_en_i input.
--                             Thus we see that the sd_controller_8bit_bram
--                             host unit can be made active by the signal
--                             input, or the register bit.
--                   Bits [7..6] = "00" (Reserved)
--                   Bit [8] = Telemetry log register read access enable.
--                             When this bit is set, then telemetry log
--                             FIFO contents can be read out via register
--                             R10, and the asynchronous serial transmitter
--                             is disabled.  When clear, the asynchronous
--                             serial transmitter has access to the telemetry
--                             log FIFO instead of register R10.
--
-- 0x0300_0023  R3   Test Command Receiver Filter (READ/WRITE)
--                   Bits [7:0] determine what type of command creates a
--                   "command event."
--                   Except for the setting of 0x80, setting bit [7] means
--                   "capture and count everything," including all command
--                   indices, in both directions.
--                   Example settings:
--                     0x81..0xFF => Capture and count everything.
--                     0x80 => Capture and count nothing. Nada. Zilch.
--                     0x7F => Capture and count all host-to-card commands
--                     0x3F => Capture and count all card-to-host responses
--                     0x59 => Capture and count CMD25 from host-to-card only
--                     0x28 => Capture and count CMD40 R5 responses only
--                     0x27 => Capture and count CMD39 R4 responses only
--                     0x19 => Capture and count CMD25 R1 responses only
--                     0x00 => Capture and count CMD0 R1 responses only
--
--   To explain more clearly how these filter settings work, it is helpful to
--   recall that the first eight bits of the command or response are:
--
--     [0][d][cccccc]
--
--     Where: 0 = start bit (always low)
--            d = direction bit (1 for host to card, 0 for card response)
--            cccccc = command index, ranging from 0 to 56, (or 63 for
--                     long responses and/or 48-bit R3 OCR responses.)
--
--     Therefore, it becomes clear that the operation of the filter is
--     not perfect.  For example, there is no way to act on only R3
--     responses.  However, there is really no need for a perfect
--     filter.  This one is, well, you know, good enough!
--
-- 0x0300_0024  R4   Error-free Command Events (READ/WRITE)
--                   Writing to this register resets it back to zero.
--
-- 0x0300_0025  R5   Command Events with CRC error (READ/WRITE)
--                   Writing to this register resets it back to zero.
--
-- 0x0300_0026  R6   Command Events with stop bit error (READ/WRITE)
--                   Writing to this register resets it back to zero.
--
-- 0x0300_0027  R7   Number of data transfers completed(READ/WRITE)
--                   No means are provided for the tester to determine
--                   what direction the data is flowing over the SD/MMC
--                   data lines.  Therefore, this register simply contains
--                   the total number of transfers started in both
--                   directions.  Writing to this register clears the count
--                   back to zero.  Note that this 32-bit counter is distinct
--                   from the eight bit "tlm_d_count" data transfer counter
--                   in the telemetry, which is a relative count, cleared at
--                   every command transfer event.
--
-- 0x0300_0028  R8   reg_dbus_size (READ/WRITE)
--                     0 => 1 bit data bus transfers
--                     1 => 4 bit data bus transfers
--                     2 => 8 bit data bus transfers
--                   In order for the tester to determine when a data transfer
--                   is completed, so that it can count valid start bits, it
--                   is required to know the data bus size.  Logic is present
--                   to decode when a host-to-card command of index 6 (CMD6),
--                   the SWITCH command, is seen with an argument 0x03B70s00,
--                   where s contains the new data bus size.  This 2-bit
--                   setting is then stored in the reg_dbus_size register,
--                   and used to set the "dstart_wait" parameter used for
--                   ignoring data bus activity during an active data
--                   transfer.  The reg_dbus_size starts out at "00b", and
--                   is expected to change to "01b" for 4-bit SD activity,
--                   and to "10b" for 8-bit MMC activity.
--                   Writing to this register simply clears it back to zero.
--
-- 0x0300_0029  R9   SD/MMC traffic log FIFO fill level (READ/WRITE)
--                   This register returns the number of bytes stored in the
--                   FIFO, awaiting commission to the log archive or telemetry
--                   link.  Writing to this register clears out the FIFO.
--
-- 0x0300_002A  R10  SD/MMC traffic log FIFO read port (READ ONLY)
--                   Telemetry bytes can be read out of the traffic log FIFO
--                   whenever enabled in R2 bit 8.  For convenience in reading
--                   the data, the bytes are packed into 32-bit words.  If R2
--                   bit 8 is clear, then reading this register returns
--                   0x55555555.
--
-- 0x0300_002C  R12  S4 Enables/lines
--
-- 0x0300_002D  R13  MMC_data_pipe write data FIFO fill level (READ/WRITE)
--                   Reading this register returns the number of bytes in
--                   the MMC slave write data FIFO.  The FIFO holds data
--                   that are meant to flow from the MMC slave to the host.
--                   Writing to this register clears the MMC slave
--                   write data FIFO.
--
-- 0x0300_002E  R14  MMC_data_pipe read data FIFO fill level (READ/WRITE)
--                   Reading this register returns the number of bytes in
--                   the MMC slave read data FIFO.  The FIFO holds data
--                   that have been sent from the host to the MMC slave.
--                   Writing to this register clears the MMC slave
--                   read data FIFO.
--
-- 0x0300_002F  R15  MMC_data_pipe FIFO data (READ/WRITE)
--                   Writing to this address loads another byte into
--                   the MMC slave write data FIFO, thereby enqueueing
--                   it to be read by the host from the MMC slave.
--                   However, if the write data FIFO is full, then nothing
--                   happens, and the byte is thrown into the "bit bucket."
--                   Reading from this address removes another byte
--                   of data from the MMC slave read data FIFO, which
--                   was previously delivered from the host to the
--                   MMC slave.
--                   However, if the read data FIFO is empty, then no valid
--                   data is actually delivered.
--
-- 0x0300_0030  R16  Rd:Opcode processor status, 8 lsbs, Wr:SPI data, device, #bytes, 14 bytes data
--
-- 0x3000_0031  R17  Opcode processor opcode counter, 32 bits
--
-- 0x3000_0032  R18  Opcode processor internal state, 8 bits
--
-- 0x3000_0033  R19  Opcode processor overall system state, 16 bits
--
-- 0x3000_0034  R20  Opcode processor overall system mode, 32 bits
--
-- 0x3000_0035  R21  Frequency processor status, 16 msbs, power processor status, 16 lsbs
--
-- 0x3000_0036  R22  Phase processor status, 16 msbs, pulse processor status, 16 lsbs
--
-- 0x3000_0037  R23  Pattern processor status, 16 msbs, opc_response_ready flag, 16 lsbs 
--
------------------------------------------------------------------------------
-- Further Discussion, for the enquiring minds that want to know...
-- The below explanations might in some way repeat what was stated above,
-- but could still be useful.
--
-- Register 2, bit[0] : "slave enable"
--   When high, this bit causes the MMC slave to receive commands, and respond to
--   them.  When this bit is enabled, the MMC slave will drive signals onto mmc_cmd_o
--   and mmc_dat_o, including driving the mmc_cmd_oe_o and mmc_dat_oe_o lines when
--   appropriate.  When this bit is low, the MMC slave cmd input will be held high,
--   and the MMC slave will not have anything to do.
--
-- Register 2, bit[1] : "host enable"
--   When high, this bit causes the MMC host to send commands, and receive responses
--   to them.  When this bit is enabled, the MMC host can drive signals onto mmc_cmd_o
--   and mmc_dat_o, including driving the mmc_cmd_oe_o and mmc_dat_oe_o lines when
--   appropriate.  When this bit is low, the MMC host cmd output will be cut off
--   from affecting mmc_cmd_o, and the MMC host will not be able to influence the
--   MMC bus signals.
--
-- If both of these bits are low, then the only function active in this core is to
-- monitor the mmc commands which occur on the MMC bus due to the action of any
-- outside MMC hosts, such as card readers, which may send commands to an MMC card
-- on the bus.
-- Register 3 can be used to filter on a certain host command index.
--
-- With "host_enable" set, the tester can be used to communicate with a real
-- external SD/MMC device, perhaps for the purpose of reading or writing some
-- sectors, or reading the device registers including the CID, CSD and the 512
-- byte EXT_CSD.
--
-- With "slave_enable" set, on the other hand, an MMC slave can be used with an
-- external SD/MMC card reader.  The MMC slave in this case uses a small amount
-- of RAM, plus a pair of FIFO buffers.  Writing data to the card at addresses
-- below the upper boundary of the RAM, simply places the data into RAM.  Beyond
-- the RAM upper boundary, the data goes into the write FIFO.  Reading is handled
-- the same way.
--
-- An alternative to using the register bits to enable the slave and host, is to
-- use the input signals "slave_en_i" and "host_en_i".  These signals are simply
-- logically ORed with the register bits.
--
-- There are no "buried tri-states" present within this module.  Therefore, each
-- signal, or related bus of signals, has a drive signal provided to allow the
-- tri-state connections to be made at the top level.  The one for the mmc_clk
-- had to be provided because this module can both give and receive an MMC
-- clock signal.
--
-- An asynchronous system controller (async_syscon) is provided here for ease
-- of debugging by humans.  A person can access the entire memory map of this
-- tester by means of simple command line style commands, using an asynchronous
-- serial terminal.
--
 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
library work;
use work.dds_pack.all;
use work.fifo_pack.all;
use work.convert_pack.all;
use work.sd_card_pack.all;
use work.sd_host_pack.all;
use work.flancter_pack.all;
use work.mmc_test_pack.all;
use work.block_ram_pack.all;
use work.auto_baud_pack.all;
use work.uart_sqclk_pack.all;
use work.async_syscon_pack.all;
 
  entity mmc_tester is
  generic (
    SYS_CLK_RATE        : real    := 50000000.0; -- The clock rate at which the FPGA runs
    SYS_LEDS            : natural := 8; -- Number of LED outputs on the board
    SYS_SWITCHES        : natural := 4; -- Number of Switch inputs on the board
    EXT_CSD_INIT_FILE   : string  := "ext_csd_init.txt"; -- Initial contents of EXT_CSD
    HOST_RAM_ADR_BITS   : natural := 14; -- Determines amount of BRAM in MMC host
    MMC_FIFO_DEPTH      : integer := 2048;
    MMC_FILL_LEVEL_BITS : integer := 14; -- Should be at least int(floor(log2(FIFO_DEPTH))+1.0)
    RSP_FILL_LEVEL_BITS : integer := 10; 
    MMC_RAM_ADR_BITS    : integer := 14  -- 16 Kilobytes
  );
  port (
 
    -- Asynchronous reset
    sys_rst_n      : in  std_logic;
    sys_clk        : in  std_logic;
 
    -- Asynchronous serial interface
    cmd_i          : in  std_logic;
    resp_o         : out std_logic;
 
    -- Board related
    switch_i       : in  unsigned(SYS_SWITCHES-1 downto 0);
    led_o          : out unsigned(SYS_LEDS-1 downto 0);
 
    -- Interface for SD/MMC traffic logging
    -- via asynchronous serial transmission
    tlm_send_i     : in  std_logic;
    tlm_o          : out std_logic;
 
    -- Tester Function Enables
    slave_en_i     : in  std_logic; -- OR with register bit
    host_en_i      : in  std_logic; -- OR with register bit
 
    -- SD/MMC card signals
    mmc_clk_i      : in  std_logic;
    mmc_clk_o      : out std_logic;
    mmc_clk_oe_o   : out std_logic;
    mmc_cmd_i      : in  std_logic;
    mmc_cmd_o      : out std_logic;
    mmc_cmd_oe_o   : out std_logic;
    mmc_dat_i      : in  unsigned( 7 downto 0);
    mmc_dat_o      : out unsigned( 7 downto 0);
    mmc_dat_oe_o   : out std_logic;
    mmc_od_mode_o  : out std_logic; -- Open drain mode
    mmc_dat_siz_o  : out unsigned(1 downto 0);
 
    -- SPI debugging connections
    dbg_spi_data0_o     : out unsigned(7 downto 0);
    dbg_spi_data1_o     : out unsigned(7 downto 0);
    dbg_spi_data2_o     : out unsigned(7 downto 0);
    dbg_spi_data3_o     : out unsigned(7 downto 0);
    dbg_spi_data4_o     : out unsigned(7 downto 0);
    dbg_spi_data5_o     : out unsigned(7 downto 0);
    dbg_spi_data6_o     : out unsigned(7 downto 0);
    dbg_spi_data7_o     : out unsigned(7 downto 0);
    dbg_spi_data8_o     : out unsigned(7 downto 0);
    dbg_spi_data9_o     : out unsigned(7 downto 0);
    dbg_spi_dataA_o     : out unsigned(7 downto 0);
    dbg_spi_dataB_o     : out unsigned(7 downto 0);
    dbg_spi_dataC_o     : out unsigned(7 downto 0);
    dbg_spi_dataD_o     : out unsigned(7 downto 0);
    dbg_spi_bytes_io    : inout unsigned(3 downto 0); --bytes to send
    dbg_spi_start_o     : out std_logic;
    dbg_spi_device_o    : out unsigned(2 downto 0); --1=VGA, 2=SYN, 3=DDS, 4=ZMON
    dbg_spi_busy_i      : in  std_logic;            --top level is writing SPI bytes
    dbg_enables_o       : out unsigned(15 downto 0); --toggle various enables/wires
 
    -- connect opcode processor to mmc fifo's    
    -- MMC read fifo to opcode processor
    opc_fif_dat_o       : out unsigned( 7 downto 0);     -- MMC opcode fifo
    opc_fif_ren_i       : in std_logic;                  -- mmc fifo read enable
    opc_fif_mt_o        : out std_logic;                 -- mmc opcode fifo empty
    opc_rd_cnt_o        : out unsigned(MMC_FILL_LEVEL_BITS-1 downto 0); -- mmc opcode fifo fill level 
    opc_rd_reset_i      : in std_logic;                  -- Synchronous mmc opcode fifo reset
    -- MMC write fifo from opcode processor
    opc_rspf_dat_i      : in  unsigned( 7 downto 0);     -- MMC response fifo
    opc_rspf_we_i       : in std_logic;                  -- response fifo write line             
    opc_rspf_mt_o       : out std_logic;                 -- response fifo empty
    opc_rspf_fl_o       : out std_logic;                 -- response fifo full
    opc_rspf_reset_i    : in std_logic;                  -- Synchronous mmc response fifo reset
    opc_rspf_cnt_o      : out unsigned(MMC_FILL_LEVEL_BITS-1 downto 0); -- mmc response fifo fill level 
 
    -- Debugging
    opc_oc_cnt_i   : in  unsigned(31 downto 0);         -- LS 16 bits=count of opcodes processed, MS 16 bits=opc fifo level
    opc_status1_i  : in  unsigned(31 downto 0);         -- LS 16 bits=opc status, MS 16-bits=opc_state
    opc_status2_i  : in  unsigned(31 downto 0);         -- rsp_fifo_count__opc_fifo_count
    opc_status3_i  : in  unsigned(31 downto 0);         -- MS 16 bits=MS 8 bits=RSP fifo level, LS 8 bits=OPC fifo level
    sys_status4_i  : in  unsigned(31 downto 0);         -- system frequency setting in Hertz
    sys_status5_i  : in  unsigned(31 downto 0);         -- MS 16 bits=SYN_STAT pin,1=PLL_LOCK, 0=not, LS 12 bits=system power, dBm x 10
    sys_status6_i  : in  unsigned(31 downto 0)          -- LS 16 bits: PTN_Status__PTN_Busy(running) 
  );
  end mmc_tester;
 
architecture beh of mmc_tester is
 
  -- Constants
 
    -- async_syscon related
  constant FPGA_PARITY     : integer :=         0; -- 0=none, 1=even, 2=odd
  constant CMD_LINE_SIZE   : natural :=       128; -- Number of bytes in CMD buffer
  constant ADR_DIGITS      : natural :=         8;
  constant DAT_DIGITS      : natural :=         8;
  constant QTY_DIGITS      : natural :=         4;
  constant WDOG_VALUE      : natural :=      2000;
  constant DAT_SIZE        : natural := 4*DAT_DIGITS;
  constant ADR_SIZE        : natural := 4*ADR_DIGITS;
 
    -- Telemetry related
  constant TLM_FIFO_DEPTH  : natural := 16384;
 
  -- Signals
 
    -- autobaud related
  signal baud_clk         : std_logic;
  signal baud_lock        : std_logic;
  signal parity           : unsigned(1 downto 0);
 
    -- async_syscon related
  signal syscon_rst       : std_logic;
  signal fpga_rst_n       : std_logic;
  signal fpga_rst         : std_logic;
  signal syscon_dat_rd    : unsigned(DAT_SIZE-1 downto 0);
  signal syscon_dat_wr    : unsigned(DAT_SIZE-1 downto 0);
  signal syscon_cyc       : std_logic;
  signal syscon_err       : std_logic;
  signal syscon_ack       : std_logic;
  signal syscon_adr       : unsigned(ADR_SIZE-1 downto 0);
  signal syscon_we        : std_logic;
 
  signal master_bg        : std_logic;
  signal master_adr       : unsigned(ADR_SIZE-1 downto 0);
  signal master_cyc       : std_logic;
  signal master_we        : std_logic;
  signal master_dat_wr    : unsigned(DAT_SIZE-1 downto 0);
 
    -- related to decoding the address bus
  signal h_reg_sel        : std_logic;
  signal h_reg_ack        : std_logic;
  signal h_reg_dat_rd     : unsigned(31 downto 0);
  signal s_reg_sel        : std_logic;
  signal s_reg_ack        : std_logic;
  signal s_reg_dat_rd     : unsigned(31 downto 0);
  signal h_ram_sel        : std_logic;
  signal h_ram_ack        : std_logic;
  signal h_ram_dat_rd     : unsigned(7 downto 0);
  signal s_ram_sel        : std_logic;
  signal s_ram_ack        : std_logic;
  signal s_ram_dat_rd     : unsigned(7 downto 0);
  signal s_ram_we         : std_logic;
  signal s_fif_sel        : std_logic;
 
    -------------------------------------------------------
    -- mmc data pipe to opcode processor interface fifo's
  --signal s_fif_dat_rd     : unsigned(7 downto 0);       -- opcode fifo data from mmc
  --signal s_fif_rd         : std_logic;                  -- opcode fifo read enable
  --signal s_fif_rd_empty   : std_logic;
  --signal s_fif_rd_full    : std_logic;
  --signal s_fif_dat_wr     : unsigned(7 downto 0);       -- response fifo to mmc
  signal s_fif_wr         : std_logic;                  -- response fifo write enable
  --signal s_fif_wr_empty   : std_logic;
  --signal s_fif_wr_full    : std_logic;
    ------------------------------------------------------
 
  signal t_reg_sel        : std_logic; -- Test registers
  signal o_reg_sel        : std_logic; -- Opcode processor registers
  signal o_reg_ack        : std_logic; -- Opcode processor register ack
  signal o_reg_dat_rd     : unsigned(31 downto 0); -- Opcode processor register read data
  signal r_reg_sel        : std_logic; -- SPI debug registers
  signal r_reg_ack        : std_logic; -- SPI debug register ack
  signal r_reg_dat_rd     : unsigned(31 downto 0); -- SPI debug register read data
  signal t_reg_sel_r1     : std_logic;
  signal t_reg_ack        : std_logic; -- Test register ack
  signal t_reg_dat_rd     : unsigned(31 downto 0); -- Test register read data
 
    -- relating to system side BRAM and FIFO access
  signal h_ram_we           : std_logic;
  --signal s_fif_dat_wr_clear : std_logic;
  --signal s_fif_dat_rd_clear : std_logic;
 
    -- MMC host BRAM interface related
  signal host_bram_clk    : std_logic;
  signal host_bram_dat_wr : unsigned(7 downto 0);
  signal host_bram_dat_rd : unsigned(7 downto 0);
  signal host_bram_adr    : unsigned(31 downto 0);
  signal host_bram_we     : std_logic;
  signal host_bram_cyc    : std_logic;
 
    -- MMC related
  signal host_cmd_i       : std_logic;
  signal host_cmd_o       : std_logic;
  signal host_cmd_oe_o    : std_logic;
  signal host_dat_i       : unsigned(7 downto 0);
  signal host_dat_o       : unsigned(7 downto 0);
  signal host_dat_oe_o    : std_logic;
  signal host_dat_siz_o   : unsigned(1 downto 0);
  signal host_clk_o_pad   : std_logic;
  signal slave_clk_i      : std_logic;
  signal slave_cmd_i      : std_logic;
  signal slave_cmd_o      : std_logic;
  signal slave_cmd_oe_o   : std_logic;
  signal slave_od_mode_o  : std_logic;
  signal slave_dat_i      : unsigned(7 downto 0);
  signal slave_dat_o      : unsigned(7 downto 0);
  signal slave_dat_oe_o   : std_logic;
  signal slave_dat_siz_o  : unsigned(1 downto 0);
  signal test_cmd_i       : std_logic;
 
    -- local registers
  signal led_reg          : unsigned(SYS_LEDS-1 downto 0);
  signal slave_en_reg     : std_logic;
  signal host_en_reg      : std_logic;
  signal slave_enable     : std_logic;
  signal host_enable      : std_logic;
 
    -- local signals for the RX command counter
  signal t_rx_cmd_filter       : unsigned(7 downto 0);
  signal t_rx_cmd_done         : std_logic;
  signal t_rx_cmd_crc_err      : std_logic;
  signal t_rx_cmd_stop_err     : std_logic;
  signal reg_gdcount_clear     : std_logic;
  signal gdcount_clear         : std_logic;
  signal reg_crc_bdcount_clear : std_logic;
  signal crc_bdcount_clear     : std_logic;
  signal reg_stp_bdcount_clear : std_logic;
  signal stp_bdcount_clear     : std_logic;
  signal reg_dat_count_clear   : std_logic;
  signal dat_count_clear       : std_logic;
  signal t_rx_cmd_raw          : unsigned(47 downto 0);
  signal t_rx_cmd_gdcount      : unsigned(31 downto 0);
  signal t_rx_cmd_crc_bdcount  : unsigned(31 downto 0);
  signal t_rx_cmd_stp_bdcount  : unsigned(31 downto 0);
  signal t_rx_dat_count        : unsigned(31 downto 0);
  signal t_rx_capture          : std_logic;
 
    -- local signals for the data transfer start detector
  signal reg_dbus_size_clear   : std_logic;
  signal dbus_size_clear       : std_logic;
  signal reg_dbus_size         : unsigned(1 downto 0);
  signal dstart_wait           : unsigned(12 downto 0);
  signal dstart_wait_reading   : unsigned(12 downto 0);
  signal dstart_wait_writing   : unsigned(12 downto 0);
  signal write_active          : std_logic;
  signal dbus_active_count     : unsigned(12 downto 0);
  signal mmc_dat_r1            : unsigned(7 downto 0);
  signal mmc_dat_r2            : unsigned(7 downto 0);
 
    -- local signals for SD/MMC logging telemetry sender
  signal tlm_d_count           : unsigned(7 downto 0);
  signal tlm_fid               : unsigned(7 downto 0); -- Telemetry "Frame ID"
  signal tlm_1us_pulse         : std_logic;
  signal tlm_time              : unsigned(23 downto 0);
  signal tlm_tstamp            : unsigned(23 downto 0);
  signal tlm_fifo_fill_level   : unsigned(15 downto 0);
  signal tlm_fifo_clear        : std_logic;
  signal mmc_tlm_start         : std_logic; -- mmc_clk_i domain
  signal tlm_start             : std_logic; -- sys_clk domain
  signal tlm_fifo_reg_access   : std_logic;
  signal tlm_fifo_dat_rd       : std_logic;
  signal tlm_fifo_dat          : unsigned(7 downto 0);
  signal tlm_r10_dat           : unsigned(31 downto 0);
  signal tlm_code_byte         : unsigned(7 downto 0);
  signal tlm_r10_count         : unsigned(2 downto 0);
  signal tlm_tx_we             : std_logic;
  signal tlm_tx_done           : std_logic;
  signal tlm_stage             : unsigned(4 downto 0);
  signal tlm_keinplatz         : std_logic;
  signal tlm_fifo_leer         : std_logic;
  signal tlm_log_dat           : unsigned(7 downto 0);
  signal tlm_log_dat_we        : std_logic;
 
    -- local signals for the MMC data pipe
  --signal s_fif_dat_rd_level    : unsigned(MMC_FILL_LEVEL_BITS-1 downto 0);
  --signal s_fif_dat_wr_level    : unsigned(MMC_FILL_LEVEL_BITS-1 downto 0);  -- for debugging?
 
  -- SPI debugging vars
  signal dbg_spi_count         : unsigned(3 downto 0); --down counter
  signal dbg_spi_state         : integer;
  signal dbg_spi_start_l       : std_logic; -- local copy of dbg_spi_start_o
 
begin
 
  ------------------------------
  -- This module generates a serial BAUD clock automatically.
  -- The unit synchronizes on the carriage return character, so the user
  -- only needs to press the "enter" key for serial communications to start
  -- working, no matter what BAUD rate and clk_i frequency are used!
  auto_baud1 : auto_baud_with_tracking
    generic map(
      CLOCK_FACTOR    =>            1,  -- Output is this factor times the baud rate
      FPGA_CLKRATE    => SYS_CLK_RATE,  -- FPGA system clock rate
      MIN_BAUDRATE    =>       9600.0,  -- Minimum expected incoming Baud rate
      DELTA_THRESHOLD =>          200   -- Measurement filter constraint.  Smaller = tougher.
    )
    port map( 
 
      sys_rst_n    => sys_rst_n,
      sys_clk      => sys_clk,
      sys_clk_en   => '1',
 
      -- rate and parity
      rx_parity_i  => parity, -- 0=none, 1=even, 2=odd
 
      -- serial input
      rx_stream_i  => cmd_i,
 
      -- Output
      baud_lock_o  => baud_lock,
      baud_clk_o   => baud_clk
    );
 
  parity <= to_unsigned(FPGA_PARITY,parity'length);
 
  syscon1 : async_syscon
    generic map (
      ECHO_COMMANDS   =>               1, -- set nonzero to echo back command characters
      ADR_DIGITS      =>      ADR_DIGITS, -- # of hex digits for address
      DAT_DIGITS      =>      DAT_DIGITS, -- # of hex digits for data
      QTY_DIGITS      =>      QTY_DIGITS, -- # of hex digits for quantity
      CMD_BUFFER_SIZE =>   CMD_LINE_SIZE, -- # of chars in the command buffer
      WATCHDOG_VALUE  =>      WDOG_VALUE, -- # of sys_clks before ack is expected
      DISPLAY_FIELDS  =>               4  -- # of fields/line
    )
    port map ( 
 
      sys_rst_n    => sys_rst_n,
      sys_clk      => sys_clk,
      sys_clk_en   => '1',
 
      -- rate and parity
      parity_i     => parity,
      baud_clk_i   => baud_clk,
      baud_lock_i  => baud_lock,
 
      -- Serial IO
      cmd_i        => cmd_i,
      resp_o       => resp_o,
      cmd_done_o   => open,
 
      -- Master Bus IO
      master_bg_i  => master_bg,
      master_adr_i => master_adr,
      master_dat_i => master_dat_wr,
      master_dat_o => open, -- There is no other master to read data...
      master_stb_i => master_cyc,
      master_we_i  => master_we,
      master_br_o  => open, -- async_syscon is the only master in this design.
 
      -- System Bus IO
      ack_i        => syscon_ack,
      err_i        => syscon_err,
      dat_i        => syscon_dat_rd,
      dat_o        => syscon_dat_wr,
      rst_o        => syscon_rst,
      stb_o        => open,
      cyc_o        => syscon_cyc,
      adr_o        => syscon_adr,
      we_o         => syscon_we
    );
 
  -- Combine the input reset with the async_syscon bus reset
  fpga_rst_n <= '0' when (sys_rst_n='0' or syscon_rst='1') else '1';
  fpga_rst   <= '1' when (sys_rst_n='0' or syscon_rst='1') else '0';
 
  -- Since there is no bus master besides the async_syscon, take care of those signals
  master_bg     <= '1';
  master_cyc    <= '0';
  master_dat_wr <= (others=>'0');
  master_we     <= '0';
  master_adr    <= (others=>'0');
 
  h_reg_sel <= '1' when syscon_cyc='1' and syscon_adr(31 downto 4)=16#0300000# else '0';
  s_reg_sel <= '1' when syscon_cyc='1' and syscon_adr(31 downto 4)=16#0300001# else '0';
  t_reg_sel <= '1' when syscon_cyc='1' and syscon_adr(31 downto 4)=16#0300002# else '0';
  o_reg_sel <= '1' when syscon_cyc='1' and syscon_adr(31 downto 4)=16#0300003# else '0';
  r_reg_sel <= '1' when syscon_cyc='1' and syscon_adr(31 downto 4)=16#0300004# else '0';
  h_ram_sel <= '1' when syscon_cyc='1' and syscon_adr(31 downto 24)=16#04# and syscon_adr(23 downto HOST_RAM_ADR_BITS)=0 else '0';
  s_ram_sel <= '1' when syscon_cyc='1' and syscon_adr(31 downto 24)=16#05# and syscon_adr(23 downto MMC_RAM_ADR_BITS)=0 else '0';
 
  syscon_dat_rd <= h_reg_dat_rd              when h_reg_sel='1' else
                   s_reg_dat_rd              when s_reg_sel='1' else
                   t_reg_dat_rd              when t_reg_sel='1' else
                   o_reg_dat_rd              when o_reg_sel='1' else
                   r_reg_dat_rd              when r_reg_sel='1' else
                   u_resize(h_ram_dat_rd,32) when h_ram_sel='1' else
                   u_resize(s_ram_dat_rd,32) when s_ram_sel='1' else
                   str2u("12340000",32);
 
  syscon_ack <= h_reg_ack when h_reg_sel='1' else
                s_reg_ack when s_reg_sel='1' else
                t_reg_ack when t_reg_sel='1' else
                o_reg_ack when o_reg_sel='1' else
                r_reg_ack when r_reg_sel='1' else
                h_ram_ack when h_ram_sel='1' else
                s_ram_ack when s_ram_sel='1' else
                '0';
 
  syscon_err <= '0' when h_reg_sel='1' or s_reg_sel='1' or t_reg_sel='1' or 
                 o_reg_sel='1' or r_reg_sel='1' or h_ram_sel='1' or s_ram_sel='1' else '1';
 
  -- Select data for Local Register Reads
  with to_integer(syscon_adr(3 downto 0)) select
  t_reg_dat_rd <=
    u_resize(led_reg,32)                           when 16#0#,
    u_resize(switch_i,32)                          when 16#1#,
    to_unsigned(0,23) & tlm_fifo_reg_access &
      "00" & host_enable & slave_enable &
      "00" & host_en_reg & slave_en_reg            when 16#2#,
    u_resize(t_rx_cmd_filter,32)                   when 16#3#,
    u_resize(t_rx_cmd_gdcount,32)                  when 16#4#,
    u_resize(t_rx_cmd_crc_bdcount,32)              when 16#5#,
    u_resize(t_rx_cmd_stp_bdcount,32)              when 16#6#,
    u_resize(t_rx_dat_count,32)                    when 16#7#,
    u_resize(reg_dbus_size,32)                     when 16#8#,
    u_resize(tlm_fifo_fill_level,32)               when 16#9#,
    u_resize(tlm_r10_dat,32)                       when 16#A#,
    --u_resize(s_fif_dat_rd,32)                      when 16#F#,
    str2u("51514343",32)                           when others;
 
  with to_integer(syscon_adr(3 downto 0)) select
  o_reg_dat_rd <=
    sys_status6_i                                  when 16#9#,      -- LS 16 bits=
    sys_status5_i                                  when 16#A#,      -- LS 12 bits=system power, dBm x 10
    sys_status4_i                                  when 16#B#,      -- system frequency setting in Hertz
    opc_status3_i                                  when 16#C#,      -- 1st_opcode__last_opcode in lower 16 bits
    opc_status2_i                                  when 16#D#,      -- rsp_fifo_count__opc_fifo_count
    opc_status1_i                                  when 16#E#,      -- opc_state__opc_status
    u_resize(opc_oc_cnt_i,32)                      when 16#F#,      -- opcodes processed
  str2u("51514343",32)                             when others;
 
 -- Handle Local Register Writes
  process(sys_rst_n,sys_clk)
  begin
    if (sys_rst_n='0') then
      --led_reg <= (others=>'0');
      t_rx_cmd_filter  <= (others=>'1'); -- Default is to count everything
      reg_gdcount_clear <= '0';
      reg_crc_bdcount_clear <= '0';
      reg_stp_bdcount_clear <= '0';
      reg_dat_count_clear <= '0';
      reg_dbus_size_clear <= '0';
      --s_fif_dat_wr_clear <= '0';
      --s_fif_dat_rd_clear <= '0';
      t_reg_sel_r1 <= '0';
      host_en_reg <= '0';
      slave_en_reg <= '0';
      tlm_fifo_reg_access <= '0';
 
      -- SPI debugging
      dbg_spi_bytes_io <= to_unsigned(0, dbg_spi_bytes_io'length);
      dbg_spi_start_l <= '0';
      dbg_spi_device_o <= to_unsigned(0, dbg_spi_device_o'length);
      dbg_enables_o <= to_unsigned(0, dbg_enables_o'length);
      dbg_spi_state <= 0;
 
    elsif (sys_clk'event and sys_clk='1') then
      -- Default values
      reg_gdcount_clear <= '0';
      reg_crc_bdcount_clear <= '0';
      reg_stp_bdcount_clear <= '0';
      reg_dat_count_clear <= '0';
      reg_dbus_size_clear <= '0';
      --s_fif_dat_wr_clear <= '0';
      --s_fif_dat_rd_clear <= '0';
      -- Register writes have the highest priority
      t_reg_sel_r1 <= t_reg_sel;
      if (t_reg_sel='1' and t_reg_sel_r1='0' and syscon_we='1') then
        case to_integer(syscon_adr(3 downto 0)) is
          when 16#0# =>
            --led_reg <= syscon_dat_wr(SYS_LEDS-1 downto 0);
          when 16#2# =>
            slave_en_reg <= syscon_dat_wr(0);
            host_en_reg  <= syscon_dat_wr(1);
            tlm_fifo_reg_access <= syscon_dat_wr(8);
          when 16#3# =>
            t_rx_cmd_filter <= syscon_dat_wr(7 downto 0);
          -- Clearing the counters must be done in the mmc_clk domain...
          -- Flancters are used to pass the signals into the other clock
          -- domain.
          when 16#4# =>
            reg_gdcount_clear <= '1';
          when 16#5# =>
            reg_crc_bdcount_clear <= '1';
          when 16#6# =>
            reg_stp_bdcount_clear <= '1';
          when 16#7# =>
            reg_dat_count_clear <= '1';
          when 16#8# =>
            reg_dbus_size_clear <= '1';
          -- Register 9 writes implemented at the FIFO
          when 16#C# =>
             dbg_enables_o <= syscon_dat_wr(15 downto 0);
          --when 16#E# =>
            --opc_rspf_reset_i <= syscon_dat_wr(0);     --s_fif_dat_wr_clear <= syscon_dat_wr(0);
            --opc_rd_reset_i <= syscon_dat_wr(1);     --s_fif_dat_rd_clear <= syscon_dat_wr(1);
          when others =>
            null;
        end case;
      end if;
 
--      if (o_reg_sel='1' and syscon_we='1') then
--        case to_integer(syscon_adr(3 downto 0)) is
--          when 16#0# =>
--            bkd_opc_load_new <= '0';
--            bkd_opc_dat0_o <= syscon_dat_wr(31 downto 0);
--          when 16#1# =>
--            bkd_opc_dat1_o <= syscon_dat_wr(31 downto 0);
--          when 16#F# =>
--            bkd_opc_datF_o <= syscon_dat_wr(31 downto 0);
--            bkd_opc_load_new <= '1';
--          when others =>
--            null;
--          end case;
--      elsif (bkd_opc_load_ack='1') then
--        bkd_opc_load_new <= '0';
--      end if;            
 
      -- spi debug, SPI debug register writes, 03000040 x y z ...
      if (r_reg_sel='1' and syscon_we='1') then
        case to_integer(syscon_adr(3 downto 0)) is
          when 16#0# =>
            dbg_spi_device_o <= syscon_dat_wr(2 downto 0);
            dbg_spi_start_l <= '0';
          when 16#1# =>
            dbg_spi_bytes_io <= syscon_dat_wr(3 downto 0);
            dbg_spi_count <= to_unsigned(1, dbg_spi_count'length);
          when 16#2# =>
            dbg_spi_data0_o <= syscon_dat_wr(7 downto 0);
            if(dbg_spi_count = dbg_spi_bytes_io) then
              dbg_spi_start_l <= '1';
            else
              dbg_spi_count <= dbg_spi_count + 1;
            end if;
          when 16#3# =>
            dbg_spi_data1_o <= syscon_dat_wr(7 downto 0);
            if(dbg_spi_count = dbg_spi_bytes_io) then
              dbg_spi_start_l <= '1';
            else
              dbg_spi_count <= dbg_spi_count + 1;
            end if;
          when 16#4# =>
            dbg_spi_data2_o <= syscon_dat_wr(7 downto 0);
            if(dbg_spi_count = dbg_spi_bytes_io) then
              dbg_spi_start_l <= '1';
            else
              dbg_spi_count <= dbg_spi_count + 1;
            end if;
          when 16#5# =>
            dbg_spi_data3_o <= syscon_dat_wr(7 downto 0);
            if(dbg_spi_count = dbg_spi_bytes_io) then
              dbg_spi_start_l <= '1';
            else
              dbg_spi_count <= dbg_spi_count + 1;
            end if;
          when 16#6# =>
            dbg_spi_data4_o <= syscon_dat_wr(7 downto 0);
            if(dbg_spi_count = dbg_spi_bytes_io) then
              dbg_spi_start_l <= '1';
            else
              dbg_spi_count <= dbg_spi_count + 1;
            end if;
          when 16#7# =>
            dbg_spi_data5_o <= syscon_dat_wr(7 downto 0);
            if(dbg_spi_count = dbg_spi_bytes_io) then
              dbg_spi_start_l <= '1';
            else
              dbg_spi_count <= dbg_spi_count + 1;
            end if;
          when 16#8# =>
            dbg_spi_data6_o <= syscon_dat_wr(7 downto 0);
            if(dbg_spi_count = dbg_spi_bytes_io) then
              dbg_spi_start_l <= '1';
            else
              dbg_spi_count <= dbg_spi_count + 1;
            end if;
          when 16#9# =>
            dbg_spi_data7_o <= syscon_dat_wr(7 downto 0);
            if(dbg_spi_count = dbg_spi_bytes_io) then
              dbg_spi_start_l <= '1';
            else
              dbg_spi_count <= dbg_spi_count + 1;
            end if;
          when 16#A# =>
            dbg_spi_data8_o <= syscon_dat_wr(7 downto 0);
            if(dbg_spi_count = dbg_spi_bytes_io) then
              dbg_spi_start_l <= '1';
            else
              dbg_spi_count <= dbg_spi_count + 1;
            end if;
          when 16#B# =>
            dbg_spi_data9_o <= syscon_dat_wr(7 downto 0);
            if(dbg_spi_count = dbg_spi_bytes_io) then
              dbg_spi_start_l <= '1';
            else
              dbg_spi_count <= dbg_spi_count + 1;
            end if;
          when 16#C# =>
            dbg_spi_dataA_o <= syscon_dat_wr(7 downto 0);
            if(dbg_spi_count = dbg_spi_bytes_io) then
              dbg_spi_start_l <= '1';
            else
              dbg_spi_count <= dbg_spi_count + 1;
            end if;
          when 16#D# =>
            dbg_spi_dataB_o <= syscon_dat_wr(7 downto 0);
            if(dbg_spi_count = dbg_spi_bytes_io) then
              dbg_spi_start_l <= '1';
            else
              dbg_spi_count <= dbg_spi_count + 1;
            end if;
          when 16#E# =>
            dbg_spi_dataC_o <= syscon_dat_wr(7 downto 0);
            if(dbg_spi_count = dbg_spi_bytes_io) then
              dbg_spi_start_l <= '1';
            else
              dbg_spi_count <= dbg_spi_count + 1;
            end if;
          when 16#F# =>
            dbg_spi_dataD_o <= syscon_dat_wr(7 downto 0);
            dbg_spi_start_l <= '1';
          when others =>
            null;
          end case;
      end if;            
 
      --If Debug SPI just started, clear start pulse, device #
      if(dbg_spi_start_l = '1' and dbg_spi_busy_i = '1') then
        dbg_spi_start_l <= '0';     -- clear start
      end if;
 
    end if;
  end process;
  -- Provide test register acknowledge
  t_reg_ack <= '1' when syscon_adr(3 downto 0)=10 and tlm_r10_count=1 else
               '1' when syscon_adr(3 downto 0)/=10 and t_reg_sel='1' and t_reg_sel_r1='0' else
               '0';
  o_reg_ack <= o_reg_sel;
  r_reg_ack <= r_reg_sel;
 
  -- assign output based on local value
  dbg_spi_start_o <= dbg_spi_start_l;
 
  -- Provide led_reg as output to external LEDs
  led_o <= led_reg;
 
  -- Handle Reads from TLM FIFO
  -- Data is shifted in on counts 5,4,3,2.
  -- The acknowledge pulse is given on count 1.
  -- Count 0 is the quiescent condition.
  process(sys_rst_n,sys_clk)
  begin
    if (sys_rst_n='0') then
      tlm_r10_dat   <= (others=>'0');
      tlm_r10_count <= (others=>'0');
    elsif (sys_clk'event and sys_clk='1') then
      -- Handle the "byte shift" register counter
      if (tlm_r10_count>0) then
        tlm_r10_count <= tlm_r10_count-1;
      end if;
      -- Implement the "byte shift" data register
      if (tlm_r10_count<6 and tlm_r10_count>1) then
        if (tlm_fifo_reg_access='1') then
          tlm_r10_dat <= tlm_r10_dat(23 downto 0) & tlm_fifo_dat;
        else
          tlm_r10_dat <= tlm_r10_dat(23 downto 0) & "01010101";
        end if;
      end if;
      -- Charge the countdown when a read is initiated
      if (t_reg_sel='1' and t_reg_sel_r1='0' and syscon_we='0' and syscon_adr(3 downto 0)=16#A#) then
        tlm_r10_count <= to_unsigned(6,tlm_r10_count'length);
      end if;
    end if;
  end process;
 
 
  t_rx_gdcount_reset : flancter_rising_pulseout
  port map(
    async_rst_n => sys_rst_n,
    set_clk     => sys_clk,
    set         => reg_gdcount_clear,
    reset_clk   => mmc_clk_i,
    reset       => gdcount_clear,
    pulse_s_o   => open,
    pulse_r_o   => gdcount_clear,
    flag_o      => open
  );
 
  t_rx_crc_bdcount_reset : flancter_rising_pulseout
  port map(
    async_rst_n => sys_rst_n,
    set_clk     => sys_clk,
    set         => reg_crc_bdcount_clear,
    reset_clk   => mmc_clk_i,
    reset       => crc_bdcount_clear,
    pulse_s_o   => open,
    pulse_r_o   => crc_bdcount_clear,
    flag_o      => open
  );
 
  t_rx_stp_bdcount_reset : flancter_rising_pulseout
  port map(
    async_rst_n => sys_rst_n,
    set_clk     => sys_clk,
    set         => reg_stp_bdcount_clear,
    reset_clk   => mmc_clk_i,
    reset       => stp_bdcount_clear,
    pulse_s_o   => open,
    pulse_r_o   => stp_bdcount_clear,
    flag_o      => open
  );
 
  t_rx_dat_count_reset : flancter_rising_pulseout
  port map(
    async_rst_n => sys_rst_n,
    set_clk     => sys_clk,
    set         => reg_dat_count_clear,
    reset_clk   => mmc_clk_i,
    reset       => dat_count_clear,
    pulse_s_o   => open,
    pulse_r_o   => dat_count_clear,
    flag_o      => open
  );
 
  reg_dbus_size_reset : flancter_rising_pulseout
  port map(
    async_rst_n => sys_rst_n,
    set_clk     => sys_clk,
    set         => reg_dbus_size_clear,
    reset_clk   => mmc_clk_i,
    reset       => dbus_size_clear,
    pulse_s_o   => open,
    pulse_r_o   => dbus_size_clear,
    flag_o      => open
  );
 
  -- Use a separate command receiver to count the number of received
  -- commands.  A register setting allows counting only commands of
  -- a certain index and/or direction, otherwise all commands can be counted.
  -- Separate counts of good/bad commands are kept.
  test_cmd_receiver : mmc_test_cmd_rx
  port map(
    -- Asynchronous reset
    sys_rst_n   => sys_rst_n,
    -- SD/MMC card command signals
    sd_clk_i    => mmc_clk_i,
    sd_cmd_i    => test_cmd_i,
    -- Command outputs
    cmd_raw_o   => t_rx_cmd_raw,
    -- Status and done indicator
    cmd_done_o  => t_rx_cmd_done,
    crc_err_o   => t_rx_cmd_crc_err,
    stop_err_o  => t_rx_cmd_stop_err
  );
  -- Telemetry code byte currently only shows the direction of the transfer
  tlm_code_byte <= "11111111" when t_rx_cmd_raw(47 downto 46)="01" else "00000000";
 
  -- Handle counting received commands, whether good or bad
  -- Also, count data transfer starts
  process(sys_rst_n,mmc_clk_i)
  begin
    if (sys_rst_n='0') then
      t_rx_cmd_gdcount <= (others=>'0');
      t_rx_cmd_crc_bdcount <= (others=>'0');
      t_rx_cmd_stp_bdcount <= (others=>'0');
      t_rx_dat_count <= (others=>'0');
      dbus_active_count <= (others=>'0');
      reg_dbus_size <= "00";
      mmc_dat_r1 <= (others=>'0');
      mmc_dat_r2 <= (others=>'0');
      tlm_d_count <= (others=>'0');
      mmc_tlm_start <= '0';
    elsif (mmc_clk_i'event and mmc_clk_i='1') then
      -- Default values
      mmc_tlm_start <= '0';
      -- Data counters are incremented at each data transfer "start bit"
      -- An attempt is made to track the current data bus size, by catching
      -- CMD6 (SWITCH) commands which write to the EXT_CSD contents at
      -- location offset 183d (0xB7).  Based on the current bus size, a
      -- dstart_wait value is derived, and used to ignore activity on the
      -- SD/MMC data bus during the transfer, thereby guaranteeing that only
      -- real start bits are counted.
      if (t_rx_cmd_done='1' and (t_rx_cmd_raw(47 downto 40)=16#46#)
          and t_rx_cmd_crc_err='0' and t_rx_cmd_stop_err='0') then
        if (t_rx_cmd_raw(31 downto 24)=16#B7#) then
          -- Try to handle all EXT_CSD access modes...
          if (t_rx_cmd_raw(33 downto 32)="11") then -- Write byte mode
            reg_dbus_size <= t_rx_cmd_raw(17 downto 16);
          end if;
          if (t_rx_cmd_raw(33 downto 32)="10") then -- Clear bits mode
            reg_dbus_size <= reg_dbus_size and not t_rx_cmd_raw(17 downto 16);
          end if;
          if (t_rx_cmd_raw(33 downto 32)="01") then -- Set bits mode
            reg_dbus_size <= reg_dbus_size or t_rx_cmd_raw(17 downto 16);
          end if;
        end if;
      end if;
      -- Store previous data, for SD/MMC data bus start bit detection
      mmc_dat_r1 <= mmc_dat_i;
      mmc_dat_r2 <= mmc_dat_r1;
      -- Handle decrementing the data active count down
      if (dbus_active_count>0) then
        dbus_active_count <= dbus_active_count-1;
      end if;
      -- Detect start bits, according to reg_dbus_size setting
      -- The dstart_wait value is used to ignore further activity until
      -- after the data transfer is completed.
      if (dbus_active_count=0) then
        if (reg_dbus_size=0) then
          if (mmc_dat_r2(0)='1' and mmc_dat_r1(0)='0') then
            t_rx_dat_count <= t_rx_dat_count+1;
            tlm_d_count <= tlm_d_count+1;
            dbus_active_count <= dstart_wait;
          end if;
        end if;
        if (reg_dbus_size=1) then
          if (mmc_dat_r2(3 downto 0)="1111" and mmc_dat_r1(3 downto 0)="0000") then
            t_rx_dat_count <= t_rx_dat_count+1;
            tlm_d_count <= tlm_d_count+1;
            dbus_active_count <= dstart_wait;
          end if;
        end if;
        if (reg_dbus_size=2) then
          if (mmc_dat_r2="11111111" and mmc_dat_r1="00000000") then
            t_rx_dat_count <= t_rx_dat_count+1;
            tlm_d_count <= tlm_d_count+1;
            dbus_active_count <= dstart_wait;
          end if;
        end if;
      end if;
      if (t_rx_capture='1') then
        mmc_tlm_start <= '1';
        if (t_rx_cmd_crc_err='0' and t_rx_cmd_stop_err='0') then
          t_rx_cmd_gdcount <= t_rx_cmd_gdcount+1;
        else
          if (t_rx_cmd_crc_err='1') then
            t_rx_cmd_crc_bdcount <= t_rx_cmd_crc_bdcount+1;
          end if;
          if (t_rx_cmd_stop_err='1') then
            t_rx_cmd_stp_bdcount <= t_rx_cmd_stp_bdcount+1;
          end if;
        end if;
      end if;
      -- Clearing the counters is given priority over incrementing them
      if (gdcount_clear='1') then
        t_rx_cmd_gdcount <= (others=>'0');
      end if;
      if (crc_bdcount_clear='1') then
        t_rx_cmd_crc_bdcount <= (others=>'0');
      end if;
      if (stp_bdcount_clear='1') then
        t_rx_cmd_stp_bdcount <= (others=>'0');
      end if;
      if (dat_count_clear='1') then
        t_rx_dat_count <= (others=>'0');
      end if;
      -- Clearing the reg_dbus_size is done in this clock domain
      if (dbus_size_clear='1') then
        reg_dbus_size <= (others=>'0');
      end if;
    end if;
  end process;
  -- Create a signal that, when high, indicates that the SD/MMC command
  -- event filter criteria have been met.
--  t_rx_capture <= '1' when (t_rx_cmd_done='1' and t_rx_cmd_filter>"10000000") else
--                  '1' when (t_rx_cmd_done='1' and t_rx_cmd_filter=t_rx_cmd_raw(47 downto 40)) else
--                  '0';
-- John C sent this capture filter bugfix 24-Jun-2017
    t_rx_capture <= '1' when (t_rx_cmd_done='1' and t_rx_cmd_filter>"10000000") else
                  '1' when (t_rx_cmd_done='1' and t_rx_cmd_filter(6)=t_rx_cmd_raw(46) and t_rx_cmd_filter(5 downto 0)="111111") else
                  '1' when (t_rx_cmd_done='1' and t_rx_cmd_filter=t_rx_cmd_raw(47 downto 40)) else
                  '0';
 
  -- Derive dstart_wait values, used in detecting valid data transfer
  -- start bits.  Tune these values as needed, based on the sector
  -- size.
  write_active <= '1' when ((t_rx_cmd_raw(45 downto 40)=24) or (t_rx_cmd_raw(45 downto 40)=25)) else '0';
  dstart_wait <= dstart_wait_writing when (write_active='1') else dstart_wait_reading;
  -- When reading, include sector, plus start, CRC-16 and stop bits
  with (reg_dbus_size) select
  dstart_wait_reading <=
    to_unsigned(4096+2+16,dstart_wait'length) when "00",
    to_unsigned(1024+2+16,dstart_wait'length) when "01",
    to_unsigned( 512+2+16,dstart_wait'length) when "10",
    to_unsigned( 512+2+16,dstart_wait'length) when others;
  -- When writing, include sector, plus start, CRC-16, stop and CRC response token (2 turnaround+5 bits)
  with (reg_dbus_size) select
  dstart_wait_writing <=
    to_unsigned(4096+2+16+7,dstart_wait'length) when "00",
    to_unsigned(1024+2+16+7,dstart_wait'length) when "01",
    to_unsigned( 512+2+16+7,dstart_wait'length) when "10",
    to_unsigned( 512+2+16+7,dstart_wait'length) when others;
 
  -------------------------------------------------------------------------
  -- SD/MMC transaction telemetry sending logic
  -- For logging activity on the SD/MMC bus
 
  -- Create a 24 bit time counter with 1 microsecond resolution
  -- This is done in the system clock domain.
  tlm_1us_unit : dds_constant_squarewave
    generic map(
      OUTPUT_FREQ  => 1000000.0,    -- Desired output frequency
      SYS_CLK_RATE => SYS_CLK_RATE, -- underlying clock rate
      ACC_BITS     => 32 -- Bit width of DDS phase accumulator
    )
    port map(
      sys_rst_n    => sys_rst_n,
      sys_clk      => sys_clk,
      sys_clk_en   => '1',
 
      -- Output
      pulse_o      => tlm_1us_pulse,
      squarewave_o => open
    );
  process(sys_rst_n,sys_clk)
  begin
    if (sys_rst_n='0') then
      tlm_time <= (others=>'0');
    elsif (sys_clk'event and sys_clk='1') then
      if (tlm_1us_pulse='1') then
        tlm_time <= tlm_time+1;
      end if;
    end if;
  end process;
  -- Implement a small FIFO to accomodate the "burstiness" of the
  -- telemetry data, as compared with the more plodding consumption
  -- of it at the other end...
  tlm_fifo_unit : swiss_army_fifo
  generic map(
    USE_BRAM         => 1, -- Set to nonzero value for BRAM, zero for distributed RAM
    WIDTH            => 8,
    DEPTH            => TLM_FIFO_DEPTH,
    FILL_LEVEL_BITS  => tlm_fifo_fill_level'length, -- Should be at least int(floor(log2(DEPTH))+1.0)
    PF_FULL_POINT    => TLM_FIFO_DEPTH-16,
    PF_FLAG_POINT    => (TLM_FIFO_DEPTH/2),
    PF_EMPTY_POINT   => 1
  )
  port map(
    sys_rst_n       => sys_rst_n, -- Asynchronous
    sys_clk         => sys_clk,
    sys_clk_en      => '1',
 
    reset_i         => tlm_fifo_clear, -- Synchronous
 
    fifo_wr_i       => tlm_log_dat_we,
    fifo_din        => tlm_log_dat,
 
    fifo_rd_i       => tlm_fifo_dat_rd,
    fifo_dout       => tlm_fifo_dat,
 
    fifo_fill_level => tlm_fifo_fill_level,
    fifo_full       => open,
    fifo_empty      => tlm_fifo_leer,
    fifo_pf_full    => tlm_keinplatz,
    fifo_pf_flag    => open,
    fifo_pf_empty   => open
  );
  tlm_fifo_clear <= '1' when (t_reg_sel='1' and t_reg_sel_r1='0' and syscon_we='1' and syscon_adr(3 downto 0)=16#9#) else '0';
  tlm_fifo_dat_rd <= '1' when (tlm_fifo_reg_access='1' and tlm_r10_count>2) else
                     '1' when (tlm_fifo_reg_access='0' and tlm_tx_we='1') else
                     '0';
  -- Create an asynchronous transmitter that sends out a stream of
  -- telemetry information, when enabled.
  -- The baud clock pulse feeding the async_syscon unit is also used here
  tlm_tx_unit : async_tx_sqclk
    port map(
      sys_rst_n    => sys_rst_n,
      sys_clk      => sys_clk,
      sys_clk_en   => baud_lock, -- Do not transmit unless Baud rate is settled.
 
      -- rate and parity
      tx_parity_i  => "00", -- 0=none, 1=even, 2 or 3=odd
      tx_clk_i     => baud_clk,
 
      -- serial output
      tx_stream    => tlm_o,
 
      -- control and status
      tx_wr_i      => tlm_tx_we,        -- Starts Transmit
      tx_dat_i     => tlm_fifo_dat,
      tx_done_o    => tlm_tx_done
    );
  -- Automatically read out the contents of the FIFO, when enabled
  tlm_tx_we <= '1' when baud_lock='1' and tlm_tx_done='1' and tlm_send_i='1'
                   and tlm_fifo_leer='0' and tlm_fifo_reg_access='0' else '0';
 
  -- This is the sequencer that coordinates the creation of a new
  -- telemetry log record, to be stuffed into the telemetry log FIFO
  process(sys_rst_n,sys_clk)
  begin
    if (sys_rst_n='0') then
      tlm_stage  <= (others=>'0');
      tlm_tstamp <= (others=>'0');
      tlm_fid    <= (others=>'1');
    elsif (sys_clk'event and sys_clk='1') then
      -- Handle the sequence step down counter
      if (tlm_stage>0) then
        tlm_stage <= tlm_stage-1;
      end if;
      -- Catch start signal.  If the FIFO has room
      -- for at least one more complete record, then
      -- capture timestamp and begin.
      if (tlm_start='1' and tlm_keinplatz='0') then
        tlm_tstamp <= tlm_time;
        tlm_fid <= tlm_fid+1;
        tlm_stage <= to_unsigned(16,tlm_stage'length);
      end if;
    end if;
  end process;
  -- When active, write a new data byte every clock cycle
  tlm_log_dat_we <= '1' when tlm_stage>0 else '0';
 
  -- Select data for Local Register Reads
  with to_integer(tlm_stage) select
  tlm_log_dat <=
    to_unsigned(16#FE#,8)             when 16,
    to_unsigned(16#6B#,8)             when 15,
    to_unsigned(16#28#,8)             when 14,
    to_unsigned(16#40#,8)             when 13,
    tlm_fid                           when 12,
    tlm_tstamp(23 downto 16)          when 11,
    tlm_tstamp(15 downto 8)           when 10,
    tlm_tstamp( 7 downto 0)           when  9,
    tlm_d_count                       when  8,
    tlm_code_byte                     when  7,
    "00" & t_rx_cmd_raw(45 downto 40) when  6, -- Upper 2 MSBs determine tlm_code_byte
    t_rx_cmd_raw(39 downto 32)        when  5,
    t_rx_cmd_raw(31 downto 24)        when  4,
    t_rx_cmd_raw(23 downto 16)        when  3,
    t_rx_cmd_raw(15 downto  8)        when  2,
    t_rx_cmd_raw( 7 downto  0)        when  1,
    to_unsigned(16#55#,8)             when others;
 
  -- Use safe clock domain crossing for the signal that starts the process
  -- of emitting a new telemetry record, so we don't miss anything.
  tlm_start_pulser : flancter_rising_pulseout
  port map(
    async_rst_n => sys_rst_n,
    set_clk     => mmc_clk_i,
    set         => mmc_tlm_start,
    reset_clk   => sys_clk,
    reset       => tlm_start,
    pulse_s_o   => open,
    pulse_r_o   => tlm_start,
    flag_o      => open
  );
 
 
  -------------------------------------------------------------------------
  -- Create a Block RAM which the SD/MMC controller uses as a data
  -- storage area.
  -- The 'A' port is attached to the simulation bus controller
  -- The 'B' port is attached to the mmc controller
  h_ram_we <= '1' when h_ram_sel='1' and syscon_we='1' else '0';
  host_0_bram_0 : swiss_army_ram
    generic map(
      USE_BRAM  => 1, -- Set to nonzero value for BRAM, zero for distributed RAM
      WRITETHRU => 1, -- Set to nonzero value for writethrough mode
      USE_FILE  => 1, -- Set to nonzero value to use INIT_FILE
      INIT_VAL  => 16#00#, -- Value used when INIT_FILE is not used
      INIT_SEL  => 0, -- Selects which segment of (larger) INIT_FILE to use
      INIT_FILE => "host_ram_init.txt", -- ASCII hexadecimal initialization file name
      FIL_WIDTH => 32, -- Bit width of init file lines
      ADR_WIDTH => HOST_RAM_ADR_BITS,
      DAT_WIDTH =>  8
    )
    port map(
      clk_a    => sys_clk,
      adr_a_i  => syscon_adr(13 downto 0),
      we_a_i   => h_ram_we,
      en_a_i   => std_logic'('1'),
      dat_a_i  => syscon_dat_wr(7 downto 0),
      dat_a_o  => h_ram_dat_rd,
 
      clk_b    => host_bram_clk,
      adr_b_i  => host_bram_adr(HOST_RAM_ADR_BITS-1 downto 0),
      we_b_i   => host_bram_we,
      en_b_i   => std_logic'('1'),
      dat_b_i  => host_bram_dat_wr,
      dat_b_o  => host_bram_dat_rd
    );
-- system side BRAM ack signal needs to be delayed by 1 cycle,
-- to allow for the BRAM to respond to the given address.
process(sys_rst_n,sys_clk)
begin
  if (sys_rst_n='0') then
    h_ram_ack <= '0';
  elsif (sys_clk'event and sys_clk='1') then
    h_ram_ack <= h_ram_sel;
  end if;
end process;
 
  sd_host_0 : sd_controller_8bit_bram
  port map(
    -- WISHBONE common
    wb_clk_i     => sys_clk,
    wb_rst_i     => fpga_rst,
    -- WISHBONE slave (register interface)
    wb_dat_i     => syscon_dat_wr,
    wb_dat_o     => h_reg_dat_rd,
    wb_adr_i     => syscon_adr(3 downto 0),
    wb_we_i      => syscon_we,
    wb_cyc_i     => h_reg_sel,
    wb_ack_o     => h_reg_ack,
    -- Dedicated BRAM port without acknowledge.
    -- Access cycles must complete immediately.
    -- (data to cross clock domains by this dual-ported BRAM)
    bram_clk_o   => host_bram_clk, -- Same as sd_clk_o_pad
    bram_dat_o   => host_bram_dat_wr,
    bram_dat_i   => host_bram_dat_rd,
    bram_adr_o   => host_bram_adr,
    bram_we_o    => host_bram_we,
    bram_cyc_o   => host_bram_cyc,
    --SD Card Interface
    sd_cmd_i     => host_cmd_i,
    sd_cmd_o     => host_cmd_o,
    sd_cmd_oe_o  => host_cmd_oe_o,
    sd_dat_i     => host_dat_i,
    sd_dat_o     => host_dat_o,
    sd_dat_oe_o  => host_dat_oe_o,
    sd_dat_siz_o => host_dat_siz_o,
    sd_clk_o_pad => host_clk_o_pad,
    -- Interrupt outputs
    int_cmd_o    => open,
    int_data_o   => open
  );
 
  mmc_slave : mmc_data_pipe
  generic map(
    EXT_CSD_INIT_FILE => "ext_csd_init.txt", -- Initial contents of EXT_CSD
    FIFO_DEPTH        => MMC_FIFO_DEPTH,
    FILL_LEVEL_BITS   => MMC_FILL_LEVEL_BITS, --s_fif_dat_wr_level'length, -- Should be at least int(floor(log2(FIFO_DEPTH))+1.0)
    RAM_ADR_WIDTH     => MMC_RAM_ADR_BITS
  )
  port map(
 
    -- Asynchronous reset
    sys_rst_n     => fpga_rst_n,
    sys_clk       => sys_clk,
 
    -- Bus interface
    adr_i         => syscon_adr(3 downto 0),
    sel_i         => s_reg_sel,
    we_i          => syscon_we,
    dat_i         => syscon_dat_wr,
    dat_o         => s_reg_dat_rd,
    ack_o         => s_reg_ack,
 
    -- SD/MMC card signals
    mmc_clk_i     => slave_clk_i,
    mmc_cmd_i     => slave_cmd_i,
    mmc_cmd_o     => slave_cmd_o,
    mmc_cmd_oe_o  => slave_cmd_oe_o,
    mmc_od_mode_o => slave_od_mode_o, -- Open drain mode
    mmc_dat_i     => slave_dat_i,
    mmc_dat_o     => slave_dat_o,
    mmc_dat_oe_o  => slave_dat_oe_o,
    mmc_dat_siz_o => slave_dat_siz_o,
 
    -- Data Pipe FIFOs
    wr_clk_i      => sys_clk,
    wr_clk_en_i   => '1',
    wr_reset_i    => opc_rspf_reset_i,          --s_fif_dat_wr_clear,  -- Synchronous
    wr_en_i       => opc_rspf_we_i,             --s_fif_wr,
    wr_dat_i      => opc_rspf_dat_i,            --s_fif_dat_wr,  --syscon_dat_wr(7 downto 0),
    wr_fifo_level => opc_rspf_cnt_o,            --s_fif_dat_wr_level,
    wr_fifo_full  => opc_rspf_fl_o,             --s_fif_wr_full,
    wr_fifo_empty => opc_rspf_mt_o,             --s_fif_wr_empty,
 
    rd_clk_i      => sys_clk,
    rd_clk_en_i   => '1',
    rd_reset_i    => opc_rd_reset_i,        --s_fif_dat_rd_clear,  -- Synchronous
    rd_en_i       => opc_fif_ren_i,         --s_fif_rd,
    rd_dat_o      => opc_fif_dat_o,         --s_fif_dat_rd,
    rd_fifo_level => opc_rd_cnt_o,          --s_fif_dat_rd_level,
    rd_fifo_full  => open,                  --s_fif_rd_full,
    rd_fifo_empty => opc_fif_mt_o,          --s_fif_rd_empty,
 
    -- Data Pipe RAM
    ram_clk_i     => sys_clk,
    ram_clk_en_i  => '1',
    ram_adr_i     => syscon_adr(MMC_RAM_ADR_BITS-1 downto 0),
    ram_we_i      => s_ram_we,
    ram_dat_i     => syscon_dat_wr(7 downto 0),
    ram_dat_o     => s_ram_dat_rd
  );
  s_fif_sel <= '1' when syscon_cyc='1' and t_reg_sel='1' and syscon_adr(3 downto 0)=16#F# else '0';
--  s_fif_rd  <= '1' when syscon_we='0' and s_fif_sel='1' else '0';
--  s_fif_we  <= '1' when syscon_we='1' and s_fif_sel='1' else '0';
  s_ram_we  <= '1' when syscon_we='1' and s_ram_sel='1' else '0';
 
-- system side BRAM ack signal needs to be delayed by 1 cycle,
-- to allow for the BRAM to respond to the given address.
process(sys_rst_n,sys_clk)
begin
  if (sys_rst_n='0') then
    s_ram_ack <= '0';
  elsif (sys_clk'event and sys_clk='1') then
    s_ram_ack <= s_ram_sel;
  end if;
end process;
 
-- Formulate function enable signals
  host_enable  <= host_en_i  or host_en_reg;
  slave_enable <= slave_en_i or slave_en_reg;
 
-- Use output enables to steer MMC signaling
 
  mmc_clk_o     <= host_clk_o_pad;
  mmc_clk_oe_o  <= '1' when host_enable='1' else '0';
  mmc_cmd_o     <= (host_cmd_o or not host_enable) and (slave_cmd_o or not slave_enable);
  mmc_cmd_oe_o  <= (host_cmd_oe_o and host_enable) or (slave_cmd_oe_o and slave_enable);
  mmc_dat_o     <= host_dat_o   when (host_dat_oe_o='1' and host_enable='1') else
                   slave_dat_o  when (slave_dat_oe_o='1' and slave_enable='1') else
                   (others=>'1');
  mmc_dat_oe_o  <= (host_dat_oe_o and host_enable) or (slave_dat_oe_o and slave_enable);
  mmc_od_mode_o <= slave_od_mode_o when slave_enable='1' else '0'; -- Open drain mode
  mmc_dat_siz_o <= host_dat_siz_o  when (host_dat_oe_o='1' and host_enable='1') else
                   slave_dat_siz_o when (slave_dat_oe_o='1' and slave_enable='1') else
                   (others=>'0');
 
  host_cmd_i  <= mmc_cmd_i when host_enable='1' and host_cmd_oe_o='0' else '1';
  slave_cmd_i <= mmc_cmd_i when slave_enable='1' and slave_cmd_oe_o='0' else '1';
  host_dat_i  <= mmc_dat_i when host_enable='1' and host_dat_oe_o='0' else (others=>'1');
  slave_dat_i <= mmc_dat_i when slave_enable='1' and slave_dat_oe_o='0' else (others=>'1');
  slave_clk_i <= mmc_clk_i;
 
  test_cmd_i  <= mmc_cmd_i;
 
end beh;
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.