Discussion:
Utiliser un access ou pas ?
(trop ancien pour répondre)
DrPi
2021-02-16 15:25:43 UTC
Permalink
Bonjour,

J'utilise svd2ada pour générer les fichiers de spécification des
périphériques d'un micro-contrôlleur.

Par exemple pour un GPIO :
type GPIO_Peripheral is record
-- GPIO data register
DR : aliased HAL.UInt32;
-- GPIO direction register
GDIR : aliased GDIR_Register;
-- GPIO data register SET
DR_SET : aliased HAL.UInt32;
-- GPIO data register CLEAR
DR_CLEAR : aliased HAL.UInt32;
-- GPIO data register TOGGLE
DR_TOGGLE : aliased HAL.UInt32;
end record
with Volatile;

for GPIO_Peripheral use record
DR at 16#0# range 0 .. 31;
GDIR at 16#4# range 0 .. 31;
DR_SET at 16#84# range 0 .. 31;
DR_CLEAR at 16#88# range 0 .. 31;
DR_TOGGLE at 16#8C# range 0 .. 31;
end record;

-- GPIO
GPIO1_Periph : aliased GPIO_Peripheral
with Import, Address => GPIO1_Base;

-- GPIO
GPIO2_Periph : aliased GPIO_Peripheral
with Import, Address => GPIO2_Base;

-- GPIO
GPIO3_Periph : aliased GPIO_Peripheral
with Import, Address => GPIO3_Base;

-- GPIO
GPIO5_Periph : aliased GPIO_Peripheral
with Import, Address => GPIO5_Base;


J'ai écrit une couche d'abtraction :
type t_GPIO_Peripheral_Access is access all GPIO_Peripheral;

GPIO_1 : GPIO_Peripheral renames GPIO1_Periph;
GPIO_2 : GPIO_Peripheral renames GPIO2_Periph;
GPIO_3 : GPIO_Peripheral renames GPIO3_Periph;
GPIO_5 : GPIO_Peripheral renames GPIO5_Periph;


subtype t_gpio_pin is Integer range 0..31;

procedure Write(gpio : out GPIO_Peripheral; gpio_pin : in
t_gpio_pin; value : in Boolean)
with Inline;

procedure Set(gpio : out GPIO_Peripheral; gpio_pin : in t_gpio_pin)
with Inline;

procedure Clear(gpio : out GPIO_Peripheral; gpio_pin : in t_gpio_pin)
with Inline;

procedure Toggle(gpio : out GPIO_Peripheral; gpio_pin : in t_gpio_pin)
with Inline;

function Get(gpio : in GPIO_Peripheral; gpio_pin : in t_gpio_pin)
return Boolean
with Inline;


J'utilise cette API comme ceci :
Write(GPIO_1, 2, True);
Set(GPIO_2, 3);


Cela fonctionne bien; Mais est-ce correct ?
Les procédures Write, Set... ne devraient-elles pas utiliser un access ?
Comme ceci :
procedure Write(gpio : out access all GPIO_Peripheral; ...);



En avançant sur mon projet, j'ai créé un tableau de structures comme ceci :
type t_Gpio_Infos is record
GPIO_Periph : gpio.GPIO_Peripheral; -- <=== GPIO_Peripheral
GPIO_Pin : gpio.t_gpio_pin;
Pad_Mux : t_PadMux;
end record;

type t_Gpio_Infos_Array is array (t_Gpio_Pad_Name) of t_Gpio_Infos;

Gpio_Infos_Array : constant t_Gpio_Infos_Array :=
(
-- GPIO 1 Pad_Mux => Alt5
PAD_GPIO_AD_B0_00 => (GPIO_Periph => gpio.GPIO_1, ...),
...
);

La structure donne des infos de GPIO pour une patte du micro-contrôlleur.
Le tableau donne les indications pour toutes les pattes concernées.

J'ai également des fonctions d'abstraction qui retournent les infos du
tableau. Par exemple.
function GPIO_Periph(Pad_Name : t_Gpio_Pad_Name) return
gpio.t_GPIO_Peripheral is
begin
return Gpio_Infos_Array(Pad_Name).GPIO_Periph;
end GPIO_Periph;


Quand je fais
Set(GPIO_Periph(xxx), 2);
ça ne marche pas.

J'ai remplacé la définition du record par ceci :
type t_Gpio_Infos is record
GPIO_Periph : gpio.t_GPIO_Peripheral_Access; -- <=== Access
GPIO_Pin : gpio.t_gpio_pin;
Pad_Mux : t_PadMux;
end record;

J'ai bien sûr modifié le tableau et les fonctions en conséquence.

Maintenant, lorsque je fais
gpio.Set(Gpio_Periph(Led).all, 2);
ca marche.

Je ne comprends pas vraiment ce qui se passe ici.
Je comprends l'utilisation de access. D'où ma question du début : les
procédures Write, Set... devraient-elles utiliser un access ?

Mais je ne comprends pas pourquoi, sans access, ça marche, ou pas.
Set(GPIO_2, 3); -- <== Fonctionne
Set(GPIO_Periph(xxx), 2); -- <== Fonctionne pas

Quand je dis que cela ne fonctionne pas, c'est simplement que tout se
passe comme si l'appel à la procédure n'était pas fait (je n'ai pas
vérifié au débugger).
Je n'ai pas d'erreur de compilation.
J'utilise GNAT community 2020 sur plateforme ARM.

Même si j'ai un code fonctionnel (en utilisant partiellement access),
j'ai peur de passer à coté d'un principe fondamental.

Cordialement,
Nicolas
Blady
2021-02-18 09:20:09 UTC
Permalink
Post by DrPi
Bonjour,
J'utilise svd2ada pour générer les fichiers de spécification des
périphériques d'un micro-contrôlleur.
   type GPIO_Peripheral is record
      --  GPIO data register
      DR        : aliased HAL.UInt32;
      --  GPIO direction register
      GDIR      : aliased GDIR_Register;
      --  GPIO data register SET
      DR_SET    : aliased HAL.UInt32;
      --  GPIO data register CLEAR
      DR_CLEAR  : aliased HAL.UInt32;
      --  GPIO data register TOGGLE
      DR_TOGGLE : aliased HAL.UInt32;
   end record
     with Volatile;
...
Post by DrPi
   --  GPIO
   GPIO1_Periph : aliased GPIO_Peripheral
     with Import, Address => GPIO1_Base;
...>    GPIO_1 : GPIO_Peripheral renames GPIO1_Periph;
...
Post by DrPi
   procedure Write(gpio : out GPIO_Peripheral; gpio_pin : in
t_gpio_pin; value : in Boolean)
     with Inline;
...
Post by DrPi
   Write(GPIO_1, 2, True);
   Set(GPIO_2, 3);
