Interactive Assembly Delay¶
This page shows how to use the Mecrisp-Interactive Assembly facility to create a millisecond blocking delay.
Note
While the delay is being used, the CPU is not available to do anything else.
To see the same thing but done by inlining the machine code from arm-none-eabi-as, see Accurate Blocking Delay
Why do it this way ?¶
The reason that the millisecond blocking delay is done this way rather than in pure Forth is because it can be done in about half the binary code size compared to a pure Forth Word such as “delay” below. Another reason is that sometimes maximum speed is required and this means using minimal instructions in the Forth Word. The delay example is a great way to demonstrate how to achieve this.
Note
The THUMB Instruction Set is used here
Using Pure Forth Instead¶
The pure Forth way is certainly much faster to write and debug compared to the alternate methods.
The “delay” Word below uses the common “do-loop” twice and is calibrated.
: delay
0 do
1526 0 do loop
loop
;
Disassembly¶
see delay
20000604: B500 push { lr }
20000606: B430 push { r4 r5 }
20000608: 2400 movs r4 #0
2000060A: 0035 lsls r5 r6 #0
2000060C: CF40 ldmia r7 { r6 }
2000060E: 3F04 subs r7 #4
20000610: 603E str r6 [ r7 #0 ]
20000612: B430 push { r4 r5 }
20000614: 2400 movs r4 #0
20000616: 25BE movs r5 #BE
20000618: 00ED lsls r5 r5 #3
2000061A: 3506 adds r5 #6
2000061C: CF40 ldmia r7 { r6 }
2000061E: 3401 adds r4 #1
20000620: 42AC cmp r4 r5
20000622: D1FC bne 2000061E
20000624: BC30 pop { r4 r5 }
20000626: 3401 adds r4 #1
20000628: 42AC cmp r4 r5
2000062A: D1F0 bne 2000060E
2000062C: BC30 pop { r4 r5 }
2000062E: BD00 pop { pc }
Bytes: 44 ok.
Usage¶
1000 delay
Produces a 1.0000 second delay.
Interactive Assembly¶
You need to load the following programs first:
Cortex-M0¶
mecrisp-stellaris-x.x.x/common/disassembler-m0.txt
mecrisp-stellaris-x.x.x/common/assembler-m0.txt
Cortex-M3¶
mecrisp-stellaris-x.x.x/common/disassembler-m3.txt
mecrisp-stellaris-x.x.x/common/assembler-m0.txt
Table-1¶
l-: l+:
jumps beq
bne bcs bcc bmi
bpl bvs bvc bhi
bls bge blt bgt
ble bhs blo b
wfi bl ldr=
add mov
bx blx ands
eors adcs sbcs rors
tst orrs muls bics
mvns sxtb sxth uxtb
uxth rev rev16 revsh
movs cmp
adds subs str
strb strh ldr ldrb
ldrh ldrsb ldrsh
lsls lsrs asrs
lslsr lsrsr asrsr
push pop stmia
ldmia
How does it work ?¶
Assembler-m0.txt provides the Words in Table-1 which look and behave much like assembler syntax using arm-none-eabi-as. However these are Forth Words and so run under Forth with all the interactive advantages.Forth compiles these Words into the same machine code produced by arm-none-eabi-as.
These Words can be used to produce minimal machine code for inlining in muct the same was as using
Assembly Examples¶
Using arm-none-eabi-as¶
Example Blocking Delay Sourcecode¶
Warning
This code will run perfectly in GDB but it is NO GOOD for use as INLINED MACHINE CODE for Forth because the LDR command produces code that is PC (program counter) relative. To inline machine code in Forth, the code must be PC INDEPENDENT.
.syntax unified
.cpu cortex-m0
.thumb
.text
Vector_Table: .word 0x20000000 @ stack pointer value when stack is empty
ResetVector: .word loop1 +1 @ Reset Handler
loop1: ldr r0,=1913
loop2: subs r0,r0,#1
bne loop2
subs r6,r6,#1
bne loop1
Disassembly¶
00000008 <loop1>:
8: 4802 ldr r0, [pc, #8] ; (14 <loop2+0xa>)
0000000a <loop2>:
a: 3801 subs r0, #1
c: d1fd bne.n a <loop2>
e: 3e01 subs r6, #1
10: d1fa bne.n 8 <loop1>
12: 07790000 ldrbeq r0, [r9, -r0]!
Using Interactive Assembly¶
Labels are supported but the syntax and use is different to arm-none-eabi-as.
Example Interactive Assembly Sourcecode¶
: ms-interactive-assy ( u -- ) \ Blocking delay for use on STM32F0xx @ 8MHz RC Clock. "1000 ms" = 1 second delay
l-: ldr= r0 1913
l-: subs r0 #1
bne -
subs r6 #1
bne --
drop
;
Jump to Labels Syntax¶
Jumping UP:
- Jump to first occurence of "l-:"
-- Jump to second occurence of "l-:"
--- Jump to third occurence of "l-:"
Jumping Down:
+ Jump to first occurence of "l+"
++ Jump to second occurence of "l+:"
+++ Jump to third occurence of "l+:"
Disassembly¶
The PUSH and POP are added by Forth
see ms-interactive-assy
20000596: B500 push { lr }
20000598: 20EF movs r0 #EF
2000059A: 00C0 lsls r0 r0 #3
2000059C: 3001 adds r0 #1
2000059E: 3801 subs r0 #1
200005A0: D1FD bne 2000059E
200005A2: 3E01 subs r6 #1
200005A4: D1F8 bne 20000598
200005A6: CF40 ldmia r7 { r6 }
200005A8: BD00 pop { pc }
20000598 to 2000059E is the Forth statement “ldr= r0 1913” computing the shortest MOVS,LSLS,ADDS sequence to guarantee that R0 contains 1913 and is PC INDEPENDENT.
movs r0 #EF
lsls r0 r0 #3
adds r0 #1
Testing the result:
: calc $ef 3 lshift 1 + . cr ;
calc 1913
ok.
Construct the Forth inlined Word from the disassembly above¶
: ms ( u -- ) \ millisecond blocking delay for Cortex-m0 with 8MHz rc clock (mecrisp-stellaris default)
[ \ 20 bytes size
$20EF h,
$00C0 h,
$3001 h,
$3801 h,
$D1FD h,
$3E01 h,
$D1F8 h,
] drop
;
Disassembly¶
see ms
200005E2: B500 push { lr }
200005E4: 20EF movs r0 #EF
200005E6: 00C0 lsls r0 r0 #3
200005E8: 3001 adds r0 #1
200005EA: 3801 subs r0 #1
200005EC: D1FD bne 200005EA
200005EE: 3E01 subs r6 #1
200005F0: D1F8 bne 200005E4
200005F2: CF40 ldmia r7 { r6 }
200005F4: BD00 pop { pc }
Bytes: 20 ok.
Usage¶
1000 ms
Will provide a blocking delay of 1 second.