- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
I'm trying to read a custom register which has a 32 bit floating point value, from the NIOS in the c-code using the Macro IORD(base,offset). If I assign this to a variable defined as float and Add it with 2. And write the result into another custom register using IOWR Macro. I'm not getting equivalent IEEE-754 value in the register. Can anybody suggest what might be the problem? Code is as below: float x,v; x= IORD(IOREG_BASE,0); // Reading from the register1 defined in H/W v= x+2; IOWR(IOREG_BASE,1,v); // Writing to register2 defined in H/WLink Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
In my opinion the compiler sees the IORD result as an integer, and will cast it to a float value. I think the only way you could get around this is by using pointers and changing the pointer type. Something like (not tested):float x,v;
*((unsigned int*)&x)= IORD(IOREG_BASE,0); // Reading from the register1 defined in H/W
v= x+2;
IOWR(IOREG_BASE,1,*((unsigned int*)&v)); // Writing to register2 defined in H/W
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
Thanks a Lot. I'm able to see proper results now..- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Be aware that the C compiler isn't necessarily required to compile that code in the way that you expect! Read up on 'strict aliasing'.
If you look at how IORD() and IOWR() are defined, you should be able to generate a version for 'float' instead of (probably) 'unsigned int'.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Fixed.....
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- This should probably work on any relatively standard C compiler. --- Quote End --- Only when sizeof float == 4.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I think you meant 'union', not 'struct'.
And the qualifiers about reading up on 'strict alaising' still apply.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Fixed......
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- I was going off of the 32-bit IORD version of the float he is using in his question. Might need some sort of compiler dependent modifier to match the version of 'float' used by his external hardware. --- Quote End --- But you said "any relatively standard C compiler" which isn't true unqualified. A lot of people here are learning C and highly non-portable constructs should be presented with warnings. I was trying to show the constraints of where it works - there are many platforms where that won't work at all. Bill A
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Most modern systems do use the standard IEEE floating point formats. But that isn't completely universal.
Likely issues that will catch out the unwary are whether denormalised encodings are used for values near zero, and (on embedded systems especially) the support of NaN and Infinity. For double precision (64bit) there is the additional issue of word order, usually this will match the byte order - but, for instance, ARM have done an FP unit where this wasn't the case (now depracated). More problematic are issues when you access the same memory as different types. For instance:int get_float(float f)
{
char buffer = { 1, 1, 1, 1};
int *a = (void *)&buffer;
float *b = (void *)&buffer;
*b = f;
return *a;
}
can legitimately be compiled to code the returns the constant 0x01010101 as the compiler can reorder the *b and *a since they refer to different types (neither of which is char), and then optimise away the rest of the function. With gcc, inserting 'asm volatile("":::"memory")' between the two lines will enforce the expected behaviour. This statement is also useful to force the instruction sequence when trying to avoid cpu stalls following memory reads, and to reduce the number of live registers.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Additionally, if the u32 isn't a valid float representation, the processor accessing the float member can throw an exception - even on a simple load or store. I know this is true on a 386 and later because I wrote a learning utility to convert IEEE floats to and from a HEX representation. A bad HEX value would throw an exception before I even got to the printf to see the ASCII value.
Bill- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- In my opinion the compiler sees the IORD result as an integer, and will cast it to a float value. I think the only way you could get around this is by using pointers and changing the pointer type. Something like (not tested):
float x,v;
*((unsigned int*)&x)= IORD(IOREG_BASE,0); // Reading from the register1 defined in H/W
v= x+2;
IOWR(IOREG_BASE,1,*((unsigned int*)&v)); // Writing to register2 defined in H/W
I don't know if there is a more elegant way to do it... --- Quote End --- Thanks a lot! This solved my problems too
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page