Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Utiliser un access ou pas ?

22 views
Skip to first unread message

DrPi

unread,
Feb 16, 2021, 10:25:45 AM2/16/21
to
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

unread,
Feb 18, 2021, 4:20:11 AM2/18/21
to
Le 16/02/2021 à 16:25, DrPi a écrit :
> 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;
...
>    --  GPIO
>    GPIO1_Periph : aliased GPIO_Peripheral
>      with Import, Address => GPIO1_Base;
...>    GPIO_1 : GPIO_Peripheral renames GPIO1_Periph;
...
>    procedure Write(gpio : out GPIO_Peripheral; gpio_pin : in
> t_gpio_pin; value : in Boolean)
>      with Inline;
>
...
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.

Prenons ta première procédure:
> 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 ?

> J'utilise cette API comme ceci :
> 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.

> Les procédures Write, Set... ne devraient-elles pas utiliser un access ?
> Comme ceci :
> 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

unread,
Feb 27, 2021, 6:42:32 AM2/27/21
to
Bonjour Pascal,
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;

>
> > J'utilise cette API comme ceci :
> >     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.
>
> > Les procédures Write, Set... ne devraient-elles pas utiliser un access ?
> > Comme ceci :
> >     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; ...); ?
>
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

unread,
Feb 28, 2021, 5:40:20 AM2/28/21
to
>> 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

unread,
Mar 5, 2021, 4:27:40 AM3/5/21
to
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

unread,
Mar 5, 2021, 5:19:13 AM3/5/21
to
Le 05/03/2021 à 10:27, DrPi a écrit :
> 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.

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

unread,
Mar 5, 2021, 5:37:04 AM3/5/21
to
Le 05/03/2021 à 11:19, J-P. Rosen a écrit :
> Le 05/03/2021 à 10:27, DrPi a écrit :
>> 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.
>
> 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.

> 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

unread,
Mar 5, 2021, 8:52:28 AM3/5/21
to
Le 05/03/2021 à 11:37, DrPi a écrit :
> 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).

> 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.

DrPi

unread,
Mar 5, 2021, 11:03:04 AM3/5/21
to
Le 05/03/2021 à 14:52, J-P. Rosen a écrit :
> Le 05/03/2021 à 11:37, DrPi a écrit :
>> 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).
>
>> 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.

> 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

unread,
Mar 5, 2021, 12:48:51 PM3/5/21
to
Le 05/03/2021 à 17:03, DrPi a écrit :
>> 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 ?
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.

DrPi

unread,
Mar 5, 2021, 1:16:04 PM3/5/21
to
Le 05/03/2021 à 18:48, J-P. Rosen a écrit :
> Le 05/03/2021 à 17:03, DrPi a écrit :
>>> 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 ?
> 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.
>
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

unread,
Mar 6, 2021, 12:45:11 AM3/6/21
to
Le 05/03/2021 à 19:16, DrPi a écrit :
> 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.

DrPi

unread,
Mar 6, 2021, 10:30:26 AM3/6/21
to
Le 06/03/2021 à 06:45, J-P. Rosen a écrit :
> Le 05/03/2021 à 19:16, DrPi a écrit :
>> 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

unread,
Mar 6, 2021, 12:07:18 PM3/6/21
to
Le 06/03/2021 à 16:30, DrPi a écrit :
> 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.

DrPi

unread,
Mar 6, 2021, 12:45:26 PM3/6/21
to
Le 06/03/2021 à 18:07, J-P. Rosen a écrit :
> Le 06/03/2021 à 16:30, DrPi a écrit :
>> 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.
>
>
Merci pour ces précisions.

Thomas

unread,
Jan 18, 2022, 10:23:19 PM1/18/22
to
In article <s20cs5$89b$1...@dont-email.me>, "J-P. Rosen" <ro...@adalog.fr>
wrote:

> Le 06/03/2021 à 16:30, DrPi a écrit :
> > 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

unread,
Jan 19, 2022, 1:38:25 AM1/19/22
to
Le 19/01/2022 à 04:23, Thomas a écrit :
>> 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é.

> 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

unread,
Jan 19, 2022, 4:24:32 PM1/19/22
to
In article <ss8bkv$hsu$1...@dont-email.me>, "J-P. Rosen" <ro...@adalog.fr>
wrote:

> Le 19/01/2022 à 04:23, Thomas a écrit :
> >> 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 ?

> 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.

>
> 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)

> 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.


>
> > 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;

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.

J-P. Rosen

unread,
Jan 20, 2022, 12:33:32 AM1/20/22
to
Le 19/01/2022 à 22:24, Thomas a écrit :
> 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

>> 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.

>> 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)
>
>> 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.


>>> 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 ;-)

[...]

> 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).
Non, ce n'est pas dans la syntaxe du rename.
>
> 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,
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"

> - 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é...
0 new messages