furs

bf@
Login

bf@

In this page FURS is used to make a new Embedded Forth Word named "bf@"

Audience - Forth programmers

A note on style: FURS uses the following styles:

CMSIS

Forth doesn't come with any Words that support CMSIS-SVD nomenclature, mainly because Forth is only the programming language, and has no knowledge of the peripherals, just like the C programming language. C gains this knowledge thru Header and Include files of libraries etc all of which use CMSIS to do so.

And Forth gains peripheral knowledge thru FURS which uses CMSIS as well.

A new Word Is Needed

In embedded design I often want to know the value of a bitfield, one of which is to confirm the value of a GPIO-X pin, mode. So a new Word is needed and it will be named bf@.

bf@ Usage

In this example, the value of GPIOA-14 mode will be read, and in FURS it would be expressed this way:

: bf@ ( GPIOA_MODER MODER_MODER14 -- x ) ;

In practice, FURS will replace those words with values before upload to the MCU, transforming the command like this

 : bf@ ( $48000000 2 28 -- x ) ;

Where :

But for now, the example will use numerical values as FURS can't be used here via this Wiki.

This is the correct value of GPIOA_MODER_MODER14 as taken from a running Forth thermometer design and printed by my real-time "register pretty print" system:

gpioa_moder.  RW   $2A00A80C
15|14|13|12|11|10|09|08|07|06|05|04|03|02|01|00
00 10 10 10 00 00 00 00 10 10 10 00 00 00 11 00
Designing The New Word

I used the return stack as a "local variable" in this design because it makes managing three items on the stack easier, but I intended to replace it with stack operations (if possible) once my design was working.


: bf@ ( register bitWidth bitOffset -- x ) dup >r swap bwm swap lshift swap @ and r> rshift ;

Example: $48000000 2 28 bf@ bin. 3322222222221111111111 10987654321098765432109876543210 00000000000000000000000000000010

Dissasembly
see bf@
0000EC42: B500  push { lr }
0000EC44: B440  push { r6 }
0000EC46: CF08  ldmia r7 { r3 }
0000EC48: 2201  movs r2 #1
0000EC4A: 409A  lsls r2 r3
0000EC4C: 3A01  subs r2 #1
0000EC4E: 40B2  lsls r2 r6
0000EC50: CF40  ldmia r7 { r6 }
0000EC52: 6836  ldr r6 [ r6 #0 ] r6 #0  r6 #0 
0000EC54: 4016  ands r6 r2
0000EC56: BC08  pop { r3 }
0000EC58: 40DE  lsrs r6 r3
0000EC5A: BD00  pop { pc }

Bytes: 26 ok.

As the result is correct I then proceeded to redesign the bf@ Word by replacing the >r and r> with pure stack operations.

: bf@ ( register bitWidth bitOffset -- x ) dup rot bwm swap lshift rot @ and swap rshift ;
keys
1207959552 (decimal) = $48000000
805306368  (mask for gpioa_moderX, all moder bits are 2 bits wide)
536870912 = 805306368 anded with 671088640 = 

The result is correct.

$48000000 2 2 bf@ bin.
3322222222221111111111
10987654321098765432109876543210
00000000000000000000000000000011

My new design is shown line by line, along with the stack contents that show the necessary stack juggling so the data is presented to the operations in the correct order. If you like Forth you should enjoy reading this and watching the program unfold ?

note: The Forth designer needed a 'placeholder' to show the stack was working properly, and he chose "the answer to everything", because why not ? So ignore the '42' as it's not counted by the stack counter (the number in square brackets).

$48000000 2 28 .s Stack: [3 ]3  42 1207959552 2 28  ok.
dup .s Stack: [4 ]4  42 1207959552 2 28 28  ok.
rot .s Stack: [4 ]4  42 1207959552 28 28 2  ok.
bwm .s Stack: [4 ]4  42 1207959552 28 28 3  ok.
swap .s Stack: [4 ]4  42 1207959552 28 3 28  ok.
lshift .s Stack: [3 ]3  42 1207959552 28 805306368  ok.
rot .s Stack: [3 ]3  42 28 805306368 1207959552  ok.
@ .s Stack: [3 ]3  42 28 805306368 671088640 ok.
and .s Stack: [2 ]2  42 28 536870912  ok.
swap .s Stack: [2 ]2  42 536870912 28  ok.
rshift .s Stack: [1 ]1  42 2  ok.

When I dissasembled the new word, I was in for a suprise as four bytes had been saved compared to my first attempt using the Return Stack.

see bf@
0000EC42: CF08  ldmia r7 { r3 }
0000EC44: 2201  movs r2 #1
0000EC46: 409A  lsls r2 r3
0000EC48: 3A01  subs r2 #1
0000EC4A: 40B2  lsls r2 r6
0000EC4C: CF08  ldmia r7 { r3 }
0000EC4E: 681B  ldr r3 [ r3 #0 ] r3 #0 
0000EC50: 401A  ands r2 r3
0000EC52: 40F2  lsrs r2 r6
0000EC54: 4616  mov r6 r2
0000EC56: 4770  bx lr
Bytes: 22  ok.

Let's test how long bf@ takes to run ?

Finally, all these cool print statements and timing measurements are made possible by swdcom.