Forth, AmForth ja AVR. Pieni opas näppärään kehitysalustaan

[size=150]Forth[/size]
Forth on hyvin vanha ohjelmointikieli, jota Charles Moore aloitti kehittelemään jo 1960-luvulla. Forth on pinokieli ja operaatiot kohdistuvat pinoon. Forth on yleensä tulkki ja kääntäjä yhdistelmä. Sillä voi kirjoittaa ohjelmia ja lisäksi tehdä interaktiivisia toimintoja. Lisäksi Forthissa on valkoista avaruutta eli välilyöntejä, tabeja jne sekä numeroita ja sanoja. Numero voi olla tietenkin desimaali tai vaikka heksadesimaali. Tämä riippuu mihin kantalukuun Forth on asetettu. Sana voi olla vakio, muuttuja tai jotain funktiota muistuttava asia. Sana siis manipuloi pinoa.

Forth on myös laajennettava. Omia sanoja, jotka jossain sopivassa ympäristössä voisi olla määriteltynä esimerkiksi : pikapesu pese huuhtele linkoa ; Kaksoispiste aloittaa sanan määrittelyn, pikapesu on sanan nimi ja pese, huuhtele ja linkoa ovat suoritettavia sanoja, jotka ovat erotettu välilyönneillä. Puolipiste päättää määrittelyn. Forth ei myöskään yleensä ole merkkikoosta tarkka. ISOSANA on yleensä sama sana kuin isosana.

Forthin kantava ajatus on, että ongelmat ovat yksinkertaisia, kun ne vain yksinkertaistetaan ja rajataan tarpeeksi. Suunnittele ylhäältä alas ja toteuta alhaalta ylös. Silloin pikapesu voi todellakin olla kuvatun kaltainen, kun monimutkaisuus on pilkottu pieniin palasiin alla oleviin kerroksiin yksinkertaistettuna.

Seuraavaksi käyn läpi kielestä läpi hyvin pienen pintaraapaisun. En sekaannu liukulukupinoon, enkä merkkijonojen käsittelyyn. Myös sanakirjan käsittely, muistin varaaminen ja monet muut asiat jätetään käsittelemättä. Kuitenkin kaikki sanat saa näkymään sanalla WORDS. Kannattaa tutustua itselle valitun toteutuksen dokumentaatioon, standardiin ja siihen miten jokin sana on määritelty.

Kooditagien sisään on kirjoitettu ja lähinnä kopipastetttu mitä tapahtui. Vastaukset ovat kommentoituina. Periaatteessa Voit kopioda näitä koodeja suoraan gForthiin, mutta jokaisen kommenttirivin perässä on sitten myös ok

[size=150]Pino[/size]

Koska Forth on pinokieli, se tekee tarjoaa käyttäjälleen käänteisen puolalaisen logiikan tai postfiksi notaation, kummaksi nyt haluaa kutsua. Mikäli Forthissa haluaa nähdä 3 + 7 laskutoimituksen tuloksen kirjoitetaan 3 7 + . Tuossa tapahtuu ensin 3 ja 7 pinoon laitto. Tämän jälkeen + ottaa pinosta kaksi elementtiä, laskee ne yhteen ja laittaa pinoon tuloksen. Piste ottaa pinosta päällimmäisen ja näyttää sen.

postfiksin voima näkyy parhaiten sulkeilla laskettaessa. 7 * ( 2 + 3 ) lasketaan

2 \ Vastaus:  ok
3 \ Vastaus:  ok
+ \ Vastaus:  ok
7 \ Vastaus:  ok
* \ Vastaus:  ok
. \ Vastaus: 35  ok

Forthissa sulkeilla on oma merkityksensä. Koska pinon tila on tärkeä kehittäjälle, yleensä (luetaan aina) sanan määrittelyyn lisätään pinon vaikutuskommentti.

: laske_tilavuus ( leveys korkeus syvyys -- tilavuus ) * * ;
\ Pinon vaikutuskommentissa kerrotaan, että ennen suoritusta 
\ tarvitaan kolme lukua, joista päällimmäinen on syvyys ja suorituksen jälkeen
\ pinossa on tilavuus
\ Normaalit kommentit alkavat kenoviivalla ja kommentti on koko rivi.
\ Ja testataan...
1 2 3 laske_tilavuus cr . 
\ Laita 1, 2 ja 3 pinoon suorita laske_tilavuus, rivinvaihto ja 
\ tulosta pinon päällimmäinen
\ Vastaus: 6 ok
\ cr aiheuttaa rivinvaihdon.

