MISRA Rule 45

Hi!

I would like to define a pointer to a hardware register. I have done as follows:

typedef unsigned int Hw_Register;

volatile Hw_Register* const gp_dor_address = (Hw_Register* const)0x84501500;

When checking against MISRA I get the following error:

line 74: error #1703-D: MISRA Rule 45: cast from type "unsigned int" to type "Hw_Register *" not allowed volatile Hw_Register* const gp_dor_address = (Hw_Register* const)0x84501500;

How do I define a constant pointer to a register according to MISRA?

Regards, Mikael Lundqvist

Reply to
Mikael Lundqvist
Loading thread data ...

Well, I guess because you are hiding the unsigned int by a typedef. MISRA rule 45 does not allow that.

I guess you are in a dilemma here.

Hardware related implementations (no matter which compiler/toolchain) usually employ coding mechanisms that MISRA rules see as "dangerous". Which in a larger context of a huge application may make sense. The low level stuff however is very hard - if not impossible - to implement following MISRA.

Perfectly legal expressions (according to ANSI) like:

unsigned int *ptr; ptr = (unsigned int *)0x67a9;

*ptr = 0xaa55; *(int * const)(0x67a9) = 0xaa55;

Trigger a massive wave of MISRA error messages:

MISRA C rule 53 violation: [R] all non-null statements shall have a side-effect 17: *(int * const)(0x67a9) = (unsigned int* const)0xaa55; MISRA C rule 13 violation: [A] specific-length typedefs should be used instead of the basic types MISRA C rule 44 violation: [A] redundant explicit casts should not be used MISRA C rule 45 violation: [R] type casting from any type to/from pointers shall not be used MISRA C rule 13 violation: [A] specific-length typedefs should be used instead of the basic types MISRA C rule 44 violation: [A] redundant explicit casts should not be used MISRA C rule 45 violation: [R] type casting from any type to/from pointers shall not be used MISRA C rule 53 violation: [R] all non-null statements shall have a side-effect

Anyone proficient in embedded C programming will use these expressions (together with volatile) to describe Special Funtion Registers or device I/O adresses.

At best you disable MISRA for hardware dependend modules, document why you have done so and use lint to check for any suspicious code constructs.

regards /jan

Mikael Lundqvist schrieb in im Newsbeitrag: snipped-for-privacy@posting.google.com...

follows:

const)0x84501500;

Reply to
Jan Homuth

You could also define all the relevant symbols in an assembly file, then define the symbols as "extern" in your code.

If MISRA has some way of temporarily turn off a rule (i.e. with a "#pragma" command or the like) then it may be a good thing to do, with a slew of comments as to why you're doing it.

--
Tim Wescott
Wescott Design Services
 Click to see the full signature
Reply to
Tim Wescott

Registers don't have addresses whose value can be taken. This is illegal in any form of C.

legal, but not portable.

perfectly legal anywhere, provided ptr has been initialized to point somewhere legal.

You can't cast the lvalue. You can only cast the value to be put into it. Illegal everywhere.

You shouldn't need the assistance of MISRA to avoid those particular foul-ups.

BTW, please don't top-post, and please do snip. The practice of top-posting a complete snipped bottom posted message only clutters the world with further useless verbiage.

--
"If you want to post a followup via groups.google.com, don't use
 the broken "Reply" link at the bottom of the article.  Click on 
 Click to see the full signature
Reply to
CBFalconer

follows:

Two options AFAIK

1- if your linker supports it you can define it there. GNU ld can be used in that fashion. 2- Use MISRAs exception capability and use the form you are using but document it as an exception. At least the last revision of MISRA I read had a provision for exceptions.

Robert

Reply to
R Adsett

You've never worked on a processor, whose initial register set starts at address 0? Very handy to run a programm just out of the registers, especially when testing core memory!

Andreas

--
It's not the things you don't know what gets you into trouble. It's
the things you do know that just ain't so.
 Click to see the full signature
Reply to
Andreas Hadler

