Trying to understand the workings of a Memory Mapped I/O

Do you have a question? Post it now! No Registration Necessary

Translate This Thread From English to

Threaded View
Here is the sample area:

#define P0 ((*(__R volatile unsigned char *)(unsigned char)0x0))
#define P1 ((*(__R volatile unsigned char *)(unsigned char)0x1))
#define P2 ((*(__R volatile unsigned char *)(unsigned char)0x2))
#define P3 ((*(__R volatile unsigned char *)(unsigned char)0x3))


How would you describe what this is or does? If someone could break it down
so I could understand what is going on I would be in your debt.



Re: Trying to understand the workings of a Memory Mapped I/O


Quoted text here. Click to load it

Why would your teacher assign you something he had not discussed?

Anyway, when confused about declarations, read from R to L

// #define P0 ((*(__R volatile unsigned char *)(unsigned char)0x0))

// (unsigned char)0x0

You have a character constant of 0

// (__R volatile unsigned char *)

It is cast to a volatile pointer for some bad reason, and who knows what __R is,
because it is a user's macro.

// *(..)

Take the contents of the (nonsense) pointer.

// #define P0

Might as well compound the nonsense with bad practice by using a gratuitous
macro.

Good luck on your homework.






Re: Trying to understand the workings of a Memory Mapped I/O
thanks for your help. Would you know of a book or website that describes
this type of process.

Quoted text here. Click to load it
How does *(..) take the contents?

Las



Re: Trying to understand the workings of a Memory Mapped I/O


Quoted text here. Click to load it

There are billions.

Quoted text here. Click to load it

When used that way, it is the C idiom for "take the contents of the address".
It is followed by an address.

Before assigning this, your teacher should have explained the "address of" and
"content of" operators in C. Maybe she jumped way ahead to scare you.


Quoted text here. Click to load it


Re: Trying to understand the workings of a Memory Mapped I/O
Quoted text here. Click to load it


Goodness --- get yourself a C textbook and start to learn from it
_now_.  It may already be too late for this, but it'll definitely be
too late if you delay this necessary previous study even further into
this new course this homework problem was taken from.  You may simply
not be fit for this course yet.

--
Hans-Bernhard Broeker ( snipped-for-privacy@physik.rwth-aachen.de)
Even if all the snow were burnt, ashes would remain.

Re: Trying to understand the workings of a Memory Mapped I/O
Quoted text here. Click to load it
__R is,
Quoted text here. Click to load it

Actually, since the description indicates that this is to allow access to
memory mapped I/O registers, this is a valid way to handle this(depending on
the definition of the __R macro).  Presumably, the register are located at
addresses 0 through 3 of the memory map.  The volatile qualifer is needed to
prevent the compiler from optimizing the access to the value to far.

Adam



Re: Trying to understand the workings of a Memory Mapped I/O
On Mon, 01 Dec 2003 02:47:04 GMT, "Adam Braun"

Quoted text here. Click to load it

The cast of the literal values to unsigned char before casting to a
pointer is gratuitous and just plain dumb, unless the compiler is
severely non-conforming.  The literals 0x0, 0x1, 0x2, and 0x3 have the
type int and are unchanged by any transformations other than to type
_Bool, which I highly doubt this compiler supports.

It looks to me like a macro written by somebody who doesn't understand
how values work in C.

