www.pudn.com > noc.rar > if_main.vhd, change:2003-10-31,size:16588b


------------------------------------------------------------------ 
--								-- 
--	If_main.vhd - Main Interface Control			-- 
--	Paul Dunn - Nallatech Ltd Copyright 1999		-- 
--	Description - 						-- 
--	This process contains the main state machine for	-- 
--	controlling the interface between the Virtex and the	-- 
--	Spartan on the Ballynuey.				-- 
--	This process also contains the main CSR.  This CSR	-- 
--	controls the DMA engine (enables and determines 	-- 
--	direction).						-- 
--								-- 
------------------------------------------------------------------ 
 
library IEEE; 
use IEEE.std_logic_1164.all; 
 
entity if_main is 
    	generic (-- Number of memory blocks in memory map in bit size. 
    		NUM_BLOCKSg : integer range 1 to 29;-- := 4; 
    		-- Block size. 
    		BLOCK_SIZEg : integer range 1 to 29;--:= 8; 
    		-- Number of registers. 
    		NUM_REGSg : integer range 1 to 29-- := 4 
    		); 
    	port (	-- Spartan - Virtex clock. 
        	CLK: in STD_LOGIC; 
        	-- Global reset 
        	RST: in STD_LOGIC; 
        	-- Synchronous reset. 
        	SYNC_RST: in STD_LOGIC; 
        	-- Indicates if Spartan can receive data. 
        	BUSY: in STD_LOGIC; 
        	-- Indicates if Spartan has data to send. 
        	EMPTY: in STD_LOGIC; 
        	-- Address Strobe / Data Strobe. 
        	AS_DSl: in STD_LOGIC; 
        	-- DMA engine is writing to Spartan. 
        	DMA_IN_FULL: in STD_LOGIC; 
        	DMA_IN_EMPTY: in STD_LOGIC; 
        	DMA_OUT_FULL: in STD_LOGIC; 
        	-- DMA engine is reading from Spartan. 
        	DMA_OUT_EMPTY: in STD_LOGIC; 
        	-- Terminal count of DMA counter. 
        	TERM_CNT: in STD_LOGIC; 
        	-- DMA count output. 
        	COUNT_OUT: in STD_LOGIC_VECTOR (31 downto 0); 
        	-- DMA output. 
        	DMA_OUT: in STD_LOGIC_VECTOR (31 downto 0); 
        	-- Read Enable / Write Enable. 
       	 	RENl_WENl: out STD_LOGIC; 
        	-- Read / Write. 
        	RDl_WR: out STD_LOGIC; 
        	-- Load DMA count. 
        	WR_COUNT: out STD_LOGIC; 
        	-- Enable DMA engine. 
        	DMA_ENABLE: out STD_LOGIC; 
        	-- DMA direction. 
        	DMA_DIRECTION: out STD_LOGIC; 
        	-- DMA select. 
        	DMA_SEL: out STD_LOGIC_VECTOR (3 downto 0);	 
			-- DMA reset. 
			DMA_RST: out STD_LOGIC; 
        	-- Active address. 
        	ADDRESS: out STD_LOGIC_VECTOR (30 downto 0); 
       	 	-- Write to active register. 
        	WR_STROBE: out STD_LOGIC; 
        	-- Read from active register. 
        	RD_STROBE: out STD_LOGIC; 
        	-- Write DMA. 
        	WR_DMA: out STD_LOGIC; 
        	-- Read DMA. 
        	RD_DMA: out STD_LOGIC; 
        	-- DMA count input. 
        	COUNT_IN: out STD_LOGIC_VECTOR (31 downto 0); 
        	-- DMA input. 
        	DMA_IN: out STD_LOGIC_VECTOR (31 downto 0); 
        	-- Data to and from Spartan. 
        	ADIO: inout STD_LOGIC_VECTOR (31 downto 0); 
        	-- Data to and from user's design. 
        	DATA: inout STD_LOGIC_VECTOR (31 downto 0) 
    		); 
end if_main; 
 
