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

Subversion Repositories saturn

[/] [saturn/] [trunk/] [FPGA Concentrateur SIL4/] [fpga_cosil4/] [memory_map.vhd] - Rev 2

Compare with Previous | Blame | View Log

--============================================================================= 
--  TITRE : MEMORY_MAP
--  DESCRIPTION : 
--        Mappe la zone mémoire du BAR accédée par le bus local sur les registres
--        internes et les DPRAM 
--        Les registres sont accesibles en RD / WR par le bus local. 
--        Les signaux discrets associés aux registres sortent/entrent directement.
--        Les zones mémoires utilisées pour stocker les commandes périodiques et 
--        apériodiques sont accessibles d'un coté par le bus local, de l'autre
--        par un bus dédié.
--
--          BUS LOCAL                                       Bus dédié
--        Mots de 32 bits                                Mots de 8 bits
--        -----------------|--------------------------|
--                         |0000h                     |
--              BAR 0      |    Registres             |   Pas d'accès
--                         |7FFFh                     |
--        -----------------|--------------------------|----------------------
--                         |8000h                0000h|
--                         |    Zone Tx Periodique    |
--                         |87FFh                1FFFh|
--                         |--------------------------|
--                         |8800h                2000h|
--                         |     Zone réservée        |
--                         |8FFFh                3FFFh|
--              BAR 1      |--------------------------|    Accés par addrr_tx
--              (RFU)      |9000h                4000h|
--                         |    Zone Tx Apériodique   |
--                         |97FFh                5FFFh|
--                         |--------------------------|
--                         |9800h                6000h|
--                         |     Zone réservée        |
--                         |9FFFh                7FFFh|
--        -----------------|--------------------------|---------------------
--                         |A000h                     |
--              BAR 1      |     Zone réservée        |   Pas d'accès
--                         |FFFFh                     |
--        -----------------|--------------------------|---------------------
--
--  Les DMA transfèrent les trames reçus Rx1, Rx2, et émises par le PIC Tx dans 3 zones de 32 buffers chacune.
--  L'adresse de ce transfert vaut @ = DMA_BASE_PA + ZON * 2000h + BUF * 100h
--  Avec :
--	      ZON = 0, 1 ou 2 pour respectivement les zones Rx1, RX2 et Tx
--	      BUF = poids du bit à ‘1’ choisi dans un des registres RX1_AVAI, RX2_AVAI ou TX_AVAI (de 0 à 31).
--
--  FICHIER :        memory_map.vhd 
--=============================================================================
--  CREATION 
--  DATE	      AUTEUR	PROJET	REVISION 
--  10/04/2014	DRA	   SATURN	V1.0 
--=============================================================================
--  HISTORIQUE  DES  MODIFICATIONS :
--  DATE	      AUTEUR	PROJET	REVISION
--  03/03/2015 DRA      SATURN   V1.1 
--    Rajout du bit 7 au registre status 
--=============================================================================
 
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
 
LIBRARY work;
USE work.package_saturn.ALL;
 
