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++
Объявления
FPGA community forums and blogs on community.intel.com are migrating to the new Altera Community and are read-only. For urgent support needs during this transition, please visit the FPGA Design Resources page or contact an Altera Authorized Distributor.
12748 Обсуждение

Writting floating point numbers using IOWR IORD

Altera_Forum
Почетный участник II
3 063Просмотр.

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 баллов
11 Ответы
Altera_Forum
Почетный участник II
2 041Просмотр.

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...
Altera_Forum
Почетный участник II
2 041Просмотр.

Hi, 

 

Thanks a Lot. 

I'm able to see proper results now..
Altera_Forum
Почетный участник II
2 041Просмотр.

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'.
Altera_Forum
Почетный участник II
2 041Просмотр.

Fixed..... 

Altera_Forum
Почетный участник II
2 041Просмотр.

 

--- Quote Start ---  

This should probably work on any relatively standard C compiler. 

--- Quote End ---  

 

 

Only when sizeof float == 4.
Altera_Forum
Почетный участник II
2 041Просмотр.

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

 

And the qualifiers about reading up on 'strict alaising' still apply.
Altera_Forum
Почетный участник II
2 041Просмотр.

Fixed......

Altera_Forum
Почетный участник II
2 041Просмотр.

 

--- 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
Altera_Forum
Почетный участник II
2 041Просмотр.

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.
Altera_Forum
Почетный участник II
2 041Просмотр.

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
Altera_Forum
Почетный участник II
2 041Просмотр.

 

--- 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
Ответить