---------------------------------------------------------------------------- -- -- File: userapp.vhd -- Rev: 3.0.0 -- -- This is an example template for the user backend application. -- -- Copyright (c) 2002 Xilinx, Inc. All rights reserved. -- ---------------------------------------------------------------------------- -- Projekt "Burst-Master mit 4 KByte RAM" -- Eine ausfuehrliche Beschreibung befindet sich in der HTML-Dokumentation. ---------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; use IEEE.STD_LOGIC_ARITH.ALL; entity userapp is port (-- Interface to PCI Logicore. FRAMEQ_N : in std_logic; TRDYQ_N : in std_logic; IRDYQ_N : in std_logic; STOPQ_N : in std_logic; DEVSELQ_N : in std_logic; ADDR : in std_logic_vector( 31 downto 0); ADIO : inout std_logic_vector( 31 downto 0); CFG_VLD : in std_logic; CFG_HIT : in std_logic; C_TERM : out std_logic; C_READY : out std_logic; ADDR_VLD : in std_logic; BASE_HIT : in std_logic_vector( 7 downto 0); S_TERM : out std_logic; S_READY : out std_logic; S_ABORT : out std_logic; S_WRDN : in std_logic; S_SRC_EN : in std_logic; S_DATA_VLD : in std_logic; S_CBE : in std_logic_vector( 3 downto 0); PCI_CMD : in std_logic_vector( 15 downto 0); REQUEST : out std_logic; REQUESTHOLD : out std_logic; COMPLETE : out std_logic; M_WRDN : out std_logic; M_READY : out std_logic; M_SRC_EN : in std_logic; M_DATA_VLD : in std_logic; M_CBE : out std_logic_vector( 3 downto 0); TIME_OUT : in std_logic; CFG_SELF : out std_logic; M_DATA : in std_logic; DR_BUS : in std_logic; I_IDLE : in std_logic; M_ADDR_N : in std_logic; IDLE : in std_logic; B_BUSY : in std_logic; S_DATA : in std_logic; BACKOFF : in std_logic; INTR_N : out std_logic; PERRQ_N : in std_logic; SERRQ_N : in std_logic; KEEPOUT : out std_logic; CSR : in std_logic_vector( 39 downto 0); SUB_DATA : out std_logic_vector( 31 downto 0); CFG : in std_logic_vector(255 downto 0); RST : in std_logic; CLK : in std_logic; USER_LED : out std_logic; ONE_DIGIT : out std_logic_vector(6 downto 0); TEN_DIGIT : out std_logic_vector(6 downto 0) ); end userapp; architecture rtl of userapp is attribute syn_edif_bit_format : string; attribute syn_edif_scalar_format : string; attribute syn_noclockbuf : boolean; attribute syn_hier : string; attribute syn_edif_bit_format of rtl : architecture is "%u<%i>"; attribute syn_edif_scalar_format of rtl : architecture is "%u"; attribute syn_noclockbuf of rtl : architecture is true; attribute syn_hier of rtl : architecture is "hard"; component displayrom port ( ADDR : in std_logic_vector(3 downto 0); DATA : out std_logic_vector(6 downto 0) ); end component; -- Deklaration der PCI-Target-Steuerung component target_control port ( RST : in std_logic; CLK : in std_logic; BASE_HIT : in std_logic_vector(7 downto 0); S_DATA : in std_logic; S_WRDN : in std_logic; ADDR : in std_logic_vector(31 downto 0); S_DATA_VLD : in std_logic; S_READY : out std_logic; S_TERM : out std_logic; S_ABORT : out std_logic; OE_PCI_START_REG : out std_logic; OE_XFER_COUNT_REG : out std_logic; OE_STATUS_REG : out std_logic; OE_INTR_FLAG : out std_logic; LOAD_PCI_START_REG : out std_logic; LOAD_XFER_COUNT_REG : out std_logic; LOAD_COMMAND_REG : out std_logic ); end component; -- Deklaration des Puffers component buffer_1k_32b is port ( RST : in std_logic; CLK : in std_logic; DATA_IN : in std_logic_vector(31 downto 0); PUSH : in std_logic; DATA_OUT : out std_logic_vector(31 downto 0); POP : in std_logic; ACK : in std_logic; BACK_UP : in std_logic ); end component; -- Buendelung nicht benutzter Eingaenge des LogiCore PCI Interfaces component benign port ( SUB_DATA : out std_logic_vector(31 downto 0); KEEPOUT : out std_logic; C_READY : out std_logic; C_TERM : out std_logic; REQUESTHOLD : out std_logic; CFG_SELF : out std_logic ); end component; -- Zustaende Master-Steuerautomat type state_type is (IDLE_S, REQ_S, XFER_S, DEAD_S, OOPS_S); signal state : state_type; signal idle_state : std_logic; -- Register PCI-Busadresse signal pci_addr : std_logic_vector(29 downto 0); -- Register Transfer-Zaehler signal xfer_count : std_logic_vector(10 downto 0); -- Interrupt-Flag signal intr_n_flag : std_logic; signal req_interrupt : std_logic; -- Transferrichtung (command-Register) -- o dir = '1' : PCI-Schreibtransfer -- Daten vom Puffer ueber den Bus in ein Target schreiben -- o dir = '0' : PCI-Lesetransfer -- Daten von einem Target ueber den Bus in den Puffer lesen signal dir : std_logic; -- Target-Steuersignale (Register setzen / lesen) signal oe_pci_addr : std_logic; signal oe_xfer_count : std_logic; signal oe_status : std_logic; signal oe_intr_n : std_logic; signal load_pci_addr : std_logic; signal load_xfer_count : std_logic; signal load_command : std_logic; -- Inkrement-Signale fuer PCI-BUS-Adresse signal inc_pci_addr : std_logic; -- Dekrement-Signal fuer den Transferzaehler signal dec_xfer_count : std_logic; -- Mastertransfer-Startsignal signal start : std_logic; -- Signale fuer Master-Steuerautomat signal fatal : std_logic; signal done, req : std_logic; signal cnt3, cnt2, cnt1 : std_logic; signal fin1, fin2, fin3 : std_logic; signal m_data_delay, m_data_fell : std_logic; signal assert_complete, hold_complete : std_logic; -- PCI-Buskommando / Byte-Enable signal command, bytemask : std_logic_vector(3 downto 0); -- Signale fuer den Puffer signal buffer_data_in : std_logic_vector(31 downto 0); signal buffer_data_out : std_logic_vector(31 downto 0); signal buffer_reset : std_logic; signal buffer_pop : std_logic; signal buffer_push : std_logic; signal buffer_ack : std_logic; signal buffer_back_up : std_logic; -- Debugging signal burst_count, state_nr : std_logic_vector(3 downto 0); begin ---------------------------------------------------------------------------- -- Target-Steuerung und Target-Register ---------------------------------------------------------------------------- -- PCI-Target-Steuerung target_inst : target_control port map ( RST => RST, CLK => CLK, BASE_HIT => BASE_HIT, S_DATA => S_DATA, S_WRDN => S_WRDN, ADDR => ADDR, S_DATA_VLD => S_DATA_VLD, S_READY => S_READY, S_TERM => S_TERM, S_ABORT => S_ABORT, OE_PCI_START_REG => oe_pci_addr, OE_XFER_COUNT_REG => oe_xfer_count, OE_STATUS_REG => oe_status, OE_INTR_FLAG => oe_intr_n, LOAD_PCI_START_REG => load_pci_addr, LOAD_XFER_COUNT_REG => load_xfer_count, LOAD_COMMAND_REG => load_command ); -- Register PCI-Busadresse process (RST, CLK) begin if RST = '1' then pci_addr <= (others => '0'); elsif CLK'event and CLK = '1' then if load_pci_addr = '1' then pci_addr <= ADIO(31 downto 2); elsif inc_pci_addr = '1' then pci_addr <= pci_addr + '1'; end if; end if; end process; -- Register Transfer-Zaehler process (RST, CLK) begin if RST = '1' then xfer_count <= (others => '0'); elsif CLK'event and CLK = '1' then if load_xfer_count = '1' then xfer_count <= ADIO(10 downto 0); elsif dec_xfer_count = '1' then xfer_count <= xfer_count - '1'; end if; end if; end process; -- Interrupt-Flag (negative Logik) -- wird auf 0 gesetzt, wenn ein Transfer abgeschlossen wurde und -- automatisch wieder auf 1 nach dem Lesen des Flags ueber die -- Target-Schnittstelle (fallende Flanke von oe_intr_flag) zurueckgesetzt process (CLK, RST) variable oe_intr_n_delay : std_logic; begin if RST = '1' then oe_intr_n_delay := '0'; intr_n_flag <= '1'; elsif CLK'event and CLK = '1' then if req_interrupt = '1' then intr_n_flag <= '0'; elsif oe_intr_n = '0' and oe_intr_n_delay = '1' then intr_n_flag <= '1'; end if; oe_intr_n_delay := oe_intr_n; end if; end process; -- Interrupt-Eingang des LogiCore PCI Interfaces INTR_N <= intr_n_flag; -- Kommando-Register (Richtung des Transfers und Transfer-Start) process (RST, CLK) begin if RST = '1' then dir <= '0'; elsif CLK'event and CLK = '1' then if load_command = '1' then dir <= ADIO(0); end if; end if; end process; M_WRDN <= dir; start <= load_command; -- Inhalt der lesbaren Register unf Flags auf den ADIO-Bus bei Target-Lesezugriff ADIO <= x"00000" & "0" & xfer_count when oe_xfer_count = '1' else x"0000000" & "000" & idle_state when oe_status = '1' else x"0000000" & "000" & intr_n_flag when oe_intr_n = '1' else pci_addr & "00" when oe_pci_addr = '1' else (others => 'Z'); idle_state <= '1' when state = IDLE_S else '0'; ---------------------------------------------------------------------------- -- Transfer-Steuerautomat -- und benoetige Eingangssignale ---------------------------------------------------------------------------- -- Erkennung einer fallenden Flanke von M_DATA -- (Ende der Datenphase im PCI-Transfer) => m_data_fell process (RST, CLK) begin if RST = '1' then m_data_delay <= '0'; elsif CLK'event and CLK = '1' then m_data_delay <= M_DATA; end if; end process; m_data_fell <= m_data_delay and not M_DATA; -- Transferabbruch -- Master Abort oder Target Abort => fatal process (RST, CLK) begin if RST = '1' then fatal <= '0'; elsif CLK'event and CLK = '1' then if M_ADDR_N = '0' then fatal <= '0'; elsif M_DATA = '1' then fatal <= CSR(39) or CSR(38); -- Master / Target Abort end if; end if; end process; -- Fertig-Signal done <= '1' when xfer_count = "00" & x"00" else '0'; process (RST, CLK) begin if RST = '1' then state <= IDLE_S; burst_count <= x"0"; -- debugging elsif CLK'event and CLK = '1' then case state is when IDLE_S => if start = '1' then burst_count <= x"0"; -- debugging state <= REQ_S; else state <= IDLE_S; end if; when REQ_S => burst_count <= burst_count + '1'; -- debugging state <= XFER_S; when XFER_S => if m_data_fell = '1' then if fatal = '1' then state <= DEAD_S; else state <= OOPS_S; end if; else state <= XFER_S; end if; when OOPS_S => if done = '1' then state <= IDLE_S; else state <= REQ_S; end if; when DEAD_S => state <= DEAD_S; when others => state <= IDLE_S; end case; end if; end process; ---------------------------------------------------------------------------- -- Signale fuer das PCI-Master-Interface ---------------------------------------------------------------------------- -- PCI-Busadresse auf den ADIO-Bus, wenn -- PCI-Interface in der Adressphase (M_ADDR_N = '0') ADIO <= pci_addr & "00" when M_ADDR_N = '0' else (others => 'Z'); -- Erzeugen von M_CBE (PCI Command und Byte Enables) command <= "011" & dir; -- memory read/write bytemask <= "0000"; -- keine Bytes maskiert -- (im Memoryspace immer 32 Bit Wortbreite) M_CBE <= command when M_ADDR_N = '0' else bytemask; -- Busanforderung req <= '1' when state = REQ_S else '0'; REQUEST <= req; -- Die letzten drei Datenphasen... cnt3 <= '1' when xfer_count = "00" & x"03" else '0'; cnt2 <= '1' when xfer_count = "00" & x"02" else '0'; cnt1 <= '1' when xfer_count = "00" & x"01" else '0'; fin1 <= cnt1 and req; fin2 <= cnt2 and m_data_delay; fin3 <= cnt3 and M_DATA_VLD; assert_complete <= fin1 or fin2 or fin3; process (RST, CLK) begin if RST = '1' then hold_complete <= '0'; elsif CLK'event and CLK = '1' then if m_data_fell = '1' then hold_complete <= '0'; elsif assert_complete = '1' then hold_complete <= '1'; end if; end if; end process; COMPLETE <= assert_complete or hold_complete; -- Master immer bereit process (CLK, RST) begin if RST = '1' then M_READY <= '0'; elsif CLK'event and CLK = '1' then M_READY <= '1'; end if; end process; ---------------------------------------------------------------------------- -- Steuersignale fuer die Target-Register ---------------------------------------------------------------------------- -- Mitzaehlen der tatsaechlich uebertragenen Daten dec_xfer_count <= M_DATA_VLD; -- Busadresse mitzaehlen inc_pci_addr <= M_DATA_VLD; -- Interrupt anfordern, wenn Transfer beendet (done = '1') req_interrupt <= done when state = OOPS_S else '0'; ---------------------------------------------------------------------------- -- Anbindung des Puffers ---------------------------------------------------------------------------- -- Puffer-Instanziierung buffer_inst: buffer_1k_32b port map ( RST => buffer_reset, CLK => CLK, DATA_IN => buffer_data_in, PUSH => buffer_push, DATA_OUT => buffer_data_out, POP => buffer_pop, ACK => buffer_ack, BACK_UP => buffer_back_up ); -- Verbindung des Puffers mit dem Datenbus -- (dir = '1' : PCI-Schreibtransfer => Puffer wird gelesen) ADIO <= buffer_data_out when M_DATA = '1' and dir = '1' else (others => 'Z'); buffer_data_in <= ADIO; -- Daten aus dem Puffer holen bei PCI-Schreibtransfer (dir = '1'), -- aber nur, wenn neue Daten angefordert wurden (M_SRC_EN = '1') oder -- zur Bereitstellung des ersten Datenworts (state = REQ_S). buffer_pop <= dir when M_SRC_EN = '1' or state = REQ_S else '0'; -- Daten in den Puffer schreiben bei PCI-Lesetransfer (dir = '0'), -- wenn die Daten gueltig sind (M_DATA_VLD = '1'). buffer_push <= M_DATA_VLD and not dir; -- Bestaetigte (tatsaechlich uebertragene und empfangene) Daten buffer_ack <= M_DATA_VLD; -- Korrieren der aktuellen Pufferadresse: -- Bei einem PCI-Schreibtransfer kann das PCI-Interface dem tatsaechlichen -- Busgeschehen um bis zu 2 Takte voraus sein (Pipeline!). Mit dem Backup- -- Signal wird daher nach einer Transferunterbrechung der Adresszaehler im -- Puffer korrigiert. -- Bei einem Lesetransfer ist die Differenz immer 0. Um zusaetzliche Logik -- einzusparen, wird der Adresszaehler trotzdem "korrigiert". buffer_back_up <= '1' when state = OOPS_S else '0'; -- Adresszaehler des Puffers zuruecksetzen bei Systemreset und nach -- abgeschlossenem Transfer => Bereit fuer den naechsten Transfer. buffer_reset <= RST or done; ---------------------------------------------------------------------------- -- Nicht verwendete LogiCore PCI Interface Eingaenge ---------------------------------------------------------------------------- benign_inst : benign port map ( SUB_DATA => SUB_DATA, KEEPOUT => KEEPOUT, C_READY => C_READY, C_TERM => C_TERM, REQUESTHOLD => REQUESTHOLD, CFG_SELF => CFG_SELF ); ---------------------------------------------------------------------------- -- Debugging ---------------------------------------------------------------------------- -- Ausgabe des PCI-Automaten-Zustandes und der Anzahl der Bursts eines -- Gesamttransfers auf den 7-Segment-Anzeigen. with state select state_nr <= "0000" when IDLE_S, "0001" when REQ_S, "0010" when XFER_S, "0011" when OOPS_S, "0100" when DEAD_S, "1111" when others; displayrom_inst2 : displayrom port map ( ADDR => burst_count, DATA => ONE_DIGIT ); displayrom_inst1 : displayrom port map ( ADDR => state_nr, DATA => TEN_DIGIT ); -- Interrupt-Flag auf der User-LED USER_LED <= intr_n_flag; end rtl;