.. index:: macros, assembly .. _macros: Macros ====== A macro is another way of ensuring modular programming in assembly language. A macro is a sequence of instructions, assigned by a name and could be used anywhere in the program. The main uses for a macro ------------------------- * To make it easier to follow the logic of the source code by replacing a block of code with a single meaningful name. * To avoid repeating a block of code several times. Macro Example ------------- :: .macro SetBitField register, literal @ SetBitField takes a register and a bitfield from svd2forth as parameters ldr r0, = \register @ load the ADDRESS of the variable "register" into r0 ldr r1, [r0] @ load CONTENTS of "register" into r1 ldr r2, = \literal @ load the VALUE of "literal" into r2 orrs r2, r1 @ OR the contents of "register" and the VALUE of "literal" into r2 str r2, [r0] @ store the ORed value back into "register", any previous set bits are untouched .endm The following code is from my Assembly article below which should be referred to here : https://mecrisp-stellaris-folkdoc.sourceforge.io/projects/blink-f0disco-gdbtui/doc/readme.html Blink.s Source Code With Macros ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ One can see how the use of the SetBitField macro has simplified the source a lot while not making it less readable once one knows what is in the macro. The size of the generated binary has not changed, there is no penalty using a macro. For more information about macros see The GNU Assembler Manual. :: @ vim:ft=armv5 @ https://github.com/ARM9/arm-syntax-vim explains the "vim:ft=armv5" above @ blink.s @ Assembly language Blinky example for stm32f051 mcu @ Board: https://mecrisp-stellaris-folkdoc.sourceforge.io/stm32-boards.html?highlight=green%20pill#why-not-make-your-own-green-pill @ led: PB-7 pin 30, blink control is pin PB-8 pin 32 @ Copyright 2020 Released under MIT License, see COPYING.TXT .cpu cortex-m0 @ Tell the assembler what model of Cortex-M this is for .thumb @ Cortex micros only understand thumb(1) code .include "../svd2forth/gpio-equates.s" @ GPIO configurations such as "INPUT" or "OUTPUT" .include "../svd2forth/bitposn-equates.s" @ BIT0 = 0x00000001, BIT3 = 0x00000008, BIT31 = 0x80000000 .include "../svd2forth/STM32F051.equates.s" @ Every register and bitfield equate for the MCU (from Svd2Forth) .include "../svd2forth/macros.s" @ All the Macros that use STM32F051.equates.s .syntax unified @ Use a modern syntax for Arm THUMB instructions. .global main @ Makes the symbol visible to ld Vector_Table: .word 0x20000000 @ Stack pointer value when stack is empty ResetVector: .word main + 1 @ Mandatory that the LSB = 1 .text @ what follows is code main: SetBitField RCC_AHBENR, RCC_AHBENR_IOPBEN @ Enable GPIOB moder: SetBitField GPIOB_MODER, (INPUT << GPIOB_MODER_moder8) + (OUTPUT << GPIOB_MODER_moder7) @ Set PB-8 to INPUT, PB-7 to OUTPUT. pullx: SetBitField GPIOB_PUPDR, (PULL_DOWN << GPIOB_PUPDR_pupdr8) + (PULL_UP << GPIOB_PUPDR_pupdr7) @ PB-8 - pull down, PB-7 - pull up check_pb8: @ if PB-8 = HIGH then LOOP until PB-8 = LOW then blink ldr r0, = GPIOB_IDR @ GPIOB_IDR register = 0x48000410 ldr r1, [r0] @ read the PB input data register ldr r2, = GPIOB_IDR_IDR8 @ load r2 with the idr8 mask (0x100) tst r1, r2 @ performs a bitwise AND operation on the value in r1 and r2, update condition codes bne check_pb8 @ loop if PB-8 is HIGH, otherwise proceed to next instruction (on_off:) on_off: ldr r1, = GPIOB_BSRR @ GPIOB bit set/reset register (address = 0x48000418) r4_on: ldr r4, = GPIOB_BSRR_BS7 @ PB-7 on = 0x80 r5_off: ldr r5, = GPIOB_BSRR_BR7 @ PB-7 off = 0x800000 led_on: str r4, [r1] bl delay led_off: str r5, [r1] bl delay b check_pb8 delay: lsls r0,r4, #13 @ r4 = 0x80 shifted left 13 times = 0x100000, delay about 1 second @ 8MHz clock loop: subs r0,r0, #1 bne loop end: bx lr @ return to caller