Assembly Language: Interactive

  • This page shows how to use interactive Assembly Language with Mecrisp-Stellaris via a Blinky example. The reader will need a basic knowledge of Mecrisp-Stellaris Forth and Cortex M Assembly Language.
  • I think this is a great way to learn Assembly Language as the Forth Core provides the user support, with recovery only a reset button press on the development board. This is much faster than the usual code, assemble, burn and test development cycle of Assembly Language which gives no feedback at all on code failure unless additional tools such as OpenOCD and GDB are also used. Even then the only visible evidence may be the Program Counter flying off to the end of memory at the end of the problem code.


Software Tools Required

Note: these tools are included with the Mecrisp-Stellaris-2.3.9 release (and many earlier releases) in the mecrisp-stellaris-2.3.9/common directory.

  • assembler-m0.txt
    • allows the entry of assembly language into Forth code. Note: It also runs example/test code when loaded to show how it works.
  • disassembler-m0.txt
    • provides the ‘see’ Word which ‘disassembles’ Forth Word compiled ‘Machine Code’ in the Dictionary into Assembly Language.


the STM32F0 Discovery Board board doesn’t have enough RAM to load the above files, so compile them into Flash instead.


Non RA Kernel.

Register(s) Usage Hints
Note: All Registers can be used, but there are few opcodes on M0 which can access high registers directly, so you may get a error/warning ‘Use low registers’
r0, r1, r2, r3 Free scratch registers for temporary usage, will be saved automatically on interrupt entry. Do not expect them to stay the same on a subroutine call.
r4, r5 Loop index and limit. Save and restore with push/pop if you wish to use them !
r6 Top of data stack
r7 Stack pointer for the data stack
r8 ... r12 Unused in Mecrisp-Stellaris, available for your special purposes. r12 is saved automatically on interrupt entry.
r13 Stack pointer for the return stack
r14 Link register for bl and bx lr or push {lr} & pop {pc}, automatically saved on interrupt entry
r15 Program counter

The Forth Blinky

  • This is a simple Blinky which turns on the blue LED by writing “$100” into memory location $48000814, then turns it off by writing a “0” into the same memory location.
$48000800 constant GPIOC                \
GPIOC $0 + constant GPIOC_MODER          \ Hardware Memory Map
GPIOC $14 + constant GPIOC_ODR            \  GPIOC_ODR = $48000814, the blue LED is connected to GPIOC-8

%01  16 lshift GPIOC_MODER bis!         \ set PC8 (blue LED) as output

 : led-on  $100 GPIOC_ODR ! ;           \ turn blue LED on

 : led-off $0   GPIOC_ODR ! ;           \ turn blue LED off

 : delay 900000 0 do loop ;             \ time delay so we can see the blue LED blinking

 : blink

 \ type 'blink' to run the blinky and flash the blue LED, press the board reset button to stop blinking.

Assembly Language ‘asm-led-off’ Word

This Word can replace the ‘led-off’ Word in the Blinky example. Performance of the blinking LED will be identical.

: asm-led-off                          \ This is my hand coded Assembly Language 'asm-led-off' using methods learned from my recent 'Blinky Challenge' with Matthias
  ldr= r0 $48000800                    \ For clarity I have chosen the same registers as used by Mecrisp Stellaris when it compiled 'led-off'
  ldr= r3 0                            \ Note: assembler-m0.fs must be loaded first, so Assembly Language statements can be used.
  str r3 r0 #$14

‘asm-led-off’ Disassembled