--
Jack Klein
Home: http://JK-Technology.Com
We've slightly trimmed the long signature. Click to see the full one.
Re: Trying to understand the workings of a Memory Mapped I/O
Quoted text here. Click to load it
to
this(depending on
Quoted text here. Click to load it
at
needed to

While the first cast isn't needed in the general case, it doesn't really
hurt to have it.  On the other hand, it may have a valid usage here.  If
this is for an 8 bit processor, then this technique may (hypothetically)
force the compiler to use single byte addressing to get to register instead
of, for instance, using an 16 bit register which would be less efficient.
Without getting into the details of the processor and compiler, you can't
know this.  Admitedly, you would like the compiler to handle this for you,
but sometimes they aren't perfect.  The end result is that it doesn't hurt
anything in this particular case and it may have an actual usage.




Re: Trying to understand the workings of a Memory Mapped I/O
On Mon, 01 Dec 2003 06:47:43 GMT, "Adam Braun"

Quoted text here. Click to load it

???

The final cast is to (volatile unsigned char *), which is a specific
type that has a specific size.  The fact that the micro involved might
have multiple address spaces, as for example does the 8051, is
presumably handled by the "__R" macro.

There can't be a compiler out there that would generate different
object code for these two lines:

   ((*(__R volatile unsigned char *)(unsigned char)0x0))

...and:

   ((*(__R volatile unsigned char *)0x0))

...at least not that anyone would buy.

--
Jack Klein
Home: http://JK-Technology.Com
We've slightly trimmed the long signature. Click to see the full one.
Re: Trying to understand the workings of a Memory Mapped I/O

Quoted text here. Click to load it

Probably not.  It's possible, though, that the __R indicates a separate
address space that uses only 8 bit addressing, and that without the
(unsigned char) cast, the compiler would issue a warning because
high-order bits are potentially "thrown away", based on a type size,
rather than value, test.  We don't know.  

It could simply be the programmer's idiom to make port addresses
explicitly 8 bits wide to reflect the size of that address space.  I use
'' for a null character, for example, knowing full well that 0 means
the same thing to the C compiler.

Thad

Re: Trying to understand the workings of a Memory Mapped I/O
Quoted text here. Click to load it
... snip ...
Quoted text here. Click to load it

All of which brings up the ancient lore - all casts are
suspicious, therefore eschew them as the plague.

I think nobody has pointed out that the __R macro lies in the
implementors name space, and thus has no standards requirements.
Even so, its actual wording would probably be instructive.

--
Chuck F ( snipped-for-privacy@yahoo.com) ( snipped-for-privacy@worldnet.att.net)
   Available for consulting/temporary embedded and systems.
We've slightly trimmed the long signature. Click to see the full one.
Re: Trying to understand the workings of a Memory Mapped I/O
snipped-for-privacy@spamcop.net says...
Quoted text here. Click to load it
Of course it's also possible that the __R is a compiler specific keyword
rather than a macro.

Robert
--
" 'Freedom' has no meaning of itself.  There are always restrictions,
be they legal, genetic, or physical.  If you don't believe me, try to
We've slightly trimmed the long signature. Click to see the full one.
Re: Trying to understand the workings of a Memory Mapped I/O
snipped-for-privacy@bhconsult.com says...
Quoted text here. Click to load it
is,
Quoted text here. Click to load it

It's being declared volatile because it refers to an I/O port; you don't
want the compiler optimizing it out, and/or failing to read/write it.

For example:

    P0 = 0x01;    /* Turn on thingy attached to bit 0 of Port 0    */
    while(P0 & 0x01)    
    {
        BlinkLights();
        BlowHorn();
    }
    // Until thing signals by driving P0.0 LOW. */

..Now, the compiler might optimize that P0 is already true due to the
assignment, and never execute what's in the braces. Volatile forces P0
to be read back for the AND operation.


--Gene



Re: Trying to understand the workings of a Memory Mapped I/O


Quoted text here. Click to load it
is,
Quoted text here. Click to load it

My problem was not with the volatile, but with the initial superflous cast to
unsigned char. What's wrong with :

#define P0 ((*(__R volatile unsigned char *)0x0))

?

Better written as:

#define P0 ( *(__R volatile unsigned char *)0x0 )

Quoted text here. Click to load it


Re: Trying to understand the workings of a Memory Mapped I/O
snipped-for-privacy@bhconsult.com says...
Quoted text here. Click to load it
is,
Quoted text here. Click to load it

Some of the compilers I've used will complain that you are trying to
cast a integer or a long to a char*; the preprocessor in these cases
treat all (non floating) literal values as int or long, and the compiler
won't perform an implicit cast to a pointer of a different (smaller?)
type.  I've had to insert explicit casts exactly like this to get the
compiler to swallow it.

--Gene

Re: Trying to understand the workings of a Memory Mapped I/O
On Sun, 30 Nov 2003 23:07:47 -0500, Gene S. Berkowitz

Quoted text here. Click to load it
__R is,
Quoted text here. Click to load it

There is no such thing as an "implicit cast".  Use of the term
demonstrates a lack of understanding of the C type system.  In C there
are conversions.  Some are automatic and require no cast.  Others are
not allowed without a cast.  A cast operator performs an explicit
conversion which might or might not be automatic in its absence.

Quoted text here. Click to load it

That's absurd.  Any compiler which will not accept this is horribly
broken, so much so that it is lying if it claims to be a C compiler at
all.

The type of the literal constants "0x0", "0x1", "0x2", and "0x3" it
signed int in every actual C compiler that has ever existed, because
otherwise it is not a C compiler.

Any compiler that treats a cast of a signed int to a pointer any
differently than it does the cast of an unsigned char to a pointer is
absolutely broken.

The actual wording of the ANSI/ISO C Standard:

========
An integer may be converted to any pointer type. Except as previously
specified, the result is implementation-defined, might not be
correctly aligned, might not point to an entity of the referenced
type, and might be a trap representation.
========

Now it makes no difference whether you understand that the standard
uses the term "an integer" to encompass all of the integer types, or
assume it just means type int.  A compiler is required to accept a
cast of a signed int to a pointer type.

The macro in question was written by either:

a.  Somebody ignorant of the C type system.

b.  Somebody acutely aware of a non-conforming compiler.

--
Jack Klein
Home: http://JK-Technology.Com
We've slightly trimmed the long signature. Click to see the full one.
Re: Trying to understand the workings of a Memory Mapped I/O
snipped-for-privacy@spamcop.net says...
Quoted text here. Click to load it
 
Quoted text here. Click to load it

You can call it whatever you like; it doesn't change the fact that
tools (I won't call it a C compiler, for your blood pressure),
especially those sold into the embedded market, are often non-standard
and/or broken.  I can insert a cast, and the error goes away, or I
can deliver my code late because I'm spending two hours on the phone
explaining it to "tech support", then waiting 3 months for the fix.

--Gene


Re: Trying to understand the workings of a Memory Mapped I/O
On Mon, 1 Dec 2003 00:17:44 -0500, Gene S. Berkowitz

Quoted text here. Click to load it

Are you claiming that you know of a compiler that generates a warning
or error for this:

   unsigned char uc = P0;

...when the P0 macro is defined as:

   #define P0 ((*(__R volatile unsigned char *)0x0))

...but does not when the P0 macro is defined as:

   #define P0 ((*(__R volatile unsigned char *)(unsigned char)0x0))

???

I have sent back alleged C compilers this bad for a refund.  It would
be better to code in assembly than some language that some unqualified
idiot made up.  There is no quality control at all, and you would have
no idea at all of what the code the compiler did accept would actually
do when executed.  If it could bungle something as basic as this, who
knows what object code it would generate from other basic C source
that it misinterprets?

As for compilers for embedded systems, I have been using them for more
than 20 years, for 8 through 32 bit controllers and processors, and
for DSPs as well, so I think I am aware of the state of the market.

--
Jack Klein
Home: http://JK-Technology.Com
We've slightly trimmed the long signature. Click to see the full one.
Re: Trying to understand the workings of a Memory Mapped I/O
[...]

Quoted text here. Click to load it


It's worse than that, because __R is explicitly _not_ a user macro.

It's in the namespace reserved for usage by the compiler implementor.
This implies it's specifically unfit for being used in normal code
that tries to be anywhere near portable.  The reason being that
portable code cannot know what meaning __R might have on a randomly
chosen platform, nor is it allowed to re-#define it to meaning
something else if it doesn't like the meaning it happens to have.


--
Hans-Bernhard Broeker ( snipped-for-privacy@physik.rwth-aachen.de)
Even if all the snow were burnt, ashes would remain.

Re: Trying to understand the workings of a Memory Mapped I/O
Quoted text here. Click to load it
down

Basically, it's a kludge.  (folks in comp.lang.c will undoubtedly point out
that it's not "guaranteed" to work -- esp. P0)

In each case, the constants 0, 1, 2, and 3 are being cast to unsigned char's
(probably out of confusion  :-/  ).  I believe these (rightmost) casts are
superfluous.

Moving towards the left, each of these constants is then cast to a pointer
to an "unsigned char" -- that being a typical concept of a "generic byte"

The volatile keyword tells the compiler not to optimize away references
to this "item" (since you claim it represents a memory mapped I/O
device, this is "as expected"...)

No comment as to what the "__R" macro does.

The leftmost '*' tells the compiler to dereference this "pointer".
In other words, it evaluates to "the value of the unsigned char
located at the 'address' referenced by this pointer that happens
to have the value ("address") of "0x0", "0x1", etc."

The leftmost token following the #define keyword allows the programmer
to refer to this contortion with a simple mnemonic -- i.e. "P0"
(Port0), etc.

--don

N.B. Incoming mail is not accepted at this email address.



Site Timeline