[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[oc] ATA core
Hi Guys,
The ATA-3 core is not ready yet, that's why it is not posted in the
repository. But because a lot of people keep asking for the design I post
it via the mailing-list (attached to this email).
Disclaimer: This core is not finished. It has not been tested, is not fully
working and is not meant to be posted in the CVS repository. Changes can
and will be made to it.
Please sent any suggestions or modifications back to me.
Richard
--
-- Project: AT Atachement interface
-- ATA-3 rev7B
-- Author: Richard Herveille
-- Version: 0.1.0 Alpha version
-- Date: 06-01-2000
--
-- Host signals:
-- Reset
-- DIOR- read strobe. The falling edge enables data from device onto DD. The rising edge latches data at the host.
-- DIOW- write strobe. The rising edge latches data from DD into the device.
-- DMACK- DMA acknowledge
-- DA(2:0) 3bit binary coded adress
-- CS0- select command block registers
-- CS1- select control block registers
-- registers:
-- control register:
--
--
--
-- To Do:
-- 1) generate timing register
-- 2) generate whishbone interface
-- 3) design DMA transfer controller
-- 4) design select statemachine
-- 5) design ATA-host IOs
-- 6) design UDMA transfer controller
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
entity atahost is
port(
clk : in std_logic; -- master clock in
ena : in std_logic; -- clock enable input
nReset : in std_logic;
ctrl_sel : in std_logic; -- ATA controller select
ide_sel : in std_logic; -- IDE devices (ide-port) select
A : in unsigned(7 downto 0);
Din : in std_logic_vector(15 downto 0);
Dout : out std_logic_vector(15 downto 0);
RdStrb, -- Read strobe
WrStrb : in std_logic; -- Write strobe
-- ATA signals
RESETn : out std_logic;
DD : inout std_logic_vector(15 downto 0);
DA : out std_logic_vector(2 downto 0);
CS0n : out std_logic;
CS1n : out std_logic;
DMARQ : in std_logic;
DMACKn : out std_logic;
DIORn : out std_logic;
DIOWn : out std_logic;
IORDY : in std_logic;
INTRQ : in std_logic
);
end entity atahost;
architecture structural of atahost is
begin
-- select state machine
-------------------------------------
-- when idle
-- if PIO transfer then nxt_state => PIO
-- elsif DMA transfer then nxt_state => DMA
-- elsif UDMA transfer then nxt_state => UDMA
--
-- when PIO
-- if pio_done = '1' then nxt_state => idle
--
-- when DMA
-- if dma_done = '1' then nxt_state => idle
--
-- when UDMA
-- if udma_done = '1' then nxt_state => idle
-- generate timing registers
end architecture structural;
--
-- Timing PIO mode transfers
----------------------------------------------
-- T0: cycle time
-- T1: address valid to DIOR-/DIOW-
-- T2: DIOR-/DIOW- pulse width
-- T2i: DIOR-/DIOW- recovery time
-- T3: DIOW- data setup
-- T4: DIOW- data hold
-- T5: DIOR- data setup
-- T6: DIOR- data hold
-- T9: address hold from DIOR-/DIOW- negated
-- Trd: Read data valid to IORDY asserted
-- Ta: IORDY setup time
-- Tb: IORDY pulse width
--
-- Transfer sequence
----------------------------------
-- 1) set address (DA, CS0-, CS1-)
-- 2) wait for T1
-- 3) assert DIOR-/DIOW-
-- when write action present Data (timing spec. T3 always honored)
-- 4) wait for T2
-- 5) check IORDY
-- when not IORDY goto 5
-- when IORDY negate DIOW-/DIOR-, latch data (if read action)
-- 6) wait end_of_cycle_time. This is T2i or T9 or (T0-T1-T2) whichever takes the longest
-- 7) start new cycle
--
-- Timing spec T4 is honored, since data is valid until at least T1 which is greater than T4
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
entity PIOmode is
generic (TWIDTH : natural := 8); -- counter width
port(
clk : in std_logic; -- master clock
ena : in std_logic; -- clock enable
nReset : in std_logic; --asynchronous active low reset
-- timing/control register settings
IORDY_en : in std_logic; -- use IORDY (or not)
T1 : in unsigned (3 downto 0); -- T1 time
T2 : in unsigned (8 downto 0); -- T2 time
Teoc : in unsigned (7 downto 0); -- end of cycle time
-- control signals
selPIO : in std_logic; -- PIO controller selected (strobe signal)
A : in unsigned(3 downto 0); -- host bus address
rd,
wr : in std_logic;
-- return signals
latchD : out std_logic; -- latch data strobe
done : out std_logic; -- finished cycle
-- ATA signals
CS0n ,
CS1n : out std_logic;
DA : out unsigned(2 downto 0);
DIORn,
DIOWn : buffer std_logic;
IORDY : in std_logic
);
end entity PIOmode;
architecture structural of PIOmode is
component ro_cnt is
generic(SIZE : natural := 8);
port(
clk : in std_logic; -- master clock
nReset : in std_logic := '1'; -- asynchronous active low reset
cnt_en : in std_logic := '1'; -- count enable
go : in std_logic; -- load counter and start sequence
done : out std_logic; -- done counting
D : in unsigned(SIZE -1 downto 0); -- load counter value
Q : out unsigned(SIZE -1 downto 0); -- current counter value
ID : in unsigned(SIZE -1 downto 0) := (others => '0') -- initial data after reset
);
end component ro_cnt;
-- PIO mode 0 settings (@100MHz clock)
constant T1_m0 : unsigned(3 downto 0) := conv_unsigned(6, 4); -- 70ns
constant T2_m0 : unsigned(8 downto 0) := conv_unsigned(289, 9); -- 290ns
constant Teoc_m0 : unsigned(7 downto 0) := conv_unsigned(239, 8); -- 240ns ==> T0 - T1 - T2 = 600 - 70 - 290 = 240
signal T1done, T2done, IORDY_done, rel_DIOR_DIOW : std_logic;
begin
-- 1) set address
T1proc : process(clk)
begin
if (clk'event and clk = '1') then
if (selPIO = '1') then
DA <= A(2 downto 0);
CS0n <= not A(3);
CS1n <= A(3);
end if;
end if;
end process T1proc;
-- 2) hookup T1 counter
t1_cnt : ro_cnt generic map (SIZE => 4)
port map (clk => clk, nReset => nReset, cnt_en => ena, go => selPIO, D => T1, ID => T1_m0, done => T1done);
-- 3) set (and reset) DIOR-/DIOW-
T2proc: process(clk, nReset)
begin
if (nReset = '0') then
DIORn <= '1';
DIOWn <= '1';
elsif (clk'event and clk = '1') then
DIORn <= not ( (rd and T1done) or (not DIORn and rel_DIOR_DIOW) );
DIOWn <= not ( (wr and T1done) or (not DIOWn and rel_DIOR_DIOW) );
end if;
end process T2proc;
-- 4) hookup T2 counter
t2_cnt : ro_cnt generic map (SIZE => 9)
port map (clk => clk, nReset => nReset, cnt_en => ena, go => T1done, D => T2, ID => T2_m0, done => T2done);
-- 5) check IORDY (if used), generate release_DIOR-/DIOW- signal (ie negate DIOR-/DIOW-)
IORDYproc: process(clk)
begin
if (clk'event and clk = '1') then
IORDY_done <= T2done and (IORDY or not IORDY_en);
rel_DIOR_DIOW <= IORDY_done; -- release DIOR- after data has been latched
end if;
end process IORDYproc;
latchD <= IORDY_done;
-- 6) hookup end_of_cycle counter
eoc_cnt : ro_cnt generic map (SIZE => 9)
port map (clk => clk, nReset => nReset, cnt_en => ena, go => IORDY_done, D => Teoc, ID => Teoc_m0, done => done);
end architecture structural;
--
-- run-once down counter, counts D+1 cycles before generating 'DONE'
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
entity ro_cnt is
generic(SIZE : natural := 8);
port(
clk : in std_logic; -- master clock
nReset : in std_logic := '1'; -- asynchronous active low reset
cnt_en : in std_logic := '1'; -- count enable
go : in std_logic; -- load counter and start sequence
done : out std_logic; -- done counting
D : in unsigned(SIZE -1 downto 0); -- load counter value
Q : out unsigned(SIZE -1 downto 0); -- current counter value
ID : in unsigned(SIZE -1 downto 0) := (others => '0') -- initial data after reset
);
end entity ro_cnt;
architecture structural of ro_cnt is
component count is
generic(
SYNCH_RCO : string := "NO";
SIZE : natural := 8
);
port(
clk : in std_logic; -- master clock
nReset : in std_logic := '1'; -- asynchronous active low reset
cnt_en : in std_logic := '1'; -- count enable
ud : in std_logic := '0'; -- up / not down
nld : in std_logic := '1'; -- synchronous active low load
D : in unsigned(SIZE -1 downto 0); -- load counter value
Q : out unsigned(SIZE -1 downto 0); -- current counter value
resD : in unsigned(SIZE -1 downto 0) := (others => '0'); -- initial data after reset
rci : in std_logic := '1'; -- carry input
rco : out std_logic -- carry output
);
end component count;
signal rci, rco, nld : std_logic;
begin
gen_ctrl: process(clk, nReset)
begin
if (nReset = '0') then
nld <= '1';
rci <= '0';
elsif (clk'event and clk = '1') then
nld <= not (go and not rci);
rci <= (go or rci) and not rco;
end if;
end process;
-- hookup counter
cnt : count generic map (SIZE => SIZE, SYNCH_RCO => "YES")
port map (clk => clk, nReset => nReset, cnt_en => cnt_en, nld => nld, D => D, Q => Q, resD => ID, rci => rci, rco => rco);
done <= rco;
end architecture structural;
--
-- general purpose counter
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
entity count is
generic(
SYNCH_RCO : string := "NO";
SIZE : natural := 8
);
port(
clk : in std_logic; -- master clock
nReset : in std_logic := '1'; -- asynchronous active low reset
cnt_en : in std_logic := '1'; -- count enable
ud : in std_logic := '0'; -- up / not down
nld : in std_logic := '1'; -- synchronous active low load
D : in unsigned(SIZE -1 downto 0); -- load counter value
Q : out unsigned(SIZE -1 downto 0); -- current counter value
resD : in unsigned(SIZE -1 downto 0) := (others => '0'); -- initial data after reset
rci : in std_logic := '1'; -- carry input
rco : out std_logic -- carry output
);
end entity count;
architecture structural of count is
signal Qi : unsigned(SIZE -1 downto 0);
signal val : unsigned(SIZE downto 0);
begin
nval: process(rci, ud, Qi)
begin
if (ud = '1') then
val <= Qi + rci;
else
val <= Qi - rci;
end if;
end process nval;
regs: process(clk, nReset)
begin
if (nReset = '0') then
Qi <= resD;
elsif (clk'event and clk = '1') then
if (nld = '0') then
Qi <= D;
elsif (cnt_en = '1') then
Qi <= val(SIZE -1 downto 0);
end if;
end if;
end process regs;
-- assign outputs
Q <= Qi;
gen_rco:
if (SYNCH_RCO = "NO") generate
rco <= val(SIZE);
end generate;
gen_srco:
if (SYNCH_RCO = "YES") generate
process(clk, nReset)
begin
if (nReset = '0') then
rco <= '0';
elsif (clk'event and clk = '1') then
if (cnt_en = '1') then
rco <= val(SIZE);
end if;
end if;
end process;
end generate;
end architecture structural;