Cela fonctionne bien; Mais est-ce correct ?
Les procédures Write, Set... ne devraient-elles pas utiliser un access ?
   procedure Write(gpio : out access all GPIO_Peripheral; ...);
   type t_Gpio_Infos is record
      GPIO_Periph : gpio.GPIO_Peripheral;    -- <===  GPIO_Peripheral
      GPIO_Pin    : gpio.t_gpio_pin;
      Pad_Mux     : t_PadMux;
   end record;
   type t_Gpio_Infos_Array is array (t_Gpio_Pad_Name) of t_Gpio_Infos;
   Gpio_Infos_Array : constant t_Gpio_Infos_Array :=
     (
      -- GPIO 1 Pad_Mux => Alt5
      PAD_GPIO_AD_B0_00 => (GPIO_Periph => gpio.GPIO_1, ...),
      ...
      );
La structure donne des infos de GPIO pour une patte du micro-contrôlleur.
Le tableau donne les indications pour toutes les pattes concernées.
J'ai également des fonctions d'abstraction qui retournent les infos du
tableau. Par exemple.
   function GPIO_Periph(Pad_Name : t_Gpio_Pad_Name) return
gpio.t_GPIO_Peripheral is
   begin
      return Gpio_Infos_Array(Pad_Name).GPIO_Periph;
   end GPIO_Periph;
Quand je fais
   Set(GPIO_Periph(xxx), 2);
ça ne marche pas.
   type t_Gpio_Infos is record
      GPIO_Periph : gpio.t_GPIO_Peripheral_Access;    -- <===  Access
      GPIO_Pin    : gpio.t_gpio_pin;
      Pad_Mux     : t_PadMux;
   end record;
J'ai bien sûr modifié le tableau et les fonctions en conséquence.
Maintenant, lorsque je fais
   gpio.Set(Gpio_Periph(Led).all, 2);
ca marche.
Je ne comprends pas vraiment ce qui se passe ici.
Je comprends l'utilisation de access. D'où ma question du début : les
procédures Write, Set... devraient-elles utiliser un access ?
Mais je ne comprends pas pourquoi, sans access, ça marche, ou pas.
   Set(GPIO_2, 3);            -- <== Fonctionne
   Set(GPIO_Periph(xxx), 2);  -- <== Fonctionne pas
Quand je dis que cela ne fonctionne pas, c'est simplement que tout se
passe comme si l'appel à la procédure n'était pas fait (je n'ai pas
vérifié au débugger).
Je n'ai pas d'erreur de compilation.
J'utilise GNAT community 2020 sur plateforme ARM.
Même si j'ai un code fonctionnel (en utilisant partiellement access),
j'ai peur de passer à coté d'un principe fondamental.
Bonjour Nicolas,

Avant de se poser la question access ou pas, regardons quelle est la
nature de l'emploi des paramètres.

Les trois modes classique de passage de paramètre sont :
- in : la valeur du paramètre est utilisée dans le sous-programme qui la
considère comme une constante
- out : une variable est passée au sous-programme qui la considère comme
une variable non initialisée
- in out : une variable est passée au sous-programme qui la considère
comme une variable à part entière

Le mode supplémentaire access est en fait un mode in dans le quel la
valeur utilisée est un pointeur.
Post by DrPi
procedure Write(gpio : out GPIO_Peripheral; gpio_pin : in
t_gpio_pin; value : in Boolean)
with Inline;
Le paramètre gpio est en mode "out" ce qui semble indiquer que Write va
initialiser gpio.
Les paramètres gpio_pi et value sont en mode "in" ce qui semble
indiquer que Write va utiliser leur valeur.
Est-ce que cela correspond bien au comportement de cette procédure ?
Post by DrPi
Write(GPIO_1, 2, True);
Cela fonctionne bien; Mais est-ce correct ?
GPIO_1 est lié à une adresse que j'imagine matérielle ce qui fait que
GPIO_1 est vue initialisée même en mode out.
Donc "ça marche" (avec GNAT tout au moins).
Cependant regarde si le mode "in out" n'est pas justifié par le code de
ta procédure.
Post by DrPi
Les procédures Write, Set... ne devraient-elles pas utiliser un access ?
procedure Write(gpio : out access all GPIO_Peripheral; ...);
Pour le moins cette proposition est incorrecte : pas de out avec access!
Veux-tu dire :
procedure Write(gpio : access GPIO_Peripheral; ...); ?

Le mode "access" est un équivalent à "in out" donnant plus de liberté
mais plus de responsabilité.
Ici comme ton GPIO est une adresse il peut être tentant d’utiliser les
access. Mais tu perds en niveau d'abstraction. C'est un choix vis à vis
du code utilisant ces procédures où cette mécanique va remonter à leur
niveau.

Cordialement, Pascal
DrPi
2021-02-27 11:42:28 UTC
Permalink
Bonjour Pascal,
Post by DrPi
Bonjour,
J'utilise svd2ada pour générer les fichiers de spécification des
périphériques d'un micro-contrôlleur.
    type GPIO_Peripheral is record
       --  GPIO data register
       DR        : aliased HAL.UInt32;
       --  GPIO direction register
       GDIR      : aliased GDIR_Register;
       --  GPIO data register SET
       DR_SET    : aliased HAL.UInt32;
       --  GPIO data register CLEAR
       DR_CLEAR  : aliased HAL.UInt32;
       --  GPIO data register TOGGLE
       DR_TOGGLE : aliased HAL.UInt32;
    end record
      with Volatile;
...
Post by DrPi
    --  GPIO
    GPIO1_Periph : aliased GPIO_Peripheral
      with Import, Address => GPIO1_Base;
...>     GPIO_1 : GPIO_Peripheral renames GPIO1_Periph;
...
Post by DrPi
    procedure Write(gpio : out GPIO_Peripheral; gpio_pin : in
t_gpio_pin; value : in Boolean)
      with Inline;
...
Post by DrPi
    Write(GPIO_1, 2, True);
    Set(GPIO_2, 3);
Cela fonctionne bien; Mais est-ce correct ?
Les procédures Write, Set... ne devraient-elles pas utiliser un access
    procedure Write(gpio : out access all GPIO_Peripheral; ...);
    type t_Gpio_Infos is record
       GPIO_Periph : gpio.GPIO_Peripheral;    -- <===  GPIO_Peripheral
       GPIO_Pin    : gpio.t_gpio_pin;
       Pad_Mux     : t_PadMux;
    end record;
    type t_Gpio_Infos_Array is array (t_Gpio_Pad_Name) of t_Gpio_Infos;
    Gpio_Infos_Array : constant t_Gpio_Infos_Array :=
      (
       -- GPIO 1 Pad_Mux => Alt5
       PAD_GPIO_AD_B0_00 => (GPIO_Periph => gpio.GPIO_1, ...),
       ...
       );
La structure donne des infos de GPIO pour une patte du micro-contrôlleur.
Le tableau donne les indications pour toutes les pattes concernées.
J'ai également des fonctions d'abstraction qui retournent les infos du
tableau. Par exemple.
    function GPIO_Periph(Pad_Name : t_Gpio_Pad_Name) return
