Mix
Random mix of pages and files
Arduino_asm
2025.02.21 20:52:55 end Arduino Howto SW Gilhad

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