%------------------------------------------------------------------------------
% $Id: document-morpheo-vhdl_generation-fr.tex 94 2008-12-15 11:04:03Z rosiere $
%------------------------------------------------------------------------------

\SEction{Introduction}

Ce document est une aide pour les développeur des générateurs de modèles VHDL de \cpu.
Il est décomposé en 5 sections :
\begin{itemize}
\item Dans la section \ref{tree}, nous présentons l'arborescence des répertoires.
\item Dans la section \ref{vhdl_declaration}, nous expliciterons l'API ({\it Application Programming Interface}) pour la déclaration des signaux et des types du VHDL.
\item Dans la section \ref{vhdl_body}, nous présenterons l'API pour générer le comportement des composants.
\item Dans la section \ref{vhdl_structural}, nous expliquerons la manière de créer des sous composants.
\item Dans la section \ref{example}, nous montrerons quelques exemples.
\end{itemize}

\Section{Arborescence}\label{tree}

Dans le répertoire contenant le projet, nous avons les répertoires suivant :
\begin{description}
\item[IPs/systemC/processor/Morpheo/Documentation/ :] Contient différent document décrivant certain point du projet, dont cette documentation.
\item[IPs/systemC/processor/Morpheo/Behavioural/ :] 
\item[IPs/systemC/processor/Morpheo/Behavioural/include/ :]
  \begin{description}
  \item [Parameters.h :] Contient la classe {\it Parameters}, cette classe définit les paramètres constants.
  \item [Vhdl.h :] Contient la classe {\it Vhdl}. 
  \end{description}
\item[IPs/systemC/processor/Morpheo/Behavioural/\dots/Component :] Chaque composant est inclue dans un répertoire spécifique.
\item[IPs/systemC/processor/Morpheo/Behavioural/\dots/Component/include :]
  \begin{description}
  \item [Parameters.h :] Contient la classe {\it Parameters}, elle dérive de la classe contenu dans le fichier le répertoire {\it \dots/Behavioural/include/}.
  \item [Component.h  :] Contient la classe {\it Component}. Il définit l'interface, les registres ainsi que les méthodes du modèle systemC.
  \item [Types.h      :] Contient les types spéciaux.
  \end{description}
\item[IPs/systemC/processor/Morpheo/Behavioural/\dots/Component/src :]
  \begin{description}
  \item [Component\_transition.cpp :]
  \item [Component\_genMoore.cpp :]
  \item [Component\_genMealy\_XXX.cpp :]

  \item [Component\_vhdl\_declaration.cpp :]
  \item [Component\_vhdl\_body.cpp :]
  \end{description}
\item[IPs/systemC/processor/Morpheo/Behavioural/\dots/Component/Selftest :]
\end{description}

\Section{VHDL : déclaration}\label{vhdl_declaration}

Les déclarations ce font dans le fichier {\it Component\_vhdl\_declaration.cpp}.

\subSection{Interfaces}
L'interface est définit dans le modèle SystemC. Il n'ont pas nécessaire de la redéfinir pour le modèle VHDL.

La nomenclature est la suivante :
\begin{itemize}
\item La direction en minuscule ({\it in}, {\it out}).
\item Le nom de l'interface en majuscule ({\it READ}, {\it PUSH}, \dots).
\item Le numéro de l'interface (la première interface aura le numéro 0. S'il n'y a qu'une interface, celle ci aura tout de même le numéro 0).
\item Le nom du signal en majuscule ({\it VAL}, {\it ADDRESS}, \dots).
\end{itemize}

Par exemple pour la 2 ème interface de lecture d'un banc de registre :
\begin{verbatim}
 in_READ_1_VAL     : in  std_logic;
out_READ_1_ACK     : out std_logic;
 in_READ_1_ADDRESS : in  std_logic_vector(8 downto 0);
out_READ_1_DATA    : out std_logic_vector(31 downto 0);
\end{verbatim}