gpio.t_GPIO_Peripheral is
    begin
       return Gpio_Infos_Array(Pad_Name).GPIO_Periph;
    end GPIO_Periph;
Quand je fais
    Set(GPIO_Periph(xxx), 2);
ça ne marche pas.
    type t_Gpio_Infos is record
       GPIO_Periph : gpio.t_GPIO_Peripheral_Access;    -- <===  Access
       GPIO_Pin    : gpio.t_gpio_pin;
       Pad_Mux     : t_PadMux;
    end record;
J'ai bien sûr modifié le tableau et les fonctions en conséquence.
Maintenant, lorsque je fais
    gpio.Set(Gpio_Periph(Led).all, 2);
ca marche.
Je ne comprends pas vraiment ce qui se passe ici.
Je comprends l'utilisation de access. D'où ma question du début : les
procédures Write, Set... devraient-elles utiliser un access ?
Mais je ne comprends pas pourquoi, sans access, ça marche, ou pas.
    Set(GPIO_2, 3);            -- <== Fonctionne
    Set(GPIO_Periph(xxx), 2);  -- <== Fonctionne pas
Quand je dis que cela ne fonctionne pas, c'est simplement que tout se
passe comme si l'appel à la procédure n'était pas fait (je n'ai pas
vérifié au débugger).
Je n'ai pas d'erreur de compilation.
J'utilise GNAT community 2020 sur plateforme ARM.
Même si j'ai un code fonctionnel (en utilisant partiellement access),
j'ai peur de passer à coté d'un principe fondamental.
Bonjour Nicolas,
Avant de se poser la question access ou pas, regardons quelle est la
nature de l'emploi des paramètres.
- in : la valeur du paramètre est utilisée dans le sous-programme qui la
considère comme une constante
- out : une variable est passée au sous-programme qui la considère comme
une variable non initialisée
- in out : une variable est passée au sous-programme qui la considère
comme une variable à part entière
Le mode supplémentaire access est en fait un mode in dans le quel la
valeur utilisée est un pointeur.
Post by DrPi
     procedure Write(gpio : out GPIO_Peripheral; gpio_pin : in
t_gpio_pin; value : in Boolean)
       with Inline;
Le paramètre gpio est en mode "out" ce qui semble indiquer que Write va
initialiser gpio.
Les paramètres gpio_pi et value sont en mode "in"  ce qui semble
indiquer que Write va utiliser leur valeur.
Est-ce que cela correspond bien au comportement de cette procédure ?
Tout à fait :

procedure Write(gpio : out GPIO_Peripheral; gpio_pin : in
t_gpio_pin; value : in Boolean) is
pin_mask : constant UInt32 := 2**gpio_pin;
begin
if value then
gpio.DR_SET := pin_mask;
else
gpio.DR_CLEAR := pin_mask;
end if;
end Write;

procedure Set(gpio : out GPIO_Peripheral; gpio_pin : in t_gpio_pin) is
pin_mask : constant UInt32 := 2**gpio_pin;
begin
gpio.DR_SET := pin_mask;
end Set;
Post by DrPi
     Write(GPIO_1, 2, True);
Cela fonctionne bien; Mais est-ce correct ?
GPIO_1 est lié à une adresse que j'imagine matérielle ce qui fait que
GPIO_1 est vue initialisée même en mode out.
Donc "ça marche" (avec GNAT tout au moins).
Cependant regarde si le mode "in out" n'est pas justifié par le code de
ta procédure.
Post by DrPi
Les procédures Write, Set... ne devraient-elles pas utiliser un access ?
     procedure Write(gpio : out access all GPIO_Peripheral; ...);
Pour le moins cette proposition est incorrecte : pas de out avec access!
procedure Write(gpio : access GPIO_Peripheral; ...); ?
En effet. Je n'ai pas essayé cette forme d'écriture, cela impliquait de
d'adapter pas mal de code. J'ai fait le fainéant ;)
Le mode "access" est un équivalent à "in out" donnant plus de liberté
mais plus de responsabilité.
Ici comme ton GPIO est une adresse il peut être tentant d’utiliser les
access. Mais tu perds en niveau d'abstraction. C'est un choix vis à vis
du code utilisant ces procédures où cette mécanique va remonter à leur
niveau.
Ce qui me pose problème, c'est justement le niveau d'abstraction que
permet Ada. Il y a des choses que je ne n'arrive pas à appréhender.

Utiliser
procedure Write(gpio : out GPIO_Peripheral...);

au lieu de
procedure Write(gpio : access GPIO_Peripheral...);

ne me pose pas plus de problème que ça.
Ada a un niveau d'abstraction qui le permet. Très bien.

Ce qui me pose problème, c'est pourquoi le compilateur me permet
d'écrire du code qui ne fonctionne pas.

Comme je l'ai décrit, lorsque j'utilise un tableau et une fonction
GPIO_Periph() pour récupérer le GPIO à utiliser avec Write() ou Set(),
le compilateur ne donne pas d'erreur mais le programme ne fait pas ce
qu'il devrait faire ou du moins, ce que je pense qu'il devrait faire.

Sauf à utiliser un access dans le tableau et la fonction GPIO_Periph()
puis à appeler Write() et Set() avec .all sur le access renvoyé par la
fonction GPIO_Periph()

J'ai bien peur que mon explication ne soit pas bien claire...


Cordialement,
Nicolas
Cordialement, Pascal
Blady
2021-02-28 10:40:15 UTC
Permalink
Post by DrPi
Bonjour Pascal,
Post by DrPi
Bonjour,
J'utilise svd2ada pour générer les fichiers de spécification des
périphériques d'un micro-contrôlleur.
    type GPIO_Peripheral is record
       --  GPIO data register
       DR        : aliased HAL.UInt32;
       --  GPIO direction register
       GDIR      : aliased GDIR_Register;
       --  GPIO data register SET
       DR_SET    : aliased HAL.UInt32;
       --  GPIO data register CLEAR
       DR_CLEAR  : aliased HAL.UInt32;
       --  GPIO data register TOGGLE
       DR_TOGGLE : aliased HAL.UInt32;
    end record
      with Volatile;
...
Post by DrPi
    --  GPIO
    GPIO1_Periph : aliased GPIO_Peripheral
      with Import, Address => GPIO1_Base;
...>     GPIO_1 : GPIO_Peripheral renames GPIO1_Periph;
...
Post by DrPi
    procedure Write(gpio : out GPIO_Peripheral; gpio_pin : in
t_gpio_pin; value : in Boolean)
      with Inline;
...
Post by DrPi
    Write(GPIO_1, 2, True);
    Set(GPIO_2, 3);
