1 DOES_Explained
Podrobně je tohle vysvětlované v MOVING FORTH Part 3: Demystifying DOES> by Brad Rodriguez, zde nabízím jiný pohled/jiná slova pro totéž (abych si načtené rychle obnovil kdykoli později)
Mám FORTH pro MHF-002 (atmega2560, 3B=24bit CELL), motivační příklad je vytvoření dvou konstant TEN a FIVE pro nějaké další použití, představme si, že je teď celá paměť jak writeable, tak executable, ať nemusíme šíbovat s adresami
: CONSTANT CREATE , DOES> @ ; 10 CONSTANT TEN ( -- 10 ) 5 CONSTANT FIVE ( -- 5 )
Provedení : CONSTANT CREATE , DOES> @ ;
- : (je interpretováno) přečte nasledující slovo a vytvoří pro něj hlavičku, zahájí kompilaci (STATUS=F_COMPILING) ( -- )
Addr | value | comment --------+---------------+------------------------------ 0x001000| 0x0009F0 | 3B odkaz na předchozí hlavičku 0x001003| 0x40 | 1B Attributy (dočasně FLAG_HIDDEN) 0x001004| 8 | 1B délka slova 0x001005| CONSTANT | 8B název slova 0x00100D| w_docol_cw | 3B CW: code_word dvojtečkové definice 0x001010| ... | <== sem přijde další kód, zatím sem ukazuje HERE
- CREATE není IMMEDIATE, takže se tam prostě vloží jeho _cw (zakompiluje se), provede se až po spuštění CONSTANT ( -- )
| | --------+---------------+------------------------------ 0x001010| w_CREATE_cw | 3B odkaz na CW slova CREATE 0x001013| ... | <== sem přijde další kód, zatím sem ukazuje HERE
- , (comma) není IMMEDIATE, takže se zakompiluje ( -- )
| | --------+---------------+------------------------------ 0x001013| w_comma_cw | 3B odkaz na CW slova čárka , 0x001016| ... | <== sem přijde další kód, zatím sem ukazuje HERE
- DOES> je IMMEDIATE, zakompiluje odkaz na ww_does_cw a asm kód pro CALL do_DOES ( -- )
| | --------+---------------+------------------------------ 0x001016| ww_does_cw | 3B odkaz na CW pomocného slova pro DOES> 0x001019| CALL do_DOES | 4B volání do_DOES (návratová hodnota bude sloužit jako odkaz sem, nikoli pro return) 0x00101D| ... | <== sem přijde další kód, zatím sem ukazuje HERE- je tu problém, že nová slova se dělají do RAM, ale provádění asm instrukci je možné jen z FLASH. Než toto slovo použijeme, musíme ho tam překlopit
- tento krok ukončil definování, co se bude dělat při spuštění slova CONSTANT a zahájil definování, co se bude dělat při spuštění slov jím vytvořených (třeba TEN)
- ww_does_cw udělá tu správnou věc až bude spuštěno (viz níže)
- @ není IMMEDIATE, takže se tam prostě vloží jeho _cw, provede se až po spuštění TEN ( -- )
| | --------+---------------+------------------------------ 0x00101D| w_at_cw | 3B odkaz na CW slova @ 0x001020| ... | <== sem přijde další kód, zatím sem ukazuje HERE
- ; je IMMEDIATE, zakompiluje odkaz na w_exit_cw, shodí flag FLAG_HIDDEN a ukončí definici (STATUS=F_INTERPRETING) ( -- )
| | --------+---------------+------------------------------ 0x001003| 0x0 | 1B Attributy | | --------+---------------+------------------------------ 0x001020| w_exit_cw | 3B odkaz na CW slova EXIT 0x001023| ... | <== sem přijde další kód, zatím sem ukazuje HERE
první řádek je hotov, mám slovo CONSTANT:
Addr | value | comment --------+---------------+------------------------------ 0x001000| 0x0009F0 | 3B odkaz na předchozí hlavičku 0x001003| 0x0 | 1B Attributy (žádné) 0x001004| 8 | 1B délka slova 0x001005| CONSTANT | 8B název slova 0x00100D| w_docol_cw | 3B CW: code_word dvojtečkové definice 0x001010| w_CREATE_cw | 3B odkaz na CW slova CREATE 0x001013| w_comma_cw | 3B odkaz na CW slova čárka , 0x001016| ww_does_cw | 3B odkaz na CW pomocného slova pro DOES> 0x001019| CALL do_DOES | 4B volání do_DOES (návratová hodnota bude sloužit jako odkaz sem, nikoli pro return) 0x00101D| w_at_cw | 3B odkaz na CW slova @ 0x001020| w_exit_cw | 3B odkaz na CW slova EXIT
Teď ho (značně později) použiju k vytvoření slova TEN takto 10 CONSTANT TEN
Provedení 10 CONSTANT TEN ( -- 10 )
INTERPRETER přečte 10, usoudí, že nejde o slovo, ale o číslo a vloží ho na zásobník ( -- 10 )
- INTERPRETER přečte CONSTANT, usoudí, že jde o slovo, a spustí ho
- tedy se spustí w_docol_cw s IP ukazujícím na další slovo a DT s hodnotou 0x001010 (w_CREATE_cw)
- DOCOL uloží IP na RST a dá do něj DT a skočí na NEXT
- 0x001010 (w_CREATE_cw) přečte TEN a utvoří pro něj hlavičku ( -- 10 )
Addr | value | comment --------+---------------+------------------------------ 0x001023| 0x001000 | 3B odkaz na předchozí hlavičku 0x001026| 0x0 | 1B Attributy (žádné) 0x001027| 3 | 1B délka slova 0x00102A| TEN | 3B název slova 0x00102D| w_docreate_cw | 3B CW: code_word vložený CREATE 0x001030| ... | <== sem přijde další kód, zatím sem ukazuje HERE
- 0x001013 (w_comma_cw) vezme hodnotu ze zásobníku a zakompiluje ji jako CELL ( -- )
| | --------+---------------+------------------------------ 0x001030| 0x00000A | 3B 10 0x001033| ... | <== sem přijde další kód, zatím sem ukazuje HERE
- 0x001016 (ww_does_cw) zakompiluje po něm následující adresu 0x001019 (CALL do_DOES) do code word nového slova a a dál zafunguje jako w_exit_cw, čili ukončí provádění, vyzvedne IP z RST a skočí na NEXT (čímž se vrátí do INTERPRETER)
| | --------+---------------+------------------------------ 0x00102D| 0x001019 | 3B CW: adresa (CALL do_DOES) ze slova CONSTANT
- takže konstanta TEN teď vypadá takto:
Addr | value | comment --------+---------------+------------------------------ 0x001023| 0x001000 | 3B odkaz na předchozí hlavičku 0x001026| 0x0 | 1B Attributy (žádné) 0x001027| 3 | 1B délka slova 0x00102A| TEN | 3B název slova 0x00102D| 0x001019 | 3B CW: adresa (CALL do_DOES) ze slova CONSTANT 0x001030| 0x00000A | 3B 10
- a konstanta FIVE teď vypadá takto:
Addr | value | comment --------+---------------+------------------------------ 0x001033| 0x001000 | 3B odkaz na předchozí hlavičku 0x001036| 0x0 | 1B Attributy (žádné) 0x001037| 4 | 1B délka slova 0x00103A| FIVE | 4B název slova 0x00103E| 0x001019 | 3B CW: adresa (CALL do_DOES) ze slova CONSTANT 0x001031| 0x000005 | 3B 5
- A povšimněme si, že vůbec neobsahují kód po DOES>, bez ohledu na jeho délku. To může být i značná úspora pro složitější kód a víc konstant
A konečně k čemu je to dobré a co to zajímavého dělá - v MOVING FORTH Part 3: Demystifying DOES> by Brad Rodriguez jsou k tomu obrázky, já si to tu rozepíšu krok po kroku, ale hlavní trik je, že se bude provádět kód v těle CONSTANT s daty z těla TEN (nebo FIVE, nebo ..).
Provedení TEN
- INTERPRETER přečte TEN, usoudí, že jde o slovo, a spustí ho
Addr | value | comment --------+---------------+------------------------------ 0x001023| 0x001000 | 3B odkaz na předchozí hlavičku 0x001026| 0x0 | 1B Attributy (žádné) 0x001027| 3 | 1B délka slova 0x00102A| TEN | 3B název slova 0x00102D| 0x001019 | 3B CW: adresa (CALL do_DOES) ze slova CONSTANT
- tedy skočí na adresu z jeho CW, čili 0x001019 s IP ukazujícím na další slovo a DT s hodnotou 0x001030 (adresa, kde je to 0x00000A = 10)
0x001019| CALL do_DOES | 4B volání do_DOES (návratová hodnota bude sloužit jako odkaz sem, nikoli pro return) 0x00101D| w_at_cw | 3B odkaz na CW slova @ 0x001020| w_exit_cw | 3B odkaz na CW slova EXIT
na adrese 0x001019 je instrukce CALL do_DOES, tedy se na systémový zásobník uloží následující adresa 0x00101D jako bod pro návrat a skočí se na do_DOES
do_DOES uloží IP na RST, uloží DT na zásobník, do IP vyzvedne hodnotu ze systémového zásobníku (0x00101D) a skočí na NEXT ( -- 0x001030 )
- NEXT zařídí, že se začnou vykonávat slova od 0x00101D včetně
0x00101D| w_at_cw | 3B odkaz na CW slova @
- @ převede adresu na obsah ( 0x001030 -- 10 )
- NEXT zařídí, že se začnou vykonávat slova od 0x00101D včetně
0x001020| w_exit_cw | 3B odkaz na CW slova EXIT
- w_exit_cw zajistí návrat do volaného slova (10 -- 10)
a to jsou právě ta slova, co byla při kompilování CONSTANT za tím DOES>
(takže se vezme CELL z té adresy, čili 10 a uloží se na zásobník a tím to skončí)
DOES_Explained