228 lines
8.7 KiB
VHDL
228 lines
8.7 KiB
VHDL
----------------------------------------------------------------------
|
|
---- ----
|
|
---- ATARI IP Core peripheral Add-On ----
|
|
---- ----
|
|
---- This file is part of the FPGA-ATARI project. ----
|
|
---- http://www.experiment-s.de ----
|
|
---- ----
|
|
---- Description: ----
|
|
---- This hardware provides an interface to connect to a SD-Card. ----
|
|
---- ----
|
|
---- This interface is based on the project 'SatanDisk' of ----
|
|
---- Miroslav Nohaj 'Jookie'. The code is an interpretation of ----
|
|
---- the original code, written in VERILOG. It is provided for ----
|
|
---- the use in a system on programmable chips (SOPC). ----
|
|
---- ----
|
|
---- Timing: Use a clock frequency of 16MHz for this component. ----
|
|
---- Use the same clock frequency for the connected AVR ----
|
|
---- microcontroller. ----
|
|
---- ----
|
|
---- To Do: ----
|
|
---- - ----
|
|
---- ----
|
|
---- Author(s): ----
|
|
---- - Wolfgang Foerster, wf@experiment-s.de; wf@inventronik.de ----
|
|
---- ----
|
|
----------------------------------------------------------------------
|
|
---- ----
|
|
---- Copyright (C) 2007 Wolfgang Foerster ----
|
|
---- ----
|
|
---- This source file may be used and distributed without ----
|
|
---- restriction provided that this copyright statement is not ----
|
|
---- removed from the file and that any derivative work contains ----
|
|
---- the original copyright notice and the associated disclaimer. ----
|
|
---- ----
|
|
---- This source file is free software; you can redistribute it ----
|
|
---- and/or modify it under the terms of the GNU Lesser General ----
|
|
---- Public License as published by the Free Software Foundation; ----
|
|
---- either version 2.1 of the License, or (at your option) any ----
|
|
---- later version. ----
|
|
---- ----
|
|
---- This source is distributed in the hope that it will be ----
|
|
---- useful, but WITHOUT ANY WARRANTY; without even the implied ----
|
|
---- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ----
|
|
---- PURPOSE. See the GNU Lesser General Public License for more ----
|
|
---- details. ----
|
|
---- ----
|
|
---- You should have received a copy of the GNU Lesser General ----
|
|
---- Public License along with this source; if not, download it ----
|
|
---- from http://www.gnu.org/licenses/lgpl.html ----
|
|
---- ----
|
|
----------------------------------------------------------------------
|
|
---- This hardware works with the original ATARI ----
|
|
---- hard dik driver. ----
|
|
----------------------------------------------------------------------
|
|
--
|
|
-- Revision History
|
|
--
|
|
-- Revision 1.0 2007/01/05 WF
|
|
-- Initial Release.
|
|
|
|
library ieee;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.std_logic_unsigned.all;
|
|
|
|
entity WF_SD_CARD is
|
|
port (
|
|
-- System:
|
|
RESETn : in bit;
|
|
CLK : in bit; -- 16MHz, see above.
|
|
|
|
-- ACSI section:
|
|
ACSI_A1 : in bit;
|
|
ACSI_CSn : in bit;
|
|
ACSI_ACKn : in bit;
|
|
ACSI_INTn : out bit;
|
|
ACSI_DRQn : out bit;
|
|
ACSI_D : inout std_logic_vector(7 downto 0);
|
|
|
|
-- Microcontroller interface:
|
|
MC_D : inout std_logic_vector(7 downto 0);
|
|
MC_DO : in bit;
|
|
MC_PIO_DMAn : in bit;
|
|
MC_RWn : in bit;
|
|
MC_CLR_CMD : in bit;
|
|
MC_DONE : out bit;
|
|
MC_GOT_CMD : out bit
|
|
);
|
|
end WF_SD_CARD;
|
|
|
|
architecture BEHAVIOR of WF_SD_CARD is
|
|
signal DATA_REG : std_logic_vector(7 downto 0);
|
|
signal D0_REG : bit;
|
|
signal INT_REG : bit;
|
|
signal DRQ_REG : bit;
|
|
signal DONE_REG : bit;
|
|
signal GOT_CMD_REG : bit;
|
|
signal HOLD : bit;
|
|
signal PREV_CSn : bit;
|
|
signal PREV_ACKn : bit;
|
|
begin
|
|
MC_D <= DATA_REG when MC_RWn = '0' and DONE_REG = '1' else (others => 'Z');
|
|
ACSI_D <= DATA_REG when MC_RWn = '1' and (ACSI_CSn = '0' or ACSI_ACKn = '0' or HOLD = '1') else (others => 'Z');
|
|
ACSI_INTn <= INT_REG;
|
|
ACSI_DRQn <= DRQ_REG;
|
|
MC_DONE <= DONE_REG;
|
|
MC_GOT_CMD <= GOT_CMD_REG;
|
|
|
|
P_DATA: process(RESETn, CLK)
|
|
begin
|
|
if RESETn = '0' then
|
|
DATA_REG <= (others => '0');
|
|
elsif CLK = '1' and CLK' event then
|
|
if D0_REG = '0' and MC_DO = '1' and MC_RWn = '1' then
|
|
DATA_REG <= MC_D; -- Read from AVR to ACSI.
|
|
end if;
|
|
--
|
|
if PREV_CSn = '0' and ACSI_CSn = '0' and MC_RWn = '0' and DONE_REG = '0' then
|
|
DATA_REG <= ACSI_D; -- Write from ACSI to AVR.
|
|
elsif PREV_ACKn = '0' and ACSI_ACKn = '0' and MC_RWn = '0' and DONE_REG = '0' then
|
|
DATA_REG <= ACSI_D; -- Write from ACSI to AVR.
|
|
end if;
|
|
end if;
|
|
end process P_DATA;
|
|
|
|
P_SYNC: process
|
|
begin
|
|
wait until CLK = '1' and CLK' event;
|
|
PREV_CSn <= ACSI_CSn;
|
|
PREV_ACKn <= ACSI_ACKn;
|
|
end process P_SYNC;
|
|
|
|
P_INT_DRQ: process(RESETn, CLK)
|
|
begin
|
|
if RESETn = '0' then
|
|
INT_REG <= '1'; -- No interrupt.
|
|
DRQ_REG <= '1'; -- No data request.
|
|
elsif CLK = '1' and CLK' event then
|
|
if D0_REG = '0' and MC_DO = '1' and MC_PIO_DMAn = '1' then -- Positive MC_DO edge.
|
|
INT_REG <= '0'; -- Release an interrupt.
|
|
DRQ_REG <= '1';
|
|
elsif D0_REG = '0' and MC_DO = '1' then
|
|
INT_REG <= '1';
|
|
DRQ_REG <= '0'; -- Release a data request.
|
|
end if;
|
|
--
|
|
if MC_CLR_CMD = '1' then -- Clear done.
|
|
INT_REG <= '1'; -- Restore INT_REG.
|
|
DRQ_REG <= '1'; -- Restore DRQ_REG.
|
|
end if;
|
|
--
|
|
if (PREV_CSn = '0' and ACSI_CSn = '0') or (PREV_ACKn = '0' and ACSI_ACKn = '0') then
|
|
if ACSI_CSn = '0' then
|
|
INT_REG <= '1';
|
|
end if;
|
|
--
|
|
if ACSI_ACKn = '0' then
|
|
DRQ_REG <= '1';
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end process P_INT_DRQ;
|
|
|
|
P_HOLD: process(RESETn, CLK)
|
|
begin
|
|
if RESETn = '0' then
|
|
HOLD <= '0';
|
|
elsif CLK = '1' and CLK' event then
|
|
if (PREV_CSn = '0' and ACSI_CSn = '0') or (PREV_ACKn = '0' and ACSI_ACKn = '0') then
|
|
HOLD <= '1';
|
|
elsif PREV_CSn = '1' and ACSI_CSn = '1' then -- If signal is high.
|
|
HOLD <= '0';
|
|
elsif PREV_ACKn = '1' and ACSI_ACKn = '1' then -- If signal is high.
|
|
HOLD <= '0';
|
|
elsif PREV_CSn = '0' and ACSI_CSn = '1' then -- Rising edge.
|
|
HOLD <= '1';
|
|
elsif PREV_ACKn = '0' and ACSI_ACKn = '1' then -- Rising edge.
|
|
HOLD <= '1';
|
|
elsif MC_CLR_CMD = '1' then -- Clear done.
|
|
HOLD <= '0';
|
|
end if;
|
|
end if;
|
|
end process P_HOLD;
|
|
|
|
P_DONE: process(RESETn, CLK)
|
|
begin
|
|
if RESETn = '0' then
|
|
DONE_REG <= '0';
|
|
elsif CLK = '1' and CLK' event then
|
|
if (PREV_CSn = '0' and ACSI_CSn = '0') or (PREV_ACKn = '0' and ACSI_ACKn = '0') then
|
|
DONE_REG <= '1';
|
|
elsif MC_CLR_CMD = '1' then -- Clear done.
|
|
DONE_REG <= '0';
|
|
elsif D0_REG = '0' and MC_DO = '1' then -- Positive MC_DO edge.
|
|
DONE_REG <= '0';
|
|
elsif D0_REG = '1' and MC_DO = '0' then -- Negative MC_DO edge.
|
|
DONE_REG <= '0';
|
|
end if;
|
|
end if;
|
|
end process P_DONE;
|
|
|
|
P_DO_REG: process(RESETn, CLK)
|
|
begin
|
|
if RESETn = '0' then
|
|
D0_REG <= '0';
|
|
elsif CLK = '1' and CLK' event then
|
|
if D0_REG = '0' and MC_DO = '1' then -- Positive MC_DO edge.
|
|
D0_REG <= MC_DO;
|
|
elsif D0_REG = '1' and MC_DO = '0' then -- Negative MC_DO edge.
|
|
D0_REG <= MC_DO;
|
|
end if;
|
|
end if;
|
|
end process P_DO_REG;
|
|
|
|
P_GOT_CMD: process(RESETn, CLK)
|
|
begin
|
|
if RESETn = '0' then
|
|
GOT_CMD_REG <= '0';
|
|
elsif CLK = '1' and CLK' event then
|
|
if PREV_CSn = '0' and ACSI_CSn = '0' and ACSI_CSn = '0' and ACSI_A1 = '0' then
|
|
GOT_CMD_REG <= '1'; -- If command was received.
|
|
elsif PREV_ACKn = '0' and ACSI_ACKn = '0' and ACSI_CSn = '0' and ACSI_A1 = '0' then
|
|
GOT_CMD_REG <= '1'; -- If command was received.
|
|
elsif MC_CLR_CMD = '1' then -- Clear done.
|
|
GOT_CMD_REG <= '0';
|
|
end if;
|
|
end if;
|
|
end process P_GOT_CMD;
|
|
end architecture BEHAVIOR; |