Chaque composent (aussi bien combinatoire que séquentielle) possède un signal d'horloge et un signal de reset. (Ce dernier est actif à l'état bas). Ils ont tout les deux le même nom quelque soit le composant.
\begin{verbatim}
 in_CLOCK  : in std_logic;
 in_NRESET : in std_logic;
\end{verbatim}

\subSection{Types}

Le type de base utilisé est le {\it std\_logic\_vector} (ou std\_logic si le vecteur est sur un seul bit). Pour cela on utilise la fonction suivante :

\begin{verbatim}
std::string std_logic (uint32_t size);
\end{verbatim}

Pour accéder à une partie du vecteur on utilise la fonction {\it std\_logic\_range}. Elle a les prototypes suivant :
\begin{verbatim}
std::string std_logic_range (uint32_t size,
                             uint32_t max ,
                             uint32_t min ,
                             bool force=false);
std::string std_logic_range (uint32_t max ,
                             uint32_t min ,
                             bool force=false);
std::string std_logic_range (uint32_t size,
                             bool force=false);
\end{verbatim}

La première fonction fais un test sur la taille que la seconde ne fait pas.
L'argument de la troisième définit la taille (ce qui implique que la borne minimum est 0 et la borne maximum est size-1).
Toute les surcharges ont le bolléen optionnel {\it force}. S'il est à faux, alors des tests seront effectués sur les bornes et la taille, sinon aucun test n'est effectué.

Par exemple :
\begin{verbatim}
std_logic_range(4,false) renvoie "(3 downto 0)".
std_logic_range(1,false) renvoie "(0)".
std_logic_range(1,true ) renvoie "(0 downto 0)".
\end{verbatim}

Pour les types plus complexe, la classe {\it Vhdl} possède une méthode générique. Le premier argument est le nom du type le second est le type.

\begin{verbatim}
void set_type (std::string name,
               std::string type);
\end{verbatim}

L'exemple suivant définit un type représentat un tableau de {\it nb\_word} mots de {\it size\_word} bit chacun :
\begin{verbatim}
vhdl->set_type ("Tregfile", 
                "array "+std_logic_range(nb_word)+" of "+std_logic(size_word));
\end{verbatim}

\subSection{Constantes}

La déclaration de constante, ce fait avec la méthode {\it set\_constant} de la classe {\it Vhdl}. Les différentes surcharges de cette méthode est le type des arguments {\it type} et {\it init}. 

\begin{verbatim}
void set_constant (std::string name,
                   std::string type,
                   std::string init);
void set_constant (std::string name,
                   uint32_t    size,
                   std::string init);
void set_constant (std::string name,
                   uint32_t    size,
                   uint32_t    init);
\end{verbatim}

Par exemple pour coder les états d'un automate à 5 états en One Hot :
\begin{verbatim}
vhdl->set_constant ("State_idle",5,1);
\end{verbatim}

Dans le cas de signaux de type {\it std\_logic}, au lieu de déclarer des constantes, il existe deux fonctions permettant d'utiliser des constantes directement dans le corps du composant.
La première est {\it std\_logic\_others}. Elle permet de définir des constantes dont soit les bits sont à pleins un soit à plein zéro.

\begin{verbatim}
std::string std_logic_others (uint32_t size,
                              bool cst  );
\end{verbatim}

Pour toute les autres constantes, la méthode {\it std\_logic\_conv} transforme un entier en {\it std\_logic\_vector}.

\begin{verbatim}
std::string std_logic_conv (uint32_t    size,
                            std::string value);
std::string std_logic_conv (uint32_t    size,
                            uint32_t    value);
\end{verbatim}


\subSection{Signaux internes}

Les signaux internes sont définit grâce au méthode {\it set\_signal}. Le premier argument est le nom du signal. Le second est soit un type soit une taille (dans le cas où le type est un  {\it std\_logic\_vector}).
\begin{verbatim}
void set_signal (std::string name,
                 std::string type);
