--
-- Intel 8237A DMA controller
-- Roman Lysecky

-- 08/20/98
-- Version 1.0
-- Notes: The port names follow the 8237A naming except for EOP.
--	  Due to synthesis problems, EOP has been named eopp.
--

--*************************************************************************--

library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_ARITH.all;

--*************************************************************************--
--
-- Intel 8237A DMA Controller
--
-- This is a synthesizable VHDL behavioral description of the 8237A.  The
-- following is a list of the current functionality:
--
-- 8/18/98 - Priority Encoding ( Fixed and Rotating )
--         - Active HIGH/LOW setting for DACK and DREQ
--	   - Command Register programmability
--	   - Reset and Master Clear functional
--
-- 8/20/98 - Single Transfer Verify Mode
--
-- 8/25/98 - Single Transfer Read and Write Modes
--         - Programmable for all option except word and address registers
--	   - Fixed problem with status register
--         - Changed mask register for easier programming
--	   - Fixed problem with dack(acknowledge was for only one cycle) 
--
-- 8/26/98 - Testbench greatly improved.  Asserts will cause severity errors
--           whenever an incorrect value is seen
--*************************************************************************--


entity DMA_IN is
	port(	clk	: in	STD_LOGIC;
		cs	: in	STD_LOGIC;
		reset	: in	STD_LOGIC;
		ready	: in	STD_LOGIC;
		hlda	: in	STD_LOGIC;
		dreq	: in	UNSIGNED(3 downto 0);
		db	: inout UNSIGNED(7 downto 0);
		ior	: inout STD_LOGIC;
		iow	: inout STD_LOGIC;
		eopp	: inout STD_LOGIC;
		a3_0	: inout UNSIGNED(3 downto 0);
		a7_4	: out	UNSIGNED(3 downto 0);
		hrq	: out	STD_LOGIC;
		dack	: out	UNSIGNED(3 downto 0);
		aen	: out	STD_LOGIC;
		adstb	: out	STD_LOGIC;
		memr	: out	STD_LOGIC;
		memw	: out	STD_LOGIC);
end DMA_IN;

--*************************************************************************--

architecture BHV_DMA of DMA_IN is

	--
	-- type declarations
	--
	subtype INT2            is INTEGER range 0 to 3;
	subtype REG_16          is UNSIGNED(15 downto 0);
	subtype REG_8           is UNSIGNED(7 downto 0);
	subtype REG_6           is UNSIGNED(5 downto 0);
	subtype REG_4           is UNSIGNED(3 downto 0);
	type    STATE_TYPE      is (IDLE, S0, SS1, SSB2, SS2, SS3, SS4);

	--
	-- constant declarations
	--
	constant Z_8 : UNSIGNED(7 downto 0) := "ZZZZZZZZ";
	constant Z_4 : UNSIGNED(3 downto 0) := "ZZZZ";
	constant C0_16 : UNSIGNED(15 downto 0) := "0000000000000000";	
	constant C0_8 : UNSIGNED(7 downto 0) := "00000000";	
	constant CFF_8 : UNSIGNED(7 downto 0) := "11111111";	
	constant C0_6 : UNSIGNED(5 downto 0) := "000000";	
	constant C0_4 : UNSIGNED(3 downto 0) := "0000";	
	constant C1_4 : UNSIGNED(3 downto 0) := "1111";
	constant BT : UNSIGNED(1 downto 0) := "10";	

	--
	-- register declarations
	--
	signal curr_addr : REG_16;
	signal curr_word : REG_16;
	signal base_addr : REG_16;
	signal base_word : REG_16;
	signal command   : REG_8;
	signal mode      : REG_6;
	signal request   : REG_4;
	signal mask      : REG_4;
	signal status    : REG_8;
	signal temp	 : REG_8;
	
	--
	-- signal declarations
	--
	signal drequest	: UNSIGNED(3 downto 0);
	signal ff	: STD_LOGIC;
	signal mast_clr : STD_LOGIC;
	signal state    : STATE_TYPE;
	signal channel	: INT2;
	signal adstb_needed : STD_LOGIC;
	
