Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

déclaration de structures avec padding explicite

8 réponses
Avatar
jerome.arbez-gindre
Bonjour,

Pour acceder =E0 des ports I/O, je souhaiterai d=E9finir une structure et
la mapper =E0 mes ports.

J'ai donc =E9cris quelque chose qui ressemble =E0 =E7a:

#define BIG_BUFFER_LOCATION 0x00080000UL /*512Ko*/
#define BIG_BUFFER_SIZE 0x00080000UL /*512Ko*/

struct regs_t {
union {
struct { c
uint32_t a1 ;
uint32_t a2 ;
} ;
uint8_t before_big_buffer[BIG_BUFFER_LOCATION] ;
} ;
uint8_t big_buffer[BIG_BUFFER_SIZE] ;
} ;


Mais je trouve =E7a assez "moche"... et =E7a risque devenir tr=E8s vite
illisible (mon exemple ci-dessus est condens=E9 !)


j'ai pens=E9 faire quelque chose comme =E7a :

struct regs_t {
struct part1_t{
uint32_t a1 ;
uint32_t a2 ;
} part1 ;
uint8_t __padding0 [BIG_BUFFER_LOCATION-sizeof (struct part1_t)] ;
uint8_t big_buffer[BIG_BUFFER_SIZE] ;
} ;

mais =E7a m'oblige =E0 donner ajouter une indirection syntaxique pour
acc=E9der =E0 "a1" par exemple, ce qui ne me plait pas non plus.

Je vous remercie d'avance pour vos suggestions,

J=E9r=F4me Arbez-Gindre

PS : j'utilise gcc (versions r=E9centes) et suis ouvert aux extansions
de celui-ci

8 réponses

Avatar
Eric Levenez
Le 18/09/06 12:09, dans
,
«  » a
écrit :

Pour acceder à des ports I/O, je souhaiterai définir une structure et
la mapper à mes ports.

J'ai donc écris quelque chose qui ressemble à ça:

#define BIG_BUFFER_LOCATION 0x00080000UL /*512Ko*/
#define BIG_BUFFER_SIZE 0x00080000UL /*512Ko*/

struct regs_t {
union {
struct { c
uint32_t a1 ;
uint32_t a2 ;
} ;
uint8_t before_big_buffer[BIG_BUFFER_LOCATION] ;
} ;
uint8_t big_buffer[BIG_BUFFER_SIZE] ;
} ;


Mais je trouve ça assez "moche"... et ça risque devenir très vite
illisible (mon exemple ci-dessus est condensé !)


Si le périphérique que tu accèdes est en mode 32 bits, alors autant définir
les "big_buffer" de la même façon (en uint32_t), non ?

j'ai pensé faire quelque chose comme ça :

struct regs_t {
struct part1_t{
uint32_t a1 ;
uint32_t a2 ;
} part1 ;
uint8_t __padding0 [BIG_BUFFER_LOCATION-sizeof (struct part1_t)] ;
uint8_t big_buffer[BIG_BUFFER_SIZE] ;
} ;

mais ça m'oblige à donner ajouter une indirection syntaxique pour
accéder à "a1" par exemple, ce qui ne me plait pas non plus.


C'est pourtant assez propre pour du C. Si à la place de part1 tu mets un nom
comme reg, alors ton code C sera du type :

base->reg.truc = 42;

Ce qui est lisible.

L'autre solution c'est utiliser des defines ou des enums :

enum {
TRUC = 10,
MACHIN = 30
};

base[TRUC] = 42;

--
Éric Lévénez -- <http://www.levenez.com/>
Unix is not only an OS, it's a way of life.

Avatar
Marc Boyer
Le 18-09-2006, a écrit :
Pour acceder à des ports I/O, je souhaiterai définir une structure et
la mapper à mes ports.


Est-ce vraiment une bonne idée ? Tu vas te prendre la tête
à écrire une structure de donnée pas portable, avec perte
d'espace mémoire (BIG_BUFFER_LOCATION - 2* sizeof(uint8_t) ),
tout ça pour faire des accès en memcpy ?
N'auras-tu pas aussi vite fait de dissocier le port
et la représentation dans le code ?

J'ai donc écris quelque chose qui ressemble à ça:

