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++
12596 Discussions

incompatible type for argument 2 of '__builtin_stwio'

Altera_Forum
Honored Contributor II
2,725 Views

I'm trying to write to memory using the IOWR_32DIRECT function, however I'm receiving an error complaining about an incompatible type. I'll have to admit that it's difficult to find the specifics on how this function works. In the software developer's handbook, there's only a table mentioning OFFSET with no detail as to what type OFFSET is. I'd assumed that since this function is used to write 32 bit data sections, the offset would be 32 bits, or 4 bytes.  

 

However, I haven't even gotten to the point of using the OFFSET, as I'm receiving this error when calling the function with an offset of 0. Here is how I'm using the function, 

 

IOWR_32DIRECT(SLAVE_BASE, 0, DATA_STRUCTURE);  

 

Where SLAVE_BASE is defined in the system.h file and DATA_STRUCTURE is a 32 bit value defined in my code. 

 

Edit: Ok, after looking more closely, I see that the error is actually referring to the DATA parameter and not the OFFSET. 

 

__builtin_stwio (__IO_CALC_ADDRESS_DYNAMIC ((BASE), (OFFSET)), (DATA))  

 

So, that brings up another problem. I have what I think is a 32 bit value being passed in. Is DATA expected to be a specific type? 

 

Thanks for any help, in advance. 

 

Drew
0 Kudos
10 Replies
Altera_Forum
Honored Contributor II
1,510 Views

I think I've figured this out. I'm still not 100% sure what's going on beneath the HAL level, but, according to the nios ii software developer's handbook (http://www.altera.com/literature/hb/nios2/n2sw_nii5v2.pdf), section 6-5, HAL uses its own standard data types. It looks like, if you're using a 32 bit write, you need to use one of the following, int, unsigned int, alt_32, alt_u32.

0 Kudos
Altera_Forum
Honored Contributor II
1,510 Views

Personally I wouldn't ever have written anything like IOWR_32DIRECT() or any of its friends. 

It is much, much, much safer to define C structures to map device registers and then either use a pointer initialiased to the correct value or get the linker to assign a constant to a normal C structure variable. 

 

That doesn't, or course, solve the problem of bypassing the cache - using the stwio instruction is one way of doing that. 

__builtin_stwio() if probably defined as: 

void __builtin_stwio(void *, unsigned int); 

So your 'data' value will need to be an integeral one (not a pointer). 

 

It is actually much easier to bypass the data cache by setting the high bit of the address and using 'normal' memory access instructions (not the xxxio ones). In which case you can just dereference a normal C pointer (to a structure of the correct type). 

 

If your code might run in a system with an mmu it is all more complex, and the OS will likely have support functions.
0 Kudos
Altera_Forum
Honored Contributor II
1,510 Views

I agree about the struct access and you can extend it even further by taking the address of a pointer casted to the base address of the peripheral (plus 0x80000000) of the struct. This gives you a compile-time accessed non-cached access which IMO is much easier to read. 

 

Example: 

 

# define MY_PER_BASE 0x10000000UL typedef struct { alt_u32 control; alt_u32 status; } s_MyPeripheral; # define MyPeripheral ((s_MyPeripheral *) (0x80000000UL | MY_PER_BASE)) void t(void) { alt_u32 stat = MyPeripheral->status; MyPeripheral->control = 1; }  

 

Bill A
0 Kudos
Altera_Forum
Honored Contributor II
1,510 Views

Actually you can make it even simpler (and generate better code). 

If you assign known fixed addresses to your peripherals then you can safely define the addresses in the linker script. eg: 

my_peripheral = 0x81000000; 

Your C can then contain: 

struct { volatile int reg; }; extern struct my_peripheral; ... x = my_peripheral.reg; 

If you don't have a data cache and can arrange for the 'small io' and tightly coupled memory to be within 64k you can put everything in .sdata sections and have efficient access from the gp register. 

 

Alternatively grab the patch to ld I posted a couple of weeks ago and put your 'small io' above 0x7fff8000 (above 0xffff8000 for uncached access) so that it can be accessed by a small offset from r0. 

(Without a data cache below 0x8000 works just as well and probably uses less logic.)
0 Kudos
Altera_Forum
Honored Contributor II
1,510 Views

Thank you both for your replies. I'll admit that using the HAL API was somewhat lazy on my part and mostly out of habit, too many frameworks lately, so thank you for suggesting an alternative. 

 

I have no input on the hardware design. My programming is in the application layer and I have no input on anything below. This matter is complicated more, for me, given the fact that I don't typically think in the context of bit level development.  

 

My attempt at building structures to work with the peripherals looked like this,  

 

typedef struct { alt_u32 a:2; alt_u32 b:4; alt_u32 c:26; } PeripheralOne;  

with separate functions to read from, 

alt_u32 PeripheralOn_to_alt_u32() 

and write to, 

alt_u32_to_PeripheralOn() 

each peripheral using bit shifting.  

 

I have a large number of these interface, which all have different formats, so I feel that this approach is inefficient, however, I'm having trouble thinking of a better, portable, approach.
0 Kudos
Altera_Forum
Honored Contributor II
1,510 Views

You really don't want to use C bitfields to access device registers, apart from the complete non-portability of the order in which the bits are assigned you have no control over the actual memory cycles generated by the compiler. 

 

Any structures used to (directly) map io registers should also have all their fields marked 'volatile'. 

 

If the bitfield is only used for a normal progam variable, the following might work (not even compiled though): 

typedef struct { alt_u32 a:2; alt_u32 b:4; alt_u32 c:26; } PeripheralOne; union { PeripheralOne b; alt_u32 i; } PeripheralOne_u; static inline void write_PeripheralOne(PeripheralOne value) { PeripheralOne_u u; u.b = value; __builtin_stwio(address, u.i); }
0 Kudos
Altera_Forum
Honored Contributor II
1,510 Views

 

--- Quote Start ---  

Any structures used to (directly) map io registers should also have all their fields marked 'volatile'. 

--- Quote End ---  

 

 

Which is a huge oversight I made too - I should have written: 

 

# define MyPeripheral ((s_MyPeripheral volatile *) (0x80000000UL | MY_PER_BASE))  

 

Bill
0 Kudos
Altera_Forum
Honored Contributor II
1,510 Views

 

--- Quote Start ---  

Personally I wouldn't ever have written anything like IOWR_32DIRECT() or any of its friends. 

It is much, much, much safer to define C structures to map device registers and then either use a pointer initialiased to the correct value or get the linker to assign a constant to a normal C structure variable. 

--- Quote End ---  

 

 

This was taken from section 9-4 of the nios ii software developers handbook

 

"The HAL provides the C-language macros IORD and IOWR that expand to the 

appropriate assembly instructions to bypass the data cache. The IORD macro expands 

to the ldwio instruction, and the IOWR macro expands to the stwio instruction. These 

macros are provided to enable HAL device drivers to access device registers." 

 

Can you explain how using the macro expansion IOWR_32DIRECT() is different? 

 

thanks, 

Drew
0 Kudos
Altera_Forum
Honored Contributor II
1,510 Views

You lose any checking that the offsets are being applied to the correct base address.

0 Kudos
Altera_Forum
Honored Contributor II
1,510 Views

Got it. I'd completely missed the point of your original comment, but I see it now. Thanks.

0 Kudos
Reply