ENTITY memory_map IS
   GENERIC (
      reg_version : STD_LOGIC_VECTOR(7 DOWNTO 0) := x"10"   -- Version du firmware
      );
   PORT (
      clk_sys        : IN  STD_LOGIC;                       -- Clock général système à 62.5MHz issue du module IF_PCIE
      rst_n          : IN  STD_LOGIC;                       -- Reset général système
      iid            : IN  STD_LOGIC_VECTOR(63 DOWNTO 0);   -- iid du Cocentrateur
      actif_passifn  : IN  STD_LOGIC;                       -- Indique que le concentrateur est actif ou passif
 
      -- Signaux du bus Local Bus du PCIe
      rd_addr        : IN  STD_LOGIC_VECTOR(NBBIT_ADD_LOCAL-1 DOWNTO 0);
      rd_data        : OUT STD_LOGIC_VECTOR(31 DOWNTO 0);
      rd_be          : IN  STD_LOGIC_VECTOR(3 DOWNTO 0);
      rd_en          : IN  STD_LOGIC;
      wr_addr        : IN  STD_LOGIC_VECTOR(NBBIT_ADD_LOCAL-1 DOWNTO 0);
      wr_data        : IN  STD_LOGIC_VECTOR(31 DOWNTO 0);
      wr_be          : IN  STD_LOGIC_VECTOR(3 DOWNTO 0);
      wr_en          : IN  STD_LOGIC;  
      wr_busy        : OUT STD_LOGIC;
 
      -- Interface Main Process
      -- Controle général
      rst_regn       : OUT STD_LOGIC;                       -- Reset du FPGA par registre interne
      store_enable   : OUT STD_LOGIC;                       -- Autorise le stockage de trame dans la mémoire DMA
      dma_inprogress : IN  STD_LOGIC;                       -- Indique qu'un DMA est en cours
      update_ena     : IN  STD_LOGIC;                       -- Indique que les mémoires d'émission pridoique peuvent être modifiées
      rx_flushn      : OUT STD_LOGIC;                       -- Purge les mémoires de stockage destrames
      topcyc         : IN  STD_LOGIC;                       -- Un pulse indique un début de cycle
 
      -- Paramètres DMA
      dma_base_pa    : OUT STD_LOGIC_VECTOR(31 DOWNTO 0);   -- Adresse de base du DMA coté micro
      dma_timestamp  : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);    -- LSB du numéro de cycle en cours
 
      -- Interfaces de gestion des buffers d'enregitrement des trames Rx et Tx
      bufferrx1_full : OUT STD_LOGIC_VECTOR(31 DOWNTO 0);   -- Buffers non vides en réception coté port 1
      bufferrx2_full : OUT STD_LOGIC_VECTOR(31 DOWNTO 0);   -- Buffers non vides en réception coté port 2
      buffertx_full  : OUT STD_LOGIC_VECTOR(31 DOWNTO 0);   -- Buffers non vides des trames émises par le PIC
      newframe_rx1   : IN  STD_LOGIC_VECTOR(31 DOWNTO 0);   -- Indique un(les) nouveau(x) buffer(s) Rx 1 rempli(s)
      newframe_rx2   : IN  STD_LOGIC_VECTOR(31 DOWNTO 0);   -- Indique un(les) nouveau(x) buffer(s) Rx 2 rempli(s)
      newframe_tx    : IN  STD_LOGIC_VECTOR(31 DOWNTO 0);   -- Indique un(les) nouveau(x) buffer(s) Tx rempli(s)
      rx1_overflow   : IN  STD_LOGIC;                       -- Indique l'impossiblité de stocker une trame reçue sur Rx1
      rx2_overflow   : IN  STD_LOGIC;                       -- Indique l'impossiblité de stocker une trame reçue sur Rx2
      tx_overflow    : IN  STD_LOGIC;                       -- Indique l'impossiblité de stocker une trame Tx
      rx1_badformat  : IN  STD_LOGIC;                       -- Indique une erreur de fromat sur une trame de Rx1
      rx2_badformat  : IN  STD_LOGIC;                       -- Indique une erreur de fromat sur une trame de Rx2
		clk_96			: IN  STD_LOGIC;                       -- Horloge 96MHz synhcrone des traitements LS1 et LS2               
 
      testpoint      : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)     -- Signaux de tests généralistes
     );
END memory_map;
 