Pinoa voi myös manipuloida.
DUP ( x – x x ) Kopioi päällimmäisen pinossa.
SWAP ( x1 x2 – x2 x1 ) vaihtaa kahden päällimmäisen järjestystä pinossa
ROT ( x1 x2 x3 – x2 x3 x1 ) Kierrättää kolmea päällimmäistä pinossa
DROP ( x – ) poistaa ja unohtaa päällimmäisen pinosta
ovat yleisimmät, mutta eivät ainoat manipulaattorit.

[size=150]Kääntäminen ja tulkkaus[/size]
Kuten mainittu, Forthissa on kaksi tilaa: kääntäminen ja tulkkaus. Kääntäessä luodaan sanoja, kuten ylemmässä koodissa luotiin laske_tilavuus ja tulkattaessa ajetaan näitä sanoja esimerkkinä 1 2 3 laske_tilavuus cr .

Näissä tiloissa on käytössä eri sanoja. Joitain ei voi ajaa kääntäessä ja toisia ei voi ajaa tulkatessa. Ja tämähän on sitten täysin riippuvainen mitä Forthin toteutusta käytetään.

2 0> if ." Ei onnistu." then 
\ Vastaus: :32: Interpreting a compile-only word
\ Vastaus: 2 0> >>>if<<< ." Ei onnistu." then


: parannettu_hello_world cr dup 0> if . ." kertaa heippa maailma!" else ." Negatiivinen tervehdys." then cr ; \ Vastaus: ok
-2 parannettu_hello_world  
\ Vastaus: Negatiivinen tervehdys.
\ Vastaus:  ok
2 parannettu_hello_world   
\ Vastaus: 2 kertaa heippa maailma!
\ Vastaus:  ok

Tulkatessa ei voi käyttää if else then vuonohjausrakennetta. Siksi se tarvitsee kääntää. Ja siksi on luotu parannettu_hello_world. Ensin tulostetaan rivinvaihto ja kopioidaan päällimmäinen pinosta. Päällimmäistä verrataan nollaan, jolloin pinoon jää numero ja totuusarvo. IF suorittaa if … else välin, mikäli totuusarvo on totta ja else … then mikäli ei. ." Tulostettava juttu" käskyllä tulostuu tekstiä ruudulle. ." jälkeinen välilyönti ei kuitenkaan tulostu, sillä se on sanan erotin.

Totuusarvot ovat määritelty seuraavasti 0 on epätosi (kaikki bitit alhaalla) ja 0 invert on tosi, joka sitten on -1 (kaikki bitit ylhäällä). Myös kaikki muut arvot kuin 0 voidaan tulkita tosi arvoiksi.

Usein on esitelty myös sana endif, jota voi käyttää then sanan tilalla. Forthissa then tarkoittaa nyt kun ollaan tämä käsitelty niin jatketaan sitten tästä. Siksi endif kuvaa paremmin if-rakenteen lopetusta.

[size=150]Silmukat[/size]
Ikikieriön saa aikaan määrittelemällä sanan jossa on BEGIN ja AGAIN esimerkiksi : ikikierio ( – ) 1 begin 1 + dup . cr again ; tulostaisi numeroita päättymättömästi kasvaen ja ylivuotaen.

Koska moinen olisi hieman pöljää lähes aina on olemassa myös BEGIN koodia totuusarvo UNTIL. Esimerkkinä

: laske_alas ( alku -- ) BEGIN 1 - dup dup . cr 0= UNTIL drop ; \ Viimeinen drop pudottaa laskussa käytetyn numeron pois, joka on tapauksessamme 0 10 laske_alas \ Vastaus: 9 \ Vastaus: 8 \ Vastaus: 7 \ Vastaus: 6 \ Vastaus: 5 \ Vastaus: 4 \ Vastaus: 3 \ Vastaus: 2 \ Vastaus: 1 \ Vastaus: 0 \ Vastaus: ok Silmukkaa ajetaan siis kunnes totuusarvo on tosi.

BEGIN koodi1 totuusarvo WHILE koodi 2 REPEAT silmukka ajaa koodi1 josta tulee totuusarvo ja koodi2 ajetaan mikäli totuusarvo oli totta, jonka jälkeen palataan koodi1 alkuun. Mikäli totuusarvo olikin epätosi, jatketaan REPEAT jälkeisestä sanasta.

