Type struct question
-
I read a demo code from a semiconductor producer, in cpu.h, there are some typedef structs for registers.
typedef struct {
u32_T asid; /* ASID, 32-bit access */
struct {
u32_T ASID:10, /* Bit 0-15, Address space identifier */
rsvd1:22; /* Bit10-31, reserved */
};
} ASID_T;According to the comments, I think the writer thought he defined a struct to represent the asid register, and the struct can be accessed in 32 bit pattern or bit-field way. But, is this struct can do that, I mean, are the U32_T asid and the anonymous struct share a same memory location? I think it can't work. just want to hear some other opinions.
-
I read a demo code from a semiconductor producer, in cpu.h, there are some typedef structs for registers.
typedef struct {
u32_T asid; /* ASID, 32-bit access */
struct {
u32_T ASID:10, /* Bit 0-15, Address space identifier */
rsvd1:22; /* Bit10-31, reserved */
};
} ASID_T;According to the comments, I think the writer thought he defined a struct to represent the asid register, and the struct can be accessed in 32 bit pattern or bit-field way. But, is this struct can do that, I mean, are the U32_T asid and the anonymous struct share a same memory location? I think it can't work. just want to hear some other opinions.
They don't share the same memory location. To do that the outer
struct
must be aunion
(see Union declaration - cppreference.com[^] ). From my point of view you are right that it looks like a definition for shared access and that is an error in the documentation. To verify this have a look at the register specifications in the data sheet. -
They don't share the same memory location. To do that the outer
struct
must be aunion
(see Union declaration - cppreference.com[^] ). From my point of view you are right that it looks like a definition for shared access and that is an error in the documentation. To verify this have a look at the register specifications in the data sheet. -
How about this struct:
typedef struct {
struct {
u32_T ASID:10, /* Bit 0-15, Address space identifier */
rsvd1:22; /* Bit10-31, reserved */
} asid; /* ASID, 32-bit access */
} ASID_T;it can implement the 32-bit access and bit access, right?
With that you have no access to the 32-bit value. Use a union instead:
typedef union {
u32_T asid; /* ASID, 32-bit access */
struct {
u32_T ASID:10, /* Bit 0-15, Address space identifier */
rsvd1:22; /* Bit10-31, reserved */
};
} ASID_T; -
With that you have no access to the 32-bit value. Use a union instead:
typedef union {
u32_T asid; /* ASID, 32-bit access */
struct {
u32_T ASID:10, /* Bit 0-15, Address space identifier */
rsvd1:22; /* Bit10-31, reserved */
};
} ASID_T; -
Then use what you need in your code (
struct
oru32_T
). As last resort you can also use casting:/* A pointer to ASID_T struct */
ASID_T *asid = ASID_REG_ADDR;
/* Cast it to a pointer to 32-bit reg value */
u32_T *asidReg = (u32_T*)asid; -
SO use pointers.
-
Then use what you need in your code (
struct
oru32_T
). As last resort you can also use casting:/* A pointer to ASID_T struct */
ASID_T *asid = ASID_REG_ADDR;
/* Cast it to a pointer to 32-bit reg value */
u32_T *asidReg = (u32_T*)asid;From memory that breaks several other MISRA-C rules under section 11 ... 11.1 through 11.6 restrict what you can do with C casts. Hardware related implementations usually involve coding that MISRA rules see as "dangerous". I can tell you from experience the easiest way around them is drag it down to included assembler blocks. The assembler blocks fall outside the scope of MISRA. You could define two different extern's in a .h file to the same register with assembler which would essentially restore the use of the union yet be MISRA compliant :-)
In vino veritas
-
From memory that breaks several other MISRA-C rules under section 11 ... 11.1 through 11.6 restrict what you can do with C casts. Hardware related implementations usually involve coding that MISRA rules see as "dangerous". I can tell you from experience the easiest way around them is drag it down to included assembler blocks. The assembler blocks fall outside the scope of MISRA. You could define two different extern's in a .h file to the same register with assembler which would essentially restore the use of the union yet be MISRA compliant :-)
In vino veritas
I suspected that casting may be limited too. I don't know MISRA rules well but when macros - or better - inline functions are allowed those can be used to split the 32-bit value into bits fields or vice versa.
-
I suspected that casting may be limited too. I don't know MISRA rules well but when macros - or better - inline functions are allowed those can be used to split the 32-bit value into bits fields or vice versa.
No those are still technically C and hence under MISRA rules. It's a really weird standard adopted by some automobile manufacturers and a few telco's as some sort of we will get better code think-tank. The reality is all studies have shown it has almost zero improvement on software bug numbers or severity. As I said, the few times I have run across it, I do what most do ... drop to assembler and go around the rubbish. That in itself tells you how good the standard is. Other than that you can go thru the process to raise a deviation (section 5.3.2) but that means documenting and getting approval for the variation which is far more red tape than most can handle. The standard libraries are also exempt from MISRA under a special rule 6.6 and so you can implement your own special standard library function to get around it. Think about it memcpy and memmove take void* and you have a specific register address target :-)
In vino veritas
-
I read a demo code from a semiconductor producer, in cpu.h, there are some typedef structs for registers.
typedef struct {
u32_T asid; /* ASID, 32-bit access */
struct {
u32_T ASID:10, /* Bit 0-15, Address space identifier */
rsvd1:22; /* Bit10-31, reserved */
};
} ASID_T;According to the comments, I think the writer thought he defined a struct to represent the asid register, and the struct can be accessed in 32 bit pattern or bit-field way. But, is this struct can do that, I mean, are the U32_T asid and the anonymous struct share a same memory location? I think it can't work. just want to hear some other opinions.
This doesn't seem to make sense: the inner struct is just a type definition without an actual typename, but it does not define a variable of that type:
struct { // <-- no typedef, no tag to use as a struct identifier u32\_T ASID:10, /\* Bit 0-15, Address space identifier \*/ rsvd1:22; /\* Bit10-31, reserved \*/ }; // <-- end of type specification, but no variable name
You might just as well delete that inner struct declaration, since, being unnamed and unused, there is no way to use it later. If you move the symbol
asid
to the end of that type declaration,asid
would be astruct
, not anint
, although it would occupy exactly 4 bytes, which may or may not coincide with the size of anint
in your system.GOTOs are a bit like wire coat hangers: they tend to breed in the darkness, such that where there once were few, eventually there are many, and the program's architecture collapses beneath them. (Fran Poretto)
-
This doesn't seem to make sense: the inner struct is just a type definition without an actual typename, but it does not define a variable of that type:
struct { // <-- no typedef, no tag to use as a struct identifier u32\_T ASID:10, /\* Bit 0-15, Address space identifier \*/ rsvd1:22; /\* Bit10-31, reserved \*/ }; // <-- end of type specification, but no variable name
You might just as well delete that inner struct declaration, since, being unnamed and unused, there is no way to use it later. If you move the symbol
asid
to the end of that type declaration,asid
would be astruct
, not anint
, although it would occupy exactly 4 bytes, which may or may not coincide with the size of anint
in your system.GOTOs are a bit like wire coat hangers: they tend to breed in the darkness, such that where there once were few, eventually there are many, and the program's architecture collapses beneath them. (Fran Poretto)