ARCHITECTURE rtl of memory_map is
   -- Définition des @ des registres sur le bus Local
   CONSTANT msb_addr       : INTEGER := 5;
   CONSTANT ad_iid1        : STD_LOGIC_VECTOR(msb_addr DOWNTO 0) := "000000";
   CONSTANT ad_iid2        : STD_LOGIC_VECTOR(msb_addr DOWNTO 0) := "000001";
   CONSTANT ad_controle    : STD_LOGIC_VECTOR(msb_addr DOWNTO 0) := "000010";
   CONSTANT ad_statut      : STD_LOGIC_VECTOR(msb_addr DOWNTO 0) := "000011";
   CONSTANT ad_statutrp    : STD_LOGIC_VECTOR(msb_addr DOWNTO 0) := "000100";
   CONSTANT ad_txenaper    : STD_LOGIC_VECTOR(msb_addr DOWNTO 0) := "000101";
   CONSTANT ad_txenaaper   : STD_LOGIC_VECTOR(msb_addr DOWNTO 0) := "000110";
   CONSTANT ad_rx1avai     : STD_LOGIC_VECTOR(msb_addr DOWNTO 0) := "000111";
   CONSTANT ad_rx2avai     : STD_LOGIC_VECTOR(msb_addr DOWNTO 0) := "001000";
   CONSTANT ad_txavai      : STD_LOGIC_VECTOR(msb_addr DOWNTO 0) := "001001";
   CONSTANT ad_dmabasepa   : STD_LOGIC_VECTOR(msb_addr DOWNTO 0) := "001010";
   CONSTANT ad_timestamp   : STD_LOGIC_VECTOR(msb_addr DOWNTO 0) := "001011";
   CONSTANT ad_fifoforce   : STD_LOGIC_VECTOR(msb_addr DOWNTO 0) := "001100";
   CONSTANT ad_testpoint   : STD_LOGIC_VECTOR(msb_addr DOWNTO 0) := "001101";
 
   CONSTANT vec_null : STD_LOGIC_VECTOR(31 DOWNTO 0) := x"00000000";
 
   -- Signaux temporaires de constitution des bus adresse et data (RFU)
   SIGNAL rd_data_int      : STD_LOGIC_VECTOR(31 DOWNTO 0); -- Pour passer le bus data read du local bus de Little à Big Endian
   SIGNAL wr_data_int      : STD_LOGIC_VECTOR(31 DOWNTO 0); -- Pour passer le bus data write du local bus de Little à Big Endian
   SIGNAL rd_reg           : STD_LOGIC_VECTOR(31 DOWNTO 0); -- Signal multiplexé de lecture des registres
   SIGNAL mem_rxflush      : STD_LOGIC;                     -- Pour gérer l'ordre de flush des mémories Rx
 
   -- Registres internes
   SIGNAL reg_iid          : STD_LOGIC_VECTOR(63 DOWNTO 0);
   SIGNAL reg_ctl          : STD_LOGIC_VECTOR(31 DOWNTO 0);
   SIGNAL reg_status       : STD_LOGIC_VECTOR(31 DOWNTO 0);
   SIGNAL reg_statutrp     : STD_LOGIC_VECTOR(31 DOWNTO 0);
   SIGNAL reg_rx1avai      : STD_LOGIC_VECTOR(31 DOWNTO 0);
   SIGNAL reg_rx2avai      : STD_LOGIC_VECTOR(31 DOWNTO 0);
   SIGNAL reg_txavai       : STD_LOGIC_VECTOR(31 DOWNTO 0);
   SIGNAL reg_dmabasepa    : STD_LOGIC_VECTOR(31 DOWNTO 0);
   SIGNAL reg_timestamp    : STD_LOGIC_VECTOR(31 DOWNTO 0);
   SIGNAL reg_testpoint    : STD_LOGIC_VECTOR(31 DOWNTO 0);
 
   -- Compteurs de satut
   SIGNAL cpt_badfmt1      : STD_LOGIC_VECTOR(7 DOWNTO 0);  -- Compteur de trame reçue avec un mauvais FCS sur port 1
   SIGNAL cpt_badfmt2      : STD_LOGIC_VECTOR(7 DOWNTO 0);  -- Compteur de trame reçue avec un mauvais FCS sur port 2
 
   -- Pour détecter un front sur Top_cyc
   SIGNAL top_cyc_r        : STD_LOGIC_VECTOR(2 DOWNTO 0);
   SIGNAL front_topcyc     : STD_LOGIC;
 