see asm-led-off                      \ 'see' is provided by disassembler-m0.fs
20000402: B500  push { lr }
20000404: 2090  movs r0 #90
20000406: 04C0  lsls r0 r0 #13
20000408: 3080  adds r0 #80
2000040A: 0100  lsls r0 r0 #4
2000040C: 2300  movs r3 #0
2000040E: 6143  str r3 [ r0 #14 ]
20000410: BD00  pop { pc }

‘led-off’ Disassembled

Compare this to ‘asm-led-off’ above, neglecting the ‘push’ and ‘pop’ they’re identical.

see led-off
200003CE: 2090  movs r0 #90
200003D0: 04C0  lsls r0 r0 #13
200003D2: 3080  adds r0 #80
200003D4: 0100  lsls r0 r0 #4
200003D6: 2300  movs r3 #0
200003D8: 6143  str r3 [ r0 #14 ]
200003DA: 4770  bx lr

Assembly Language ‘asm-delay’ Word

This Word can replace the ‘delay’ Word in the Blinky example. Performance of the blinking LED will be identical.

: asm-delay
     ldr= r0 $fffff
l-:  subs r0 r0 #1
     bne -

‘asm-delay’ Disassembled

This Word does save five instructions compared to the ‘delay’ code generated by Mecrisp-Stellaris, making it a worthwhile exercise.

see asm-delay
20000450: B500  push { lr }
20000452: 20FF  movs r0 #FF
20000454: 0200  lsls r0 r0 #8
20000456: 30FF  adds r0 #FF
20000458: 0100  lsls r0 r0 #4
2000045A: 300F  adds r0 #F
2000045C: 1E40  subs r0 r0 #1
2000045E: D1FD  bne 2000045C
20000460: BD00  pop { pc }

‘delay’ Disassembled

see delay
20000420: B500  push { lr }
20000422: 3F04  subs r7 #4
20000424: 603E  str r6 [ r7 #0 ]
20000426: B430  push { r4  r5 }
20000428: 2400  movs r4 #0
2000042A: 25DB  movs r5 #DB
2000042C: 022D  lsls r5 r5 #8
2000042E: 35BA  adds r5 #BA
20000430: 012D  lsls r5 r5 #4
20000432: CF40  ldmia r7 { r6 }
20000434: 3401  adds r4 #1
20000436: 42AC  cmp r4 r5
20000438: D1FC  bne 20000434
2000043A: BC30  pop { r4  r5 }
2000043C: BD00  pop { pc }


  • Handwritten Assembly code can produce smaller code than the Mecrisp-Stellaris generated code, but can also be identical.
  • If you’d prefer to use Assembly only with Cortex M, see the Assembly Language article here.


The Forth Handwritten Assembly code above, while smaller by five instructions then the Forth code, actually takes a LOT longer to run probably because the Forth only code is optimised within the Mecrisp-Stellaris system ?

Assembler-m0.txt Opcode Tables

Section Labels

label Description Comment
l- label, backward jump The assembler resolves the closest 3 labels in every direction relative to the current location. They can be referenced with bne -
l+ label, forward jump bge ++ bhi - - - which means: one l-: label back, two l+: labels forward, three l-: back. Different to normal assembler.


Opcode Description Comment
beq Branch if Z set equal
bne Branch if Z clear not equal
bcs Branch if C set unsigned higher or same
bcc Branch if C clear unsigned lower
bmi Branch if N set negative
bpl Branch if N clear positive or zero
bvs Branch if V set overflow
bvc Branch if V clear no overflow
bhi Branch if C set and V clear unsigned higher
bls Branch if C clear and Z set unsigned lower or same
bge Branch if N set and V set, or N clear and V clear greater or equal
blt Branch if N set and V clear, or N clear and V set less than
bgt Branch if Z clear, and either N set and V set or N clear and V clear greater than
ble Branch if Z set, or N set and V clear, or N clear and V set less than or equal
bhs Alias  
blo Alias  
b Unconditional branch  

Instructions with its own special handling

Opcode Description / example Comment
bl branch with link, a subroutine call If range is too far for bl opcode, it will generate a blx r0 sequence.
ldr= ldr= r0 $48000800 Load register 0 with the Hexadecimal 48000800 ( GPIOC BASE address)

Instructions with one register-16 operand

Opcode Description / example Comment
b Unconditional branch b <label> Branch PC relative +/- Offset11 << 1, where label is PC +/- 2048 bytes.
blx Branch and Link (immediate) calls a subroutine at a PC-relative address

Instructions with two register operands

Opcode Description / example Comment

Still Under Construction

Opcode Description / example Comment
Under Construction !