OpenCores
URL https://opencores.org/ocsvn/saturn/saturn/trunk

Subversion Repositories saturn

[/] [saturn/] [trunk/] [IPCommunication/] [switch.vhd] - Rev 3

Go to most recent revision | Compare with Previous | Blame | View Log

--============================================================================= 
--  TITRE : SWITCH
--  DESCRIPTION : 
--        - Gère la réception et la transmission d'une ligne série
--			 - Copie du port Rx sur le port Tx avec remise en forme du signal
--        - Gestion du switch entre les sources Tx
--        - Buffurise les données reçues pendant la transmission		
 
--  FICHIER :        switch.vhd 
--=============================================================================
--  CREATION 
--  DATE	AUTEUR	PROJET	REVISION 
--  29/02/2012	DRA	CONCERTO	V1.0 
--=============================================================================
--  HISTORIQUE  DES  MODIFICATIONS :
--  DATE	AUTEUR	PROJET	REVISION 
--=============================================================================
 
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
 
 
 
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
 
ENTITY switch IS
   GENERIC (
      nbbit_div : INTEGER := 10);   -- Nombre de bits pour coder le diviseur d'horloge 
   PORT (
      -- Ports système
      clk_sys  : IN  STD_LOGIC;  -- Clock système
      rst_n    : IN  STD_LOGIC;  -- Reset génrél système
      baud_lock: IN  STD_LOGIC;  -- Indique que le baudrate est calé
 
      -- Interface série
      tc_divclk: IN  STD_LOGIC_VECTOR (nbbit_div-1 DOWNTO 0); -- Diviseur de l'horloge système pour le baudrate
      rx       : IN  STD_LOGIC;  -- Réception série    
      tx       : OUT  STD_LOGIC; -- Transmission série
 
      -- Interface avec la mémoire de transmission
      tx_dat   : IN  STD_LOGIC_VECTOR (7 DOWNTO 0);  -- Prochaine donnée à transmettre
      tx_empty : IN  STD_LOGIC;  -- Mémoire de transmission vide
      tx_rd    : OUT  STD_LOGIC; -- Lecture de la donnée suivante à transmettre
 
      -- Interface avec la mémoire de réception
      rx_dat   : OUT  STD_LOGIC_VECTOR (7 DOWNTO 0);  -- Donnée en cours de réception
      rx_val   : OUT  STD_LOGIC; -- Signal d'écriture dans la méoire de réception
 
      -- Gestion de la recopie
      sw_ena   : IN  STD_LOGIC;  -- Autorisation du changement d'émetteur
      copy_ena : IN  STD_LOGIC  -- Autorisation de recopie d'un port sur l'autre
      );
END switch;
 
ARCHITECTURE rtl of switch is
   SIGNAL data_deser       : STD_LOGIC_VECTOR(7 downto 0);  -- Donnée reçue déserialisée
   SIGNAL tx_copy          : STD_LOGIC;                     -- Valeur d'un bit à retransmettre pour la recopie
   SIGNAL rx_wr_buf        : STD_LOGIC;                     -- Pulse d'écriture d'un nouveau caractère reçu
   SIGNAL rx_encours       : STD_LOGIC;                     -- Indique qu'une réception est en cours
 
   SIGNAL ser_rdy          : STD_LOGIC;                     -- Le sérialisateur est prêt à traiter un nouveau car
   SIGNAL tx_ser           : STD_LOGIC;                     -- Sortie du sérialisateur
 
   SIGNAL sel_ser          : STD_LOGIC;                     -- Sélection de la source série pour le Tx (recopie ou sérialisateur)
   SIGNAL sel_par          : STD_LOGIC;                     -- Sélection de la source parallèle pour le sérialisateur (FIFO de copy ou transmission)
   SIGNAL datatx_mux_c     : STD_LOGIC_VECTOR(7 downto 0);  -- Source parallèle pour le sérialisateur (FIFO de copy ou transmission)
   SIGNAL fifocopy_dout    : STD_LOGIC_VECTOR(7 downto 0);  -- Donnée en sortie de la FIFO de recopie
   SIGNAL start_ser_c      : STD_LOGIC;                     -- Déclenche la sérialisation du mot présent sur datatx_mux_c
   SIGNAL cop_read_c       : STD_LOGIC;                     -- Lit un car dans la FIFO de recopie
   SIGNAL tx_read_c        : STD_LOGIC;                     -- Lit un car dans la mémoire de transmission
   SIGNAL cop_empty        : STD_LOGIC;                     -- FIFO de recopie vide
   SIGNAL cop_clr          : STD_LOGIC;                     -- Purge de la FIFO de recopie
   SIGNAL req_cop_c        : STD_LOGIC;                     -- Indique qu'il y'a ou qu'il va y'avoir un caractère dans la FIFO de recopie
   SIGNAL tempo            : STD_LOGIC_VECTOR(nbbit_div-1 downto 0); -- Tempo de 1 bit
 
   -- Machine d'état de gestion du module
   TYPE switch_state IS (idle_st, txreq_st, wait1bit_st, txproc_st, copproc_st);
   SIGNAL fsm_switch       : switch_state;
 
   -- Composant de serialisation
   COMPONENT serial_tx
	GENERIC (
      nbbit_div : INTEGER := 10);
   PORT(
		clk_sys     : IN std_logic;
		rst_n       : IN std_logic;
		tc_divclk   : IN std_logic_vector(nbbit_div-1 downto 0);
		start_ser   : IN std_logic;
		tx_dat      : IN std_logic_vector(7 downto 0);          
		tx          : OUT std_logic;
		ser_rdy     : OUT std_logic
		);
	END COMPONENT;
 
   -- Composant de déserialisation
	COMPONENT serial_rx
	GENERIC (
      nbbit_div : INTEGER := 10);
	PORT(
		clk_sys     : IN std_logic;
		rst_n       : IN std_logic;
      baud_lock   : IN  STD_LOGIC;
		tc_divclk   : IN std_logic_vector(nbbit_div-1 downto 0);
		rx          : IN std_logic;          
		tx          : OUT std_logic;
      busy        : OUT STD_LOGIC;
		val         : OUT std_logic;
		rx_dat      : OUT std_logic_vector(7 downto 0)
		);
	END COMPONENT;
 
   -- FIFO de stockage des données reçues qui ne peuvent pas être recopiées
   -- La FIFO est en FWFT
   COMPONENT fifo_copy
   PORT (
      clk      : IN STD_LOGIC;
      srst     : IN STD_LOGIC;
      din      : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
      wr_en    : IN STD_LOGIC;
      rd_en    : IN STD_LOGIC;
      dout     : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
      full     : OUT STD_LOGIC;
      overflow : OUT STD_LOGIC;
      empty    : OUT STD_LOGIC
      );
   END COMPONENT;
 