DO koodia LOOP on vähän kuin for rakenne C:ssä. DO ( raja alku – ) aloittaa silmukan ja koodia suoritetaan LOOP ( – ) sanaan asti. LOOP sanassa indeksiä korotetaan yhdellä ja jos se on yhtä suuri kuin raja, silmukasta poistutaan.

I on erityinen muuttuja. Se sijaitsee toisaalla ja paikassa, johon en tule tässä puuttumaan. Paikka on return stack. I pitää sisällään indeksin, jota silmukka iteroi.

: laskettu_silmukka do i . loop ;  \ Vastaus:  ok
10 5 laskettu_silmukka \ Vastaus:  5 6 7 8 9  ok

[size=150]Muuttujat[/size]

Joskus on vain kiva käyttää muuttujia ja vakioita.
Muuttujia voi käsitellä seuraavalla tavalla

\ luodaan muuttuja
variable muuttuja 
\ tallennetaan pinosta muuttujaan arvo !-sanalla. Lausutaan store
10 muuttuja !
\ haetaan muuttujan arvo pinoon @-sanalla. Lausutaan fetch
muuttuja @

Vakioita luodaan miltei samalla tavalla. Siihen eteen vain laitetaan eteen haluttu arvo.

\ Luodaan
100 constant sentit_metrissa
\ Laitetaan pinoon ja tulostetaan pois
sentit_metrissa cr .
\ Vastaus: 100  ok

[size=150]Standardi ja toteutukset[/size]

Forthista on olemassa standardi. ANS FORTH vuodelta 1994 ja päivitettyä versiota ollaan tekemässä. Standardia voi lukea http://www.taygeta.com/forth/dpans.html ja valita itselleen sopivan Forth toteuksen http://www.forth.org/compilers.html

Tässä artikkelissa on käytetty gforthia esimerkkien tekemiseen. Sivulta huomattaneen helposti, että useimmat toteutukset ovat tarkoitettu mikrokontrollereihin. Lisäksi paljastettakoon, että monet toteutuksista on tehty assemblerilla.

[size=150]AmForth[/size]

AmForth on AVR mikrokontrollereille tarkoitettu Forth toteutus. http://amforth.sourceforge.net/ Se vaatii vähän yli 8 kiloa flashia, eli vähintään atmega168 tai atmega328. Itse tungin sen atmega128 järjestelmään.

Käänsin sen AVR studio 4 avulla, koska en saanut Avralla (vaatii git version) toimivaa binääriä aikaiseksi.

Resepti:

  1. Lataa AVR studio 4. Linkit http://i.amniels.com/avr-studio-4-and-5-download-links
  2. Asenna WinAVR
  3. Lataa AmForth ja pura lähdekoodi jonnekin välilyönnittömään paikkaan. (Ei Documents and Settings kansion alle vaan esim f:\amforth)
  4. Kopioi Amforth\appl\template hakemisto appl kansion alle esimerkiksi mun_forth kansioksi.
  5. Avaa AVR studio.
  6. Luo assembleri v2 projekti aseta kontrolleri ja ohjelmointilaite kohdilleen. Ja sano, ettet tarvitse uutta tiedostoa.
  7. Avaa project->assembler options ja Lisää hakemisto amforth\core additional include pathiin
  8. Tuo projektiin template.asm
  9. Avaa template.asm tiedostoa.
  10. Muuta .include “device.asm” muotoon .include “devices/atmega128/device.asm”
  11. Jos käytössä on ATmega128, lisää edellisen perään .equ MCUSR = MCUCSR
  12. Arvo fuset kohdilleen. Lähinnä kellotaajuus ja bootloader sizen pitää olla NRWW flashin kokoinen.
  13. Assemble
  14. Ja flashaa.

Tämän jälkeen vain sarjakaapeli kiinni, terminaali 9600 8n1 ei kättelyä asetuksin auki.
Virrat päälle ja saat tervehdykseksi:

amforth 4.9 ATmega128

tai jotain vastaavaa. Tästä liittymästä voisi aivan varmasti käyttää, ja olen käyttänytkin AmForthia. Se nyt on vain herkkä backspacen käytölle ja muutenkin herkkä.

Siksi tarvitaan AmForth-shell Tämä on python skripti ja sitä varten tarvitaan python. Windows käyttäjät ovat tässä omillaan ja Linux käyttäjillä se todennäköisesti on. Oman distribuution paketista vain asentamaan.

AmForthin tools hakemistossa on kyseinen ohjelma.

