mirror of https://github.com/marqs85/ossc.git
383 lines
13 KiB
VHDL
383 lines
13 KiB
VHDL
-- (C) 2001-2015 Altera Corporation. All rights reserved.
|
|
-- Your use of Altera Corporation's design tools, logic functions and other
|
|
-- software and tools, and its AMPP partner logic functions, and any output
|
|
-- files 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 Altera Program License Subscription
|
|
-- Agreement, Altera MegaCore Function License Agreement, or other applicable
|
|
-- license agreement, including, without limitation, that your use is for the
|
|
-- sole purpose of programming logic devices manufactured by Altera and sold by
|
|
-- Altera or its authorized distributors. Please refer to the applicable
|
|
-- agreement for further details.
|
|
|
|
|
|
-------------------------------------------------------------------------------------
|
|
-- This module is a dual port memory block. It has a 16-bit port and a 1-bit port.
|
|
-- The 1-bit port is used to either send or receive data, while the 16-bit port is used
|
|
-- by Avalon interconnet to store and retrieve data.
|
|
--
|
|
-- NOTES/REVISIONS:
|
|
-------------------------------------------------------------------------------------
|
|
library ieee;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.std_logic_arith.all;
|
|
use ieee.std_logic_unsigned.all;
|
|
|
|
entity Altera_UP_SD_Card_Buffer is
|
|
generic (
|
|
TIMEOUT : std_logic_vector(15 downto 0) := "1111111111111111";
|
|
BUSY_WAIT : std_logic_vector(15 downto 0) := "0000001111110000"
|
|
);
|
|
port
|
|
(
|
|
i_clock : in std_logic;
|
|
i_reset_n : in std_logic;
|
|
|
|
-- 1 bit port to transmit and receive data on the data line.
|
|
i_begin : in std_logic;
|
|
i_sd_clock_pulse_trigger : in std_logic;
|
|
i_transmit : in std_logic;
|
|
i_1bit_data_in : in std_logic;
|
|
o_1bit_data_out : out std_logic;
|
|
o_operation_complete : out std_logic;
|
|
o_crc_passed : out std_logic;
|
|
o_timed_out : out std_logic;
|
|
o_dat_direction : out std_logic; -- set to 1 to send data, set to 0 to receive it.
|
|
|
|
-- 16 bit port to be accessed by a user circuit.
|
|
i_enable_16bit_port : in std_logic;
|
|
i_address_16bit_port : in std_logic_vector(7 downto 0);
|
|
i_write_16bit : in std_logic;
|
|
i_16bit_data_in : in std_logic_vector(15 downto 0);
|
|
o_16bit_data_out : out std_logic_vector(15 downto 0)
|
|
);
|
|
|
|
end entity;
|
|
|
|
architecture rtl of Altera_UP_SD_Card_Buffer is
|
|
|
|
component Altera_UP_SD_CRC16_Generator
|
|
port
|
|
(
|
|
i_clock : in std_logic;
|
|
i_enable : in std_logic;
|
|
i_reset_n : in std_logic;
|
|
i_sync_reset : in std_logic;
|
|
i_shift : in std_logic;
|
|
i_datain : in std_logic;
|
|
o_dataout : out std_logic;
|
|
o_crcout : out std_logic_vector(15 downto 0)
|
|
);
|
|
end component;
|
|
|
|
component Altera_UP_SD_Card_Memory_Block
|
|
PORT
|
|
(
|
|
address_a : IN STD_LOGIC_VECTOR (7 DOWNTO 0);
|
|
address_b : IN STD_LOGIC_VECTOR (11 DOWNTO 0);
|
|
clock_a : IN STD_LOGIC ;
|
|
clock_b : IN STD_LOGIC ;
|
|
data_a : IN STD_LOGIC_VECTOR (15 DOWNTO 0);
|
|
data_b : IN STD_LOGIC_VECTOR (0 DOWNTO 0);
|
|
enable_a : IN STD_LOGIC := '1';
|
|
enable_b : IN STD_LOGIC := '1';
|
|
wren_a : IN STD_LOGIC := '1';
|
|
wren_b : IN STD_LOGIC := '1';
|
|
q_a : OUT STD_LOGIC_VECTOR (15 DOWNTO 0);
|
|
q_b : OUT STD_LOGIC_VECTOR (0 DOWNTO 0)
|
|
);
|
|
END component;
|
|
|
|
-- Build an enumerated type for the state machine. On reset always reset the DE2 and read the state
|
|
-- of the switches.
|
|
type state_type is (s_RESET, s_WAIT_REQUEST, s_SEND_START_BIT, s_SEND_DATA, s_SEND_CRC, s_SEND_STOP, s_WAIT_BUSY, s_WAIT_BUSY_END,
|
|
s_WAIT_DATA_START, s_RECEIVING_LEADING_BITS, s_RECEIVING_DATA, s_RECEIVING_STOP_BIT, s_WAIT_DEASSERT);
|
|
|
|
-- Register to hold the current state
|
|
signal current_state : state_type;
|
|
signal next_state : state_type;
|
|
-- Local wires
|
|
-- REGISTERED
|
|
signal crc_counter : std_logic_vector(3 downto 0);
|
|
signal local_mode : std_logic;
|
|
signal dataout_1bit : std_logic;
|
|
signal bit_counter : std_logic_vector(2 downto 0);
|
|
signal byte_counter : std_logic_vector(8 downto 0);
|
|
signal shift_register : std_logic_vector(16 downto 0);
|
|
signal timeout_register : std_logic_vector(15 downto 0);
|
|
signal data_in_reg : std_logic;
|
|
-- UNREGISTERED
|
|
signal crc_out : std_logic_vector(15 downto 0);
|
|
signal single_bit_conversion, single_bit_out : std_logic_vector( 0 downto 0);
|
|
signal packet_mem_addr_b : std_logic_vector(11 downto 0);
|
|
signal local_reset, to_crc_generator, from_crc_generator, from_mem_1_bit, shift_crc,
|
|
recv_data, crc_generator_enable : std_logic;
|
|
begin
|
|
-- State transitions
|
|
state_transitions: process( current_state, i_begin, i_sd_clock_pulse_trigger, i_transmit, byte_counter,
|
|
bit_counter, crc_counter, i_1bit_data_in, timeout_register, data_in_reg)
|
|
begin
|
|
case (current_state) is
|
|
when s_RESET =>
|
|
-- Reset local registers and begin waiting for user input.
|
|
next_state <= s_WAIT_REQUEST;
|
|
|
|
when s_WAIT_REQUEST =>
|
|
-- Wait for i_begin to be high
|
|
if ((i_begin = '1') and (i_sd_clock_pulse_trigger = '1')) then
|
|
if (i_transmit = '1') then
|
|
next_state <= s_SEND_START_BIT;
|
|
else
|
|
next_state <= s_WAIT_DATA_START;
|
|
end if;
|
|
else
|
|
next_state <= s_WAIT_REQUEST;
|
|
end if;
|
|
|
|
when s_SEND_START_BIT =>
|
|
-- Send a 0 first, followed by 4096 bits of data, 16 CRC bits, and stop bit.
|
|
if (i_sd_clock_pulse_trigger = '1') then
|
|
next_state <= s_SEND_DATA;
|
|
else
|
|
next_state <= s_SEND_START_BIT;
|
|
end if;
|
|
|
|
when s_SEND_DATA =>
|
|
-- Send 4096 data bits
|
|
if ((i_sd_clock_pulse_trigger = '1') and (bit_counter = "000") and (byte_counter = "111111111")) then
|
|
next_state <= s_SEND_CRC;
|
|
else
|
|
next_state <= s_SEND_DATA;
|
|
end if;
|
|
|
|
when s_SEND_CRC =>
|
|
-- Send 16 CRC bits
|
|
if ((i_sd_clock_pulse_trigger = '1') and (crc_counter = "1111")) then
|
|
next_state <= s_SEND_STOP;
|
|
else
|
|
next_state <= s_SEND_CRC;
|
|
end if;
|
|
|
|
when s_SEND_STOP =>
|
|
-- Send stop bit.
|
|
if (i_sd_clock_pulse_trigger = '1') then
|
|
next_state <= s_WAIT_BUSY;
|
|
else
|
|
next_state <= s_SEND_STOP;
|
|
end if;
|
|
|
|
when s_WAIT_BUSY =>
|
|
-- After a write, wait for the busy signal. Do not return a done signal until you receive a busy signal.
|
|
-- If you do not and a long time expires, then the data must have been rejected (due to CRC error maybe).
|
|
-- In such a case return failure.
|
|
if ((i_sd_clock_pulse_trigger = '1') and (data_in_reg = '0') and (timeout_register = "0000000000010000")) then
|
|
next_state <= s_WAIT_BUSY_END;
|
|
else
|
|
if (timeout_register = BUSY_WAIT) then
|
|
next_state <= s_WAIT_DEASSERT;
|
|
else
|
|
next_state <= s_WAIT_BUSY;
|
|
end if;
|
|
end if;
|
|
|
|
when s_WAIT_BUSY_END =>
|
|
if (i_sd_clock_pulse_trigger = '1') then
|
|
if (data_in_reg = '1') then
|
|
next_state <= s_WAIT_DEASSERT;
|
|
else
|
|
next_state <= s_WAIT_BUSY_END;
|
|
end if;
|
|
else
|
|
next_state <= s_WAIT_BUSY_END;
|
|
end if;
|
|
|
|
when s_WAIT_DATA_START =>
|
|
-- Wait for the start bit
|
|
if ((i_sd_clock_pulse_trigger = '1') and (data_in_reg = '0')) then
|
|
next_state <= s_RECEIVING_LEADING_BITS;
|
|
else
|
|
if (timeout_register = TIMEOUT) then
|
|
next_state <= s_WAIT_DEASSERT;
|
|
else
|
|
next_state <= s_WAIT_DATA_START;
|
|
end if;
|
|
end if;
|
|
|
|
when s_RECEIVING_LEADING_BITS =>
|
|
-- shift the start bit in as well as the next 16 bits. Once they are all in you can start putting data into memory.
|
|
if ((i_sd_clock_pulse_trigger = '1') and (crc_counter = "1111")) then
|
|
next_state <= s_RECEIVING_DATA;
|
|
else
|
|
next_state <= s_RECEIVING_LEADING_BITS;
|
|
end if;
|
|
|
|
when s_RECEIVING_DATA =>
|
|
-- Wait until all bits arrive.
|
|
if ((i_sd_clock_pulse_trigger = '1') and (bit_counter = "000") and (byte_counter = "111111111")) then
|
|
next_state <= s_RECEIVING_STOP_BIT;
|
|
else
|
|
next_state <= s_RECEIVING_DATA;
|
|
end if;
|
|
|
|
when s_RECEIVING_STOP_BIT =>
|
|
-- Wait until all bits arrive.
|
|
if (i_sd_clock_pulse_trigger = '1')then
|
|
next_state <= s_WAIT_DEASSERT;
|
|
else
|
|
next_state <= s_RECEIVING_STOP_BIT;
|
|
end if;
|
|
|
|
when s_WAIT_DEASSERT =>
|
|
if (i_begin = '1') then
|
|
next_state <= s_WAIT_DEASSERT;
|
|
else
|
|
next_state <= s_WAIT_REQUEST;
|
|
end if;
|
|
|
|
when others =>
|
|
next_state <= s_RESET;
|
|
end case;
|
|
end process;
|
|
|
|
-- State registers
|
|
state_regs: process(i_clock, i_reset_n, local_reset)
|
|
begin
|
|
if (i_reset_n = '0') then
|
|
current_state <= s_RESET;
|
|
elsif (rising_edge(i_clock)) then
|
|
current_state <= next_state;
|
|
end if;
|
|
end process;
|
|
|
|
-- FSM outputs
|
|
to_crc_generator <= shift_register(16) when (current_state = s_RECEIVING_DATA) else
|
|
from_mem_1_bit when (current_state = s_SEND_DATA) else
|
|
'0';
|
|
shift_crc <= '1' when (current_state = s_SEND_CRC) else '0';
|
|
local_reset <= '1' when ((current_state = s_RESET) or (current_state = s_WAIT_REQUEST)) else '0';
|
|
recv_data <= '1' when (current_state = s_RECEIVING_DATA) else '0';
|
|
single_bit_conversion(0) <= shift_register(15);
|
|
crc_generator_enable <= '0' when (current_state = s_WAIT_DEASSERT) else i_sd_clock_pulse_trigger;
|
|
o_operation_complete <= '1' when (current_state = s_WAIT_DEASSERT) else '0';
|
|
o_dat_direction <= '1' when ( (current_state = s_SEND_START_BIT) or
|
|
(current_state = s_SEND_DATA) or
|
|
(current_state = s_SEND_CRC) or
|
|
(current_state = s_SEND_STOP))
|
|
else '0';
|
|
o_1bit_data_out <= dataout_1bit;
|
|
o_crc_passed <= '1' when ((crc_out = shift_register(16 downto 1)) and (shift_register(0) = '1')) else '0';
|
|
o_timed_out <= '1' when (timeout_register = TIMEOUT) else '0';
|
|
|
|
-- Local components
|
|
local_regs: process(i_clock, i_reset_n, local_reset)
|
|
begin
|
|
if (i_reset_n = '0') then
|
|
bit_counter <= (OTHERS => '1');
|
|
byte_counter <= (OTHERS => '0');
|
|
dataout_1bit <= '1';
|
|
crc_counter <= (OTHERS => '0');
|
|
shift_register <= (OTHERS => '0');
|
|
elsif (rising_edge(i_clock)) then
|
|
-- counters and serial output
|
|
if (local_reset = '1') then
|
|
bit_counter <= (OTHERS => '1');
|
|
byte_counter <= (OTHERS => '0');
|
|
dataout_1bit <= '1';
|
|
data_in_reg <= '1';
|
|
crc_counter <= (OTHERS => '0');
|
|
shift_register <= (OTHERS => '0');
|
|
elsif (i_sd_clock_pulse_trigger = '1') then
|
|
if ((not (current_state = s_RECEIVING_LEADING_BITS)) and (not (current_state = s_SEND_CRC))) then
|
|
crc_counter <= (OTHERS => '0');
|
|
else
|
|
if (not (crc_counter = "1111")) then
|
|
crc_counter <= crc_counter + '1';
|
|
end if;
|
|
end if;
|
|
if ((current_state = s_RECEIVING_DATA) or (current_state = s_SEND_DATA)) then
|
|
if (not ((bit_counter = "000") and (byte_counter = "111111111"))) then
|
|
if (bit_counter = "000") then
|
|
byte_counter <= byte_counter + '1';
|
|
bit_counter <= "111";
|
|
else
|
|
bit_counter <= bit_counter - '1';
|
|
end if;
|
|
end if;
|
|
end if;
|
|
-- Output data bit.
|
|
if (current_state = s_SEND_START_BIT) then
|
|
dataout_1bit <= '0';
|
|
elsif (current_state = s_SEND_DATA) then
|
|
dataout_1bit <= from_mem_1_bit;
|
|
elsif (current_state = s_SEND_CRC) then
|
|
dataout_1bit <= from_crc_generator;
|
|
else
|
|
dataout_1bit <= '1'; -- Stop bit.
|
|
end if;
|
|
|
|
-- Shift register to store the CRC bits once the message is received.
|
|
if ((current_state = s_RECEIVING_DATA) or
|
|
(current_state = s_RECEIVING_LEADING_BITS) or
|
|
(current_state = s_RECEIVING_STOP_BIT)) then
|
|
shift_register(16 downto 1) <= shift_register(15 downto 0);
|
|
shift_register(0) <= data_in_reg;
|
|
end if;
|
|
data_in_reg <= i_1bit_data_in;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
-- Register holding the timeout value for data transmission.
|
|
timeout_reg: process(i_clock, i_reset_n, current_state, i_sd_clock_pulse_trigger)
|
|
begin
|
|
if (i_reset_n = '0') then
|
|
timeout_register <= (OTHERS => '0');
|
|
elsif (rising_edge(i_clock)) then
|
|
if ((current_state = s_SEND_STOP) or
|
|
(current_state = s_WAIT_REQUEST)) then
|
|
timeout_register <= (OTHERS => '0');
|
|
elsif (i_sd_clock_pulse_trigger = '1') then
|
|
-- Increment the timeout counter
|
|
if (((current_state = s_WAIT_DATA_START) or
|
|
(current_state = s_WAIT_BUSY)) and (not (timeout_register = TIMEOUT))) then
|
|
timeout_register <= timeout_register + '1';
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
-- Instantiated components.
|
|
crc16_checker: Altera_UP_SD_CRC16_Generator
|
|
port map
|
|
(
|
|
i_clock => i_clock,
|
|
i_reset_n => i_reset_n,
|
|
i_sync_reset => local_reset,
|
|
i_enable => crc_generator_enable,
|
|
i_shift => shift_crc,
|
|
i_datain => to_crc_generator,
|
|
o_dataout => from_crc_generator,
|
|
o_crcout => crc_out
|
|
);
|
|
|
|
packet_memory: Altera_UP_SD_Card_Memory_Block
|
|
PORT MAP
|
|
(
|
|
address_a => i_address_16bit_port,
|
|
address_b => packet_mem_addr_b,
|
|
clock_a => i_clock,
|
|
clock_b => i_clock,
|
|
data_a => i_16bit_data_in,
|
|
data_b => single_bit_conversion,
|
|
enable_a => i_enable_16bit_port,
|
|
enable_b => '1',
|
|
wren_a => i_write_16bit,
|
|
wren_b => recv_data,
|
|
q_a => o_16bit_data_out,
|
|
q_b => single_bit_out
|
|
);
|
|
from_mem_1_bit <= single_bit_out(0);
|
|
packet_mem_addr_b <= (byte_counter & bit_counter);
|
|
|
|
end rtl;
|