Obsah
- Arduino_asm
- Summary
- Register Usage in AVR GCC Calling Convention
- 1. Argument Passing (Registers Used for Function Parameters)
- 2. Registers That Can Be Freely Changed (Caller-Saved)
- 3. Registers That Must Be Preserved (Callee-Saved)
- 4. Special Registers
- Push/Pop Preservation
- What Should Not Be Used?
- Example: Calling an Assembly Function from C++
Arduino_asm
http://eleccelerator.com/fusecalc/fusecalc.php?chip=atmega328p
https://gcc.gnu.org/wiki/avr-gcc#Register_Layout
Ve zkratce:
- 1 bytové argumenty se považují za dvojbytové
- předávají se v registrech kde nejnižší byte je v registru s nejnižším číslem
- R26 se nepoužíje, vše se naštosuje POD něj
- R8 se nepoužíje, pokud by měl přijít na řadu, tak to jde na stack od té chvíle všechno
- R9-R17 se použijou, ale musí mít při návratu stejnou hodnotu
Summary
Register | Purpose | Caller-Saved? |
---|---|---|
R0 | Temporary use, often used for multiplication/division | Yes |
R1 | Must always be zero before returning | Yes (restore to 0) |
R2-R17 | Callee-saved (preserve if modified) | No |
R18-R27 | Temporary variables, can be freely changed | Yes |
R26-R27 (X) | General indirect addressing in SRAM | Yes |
R28-R29 (Y) | Frame pointer (stack-related) | No |
R30-R31 (Z) | Used for indirect addressing (e.g., LD, ST) & reading from Flash memory | Yes |
When programming the ATmega328P (used in Arduino Uno) in assembly, especially when interfacing with C++ functions, you need to follow the AVR GCC calling convention.
Register Usage in AVR GCC Calling Convention
AVR uses a modified caller-save convention, meaning the caller is responsible for saving certain registers before calling a function.
1. Argument Passing (Registers Used for Function Parameters)
- The first two arguments (for 8-bit values) are passed in R24 and R22.
- For 16-bit values: - First argument: R24-R25 - Second argument: R22-R23
- For 32-bit values: - First argument: R22-R25 - Second argument: R18-R21
- For pointer values (16-bit): Passed in R24-R25
- For return values: - 8-bit: R24 - 16-bit: R24-R25 - 32-bit: R22-R25
2. Registers That Can Be Freely Changed (Caller-Saved)
- R18-R27
- R30-R31 (Z-register, used for indirect addressing)
- R0 (but GCC expects it to be zero after use)
These must be saved if needed after calling a function.
3. Registers That Must Be Preserved (Callee-Saved)
These registers must not be changed by the assembly function unless they are saved/restored (via push/pop or store/load on the stack):
- R2-R17
- R28-R29 (Y-register, used for the frame pointer)
4. Special Registers
- R1: Always assumed to be zero. If modified, it must be cleared before returning.
- R0: Used for temporary storage, can be modified but needs special care.
- R30-R31: Often used for pointer arithmetic (Z-register).
Push/Pop Preservation
If your assembly function uses callee-saved registers, you must push them to the stack and restore them before returning. Example:
.global my_asm_function my_asm_function: push r2 ; Save registers that should be preserved push r3 push r4 ... ; Function logic ... pop r4 ; Restore registers before returning pop r3 pop r2 ret
What Should Not Be Used?
- Do not modify R1 without restoring it to zero (`clr r1`).
- Avoid corrupting callee-saved registers without restoring them (R2-R17, R28-R29).
- Use stack (`push`/`pop`) for temporary storage if you need extra registers.
Example: Calling an Assembly Function from C++
C++ Function Prototype (Arduino Sketch)
extern "C" uint8_t my_asm_function(uint8_t x); void setup() { Serial.begin(9600); uint8_t result = my_asm_function(42); Serial.println(result); } void loop() {}
Assembly Code (`file.S`)
.global my_asm_function my_asm_function: ; Argument comes in R24 mov r18, r24 ; Save input value in R18 lsl r18 ; Example operation: Multiply by 2 mov r24, r18 ; Store result in return register ret ; Return value is in R24
ldi ZL,pm_lo8(foo) ldi ZH,pm_hi8(foo) ijmp
; indirect jmp ldi zl,low(CommandTable) ;Z points to table ldi zh,high(CommandTable) add zl,Mode ;add mode as an offset brcc DoS1 inc zh ;account for a carry DoS1: ijmp ;jump to the command to run CommandTable: ;table of commmands to run from menus rjmp MainLoop ;blank entry rjmp DoLearnMode ;learn the maze rjmp DoSolveMode ;solve the maze rjmp DoSolveFast ;solve the maze fast rjmp DoSingleStep ;single step debug rjmp DoSensors ;display sensor readings rjmp DoShowCells ;display cell data rjmp MainLoop ;blank entry