$ python2 ./amforth-shell.py -p /dev/ttyUSB0 -s 9600
|I=Entering amforth interactive interpreter
|I=Updating Controller Type
|I=successfully loaded controller definitions for atmega128
|I=Updating host files
|I= Reading .
(ATmega128)>
Ja nyt voidaan tehdä esimerkiksi seuraava temppu:
(ATmega128)> hex PINA @ PINB @ PINC @ PIND @ . . . .
BC FB FF BF ok
(ATmega128)>

Ja komentamalla words ei löydetäkään mainittuja PINA jne vakioita. Rekisterien muuttaminen osoitteiksi tapahtui sujuvasti amforth-shellin sisällä.

Hyviä apureita, joita kannattaa ajaa järjestelmään ovat bitnames.frt, sekä markerin lisääminen, joka vaatii uudelleen kääntämisen ja flashauksen. http://amforth.sourceforge.net/recipes/undoing-definitions.html

Niin ja ominaisuus. Vaikka virta katkaistaan mikrokontrollerista, sanat eivät katoa. Ne ovat kirjoitettuna flashille.

Kannattaa kuitenkin tutustua huolella tuohon vähäiseen dokumentaatioon, mikä on AmForthin kotisivuilla ja ehkä myös gForthin dokumentaatioon noin yleisesti. Se on hyvin dokumentoitu ympäristö, vaikka tekeekin joitain asioita mielestäni väärin. Antaa hyvän kuvan kieleen ja millaisia sanoja kielestä voi löytyä.

Kysymyksiin yritän vastata ja ongelmiin ohjata helpotusta.

Lisätään vielä vähän tietoa tuosta AmForthista.
Jos asennat AmForthin Arduinoon, sen käyttäminen Arduinona ei ole enään niin helppoa, vaan piiri tulee flashata Arduinon buuttiloaderilla.

Ja jotta järjestelmä toimii tulee myös dict_appl.inc tiedostoon kajota.
Itsellä lukee kohdassa:
; include some controller specific definitions
.include “devices/atmega128/device.inc”

Ja template.asm on tämän näköinen:

[code]; This is a template for an amforth project.
;
; The order of the entries (esp the include order) must not be
; changed since it is very important that the settings are in the
; right order
;
; note: .set is like a variable, .equ is like a constant
;
; first is to include the macros from the amforth
; directory

.include “macros.asm”

; include the amforth device definition file. These
; files include the *def.inc from atmel internally.
.include “devices/atmega128/device.asm”
.equ MCUSR = MCUCSR
; the dictionary search treats lowercase and uppercase
; letters the same. Set to 0 if you do not want it
.set WANT_IGNORECASE = 1

; amforth needs two essential parameters
; cpu clock in hertz, 1MHz is factory default
.equ F_CPU = 16000000

; terminal settings
; check http://amforth.sourceforge.net/recipes/usart-settings.html
; for further information
.set WANT_ISR_RX = 1 ; interrupt driven receive
.set WANT_ISR_TX = 0 ; send slowly but with less code space
; define which usart to use.
.include “drivers/usart_1.asm”
; 9600 @ 8N1 is commonly used.
.equ BAUD = 9600
.equ USART_C_VALUE = bm_ASYNC | bm_NO_PARITY | bm_1STOPBIT | bm_8BIT

; dont touch the next 5 lines
.if WANT_ISR_RX == 1
.set USART_B_VALUE = bm_ENABLE_TX | bm_ENABLE_RX | bm_ENABLE_INT_RX
.else
.set USART_B_VALUE = bm_ENABLE_TX | bm_ENABLE_RX
.endif

.equ TIBSIZE = $64 ; ANS94 needs at least 80 characters per line
.equ APPUSERSIZE = 10 ; size of application specific user area in bytes

; addresses of various data segments
.set rstackstart = RAMEND ; start address of return stack, grows downward
.set stackstart = RAMEND - 80 ; start address of data stack, grows downward
; change only if you know what to you do
.equ NUMWORDLISTS = 8 ; number of word lists in the searh order, at least 8

; include the whole source tree.
.include “amforth.asm”[/code]
Eli joidenkin rivien järjestystä on muuteltu.

amforth shellistä pääsee muuten pois kirjoittamalla #exit ja sen muut toiminnot ovat dokumentoituina kyseisessä tiedostossa kommentteina. helpin saa ohjelman pätkästä käynnistämällä vivulla -h

Hieman Forth koodia.

Tämä on tarkoitettu Olimexin MT-128 levylle.

