wordlists, vocabularies, vocabulary prefixes and implicit context switching

A big Thank You to [manfredmahlow] for creating Vocabularies for Mecrisp-Stellaris !

Software Versions used in this demo

  • The latest Mecrisp-Stellaris https://sourceforge.net/projects/mecrisp/files/mecrisp-stellaris-2.3.9a.tar.gz is required to use Manfred Mahlow’s VOCS which is included in the common/experimental/vocs-0.7.0 directoru of the release.

  • Howto’s include :-
    • VOC-HOWTO-Classes-1: Shows some basics of VOCs based OOP.

    • VOC-HOWTO-Classes-2: How to create classes, using instance variables, defined in other classes.

    • VOC-HOWTO-DataTypes: A short demo to show how VOCs can be used to define data types.

    • VOC-HOWTO-Registers: Using VOCs to implement register identifiers.

VOC-HOWTO-Registers


\ VOC-HOWTO-Registers                                                  MM-170618
\ ------------------------------------------------------------------------------
\              HOWTO for Mecrisp-Stellaris for VOC Version 0.6.2-FR

\     A short demo to show how to use VOCs to define register identifiers.

\                  Copyright (C) 2017 Manfred Mahlow

\        This is free software under the GNU General Public License v3.
\ ------------------------------------------------------------------------------

  key drop

{
  Modern MCUs have lots of peripheral units to be controlled with many register
  identifiers. In Forth this identifiers are often implemented as constants, 
  cluttering the dictionary.

  With good hardware designs, the register identifiers should be a combination
  of a unit specific base addres and a register specific offset address. Then
  they can be implemented as such, significantly reducing the number of 
  required words.

  But earlier or later name conflict may arise when different units use the 
  same register name for a different offset address.

  Using VOCs to implement register identifiers can avoid such conflicts and can
  significantly reduce the number of identifiers to be implemented.
}

  key drop

  compiletoram

\ Loading vocs.txt    ** Please first read the preamble in that file. **
\ -----------------------------------------------------------------------------
  key drop

\ #require das.txt

#require vocs.txt

  key drop


\ Some tools used:
\ -----------------------------------------------------------------------------
\
\  ??     Displays the top wordlist of the search order. In the context Forth
\         the core words are ignored. To also see the core words use ???.
\
\  ..     Returns from a VOC context to the Forth context.
\
\ -----------------------------------------------------------------------------
  key drop

  ??

\ lfa: = Address: , xt: = Code:  in the original Mecrisp Listing

 
\ First we create a VOC and words to define unit and register identifiers
\ -----------------------------------------------------------------------------
  key drop


  forth definitions

  voc GPIO  GPIO definitions  hex

  : port: ( "name" base-addr -- ) ( GPIO ) casted constant ;

  : reg: ( "name" offset-addr -- ) <builds , does> @ or ;


\ then we define the required register identfiers as members of the GPIO VOC
\ -----------------------------------------------------------------------------
  key drop


  $3FC GPIO reg: DATA ( Ein- und Ausgaberegister )  
  $400 GPIO reg: DIR  ( Soll der Pin Eingang oder Ausgang sein ? )
  $500 GPIO reg: DR2R ( 2 mA Treiber )
  $504 GPIO reg: DR4R ( 4 mA )
  $508 GPIO reg: DR8R ( 8 mA )
  $50C GPIO reg: ODR  ( Open Drain )
  $510 GPIO reg: PUR  ( Pullup Resistor )
  $514 GPIO reg: PDR  ( Pulldown Resistor )
  $518 GPIO reg: PORTA_SLR  ( Slew Rate )
  $51C GPIO reg: PORTA_DEN  ( Digital Enable )
  $420 GPIO reg: PORTA_AFSEL ( Analog function select )
  $528 GPIO reg: PORTA_AMSEL ( Analog Mode Select )

\ and finally we define the required unit identifers in the Forth context.
\ -----------------------------------------------------------------------------
  key drop


  forth definitions

  $40004000 GPIO port: PORTA
  $40005000 GPIO port: PORTB
  $40006000 GPIO port: PORTC



\ Only the VOC and the unit identifiers are visible in the Forth context.
\ -----------------------------------------------------------------------------
  key drop

  ??


\ All unit identifiers share the same set of register identifiers
\ -----------------------------------------------------------------------------
  key drop

  PORTA ?? .. drop

  key drop

  PORTB ?? .. drop

  key drop

  PORTC ?? .. drop

  key drop 

