Can a 32 bit pointer be forced?

Go To Last Post
20 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have an existing routine, one of whose arguments is a word pointer. On the 1284p pointers are 16 bit, but this one points to flash above 64K so needs to be 32 bit. Is there a way to force the pointer to 32 bits? Simplifying,

//Existing code

word readflashword(word *address)
{
 address++;         //adds 2 to 16 bit pointer
 return(*address);  //uses 16 bit address
}

//Desired modified behavior
word readflashword(word __MAGIC_ATTRIBUTE__ *address)
{
 address++;         //adds 2 to 32 bit poiter
 return(*address);  //uses 32 bit address
}

I know the arg type could be changed to uint32_t using explicit increments of 2 but I'd like to keep the source code unchanged for legacy compatibility with builds on other platforms.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Since you are manipulating pointer to __flash, I will assume you are using IAR, ImageCraft or CodeVision.

Surely they will use the model (and instructions) relevant to your AVR. i.e. a 24 or 32 bit pointer.

You can always do nasty arithmetic and cast backwards and forwards, but I would attempt to avoid that.

You seem to be posting in the avr-gcc forum anyway so this looks like your only choice if the compiler does not support far __flash.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why not use a conditional compilation on a typedef?

#if defined(PLATFORM_A)
  typedef uint16_t Word;
#elif defined(PLATFORM_B)
  typdef uint32_t Word;
#endif

void MyFunc(Word* Ptr) {...}

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Perhaps I oversimplified - I am using gcc and my alternate routine uses pgm_read_word_far((uint32) addr). At this point the other routine is not used and I'd just like to have it compile without a slew of warnings (e.g. right shifts >=16). It would be fine to eliminate it with a preprocesser directive like

#if sizeof(*word)>=4
...
#endif

but I couldn't figure out how to do that either.

But if this magic attribute did exist I could leave everything as-is and have it compile without warnings on all platforms, and even use it on mine by calling

uint32_t address;
data=readflashword((word __MAGIC_ATTRIBUTE__ *)address);

Dean, wouldn't that change sizeof(*Ptr)from 16 to 32 with a sizeof(Ptr)==16 in both cases?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You cannot use sizeof in the pre-processor.

But you can certainly detect the AVR chip from it's own macro.
Or better still by the code-generation model macro.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

but I couldn't figure out how to do that either.

Create an empty .c file and give the command:

C:\> avr-gcc -E -dM empty.c

which will make the compiler dump out all it's predefined macros...

