one I wrote and posted ages ago.
.device ATmega168
.equ DDRB = 0x04
.equ PORTB = 0x05
.org 0x0000
rjmp RESET
RESET:
ldi R16,0x20
out DDRB,R16
ldi R18,0x00
ldi R17,0x00
ldi R20,0x20
Loop:
ldi R19,0xE8
aloop:
inc R17
cpi R17,0x00
brne aloop
inc R18
cpi R18,0x00
brne aloop
inc R19
cpi R19,0x00
brne aloop
eor R16,R20
out PORTB, R16
rjmp Loop
I used avra and likely wrote my own arduino loader
blinker01.s.hex : blinker01.s
avra -fI blinker01.s
clean :
rm -f blinker01.s.*
you could use avr_dude of course.
With gnu something a little different:
.globl _start
_start:
rjmp RESET
RESET:
ldi R18,0x00
ldi R17,0x00
ldi R20,0x20
Loop:
ldi R19,0xE8
aloop:
inc R17
cpi R17,0x00
brne aloop
inc R18
cpi R18,0x00
brne aloop
inc R19
cpi R19,0x00
brne aloop
rjmp Loop
you dont really need the header files to define ports, you can declare those yourself.
MEMORY
{
rom : ORIGIN = 0x00000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > rom
}
avr-as so.s -o so.o
avr-ld -T so.ld so.o -o so.elf
avr-objdump -D so.elf > so.list
avr-objcopy so.elf -O ihex so.hex
Using an apt-got avr-gcc (and binutils) possibly the same tools used with the arduino sandbox and should be directly accessible, but I dont use the sandbox so dont know.
EDIT
another approach is limited, but more likely to succeed with the toolchain since you start with a working C application and environment then add an object, also helps with assembly basics, see what the compiler does then go read up on it:
unsigned short fun ( unsigned short x, unsigned short y )
{
return(x+y+5);
}
avr-gcc -c -O2 so.c -o so.o
avr-objdump -D so.o
00000000 <fun>:
0: 6b 5f subi r22, 0xFB ; 251
2: 7f 4f sbci r23, 0xFF ; 255
4: 86 0f add r24, r22
6: 97 1f adc r25, r23
8: 08 95 ret
so
create so.s
.globl fun
fun:
subi r22, 0xFB ; 251
sbci r23, 0xFF ; 255
add r24, r22
adc r25, r23
ret
avr-as so.s -o so.o
avr-objdump -D so.o
00000000 <fun>:
0: 6b 5f subi r22, 0xFB ; 251
2: 7f 4f sbci r23, 0xFF ; 255
4: 86 0f add r24, r22
6: 97 1f adc r25, r23
8: 08 95 ret
and then instead of linking in the C produced object, link in the assembly produced object, you have to learn the calling convention which through experiments you can figure out.
unsigned char fun ( unsigned char x, unsigned char y )
{
return(x+(y<<1));
}
00000000 <fun>:
0: 66 0f add r22, r22
2: 86 0f add r24, r22
4: 08 95 ret
in this case second parameter in r22 first in r24, return value in r24. so 22/23 is probably for the first parameter for larger items like a short, and 24/25 for the second. it will be documented somewhere as well, the compiler conforms to it, there will be exceptions so crafting a proper example to see what the compiler does rather than just assume everything from one example is critical, even if you read the docs it is probably vague or uses terminology that might not make sense until you experiment.