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;