void set_signal (std::string name,
                 uint32_t    size);
\end{verbatim}

La méthode est également surchargé si le signal à besoin d'une initialisation.

\begin{verbatim}
void set_signal (std::string name,
                 std::string type,
                 std::string init);
void set_signal (std::string name,
                 uint32_t    size,
                 std::string init);
void set_signal (std::string name,
                 uint32_t    size,
                 uint32_t    init);
\end{verbatim}

En vhdl il est possible de renommer une champ d'un signal. Ceci ce fait à l'aide de la fonction {\it set\_alias}. Elle prend 4 arguments. Le premier étant le nom du signal après le renommage. le second est soit le type, soit la taille du {\it std\_logic\_vector} du signal rénommé. Les deux derniers conserné le signal à renommé : le nom de ce dernier ainsi que l'intervalle. Pour le dernier paramètre il est recommandé d'utilisé la fonction {\it std\_logic\_range}.

\begin{verbatim}
void set_alias (std::string name1 ,
                std::string type1 ,
                std::string name2 ,
                std::string range2);
void set_alias (std::string name1 ,
                uint32_t    size1 ,
                std::string name2 ,
                std::string range2);
\end{verbatim}


\Section{VHDL : comportement}\label{vhdl_body}

Le comportement du composant est définit dans le fichier  {\it Component\_vhdl\_body.cpp}.

Il n'y a pas de fonction aidant à l'écriture du Vhdl.
La méthode {\it set\_body} permet de définir une ligne de code VHDL. Un retour à la ligne est automatiquement inséré. Le premier argument est pour l'indentation.
\begin{verbatim}
void set_body (uint32_t    depth,
               std::string text );
void set_body (std::string text );
\end{verbatim}

Pour les commentaires, il y a la fonction {\it set\_comment}.
\begin{verbatim}
void set_comment (uint32_t    depth,
                  std::string text );
void set_comment (std::string text );
\end{verbatim}



\Section{VHDL : structurelle}\label{vhdl_structural}

\Section{Exemples}\label{example}

\subSection{Banc de Registres Monolithique}

\subsubSection{Fichier RegisterFile\_Monolithic\_vhdl\_declaration.cpp}
\begin{verbatim}
void RegisterFile_Monolithic::vhdl_declaration (Vhdl * & vhdl)
{
  vhdl->set_type ("Tregfile", "array " + std_logic_range(_param->_nb_word,true)+
                              " of "+
                              std_logic(_param->_size_word));

  vhdl->set_signal ("reg_DATA", "Tregfile");
};
\end{verbatim}
\subsubSection{Fichier RegisterFile\_Monolithic\_vhdl\_body.cpp}
\begin{verbatim}
void RegisterFile_Monolithic::vhdl_body (Vhdl * & vhdl)
{
  vhdl->set_body   (0,"");
  vhdl->set_comment(0,"---------------------------------------------------");
  vhdl->set_comment(0," Ackitement");
  vhdl->set_comment(0,"---------------------------------------------------");
  vhdl->set_body   (0,"");

  for (uint32_t i = 0; i < _param->_nb_port_read; i++)
    vhdl->set_body   (0,"out_READ_"+toString(i)+"_ACK  <= '1';");
  for (uint32_t i = 0; i < _param->_nb_port_write; i++)
    vhdl->set_body   (0,"out_WRITE_"+toString(i)+"_ACK <= '1';");

  vhdl->set_body   (0,"");
  vhdl->set_comment(0,"---------------------------------------------------");
  vhdl->set_comment(0," Read RegisterFile");
  vhdl->set_comment(0,"---------------------------------------------------");
  vhdl->set_body   (0,"");
  
  for (uint32_t i = 0; i < _param->_nb_port_read; i++)
    {
      std::string str_address;
      if (_param->_have_port_address)
        str_address = "conv_integer(in_READ_"+toString(i)+"_ADDRESS)";
      else
        str_address = "0";

      vhdl->set_body   (0,"out_READ_"+toString(i)+"_DATA <= reg_DATA ("+str_address+
                           ") when in_READ_"+toString(i)+"_VAL = '1' else "+
                           std_logic_others(_param->_size_word,0)+";");
    }

  vhdl->set_body   (0,"");
  vhdl->set_comment(0,"---------------------------------------------------");
  vhdl->set_comment(0," Write RegisterFile");
  vhdl->set_comment(0,"---------------------------------------------------");
  vhdl->set_body   (0,"");

  vhdl->set_body   (0,"RegisterFile_write: process (in_CLOCK)");
  vhdl->set_body   (0,"begin  -- process RegisterFile_write");
  vhdl->set_body   (1,"if in_CLOCK'event and in_CLOCK = '1' then");
  
  for (uint32_t i = 0; i < _param->_nb_port_write; i++)
    {
      std::string str_address;
      if (_param->_have_port_address)
        str_address = "conv_integer(in_WRITE_"+toString(i)+"_ADDRESS)";
      else
        str_address = "0";

      vhdl->set_body   (2,"if (in_WRITE_"+toString(i)+"_VAL = '1') then");
      vhdl->set_body   (3,"reg_DATA("+str_address+") <= in_WRITE_"+toString(i)+"_DATA;");
      vhdl->set_body   (2,"end if;");
    }

  vhdl->set_body   (1,"end if;");
  vhdl->set_body   (0,"end process RegisterFile_write;");
};
\end{verbatim}