#define __DBL_MIN_EXP__ (-125)
#define __FLT_MIN__ 1.17549435e-38F
#define __DEC64_DEN__ 0.000000000000001E-383DD
#define __CHAR_BIT__ 8
#define __WCHAR_MAX__ 32767
#define __DBL_DENORM_MIN__ 1.40129846e-45
#define __FLT_EVAL_METHOD__ 0
#define __DBL_MIN_10_EXP__ (-37)
#define __FINITE_MATH_ONLY__ 0
#define __GNUC_PATCHLEVEL__ 2
#define __DEC64_MAX_EXP__ 384
#define __SHRT_MAX__ 32767
#define __LDBL_MAX__ 3.40282347e+38L
#define __UINTMAX_TYPE__ long long unsigned int
#define __DEC32_EPSILON__ 1E-6DF
#define __LDBL_MAX_EXP__ 128
#define __SCHAR_MAX__ 127
#define __DBL_DIG__ 6
#define __SIZEOF_INT__ 2
#define __SIZEOF_POINTER__ 2
#define __USER_LABEL_PREFIX__ 
#define __STDC_HOSTED__ 1
#define __LDBL_HAS_INFINITY__ 1
#define __FLT_EPSILON__ 1.19209290e-7F
#define __LDBL_MIN__ 1.17549435e-38L
#define __DEC32_MAX__ 9.999999E96DF
#define __SIZEOF_LONG__ 4
#define __DECIMAL_DIG__ 9
#define __AVR_2_BYTE_PC__ 1
#define __LDBL_HAS_QUIET_NAN__ 1
#define __GNUC__ 4
#define __FLT_HAS_DENORM__ 1
#define __SIZEOF_LONG_DOUBLE__ 4
#define __DBL_MAX__ 3.40282347e+38
#define __DBL_HAS_INFINITY__ 1
#define __DEC32_MIN_EXP__ (-95)
#define __LDBL_HAS_DENORM__ 1
#define __DEC128_MAX__ 9.999999999999999999999999999999999E6144DL
#define __USING_SJLJ_EXCEPTIONS__ 1
#define __DEC32_MIN__ 1E-95DF
#define __DBL_MAX_EXP__ 128
#define __DEC128_EPSILON__ 1E-33DL
#define __LONG_LONG_MAX__ 9223372036854775807LL
#define __SIZEOF_SIZE_T__ 2
#define __SIZEOF_WINT_T__ 2
#define __GXX_ABI_VERSION 1002
#define __FLT_MIN_EXP__ (-125)
#define __DBL_MIN__ 1.17549435e-38
#define __DEC128_MIN__ 1E-6143DL
#define __REGISTER_PREFIX__ 
#define __DBL_HAS_DENORM__ 1
#define __AVR_ARCH__ 2
#define __NO_INLINE__ 1
#define __FLT_MANT_DIG__ 24
#define __VERSION__ "4.3.2"
#define __DEC64_EPSILON__ 1E-15DD
#define __DEC128_MIN_EXP__ (-6143)
#define __SIZE_TYPE__ unsigned int
#define __DEC32_DEN__ 0.000001E-95DF
#define __FLT_RADIX__ 2
#define __LDBL_EPSILON__ 1.19209290e-7L
#define __SIZEOF_PTRDIFF_T__ 2
#define __AVR 1
#define __FLT_HAS_QUIET_NAN__ 1
#define __FLT_MAX_10_EXP__ 38
#define __LONG_MAX__ 2147483647L
#define __FLT_HAS_INFINITY__ 1
#define __DEC64_MAX__ 9.999999999999999E384DD
#define __DEC64_MANT_DIG__ 16
#define __DEC32_MAX_EXP__ 96
#define __DEC128_DEN__ 0.000000000000000000000000000000001E-6143DL
#define __LDBL_MANT_DIG__ 24
#define __DBL_HAS_QUIET_NAN__ 1
#define AVR 1
#define __WCHAR_TYPE__ int
#define __SIZEOF_FLOAT__ 4
#define __AVR__ 1
#define __DEC64_MIN_EXP__ (-383)
#define __FLT_DIG__ 6
#define __INT_MAX__ 32767
#define __FLT_MAX_EXP__ 128
#define __DBL_MANT_DIG__ 24
#define __DEC64_MIN__ 1E-383DD
#define __WINT_TYPE__ unsigned int
#define __SIZEOF_SHORT__ 2
#define __LDBL_MIN_EXP__ (-125)
#define __LDBL_MAX_10_EXP__ 38
#define __DBL_EPSILON__ 1.19209290e-7
#define __SIZEOF_WCHAR_T__ 2
#define __DEC_EVAL_METHOD__ 2
#define __INTMAX_MAX__ 9223372036854775807LL
#define __FLT_DENORM_MIN__ 1.40129846e-45F
#define __FLT_MAX__ 3.40282347e+38F
#define __SIZEOF_DOUBLE__ 4
#define __FLT_MIN_10_EXP__ (-37)
#define __INTMAX_TYPE__ long long int
#define __DEC128_MAX_EXP__ 6144
#define __GNUC_MINOR__ 3
#define __DEC32_MANT_DIG__ 7
#define __DBL_MAX_10_EXP__ 38
#define __LDBL_DENORM_MIN__ 1.40129846e-45L
#define __STDC__ 1
#define __PTRDIFF_TYPE__ int
#define __DEC128_MANT_DIG__ 34
#define __LDBL_MIN_10_EXP__ (-37)
#define __SIZEOF_LONG_LONG__ 8
#define __LDBL_DIG__ 6
#define __GNUC_GNU_INLINE__ 1

In there you will see things such as:

#define __SIZEOF_INT__ 2

I'd suggest this could be used during the CPP phase to determine that you are using a compiler for an architecture with 16 bit ints.

When I do the equivalent command for the i386 "gcc" on a Linux machine the __SIZEOF_INT__ value is (perhaps not surprisingly?) 4

Cliff

PS It could be even simpler to use:

#define AVR 1

or

#define __AVR 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Wonderful, thanks. Hmm, wonder if I can do

#if __SIZEOF_POINTER__< 4
#define OLD_POINTER_SIZE __SIZEOF_POINTER__
#undef __SIZEOF_POINTER__
#define __SIZEOF_POINTER__ 4
#endif
word readflashword(word *address) {
..
}
#ifdef OLD_POINTER_SIZE
#undef __SIZEOF_POINTER__
#define __SIZEOF_POINTER__ OLD_POINTER_SIZE
#endif

I'll give it a try. If it works with avr-gcc, would it work on all platforms?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

By all means try it. I am fairly certain that the macros reflect the gcc options and not the other way about.

I would also reckon it will be not only unportable but unwise. Other compilers will almost certainly have different behaviour.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well all variants of GCC will have __SIZEOF_BLOB__ but there's no guarantee that other compilers will - read your compiler documentation.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, it doesn't change the pointer size in the embedded routines. But

#if __SIZEOF_POINTER__ > 3
...
#endif

does remove the offending code in my build. How unwise would that be, for all platforms?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

How unwise would that be, for all platforms?

What "other platforms" are you talking about? Is this stuff all for 8 bit embedded micros or is it also for "big iron"? If just 8-bit with small memory spaces then isn't it a pretty fair bet that sizeof(char *) is 16 on most ?

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have not found a way to automatically generate 32-bit pointers into flash; I must generate them manually with Carlos Lamas' GET_FAR_ADDRESS() routine from morepgmspace.h.

