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