Cela fonctionne bien; Mais est-ce correct ?
Les procédures Write, Set... ne devraient-elles pas utiliser un
    procedure Write(gpio : out access all GPIO_Peripheral; ...);
    type t_Gpio_Infos is record
       GPIO_Periph : gpio.GPIO_Peripheral;    -- <===  GPIO_Peripheral
       GPIO_Pin    : gpio.t_gpio_pin;
       Pad_Mux     : t_PadMux;
    end record;
    type t_Gpio_Infos_Array is array (t_Gpio_Pad_Name) of t_Gpio_Infos;
    Gpio_Infos_Array : constant t_Gpio_Infos_Array :=
      (
       -- GPIO 1 Pad_Mux => Alt5
       PAD_GPIO_AD_B0_00 => (GPIO_Periph => gpio.GPIO_1, ...),
       ...
       );
La structure donne des infos de GPIO pour une patte du
micro-contrôlleur.
Le tableau donne les indications pour toutes les pattes concernées.
J'ai également des fonctions d'abstraction qui retournent les infos
du tableau. Par exemple.
    function GPIO_Periph(Pad_Name : t_Gpio_Pad_Name) return
gpio.t_GPIO_Peripheral is
    begin
       return Gpio_Infos_Array(Pad_Name).GPIO_Periph;
    end GPIO_Periph;
Quand je fais
    Set(GPIO_Periph(xxx), 2);
ça ne marche pas.
    type t_Gpio_Infos is record
       GPIO_Periph : gpio.t_GPIO_Peripheral_Access;    -- <===  Access
       GPIO_Pin    : gpio.t_gpio_pin;
       Pad_Mux     : t_PadMux;
    end record;
J'ai bien sûr modifié le tableau et les fonctions en conséquence.
Maintenant, lorsque je fais
    gpio.Set(Gpio_Periph(Led).all, 2);
ca marche.
Je ne comprends pas vraiment ce qui se passe ici.
Je comprends l'utilisation de access. D'où ma question du début : les
procédures Write, Set... devraient-elles utiliser un access ?
Mais je ne comprends pas pourquoi, sans access, ça marche, ou pas.
    Set(GPIO_2, 3);            -- <== Fonctionne
    Set(GPIO_Periph(xxx), 2);  -- <== Fonctionne pas
Quand je dis que cela ne fonctionne pas, c'est simplement que tout se
passe comme si l'appel à la procédure n'était pas fait (je n'ai pas
vérifié au débugger).
Je n'ai pas d'erreur de compilation.
J'utilise GNAT community 2020 sur plateforme ARM.
Même si j'ai un code fonctionnel (en utilisant partiellement access),
j'ai peur de passer à coté d'un principe fondamental.
Bonjour Nicolas,
Avant de se poser la question access ou pas, regardons quelle est la
nature de l'emploi des paramètres.
- in : la valeur du paramètre est utilisée dans le sous-programme qui
la considère comme une constante
- out : une variable est passée au sous-programme qui la considère
comme une variable non initialisée
- in out : une variable est passée au sous-programme qui la considère
comme une variable à part entière
Le mode supplémentaire access est en fait un mode in dans le quel la
valeur utilisée est un pointeur.
 >     procedure Write(gpio : out GPIO_Peripheral; gpio_pin : in
 > t_gpio_pin; value : in Boolean)
 >       with Inline;
Le paramètre gpio est en mode "out" ce qui semble indiquer que Write
va initialiser gpio.
Les paramètres gpio_pi et value sont en mode "in"  ce qui semble
indiquer que Write va utiliser leur valeur.
Est-ce que cela correspond bien au comportement de cette procédure ?
   procedure Write(gpio : out GPIO_Peripheral; gpio_pin : in
t_gpio_pin; value : in Boolean) is
      pin_mask : constant UInt32 := 2**gpio_pin;
   begin
      if value then
         gpio.DR_SET := pin_mask;
      else
         gpio.DR_CLEAR := pin_mask;
      end if;
   end Write;
   procedure Set(gpio : out GPIO_Peripheral; gpio_pin : in t_gpio_pin) is
      pin_mask : constant UInt32 := 2**gpio_pin;
   begin
       gpio.DR_SET := pin_mask;
   end Set;
Le mode "access" est un équivalent à "in out" donnant plus de liberté
mais plus de responsabilité.
Ici comme ton GPIO est une adresse il peut être tentant d’utiliser les
access. Mais tu perds en niveau d'abstraction. C'est un choix vis à
vis du code utilisant ces procédures où cette mécanique va remonter à
leur niveau.
Ce qui me pose problème, c'est justement le niveau d'abstraction que
permet Ada. Il y a des choses que je ne n'arrive pas à appréhender.
Utiliser
procedure Write(gpio : out GPIO_Peripheral...);
au lieu de
procedure Write(gpio : access GPIO_Peripheral...);
ne me pose pas plus de problème que ça.
Ada a un niveau d'abstraction qui le permet. Très bien.
Ce qui me pose problème, c'est pourquoi le compilateur me permet
d'écrire du code qui ne fonctionne pas.
Attention comme indiqué ci-dessus le mode "access" est équivalent à "in
out" mais pas à "out" car dans ce dernier cas les valeurs précédentes ne
sont pas reprises. Le paramètre mode "out" peut être vu comme la
déclaration d'une variable locale non initialisée qui en fin de
procédure est recopiée dans la variable de l'appel.
Tu ne peux pas alors enchainer les appels avec le même port et
t'attendre à ce qu'il soit mis à jour fur à mesure des appels.
Avec le mode "out" le port sera toujours réinitialisé à chaque appel,
est ce que tu souhaite obtenir ?
Sinon essaye avec "in out" ?

Cordialement, Pascal
DrPi
2021-03-05 09:27:39 UTC
Permalink
Post by Blady
Post by DrPi
Bonjour Pascal,
Post by DrPi
Bonjour,
J'utilise svd2ada pour générer les fichiers de spécification des
périphériques d'un micro-contrôlleur.
    type GPIO_Peripheral is record
       --  GPIO data register
       DR        : aliased HAL.UInt32;
       --  GPIO direction register
       GDIR      : aliased GDIR_Register;
       --  GPIO data register SET
       DR_SET    : aliased HAL.UInt32;
       --  GPIO data register CLEAR
       DR_CLEAR  : aliased HAL.UInt32;
       --  GPIO data register TOGGLE
       DR_TOGGLE : aliased HAL.UInt32;
    end record
      with Volatile;
...
Post by DrPi
    --  GPIO
    GPIO1_Periph : aliased GPIO_Peripheral
      with Import, Address => GPIO1_Base;
...>     GPIO_1 : GPIO_Peripheral renames GPIO1_Periph;
...
Post by DrPi
    procedure Write(gpio : out GPIO_Peripheral; gpio_pin : in
t_gpio_pin; value : in Boolean)
      with Inline;
...
Post by DrPi
    Write(GPIO_1, 2, True);
    Set(GPIO_2, 3);
