Baniere Saphir Control
http://www.saphir-control.fr/

bar


BACK

Tous ces articles en ligne sur Scilab ont été écrits pour LINUX MAGAZINE FRANCE par les développeurs du Scilab Group. Les articles sont sous licence FDL (Free Documentation Licence)

La génération de code dans Scicos

Dans l'article paru dans le numéro précédent nous avions montré en détail quelles sont, dans Scicos , les différentes étapes necéssaires à la compilation et la simulation de schéma-blocs (représentation d'un modèle de systèmes dynamiques). Nous présentons ici une nouvelle boite à outils dans Scicos, dédiée à la génération automatique de code, à partir d'un schéma-blocs.

1   Introduction

Scicos (Scilab Connected Object Simulator, http://www-rocq.inria.fr/scilab) est un environnement puissant, convivial et bien sur gratuit, pour la modélisation et la simulation de systèmes dynamiques hybrides (constitués d'éléments continus, discrets, événementiels). L'exemple le plus classique de ces systèmes est un modèle d'environnement physique continu, commandé par un contrôleur discret, dont la simulation est l'interprétation d'un algorithme, défini par le compilateur Scicos (cf. numéro 35 de Linux Magazine) et décrivant le fonctionnement du système dans son ensemble. Le schéma-bloc de la figure 1 illustre la représentation d'un tel système. Le bloc Horloge génère des activations périodiques, imposant une cadence au contrôleur.



Figure 1: Un système hybride typique

La simulation d'un schéma-bloc hybride (continu-discret) est obtenue par l'exécution d'un algorithme décrivant le fonctionnement du système dynamique (modélisé par le schéma-bloc) dans son ensemble (cf. numéro 35 de Linux Magazine). Signalons que, de par les interactions entre les différentes parties d'un système dynamique, l'algorithme de simulation ne peut pas être décomposable en entités séparées. Autrement dit, le fonctionnement d'une partie du système ne peut pas être décrit par une partie distincte de l'algorithme de simulation. Dans le contexte des applications industrielles à mettre en oeuvre (après étude), la plupart du temps, seul le modèle de contrôleur discret est concerné par une implantation sur un calculateur (architecture embarquée). Le modèle de contrôleur discret étant défini par un algorithme lors de la simulation (dans Scicos), il ne reste plus qu'à générer cet algorithme sous la forme d'un code, pour qu'il puisse être implanté sur une architecture embarquée. Il existe maintenant dans Scicos, une nouvelle boîte à outils dédiée à la génération automatique de code, qui permet de fournir sous la forme d'un code (en langage C) et de manière séparée, l'algorithme décrivant n'importe quelle partie du système. Cette nouvelle fonctionnalité peut être utilisée à la fois pour accélérer la simulation Scicos (en remplaçant un super-bloc par un bloc standard) ou pour générer du code à implanter sur une architecture embarquée (cf. figure 2).

{short description of image}


Figure 2: Un même environnement

En principe la génération de code pourrait concerner aussi bien le système dans son ensemble qu'une de ses parties, mais puisque dans les faits, les produits visés par les applications industrielles ne concernent que la mise en oeuvre du modèle de contrôleur discret, nous avons donc limiter la génération automatique de code, à des sous-ensembles de blocs purement discrets. D'ailleurs, comme bien souvent les architectures sont embarquées (et donc avec des contraintes dimensionnelles), il faut savoir que le code généré pour des sous-ensembles continu impose l'intégration d'un solveur numérique nécessitant des ressources mémoires plus qu'encombrantes pour de telles architectures.

2   Le pré-traitement du super-bloc

La première étape consiste à isoler le sous-ensemble de blocs définissant le contrôleur (discret), dans un super-bloc. Et puisque nous nous limitons à des sous-ensembles de blocs purement discrets, cela exclu les blocs ayant un état continu (comme par exemple les bloc de type zcross). Notons aussi que l'utilisation des blocs ayant une fonction de simulation en langage Scilab (cf. numéro 19 de Linux Magazine) n'est pas possible pour l'instant. Dans la pratique, cette nouvelle boîte à outils permet de générer le code C associé à un super-bloc, mais aussi de remplacer le super-bloc dans l'éditeur Scicos par un bloc compilé équivalent. Ainsi, le code obtenu peut être non seulement implanté sur une architecture embarquée (pour être utilisé par n'importe quel programme ne nécessitant pas forcément les routines Scilab), mais aussi réutilisé dans le schéma bloc Scicos, en vue d'améliorer les performances de simulation. Pour générer le code de l'algorithme de fonctionnement spécifique à un sous-ensemble de schéma bloc, il faut considérer le super-bloc indépendamment des autres éléments l'environnant. Pour ce faire, il est nécessaire d'isoler au préalable les entrées et sorties du super-bloc et de les remplacer automatiquement par des blocs fictifs, appelés respectivement des ``capteurs'' et des ``actionneurs''. Ceci de manière à permettre à l'utilisateur, lors de l'implantation du code sur une architecture embarquée, d'adapter les entrées et sorties du super-bloc à l'environnement ad hoc.

2.1   Au niveau des ports d'entrées réguliers

Si l'on considère un super-bloc au sein d'un schéma, ses ports d'entrée régulière reçoivent des signaux évoluant en fonction d'activations. La première étape de la génération de code est de considérer le super-bloc au même titre qu'un schéma Scicos et de le compiler. Le résultat de la compilation est alors utilisé pour générer du code en langage C. Le fait est cependant que la compilation n'est pas toujours rigoureusement concevable car le contenu du super-bloc n'est pas exactement celui d'un schéma bloc, en particulier en ce qui concerne les ports d'entrée régulière. Un schéma bloc ne peut pas avoir des ports d'entrée régulière extérieurs à son environnement, sans quoi les activations de ces signaux d'entrées ne sont pas connues et ne peuvent donc pas être prises en compte à la compilation. Il en va de même pour les ports d'entrée régulière du super-bloc qui sont ainsi considérées dans son environnement extérieur au même titre que leurs activations. C'est pourquoi les ports d'entrée régulière qui sont alors remplacés par des blocs fictifs doivent en plus être activés artificiellement. Ainsi, nous choisissons de relier, systématiquement chaque ``capteur'', aux ports d'entrée d'activation du super-bloc. En effet, ne connaissant pas à priori le conditionnement des entrées régulières, ce choix nous permet de traiter de manière générale les connections sur les ports du super-bloc. Le super-bloc de la figure 3 par exemple, après la phase de traitement est transformé comme sur la figure 4.



Figure 3: Un simple super-bloc





Figure 4: Après la phase de pré-traitement

Notons que dans le code généré, les appels aux entrées du super-bloc (représentées par des ``capteurs'') sont systématiquement mis en commentaire, afin de permettre à l'utilisateur d'utiliser facilement les entrées de son choix.

2.2   Au niveau des ports d'entrée d'activation

Le super-bloc peut posséder zéro, un ou plusieurs ports d'entrée d'activations. Ce qui nécessite des modifications, à l'intérieur du super-bloc, en fonction de trois situations possibles :
  1. le super-bloc ne possède pas de port d'entrée d'activation : dans ce cas l'activation est héritée du schéma bloc original. Pour compiler le super-bloc nous avons besoin d'introduire un signal d'activation sans quoi le compilateur le considère comme étant inactif. Nous introduisons un bloc fictif pour activer les ``capteurs'', de manière à exploiter la notion de l'héritage à travers les autres blocs constituant le super-bloc (cf. fig 5). Ce bloc fictif d'activation est caractérisé par :



    Figure 5: Le super-bloc ne possède pas de port d'entrée d'activation

  2. le bloc possède un ou plusieurs port(s) d'entrée d'activation : de la même manière que précédemment nous introduisons un bloc fictif pour activer les ``capteurs''. Mais si le bloc possède plusieurs ports d'entrée d'activation, cette situation est plus délicate car nous devons pouvoir considérer le cas ou les signaux d'entrées d'activations sont synchrones. Pour cette raison, toutes les possibilités doivent être prises en compte. Prenons par exemple le cas où nous avons deux ports d'entrée d'activations, il faut envisager la possibilité où l'activation est reçue par le premier port, la possibilité où elle est reçue par le second port et la possibilité où deux activations synchrones sont reçues par les deux ports. C'est la raison pour laquelle dans cette situation nous ajoutons au super-bloc un bloc fictif caractérisé par :



    Figure 6: Le super-bloc possède plus d'un port d'entrée d'activation

Ces modifications sont effectuées de manière automatique pendant la phase de génération de code, le processus de transformation étant complètement transparent pour l'utilisateur.

3   La procédure pour la génération de code

La génération de code dans Scicos est une procédure qui a pour résultat la création des deux fichiers caractérisant systématiquement chaque bloc Scicos (cf. numéro 19 de Linux Magazine) : Dans la fenêtre de l'éditeur Scicos, la génération de code s'exécute par un nouveau bouton (Code) dans la barre du menu Generation. Après avoir placé le schéma bloc désiré dans un super-bloc, l'action sur ce bouton permet de générer le code correspondant et de remplacer le super-bloc par un nouveau bloc standard ``équivalent''. Dès que l'utilisateur désigne par un clic de souris le super-bloc concerné, l'action sur le bouton Code lance la fonction Scilab ``do_GenerateCode''. Le résultat obtenu est la transformation du super-bloc par un nouveau bloc standard ``équivalent'', qui possède le même nombre de ports d'entrée-sortie (régulière et d'activations) que le super-bloc. Pour réaliser cette substitution, deux fonctions sont générées : La fonction ``do_GenerateCode'', représentée à la figure 7, exécute les étapes suivantes :
  1. la vérification que le super-bloc est compilable séparément : il ne possède pas de port de sortie d'activations, ne contient pas de blocs activés en continu.
  2. le pré-traitement du contenu du super-bloc (ajout de bloc fictif, remplacement des blocs d'entrée/sortie par des capteurs/actionneurs etc...).
  3. la compilation du sous-ensemble du schéma bloc, constituant le super-bloc. Cette étape est exécutée par les fonctions Scilab (``c_pass1'' et ``c_pass2''), afin de générer les tables de programmation nécessaires à la construction de la fonction de simulation du nouveau bloc.
  4. la génération de la fonction d'interface graphique du nouveau bloc, par la fonction Scilab ``c_make_gui'',
  5. la génération de la fonction de simulation par la fonction Scilab ``c_make_main'', obtenue en trois parties :
  6. la compilation de la fonction de simulation du nouveau bloc et son lien dynamique avec la session Scicos en cours, pour permettre la prise en compte dans la simulation, des modifications du schéma bloc Scicos.


{short description of image}


Figure 7: La fonction do_generate_code.sci

3.1   Un exemple simple

Observons le schéma bloc simple de la figure 8. Le bloc Num(z)/Den(z) réalise un filtre numérique décrit par sa transformée en ``z'' associée. Supposons que nous voulons réunir ce bloc et le bloc sin pour former un seul bloc dans le schéma Scicos, et pour générer le code adapté. Cet exemple est bien entendu trop simple pour être d'un réel intérêt, mais nous l'utilisons seulement pour illustrer l'idée. Dans cet exemple le super-bloc et le bloc Modulo Counter ont le même conditionnement. Les modifications apportées par la génération de code, font que le bloc sin hérite des activations du bloc Modulo Counter. L'activation du bloc sin est donc identique avant et après la génération de code. Après avoir placé les deux blocs dans un super-bloc en utilisant le bouton Region to Super block du menu File, il suffit d'abord de cliquer sur le bouton Generation dans le menu Code (cf. figure 8), puis sur le super-bloc. Sur la figure 9 on observe le résultat obtenu : le super-bloc est ``compilé'' et remplacé par un nouveau bloc standard appelé foo dans cet exemple (l'utilisateur peut spécifier le nom de son choix).

{short description of image}


Figure 8: Un exemple très simple.



{short description of image}


Figure 9: Le schéma après compilation du super-bloc.

Le nouveau schéma Scicos doit bien entendu avoir un comportement qui doit être complètement équivalent au précédent lors de la simulation. Sur la figure 10 est illustré le résultat de simulation qui est bien sur identique, avant et après les modifications.



Figure 10: Le résultat de simulation.

Le fichier ``foo.c'' obtenu contient le code généré, constitué de la déclaration des différents paramètres et du coeur du programme, comprenant les procédures ``foo'', ``foomain1'' et ``foomain2''. Nous présentons pour le schéma de la figure 9 le coeur du programme généré, afin de le commenter.

3.1.1   La procédure ``foo''

Cette procédure indique que lorsque le nouveau bloc foo est activé, il doit mettre à jour :
/* SCILAB Computational function  */
/*     Copyright INRIA */
/*     Generated by Code_Generation toolbox of Scicos with scilab-2.6 */
/*     date : Year 2001, Month 12, Day 20 */
#include <stdio.h>
#include <string.h>
#include "/home/djenidi/scilab-2.6/routines/machine.h"
#include "/home/djenidi/scilab-2.6/routines/sun/link.h"
#include "/home/djenidi/scilab-2.6/routines/scicos/scicos.h"
.
.
.
.
{
  /*     Copyright INRIA */
  /*     Scicos block simulator */
 
 
  /* Parameter adjustments */
  --y1;
  --ipar;
  --rpar;
  --tvec;
  --z;
  
  /* Function Body */
  z[3]=u1[1];  
  totalnevprt= *nevprt;
  if (*flag == 1) { /* update outputs */
    foomain1(&(z[1]),t);
  } 
  else if (*flag == 2) { /* update discrete states */
    foomain2(&(z[1]),t);
  } 
  if (*ierr != 0) { 
    return 0; 
  }
  y1[1]=z[4];  
  return 0; 
} /* foo */  
Dans les procédures suivantes, pour pouvoir appeler des routines écrites en fortran, nous utilisons la directive de compilation C2F qui se trouve dans le fichier machine.h.

3.1.2   La procédure foomain1

La procédure foomain1 fait appel à la procédure fooddoit1 qui elle même consiste en des appels aux procédures de simulation dsslti (bloc Num(z)/Den(z)), capteur1 (entrée régulière du bloc foo) et sinblk (bloc sin), afin de mettre à jour les registres de sortie régulière. Signalons qu'en ce qui concerne capteur1, l'appel à sa procédure de simulation a été mis automatiquement en commentaire afin de permettre à l'utilisateur de faire appel à l'entrée de son choix. Notons que pour assurer sa récursivité, la procédure fooddoit1 fait aussi appel à la procédure fooeddoit1 dont le contenu lui est identique.
int foomain1(double *z, double *t)  
{
  double *rpar; 
  integer *nrpar, *ipar, *nipar;
  integer pointi[ ] = {0};
  fooddoit1(
     &(z[0]),&(zptr[0]),
            &t0,&(tevts[0]),
            &(evtspt[0]),&(nevts[0]),&(pointi[0]),
            &(outptr[0]),
            &(clkptr[0]),&(ordptr[0]),&(ordclk[0]),
     &nordcl,&(rpar[0]),&(ipar[0]),
            &(rdfunptr[0]),&(funtyp[0]),&(z[2]),
     &(z[7]));
} 
/* ddoit1.c */ 
/* Subroutine */ int fooddoit1( z, zptr, told, 
    tevts, evtspt, nevts, pointi, outptr, 
    clkptr, ordptr, ordclk, nordcl,  
    rpar, ipar, funptr, funtyp, outtb, iwa) 
  
     double *z; 
     integer *zptr; 
     double *told,  *tevts; 
     integer *evtspt, *nevts, *pointi, *outptr; 
     integer *clkptr, *ordptr, *ordclk, *nordcl; 
     double *rpar, *outtb; 
     integer  *ipar, *funptr, *funtyp; 
     integer *iwa; 
{ 
  /* System generated locals */ 
  integer ordclk_dim1, ordclk_offset, i1, i2, i3; 
.
.
.
. 
    ++iwa[9]; 
    iwa[iwa[9]] = keve;
 
 switch(keve) {
 case 1:

 
     flag = 1; 
      nevprt=1;
  args[0]=&(outtb[1]);
  args[1]=&(outtb[3]);

 C2F(dsslti) (&flag, &nevprt,told, &(w[1]), &(x[1]), &nrd_0,
&(z[1]),&nrd_1, tvec, &ntvec, &(rpar[1]), &nrd_4, &(ipar[1]), &nrd_0
 , (double *)args[0], &nrd_1, (double *)args[1], &nrd_1);

 if(flag < 0 ) {
  *ierr = 5 - flag; 
         return 0;
 } 
 
 
 
/*    flag = 1; 
      nevprt=1;
  args[0]=&(outtb[1]);
  args[1]=&(outtb[2]);

 C2F(capteur1) (&flag, &nevprt,told, &(w[1]), &(x[1]), &nrd_0, &(z[1]), 
&nrd_0, tvec, &ntvec, &(rpar[1]), &nrd_0, &(ipar[1]), &nrd_1
 , (double *)args[0], &nrd_0, (double *)args[1], &nrd_1);

 if(flag < 0 ) {
  *ierr = 5 - flag; 
         return 0;
 }*/
 
 
 
     flag = 1; 
      nevprt=1;
  args[0]=&(outtb[2]);
  args[1]=&(outtb[1]);
 C2F(sinblk) (&flag, &nevprt,told, &(w[1]), &(x[1]), &nrd_0, &(z[1]), 
&nrd_0, tvec, &ntvec, &(rpar[1]), &nrd_0, &(ipar[1]), &nrd_0
 , (double *)args[0], &nrd_1, (double *)args[1], &nrd_1);
 
 if(flag < 0 ) {
  *ierr = 5 - flag; 
         return 0;
 } 
 
 
 break;
 }  
  
 switch(keve) {
 case 1:
 break;
 }  
 
 } 

3.1.3   La procédure ``foomain2''

La procédure foomain2 fait appel à la procédure fooddoit2 qui elle même consiste en des appels à la procédure de simulation dsslti du bloc Num(z)/Den(z), afin de mettre à jour le registre d'état discret. Comme précédement pour la procédure fooddoit1, pour assurer sa récursivité la procédure fooddoit2 fait aussi appel à la procédure fooeddoit2 dont le contenu lui est identique.
int foomain2(double *z, double *t)  
{
  double *rpar; 
  integer *nrpar, *ipar, *nipar;
  integer pointi[ ] = {0};
  fooddoit2(
     &(z[0]),&(zptr[0]),
            &t0,&(tevts[0]),
            &(evtspt[0]),&(nevts[0]),&(pointi[0]),
            &(outptr[0]),
            &(clkptr[0]),&(ordptr[0]),&(ordclk[0]),
     &nordcl,&(rpar[0]),&(ipar[0]),
            &(rdfunptr[0]),&(funtyp[0]),&(z[2]),
     &(z[7]));

} 
/* ddoit1.c */ 
/* Subroutine */ int fooddoit2( z, zptr, told, 
    tevts, evtspt, nevts, pointi, outptr, 
    clkptr, ordptr, ordclk, nordcl,  
    rpar, ipar, funptr, funtyp, outtb, iwa) 
  
     double *z; 
     integer *zptr; 
     double *told,  *tevts; 
     integer *evtspt, *nevts, *pointi, *outptr; 
     integer *clkptr, *ordptr, *ordclk, *nordcl; 
     double *rpar, *outtb; 
     integer  *ipar, *funptr, *funtyp; 
     integer *iwa; 
{ 
  /* System generated locals */ 
  integer ordclk_dim1, ordclk_offset, i1, i2, i3; 
.
.
.
. 

    /* Function Body */ 
  
/*     .  update continuous and discrete states on event */
 if (iwa[9] == 0) {
    return 0 ;
 }
  i1 = iwa[9];
    for (i = 1; i <= i1; ++i) {
       keve = iwa[i];
       switch(keve) {
       case 1:
         flag = 2;
         nevprt=1;
  
  args[0]=&(outtb[1]);
  args[1]=&(outtb[3]);

         C2F(dsslti) (&flag, &nevprt,told, &(w[1]),
         &(x[1]), &nrd_0, &(z[1]), &nrd_1, tvec, &ntvec, &(rpar[1]), &nrd_4,
         &(ipar[1]), &nrd_0 , (double *)args[0], &nrd_1, (double *)args[1],
         &nrd_1);
 
  if(flag < 0 ) {
  *ierr = 5 - flag; 
         return 0;
  } 
 

 
      break;
    }  
  }  
} /* ddoit2 */      
       }  

3.2   Les problèmes en matière d'héritage

Un bloc standard peut être activé aussi bien par héritage des activations de ses entrées régulières ou directement par ses ports d'entrées d'activations. Un schéma bloc (super-bloc) peut cependant contenir des blocs qui sont en partie activés par héritage et d'autres par activation directe. Compiler de tels schémas peut dans certains cas mener à des erreurs chronométriques, en particulier lorsque des blocs sont activés par héritage, de l'extérieur du super-bloc. Dans ce cas, il est clairement impossible de construire un bloc standard ayant exactement la même commande que le super-bloc. Prenons pour exemple le schéma de la figure 11, qui est une version légèrement modifiée de notre exemple précédent. Ici le bloc sin est activé par héritage des activations à travers le premier bloc Clock (celui qui active le bloc MODULO COUNTER), tandis que le filtre numérique est activé par le second bloc Clock. Le résultat de simulation dans ce cas est donné dans la figure 12 pour un choix particulier de la fréquence et de la phase des horloges.

{short description of image}


Figure 11: Un exemple de problème chronométrique.





Figure 12: Résultats de simulation du schéma de la figure 11.

Après la génération de code, les deux blocs sin et le filtre numérique (placé dans un super-bloc) sont remplacés par un seul bloc standard (foo) (cf. figure 13. Le traitement de la boîte à outils considère dans ce cas que le nouveau bloc créé est activé à travers un port d'entrée d'activation, et non par héritage. Cela implique que le schéma Scicos modifié ne doit pas avoir exactement la même commande dynamique qu'auparavant, comme on peut le voir par une simple simulation (cf. figure 14). Dans ce cas, il n'y a tout simplement aucune solution pour remplacer le super-bloc par un seul bloc standard et préserver la commande dynamique dans chaque situation ; la génération de code a seulement donnée le meilleur choix possible.

{short description of image}


Figure 13: Schéma modifié.





Figure 14: Résultats de simulation correspondant au schéma modifié.

Ce type de problème n'est pas rencontré souvent car pour cela le schéma Scicos doit contenir au moins deux horloges indépendantes activant les blocs à l'intérieur du sous-ensemble en question. Et même lorsqu'il y a présence de plus d'un bloc Clock, souvent une simple inspection visuelle permet de s'assurer qu'aucun problème chronométrique ne se produise après la compilation du super-bloc. Mais il existe des schémas complexes pour lesquels il serait trop fastidieux de faire une telle inspection. Ceci nous amène à proposer une autre boîte à outils : Check bientôt disponible sur le site http://www-rocq.inria.fr/scilab, donnant la possibilité à l'utilisateur, de détecter automatiquement si deux blocs connectés ne sont pas activés par la même source d'activation. De cette manière libre cours est laissé à l'utilisateur pour apprécier les effets du conditionnement signalé, avant d'envisager la génération de code.

4   Un exemple

Etudions maintenant un exemple légèrement plus complexe, traduisant en l'occurrence l'algorithme exprimé par le programme Scilab suivant :
for i = 1 : n 
    if sin(i) > 0 then 
       S = S + 1 
    else 
       for j = 1 : n 
          if sin(j)^2 > 0 then 
             S = S - 1 
          end 
       end 
    end 
end 
A partir de la définition de cet algorithme, nous construisons un schéma Scicos pour le mettre en oeuvre. Cela peut être réalisé dans Scicos de différentes manières ; l'algorithme peut même être modélisé par un seul bloc. Néanmoins, nous choisissons ici d'utiliser uniquement des blocs de base existants et des blocs créés spécifiquement ( User's blocks). Notons d'ailleurs que les User's blocks peuvent avoir une procédure écrite en langage Fortran (cf.  4.1refprofor) ou en langage C (cf.  4.2.

4.1   Construction d'une procédure Fortran pour un User's block

Pour créer une procédure en Fortran, il suffit de s'inspirer des procédures existantes dans le répertoire ''scilab-2.6/routines/scicos''. Nous donnons ici l'exemple d'une procédure pour un compteur incrémental avec remise à zéro ''TIMER'':
      subroutine rdtimer(flag,nevprt,t,xd,x,nx,z,nz,tvec,ntvec, &
     rpar,nrpar,ipar,nipar,y,ny) 
c Scicos block simulator 
c timer with gain and iteration number
      
      double precision t,xd(*),x(*),z(*),tvec(*),rpar(*)
      double precision y(*)
      integer flag,nevprt,nx,nz,ntvec,nrpar,ipar(*)
      integer nipar,ny
      
      
      common /dbcos/ idb
      
      if(idb.eq.1) then
         write(6,'(''rdtimer t='',e10.3,'' flag='',i1,''nevprt='',i1)') t,flag,nevprt
      endif
      
      
      if(flag.eq.4.or.flag.eq.6) then
         y(1)=1.0d0
      endif

      if(rpar(2).gt.y(1).and.nevprt.eq.3.and.flag.eq.2) then
         y(1)=y(1)+rpar(1)
      elseif(rpar(2).eq.0.0d0.and.nevprt.eq.3.and.flag.eq.2) then
         y(1)=y(1)+rpar(1)
      elseif(rpar(2).le.y(1).and.nevprt.eq.3.and.rpar(2).ne.0.0d0) then
         write(6,*)y(1)
         y(1)=0.0d0
      endif  
      end

4.2   Construction d'une procédure C pour un User's block

Pour la création d'une procédure en langage C, il faut veiller à rajouter C2F devant le nom de la procédure. C2F est définit dans la bibliothèque machine.h qu'il faut aussi inclure, sans oublier de bien indiquer l'endroit (<chemin>) où Scilab est installé. L'exemple donné ci-dessous concerne un bloc standard qui calcule en sortie le sinus au carré de son entrée réguliere (bloc sin2).
#include <math.h>
#include "<chemin>/scilab-2.6/routines/machine.h"
/* Copyright INRIA */
 /*     Scicos block simulator */
/* Element wise som^2 */

void C2F(sinblk2)(flag, nevprt, t, xd, x, nx, z, nz, tvec, 
     ntvec, rpar, nrpar, ipar, nipar, u, nu, y, ny)
     double *t,xd[],x[],z[],tvec[];
     int *flag,*nevprt,*nx,*nz,*ntvec,*nrpar,ipar[],*nipar,*nu,*ny;
     double rpar[],u[],y[];
{
   
  /* Local variables */
  int i;
  
  /* Parameter adjustments */
  --y;
  --u;
  --ipar;
  --rpar;
  --tvec;
  --z;
  --x;
  --xd;
  
  /* Function Body */
  for (i = 1; i <=*nu ; ++i) {
    y[i] = pow(sin(u[i]),2);
    /* L15: */
  }
}
Le schéma représenté à la figure 15 montre l'utilisation des blocs synchro, pour l'exécution du conditionnement, ainsi que les User's blocks TIMER et sin 2.



Figure 15: Le schéma Scicos exécutant l'algorithme.

Nous plaçons les 4 blocs constituants la boucle des itérations j dans un super-bloc, pour lequel la compilation nous donne le schéma Scicos de la figure 16 (le code C d'exécution est généré est placé dans le fichier foo.c).



Figure 16: Le schéma Scicos modifié.

Dans cet exemple, la simulation confirme que nous obtenons, avant et après la génération de code, le même résultats (cf. figure 17).



Figure 17: Même résultat dans les deux cas.

5   Le mode d'emploi

L'utilisation de la boîte à outils pour la génération automatique de code nécessite une installation spécifique, pour cela toutes les informations nécessaires sont aussi disponibles sur le site : http://www-rocq.inria.fr/scilab/contributions.html

5.1   L'installation

Pour installer cette boîte à outils l'administrateur de la machine doit exécuter, une fois pour toute, l'instruction suivante dans la fenêtre Scilab : exec <chemin> /builder.sce Cette opération nécessite un compilateur C (pour les systèmes Unix/Linux) ou un compilateur VisualC++ (pour les systèmes Windows), ainsi que les droits d'écriture dans :
  1. <chemin> /src afin de générer le fichier Makefile et les fichiers objets (*.o, pour les systèmes Unix/Linux) ou (*.obj, *dll, ..., pour les systèmes Windows)
  2. <chemin> /macros afin de générer les fichiers binaires (*.bin) ainsi que les fichiers names et lib.

5.2   L'utilisation

Pour utiliser cette boîte à outils, aussi bien sur les systèmes Unix/Linux que les systèmes Windows, l'utilisateur doit exécuter l'instruction suivante : exec <chemin>/loader.sce, dans Scilab et avant d'utiliser la boîte à outils. Il peut aussi l'écrire dans son fichier de démarrage .scilab pour un chargement automatique. On obtient ainsi dans la barre de menu un nouveau bouton Code qui donne l'accès à une unique sélection : Generation. D'un simple clic sur cette dernière, suivi d'un autre clic pour désigner le super-bloc concerné et le tour est joué ! Le super-bloc est transformé en un bloc, pour lequel ont été générées et chargées les fonctions d'interface graphique et de simulation.

5.3   Le contenu de la boîte à outils :

La boîte à outils pour la génération automatique de code est constituée des répertoires et fichiers suivants : Rachid Djenidi
Scilab Group
scilab@inria.fr
http://www-rocq.inria.fr/scilab/
This document was translated from LATEX by HEVEA.