architecture if_main_arch of if_main is 
 
-- Main control states of interface. 
type IFACE_STATES is (RST_STATE, IDLE, WAIT_DATA, DATA_READ, ADDR_DEC, RD_REG, WR_REG, WAIT_TO_DMARD, WAIT_DATACHK, WAIT_ENDTRANS,  
			DMA_READ, WAIT_ADDRDEC, DMA_WRITE, WAIT_DMA_RD, WAIT_ADDRCHK, WAIT_TO_DMAWR, WAIT_END_DMARD); 
signal SM_STATE : IFACE_STATES; 
 
-- Delayed versions of busy and empty. 
signal EMPTYd1 : std_logic; 
signal BUSYd1 : std_logic; 
 
-- Data input register. 
signal DATAIN : std_logic_vector (31 downto 0); 
-- Address strobe / Data strobe. 
signal AS_DSl_IN : std_logic; 
-- Address in. 
signal ADDRESSi : std_logic_vector (31 downto 0); 
 
-- Data valid required to determine valid data when in DMA read mode. 
signal DVALID : std_logic; 
signal DVALIDd1 : std_logic; 
signal DVALIDd2 : std_logic; 
-- Write data into input register. 
signal DATAIN_WR : std_logic; 
-- Write in address. 
signal ADDRESS_WR : std_logic; 
-- Memory block 0 is being addressed. 
signal MEM_BLOCK0_EN : std_logic; 
 
-- Internal read and write strobe signals. 
signal READ_STROBEi : std_logic; 
signal WRITE_STROBEi : std_logic; 
signal WRITE_STROBEid1 : std_logic; 
 
-- Read DMA count. 
signal RD_COUNTi : std_logic; 
-- Read DMA. 
signal RD_DMAi : std_logic; 
signal RD_DMAii : std_logic; 
 
signal WR_DMAi, WR_DMAid1 : std_logic; 
 
-- Write to Control/Status register. 
signal WR_CSR : std_logic; 
-- Read from control/status register. 
signal RD_CSR : std_logic; 
-- Control/status register. 
signal CSR : std_logic_vector (31 downto 0); 
 
-- Enable DMA read. 
signal DMA_RD_EN : std_logic; 
-- Enable DMA write. 
signal DMA_WR_EN : std_logic; 
 
-- Data is in buffer waiting to be processed. 
signal DATA_READY : std_logic; 
 
-- Internal use of signals RDl_WR and RENl_WENl. 
signal RDl_WRi : std_logic; 
signal RENl_WENli : std_logic; 
 
-- Data out to be driven onto ADIO. 
signal DATAOUTi : std_logic_vector (31 downto 0); 
signal DATAOUT : std_logic_vector (31 downto 0); 
 
signal WR_REG_WR : std_logic; 
signal WR_REG_WRd1 : std_logic; 
 
-- Constant values for zero and one. 32 bits wide. 
constant ZEROS : std_logic_vector (31 downto 0) := (others => '0'); 
constant ONE : std_logic_vector (31 downto 0) := ( 0 => '1', others => '0'); 
 
begin 
 