\ and the combination of unit and register name returns the register identifier.
\ ------------------------------------------------------------------------------
  key drop

  PORTA DATA .
  PORTB DATA .
  PORTC DATA .

  PORTA DIR .
  PORTB DIR .
  PORTC DIR .

\ The GPIO implementation uses 644 Bytes.
\ Creating the same register identfiers as constants uses 1292 Bytes.
\ ------------------------------------------------------------------------------
\ Done. Please also see VOC-HOWTO-Classes-1.txt
\
\ Last Revision: MM-170709  voc.txt --> vocs.txt (v0.6.2)

VOC Moder Demo

This shows how vocabularies easily enable the use of phrases such as “ GPIOA MODER9 ? “ as a alternative to non vocabulary words like “ GPIOA-MODER9? “ along with the economy of OOP and a possible 50% reduction in Flash memory usage for Peripheral and Register definitions.

  • A stm32F0 GPIO has eleven+ registers that configure and control it.

  • The one which controls whether a GPIO bit is IN, OUT, SPECIAL FUNCTION or ANALOG is named the ‘MODER’ register , which means ‘MODE REGISTER’.

  • Each GPIO pin (or bit) in MODER is controlled by a 2bit pair, as shown in the list below.

gpioa. GPIOA_MODER (read-write) $28280000
15|14|13|12|11|10|09|08|07|06|05|04|03|02|01|00
00 10 10 00 00 10 10 00 00 00 00 00 00 00 00 00

These are the 2bit GPIO MODES ( % = binary base ) as used in the GPIOA MODER REGISTER above:-

%00 constant IN          ( INPUT MODE )
%01 constant OUT         ( OUTPUT MODE )
%10 constant ALTFUNCT    ( ALTERNATE FUNCTION MODE )
%11 constant ANALOG      ( ANALOG MODE )

Each GPIO port is 16 bits ( GPIOA0 - GPIOA15 ), and each bit requires a 2bit code in the MODER REGISTER, making the MODER REGISTER 32 bits long.

Using Manfred’s ‘Vocabularies’. The GPIOA MODER register may be read as below. Note: this is a working Mecrisp-Stellaris system and some bits are already set and must not be changed. This all happens in real time in the MCU.

GPIOA MODER @ bin. 101000001010000000000000000000  ok.   ( '@' means 'fetch' and 'bin.' means 'display the result in binary' )

Set GPIOA BIT 1 to ANALOG MODE ( %11 ) ..

ANALOG GPIOA MODER1 !  ok  ( "!" means store )

Check GPIOA MODER to see what the new value is …

GPIOA MODER @ bin. 101000001010000000000000001100  ok.

The GPIOA MODER1 value is also easily read ..

GPIOA MODER1 @ . 3  ok.

Or use the alternate “?” to display the MODE ( my favorite )

GPIOA MODER1 ? %11  ok.
GPIOA MODER0 ? %0  ok.

Bingo, GPIOA BIT 1 is now in ‘ANALOG’ MODE ( %11 ) and all other bits are unchanged.

Now change GPIOA BIT 1 to INPUT MODE ( %00 ) ..

IN GPIOA MODER1 !  ok

Check the change occured ..

GPIOA MODER @ bin. 101000001010000000000000000000  ok.

Or ..

GPIOA MODER1 ? %0  ok.

GPIOA BIT 1 is now reset to %00 (INPUT MODE) and the other bits are unchanged.

Note

Forth is often criticized for being terse, cryptic or hard, but if we compare our port MODE syntax with that of Arduino (C language), is Forth really harder, perhaps it’s easier ?

Forth - Arduino Comparison, INPUT

Set a Port Pin to INPUT MODE

Code

Comments

Forth on STM32F0

IN GPIOA MODER1 !

Set GPIOA bit 1 to INPUT. When the <enter> key is pressed this command will instantly take effect on the target hardware.

Arduino

pinMode(pin, INPUT);

set pin to INPUT. ‘pin’ can have a value of 0 - 13. The code must first be compiled and then uploaded to the target.

Forth - Arduino Comparison, OUTPUTS

Set all PORT pins to OUTPUTS

Code

Comments

Forth on STM32F0

%01010101010101010101010101010101 GPIOB MODER !

Easy, GPIOB BITS 0 - 15 are now all OUTPUT.

Arduino

int a; for(a=0;a < 13;a++){ pinMode(a, OUTPUT); }

Which port is ‘pin’ ? On the UNO, ‘pin’ has a value of 0 - 13 and is spread across Ports B and D, so if you want them all to be OUTPUTS, then code like this is required, or you have to refer to the databook and configure each pin individually.