lib/ans94 alta tulee olla ajettu /core/postpone.frt ja core-ext/marker.frt sekä libin alta bitnames.frt Ja tässä järjestyksessä.

Käyttääksesi buzzeria tai nappeja, tarvitsee ajaa ensin buzzer_init ja buttons_init.

\ Buzzer, buttons and relay module for Olimex MT128
\ https://www.olimex.com/dev/avr-mt128.html

\ Buzzer runs with timer3 and H/W OC3B and OC3C pins
\ Trick is to use output comare match mode.
\ beep_{on, off} does not block but beep waits using ms. 

\ executing init_buttons and init_buzzer is required
\ before using buzzer or buttons.
\ marker and bitnames required.

\ {up, left, center, right, down}_action_{on, off} are
\ deferred words. Set them what ever you want to do with buttons.
\ As default they are noop.


marker mt-128

PORTE $4 portpin: BUZZER_1
PORTE $5 portpin: BUZZER_2

: timer3_steps ( herz -- steps )
    dup $1E > \ 31 Hz 64516 steps.
    over
    $4E21 < \ 20kHz
    and invert
    if
	drop $3E8 \ default 1kHz
    then
    f_cpu $8 ud/mod \ Double cell speed for clock divided 8.
    2swap \ Bring hertz and remainder to top
    drop \ Drop remainder 
    ud/mod \ Steps required.
    d>s \ Division to single cell
    swap drop \ Drop remainder and leave steps.
;
variable tempo_multiply
variable tempo_divide
: init_buzzer
    BUZZER_1 pin_output
    BUZZER_2 pin_output
    $14 TCCR3A c! \ Toggle OC3{A B} CTC mode part1
    $08 TCCR3B c! \ CTC Mode part2 counter stopped
    $40 TCCR3C c! \ Toggle OCRB
    $40 tempo_multiply !
    $FF tempo_divide !
;
    
: beep_on ( hertz -- )
    \ Start beeping
    timer3_steps
    dup dup ( steps steps steps )
    OCR3C !
    OCR3B !
    OCR3A ! ( frequency )
    $0A TCCR3B c! \ Start timer!
;

: beep_off ( -- )
    \ Stop beeping
    $08 TCCR3B c! \ Stop timer.
;

: beep ( time hertz -- )
    beep_on
    \ Comment out next line
    dup
    ms beep_off
    \ and next if you dont want short break after beep.
    \ It sounds better with break.
    $14 / dup 0<> if ms else drop then
;
: tempo ( midi -- ms )
    \ Convert midi times to ms
    tempo_multiply @ tempo_divide @ */
;

: wagner ( -- )
    \ Ride of the valkyrie
    $814 tempo $172 beep
    $822 tempo $1EE beep
    $160 tempo $172 beep
    $814 tempo $1EE beep
    $844 tempo $24A beep
    $844 tempo $1EE beep
    $822 tempo $24A beep
    $160 tempo $1EE beep
    $814 tempo $24A beep
    $844 tempo $2E4 beep
    $844 tempo $24A beep
    $822 tempo $2E4 beep
    $160 tempo $24A beep
    $814 tempo $2E4 beep
    $844 tempo $370 beep
    $844 tempo $1B8 beep
    $822 tempo $24A beep
    $160 tempo $1B8 beep
    $814 tempo $24A beep
    $890 tempo $2E4 beep
;


PORTA $0 portpin: BUTTON_UP
PORTA $1 portpin: BUTTON_LEFT
PORTA $2 portpin: BUTTON_CENTER
PORTA $3 portpin: BUTTON_RIGHT
PORTA $4 portpin: BUTTON_DOWN

variable button_status $4 cells allot
Rdefer up_action_on ( -- )
Rdefer left_action_on ( -- )
Rdefer center_action_on ( -- )
Rdefer right_action_on ( -- )
Rdefer down_action_on ( -- )

Rdefer up_action_off ( -- )
Rdefer left_action_off ( -- )
Rdefer center_action_off ( -- )
Rdefer right_action_off ( -- )
Rdefer down_action_off ( -- )



