Nios® V/II Embedded Design Suite (EDS)
Support for Embedded Development Tools, Processors (SoCs and Nios® V/II processor), Embedded Development Suites (EDSs), Boot and Configuration, Operating Systems, C and C++
12600 Discussions

Writting floating point numbers using IOWR IORD

Altera_Forum
Honored Contributor II
1,859 Views

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/W 

 

 

0 Kudos
11 Replies
Altera_Forum
Honored Contributor II
837 Views

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...
0 Kudos
Altera_Forum
Honored Contributor II
837 Views

Hi, 

 

Thanks a Lot. 

I'm able to see proper results now..
0 Kudos
Altera_Forum
Honored Contributor II
837 Views

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'.
0 Kudos
Altera_Forum
Honored Contributor II
837 Views

Fixed..... 

0 Kudos
Altera_Forum
Honored Contributor II
837 Views

 

--- Quote Start ---  

This should probably work on any relatively standard C compiler. 

--- Quote End ---  

 

 

Only when sizeof float == 4.
0 Kudos
Altera_Forum
Honored Contributor II
837 Views

I think you meant 'union', not 'struct'. 

 

And the qualifiers about reading up on 'strict alaising' still apply.
0 Kudos
Altera_Forum
Honored Contributor II
837 Views

Fixed......

0 Kudos
Altera_Forum
Honored Contributor II
837 Views

 

--- 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
0 Kudos
Altera_Forum
Honored Contributor II
837 Views

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.
0 Kudos
Altera_Forum
Honored Contributor II
837 Views

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
0 Kudos
Altera_Forum
Honored Contributor II
837 Views

 

--- 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
0 Kudos
Reply