Cela fonctionne bien; Mais est-ce correct ?
Les procédures Write, Set... ne devraient-elles pas utiliser un
    procedure Write(gpio : out access all GPIO_Peripheral; ...);
    type t_Gpio_Infos is record
       GPIO_Periph : gpio.GPIO_Peripheral;    -- <===  GPIO_Peripheral
       GPIO_Pin    : gpio.t_gpio_pin;
       Pad_Mux     : t_PadMux;
    end record;
    type t_Gpio_Infos_Array is array (t_Gpio_Pad_Name) of t_Gpio_Infos;
    Gpio_Infos_Array : constant t_Gpio_Infos_Array :=
      (
       -- GPIO 1 Pad_Mux => Alt5
       PAD_GPIO_AD_B0_00 => (GPIO_Periph => gpio.GPIO_1, ...),
       ...
       );
La structure donne des infos de GPIO pour une patte du
micro-contrôlleur.
Le tableau donne les indications pour toutes les pattes concernées.
J'ai également des fonctions d'abstraction qui retournent les infos
du tableau. Par exemple.
    function GPIO_Periph(Pad_Name : t_Gpio_Pad_Name) return
gpio.t_GPIO_Peripheral is
    begin
       return Gpio_Infos_Array(Pad_Name).GPIO_Periph;
    end GPIO_Periph;
Quand je fais
    Set(GPIO_Periph(xxx), 2);
ça ne marche pas.
    type t_Gpio_Infos is record
       GPIO_Periph : gpio.t_GPIO_Peripheral_Access;    -- <===  Access
       GPIO_Pin    : gpio.t_gpio_pin;
       Pad_Mux     : t_PadMux;
    end record;
J'ai bien sûr modifié le tableau et les fonctions en conséquence.
Maintenant, lorsque je fais
    gpio.Set(Gpio_Periph(Led).all, 2);
ca marche.
Je ne comprends pas vraiment ce qui se passe ici.
les procédures Write, Set... devraient-elles utiliser un access ?
Mais je ne comprends pas pourquoi, sans access, ça marche, ou pas.
    Set(GPIO_2, 3);            -- <== Fonctionne
    Set(GPIO_Periph(xxx), 2);  -- <== Fonctionne pas
Quand je dis que cela ne fonctionne pas, c'est simplement que tout
se passe comme si l'appel à la procédure n'était pas fait (je n'ai
pas vérifié au débugger).
Je n'ai pas d'erreur de compilation.
J'utilise GNAT community 2020 sur plateforme ARM.
Même si j'ai un code fonctionnel (en utilisant partiellement
access), j'ai peur de passer à coté d'un principe fondamental.
Bonjour Nicolas,
Avant de se poser la question access ou pas, regardons quelle est la
nature de l'emploi des paramètres.
- in : la valeur du paramètre est utilisée dans le sous-programme qui
la considère comme une constante
- out : une variable est passée au sous-programme qui la considère
comme une variable non initialisée
- in out : une variable est passée au sous-programme qui la considère
comme une variable à part entière
Le mode supplémentaire access est en fait un mode in dans le quel la
valeur utilisée est un pointeur.
 >     procedure Write(gpio : out GPIO_Peripheral; gpio_pin : in
 > t_gpio_pin; value : in Boolean)
 >       with Inline;
Le paramètre gpio est en mode "out" ce qui semble indiquer que Write
va initialiser gpio.
Les paramètres gpio_pi et value sont en mode "in"  ce qui semble
indiquer que Write va utiliser leur valeur.
Est-ce que cela correspond bien au comportement de cette procédure ?
    procedure Write(gpio : out GPIO_Peripheral; gpio_pin : in
t_gpio_pin; value : in Boolean) is
       pin_mask : constant UInt32 := 2**gpio_pin;
    begin
       if value then
          gpio.DR_SET := pin_mask;
       else
          gpio.DR_CLEAR := pin_mask;
       end if;
    end Write;
    procedure Set(gpio : out GPIO_Peripheral; gpio_pin : in
t_gpio_pin) is
       pin_mask : constant UInt32 := 2**gpio_pin;
    begin
        gpio.DR_SET := pin_mask;
    end Set;
Le mode "access" est un équivalent à "in out" donnant plus de liberté
mais plus de responsabilité.
Ici comme ton GPIO est une adresse il peut être tentant d’utiliser
les access. Mais tu perds en niveau d'abstraction. C'est un choix vis
à vis du code utilisant ces procédures où cette mécanique va remonter
à leur niveau.
Ce qui me pose problème, c'est justement le niveau d'abstraction que
permet Ada. Il y a des choses que je ne n'arrive pas à appréhender.
Utiliser
procedure Write(gpio : out GPIO_Peripheral...);
au lieu de
procedure Write(gpio : access GPIO_Peripheral...);
ne me pose pas plus de problème que ça.
Ada a un niveau d'abstraction qui le permet. Très bien.
Ce qui me pose problème, c'est pourquoi le compilateur me permet
d'écrire du code qui ne fonctionne pas.
Attention comme indiqué ci-dessus le mode "access" est équivalent à "in
out" mais pas à "out" car dans ce dernier cas les valeurs précédentes ne
sont pas reprises. Le paramètre mode "out" peut être vu comme la
déclaration d'une variable locale non initialisée qui en fin de
procédure est recopiée dans la variable de l'appel.
Tu ne peux pas alors enchainer les appels avec le même port et
t'attendre à ce qu'il soit mis à jour fur à mesure des appels.
Avec le mode "out" le port sera toujours réinitialisé à chaque appel,
est ce que tu souhaite obtenir ?
Sinon essaye avec "in out" ?
Cordialement, Pascal
Le but de mon code est d'ajouter un niveau d'abstraction dans
l'utilisation des GPIOs du chip.
A chaque pin du chip est associé un GPIO et un numéro de bit (du GPIO).
A l'usage, au lieu de d'écrire, par exemple, "Set(GPIO1, 2);", j'écris
"Set(GPIO_Periph(100), GPIO_Bit(100));". 100 étant le numéro de pin du
chip. Le schéma de la carte m'indique les numéros de pins. En utilisant
la forme "Set(GPIO_Periph(100), GPIO_Bit(100));", je n'ai pas à chercher
dans la doc du chip quel couple GPIO/bit est associé à la pin 100.
Pour cela, j'utilise un tableau de record qui contient, pour chaque pin
du chip, le GPIO et le bit associés.
Les fonctions GPIO_Periph() et GPIO_Bit() acceptent le numéro de pin en
paramètre et renvoient le GPIO/bit associé.
Pour le bit, pas de problème, c'est un simple nombre.
Pour le GPIO :
- lorsque la fonction GPIO_Periph() retourne un type GPIO_Peripheral, le
programme ne fonctionne pas, comme si les fonctions n'étaient pas
apppelées (mais il n'y a pas d'erreur à la compilation).
- lorsque la fonction GPIO_Periph() retourne un type access all
GPIO_Peripheral, j'utilise la forme "Set(Gpio_Periph(100).all,
Gpio_Pin(100));". Mon programme fonctionne.