\subsubSection{Fichier RegisterFile\_Monolithic.vhdl}
\begin{verbatim}
library ieee;
  use ieee.numeric_bit.all;       
  use ieee.numeric_std.all;       
  use ieee.std_logic_1164.all;    
  use ieee.std_logic_arith.all;   
  use ieee.std_logic_misc.all;    
--use ieee.std_logic_signed.all;  
  use ieee.std_logic_unsigned.all;
--use ieee.std_logic_textio.all;  


library work;
use work.RegisterFile_Monolithic_Pack.all;


entity RegisterFile_Monolithic is
  port ( in_CLOCK          : in  std_logic;
         in_NRESET         : in  std_logic;
         in_READ_0_VAL     : in  std_logic;
        out_READ_0_ACK     : out std_logic;
         in_READ_0_ADDRESS : in  std_logic_vector(8 downto 0);
        out_READ_0_DATA    : out std_logic_vector(31 downto 0);
         in_WRITE_0_VAL    : in  std_logic;
        out_WRITE_0_ACK    : out std_logic;
         in_WRITE_0_ADDRESS: in  std_logic_vector(8 downto 0);
         in_WRITE_0_DATA   : in  std_logic_vector(31 downto 0)
       );
end RegisterFile_Monolithic;

architecture behavioural of RegisterFile_Monolithic is
  type Tregfile   is array (511 downto 0) of std_logic_vector(31 downto 0);

  signal reg_DATA : Tregfile;

begin
  -----------------------------------------------------
  -- Ackitement
  -----------------------------------------------------
  
  out_READ_0_ACK  <= '1';
  out_WRITE_0_ACK <= '1';
  
  -----------------------------------------------------
  -- Read RegisterFile
  -----------------------------------------------------
  
  out_READ_0_DATA <= reg_DATA (conv_integer(in_READ_0_ADDRESS)) 
                     when in_READ_0_VAL = '1'
                     else (others => '0');
  
  -----------------------------------------------------
  -- Write RegisterFile
  -----------------------------------------------------
  
  RegisterFile_write: process (in_CLOCK)
  begin  -- process RegisterFile_write
    if in_CLOCK'event and in_CLOCK = '1' then
      if (in_WRITE_0_VAL = '1') then
        reg_DATA(conv_integer(in_WRITE_0_ADDRESS)) <= in_WRITE_0_DATA;
      end if;
    end if;
  end process RegisterFile_write;
end behavioural;

\end{verbatim}
