# Binary width modulation

In a 32-bit system, it is frequent to want to access memory in 3 widths: 32-bit,
16-bit and 8-bit.

Traditionally, Forths have the "c" variant of words for accessing memory in
8-bit. For example, "@" fetches a 32-bit number and "c@" fetches a 8-bit one.

Dusk has a few of these words, for convenience, as well as a "w" variant for
16-bit.

However, Dusk has a wide selection of useful, native memory-related word:
@ ! +! @! @+ !+ @@+ @!+ ,. These all can all be useful in their 16-bit and 8-bit
variants. If we add a "c" and "w" variant to all these words, that's a lot of
noise.

But there's more! "to" semantics are built upon those words, so we'd need to add
a "c" and "w" variant to all "to" words too? That's heavy.

To make things lighter, Dusk has "8b" and "16b" modulator words. A memory word,
when preceded by one of these modulator word, will execute its 8-bit or 16-bit
variant. These words are immediate and work during compilation too.

Better yet: the choice of variant is applied at compile time, which means that
this modulation system has no runtime cost.

Those modulator words can only be used in front of one of the "memory" words
listed above or in front of a "to" word. It *doesn't* work in front of a "naked"
(no "to") value reference.

The logic for applying modulators is that when "8b" or "16b" words (which are
immediate) are called the global MOD variable is set to either EMETA_8B or
EMETA_16B. This activates a special rule in "find": Once a word is found, we
call "findmod" on the result. This word looks in the found word's metadata for
an entry with ID = MOD. If found, that's our modulator word, so that's the word
we return instead, after having reset MOD to 0. If no modulator is found, *we
keep MOD as-is*. We'll look for a modulator in the next find. Example usage:

  $1234 8b @+ . \ prints 8b value at $1234. PS has $1235 on top.

## Binary width and "find"

Using a binary width modulator in front of "find", "'" or any word that finds
another word, will behave as expected: it will yield the address of the
modulated word. This also works with "compiled" finds:

  : foo 8b ['] @ ; \ yields the address of the 8b "@" word

## Binary width and "to"

This logic applies similarly to "to" words, but the implementation is a bit
different because "to" words are compiled with pre-found words. In that case,
"findmod" is applied when the "to" variant is called. Example usage:

  $1234 value foo
  8b to@+ foo . \ prints 8b value at $1234. foo is now $1235.

## Creating modulators

You can create your own binary width modulators:

  : foo ." foo!" ;
  :8b ." bar!" ;
  :16b ." baz!" ;
  foo \ prints foo!
  8b foo \ prints bar!
  16b foo \ prints bar!

For modulators with native code, there is also "code8b" and "code16b".

## Modulator matrixes

Code in "16b" and "8b" variants of a word will often be repetitive. For example,
we can imagine the implementation of the word "@":

code @ W) @, exit,
code16b W) 16b) @, exit,
code8b W) 8b) @, exit,

After a few implementations like that, one might get tired of the repetition.
To alleviate this, there are "MOD)", "MODsz" and "modulablecode".

"MOD) ( halop -- halop )" applies "8b)" or "16b)" (or nothing) depending on the
current value in MOD.

"MODsz ( -- sz )" yields 1, 2 or 4 depending on the value in MOD.

"MOD$" ( -- )" clears MOD.

"[16b]" and "[8b]" are the non-immediate versions of "16b" and "8b", that is,
they compile a MOD setter.

"modulablecode ( "name" -- )" assumes that the last word of the dictionary is a
compiler word, then creates a new code word "name", then calls the compiler,
then calls "exit,". It then repeats the same thing with "code16b" and "code8b",
but this time by calling "[16b]" and "[8b]" first.

This means that we can replace the example above with:

: _, W) MOD) @, MOD$ ;
modulablecode @

Because "MOD)" and "MODsz" don't modify "MOD", we have to be careful to clear it
ourselves.

This system works very well with inlining [doc/usage/imm]. If we wanted to make
our "@" inlinable, we'd go like this:

: _, W) MOD) @, MOD$ ;
modulablecode @ :compiling _, ;

We don't need to apply a matrix to the compiling word because it's the caller of
the compiler that takes care of setting the MOD.

## Binary modulator are not dictionary entries

An important thing to remember with binary width modulators is that they're not
full-fledged dictionary entries. They are metadata entries to the associated
word. This means that you can't apply "w>e" to them. If you do, the yielded
address will be garbage. In the "foo" example above, "' foo w>e" is fine, but
"8b ' foo w>e" is not (but, of course, "8b ' foo execute" is perfectly fine and
is the equivalent of "8b foo").