: init_buttons ( -- )
    BUTTON_UP pin_input
    BUTTON_LEFT pin_input
    BUTTON_CENTER pin_input
    BUTTON_RIGHT pin_input
    BUTTON_DOWN pin_input
    \ MT128 has external pull-up.
    \    BUTTON_UP pin_pullup_on
    \    BUTTON_LEFT pin_pullup_on
    \    BUTTON_CENTER pin_pullup_on
    \    BUTTON_RIGHT pin_pullup_on
    \    BUTTON_DOWN pin_pullup_on
    ['] noop dup is up_action_on
    dup is left_action_on
    dup is center_action_on
    dup is right_action_on
    dup is down_action_on
    dup is up_action_off
    dup is left_action_off
    dup is center_action_off
    dup is right_action_off
    is down_action_off
;
: button_status@ ( x -- f )
    cells button_status + @
;
: button_status! ( f x -- )
    cells button_status + !
;
: button_up_status@ ( -- f )
    button_status @
;
: button_left_status@ ( -- f )
    $1 button_status@
;

: button_center_status@ ( -- f )
    $2 button_status@
;
: button_right_status@ ( -- f )
    $3 button_status@
;
: button_down_status@ ( -- f )
    $4 button_status@
;

: read_buttons ( -- )
    BUTTON_UP pin@ 0= dup button_up_status@ - dup -1 =
    if
	\ Button just went down
	drop
	$320 beep_on \ 800Hz
	up_action_on
    else
	$1 =
	if
	    \ button released
	    beep_off
	    up_action_off
	then
    then
    $0 button_status!
    BUTTON_LEFT pin@ 0= dup button_left_status@ - dup -1 =
    if
	drop
	$384 beep_on \ 900Hz
	left_action_on
    else
	$1 =
	if
	    beep_off
	    left_action_off
	then
    then
    $1 button_status!
    BUTTON_CENTER pin@ 0= dup button_center_status@ - dup -1 =
    if
	drop
	$3E8 beep_on \ 1000Hz
	center_action_on
    else
	$1 =
	if
	    beep_off
	    center_action_off
	then
    then
    $2 button_status!
    BUTTON_RIGHT pin@ 0= dup button_right_status@ - dup -1 =
    if
	drop
	$44C beep_on \ 1100Hz
	right_action_on
    else
	$1 =
	if
	    beep_off
	    right_action_off
	then
    then
    $3 button_status!
    BUTTON_DOWN pin@ 0= dup button_down_status@ - dup -1 =
    if
	drop
	$4B0 beep_on \ 1200Hz
	down_action_on
	$1 =
	if
	    beep_off
	    down_action_off
	then
    then
    $4 button_status!
;


PORTA $6 portpin: RELAY

: relay_on ( -- )
    RELAY pin_output
    RELAY high
;
: relay_off ( -- )
    RELAY low
    RELAY pin_input
;

Sanat, joita tuolla koodilla tulee käyttöön ovat alla selostettu. Lihavammalla ovat sitten ne sanat, jotka ovat useammin mielessä ja käytössä. Ovat käännetyssä järjestyksessä, koska ovat wordsin tulostuksesta otettu.

relay_off Rele pois vetämästä
relay_on rele vetämään
RELAY Releen osoite ja maski
read_buttons Lukee napit
button_down_status@ button_right_status@ button_center_status@ button_left_status@ button_up_status@ Tilaliput nappien tilalle.

button_status! Apusana, jolla nappulan tila tallennetaan muuttujaan.
button_status@ Apusana jolla haetaan nappulan tila muuttujaan
init_buttons nappuloiden alustus
down_action_off right_action_off center_action_off left_action_off up_action_off
Ovat sanoja jotka suoritetaan kun nappula vapautetaan. Oletuksena noop, mutta voidaan asettaa muuksi ’ sana ’ down_action_off defer!
Luotaessa sanaa tuo menee sitten muotoon : uusi_sana [’] sana [’] down_action defer! ;

down_action_on right_action_on center_action_on left_action_on up_action_on Sama kuin off, mutta suoritetaan painettaessa.

button_status taulukko, jossa tilat ovat tallessa.
BUTTON_DOWN BUTTON_RIGHT BUTTON_CENTER BUTTON_LEFT BUTTON_UP nappien bittimaskit ja osoitteet.

wagner Onko aamu? Haistanko napalmia?
tempo Muuttaa wagnerin midiajat millisekunneiksi.
beep piippaa taajuudella ja ajalla.
beep_off beep_on piippaus pois ja päälle
init_buzzer alustaa piipperin
tempo_divide tempo_multiply Muuta midiaikoja suhteessa multiply/divide
timer3_steps Taajuus timer3 askeliksi piippauksen korkeutta varten
BUZZER_2 BUZZER_1 piipperin bittimaskit ja osoitteet.