Write and read to target memory

published: 13 April 2021 / updated 14 April 2021

Lire cette page en français

 

 

Preamble

We are fortunate to use gForth, a version of the FORTH language available under Windows, Linux and even ANDROID. gForth has the following advantages that we are interested in metacompilation:

gForth therefore offers sufficient workspace to allow the generation of targets of significant size.

Definition of target memory space

For our generation of ARDUINO code, we will reserve a memory space of 32 kilobytes:

forth definitions 
1024 constant PAGE-SIZE 
 
\ allot n pages in memory 
create META-TARGET 
    PAGE-SIZE 32 * allot 

META-TARGET is our target memory space. We must now graft this space memory to the metacompiler. We compile the metacompiler, then we assign to ADR-T defined in the META vocabulary the address of our metacompilation workspace:

meta 
META-TARGET ADR-T ! 

File access meta.txt.

Compilation direction of 16-bit words

gForth uses the words c @ c! @! to access the content of variables and memory space. If c @ c! handles 8-bit data perfectly, it doesn't. words @! which deal with 64-bit data! Our meta-compiler will need to take specifically supports 8 and 16 bit data processing.

Entering a 16-bit word into memory is specific to each type of target processor. It exists two models for recording 16-bit words:

In FORTH the execution on ARDUINO of a sequence $ 1234 i, gives this:

flash create TEST $1234 i,  ok<#,flash>
TEST $10 dump
800e :34 12 02 80 83 2d 61 73 0e 94 8d 7b 1c 80 00 00 4....-as...{.... ok<$,ram>

As we can see on the line for restoring the code in memory, we see the sequence 800e :34 12 ... which demonstrates that memory management on an ARDUINO card conforms to the LITTLE-ENDIAN model.

To manage a model without worry in meta-compilation, we define:

true value LITTLE-ENDIAN 
: byte-invert ( w -- w') 
    LITTLE-ENDIAN invert if 
        $100 /mod 
        swap $100 * + 
    then 
    ; 

The word byte-invert inverts the pair of bytes in a 16-bit word at destination target memory that is not LITTLE-ENDIAN model. For AVR processors, select the LITTLE-ENDIAN model.

The word byte-invert is used by our metacompiler.

File access forthExtend.txt.

Management of target memory space

In the meta.txt file, we start by defining two variables allowing access to the target memory space:

\ Memory access variables in the target 
variable ADR-T                      \ memorize target address; ADRment-Target 
variable DP-T                       \ and Target offset;  Dict.Pointer-Target 
 
\ convert target-addr in physical-address 
: taddr-calc ( taddr -- phys-addr) 
    ADR-T @ + 
    ; 

The ADR-T variable stores the target memory address (see above).

The DP-T variable is our dictionary pointer to this target memory.

The word taddr-calc transforms a relative pointing address in memory target in physical address exploitable by gForth.

Reading target memory

The words c@-t and @-t allow reading of 8 and 16 bit values in the target memory pointed to by taddr.

\ get a byte in the target 
: c@-t  ( taddr -- c ) 
    taddr-calc c@ 
    ; 
 
\ get a 16-bit word from the target 
: @-t  ( taddr -- w ) 
    dup 1+ c@-t $100 * 
    swap c@-t + 
    byte-invert 
    ; 

taddr is a value between 0 and the maximum value of the size of the target memory space.

Write to target memory

The words c!-t and !-t allow the writing of 8 and 16 bit values in the target memory pointed to by taddr.

\ store a byte in the target 
: c!-t  ( char taddr -- ) 
    taddr-calc c! 
    ; 
 
\ store a 16-bit word in the target 
: !-t  { word taddr -- }    \ CAUTION: local variables 
    word byte-invert 
    $100 /mod swap 
    taddr  c!-t 
    taddr  1+ c!-t 
    ; 

WARNING the definition of the word !-t uses locals variables in order to make the code more readable.

Pointing and allocation in target memory

The words here-t and allot-t handle dictionary pointers in the target.

\ target dictionary pointer stacks 
: here-t  ( -- taddr ) 
    DP-T @ 
    ; 
 
\ allocate n bytes in the target 
: allot-t  ( n -- ) 
    DP-T +! 
    ; 

Their operation is similar to the words here and allot for FORTH dictionary.

Injecting data into target memory

These words are used to inject bytes, 16-bit values and character strings.

\ compile a byte in the target 
: c,-t  ( char -- ) 
    here-t c!-t 
    1 allot-t 
    ; 
 
\ compile a 16-bit word into the target 
: ,-t  ( w -- ) 
    here-t !-t 
    2 allot-t 
    ; 
 
\ compile a string in the target 
: string,-t  ( addr len -- ) 
    0 
    ?do 
        count c,-t 
    loop 
    drop 
    ; 

The words c,-t and ,-t work as their equivalent c, , of FORTH vocabulary.

The word string,-t compiles a string in space target memory. Examples:

$5678 0 !-t  ok
META-TARGET $20 dump
7FC1E6B1BB90: 78 56 00 00  00 00 00 00 - 00 00 00 00  00 00 00 00  .V..............
7FC1E6B1BBA0: 00 00 00 00  00 00 00 00 - 00 00 00 00  00 00 00 00  ................
 
$2345 ,-t  ok
META-TARGET $20 dump
7FC1E6B1BB90: 45 23 00 00  00 00 00 00 - 00 00 00 00  00 00 00 00  E#..............
7FC1E6B1BBA0: 00 00 00 00  00 00 00 00 - 00 00 00 00  00 00 00 00  ................
 
s" MENU GENERAL" string,-t  ok
META-TARGET $20 dump
7FC1E6B1BB90: 45 23 4D 45  4E 55 20 47 - 45 4E 45 52  41 4C 00 00  E#MENU GENERAL..
7FC1E6B1BBA0: 00 00 00 00  00 00 00 00 - 00 00 00 00  00 00 00 00  ................

At this point, I hope you are beginning to sense the interest of the metacompilation. If you go back to the Xassembleur code, you will have noticed that the words c, and , in the Xassembler vocabulary are execution word defined by DEFER. So we can change their behavior.

If we have compiled the contents of meta.txt and Xassembler.txt, we can do our first test of AVR code metacompilation with gForth:

meta ' c,-t  Xassembler is c, 
meta '  ,-t  Xassembler is  , 
meta 0 DP-T !   \ reset DP-T 
Xassembler 
r16 constant t0 
r17 constant t1 
r24 constant tosl 
r25 constant tosh 
: plus 
    [    t0 Y+ ld,          ] 
    [    t1 Y+ ld,          ] 
    [    tosl t0 add,       ] 
    [    tosh t1 adc,       ] 
    [    ret,               ] 
; 

We can find in the dump of META-TARGET the generated binary code by our very first metacompilation test:

META-TARGET $20 dump
7FC1E6B1BB90: 09 91 19 91  80 0F 91 1F - 08 95 00 00  00 00 00 00  ................
7FC1E6B1BBA0: 00 00 00 00  00 00 00 00 - 00 00 00 00  00 00 00 00  ................

There are still many steps to take before having a metacompiler fully operational. This will be the subject of future articles ...