L'utilisation de pointeurs ne me pose pas de problème, c'est similaire
au C que je pratique depuis longtemps.

La forme sans pointeur m'interroge. Je ne saisis pas bien comment
fonctionne l'abstraction, ses limites et contraintes.

Cordialement,
Nicolas
J-P. Rosen
2021-03-05 10:19:11 UTC
Permalink
Post by DrPi
- lorsque la fonction GPIO_Periph() retourne un type GPIO_Peripheral, le
programme ne fonctionne pas, comme si les fonctions n'étaient pas
apppelées (mais il n'y a pas d'erreur à la compilation).
- lorsque la fonction GPIO_Periph() retourne un type access all
GPIO_Peripheral, j'utilise la forme "Set(Gpio_Periph(100).all,
Gpio_Pin(100));". Mon programme fonctionne.
L'utilisation de pointeurs ne me pose pas de problème, c'est similaire
au C que je pratique depuis longtemps.
La forme sans pointeur m'interroge. Je ne saisis pas bien comment
fonctionne l'abstraction, ses limites et contraintes.
La fonction renvoie une /valeur/, pas un objet. Autrement dit, elle
renvoie un record qui contient les valeurs indiquées, mais qui n'a
aucune chance de se trouver à l'adresse physique de ton GPIO, c'est une
copie ailleurs en mémoire. Et bien sûr, écrire dedans n'a aucun effet
sur le périphérique.

Un accès est précisément ce qu'il faut: une valeur qui permet d'accéder
à une variable particulière.
--
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
http://www.adalog.fr
DrPi
2021-03-05 10:37:03 UTC
Permalink
Post by J-P. Rosen
Post by DrPi
- lorsque la fonction GPIO_Periph() retourne un type GPIO_Peripheral,
le programme ne fonctionne pas, comme si les fonctions n'étaient pas
apppelées (mais il n'y a pas d'erreur à la compilation).
- lorsque la fonction GPIO_Periph() retourne un type access all
GPIO_Peripheral, j'utilise la forme "Set(Gpio_Periph(100).all,
Gpio_Pin(100));". Mon programme fonctionne.
L'utilisation de pointeurs ne me pose pas de problème, c'est similaire
au C que je pratique depuis longtemps.
La forme sans pointeur m'interroge. Je ne saisis pas bien comment
fonctionne l'abstraction, ses limites et contraintes.
La fonction renvoie une /valeur/, pas un objet. Autrement dit, elle
renvoie un record qui contient les valeurs indiquées, mais qui n'a
aucune chance de se trouver à l'adresse physique de ton GPIO, c'est une
copie ailleurs en mémoire. Et bien sûr, écrire dedans n'a aucun effet
sur le périphérique.
Ok.
Post by J-P. Rosen
Un accès est précisément ce qu'il faut: une valeur qui permet d'accéder
à une variable particulière.
Ok.

Mais alors, pourquoi la procédure Set() définie comme suit fonctionne ?
Est-ce dû au "out" ?
procedure Set(gpio : out GPIO_Peripheral; gpio_pin : in t_gpio_pin)

