.. vim: noexpandtab fileencoding=utf-8 nomodified wrap textwidth=270 foldmethod=marker foldmarker={{{,}}} foldcolumn=4 ruler showcmd lcs=tab\:|- list tabstop=8 noexpandtab nosmarttab softtabstop=0 shiftwidth=0 :date: 2025.02.21 20:52:55 :_modified: 1970.01.01 00:00:00 :tags: Arduino,Howto,SW :authors: Gilhad :summary: Arduino_asm :title: Arduino_asm :nice_title: |logo| %title% |logo| %HEADER% Arduino_asm -------------------------------------------------------------------------------- http://eleccelerator.com/fusecalc/fusecalc.php?chip=atmega328p ``__ 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: .. code:: asm .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)** .. code:: cpp 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`)** .. code:: asm .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 .. code:: ldi ZL,pm_lo8(foo) ldi ZH,pm_hi8(foo) ijmp .. code:: ; 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