begin
	drequest(0) <= ((command(6) xor dreq(0)) and not mask(0)) or request(0);
	drequest(1) <= ((command(6) xor dreq(1)) and not mask(1)) or request(1);
	drequest(2) <= ((command(6) xor dreq(2)) and not mask(2)) or request(2);
	drequest(3) <= ((command(6) xor dreq(3)) and not mask(3)) or request(3);

	process(clk, reset, mast_clr, drequest)
	begin
		if ( reset = '1' ) then

			--
			-- steady state
			--
			state <= IDLE;
			db    <= Z_8;
			ior   <= 'Z';
			iow   <= 'Z';
			eopp  <= '1';
			a3_0  <= Z_4;
			a7_4  <= Z_4;
			hrq   <= '0';
			dack  <= "1111";
			aen   <= '0';
			adstb <= '0';
			memr  <= '0';
			memw  <= '0';

			--
			-- reset device
			--
			curr_addr <= C0_16;
			curr_word <= C0_16;
			base_addr <= C0_16;
			base_word <= C0_16;
			command   <= C0_8;
			mode      <= C0_6;
			request   <= C0_4;
			mask      <= C0_4;
			status    <= drequest & C0_4;
			temp	  <= C0_8;
			ff	  <= '0';
			mast_clr  <= '0';
			channel   <= 0;
			adstb_needed <= '0';

		elsif ( mast_clr = '1' ) then

			--
			-- steady state
			--
			state <= IDLE;
			db    <= Z_8;
			ior   <= 'Z';
			iow   <= 'Z';
			eopp   <= 'Z';
			a3_0  <= Z_4;
			a7_4  <= Z_4;
			hrq   <= '0';
			dack  <= C1_4;
			aen   <= '0';
			adstb <= '0';
			memr  <= '0';
			memw  <= '0';

			--
			-- reset device
			--
			command   <= C0_8;
			request   <= C0_4;
			mask      <= C0_4;
			status    <= drequest & C0_4;
			temp	  <= C0_8;
			ff	  <= '0';
			mast_clr  <= '0';
			channel   <= 0;
			adstb_needed <= '0';

		elsif ( clk'event and clk = '1' ) then

			--
			-- steady state
			--
			state <= IDLE;
			db    <= Z_8;
			ior   <= 'Z';
			iow   <= 'Z';
			eopp  <= 'Z';
			a3_0  <= Z_4;
			a7_4  <= Z_4;
			hrq   <= '0';
			adstb_needed <= '0';

			if ( command(7) = '1' ) then
				dack <= C0_4;
			elsif( command(7) = '0' ) then
				dack <= C1_4;
			else
				dack <= C1_4;
			end if;

			aen   <= '0';
			adstb <= '0';
			memr  <= '0';
			memw  <= '0';
			status(7 downto 4) <= drequest;

			case ( state ) is

				when IDLE =>
					state <= IDLE;
					if ( hlda = '0' and drequest /= C0_4 ) then
						state <= S0;
						hrq <= '1';
					elsif ( hlda = '0' and cs = '0' ) then

						if( ior = '1' and iow = '0' ) then
							case( a3_0 ) is
							when "1000" =>
								command <= db;

							when "1011" =>
								if ( db(3 downto 2) /= 3 ) then
									mode <= db(7 downto 2);
								end if;

							when "1101" =>
								mast_clr <= '1';

							when "0000" =>
								if ( ff = '0' ) then
									curr_addr(7 downto 0) <= db;
									base_addr(7 downto 0) <= db;
									ff <= '1';
								else
									curr_addr(15 downto 8) <= db;
									base_addr(15 downto 8) <= db;
									ff <= '0';
								end if;

							when "0001" =>
								if ( ff = '0' ) then
									curr_word(7 downto 0) <= db;
									base_word(7 downto 0) <= db;
									ff <= '1';
								else
									curr_word(15 downto 8) <= db;
									base_word(15 downto 8) <= db;
									ff <= '0';
								end if;

							when others =>
								null;
							end case;
						elsif( ior = '0' and iow = '1' ) then
							case( a3_0 ) is
							when "0000" =>
								if ( ff = '0' ) then
									db <= curr_addr(7 downto 0);
									ff <= '1';
								else
									db <= curr_addr(15 downto 8);
									ff <= '0';
								end if;
								
							when "0001" =>
								if ( ff = '0' ) then
									db <= curr_word(7 downto 0);
									ff <= '1';
								else
									db <= curr_word(15 downto 8);
									ff <= '0';
								end if;

							when others =>
								null;
							end case;
						end if;
					end if;

				when S0 =>
					state <= S0;
					hrq <= '1';
					if ( drequest(channel) = '0' ) then
						state <= IDLE;
					elsif ( hlda  = '1' ) then
						state <= SS1;
					end if;

					if ( hlda = '0' and cs = '0' ) then
						state <= S0;
						if( ior = '1' and iow = '0' ) then 
							case( a3_0 ) is
							when "1000" =>
								command <= db;

							when "1011" =>
								if ( db(3 downto 2) /= 3 ) then
									mode <= db(7 downto 2);
								end if;

							when "1101" =>
								mast_clr <= '1';

							when others =>
								null;
							end case;
						end if;
					end if;

				when SS1 =>
					state <= SS2;
					hrq <= '1';
					if ( drequest(channel) = '0' ) then
						state <= IDLE;
					else
						aen <= '1';
					end if;
					
				when SS2 =>
					state <= SS3;
					hrq <= '1';
					if ( drequest(channel) = '0' ) then
						state <= IDLE;
					else
						aen <= '1';
						adstb <= '1';
						db <= curr_addr(15 downto 8);
						a7_4 <= curr_addr(7 downto 4);
						a3_0 <= curr_addr(3 downto 0);
						dack(channel) <= command(7);
						case ( mode(1 downto 0) ) is
							when "00" =>
								null;
							when "01" =>
								ior  <= '1';
								memw <= '1';
							when "10" =>
								iow  <= '1';
								memr <= '1';
							when others =>
								null;
						end case;
					end if;

				when SSB2 =>
					state <= SS3;
					hrq <= '1';
					aen <= '1';
					if( adstb_needed = '1' ) then
						adstb <= '1';
						db <= curr_addr(15 downto 8);
					end if;
					a7_4 <= curr_addr(7 downto 4);
					a3_0 <= curr_addr(3 downto 0);
					dack(channel) <= command(7);
					case ( mode(1 downto 0) ) is
						when "00" =>
							null;
						when "01" =>
							ior  <= '1';
							memw <= '1';
						when "10" =>
							iow  <= '1';
							memr <= '1';
						when others =>
							null;
					end case;

				when SS3 =>
--					state <= SS4;
					state <= IDLE;
					hrq <= '1';
					aen <= '1';
					a7_4 <= curr_addr(7 downto 4);
					a3_0 <= curr_addr(3 downto 0);
					dack(channel) <= command(7);
					case ( mode(1 downto 0) ) is
						when "00" =>
							null;
						when "01" =>
							ior  <= '0';
							memw <= '0';
						when "10" =>
							iow  <= '0';
							memr <= '0';
						when others =>
							null;
					end case;

--				when SS4 =>
--					state <= IDLE;
--					hrq <= '1';
--					aen <= '1';
--					a7_4 <= curr_addr(7 downto 4);
--					a3_0 <= curr_addr(3 downto 0);
--					dack(channel) <= command(7);
--					case ( mode(1 downto 0) ) is
--						when "00" =>
--							null;
--						when "01" =>
--							ior  <= '0';
--							memw <= '0';
--						when "10" =>
--							iow  <= '0';
--							memr <= '0';
--						when others =>
--							null;
--					end case;

					if( curr_word = C0_16 ) then
						status(channel) <= '1';
						if( mode(2) = '1' ) then
							curr_word <= base_word;
							curr_addr <= base_addr;
						elsif( mode(2) = '0' ) then
							curr_word <= curr_word - 1;
							if( mode(3) = '0' ) then
								curr_addr <= curr_addr + 1;
							elsif( mode(3) = '1' ) then
								curr_addr <= curr_addr - 1;
							end if;
						end if;
					else
						curr_word <= curr_word - 1;
						if( mode(3) = '0' ) then
							if( curr_addr(7 downto 0) = CFF_8) then
								adstb_needed <= '1';
							end if;
							curr_addr <= curr_addr + 1;
						elsif( mode(3) = '1' ) then
							if( curr_addr(7 downto 0) = C0_8) then
								adstb_needed <= '1';
							end if;
							curr_addr <= curr_addr - 1;
						end if;

						if( mode(5 downto 4) = BT ) then
							state <= SSB2;
						else
							state <= IDLE;
						end if;
					end if;

				when others =>
					null;
			end case;
		end if;
	end process;
end BHV_DMA;

--*************************************************************************--

library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_ARITH.all;

--*************************************************************************--

entity DMA is
	generic(COMMAND_ADDR : INTEGER := 400;
		MODE_ADDR : INTEGER := 401;
		BASE_WORD_ADDR : INTEGER := 402;
		BASE_ADDR_ADDR : INTEGER := 403);
	port( clk  : in STD_LOGIC;
	      rst  : in STD_LOGIC;
	      data : in UNSIGNED(31 downto 0); 
	      addr : inout UNSIGNED(22 downto 0);
	      rd   : inout STD_LOGIC;
              wr   : inout STD_LOGIC;
	      dreq : in STD_LOGIC;
	      dack : out STD_LOGIC;
	      hrq  : out STD_LOGIC;
	      hlda : in STD_LOGIC;
	      ior  : out STD_LOGIC );
end DMA;

--*************************************************************************--

architecture DMA_BHV of DMA is

	--
	-- type declarations
	--
	type STATE_TYPE is ( IDLE_S, MONITOR_S );

	--
	-- constant declarations
	--
	constant CZ_32 : UNSIGNED(31 downto 0) := 
		"ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ";

	constant CZ_23 : UNSIGNED(22 downto 0) :=
		"ZZZZZZZZZZZZZZZZZZZZZZZ";

	constant C0_23 : UNSIGNED(22 downto 0) :=
		"00000000000000000000000";

	constant CZ_8 : UNSIGNED(7  downto 0) := "ZZZZZZZZ";
	constant CZ_4 : UNSIGNED(3  downto 0) := "ZZZZ";
	constant C0_8 : UNSIGNED(7  downto 0) := "00000000";	
	constant C0_7 : UNSIGNED(6  downto 0) := "0000000";	
	constant C0_4 : UNSIGNED(3  downto 0) := "0000";	
	constant C0_3 : UNSIGNED(2  downto 0) := "000";	

	--
	-- component declartions
	--
	component DMA_IN
		port(	clk	: in	STD_LOGIC;
			cs	: in	STD_LOGIC;
			reset	: in	STD_LOGIC;
			ready	: in	STD_LOGIC;
			hlda	: in	STD_LOGIC;
			dreq	: in	UNSIGNED(3 downto 0);
			db	: inout	UNSIGNED(7 downto 0);
			ior	: inout	STD_LOGIC;
			iow	: inout	STD_LOGIC;
			eopp	: inout	STD_LOGIC;
			a3_0	: inout	UNSIGNED(3 downto 0);
			a7_4	: out	UNSIGNED(3 downto 0);
			hrq	: out	STD_LOGIC;
			dack	: out	UNSIGNED(3 downto 0);
			aen	: out	STD_LOGIC;
			adstb	: out	STD_LOGIC;
			memr	: out	STD_LOGIC;
			memw	: out	STD_LOGIC );
	end component;

	--
	-- signal declartions
	--
	signal state : STATE_TYPE;
	signal cs, grab, done : STD_LOGIC;
	signal addr3_0, addr7_4, dreq_in, dack_in : UNSIGNED(3 downto 0);
	signal addr15_8 : UNSIGNED(7 downto 0);
	signal db : UNSIGNED(7 downto 0);
	signal hrq_in, memr, memw, aen, adstb, ior_in, iow_in, ready, eopp : STD_LOGIC;

begin
	--
	-- concurrent assignments
	--
	hrq <= hrq_in;
	ior <= ior_in;
	dreq_in(0) <= dreq;
	dreq_in(3 downto 1) <= C0_3;
	dack <= dack_in(0);

	--
	-- component instantiations
	--
	DMA_IN_1 : DMA_IN port map( clk, cs, rst, ready, hlda, dreq_in, db, 
				    ior_in, iow_in, eopp, addr3_0, addr7_4,
                                    hrq_in, dack_in, aen, adstb, memr, memw );

	--
	-- processes
	--
	process(clk, rst, hlda, hrq_in, grab, done)
	begin
	
		if ( rst = '1' ) then

			--
			-- steady state
			--
			state <= IDLE_S;
			addr <= CZ_23;
			rd <= 'Z';
			wr <= 'Z';
			cs <= '1';
			ior_in <= 'Z';
			iow_in <= 'Z';			
			addr3_0 <= CZ_4;
			addr15_8 <= C0_8;
			db <= CZ_8;
			eopp <= 'Z';
			ready <= '0';
			grab <= '1';
			done <= '0';	

		elsif( hlda = '1' and grab = '1' ) then
			
			grab <= '0';
			addr <= CZ_23;
			rd <= '0';
			wr <= '0';
			cs <= '1';
			ior_in <= 'Z';
			iow_in <= 'Z';			
			addr3_0 <= CZ_4;
			addr15_8 <= C0_8;
			db <= CZ_8;
			eopp <= 'Z';
			ready <= '0';
		
		elsif( hrq_in = '0' and done = '1' ) then
			
			done <= '0';
			addr <= CZ_23;
			rd <= 'Z';
			wr <= 'Z';
			cs <= '1';
			ior_in <= 'Z';
			iow_in <= 'Z';			
			addr3_0 <= CZ_4;
			addr15_8 <= C0_8;
			db <= CZ_8;
			eopp <= 'Z';
			ready <= '0';

		elsif ( clk'event and clk = '1' ) then

			--
			-- steady state
			--
			addr <= CZ_23;
			rd <= 'Z';
			wr <= 'Z';

			if( hlda = '1' and hrq_in = '1' ) then
				rd <= '0';
				wr <= '0';
			end if;

			cs <= '1';
			ior_in <= 'Z';
			iow_in <= 'Z';			
			addr3_0 <= CZ_4;
			db <= CZ_8;
			eopp <= 'Z';
			ready <= '0';

			case( state ) is
			when IDLE_S =>
				state <= IDLE_S;
				if( wr = '1' and hlda = '0' ) then
					if ( addr = conv_integer(BASE_WORD_ADDR) ) then
						cs <= '0';
						ior_in <= '1';
						iow_in <= '0';
						addr3_0 <= "0001";
						db <= data(7 downto 0);
					elsif( addr = conv_integer(BASE_ADDR_ADDR) ) then 
						cs <= '0';
						ior_in <= '1';
						iow_in <= '0';
						addr3_0 <= "0000";
						db <= data(7 downto 0);
					elsif( addr = conv_integer(MODE_ADDR) ) then
						cs <= '0';
						ior_in <= '1';
						iow_in <= '0';
						addr3_0 <= "1011";
						db <= data(7 downto 0);
					elsif( addr = conv_integer(COMMAND_ADDR) ) then
						cs <= '0';
						ior_in <= '1';
						iow_in <= '0';
						addr3_0 <= "1000";
						db <= data(7 downto 0);
					end if;
				end if;

				if( hlda = '1' ) then
					state <= MONITOR_S;
				end if; 

			when MONITOR_S =>

				state <= MONITOR_S;
				if( hrq_in = '0' ) then
					grab <= '1';
					state <= IDLE_S;
				else 
					done <= '1';
					if( memw = '1' ) then
						wr <= '1';
						if( adstb = '1' ) then
							addr15_8 <= db;
							addr <= C0_7 & db & addr7_4 & addr3_0;
						else
							addr <= C0_7 & addr15_8 & addr7_4 & addr3_0;
						end if;
					end if;
				end if;
					
			when others =>
				null;
			end case;
		end if;
	end process;
end DMA_BHV;

--*************************************************************************--
-- end of file --
<div align="center"><br /><script type="text/javascript"><!--
google_ad_client = "pub-7293844627074885";
//468x60, Created at 07. 11. 25
google_ad_slot = "8619794253";
google_ad_width = 468;
google_ad_height = 60;
//--></script>
<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script><br />&nbsp;</div>