Please do let us know of your results. Your approach is different than anything I have tried and I am interested in your results.

Stu

Edit 1: PS: AFAIK there is no way to get AVR-GCC to generate a 32-bit pointer to anything. I must always pass my 32-bit pointer as a uint32_t (unsigned long). YMMV

Engineering seems to boil down to: Cheap. Fast. Good. Choose two. Sometimes choose only one.

Newbie? Be sure to read the thread Newbie? Start here!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It is a contiki core routine, for early 8 bit micros on up to big iron. Most builds would use gcc I should think.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

dak664 wrote:
Well, it doesn't change the pointer size in the embedded routines. But
#if __SIZEOF_POINTER__ > 3
...
#endif

does remove the offending code in my build. How unwise would that be, for all platforms?

The pre-processor will be quite happy to evaluate this macro. I would just test for __GNUC__ first. But it all depends on how portable you want your code to be.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think I solved my immediate problem with

/* Eliminate compiler warnings for (non-functional) code when flash requires 32 bit addresses and pointers are 16 bit */
#define INCLUDE_APPLICATE_SOURCE 1
#ifdef __GNUC__
#if (FLASHEND > USHRT_MAX) && (__SIZEOF_POINTER__ <= 2)
#undef INCLUDE_APPLICATE_SOURCE
#define INCLUDE_APPLICATE_SOURCE 0
#endif
#if (__SIZEOF_POINTER__ > 2)
#define INCLUDE_32BIT_CODE 1
#endif
#endif
#if INCLUDE_APPLICATE_SOURCE

BOOTLOADER_SECTION void
elfloader_arch_write_rom(int fd, unsigned short textoff, unsigned int size, char *mem)
{
    unsigned char   buf[SPM_PAGESIZE];
    unsigned short* flashptr = mem;
...
}

and later

void
elfloader_arch_relocate(int fd, unsigned int sectionoffset,
 char *sectionaddr, struct elf32_rela *rela, char *addr)
{
...
 case R_AVR_LO8_LDI_PM: /* 12 */
    write_ldi(fd, instr, (int)addr >> 1);
    break;
  case R_AVR_HI8_LDI_PM: /* 13 */
    write_ldi(fd, instr, (int)addr >> 9);
    break;

#if INCLUDE_32BIT_CODE         /* 32 bit AVRs */
  case R_AVR_HH8_LDI_PM: /* 14 */
    write_ldi(fd, instr, (int)addr >> 17);
    break;
#endif

...

So I will put the idea of forcing 32 bit pointers onto the back burner. Thanks for the quick help freaks.

Edit 1: Added INCLUDE_32_BIT_CODE since INCLUDE_APPLICATE_SOURCE=1 for MCUs with <64K flash.
Edit 2: Use signed addr because branch instructions use signed offsets.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I know this is kind of simplistic, but what I would do is define a custom type in the .h file and use a preprocessing directive to set it. Fore example:

#if 
  typedef uint16_t mytype_t;
#else
  typedef uint32_t mytype_t;
#endif

word readflashword(mytype_t *address)
{       
 return(word)(*address);  
}

Edited: corrected copied and posted code.

Last Edited: Thu. Jul 16, 2009 - 09:04 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

blackthorne wrote:
I know this is kind of simplistic, but what I would do is define a custom type in the .h file and use a preprocessing directive to set it. Fore example:

#if 
  typedef uint16_t mytype_t;
#else
  typedef uint32_t mytype_t;
#endif

word readflashword(mytype_t *address)
{
 address++;         
 return(*address);  
}

Sorry, but this code is totally nonsense. This does in no way change the size of "address". And what was your idea behind the "address++"?

Stefan Ernst

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sternst wrote:
blackthorne wrote:
Sorry, but this code is totally nonsense. This does in no way change the size of "address". And what was your idea behind the "address++"?

I would like to know what you mean by that. My suggestion is to not bother changing the address size at all. In this case, the OP has a method that takes a word as a parameter and retrieves the dereferenced value at that address. My suggestion is forget fighting it, just create a custom type or redefine the type used.

He can do one of two options:

A. redefine the "word" type itself
B. global replace "word" with his custom type (suggested)

Is there something I am missing with this?

Oh, in regards to the ++, I just copied his sample. I did not pay attention to what it was doing. The point is the parameter type change.

Edited to add: you may not be able to redefine a core type. Some compilers will allow it, but it depends on compiler rules. "word" is not a core gcc_avr type though.

Last Edited: Thu. Jul 16, 2009 - 09:17 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

blackthorne wrote:
My suggestion is to not bother changing the address size at all.
Sorry, my fault. I thought that exactly this is the topic. I got fooled by the thread title.

Stefan Ernst

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sternst wrote:
blackthorne wrote:
My suggestion is to not bother changing the address size at all.
Sorry, my fault. I thought that exactly this is the topic. I got fooled by the thread title.

No problem. I got sloppy and pasted his sample code without looking at what it does. Plus, I should have explained my suggestion of just using a custom type clearer.