-- This state machine controls the all data to and from the Spartan. 
-- Priority is given to reading data from the Spartan in case any CSRs need updating. 
process (RST, CLK) 
begin 
	if RST='1' then 
		SM_STATE <= RST_STATE; 
		RDl_WRi <= '1'; 
		RENl_WENli <= '1'; 
		DATA_READY <= '0'; 
		WR_DMAi <= '0'; 
		RD_DMAi <= '0'; 
	elsif CLK'event and CLK='1' then 
		case SM_STATE is 
			-- Reset state ensures that the state machine remains reset until the whole design is definitely reset. 
			when RST_STATE => 
				if SYNC_RST='1' then 
					SM_STATE <= RST_STATE; 
					RDl_WRi <= '1'; 
					RENl_WENli <= '1'; 
					DATA_READY <= '0'; 
					WR_DMAi <= '0'; 
					RD_DMAi <= '0'; 
				else 
					SM_STATE <= IDLE; 
				end if; 
			-- When idle, check to see if there's data to be sent.   
			-- If there isn't, check to see if the DMA engine is set up to output data.	 
			when IDLE => 
				if EMPTYd1='0' then 
					SM_STATE <= WAIT_DATA; 
					RDl_WRi <= '0'; 
					RENl_WENli <= '0'; 
				elsif EMPTYd1='1' and DMA_WR_EN='1' and TERM_CNT='0' then 
					SM_STATE <= WAIT_TO_DMAWR; 
				end if; 
			-- Wait for data to be valid.	 
			when WAIT_DATA => 
				RDl_WRi <= '1'; 
				RENl_WENli <= '1'; 
				SM_STATE <= DATA_READ; 
			-- Firstly check to see if data is address or not. 
			-- If it is an address, go to address decode. 
			-- If it's not an address see if the data is for the DMA engine or not.	 
			when DATA_READ => 
				RDl_WRi <= '1'; 
				RENl_WENli <= '1'; 
				if AS_DSl_IN='1' then 
					SM_STATE <= ADDR_DEC; 
				elsif DMA_RD_EN='1' and TERM_CNT='0' then 
					if DMA_IN_FULL='1' then 
						SM_STATE <= WAIT_DMA_RD; 
						WR_DMAi <= '0'; 
					elsif EMPTY='0' and DMA_IN_FULL='0' then 
						SM_STATE <= WAIT_TO_DMARD; 
						RDl_WRi <= '0'; 
						RENl_WENli <= '0'; 
						WR_DMAi <= '1'; 
					elsif EMPTY='1' and DMA_IN_FULL='0' then  
						SM_STATE <= WAIT_ENDTRANS; 
						WR_DMAi <= '1'; 
					end if;	 
				else	 
					DATA_READY <= '1'; 
					SM_STATE <= WR_REG; 
				end if; 
			-- Determine if the address is being written to or read from.	 
			when ADDR_DEC => 
				if ADDRESSi(31)='0' then 
					SM_STATE <= WR_REG; 
				else 
					SM_STATE <= RD_REG; 
				end if; 
			-- Check to see if data has already been read. 
			-- If it hasn't, read from Spartan.	 
			when WR_REG => 
				if DATA_READY='0' then 
					if EMPTYd1='0' then 
						RDl_WRi <= '0'; 
						RENl_WENli <= '0'; 
						SM_STATE <= WAIT_DATACHK; 
					end if;	 
				else 
					DATA_READY <= '0'; 
					SM_STATE <= WAIT_DATACHK;	 
				end if; 
			-- Read from register.		 
			when RD_REG => 
				RDl_WRi <= '1'; 
				RENl_WENli <= '0'; 
				SM_STATE <= WAIT_DATACHK; 
			-- Wait before going into DMA read.	 
			when WAIT_TO_DMARD => 
				RDl_WRi <= '0'; 
				RENl_WENli <= '0'; 
				WR_DMAi <= '1'; 
				SM_STATE <= DMA_READ; 
			-- Check to see if there's still data to be processed. 
			-- If there is, determine the nature of the data.	 
			when WAIT_DATACHK => 
				RDl_WRi <= '1'; 
				RENl_WENli <= '1'; 
				if DATA_READY='1' then 
					if AS_DSl_IN='1' then 
						SM_STATE <= ADDR_DEC; 
						DATA_READY <= '0'; 
					elsif DMA_RD_EN='1' and TERM_CNT='0' then 
						SM_STATE <= WAIT_TO_DMARD; 
						DATA_READY <= '0'; 
					else 
						SM_STATE <= WR_REG; 
					end if; 
				else				 
					SM_STATE <= WAIT_ENDTRANS; 
				end if;	 
			-- Wait before going idle.	 
			when WAIT_ENDTRANS => 
				SM_STATE <= IDLE; 
				WR_DMAi <= '0'; 
				RDl_WRi <= '1'; 
				RENl_WENli <= '1'; 
			-- Check that data in isn't an address. 
			-- Also check for terminal count. 
			-- If neither of these are true, check that it's okay to read data.	 
			when DMA_READ => 
				if EMPTY='1' then--or TERM_CNT='1' then 
					SM_STATE <= WAIT_ADDRCHK; 
					RDl_WRi <= '1'; 
					RENl_WENli <= '1'; 
					WR_DMAi <= '0'; 
				elsif TERM_CNT='1' then 
					RDl_WRi <= '0';	   
					RENl_WENli <= '1'; 
					WR_DMAi <= '0'; 
					if AS_DSl='1' then 
						SM_STATE <= WAIT_ADDRDEC;  
						DATA_READY <= '1'; 
					else 
						SM_STATE <= WR_REG; 
						DATA_READY <= '1'; 
					end if; 
				elsif DMA_IN_FULL='1' then 
					SM_STATE <= WAIT_END_DMARD; 
					RDl_WRi <= '0'; 
					RENl_WENli <= '1'; 
					WR_DMAi <= '1'; 
				else	 
					if AS_DSl='1' then 
						RDl_WRi <= '1'; 
						RENl_WENli <= '1'; 
						SM_STATE <= WAIT_ADDRDEC; 
						DATA_READY <= '1'; 
						WR_DMAi <= '0'; 
					else 
						RDl_WRi <= '0'; 
						RENl_WENli <= '0'; 
						WR_DMAi <= '1'; 
					end if; 
				end if;		 
			-- Wait before going to address decode. 
			-- This allows the address to be stored.			 
			when WAIT_ADDRDEC => 
				SM_STATE <= ADDR_DEC;	 
			-- Make sure that Spartan doesn't want to send data before sending data.	 
			-- Make sure that there is data to send. 
			when DMA_WRITE => 
				RD_DMAi <= '0'; 
				if EMPTY='0' then  
					SM_STATE <= WAIT_ENDTRANS; 
					RDl_WRi <= '1'; 
					RENl_WENli <= '1'; 
				elsif TERM_CNT='1' then 
					SM_STATE <= WAIT_ENDTRANS; 
					RDl_WRi <= '1'; 
					RENl_WENli <= '0';	 
				elsif BUSYd1='0' then 
					if BUSY='0' then 
						RD_DMAi <= '1'; 
					else 
						RD_DMAi <= '0'; 
					end if;		 
					if RD_DMAii='1' then 
						RDl_WRi <= '1'; 
						RENl_WENli <= '0'; 
					else 
						RDl_WRi <= '1'; 
						RENl_WENli <= '1'; 
					end if;		 
				else 
					RENl_WENli <= '1'; 
				end if;	 
			-- Wait for DMA input to not be full to write the data that has been captured. 
			when WAIT_DMA_RD => 
				if DMA_IN_FULL='0' then 
					WR_DMAi <='1'; 
					SM_STATE <= WAIT_ENDTRANS; 
				end if;		 
			-- Check to see if last data captured is an address.	 
			when WAIT_ADDRCHK => 
				if AS_DSl_IN='1' then 
					SM_STATE <= ADDR_DEC; 
					DATA_READY <= '0'; 
				else 
					SM_STATE <= IDLE; 
				end if; 
			-- Wait before enabling DMA write.		 
			when WAIT_TO_DMAWR => 
				if EMPTYd1='0' then 
					SM_STATE <= IDLE; 
				else 
					if DMA_OUT_EMPTY='0' then 
						RD_DMAi <= '1'; 
						SM_STATE <= DMA_WRITE; 
					end if; 
				end if;	 
			-- DMA read has ended.		 
			when WAIT_END_DMARD => 
				SM_STATE <= IDLE; 
				RDl_WRi <= '1'; 
				WR_DMAi <= '0';												 
			when others => 
				SM_STATE <= RST_STATE; 
				RDl_WRi <= '1'; 
				RENl_WENli <= '1'; 
				DATA_READY <= '0'; 
				WR_DMAi <= '0'; 
				RD_DMAi <= '0';											 								 
		end case; 
	end if; 