#define BIG_BUFFER_LOCATION 0x00080000UL /*512Ko*/
#define BIG_BUFFER_SIZE 0x00080000UL /*512Ko*/

struct regs_t {
union {
struct { c
uint32_t a1 ;
uint32_t a2 ;
} ;
uint8_t before_big_buffer[BIG_BUFFER_LOCATION] ;
} ;
uint8_t big_buffer[BIG_BUFFER_SIZE] ;
} ;

Mais je trouve ça assez "moche"... et ça risque devenir très vite
illisible (mon exemple ci-dessus est condensé !)


Oui

j'ai pensé faire quelque chose comme ça :

struct regs_t {
struct part1_t{
uint32_t a1 ;
uint32_t a2 ;
} part1 ;
uint8_t __padding0 [BIG_BUFFER_LOCATION-sizeof (struct part1_t)] ;
uint8_t big_buffer[BIG_BUFFER_SIZE] ;
} ;

mais ça m'oblige à donner ajouter une indirection syntaxique pour
accéder à "a1" par exemple, ce qui ne me plait pas non plus.


Est-ce bien grave ?

Je vous remercie d'avance pour vos suggestions,


strut regs_t{
uint8_t a1;
uint8_t a2;
uint8_t big_buffer[BIG_BUFFER_SIZE] ;
};
#define OFFSET_a1 0
#define OFFSET_a2 sizeof(uint8_t)
#define OFFSET_big_buffer 0x00080000UL


void write_reg_t(const reg_t* reg, void* port_adr){
memcpy(((char*) port_adr) + OFFSET_a1, &(reg->a1), sizeof(reg->a1) );
memcpy(((char*) port_adr) + OFFSET_a2, &(reg->a2), sizeof(reg->a2) );
memcpy(((char*) port_adr) + OFFSET_big_buffer, &(reg->big_buffer), sizeof(reg->big_buffer) );
}

et idem pour read_reg_t


Marc Boyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. Paul Éluard)

Avatar
jerome.arbez-gindre
mais ça m'oblige à donner ajouter une indirection syntaxique pour
accéder à "a1" par exemple, ce qui ne me plait pas non plus.


C'est pourtant assez propre pour du C. Si à la place de part1 tu mets u n nom
comme reg, alors ton code C sera du type :

base->reg.truc = 42;



sauf que là, la structure de register, c'est "struct regs_t" et que
ça risaue plutot de donner des choses comme ça :

device->regs->part1.a1

Et comme j'ai dit dans mon premier message, ce que j'ai mis en exemple
est une simplification.


Avatar
Pierre Maurette
Bonjour,

Pour acceder à des ports I/O, je souhaiterai définir une structure et
la mapper à mes ports.

J'ai donc écris quelque chose qui ressemble à ça:

#define BIG_BUFFER_LOCATION 0x00080000UL /*512Ko*/
#define BIG_BUFFER_SIZE 0x00080000UL /*512Ko*/

struct regs_t {
union {
struct { c
uint32_t a1 ;
uint32_t a2 ;
} ;
uint8_t before_big_buffer[BIG_BUFFER_LOCATION] ;
} ;
uint8_t big_buffer[BIG_BUFFER_SIZE] ;
} ;


Mais je trouve ça assez "moche"... et ça risque devenir très vite
illisible (mon exemple ci-dessus est condensé !)


j'ai pensé faire quelque chose comme ça :

struct regs_t {
struct part1_t{
uint32_t a1 ;
uint32_t a2 ;
} part1 ;
uint8_t __padding0 [BIG_BUFFER_LOCATION-sizeof (struct part1_t)] ;
uint8_t big_buffer[BIG_BUFFER_SIZE] ;
} ;

mais ça m'oblige à donner ajouter une indirection syntaxique pour
accéder à "a1" par exemple, ce qui ne me plait pas non plus.

Je vous remercie d'avance pour vos suggestions,

Jérôme Arbez-Gindre

PS : j'utilise gcc (versions récentes) et suis ouvert aux extansions
de celui-ci


<GAG_ON>
#define REGS_T struct{ uint32_t a1 ; uint32_t a2 ;}

typedef struct regs_t_nopad{
REGS_T;
uint8_t a;
}regs_t_nopad;

