0

I often times write to memory mapped I/O pins like this

P3OUT |= BIT1;

I assumed that P3OUT was being replaced with something like this by my preprocessor:

*((unsigned short *) 0x0222u)

But I dug into an H file today and saw something along these lines:

 volatile unsigned short P3OUT @ 0x0222u;

There's some more expansion going on before that, but it is generally that. A symbol '@' is being used. Above that there are some #pragma's about using an extended set of the C language. I am assuming this is some sort of directive to the linker and effectively a symbol is being defined as being at that location in the memory map.

Was my assumption right for what happens most of the time on most compilers? Does it matter one way or the other? Where did that @ notation come from, is it some sort of standard?

I am using IAR Embedded workbench.

This question is similar to this one: How to place a variable at a given absolute address in memory (with GCC). It matches what I assumed my compiler was doing anyway.

Community
  • 1
  • 1
Nick
  • 1,361
  • 1
  • 14
  • 42
  • It is mentioned in this IAR appnote http://supp.iar.com/Support/?note=36121 But I wouldn't want to use that generally if it isn't something portable. – Nick Dec 15 '14 at 23:15

2 Answers2

1

The short answer to the question in your title is "differently". What's worse is that compilers from different vendors for the same target processor will use different approaches. This one

volatile unsigned short P3OUT @ 0x0222u;

Is a common way to place a variable at a fixed address. But you will also see it used to identify individual bits within a memory mapped location = especially for microcontrollers which have bit-wide instructions like the PIC families.

These are things that the C Standard does not address, and should IMHO, as small embedded microcontrollers will eventually end up being the main market for C (yes, I know the kernel is written in C, but a lot of user-space stuff is moving to C++).

I actually joined the C committee to try and drive for changes in this area, but my sponsorship went away and it's a very expensive hobby.

A similar area is declaring a function to be an ISR.

This document shows one of the approaches we considered

kdopen
  • 8,032
  • 7
  • 44
  • 52
  • IMHO, C has some major deficiencies as an embedded language, and I've long wished a standards committee would either improve it or develop something better; any interest in chatting about such things? – supercat Dec 15 '14 at 23:50
  • Yep, but I can't afford to travel 2 weeks every year at my own expense. The committee is aware of the issue, and I expect it will be addressed eventually – kdopen Dec 15 '14 at 23:51
  • Any idea if C will ever define genuinely-portable integer types or bitfields? I'd like to see, for example, a `wrap32_t` which behaved like `uint32_t` *except* that it would be exempt from any int-size-dependent promotions; the product of two `wrap32_t` values, or the sum of a `wrap32_t` and a signed value, would be a `wrap32_t` even on a system where `int` is 64 bits. – supercat Dec 16 '14 at 00:01
  • That sounds like a rather fundamental change to the promotion rules. the committee is very conservative (small c) – kdopen Dec 16 '14 at 00:06
  • As I would want things implemented, all operations on existing integer types would continue to operate as they always have. Only new types would behave differently. As I see it, the existing rules have evolved as they have because of a desire to avoid requiring implementations to change in ways which would break pre-existing code. If new types are defined with names which are presently designated as "reserved" and are not used by any existing implementations, requiring those new types to use new rules would not compel implementations to behave in a way that would break existing code... – supercat Dec 16 '14 at 00:12
  • ...since no existing code would use such types, and code which does use such types could be presumed to want the new semantics. – supercat Dec 16 '14 at 00:18
  • @supercat To clarify, you are saying "I want my bitfields to remain unsigned, regardless of whether or not they can now fit into to positive range of a signed int on a 64bit target system". Which essentially means your bitfield is exempt from promotion rules. Why not just explicitly cast to an unsigned fixed width type then whenever you're working with bitfields as part of a coding standard - wouldn't that always be portable? Or is your complaint that you shouldn't need to go through all of that extra effort? The standard should just know that treating a bit field as signed could break stuff. – Nick Dec 16 '14 at 20:55
  • @Nick: Sorry I was unclear; I would like portable unsigned integer types, and I would like a portable means of defining bitfields. The subsequent discussions were focused on the former (I'm interested in bitfields, but they're a completely separate issue). At present, given `uint32_t current,prev; uint64_t total;`, a statement like `total += current-prev;` will be perfectly valid (producing no diagnostic) when `int` is 32 bits or smaller, and also completely valid (with no diagnostic) when `int` is larger, but the meanings will be completely different. – supercat Dec 16 '14 at 21:07
  • @Nick: What I would like would be a type which could be given to `current` and `prev` which would ensure that `current-prev` would not do anything other than mod-4294967296 arithmetic. Note, btw, that even a compiler on a machines with an unusual (e.g. 36-bit) register size could support such a type; it would simply have to generate `AND reg,0xFFFFFFFF` instructions at appropriate places in the code. Adding instructions would slow code down compared with not adding them, but slower code that does what is required to yield correct results is better than faster code that doesn't. – supercat Dec 16 '14 at 21:13
  • @Nick: A detail I should clarify: I don't want to encourage code like `total += current-prev;`, and would be happy if the compiler required an explicit cast from `wrap32_t` to to `uint32_t` before the addition. What's important is not that the compiler accept everything, but rather that it reject usages of `wrap32_t` which would aren't performed using mod-4294967296 arithmetic. – supercat Dec 16 '14 at 22:57
1

Although an expression like (unsigned char *)0x1234 will, on many compilers, yield a pointer to hardware address 0x1234, nothing in the standard requires any particular relationship between an integer which is cast to a pointer and the resulting address. The only thing which the standard specifies is that if a particular integer type is at least as large as intptr_t, and casting a pointer to that particular type yields some value, then casting that particular value back to the original pointer type will yield a pointer equivalent to the original.

The IAR compiler offers a non-standard extension which allows the compiler to request that variables be placed at specified hard-coded addresses. This offers some advantages compared to using macros to create pointer expressions. For one thing, it ensures that such variables will be regarded syntactically as variables; while pointer-kludge expressions will generally be interpreted correctly when used in legitimate code, it's possible for illegitimate code which should fail with a compile-time error to compile but produce something other than the desired effect. Further, the IAR syntax defines symbols which are available to the linker and may thus be used within assembly-language modules. By contrast, a .H file which defines pointer-kludge macros will not be usable within an assembly-language module; any hardware which will be used in both C and assembly code will need to have its address specified in two separate places.

supercat
  • 77,689
  • 9
  • 166
  • 211
  • That's a really good point W.R.T. being able to access the symbols from assembly. – Nick Dec 16 '14 at 00:01
  • Actually, for small micros the assembler and compiler are usually tightly coupled and the assmebler can often "use" C header files (at least for pre-processor macros) – kdopen Dec 16 '14 at 00:07
  • @kdopen: The assembler and compiler are pretty tightly coupled, and many assemblers use a C-style preprocessor, but I don't think I've seen assemblers that can use C-style syntax for casting integers to pointers. – supercat Dec 16 '14 at 00:24