end process;					 													 
 
-- Delay busy and empty by one clock. 
process (RST, CLK) 
begin 
	if RST='1' then 
		EMPTYd1 <= '1'; 
		BUSYd1 <= '1'; 
	elsif CLK'event and CLK='1' then 
		EMPTYd1 <= EMPTY; 
		BUSYd1 <= BUSY; 
	end if; 
end process;			 
 
-- Generate RDl_WR and RENl_WENl. 
RDl_WR <= RDl_WRi; 
RENl_WENl <= RENl_WENli; 
 
-- Control for writing address. 
ADDRESS_WR <= '1' when (SM_STATE=DATA_READ and AS_DSl_IN='1') or SM_STATE=WAIT_ADDRDEC or (SM_STATE=WAIT_DATACHK and AS_DSl_IN='1') or (SM_STATE=WAIT_ADDRCHK and AS_DSl_IN='1')else '0';  
 
-- Write new address. 
process (RST, CLK) 
begin 
	if RST='1' then 
		ADDRESSi <= (others => '0'); 
	elsif CLK'event and CLK='1' then 
		if ADDRESS_WR='1' then 
			ADDRESSi <= DATAIN; 
		end if; 
	end if; 
end process; 
ADDRESS <= ADDRESSi(30 downto 0);				 
 