struct regs_t{
REGS_T;
uint8_t __padding0[BIG_BUFFER_LOCATION - offsetof(regs_t_nopad,
a)];
uint8_t big_buffer[BIG_BUFFER_SIZE];
};
<GAG_OFF>

--
Pierre Maurette

Avatar
jerome.arbez-gindre

Pour acceder à des ports I/O, je souhaiterai définir une structure et
la mapper à mes ports.


Est-ce vraiment une bonne idée ? Tu vas te prendre la tête
à écrire une structure de donnée pas portable, avec perte
d'espace mémoire (BIG_BUFFER_LOCATION - 2* sizeof(uint8_t) ),
tout ça pour faire des accès en memcpy ?


Dans ce cas, il n'y a pas de perte d'espace mémoire, c'est de la
mémoire mappée sur un périphérique (dont je ne maitrise pas le
mapping)

N'auras-tu pas aussi vite fait de dissocier le port
et la représentation dans le code ?

J'ai donc écris quelque chose qui ressemble à ça:

#define BIG_BUFFER_LOCATION 0x00080000UL /*512Ko*/
#define BIG_BUFFER_SIZE 0x00080000UL /*512Ko*/

struct regs_t {
union {
struct { c
uint32_t a1 ;
uint32_t a2 ;
} ;
uint8_t before_big_buffer[BIG_BUFFER_LOCATION] ;
} ;
uint8_t big_buffer[BIG_BUFFER_SIZE] ;
} ;

Mais je trouve ça assez "moche"... et ça risque devenir très vite
illisible (mon exemple ci-dessus est condensé !)


Oui

j'ai pensé faire quelque chose comme ça :

struct regs_t {
struct part1_t{
uint32_t a1 ;
uint32_t a2 ;
} part1 ;
uint8_t __padding0 [BIG_BUFFER_LOCATION-sizeof (struct part1_t)] ;
uint8_t big_buffer[BIG_BUFFER_SIZE] ;
} ;

mais ça m'oblige à donner ajouter une indirection syntaxique pour
accéder à "a1" par exemple, ce qui ne me plait pas non plus.


Est-ce bien grave ?


Ca peut devenir très lourd, vu qu'il y a beaucoup de "trous" dasn ma
structure réelle.


Je vous remercie d'avance pour vos suggestions,


strut regs_t{
uint8_t a1;
uint8_t a2;
uint8_t big_buffer[BIG_BUFFER_SIZE] ;
};
#define OFFSET_a1 0
#define OFFSET_a2 sizeof(uint8_t)
#define OFFSET_big_buffer 0x00080000UL


void write_reg_t(const reg_t* reg, void* port_adr){
memcpy(((char*) port_adr) + OFFSET_a1, &(reg->a1), sizeof(reg->a1) );
memcpy(((char*) port_adr) + OFFSET_a2, &(reg->a2), sizeof(reg->a2) );
memcpy(((char*) port_adr) + OFFSET_big_buffer, &(reg->big_buffer), size of(reg->big_buffer) );
}


Mon idée, c'est d'écrire

regs->some_feature_enable = true ;

plutôt que

write_reg (base+SOME_FEATURE_ENABLE_OFFSET, true) ;

Ce qui me parait plus lisible et plus élégant.

Jérome A-G


Avatar
Marc Boyer
Le 18-09-2006, a écrit :


Pour acceder à des ports I/O, je souhaiterai définir une structure et
la mapper à mes ports.


Est-ce vraiment une bonne idée ? Tu vas te prendre la tête
à écrire une structure de donnée pas portable, avec perte
d'espace mémoire (BIG_BUFFER_LOCATION - 2* sizeof(uint8_t) ),
tout ça pour faire des accès en memcpy ?


Dans ce cas, il n'y a pas de perte d'espace mémoire, c'est de la
mémoire mappée sur un périphérique (dont je ne maitrise pas le
mapping)


Mais as-tu des variables de type regs_t dans ton code, ou te
contentes-tu de faire des cast entre des adresses memoires
(celles des ports) et un reg_t* ?