Si je comprends bien, une fonction Get() définie comme suit ne
fonctionnerait pas non plus (je n'ai pas encore essayé). Exact ?
function Get(gpio : in GPIO_Peripheral; gpio_pin : in t_gpio_pin) return
boolean;
J-P. Rosen
2021-03-05 13:52:26 UTC
Permalink
Post by DrPi
Mais alors, pourquoi la procédure Set() définie comme suit fonctionne ?
Est-ce dû au "out" ?
procedure Set(gpio : out GPIO_Peripheral; gpio_pin : in t_gpio_pin)
Oui. Un paramètre in ou in out passe un objet, pas une valeur, donc la
procédure travaille directement dans la variable fournie (même au cas ou
la variable serait passée par copie, il y aura au bout du compte une
écriture dans la variable d'origine).
Post by DrPi
Si je comprends bien, une fonction Get() définie comme suit ne
fonctionnerait pas non plus (je n'ai pas encore essayé). Exact ?
function Get(gpio : in GPIO_Peripheral; gpio_pin : in t_gpio_pin) return
boolean;
Pour un paramètre in, on passe une valeur; ça peut fonctionner quand
même si le paramètre est passé par adresse, mais ce n'est pas garanti.

Un conseil: déclare tes variables avec l'aspect "volatile": c'est ce
qu'il faut faire avec toutes les variables en mapping d'adresse, et ça
évite bien des ennuis.
--
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
http://www.adalog.fr
DrPi
2021-03-05 16:03:02 UTC
Permalink
Post by J-P. Rosen
Post by DrPi
Mais alors, pourquoi la procédure Set() définie comme suit fonctionne ?
Est-ce dû au "out" ?
procedure Set(gpio : out GPIO_Peripheral; gpio_pin : in t_gpio_pin)
Oui. Un paramètre in ou in out passe un objet, pas une valeur, donc la
procédure travaille directement dans la variable fournie (même au cas ou
la variable serait passée par copie, il y aura au bout du compte une
écriture dans la variable d'origine).
Post by DrPi
Si je comprends bien, une fonction Get() définie comme suit ne
fonctionnerait pas non plus (je n'ai pas encore essayé). Exact ?
function Get(gpio : in GPIO_Peripheral; gpio_pin : in t_gpio_pin)
return boolean;
Pour un paramètre in, on passe une valeur; ça peut fonctionner quand
même si le paramètre est passé par adresse, mais ce n'est pas garanti.
La différence entre objet et valeur, c'est ça qu'il me manquait pour
comprendre.
Post by J-P. Rosen
Un conseil: déclare tes variables avec l'aspect "volatile": c'est ce
qu'il faut faire avec toutes les variables en mapping d'adresse, et ça
évite bien des ennuis.
C'est bien le cas :

type GPIO_Peripheral is record
...
end record
with Volatile;

GPIO1_Periph : aliased GPIO_Peripheral
with Import, Address => GPIO1_Base;

GPIO_1 : GPIO_Peripheral renames GPIO1_Periph;

Est-ce que le renames change quelque chose à ce niveau ?
J-P. Rosen
2021-03-05 17:48:49 UTC
Permalink
Post by DrPi
Post by J-P. Rosen
Un conseil: déclare tes variables avec l'aspect "volatile": c'est ce
qu'il faut faire avec toutes les variables en mapping d'adresse, et ça
évite bien des ennuis.
   type GPIO_Peripheral is record
      ...
   end record
     with Volatile;
   GPIO1_Periph : aliased GPIO_Peripheral
     with Import, Address => GPIO1_Base;
   GPIO_1 : GPIO_Peripheral renames GPIO1_Periph;
Est-ce que le renames change quelque chose à ce niveau ?
Non, "volatile" est une propriété de l'objet. Un rename donne un nouveau
nom à un objet, mais c'est tout.

Formellement, quand tu écris:
V : T;

tu déclares un objet en mémoire de type T, puis tu définis un nom V qui
le désigne. Un rename ne fait que définir un nom supplémentaire sur le
même objet.
--
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
http://www.adalog.fr
DrPi
2021-03-05 18:16:03 UTC
Permalink
Post by J-P. Rosen
Post by DrPi
Post by J-P. Rosen
Un conseil: déclare tes variables avec l'aspect "volatile": c'est ce
qu'il faut faire avec toutes les variables en mapping d'adresse, et
ça évite bien des ennuis.
    type GPIO_Peripheral is record
       ...
    end record
      with Volatile;
    GPIO1_Periph : aliased GPIO_Peripheral
      with Import, Address => GPIO1_Base;
    GPIO_1 : GPIO_Peripheral renames GPIO1_Periph;
Est-ce que le renames change quelque chose à ce niveau ?
Non, "volatile" est une propriété de l'objet. Un rename donne un nouveau
nom à un objet, mais c'est tout.
V : T;
tu déclares un objet en mémoire de type T, puis tu définis un nom V qui
le désigne. Un rename ne fait que définir un nom supplémentaire sur le
même objet.
Donc, le volatile, il faut le mettre sur GPIO1_Periph ? Comme ceci ?
GPIO1_Periph : aliased GPIO_Peripheral
with volatile, Import, Address => GPIO1_Base;
J-P. Rosen
2021-03-06 05:45:10 UTC
Permalink
Post by DrPi
Donc, le volatile, il faut le mettre sur GPIO1_Periph ? Comme ceci ?
   GPIO1_Periph : aliased GPIO_Peripheral
     with volatile, Import, Address => GPIO1_Base;
Pas obligatoirement. Si tu le mets sur le type, tous les objets du type
sont volatiles. Si tu le mets sur une variable, seule cette variable est
volatile.
--
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
http://www.adalog.fr
DrPi
2021-03-06 15:30:24 UTC
Permalink
Post by J-P. Rosen
Post by DrPi
Donc, le volatile, il faut le mettre sur GPIO1_Periph ? Comme ceci ?
    GPIO1_Periph : aliased GPIO_Peripheral
      with volatile, Import, Address => GPIO1_Base;
Pas obligatoirement. Si tu le mets sur le type, tous les objets du type
sont volatiles. Si tu le mets sur une variable, seule cette variable est
volatile.
C'est ce que je pensais.
En fait, j'ai mal interprété "Non, "volatile" est une propriété de
l'objet. Un rename donne un nouveau nom à un objet, mais c'est tout. "
C'est pour ça que j'ai développé.

Ma question d'origine sur "rename" vient du fait que dans le news
anglophone, il a été dit que "rename" peut avoir des effets de bord.
Renommer le résultat d'une fonction, par exemple, permettrait
d'outre-passer le type checking (si j'ai bien compris).
J-P. Rosen
2021-03-06 17:07:13 UTC
Permalink
Post by DrPi
Renommer le résultat d'une fonction, par exemple, permettrait
d'outre-passer le type checking (si j'ai bien compris).
Deux choses:
1) Une fonction renvoie un objet anonyme, donc un rename d'appel de
fonction permet en fait de nommer cet objet - plus vraiment anonyme.
2) Le /type/ donné dans un rename doit correspondre au /type/ de ce qui
est renommé (on devrait dire surnommé en bon français). En revanche, il
n'y a pas de vérification que les /sous-types/ correspondent, donc pas
de Constraint_Error si la valeur surnommée n'est pas dans l'intervalle
du sous-type annoncé dans le rename.
--
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
http://www.adalog.fr
DrPi
2021-03-06 17:45:24 UTC
Permalink
Post by J-P. Rosen
Post by DrPi
Renommer le résultat d'une fonction, par exemple, permettrait
d'outre-passer le type checking (si j'ai bien compris).
1) Une fonction renvoie un objet anonyme, donc un rename d'appel de
fonction permet en fait de nommer cet objet - plus vraiment anonyme.
2) Le /type/ donné dans un rename doit correspondre au /type/ de ce qui
est renommé (on devrait dire surnommé en bon français). En revanche, il
n'y a pas de vérification que les /sous-types/ correspondent, donc pas
de Constraint_Error si la valeur surnommée n'est pas dans l'intervalle
du sous-type annoncé dans le rename.
Merci pour ces précisions.
Thomas
2022-01-19 03:23:17 UTC
Permalink
Post by J-P. Rosen
Post by DrPi
Renommer le résultat d'une fonction, par exemple, permettrait
d'outre-passer le type checking (si j'ai bien compris).
2) Le /type/ donné dans un rename doit correspondre au /type/ de ce qui
est renommé (on devrait dire surnommé en bon français). En revanche, il
n'y a pas de vérification que les /sous-types/ correspondent, donc pas
de Constraint_Error si la valeur surnommée n'est pas dans l'intervalle
du sous-type annoncé dans le rename.
si je te comprend bien,
- il n'y a pas d'outre-passement de (donc il y a) vérification du
sous-type du résultat de la fonction,
- mais il n'y a pas de vérification du sous-type annoncé dans le rename ?