-- Generate data valid. 
process (RST, CLK) 
begin 
	if RST='1' then 
		DVALIDd1 <= '0'; 
	elsif CLK'event and CLK='1' then 
		DVALIDd1 <= DVALID; 
	end if; 
end process; 
 
-- Generate signal that writes to register. 
WR_REG_WR <= '1' when SM_STATE=WR_REG and DATA_READY='0' and EMPTYd1='0' else '0'; 
process (RST, CLK) 
begin 
	if RST='1' then 
		WR_REG_WRd1 <= '0'; 
	elsif CLK'event and CLK='1' then 
		WR_REG_WRd1 <= WR_REG_WR; 
	end if; 
end process;			 
 
-- Control for writing data in. 
DATAIN_WR <= '1' when SM_STATE=WAIT_DATA or SM_STATE=DMA_READ or SM_STATE=WAIT_ADDRDEC or SM_STATE=WAIT_END_DMARD or (WR_REG_WRd1='1') else '0';			 
 
-- Write data into buffer.  Store address/data strobe also. 
process (RST, CLK) 
begin  
	if RST='1' then 
		AS_DSl_IN <= '0'; 
		DATAIN <= (others => '0'); 
	elsif CLK'event and CLK='1' then 
		if DATAIN_WR='1' then 
			AS_DSl_IN <= AS_DSl; 
			DATAIN <= ADIO; 
		end if; 
	end if; 
end process;				 
 
-- Generate write strobe and read strobe. 
WRITE_STROBEi <= '1' when (WR_REG_WRd1='1') or (SM_STATE=WR_REG and DATA_READY='1') else '0'; 
READ_STROBEi <= '1' when (SM_STATE=RD_REG) else '0'; 
process (RST, CLK) 
begin 
	if RST='1' then 
		WRITE_STROBEid1 <= '0'; 
	elsif CLK'event and CLK='1' then 
		WRITE_STROBEid1 <= WRITE_STROBEi; 
	end if; 
end process;			 
WR_STROBE <= WRITE_STROBEid1; 
RD_STROBE <= READ_STROBEi; 
 
-- Internal address decode. 
MEM_BLOCK0_EN <= '1' when ADDRESSi(((NUM_BLOCKSg+BLOCK_SIZEg)-1) downto (BLOCK_SIZEg)) = ZEROS((NUM_BLOCKSg-1) downto 0) else '0';	 
 
-- CSR decode. 
WR_CSR <= '1' when (MEM_BLOCK0_EN='1') and (ADDRESSi((NUM_REGSg-1) downto 0) = ZEROS((NUM_REGSg-1) downto 0)) and (WRITE_STROBEid1='1') else '0'; 
RD_CSR <= '1' when (MEM_BLOCK0_EN='1') and (ADDRESSi((NUM_REGSg-1) downto 0) = ZEROS((NUM_REGSg-1) downto 0)) and (READ_STROBEi='1') else '0'; 
 