BEGIN
   wr_busy <= '0';         -- Aucune opération de WR sur le bus local ne dure plus d'un cycle de clk_sys
   -- Swap des octets des mots de 32 bits (little endian <-> big endian) 
   wr_data_int <= wr_data( 7 DOWNTO  0) & wr_data(15 DOWNTO  8) & 
                  wr_data(23 DOWNTO 16) & wr_data(31 DOWNTO 24);
   rd_data <= rd_data_int( 7 DOWNTO  0) & rd_data_int(15 DOWNTO  8) & 
              rd_data_int(23 DOWNTO 16) & rd_data_int(31 DOWNTO 24);
 
   reg_iid <= iid;         -- Affectation de l'IID du module
 
   -- Affectation des sorties de controle général
   store_enable <= reg_ctl(0);   -- Autorise le stockage des trames pour transfert DMA
 
   -- Affectation des sorties de gestion des buffers de réception
   bufferrx1_full <= reg_rx1avai;
   bufferrx2_full <= reg_rx2avai;
   buffertx_full  <= reg_txavai;
 
   -- Affectation de l'adresse de base du DMA
   dma_base_pa <= reg_dmabasepa;
   dma_timestamp <= reg_timestamp(7 DOWNTO 0);
 
   testpoint <= reg_testpoint(7 DOWNTO 0);
 
   -- Process pour assurer que le reset interne piloté par registre dure un clk
   proc_rstreg : PROCESS(clk_sys)
   BEGIN
      IF (clk_sys'event AND clk_sys = '1') THEN
         -- Gestion du reset interne piloté par registre
         rst_regn <= NOT(reg_ctl(1));
      END IF;
   END PROCESS;
 
   ---------------------------------------------
   -- Process de gestion des écritures dans les registres
   -- Une écriture est efefctive lorsque le signal WR_EN est actif
   -- et que le vecteur WR_ADDR désigne une adresse valable dans le BAR0
   -- L'adresse du registre dans le BAR0 est définie par:
   --   @ BAR0 + Offset_registre ce qui équivaut à @BAR OR Offset_registre
   -- car l'@BAR0 est forcément aligné sur une adresse multiple de la taille du BAR0 (i.e. les LSB sont nuls)
   ---------------------------------------------
   proc_writereg : PROCESS(clk_sys, rst_n)
   BEGIN
      IF (rst_n = '0') THEN
         reg_ctl        <= x"00000000";
         reg_rx1avai    <= x"00000000";
         reg_rx2avai    <= x"00000000";
         reg_txavai     <= x"00000000";
         reg_dmabasepa  <= x"00000000";
         reg_testpoint  <= x"00000000";
      ELSIF (clk_sys'event AND clk_sys = '1') THEN
         IF (wr_en = '1' AND wr_addr = (ADD_BASE_BAR0 OR EXT(ad_controle, NBBIT_ADD_LOCAL))) THEN
            reg_ctl <= wr_data_int;
         END IF;
         -- Gestion du registre de statuts du buffer DMA pour Rx1
         loop_rx1full : FOR i IN 0 TO 31 LOOP
            IF (mem_rxflush = '1') THEN
               reg_rx1avai(i) <= '0';
            ELSIF (newframe_rx1(i) = '1') THEN
            -- Lorsqu'une nouvelle trame est envoyée par DMA
               reg_rx1avai(i) <= '1';     -- On positionne le bit correspondant
            ELSE
               IF (wr_en = '1' AND wr_addr = (ADD_BASE_BAR0 OR EXT(ad_rx1avai, NBBIT_ADD_LOCAL))) THEN
               -- Sur un WR au registre de RX1_AVAI
                  IF (wr_data_int(i) = '1') THEN
                  -- Seul un '1' cleare le registre
                     reg_rx1avai(i) <= '0';
                  END IF;
               END IF;
            END IF;
         END LOOP;
         -- Gestion du registre de statuts du buffer DMA pour Rx2
         loop_rx2full : FOR i IN 0 TO 31 LOOP
         -- Idem pour RX1_AVAI
            IF (mem_rxflush = '1') THEN
               reg_rx2avai(i) <= '0';
            ELSIF (newframe_rx2(i) = '1') THEN
               reg_rx2avai(i) <= '1';
            ELSE
               IF (wr_en = '1' AND wr_addr = (ADD_BASE_BAR0 OR EXT(ad_rx2avai, NBBIT_ADD_LOCAL))) THEN
                  IF (wr_data_int(i) = '1') THEN
                     reg_rx2avai(i) <= '0';
                  END IF;
               END IF;
            END IF;
         END LOOP;
         -- Gestion du registre de statuts du buffer DMA pour Tx
         loop_txfull : FOR i IN 0 TO 31 LOOP
         -- Idem pour RX2_AVAI
            IF (mem_rxflush = '1') THEN
               reg_txavai(i) <= '0';
            ELSIF (newframe_tx(i) = '1') THEN
               reg_txavai(i) <= '1';
            ELSE
               IF (wr_en = '1' AND wr_addr = (ADD_BASE_BAR0 OR EXT(ad_txavai, NBBIT_ADD_LOCAL))) THEN
                  IF (wr_data_int(i) = '1') THEN
                     reg_txavai(i) <= '0';
                  END IF;
               END IF;
            END IF;
         END LOOP;
         IF (wr_en = '1' AND wr_addr = (ADD_BASE_BAR0 OR EXT(ad_dmabasepa, NBBIT_ADD_LOCAL))) THEN
            reg_dmabasepa <= wr_data_int;
         END IF;
         IF (wr_en = '1' AND wr_addr = (ADD_BASE_BAR0 OR EXT(ad_testpoint, NBBIT_ADD_LOCAL))) THEN
            reg_testpoint <= wr_data_int;
         END IF;
      END IF;
   END PROCESS;
 
   -------------------------------------
   -- Process de gestion du registre STATUT
   -------------------------------------
   proc_status : PROCESS(clk_sys, rst_n)
   BEGIN
      IF (rst_n = '0') THEN
         reg_status   <= x"00000000";
      ELSIF (clk_sys'event AND clk_sys = '1') THEN
         IF (wr_en = '1' AND wr_addr = (ADD_BASE_BAR0 OR EXT(ad_statut, NBBIT_ADD_LOCAL))) THEN
         -- Remise à '0' des bits en Write One Clear
         -- Un registre n'est remis à '0' sur WOC que si l'évènement corrspondant n'est pas actif
            IF (wr_data_int(0) = '1') THEN
               reg_status(0)  <= front_topcyc;   
            END IF;
            IF (wr_data_int(1) = '1') THEN
               reg_status(1)  <= rx1_overflow;
            END IF;
            IF (wr_data_int(2) = '1') THEN
               reg_status(2) <= rx2_overflow;
            END IF;
            IF (wr_data_int(3) = '1') THEN
               reg_status(3)  <= tx_overflow;
            END IF;
            IF (wr_data_int(4) = '1') THEN
               reg_status(4) <= rx1_badformat;
            END IF;
            IF (wr_data_int(5) = '1') THEN
               reg_status(5) <= rx2_badformat;
            END IF;
         ELSE
            IF (front_topcyc = '1') THEN
               reg_status(0)  <= '1';
            END IF;
            IF (rx1_overflow = '1') THEN
               reg_status(1)  <= '1';
            END IF;
            IF (rx2_overflow = '1') THEN
               reg_status(2) <= '1';
            END IF;
            IF (tx_overflow = '1') THEN
               reg_status(3)  <= '1';
            END IF;
            IF (rx1_badformat = '1') THEN
               reg_status(4)  <= '1';
            END IF;
            IF (rx2_badformat = '1') THEN
               reg_status(5)  <= '1';
            END IF;            
         END IF;
         reg_status(6) <= update_ena;
         reg_status(7) <= actif_passifn;
         reg_status(23 DOWNTO 8) <= (OTHERS => '0');
         reg_status(31 DOWNTO 24) <= reg_version;
      END IF;
   END PROCESS;
 
   ---------------------------------------------
   -- Process de gestion des registres particuliers
   ---------------------------------------------
   proc_spec : PROCESS(clk_sys, rst_n)
   BEGIN
      IF (rst_n = '0') THEN
         mem_rxflush <= '1';  
         rx_flushn   <= '0';  -- Pour faire un Reset au démarrage
      ELSIF (clk_sys'event AND clk_sys = '1') THEN
         IF (wr_en = '1' AND wr_addr = (ADD_BASE_BAR0 OR EXT(ad_controle, NBBIT_ADD_LOCAL)) AND
             wr_data_int(7) = '1') THEN
         -- Si on écrit un '1' dans le bit 7 du registre de controle
            mem_rxflush <= '1';  -- on mémorise la commande 
         ELSIF (dma_inprogress = '0') THEN
            mem_rxflush <= '0';  -- la commande reste active jusqu'à la fin d'un DMA
         END IF;
         -- le reset du module DMA ne survient que si un DMA n'est pas en cours.
         -- la condition sur mem_rxflush fait en sorte que le rx_flush ne dure qu'1 cycle
         rx_flushn    <= NOT(mem_rxflush) OR dma_inprogress;
      END IF;
   END PROCESS;
 
   --------------------------------------------------
   -- Process de gestion des compteurs de trame avec un mauvais format
   --------------------------------------------------
   proc_fmt : PROCESS(clk_sys, rst_n)
   BEGIN
      IF (rst_n = '0') THEN
         cpt_badfmt1 <= (OTHERS => '0');
         cpt_badfmt2 <= (OTHERS => '0');
      ELSIF (clk_sys'event AND clk_sys = '1') THEN
         IF (rd_en = '1' AND rd_addr = (ADD_BASE_BAR0 OR EXT(ad_statutrp, NBBIT_ADD_LOCAL))) THEN
         -- Les compteurs sont remis à 0 sur un RD du registre. Si l'évènement est actif à ce moment là
         -- on remet pas à 0 mais à 1 -> LSB = évènement
            cpt_badfmt1 <= "0000000" & rx1_badformat;
            cpt_badfmt2 <= "0000000" & rx2_badformat;
         ELSE
            IF (rx1_badformat = '1') THEN
               IF (cpt_badfmt1 /= x"FF") THEN
                  cpt_badfmt1 <= cpt_badfmt1 + 1;
               END IF;
            END IF;
            IF (rx2_badformat = '1') THEN
               IF (cpt_badfmt2 /= x"FF") THEN
                  cpt_badfmt2 <= cpt_badfmt2 + 1;
               END IF;
             END IF;            
         END IF;
      END IF;
   END PROCESS;
 
   reg_statutrp   <= x"0000" & cpt_badfmt2 & cpt_badfmt1;
 
   ---------------------------------------------
   -- Process de gestion d'un free compteur de cycle indiquant le timestamp
   ---------------------------------------------
   front_topcyc <= NOT(top_cyc_r(2)) AND top_cyc_r(1);
   proc_tmstmp : PROCESS(clk_sys, rst_n)
   BEGIN
      IF (rst_n = '0') THEN
         reg_timestamp <= (OTHERS => '0');
         top_cyc_r <= "000";
      ELSIF (clk_sys'event AND clk_sys = '1') THEN
         top_cyc_r <= top_cyc_r(1 DOWNTO 0) & topcyc; -- Pour détecter un front montant de top_cyc qu est généré à 96MHz
         IF (front_topcyc = '1') THEN
            reg_timestamp <= reg_timestamp + 1;
         END IF;
      END IF;
   END PROCESS;
 
   ---------------------------------------------
   -- Multiplexage du bus de donnée local en lecture
   ---------------------------------------------
   -- Sélection entre registres ou mémoires internes selon MSB du bus local
   rd_data_int <= rd_reg;
 
   -- Multiplexage des registres en lecture
   proc_readreg : PROCESS(clk_sys, rst_n)
   BEGIN
      IF (rst_n = '0') THEN
         rd_reg     <= (OTHERS => '0');
      ELSIF (clk_sys'event AND clk_sys = '1') THEN
         CASE rd_addr(msb_addr DOWNTO 0) IS
            WHEN ad_iid1 =>
               rd_reg <= reg_iid(31 DOWNTO  0);
            WHEN ad_iid2 =>
               rd_reg <= reg_iid(63 DOWNTO 32);
            WHEN ad_controle =>
               rd_reg <= reg_ctl;
            WHEN ad_statut =>
               rd_reg <= reg_status;
            WHEN ad_statutrp =>
               rd_reg <= reg_statutrp;
            WHEN ad_rx1avai =>
               rd_reg <= reg_rx1avai;
            WHEN ad_rx2avai =>
               rd_reg <= reg_rx2avai;
            WHEN ad_txavai =>
               rd_reg <= reg_txavai;
            WHEN ad_dmabasepa =>
               rd_reg <= reg_dmabasepa;
            WHEN ad_timestamp =>
               rd_reg <= reg_timestamp;            
            WHEN ad_testpoint =>
               rd_reg <= reg_testpoint;            
            WHEN OTHERS =>
               rd_reg <= reg_status;
         END CASE;
      END IF;
   END PROCESS;
 
END rtl;
 
 

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.