[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;