-- DMA Count decode. 
WR_COUNT <= '1' when (MEM_BLOCK0_EN='1') and (ADDRESSi((NUM_REGSg-1) downto 0) = ONE((NUM_REGSg-1) downto 0)) and (WRITE_STROBEid1='1') else '0'; 
RD_COUNTi <= '1' when (MEM_BLOCK0_EN='1') and (ADDRESSi((NUM_REGSg-1) downto 0) = ONE((NUM_REGSg-1) downto 0)) and (READ_STROBEi='1') else '0'; 
--RD_COUNT <= RD_COUNTi; 
 
-- Generate DMA write. 
process (RST, CLK) 
begin 
	if RST='1' then 
		WR_DMAid1 <= '0'; 
	elsif CLK'event and CLK='1' then 
		WR_DMAid1 <= WR_DMAi; 
	end if; 
end process; 
WR_DMA <= '0' when WR_DMAid1='0' or SM_STATE=WAIT_ADDRDEC or (SM_STATE=WAIT_ADDRCHK and AS_DSl_IN='1') else '1'; 
			 
--RD_DMA <= RD_DMAi; 
-- Generate DMA read. 
RD_DMAii <= '1' when RD_DMAi='1' and SM_STATE = DMA_WRITE and DMA_OUT_EMPTY='0' else '0'; 
RD_DMA <= RD_DMAii; 
 
-- CSR register. 
process (RST, CLK) 
begin 
	if RST='1' then 
		CSR(6 downto 0) <= (others => '0'); 
		CSR(7) <= '0'; 
		CSR(8) <= '1'; 
		CSR(9) <= '0'; 
		CSR(10) <= '1'; 
	elsif CLK'event and CLK='1' then 
		CSR(7) <= DMA_IN_FULL; 
		CSR(8) <= DMA_IN_EMPTY; 
		CSR(9) <= DMA_OUT_FULL; 
		CSR(10) <= DMA_OUT_EMPTY; 
		if WR_CSR='1' then 
			CSR(6 downto 0) <= DATAIN(6 downto 0); 
		end if; 
	end if; 
end process;		 
 
CSR(31 downto 11) <= (others => '0'); 
 
-- DMA enable signals derived from CSR.		 
DMA_RD_EN <= '1' when CSR(0)='1' and CSR(1)='0' else '0'; 
DMA_WR_EN <= '1' when CSR(0)='1' and CSR(1)='1' else '0'; 
DMA_ENABLE <= CSR(0); 
DMA_DIRECTION <= CSR(1); 
DMA_SEL <= CSR(5 downto 2);	    
DMA_RST <= CSR(6); 
 
-- Data out for DMA count.	 
COUNT_IN <= DATAIN; 
 
-- Data bus output.	 
DATA <= COUNT_OUT when RD_COUNTi='1' else (others => 'Z'); 
DATA <= DMA_OUT when RD_DMAi='1' else (others => 'Z'); 
DATA <= CSR when RD_CSR='1' else (others => 'Z');	 
DATA <= DATAIN when WRITE_STROBEid1='1' else (others => 'Z');	 
	 
DATAOUTi <= DATA;	 
		 
-- Store data output.		 
process (RST, CLK) 
begin 
	if RST='1' then 
		DATAOUT <= (others => '0'); 
	elsif CLK'event and CLK='1' then 
		if READ_STROBEi='1' or RD_DMAi='1' then 
			DATAOUT <= DATAOUTi; 
		end if; 
	end if; 
end process;						 
 
-- DMA input data. 
DMA_IN <= DATAIN; 
	 
-- Determine if Virtex is driving ADIO.	 
ADIO <= DATAOUT when RDl_WRi='1' else (others => 'Z'); 
				 
end if_main_arch;