c'est dommage,
de même que l'interdiction du mot "constant", qui ne devrait pas
forcément vérifier si l'objet pointé en est une, mais au moins que toute
utilisation du surnom respecte ça.
--
RAPID maintainer
http://savannah.nongnu.org/projects/rapid/
J-P. Rosen
2022-01-19 06:38:24 UTC
Permalink
Post by Thomas
Post by J-P. Rosen
2) Le /type/ donné dans un rename doit correspondre au /type/ de ce qui
est renommé (on devrait dire surnommé en bon français). En revanche, il
n'y a pas de vérification que les /sous-types/ correspondent, donc pas
de Constraint_Error si la valeur surnommée n'est pas dans l'intervalle
du sous-type annoncé dans le rename.
si je te comprend bien,
- il n'y a pas d'outre-passement de (donc il y a) vérification du
sous-type du résultat de la fonction,
- mais il n'y a pas de vérification du sous-type annoncé dans le rename ?
c'est dommage,
Le problème (surtout en Ada 83 d'où provient la règle), c'est qu'un
sous-type peut être dynamique, et une règle de compilation ne peut pas
dépendre de quelque chose qui n'est connu qu'à l'exécution.

A partir d'Ada 95, on a introduit la notion de "statically matching
subtypes", mais il a été estimé que cela compliquerait trop les choses
de l'appliquer aux rename, et de toute façon ça ne pouvait pas marcher
dans tous les cas sans casser la compatibilité.
Post by Thomas
de même que l'interdiction du mot "constant", qui ne devrait pas
forcément vérifier si l'objet pointé en est une, mais au moins que toute
utilisation du surnom respecte ça.
Ca c'est fait:

procedure Essai is
V : constant Integer := 0;
C : Integer renames V;
begin
C:= 3; -- left hand side of assignment must be a variable
end Essai;
--
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52
https://www.adalog.fr
Thomas
2022-01-19 21:24:15 UTC
Permalink
Post by J-P. Rosen
Post by Thomas
Post by J-P. Rosen
2) Le /type/ donné dans un rename doit correspondre au /type/ de ce qui
est renommé (on devrait dire surnommé en bon français). En revanche, il
n'y a pas de vérification que les /sous-types/ correspondent, donc pas
de Constraint_Error si la valeur surnommée n'est pas dans l'intervalle
du sous-type annoncé dans le rename.
si je te comprend bien,
- il n'y a pas d'outre-passement de (donc il y a) vérification du
sous-type du résultat de la fonction,
- mais il n'y a pas de vérification du sous-type annoncé dans le rename ?
c'est dommage,
Le problème (surtout en Ada 83 d'où provient la règle), c'est qu'un
sous-type peut être dynamique,
en Ada 83 un sous-type pouvait déjà être dynamique ?
Post by J-P. Rosen
et une règle de compilation ne peut pas
dépendre de quelque chose qui n'est connu qu'à l'exécution.
je ne comprend pas ce que tu dis, puisque le comportement attendu est de
lever Constraint_Error à l'exécution.
Post by J-P. Rosen
A partir d'Ada 95, on a introduit la notion de "statically matching
subtypes", mais il a été estimé que cela compliquerait trop les choses
de l'appliquer aux rename,
(peut-être que je comprendrai avec les questions précédentes)
Post by J-P. Rosen
et de toute façon ça ne pouvait pas marcher
dans tous les cas sans casser la compatibilité.
le 2eme argument tout seul est insuffisant, puisqu'une compatibilité
imparfaite est pratiquée quand il est estimé qu'elle vaut le coup.
mais je ne visualise pas du tout, même pas en ordre de grandeur, ce que
ça peut couter aux uns ou aux autres, de modifier telle ou telle chose.
Post by J-P. Rosen
Post by Thomas
de même que l'interdiction du mot "constant", qui ne devrait pas
forcément vérifier si l'objet pointé en est une, mais au moins que toute
utilisation du surnom respecte ça.
procedure Essai is
V : constant Integer := 0;
C : Integer renames V;
begin
C:= 3; -- left hand side of assignment must be a variable
end Essai;
veux tu dire qu'avant on n'avait pas le droit de surnommer une constante
?

ce dont je parlais c'était plutôt ça :

V : Integer := 0;
C : constant Integer renames V;

d'après mon expérience, c'est totalement interdit d'écrire ça,
et d'après ce que j'ai compris du langage, c'est autorisé mais sans
aucune conséquence (c'est pire).

en fait, ce qui me paraitrait logique, c'est que :
- le surnom doive obligatoirement être marqué "constant" si l'objet
pointé l'est, mais pas réciproquement,
- l'usage autorisé du surnom dépende du marquage du surnom, pas de
l'objet pointé.



PS : j'espère que tu m'excuses pour les majuscules,
mon client "news" n'a pas de fonction pour mettre des majuscules
automatiquement (contrairement à mon client courriel),
et je trouve ça vraiment trop fastidieux de devoir penser à la touche
majuscule en même temps qu'écrire et chercher la bonne lettre sur le
clavier.
--
RAPID maintainer
http://savannah.nongnu.org/projects/rapid/
J-P. Rosen
2022-01-20 05:33:31 UTC
Permalink
Post by Thomas
en Ada 83 un sous-type pouvait déjà être dynamique ?
oui bien sûr, le principe a toujours été:
type => statique
Sous-type => dynamique
Post by Thomas
Post by J-P. Rosen
et une règle de compilation ne peut pas
dépendre de quelque chose qui n'est connu qu'à l'exécution.
je ne comprend pas ce que tu dis, puisque le comportement attendu est de
lever Constraint_Error à l'exécution.
??? Je ne sais pas où tu as vu ça... D'ailleurs, en 8.5.1 il n'y a même
pas de paragraphe "dynamic semantic".

Ce qui est important, c'est 8.5.1(6/2) qui dit clairement que tout ce
qu'on peut mettre dans la déclaration de surnom est ignoré, ce qui
compte c'est ce qui est dit dans la déclaration de l'objet d'origine.
Post by Thomas
Post by J-P. Rosen
A partir d'Ada 95, on a introduit la notion de "statically matching
subtypes", mais il a été estimé que cela compliquerait trop les choses
de l'appliquer aux rename,
(peut-être que je comprendrai avec les questions précédentes)
Post by J-P. Rosen
et de toute façon ça ne pouvait pas marcher
dans tous les cas sans casser la compatibilité.
Ce que je veux dire, c'est que l'idéal aurait été que les définitions de
sous-type de la déclaration et de l'objet renommé correspondent, sous
peine d'erreur à la compilation. Mais en Ada83 ce n'était pas possible
puisqu'il n'y avait jamais de correspondance statique entre des
sous-types. Ada95 a introduit la notion de "statically matching
subtypes", mais l'utiliser pour un rename aurait conduit à interdire
tous les renames d'un objet dont le sous-type était dynamique => trop
incompatible.
Post by Thomas
Post by J-P. Rosen
Post by Thomas
de même que l'interdiction du mot "constant", qui ne devrait pas
forcément vérifier si l'objet pointé en est une, mais au moins que toute
utilisation du surnom respecte ça.
Effectivement, on aurait pu imaginer un rename avec le mot "constant"
qui fournirait une vue constante d'une variable (comme un paramètre
"in"). Ca n'a pas été fait, et honnètement je ne sais pas ce qu'Ichbiah
avait en tête comme cas d'utilisation du rename. Mais je peux te dire
que ça complique énormément les outils d'analyse de code ;-)

[...]
Post by Thomas
V : Integer := 0;
C : constant Integer renames V;
d'après mon expérience, c'est totalement interdit d'écrire ça,
et d'après ce que j'ai compris du langage, c'est autorisé mais sans
aucune conséquence (c'est pire).
Non, ce n'est pas dans la syntaxe du rename.
Post by Thomas
- le surnom doive obligatoirement être marqué "constant" si l'objet
pointé l'est, mais pas réciproquement,
C'est logique, mais on ne peut plus le rajouter maintenant, vu qu'on a
des rename de constantes qui n'utilisent pas le mot "constant"
Post by Thomas
- l'usage autorisé du surnom dépende du marquage du surnom, pas de
l'objet pointé.
Ca pourrait être rajouté au langage. On (l'ARG) est en train de mettre
en route un système pour centraliser les demandes des utilisateurs. Tu
pourras toujours le proposer quand ce sera annoncé...
--
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52
https://www.adalog.fr
Loading...