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.

Environment

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.

Note

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

Registers

Non RA Kernel.

Note

Assembler-m0.txt Opcode Tables can be found at the end of this page

Warning

Never abuse the stack pointer registers for anything else unless you know what you do, or the next interrupt may crash sometimes, which is a nasty bug to find. Stacks always need to be maintained in an interrupt-safe way.

Note

You can use r0, r1, r2 and r3 freely; you need to push/pop r4 and r5 before use, and you can use r6/r7 and r13/r14 as stacks.

Register(s)

Usage Hints

r 0

Saved by IRQ entry – Free scratch register, will be saved automatically on interrupt entry. Do not expect it to stay the same on a subroutine call

r 1

Saved by IRQ entry – Free scratch register, will be saved automatically on interrupt entry. Do not expect it to stay the same on a subroutine call

r 2

Saved by IRQ entry – Free scratch register, will be saved automatically on interrupt entry. Do not expect it to stay the same on a subroutine call

r 3

Saved by IRQ entry – Free scratch register, will be saved automatically on interrupt entry. Do not expect it to stay the same on a subroutine call

r 4

Is saved by code for every usage, innermost loop index. Save and restore with push/pop if you wish to use

r 5

Is saved by code for every usage, innermost loop limit. Save and restore with push/pop if you wish to use

r 6

Top of stack register. No need to save TOS, as stacks are inherently interrupt safe

r 7

Data stack pointer. No need to save PSP, as stacks are inherently interrupt safe

r 8

Unused, available for your special purposes. Keep in mind that on M0, only a few opcodes are available for them (MOV, ADD, CMP, as far as I know)

r 9

Unused, available for your special purposes. You may get a error/warning ‘Use low registers’

r 10

Unused, available for your special purposes.

r 11

Unused, available for your special purposes.

r 12

Unused, but saved automatically on interrupt entry.

r 13 = SP

Return Stack Pointer, hardwired in silicon

r 14 = LR

Link Register, hardwired in silicon. For bl and bx lr or push {lr} & pop {pc}, automatically saved on interrupt entry

r 15 = PC

Program Counter, hardwired in silicon

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
   begin
      led-on
          delay
      led-off
          delay
   again
 ;


 \ 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 }
ok.

‘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
ok.

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 }

Summary

  • 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.

Note

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.

Branching

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

ands

eors

adcs

sbcs

rors

tst

orrs

muls

bics

mvns

sxtb

sxth

uxtb

uxth

rev

rev16

revsh

Still Under Construction

Opcode

Description / example

Comment

Under Construction !