在汇编中对 Arduino 进行编程?
Programming the Arduino in assembly?
我知道我可以用 C 语言对 Arduino 进行编程,但是对于我当前的项目(一个很小的 Arduino 内核),我真的更愿意在某些部分使用 Assembly 来学习 Assembly 并可能提高效率。
我可以使用 __ASM__() 之类的东西吗?我真的只能在网上找到有人试图说服问过类似问题的人学习 C,而不是真正回答问题。
谢谢!
我很久以前写和贴的。
.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
我使用了 avra 并且可能编写了我自己的 arduino 加载器
blinker01.s.hex : blinker01.s
avra -fI blinker01.s
clean :
rm -f blinker01.s.*
你当然可以使用 avr_dude。
gnu 有点不同:
.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
你真的不需要头文件来定义端口,你可以自己声明。
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
使用 apt-got avr-gcc(和 binutils)可能与 arduino 沙箱使用的工具相同,应该可以直接访问,但我不使用沙箱,所以不知道。
编辑
另一种方法是有限的,但使用工具链更有可能成功,因为您从一个工作的 C 应用程序和环境开始,然后添加一个对象,也有助于汇编基础知识,看看编译器做了什么,然后继续阅读它:
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.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
然后不是在 C 生成的对象中 link,而是在程序集生成的对象中 link,您必须学习通过实验可以弄清楚的调用约定。
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
在这种情况下,r22 中的第二个参数首先在 r24 中,return r24 中的值。所以 22/23 可能是第一个参数,用于较大的项目,如短裤,第二个参数是 24/25。它也会在某个地方记录下来,编译器符合它,会有例外,所以制作一个合适的例子来查看编译器做了什么而不是仅仅假设一个例子中的一切都是关键的,即使你阅读了文档它可能是模糊的或使用在您进行实验之前可能没有意义的术语。
我知道我可以用 C 语言对 Arduino 进行编程,但是对于我当前的项目(一个很小的 Arduino 内核),我真的更愿意在某些部分使用 Assembly 来学习 Assembly 并可能提高效率。
我可以使用 __ASM__() 之类的东西吗?我真的只能在网上找到有人试图说服问过类似问题的人学习 C,而不是真正回答问题。
谢谢!
我很久以前写和贴的。
.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
我使用了 avra 并且可能编写了我自己的 arduino 加载器
blinker01.s.hex : blinker01.s
avra -fI blinker01.s
clean :
rm -f blinker01.s.*
你当然可以使用 avr_dude。
gnu 有点不同:
.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
你真的不需要头文件来定义端口,你可以自己声明。
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
使用 apt-got avr-gcc(和 binutils)可能与 arduino 沙箱使用的工具相同,应该可以直接访问,但我不使用沙箱,所以不知道。
编辑
另一种方法是有限的,但使用工具链更有可能成功,因为您从一个工作的 C 应用程序和环境开始,然后添加一个对象,也有助于汇编基础知识,看看编译器做了什么,然后继续阅读它:
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.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
然后不是在 C 生成的对象中 link,而是在程序集生成的对象中 link,您必须学习通过实验可以弄清楚的调用约定。
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
在这种情况下,r22 中的第二个参数首先在 r24 中,return r24 中的值。所以 22/23 可能是第一个参数,用于较大的项目,如短裤,第二个参数是 24/25。它也会在某个地方记录下来,编译器符合它,会有例外,所以制作一个合适的例子来查看编译器做了什么而不是仅仅假设一个例子中的一切都是关键的,即使你阅读了文档它可能是模糊的或使用在您进行实验之前可能没有意义的术语。