Building Applications with CamelForth

2. Dataspaces

The first thing to consider is how the program is to be divided between ROM and RAM. Obviously, the code itself will all need to be in ROM, but some data may need to be in ROM and some in RAM.

The rule here is that initialised, static data goes in ROM, and uninitialised, dynamic data goes in RAM.

If you have data in your program which is initialised to some value and is subsequently changed, you have a problem. In this case, you will need to add words so that you can copy initial values from one data structure to another copy, and then just allow the copy to be changed.

Looking at our example, the data is in fact already nicely arranged into purely initialised, static data and purely uninitialised, dynamic data. How convenient!


Namespace vs Dataspace

When Z88 CamelForth compiles words and data into the dictionary, it splits them into two sections: the first part (containing the name and various internal information) is stored in what we call the namespace; the second part (containing the actual definition or data) is stored in an area called the dataspace. When you first enter CamelForth, both these areas are set to RAM.

When compiling applications for ROM, the namespace will always be set to ROM, but the dataspace will need to change between ROM and RAM, depending on what sort of data is being compiled.

To change the current dataspace, you simply use the words ROM2 or ROM1 and RAM. To change the current namespace, you use the word NS, which makes the namespace the same as the current dataspace.

For example, the phrase ROM2 NS will make both dataspace and namespace point into ROM in segment 2. If you then execute RAM, dataspace points into RAM but namespace is still pointing to ROM2, as required for ROMmed applications.


Defining word requirements

Various defining words behave differently if dataspace and namespace are not both set to RAM as usual. The above discussion is valid for the following defining words, which allow separate dataspace and namespace, and expect the user to know what needs to go where:

The following defining words, however, require that namespace and dataspace are the same region, and will cause an exception -4093 if this is not the case:

POOL is actually a special case, since it contains both static and dynamic data; the static data is allocated in the current region, and the dynamic data is always allocated in the RAM region.

Finally, these defining words allow namespace to be any region, but always allot their data in the RAM region, regardless of the current dataspace:


Regions

Of course, you can't really compile directly into ROM. These words simply act as pointers, telling Forth the region of memory to compile into.

In fact, there are actually four possible regions you can use:

RAM
The region that Forth normally uses, this extends from 2000h (8192d) to BFFFh (49151d). You must specify this region for dynamic data.
ROM2
This is the region normally specified for ROMmed applications, using segment 2. It extends from 8000h (32768d) to BFFFh (49151d).
ROM1
Similarly, for really huge applications, you might also need this region, which extends from 4000h (16384d) to 7FFF (32767d). Note that both ROM2 and ROM1 overlap with RAM, so if you need them, your maximum RAM size is reduced.

To make it easier to see what space is available in each region, CamelForth includes the standard word UNUSED which returns the space left in the current dataspace. For example, ROM2 UNUSED U. will display the space left in the ROM2 region.


Puzzle Of The Pyramid

The above explanation may sound rather complicated, but in practice, it is rather easy to implement. For our example, we need to add a line at the start:

    ROM2 NS

which sets both dataspace and namespace to the ROM2 region. Then, for every item of dynamic data, we will need to insert RAM at the start of the line, and ROM2 at the end again.

In fact, CamelForth helpfully automatically does this for any words defined using VARIABLE (since VARIABLEs are by nature dynamic and uninitialised). It turns out that the only other line that needs changing is the definition for obj-locs, which becomes:

    RAM CREATE obj-locs #objects CHARS ALLOT ROM2

Just to be on the safe side, at the end of the file we'll add a line containing RAM NS, to ensure no unwanted data gets compiled into the ROM2 region.


Next section: The top-level definition

Previous section: Introduction


More on CamelForth

Other ROMs

Back to the Z88 home page