BEGIN
   --------------------------------------------
   -- Déserialisateur des données reçues sur rx 
   -- et remise en forme (retaillage des durée de bit) pour la recopie
   --------------------------------------------
   inst_serial_rx: serial_rx 
   GENERIC MAP (
      nbbit_div => nbbit_div)
   PORT MAP(
		clk_sys => clk_sys,
		rst_n => rst_n,
      baud_lock => baud_lock,
		tc_divclk => tc_divclk,
		tx => tx_copy,
		rx => rx,
      busy => rx_encours,
		val => rx_wr_buf,
		rx_dat => data_deser
	);
   rx_dat <= data_deser;
   rx_val <= rx_wr_buf;
 
   --------------------------------------------
   -- Sérialise sur 10 bits une donnée 8 bits en entrée 
   --------------------------------------------
   inst_serial_tx: serial_tx 
   GENERIC MAP (
      nbbit_div => nbbit_div)
   PORT MAP(
		clk_sys => clk_sys,
		rst_n => rst_n,
		tc_divclk => tc_divclk,
		tx => tx_ser,
		ser_rdy => ser_rdy,
		start_ser => start_ser_c,
		tx_dat => datatx_mux_c
	);
 
   --------------------------------------------
   -- Machine d'état de gestion de la source de tx
   --   Soit on recopie le rx
   --   Soit on émet des données reçues et stockées dans la FIFO rx
   --   Soit on émet une trame (FIFO externe au module)
   --------------------------------------------
   -- Indique qu'il y'a des données (cop_empty) ou qu'il va y'en avoir (rx_encours et rx_wr_buf et
   -- copy_ena) dans la FIFO de recopie
   req_cop_c <= NOT(cop_empty) OR ((rx_encours OR rx_wr_buf) AND copy_ena);
   man_fsm : PROCESS(clk_sys, rst_n)
   BEGIN
      IF (rst_n = '0') THEN
         fsm_switch <= idle_st;
         sel_ser <= '0';
         sel_par <= '1';
         cop_clr <= '1';
         tempo   <= (OTHERS => '0');
      ELSIF (clk_sys'EVENT and clk_sys = '1') THEN
         CASE fsm_switch IS
            WHEN idle_st =>
            -- Dans cet état, la FIO Tx et la FIFO copy sont forcément vides
                              IF (rx_encours = '0') THEN -- Le nouvel état de copy_ena n'est pris en compte que sur une frontière octet
                  sel_ser <= copy_ena;    -- Si la copie n'est pas autorisée, tx est de base sur le sérialisateur
               END IF;
               sel_par <= '1';
               cop_clr <= '1';         -- Par défaut, la FIFO de recopie doit être vide
               IF (tx_empty = '0') THEN
               -- S'il y'a des données à transmettre dans la FIFO externe
                  fsm_switch <= txreq_st;
               END IF;
 
            WHEN txreq_st =>
            -- Etat d'attente que les conditions soient favorables pour changer la source du tx
               IF ((sw_ena = '1' AND rx_encours = '0') OR 
                    (copy_ena = '0')) THEN
               -- Si la recopie est interdite, on change quand on veut
               -- Sinon, il faut attendre d'être entre 2 trames (sw_ena) et qu'on est pas déjà en train de recopier le car suivant
                  sel_ser <= '0';            -- Le tx est sur le sérialisateur
                  sel_par <= '0';            -- Les données du sérialisateur viennent de la FIFO externe
                  cop_clr <= not(copy_ena);  -- Si la recopie est interdite on purge la FIFO de recopie
                  tempo   <= (OTHERS => '0');
                  fsm_switch <= wait1bit_st;
               END IF;
 
            WHEN wait1bit_st =>
            -- Etat d'attente de 1 bit pour assurer que le STOP bit recopié fait au moins un bit
               IF (tempo = tc_divclk) THEN
                  fsm_switch <= txproc_st;
               ELSE
                  tempo <= tempo + 1;
               END IF;
 
            WHEN txproc_st =>
            -- Etat d'émission des données de la FIFO externe
               IF ((tx_empty = '1') AND (req_cop_c = '1')) THEN
               -- S'il n'y a plus rien à émettre dans la FIFO externe et qu'il y'a des données dans la FIFO de recopie
                  sel_ser <= '0';            -- Le tx est sur le sérialisateur
                  sel_par <= '1';            -- Les données du sérialisateur viennent de la FIFO de recopie
                  cop_clr <= not(copy_ena);
                  fsm_switch <= copproc_st;
               ELSIF ((tx_empty = '1') AND (ser_rdy = '1') AND (req_cop_c = '0')) THEN
               -- Si n'y a plus rien à émettre dans aucune FIFO et que l'émission du dernier car est finie
                  sel_ser <= copy_ena;       -- Le tx est branché sur le rx si la recopie est autorisée
                  sel_par <= '1';
                  cop_clr <= '1';
                  fsm_switch <= idle_st;
               END IF;
 
            WHEN copproc_st =>
            -- Etat d'émission des données de la FIFO de recopie
               IF ((tx_empty = '0') AND (req_cop_c = '0')) THEN
               -- S'il n'y a plus rien à émettre dans la FIFO de recopie et qu'il y'a des données dans la FIFO externe
                  sel_ser <= '0';            -- Le tx est sur le sérialisateur
                  sel_par <= '0';            -- Les données du sérialisateur viennent de la FIFO externe
                  cop_clr <= not(copy_ena);
                  fsm_switch <= txproc_st;
               ELSIF ((tx_empty = '1') AND (ser_rdy = '1') AND (req_cop_c = '0') AND 
                      (sw_ena = '1' OR copy_ena = '0')) THEN
               -- Si n'y a plus rien à émettre dans aucune FIFO et que l'émission du dernier car est finie
               -- et que soit on est pas au milieu d'une trame (sw_ena = 1) ou bien que la copy n'est pas 
               -- autorisé (dans ce cas on peut switcher quand on veut)
                  sel_ser <= copy_ena;       -- Le tx est branché sur le rx si la recopie est autorisée
                  sel_par <= '1';
                  cop_clr <= '1';
                  fsm_switch <= idle_st;
               END IF;
 
            WHEN OTHERS =>
               fsm_switch <= idle_st;
         END CASE;
      END IF;
   END PROCESS;
 
   -- On lit un mot dans la FIFO de recopie chaque fois que le sérialisateur est prêt et qu'on est dans le bon état
   cop_read_c <= ser_rdy AND NOT(cop_empty) WHEN (fsm_switch = copproc_st) ELSE '0';
   -- On lit un mot dans la FIFO externe chaque fois que le sérialisateur est prêt et qu'on est dans le bon état
   tx_read_c <= ser_rdy AND NOT(tx_empty) WHEN (fsm_switch = txproc_st) ELSE '0';
   tx_rd <= tx_read_c;
   -- A cahque mot lu dans une des FIFO, on active le sérialisateur
   start_ser_c <= cop_read_c OR tx_read_c;
   -- L'entrée du sérialisateur dépend du signal de sélection
   datatx_mux_c <= tx_dat WHEN (sel_par = '0') ELSE fifocopy_dout;
   -- La sortie tx dépend du signal de sélection. Il n'y a pas de problème de glitch car sel_ser ne 
   -- change qu'entre 2 caractère et donc la ligne est IDLE à ce moment là
   tx <= tx_ser WHEN (sel_ser = '0') ELSE tx_copy;
 
   inst_fifo_copy : fifo_copy
   PORT MAP (
      clk => clk_sys,
      srst => cop_clr,
      din => data_deser,
      wr_en => rx_wr_buf,
      rd_en => cop_read_c,
      dout => fifocopy_dout,
      full => OPEN,
      overflow => OPEN,
      empty => cop_empty
   );
 
END rtl;
 
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.