Hi Erik,
I did in fact, eventually do exactly that. But I do like your tip on
running xxx.S files through cpp and I'm going to use it.
I just thought that because in-line assembly was being used by members
of the community, it should be something I should have a handle on. I do
have a better understanding of it now, but I didn't continue with it for
more or less the same reasons that you don't use it.
I was trying to make sense of an Atmel demo and the mistake that I was
making was that I didn't see that there were actually 2 instances
compiled and I was only examining the first one. The following had also
been used elsewhere in the project:
_// Locate low level init function before RAM init (init3 section)__
__char __low_level_init(void) __attribute__ ((section (".init3"),naked));__
__char __low_level_init()__
__{__
__ clock_prescale_set(clock_div_1);__
__ return 1;__
__}__
_
My test looked like this:
#include <avr/io.h>
#include <avr/power.h>
int main(void)
{
DDRC = 0x80;
PORTC |= 0x80;
clock_prescale_set(clock_div_2);
PORTC &= 0x7F;
while(1) {};
}
and an extract from "avr/power.h" (shortened for explanation here) is:
typedef enum
{
clock_div_1 = 0, clock_div_2 = 1, clock_div_4 = 2, clock_div_8 = 3,
clock_div_16 = 4,
clock_div_32 = 5, clock_div_64 = 6, clock_div_128 = 7,
clock_div_256 = 8
} clock_div_t;
static __inline__ void clock_prescale_set(clock_div_t)
__attribute__((__always_inline__));
void clock_prescale_set(clock_div_t __x)
{
uint8_t __tmp = _BV(CLKPCE);
__asm__ __volatile__ (
"in __tmp_reg__,__SREG__" "\n\t"
"cli" "\n\t"
"sts %1, %0" "\n\t"
"sts %1, %2" "\n\t"
"out __SREG__, __tmp_reg__"
: /* no outputs */
: "d" (__tmp),
"M" (_SFR_MEM_ADDR(CLKPR)),
"d" (__x)
: "r0");
}
The compilations are flawless whether optimised or not, and needless to
say, I felt a bit stupid when I found it.
Thanks to you Erik, Johann and Jan for the help, and I apologise for any
wild goose chases.
Best regards,
Alistair.
On 2015/03/18 09:07 AM, Erik Christiansen wrote:
On 07.03.15 17:07, Alistair Gadd wrote:
I'm used to using separate assembler files and I'm not a great boffin
on using in-line assembly, but I really think I need to get a collar
on it.
Alistair, is there any reason for not using separate assembler files, as
is your custom? As clock_prescale_set() is entirely assembler, it is
ripe for linking in from a separate assembler source file, either put
through the assembler only, or avr-gcc, as preferred.
In the latest makefile I wrote for use on avr, I find I'm using:
%.o: %.c
$(CC) -c $(CFLAGS) -o $(OBJDIR)/$@ $<
%.o: %.s
$(AS) -I$(INC_DIR) $(ASFLAGS) -o $(OBJDIR)/$@ $<
%.o: %.S
$(CC) -c -I$(INC_DIR) -x assembler-with-cpp $(CFLAGS)
-Wa,-alms=$(OBJDIR)/$@.lst -o $(OBJDIR)/$@ $<
I.e. xxx.S goes through cpp, so lots of good macros are expanded.
If register allocation is a doubt, the ABI is documented here:
http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_reg_usage
I would certainly never use in-line assembler for anything other than a
desperate hack of a large C function which couldn't be fixed any other
way. In-line assembler is unreadable gibberish, and not an efficient or
adequately maintainable method for writing a complete function, IME.
Given that linking file(s) of assembler function(s) into a C program is
quite elementary, it should hardly ever be necessary to use in-line
assembler. (And in a 30 year embedded systems design/programming career,
I never found it useful to do so.)
Erik
_______________________________________________
AVR-GCC-list mailing list
AVR-GCC-list@nongnu.org
https://lists.nongnu.org/mailman/listinfo/avr-gcc-list