%------------------------------------------------------------------------------ % $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}