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 <terry@tjporter.com.au> 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