void write_reg_t(const reg_t* reg, void* port_adr){
memcpy(((char*) port_adr) + OFFSET_a1, &(reg->a1), sizeof(reg->a1) );
memcpy(((char*) port_adr) + OFFSET_a2, &(reg->a2), sizeof(reg->a2) );
memcpy(((char*) port_adr) + OFFSET_big_buffer, &(reg->big_buffer), sizeof(reg->big_buffer) );
}


Mon idée, c'est d'écrire

regs->some_feature_enable = true ;

plutôt que

write_reg (base+SOME_FEATURE_ENABLE_OFFSET, true) ;

Ce qui me parait plus lisible et plus élégant.


Mon idée (mais peut-être pas du tout adapté à ton contexte),
c'est de préparer la structure avant de l'envoyer en mémoire.
reg_t val;
val.some_feature_enable = true ;
val.other_thing= false;
val.param_truc= 64;
write_reg(&val, port);

Mais si on passe son temps à faire de mini-modifs,
ça n'a pas d'intérêt.

Marc Booyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. Paul Éluard)



Avatar
jerome.arbez-gindre

<GAG_ON>
#define REGS_T struct{ uint32_t a1 ; uint32_t a2 ;}

typedef struct regs_t_nopad{
REGS_T;
uint8_t a;
}regs_t_nopad;

struct regs_t{
REGS_T;
uint8_t __padding0[BIG_BUFFER_LOCATION - offsetof(regs_t_nopad,
a)];
uint8_t big_buffer[BIG_BUFFER_SIZE];
};
<GAG_OFF>




<GAG_OFF>
J'avais pensé à quelque chose comme... et finalement ton message m'a
incité à percévérer, et ça donne ça :


#define DECLARE_WITH_MIN_SIZE(size,args...)
union {
u_int8_t __padding__[size] ;
struct {
args
} ;
}


struct toto {
DECLARE_WITH_MIN_SIZE ( 1024,
u_int32_t a1 ;
u_int32_t a2 ;
) ;
u_int8_t mon_buffer[10] ;
} ;



... il faut encore que je trouve un moyen de rendre la nom __padding__
unique... et c'est dans la poche. ( je suis sur la piste __LINE__
__FILE__ etc.)

Avatar
jerome.arbez-gindre



Pour acceder à des ports I/O, je souhaiterai définir une structu re et
la mapper à mes ports.


Est-ce vraiment une bonne idée ? Tu vas te prendre la tête
à écrire une structure de donnée pas portable, avec perte
d'espace mémoire (BIG_BUFFER_LOCATION - 2* sizeof(uint8_t) ),
tout ça pour faire des accès en memcpy ?


Dans ce cas, il n'y a pas de perte d'espace mémoire, c'est de la
mémoire mappée sur un périphérique (dont je ne maitrise pas le
mapping)


Mais as-tu des variables de type regs_t dans ton code, ou te
contentes-tu de faire des cast entre des adresses memoires
(celles des ports) et un reg_t* ?


L'idée, c'est de faire un cast (struct regs_t *) une fois pour toute
avec l'addresse du premier port.
et ensuite d'écrire sur les port en passant uniquement par mon
pointeur sur les registers.


void write_reg_t(const reg_t* reg, void* port_adr){
memcpy(((char*) port_adr) + OFFSET_a1, &(reg->a1), sizeof(reg->a1) );
memcpy(((char*) port_adr) + OFFSET_a2, &(reg->a2), sizeof(reg->a2) );
memcpy(((char*) port_adr) + OFFSET_big_buffer, &(reg->big_buffer), s izeof(reg->big_buffer) );
}


Mon idée, c'est d'écrire

regs->some_feature_enable = true ;

plutôt que

write_reg (base+SOME_FEATURE_ENABLE_OFFSET, true) ;

Ce qui me parait plus lisible et plus élégant.


Mon idée (mais peut-être pas du tout adapté à ton contexte),



c'est de préparer la structure avant de l'envoyer en mémoire.
reg_t val;
val.some_feature_enable = true ;
val.other_thing= false;
val.param_truc= 64;
write_reg(&val, port);

Mais si on passe son temps à faire de mini-modifs,
ça n'a pas d'intérêt.


J'ai près de 1Mo de registre à mapper (et ce sont des registres
différenciés, pas seulement des buffers) ... donc oui, je voudrais y
accéder de façon "chirugicale"

Jérôme A-G