Come now, "memory mapped register" is surely a fairly common usage. And referring to memory as a "register file" may be old-fashioned but I do seem to recall seeing the term in documentation recently (just don't ask me for a reference).

On the other hand, peripheral reigster definition is pretty much inheritly non-portable.

Robert

Reply to
R Adsett

[...]

The main problem is that you even tried to apply a portability / safety oriented C coding ruleset such as MISRA to this strictly hardware-specific task. That makes no sense.

You don't. You might as well try to make an omelett according to a "no breaking of eggs" standard.

--
Hans-Bernhard Broeker (broeker@physik.rwth-aachen.de)
Even if all the snow were burnt, ashes would remain.
Reply to
Hans-Bernhard Broeker

Well, it's a GCC extention. So, while it's not (std.) conformant, it's not 'illegal everywhere' either.

Regards, Andras Tantos

Reply to
Andras Tantos

registers can be memory mapped, and I think here we are talking about memory mapped hardware registers not cpu registers.

who else would you access memory mapped registers in peripherals?

doesn't have to be, what ever is at 0x67a9 in this micro will probably be some where else in another.

but it would be nicer to use a define or somthing.

hmm...

compiles with gcc and does what I'd expect; write the value 0xaa55 to adress 0x67a9 using STR

-Lasse

Reply to
Lasse Langwadt Christensen

I don't have a compiler or tool that complains about the above, other than noting that the "const" is meaningless. What in the standard indicates this is illegal?

--
John W. Temples, III
Reply to
John Temples

It isn't casting an lvalue it is casting a constant to a pointer which is dereferenced to yield an lvalue.

Reply to
nospam

Touche. A point, a veritable point.

--
"If you want to post a followup via groups.google.com, don't use
 the broken "Reply" link at the bottom of the article.  Click on 
 Click to see the full signature
Reply to
CBFalconer

Since, somewhere in the code, there HAS to be a translation point between the 'standard' language and something that accesses the underlying hardware, how does the MISRA standard suggest this be done?

No use saying "do it in assembler"- a safety and portability standard couldn't even contemplate such. A HAL shunts the problem a stage down the line, but it's still necessary somewhere.

Paul Burke

Reply to
Paul Burke

Tim, thanks for your comment

Again, as you mention it, MISRA is circumvented. This is one way to do it. But Assembly is not really necessary. The same can be done in C. Another detour is the creation of object files or a library containing 'Non MISRA checked' functions with proper protoyping.

There are tools on the market that allow to disable MISRA rules or use special configuration files. One thing common to all: Proper documentation is mandatory.

with kind regards /jan

Reply to
Jan Homuth

Hi all, As a followup to CBFalconer's contribution and the resulting discussion: It is always possible to find a hair in the soup. ;-)

To clarify some issues: The example was taken from an article in the embedded systems programming magazine (Programmer's test) which I find very enlightening because it reflects 99% of the C language related support questions I get to handle every day.

The 'registers' I was mentioning were meant to be so called Special Function Registers of peripherals on an MCU.

It is common procedure (as with many toolchains I know) to implement header files for MCU derivatives this way. This goes for GNU as well as vendor specific tools alike.

Before posting I have tested the example with a little testcase.

The example:

unsigned int *ptr; ptr = (unsigned int *)0x67a9;

*ptr = 0xaa55;

*(int * const)(0x67a9) = 0xaa55;

should better have been posted like:

/******* memio.c ********/ volatile unsigned int* SFR_IO_addr = (volatile unsigned int* )0x1500;

unsigned int *ptr;

void foo(void) { ptr = (unsigned int *)0x67a9; /* assign address */ * ptr = 0xaa55; /* store datum into address */ *(int * const)(0x67a9) = 0xaa55; /*The expression is legal but somewhat cyptic.*/

while(*SFR_IO_addr==0) { ; /* wait forever while SFR_IO_addr = 0 */ } }

void main(void) { foo(); }

/******* EOF memio.c ********/ So we do not run into the 'uninitialized pointer' issue CBFalconer mentioned.

I hope this clears the fog a bit.

with kind regards /jan

Reply to
Jan Homuth

This case would be more clear with other way of setting the parentheses:

*((int *)0x67a9) = 0xaa55;

(The example is bad, many architectures are not happy with a longer datum (int, 16 or 32 bits) loaded to an odd address).

--
Tauno Voipio
tauno voipio (at) iki fi
 Click to see the full signature
Reply to
Tauno Voipio

The _best_ thing to be said of MISRA is that it recognizes it is unreasonable to expect complete compliance, that the rules will have to be broken from time to time (indeed, rule 3 says "break rule 1" in almost so many words), and gives a procedure for doing so.

In MISRA 1, it is described in section 5.2.3 "Deviation procedure." I don't have a copy of MISRA 2 yet...

Regards,

-=Dave

--
Change is inevitable, progress is not.
Reply to
Dave Hansen

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.