Dictionary (Radix Tree) Source Code Test Program Word Entries


URI:

http://herbert.gandraxa.com/herbert/dic_test_words.asp

Link template:   

<a href="http://herbert.gandraxa.com/herbert/dic_test_words.asp">Dictionary (Radix Tree) Source Code Test Program Word Entries</a>


Link symbols:   

Local LinkOn current page | DocumentOn this site | External PageOn external site | WikipediaWikipedia article | Compressed ArchiveZIP archive | PDF documentPDF | E-MailE-Mail


Article

Organization

DocumentHome » DocumentLinoleum Source Code » DocumentDictionary (Radix Tree) » Source Code Test Program Words

Scope

This is the source code of the Dictionary (Radix Tree) Test Program for Word Entries, testing the Dictionary (Radix Tree) library, implemented in the WikipediaLinoleum programming language.

Author

DocumentHerbert Glarner


Usage

This test program tests long-term functionality of the DocumentDictionary (Radix Tree) library.

Make sure you have the library named dic.txt in the same folder as this test program before assembling the latter.

To make use of this test, you also need a wordlist file, available from Berkeley: see External Sitewordlist. Save this file as "wordlist.txt" in the same directory as this program.


Source Code

(Test application, using the Dictionary Routines "DIC.txt".)

(NOTE: To make use of this test, you also need a wordlist file, available from 
http://aima.cs.berkeley.edu/data/wordlist. Save it in the same directory as this
test program, and give it a proper extension: 'wordlist.txt'.)

(*****************************************************************************)
(Interpreting the test screen:

DICTIONARY

1st bar:    Number of leaves in the DIC's radix tree, 0<------->173528 entries
            Should always be around 50%
2nd bar:    Number of internal nodes in the DIC's radix tree, 0<------->173528
            Should be significantly less than the 1st bar, never above
3rd bar:    Prediction quality, 0%<------->100%
            Being ASCII data, we can predict much better than with random data

DYNAMIC STORAGE ALLOCATION

4th bar:    Used memory units, 0<------->22MU
            Will be close to max. The less, the better. However there is a
            theoretical potential to need 38 MU. Hitting the right edge =
            'Out of Memory' {not of your machine's RAM, only of what we
            allocated for the DIC}.
5th bar:    Fragmentation, i.e. free units within allocation, 0%<------->100%
            Sets the fragmentation in relation to the allocated memory. The
            less the better.

COUNTER

Yellow symbols:     Counting million loop iterations, 0...9 symbols
Green symbols:      Counting ten million loop iterations, 0...9 symbols
Red symbols:        Counting hundred million loop iterations, 0...9 symbols
Magenta symbols:    Counting billion loop iterations, 0...25 symbols

I went to 6.759 billion loop iterations. Beware from breaking records, though:
this test program was not written for speed but for visual feedback ;)

(*****************************************************************************)
(Test Scenario:

Used abbreviations in this scenario description:
MU:  Mega Units = 1,048,576 Units = 4 MB
PRN: Pseudo Random Number, a 32 bit value as delivered by the RNG library
RNG: Random Number Generator
EN:  Entry Number, in this test setup a number 0...173,527 to identify one
     of the 'slots' managing the dictionary's entries by this test program.
     Note, that the concept of a 'Entry Number' does not exist in the DIC
     library itself: it's just introduced in this test program to facilitate
     testing.

I. Setting up a test environment:

1. Read in a wordlist containing 175,528 different English words, hold it in
   RAM as long as this program runs.
2. Create management vector of 1,755,280 units for a maximum of 175,528 entries
   at 10 units each, each of these units being a 'slot' for a dedicated dictionary
   entry holdig the entry's key length in bits and the bistream forming the key.
3. Init DIC with 88 Units * 175,528 entries {see discussion [1] below for the
   reason of this value} to hold an average of 87,764 words.
4. Init the RNG Library.
5. Setting up a visualization screen.

II. Permanent Loop, to be left after hitting any key:

1. Get a PRN, let's call it the 'Control PRN'.
2. We need the PRN to be in the range of 0...173,527 to randomly select one of
   the 173,528 slots and calculate the slot's address.
3. We test the first unit of slot 0...173,527 for a set MSB {80000000h}.
   A. If the slot's MSB is 0 = there is no such entry yet/anymore in the DIC:
      a. The first 8 bits of the Control PRN provide a random user data size
         0...255, plus 1 unit to obtain a valid user data size of 1...256 units
      b. In the first unit of the slot set the MSB, which identifies the slot
         as being in use, i.e. indicates an existing entry in the dictionary.
      c. Use 'Dic Add Entry' with above specifications, i.e. random key number
         0...173,527 with its associated key length in bits, and a random
         userdata segment size.
         --> All errors = report error and stop.
   B. If the slots MSB is 1 = such an entry already exists in the dictionary:
      a. The rest of the first unit in that slot is the key length in bits
      b. The following units are the bitstream of the key: this can consume up
         to 9 units.
      c. Use 'Dic Remove' on that key with the given keylength.
         --> All errors = report error and stop.
      d. Clear the MSB of the slot's first unit = ready to accept new entry.
4. All now and then, i.e. all 4k activities, visualize something to have
   something to stare at and to confirm that the test program still 'does
   something': visualize a counter. Show the number of DIC entries: leaves and
   internal nodes separately. Also include some DSA statistics to see how it
   works with the DIC library.
5. Loop until arbitrary key is hit.

III. Output some statistics in the registers

[1] How much space shall we give the DIC library to manage all this randomness?
- There are max. 173,528 entries, average will be half = 86,764 entries all
  the time.
- Each entry has a maximum user data area of 256 units, in average
  1+[0+255]/2=128.5 units.
- Each entry has a key length of max. 9 units. Calculation of average is more
  difficult. The testfile is 1,923,517 bytes long. Each line is separated by a
  CR/LF sequence. There are 173,528 such separators. 1,923,517 - 2*173,528 =
  1,576,461 letters at 8 bit each. The average word thus has 1,576,461/173,528=
  9.1 letters at 8 bits each. Since 4 ASCII letters can be stored in each unit,
  the average word can easily be stored in 2 units.
- But: there are also internal nodes holding prefixes common to their children.
  1-child-only nodes are frequent with ASCII keys, e.g. 'magical' is a child of
  'magic'. This will cause a certain unbalance, so we will have more than 50%
  internal nodes for 100% leaves. However, we will have many common prefixes,
  because ASCII characters follow a certain bit pattern. Thus we will have less
  than 100% internal nodes for 100% leaves. If I am forced to give an educated
  guess before having it programmed, I would say 75%. So we will have a total
  maximum number of nodes of approx. 1.75 * 173,528 = 303,674 and an average
  number of 1.75 * 86,764 = 151,837 nodes.
  UPDATE: Watching the bars after programming the whole thing we can see the
  internal nodes fluctuate around at approx. 77-78% of 100% leaves.
- Each node has 5 units management information, thus in average 303,674 nodes
  x 5 units DIC management data = 1,518,370 units.
- Each node requires 4 units DSA management data = 1,214,696 units in average.
- Each individual chunk length of 1...9 units key bitstream and 1...256 units
  requires an AVL node managed by the DSL library, and due to the large average
  entry volume in average there will be an AVL node for all those 256 lengths,
  thus 256 AVL nodes x 6 units = 1,536 units. No issue to really bother about.
- All in all we have the following storage requirement:
  maximum 256.0*173,528 + [1.10+5+4]*303,674 + 1,536 = 47,491,812 units
  average 128.5* 86,764 + [1.10+5+4]*151,837 + 1,536 = 12,684,264 units
  In relation to the max number of entries:
  maximum 47,491,812 / 173,528 = 273.7 units per entry
  average 12,684,264 / 173,528 =  73.1 units per entry
- Because of the many more different chunk sizes than in the random test numbers
  scenario, we will doubtlessly have more fragmentation. Also, the real ratio
  of internal nodes is not really secure, the 75% are an educated guess only.
  All in all, it is likely that we won't be able to get away with a mere 10%.
  Somewhat cautiously we go with a 20% reserve, i.e. 73.1*1.2=88 units per entry.
  UPDATE: Watching the bars after programming the whole thing we can see the
  internal nodes fluctuate around at approx. 77-78% of 100% leaves. However,
  the 20% reserve still seems to hold, at least for the first 567 million loop
  iterations. Although it's really close to the upper limit.
)

(*****************************************************************************)

"libraries"

    (=========================================================================)
    (Dictionary; the library which is tested with this test program.)
    (-------------------------------------------------------------------------)
        DIC;
    (=========================================================================)

    (=========================================================================)
    (RNG Random Number Generator)
    (-------------------------------------------------------------------------)
    (Used as explained in this file's header under 'Test Scenario'. Available
    at http://herbert.wikispaces.com/RNG)
    (-------------------------------------------------------------------------)
        RNG;
    (=========================================================================)

    (=========================================================================)
    (Bitstream Generator)
    (-------------------------------------------------------------------------)
    (Used to extract words from the wordlist. Since the wordlist is an ASCII
    file and we read it into workspace units, we also need to convert from
    Little Endian. This all can be done by the Bitstream Generator. Available
    at http://herbert.wikispaces.com/BST)
    (-------------------------------------------------------------------------)
        BST;
    (=========================================================================)

(*****************************************************************************)
"directors"
        program name = { DIC Test };
        unit = 32;

    (=========================================================================)
    (Test screen reflecting what's allocated and what's free)
    (-------------------------------------------------------------------------)
        display width = DIC TEST SCREEN WIDTH;
        display height = DIC TEST SCREEN HEIGHT;
    (=========================================================================)

(*****************************************************************************)
"constants"                             (Convention: "DIC ...", UPPER CASE)

    (=========================================================================)
    (Wordlist)
    (-------------------------------------------------------------------------)
    (The testfile is a list of English plain ASCII words. It can be downloaded
    from http://aima.cs.berkeley.edu/data/wordlist. It is 1,923,517 bytes large
    including CR/LF characters at the end of each word. It contains 173,528
    different words.)
    (-------------------------------------------------------------------------)
    (Four bytes each occupy a unit. Of the last unit only 1 byte is used: it is
    the 0Ah byte of the newline sequence 0D0Ah after the last word. We need
    some space to read in the file into one go, including that last byte. The
    following 3 bytes are 00h each.)
        DIC TEST FILENAME SIZE = 1 923 517 plus 3 div 4;    (Space in units)
    (-------------------------------------------------------------------------)
    (Longest word size in units. Without really checking, I assume that the
    longest word within the test file does not exceed 9 units = 36 ASCII
    characters = 288 bits.)
    (-------------------------------------------------------------------------)
        DIC TEST MAX WORD SIZE = 9;
    (=========================================================================)

    (=========================================================================)
    (Define the size of the testing screen here. The topmost 5*16 pixels are
    used to draw 5 bars measuring different DIC and DSA qualities. The next 4
    'rows' are used to draw symbols acting as loop counters.)
    (-------------------------------------------------------------------------)
        DIC TEST SCREEN WIDTH = 512;
        DIC TEST SCREEN HEIGHT = 9 mtp 16;      (9 'lines' at 16 pixels)
    (=========================================================================)

    (=========================================================================)
    (Requested memory area for our Dictionary)
    (-------------------------------------------------------------------------)
        DIC TEST MAX ENTRIES = 173 528;                     (All words)
        DIC TEST RAM SIZE = 88 mtp DIC TEST MAX ENTRIES;    (see [1] in header)
    (-------------------------------------------------------------------------)
    (How many bytes can be represented per pixel)
        DIC TEST BYTES PER PIXEL = DIC TEST RAM SIZE div
                                   DIC TEST SCREEN WIDTH;
    (=========================================================================)

    (=========================================================================)
    (Visualization constants)
    (-------------------------------------------------------------------------)
    (See comments in the visualization subroutine 'Dic Test Visualize'.)
        DIC TEST FILL BAR HEIGHT = 16;
    (-------------------------------------------------------------------------)
    (How many entries can be represented per pixel)
        DIC TEST ENTRIES PER PIXEL = DIC TEST MAX ENTRIES div
                                     DIC TEST SCREEN WIDTH;
    (=========================================================================)

(*****************************************************************************)
"variables"                             (Convention: "dic ...", lower case)

    (=========================================================================)
    (Name of the file we want to process)
    (-------------------------------------------------------------------------)
        dic test filename = { wordlist.txt };
    (=========================================================================)

    (=========================================================================)
    (Visualization)
    (-------------------------------------------------------------------------)
    (Some counters merely to draw a non-text counter)
        dic test loop counter = 0;      (Counts the iterations below millions)
        dic test loop millions = 0;     (Counts whole millions of iterations)
        dic test loop tenmillions = 0;  (etc.)
        dic test loop hundredmillions = 0;
        dic test loop billions = 0;
        dic test symbols color = 0;     (Each magnitude in own color)
        dic test visualizations = 0;    (Calls to the visualization routine)
        dic test last millions = 0;     (Spares superfluous symbols drawing)
    (=========================================================================)

    (=========================================================================)
    (Just out of curiosity we count some values. Upon termination they will be
    displayed in registers C, D and E, unless there was an error.)
    (-------------------------------------------------------------------------)
        dic test added = 0;             (Successfull 'Dic Add Entry' calls)
        dic test removed = 0;           (Successfull 'Dic Add Remove' calls)
        dic test existing keys = 0;     ('Dic Add Entry' rejects double keys)
    (=========================================================================)

(*****************************************************************************)
"workspace"                             (Convention: "dic ...", lower case)

    (=========================================================================)
    (Display area)
    (-------------------------------------------------------------------------)
        dic test window = DIC TEST SCREEN WIDTH mtp DIC TEST SCREEN HEIGHT;
    (=========================================================================)

    (=========================================================================)
    (Space to read in the whole wordlist)
    (-------------------------------------------------------------------------)
        dic test file = DIC TEST FILENAME SIZE;
    (=========================================================================)

    (=========================================================================)
    (Random Number initialization, needs 4 units)
    (-------------------------------------------------------------------------)
        dic test rng init key = 4;
    (=========================================================================)

    (=========================================================================)
    (This is a pseudo 'object' vector. In reality, this contains the data of
    your 'object', be that a player's infos in a game, a database record,
    whatever. In this test setup, objects have a random length of 1...256 units;
    in reality they may have just any length, as long as the provided RAM is
    large enough.)
    (-------------------------------------------------------------------------)
        dic test object = 256;
    (=========================================================================)

    (=========================================================================)
    (Into the following vector the actual key is stored when dealing with
    the dictionary.)
    (-------------------------------------------------------------------------)
        dic test key = DIC TEST MAX WORD SIZE;
    (=========================================================================)

    (=========================================================================)
    (Some space for creating a bitstream for individual words.)
    (-------------------------------------------------------------------------)
        dic test bitstream = DIC TEST MAX WORD SIZE;
    (=========================================================================)

    (=========================================================================)
    (This is the management vector which contains up 1 Mega-Entries with
    1+DIC TEST MAX WORD SIZE units each: for each entry, the first unit stores
    the key length encoded as a bitstream in the next max. DIC TEST MAX WORD
    SIZE units. Such a storage is needed to be able to identify an entry by its
    key in order to access an entry. In a real application, such overhead is
    not needed, of course, as the DIC itself holds all information.)
    (-------------------------------------------------------------------------)
        dic test node mgmt = DIC TEST MAX WORD SIZE plus 1
                             mtp DIC TEST MAX ENTRIES;     (10 * 173,528 units)
    (=========================================================================)

(*****************************************************************************)
"programme"                             (Convention: "Dic ...", Mixed case)

    (*************************************************************************)
    (I. SETTING UP THE TEST ENVIRONMENT)
    (*************************************************************************)

    (=========================================================================)
    (Screen init)
    (-------------------------------------------------------------------------)
        [Display Origin] = dic test window;     (Defined in the workspace area)
    (=========================================================================)

    (=========================================================================)
    (Providing some RAM for the Dictionary.)
    (-------------------------------------------------------------------------)
        D = DIC TEST RAM SIZE;          (Number of units)
        => Dic Create;
        ? ok -> Dic Test Dic Created;
        A = 1;                          (Testing phase)
        B = [dic error];                (What error occured)
        -> Dic Test Stop;
    "Dic Test Dic Created"
    (=========================================================================)

    (=========================================================================)
    (Initializing the Random Number Generator.)
    (-------------------------------------------------------------------------)
        [dic test rng init key plus 0] = 123h;
        [dic test rng init key plus 1] = 234h;
        [dic test rng init key plus 2] = 345h;
        [dic test rng init key plus 3] = 456h;

        E = dic test rng init key;      (Address of init key)
        D = 4;                          (Length of init key)
        => Rng Init;
    (Now random Numbers can be produced by simply calling '=> Rng Long'. Each
    call will provide a differnt 32 bit number into E.)
    (=========================================================================)

    (=========================================================================)
    (Reading in the testfile. It contains 8 bit ASCII characters. There are
    1,923,517 bytes in the file.)
    (-------------------------------------------------------------------------)
    (Check if file exists)
        [File Name] = dic test filename;
        [File Command] = TEST;
        isocall;
        ? ok -> Dic Test File Found;
        A = 2;                          (Testing phase)
        [dic error] = 100000;           (Pseudo Error Code)
        -> Dic Test Stop;
    "Dic Test File Found"
    (-------------------------------------------------------------------------)
    (Check if we may read the file)
        ? [File Status] + PERMIT TO READ -> Dic Test File Readable;
        A = 2;                          (Testing phase)
        [dic error] = 100001;           (Pseudo Error Code)
        -> Dic Test Stop;
    "Dic Test File Readable"
    (-------------------------------------------------------------------------)
    (The testfile is read into RAM.)
        [Block Pointer] = dic test file;    (Buffer holding the whole file)
        [File Command] = READ;
        [File Position] = ZERO;
        [Block Size] = DIC TEST FILENAME SIZE mtp BYTESPERUNIT;
        isocall;
        ? ok -> Dic Test File Read;
        A = 2;                          (Testing phase)
        [dic error] = 100002;           (Pseudo Error Code)
        -> Dic Test Stop;
    "Dic Test File Read"
    (=========================================================================)

    (=========================================================================)
    (On Intels, the just read in file is in Little Endian. We need to convert
    the file into Big Endian, such that the bytes can be read from 'left to
    right'. Also we want individual words in their own slot of the reserved
    workspace 'at dic test node mgmt'. There are DIC TEST MAX ENTRIES such
    slots, numbered from 0 to DIC TEST MAX ENTRIES-1. Each slot has a size of
    1+DIC TEST MAX WORD SIZE units. The first unit holds the word's size in
    bits, which always is a multiple of 8, since we process bytes. The remaining
    DIC TEST MAX WORD SIZE units hold the bitstream of this word, i.e. the
    left-aligned bytes eradable from left to right.)
    (-------------------------------------------------------------------------)
    (Initialising a bitstream area. The resulting bitstream has 8 bits per
    character, because most applications won't fiddle around with the bits.
    However, as the input file I used contains plain vanilla ASCII characters,
    a 7-bit bitstream could be used: if you want to test this out, set LSW to 7.)
        A = 8;                      (PSW: Characters are in 8 bit units)
        B = 8;                      (LSW: using 8 bit bitstreams)
        C = 13;                     (End-of-symbols symbol is 'CR' = 0Dh = 13)
        => Bst Init;
        ? ok -> Dic Test Bst Created;
        A = 3;                      (Testing phase)
        [dic error] = 100000;       (Pseudo Error Code)
        -> Dic Test Stop;
    "Dic Test Bst Created"
    (-------------------------------------------------------------------------)
    (We need a slot counter to process DIC TEST MAX ENTRIES words.)
        B = DIC TEST MAX ENTRIES;
    (-------------------------------------------------------------------------)
    (Make a bitstream from the first word.)
        E = dic test file;              (Address to unit with start of 1st word)
        D = dic test node mgmt; D + 1;  (Address of outstream is slot+1)
        => Bst Stream;
        [D minus 1] = [bst bits];       (Number of bits into slot+0)
        B - 1;                          (First word was processed)

    (Now loop through the whole file, filling slot by slot)
    (-------------------------------------------------------------------------)
    (Make a bitstream from the next word and store into the slot.)

    "Dic Test Stream Word"
        C = 1;                              (Symbols to skip: We don't want the LF)
        D + DIC TEST MAX WORD SIZE plus 1;  (Address of output bitstream=next slot)
        => Bst Resume;
        [D minus 1] = [bst bits];           (Number of bits into slot+0)
    (-------------------------------------------------------------------------)
    (Looping until all words processed.)
        B ^ Dic Test Stream Word;
    (=========================================================================)


    (=========================================================================)
    (Now we have a foundation to work with the dictionary: All slots at address
    'dic test node mgmt' have been filled. The first unit of each slot has the
    word's size in bits, the following max. DIC TEST MAX WORD SIZE units have
    the left-aligned bitstream of this word. For example does the first word
    'aa' at address 'dic test node mgmt' look so:

                +0   +1          +2          +3          +4    ...
                +----+-----------+-----------+-----------+------/ /-----+
    Slot 0      | 16 | 61610000h | empty     | empty     |     / /      |
                +----+-----------+-----------+-----------+----/ /-------+
                6161h is the hex representation of the characters 'aa'.
                They need 16 bits = 2 characters * 8 bits each.

    And the last word 'zyzzyvas' {is that really a word?} looks so:

                +0   +1          +2          +3          +4    ...
                +----+-----------+-----------+-----------+------/ /-----+
    Slot 173527 | 64 | 7A797A7Ah | 79766173h | empty     |     / /      |
                +----+-----------+-----------+-----------+----/ /-------+
                7A797A7A79766173h is the hex representation of the characters
                'zyzzyvas'. They need 64 bits = 8 characters * 8 bits each.
    )
    (=========================================================================)




    (*************************************************************************)
    (II. THE INFINITE LOOP. Break with any key.)
    (*************************************************************************)
    "Dic Test Infinite Loop"

    (=========================================================================)
    (Check if the user aborts by hitting any key.)
    (-------------------------------------------------------------------------)
        [Console Command] = GETCONSOLEINPUT;
        isocall;
        ? ok -> Dic Test Exit;
    (=========================================================================)

    (=========================================================================)
    (Visualize something to confirm that 'it still runs'.)
    (-------------------------------------------------------------------------)
    (Visualization is done only once in about 4k loops, otherwise most of the
    time would be spent on drawing rather than on actually testing the lib.
    For this reason, we implement a loop counter. Anding the last 12 bits
    gives us a range of 0...4095. Only if we are at 0 we draw. We do this in
    a subroutine to have it out of the way.)
        [dic test loop counter] + 1;    (One iteration more)

    (For visualization reasons we count whole millions separately. When we
    reach a million, the normal counter is reset to 0. Each magnitude beyond
    millions is counted separately to facilitate visualization with symbols.
    Beyond approx. 25 billion there is no more space for the billion symbols:
    that's the point where we stop with the test to prevent a crash from
    drawing symbols beyond the screen area. However, feel free to implement
    also a 10 billion counter etc. if you really need more of this ;)
        ? [dic test loop counter] < 1 000 000 -> Dic Test No Million Update;
        [dic test loop millions] + 1;   (One million loops more)
        [dic test loop counter] = 0;    (Reset basic counter)

        ? [dic test loop millions] < 10 -> Dic Test No Million Update;
        [dic test loop tenmillions] + 1;
        [dic test loop millions] = 0;

        ? [dic test loop tenmillions] < 10 -> Dic Test No Million Update;
        [dic test loop hundredmillions] + 1;
        [dic test loop tenmillions] = 0;

        ? [dic test loop hundredmillions] < 10 -> Dic Test No Million Update;
        [dic test loop billions] + 1;
        [dic test loop hundredmillions] = 0;

    (Ok, ok, we stop here and enforce terminattion after 25.999 billions ;)
        ? [dic test loop billions] = 26 -> Dic Test Exit;
    "Dic Test No Million Update"

        A = [dic test loop counter];
        A & 0000 0FFFh;                         (last 12 bits  0...4095)
        ? A != 0 -> Dic Test No Visualization;  (Only if 0 we visualize)
        => Dic Test Visualize;
    "Dic Test No Visualization"
    (=========================================================================)

    (=========================================================================)
    (Determine on which of the 173,528 entries we want to operate this time.)
    (-------------------------------------------------------------------------)
    (Get a Pseudo Random Number PRN)
        => Rng Long;                    (32 bit PRN available in E)
        A = E;                          (Save the PRN)


    (The PRN provides us with 3 different values in 2 bitfields. The bitfields
    are: bits 31:24 = a 8 bits biased userdata size in units; 23:0 = a 24 bits
    value which needs to be scaled such, that a value 0...173,527 results.
    Because the latter is no power of 2, we can't simply shift out values and
    need to convert to floating point first in order to scale.)
        E & 00FF FFFFh;                 (Bits 23:0 = 0...16,777,215)
        E ,= E;                         (Same value in IEEE754)
        E // 96.68359967f;              (0...173527.00000066)
        E =, E;                         (0...173527)
    (The first random entry will be 109953. This is the 109954th word, and a
    lookup in the wordlist's file at line 109954 shows 'pedicuring' for it.)

    (E has the slot number 0...173527. Each slot is DIC TEST MAX WORD SIZE+1
    units in size. Get the offset by multiplying with this value. Then get
    the absolute address by adding the workarea address.)
        E * DIC TEST MAX WORD SIZE plus 1;
        E + dic test node mgmt;         (Address of the slot)
    (=========================================================================)


    (=========================================================================)
    (Either add a new entry, or remove an existing entry)
    (-------------------------------------------------------------------------)
    (If the first unit starting at [E plus 0] has its MSB clear, then this entry
    currently is empty. In this case we can provide a new entry into it.)
        ? [E plus 0] - 8000 0000h -> Dic Test Add Entry;

    (The MSB at [E] is set, thus the other bits must be the length of an
    already existing entry. The length is measured in bits.)
        (-> Dic Test Remove Entry;)
    (=========================================================================)

    (=========================================================================)
    (Removing an existing entry from the dictionary)
    (-------------------------------------------------------------------------)
    (In [E plus 0] is the length of the bistream acting as key which needs to
    be removed. in [E plus 1] is the bitstream itself, which is the key of the
    existing node. That's all we need to know to remove that entry from the
    dictionary, including its 'data object'.)
    (-------------------------------------------------------------------------)
    ("Dic Test Remove Entry")

    (Copy the word to the key buffer.)
        B = [E plus 0];                 (Length of key in bits)
        B & 7FFF FFFFh;                 (Without the flag in the MSB)
        B -->;                          (Need the number of bits back)
        B + 31;                         (Rounding up to needed units)
        B > 5;                          (Word length in units)
        A = E; A + 1;                   (Address of start of key)
        C = dic test key;               (Address of key buffer)
    "Dic Test Remove Entry Copy Key"
        [C] = [A];                      (Copy key to key buffer)
        A + 1; C + 1;
        B ^ Dic Test Remove Entry Copy Key;
        <-- B;                          (Key's number of bits)
    (-------------------------------------------------------------------------)
    (Let's remove the node.)
        A = dic test key;               (Address of key buffer)
        (B = B;)                        (Length of key in bits)
        => Dic Remove Entry;
        ? ok -> Dic Test Remove Entry Removed;
    (That really should not happen...)
        A = 5;                          (Testing phase)
        B = [dic error];                (What error occured)
        -> Dic Test Stop;               (Break the loop and stop the program)
     "Dic Test Remove Entry Removed"
    (-------------------------------------------------------------------------)
    (By clearing the removed entry's MSB in the key length unit in this test's
    management area we declare it to be a free entry: such it can be used to
    be added again and exist until also removed, etc.)
        [E plus 0] & 7FFF FFFFh;        (Can be re-used now)

    (Let's loop until either the user feels to break by hitting any key or an
    error occurs. But before that, we count the successful operation.)
        [dic test removed] + 1;         (Count success)
        -> Dic Test Infinite Loop;
    (=========================================================================)

    (=========================================================================)
    (Adding an entry to the dictionary)
    (-------------------------------------------------------------------------)
    "Dic Test Add Entry"

    (The management units at E indicate that the node is free, because [E]'s
    MSB is clear. The PRN was saved into A. Its 8 MSBs give us the biased
    user data length in units. To this value we add 1, because we must provide
    at least 1 unit for the payload. This will give us an average user data
    length of 128.5 units.)
        A > 24;                         (Biased user data length 0...255 units)
        A + 17;                         (User data length 1...256 units)

    (The key starting at address E+1 is copied into the workarea 'dic test key'.
    It is [E+0] /bits/ long.)
        C = E;                          (Address of slot)
        C + 1;                          (Start of key in slot)
        D = dic test key;               (Key buffer)
        B = [E plus 0];                 (Key length in bits)
        B + 31;                         (Rounding up to calculate units)
        B > 5;                          (1...DIC TEST MAX WORD SIZE)
    "Dic Test Copy Key Unit"
        [D] = [C];
        C + 1; D + 1;
        B ^ Dic Test Copy Key Unit;
    (-------------------------------------------------------------------------)
    (Now we have everything what's needed to create a dictionary entry:
    several units of the key in the vecor 'dic test key', its length in bits
    in [E], the length of the object in units is in A, and the object data is
    at 'dic test object'. Note, that we don't care for a content in the object
    vector. In a real application, it is here where your object structure goes,
    whatever it may contain. These 4 arguments are passed in registers now.)
        C = dic test object;            (Address of the 1st unit of the data)
        D = A;                          (Length of data in units)
        A = dic test key;               (Address of the 1st unit of the key)
        B = [E plus 0];                 (Length of key in bits)
        => Dic Add Entry;               (Store into the dictionary)
        ? ok -> Dic Test Add Entry Added;
    (Oops an error. Note, that in this test scenario non-unique keys are not
    possible and will be counted as a real error. This is different from the
    test scenario 'DIC Test Random Entries.txt' which works with 1 Mega random
    keys.)
        A = 6;                          (Testing phase)
        B = [dic error];                (What error occured)
        -> Dic Test Stop;               (Break the loop and stop the program)
    "Dic Test Add Entry Added"
    (-------------------------------------------------------------------------)
    (Everything fine? Great, we count the successful operation.)
        [dic test added] + 1;           (Count success)

    (The slot's first unit will be flagged as 'in use' now by setting the MSB
    in [E plus 0]. When we get the same random number again the next time,
    then this flag is the signal to jump to 'Dic Remove Entry' and such to
    remove the entry instead of adding it again.)
        [E plus 0] | 8000 0000h;        (The entry was added)

    (And now let's loop happily along until the user feels to break by hitting
    any key.)
        -> Dic Test Infinite Loop;
    (=========================================================================)



    (*************************************************************************)
    (III. TERMINATING)
    (*************************************************************************)

    (=========================================================================)
    (Address we jump to if we exit on user request = hit any key.)
    (-------------------------------------------------------------------------)
    "Dic Test Exit"

    (Destroying the Dictionary. No input parameters required. No result
    provided. No errors possible. Still needs to be called to return the
    allocated memory to the OS.)
        => Dic Destroy;
    (-------------------------------------------------------------------------)
    (Output Some statistical data.)
        A = 99;                         (A = 99 = all ok, otherwise failure)

    (Branch prediction quality in percent)
        B = [dic number correct pred];
        C = B;
        B * 100;
        C + [dic number incorrect pred];
        B / C;

    (All the following counters are subject to overflow beyond FFFFFFFFh,
    although an overflow does not cause any harm beyond making interpretation
    of the final output values more difficult. However, overflowing means to
    run the test for approx. 8.6 billion times, i.e. 2*FFFFFFFFh, which would
    take quite a while: this test program is not designed for speed but for
    visualization of background quality.)
        C = [dic test added];
        D = [dic test removed];
        E = [dic test existing keys];

    (Both the DIC and DSA libraries provide statistical values which you might
    want to retrieve and display instead of above statics. You can do this here.)

        show registers;
    (=========================================================================)

    (=========================================================================)
    (Address we jump to if there is an error. In A is the testing phase, in
    B is the error number.)
    (-------------------------------------------------------------------------)
    "Dic Test Stop"
        show registers;
    (=========================================================================)

(*****************************************************************************)
(This is the visualization routine. It is implemented as a routine to keep it
out of the way of above program's main stream.)

"Dic Test Visualize"

    (=========================================================================)
    (Called each 4k loop iterations to visually confirm to the user that the
    program still runs.)
    (-------------------------------------------------------------------------)
    (Some evaluations are done less frequently because they cost much of time.
    For those this counter exists: they will be executed as a fraction of
    calls to this routine.)
        [dic test visualizations] + 1;  (Calls to the visualization routine)
    (-------------------------------------------------------------------------)
    (The topmost DIC TEST FILL BAR HEIGHT pixels of the screen are used to draw
    a colored 'fill bar' of current dictionary entries. This height originally
    is 16 pixels. The bar grows from the left edge = 0 entries to the right
    edge = DIC TEST MAX ENTRIES entries, which in the original test file is
    1024*1024. Since we have a limited screen width only, we need to divide the
    current number of entries with the number of entries fitting in a pixel,
    i.e. DIC TEST MAX ENTRIES/DIC TEST SCREEN WIDTH to get the number of
    horizontal pixels which we want to color. The expression '1,048,576 /
    DIC TEST SCREEN WIDTH' is defined as a constant, its name is 'DIC TEST
    ENTRIES PER PIXEL'. The number of actual entries could be calculated by
    using the two counters [dic test added] and [dic test removed]: the
    difference is the current number of existing entries. However, we would
    need to care for overflow handling in really long termed tests. There's an
    easier way though to obtain the same number without the overflow issue:
    The DIC library maintains a variable [dic number of leaves] which is
    identical with [dic test added]-[dic test removed]. Due to this test's
    design the existing entries very soon will grow to DIC TEST MAX ENTRIES/2
    and then fluctuate around that value.)
        A = [dic number of leaves];     (Number of currently existing entries)
        A / DIC TEST ENTRIES PER PIXEL; (Required horizontal pixels)
        C = A;                          (Save this number, need often)

        E = dic test window;            (Upper left edge of fill bar)
    (Loop over the whole bar's height)
        B = DIC TEST FILL BAR HEIGHT;
    "Dic Test Visualize Leaves Bar Line"

    (Draw A green pixels to symbolize the fill bar)
    "Dic Test Visualize Leaves Bar Exist"
        [E] = 00 008000h;               (Draw pixel)
        E + 1;                          (Next address to draw to)
        A ^ Dic Test Visualize Leaves Bar Exist;

    (The rest of the line consists of DIC TEST SCREEN WIDTH-C black pixels:
    such we cancel out a formerly longer bar.)
        A = DIC TEST SCREEN WIDTH;
        A - C;
    "Dic Test Visualize Leaves Bar Empty"
        [E] = 00 000000h;               (Draw pixel)
        E + 1;                          (Next address to draw to)
        A ^ Dic Test Visualize Leaves Bar Empty;

    (Restore A for the next line)
        A = C;

    (Next line of the fill bar)
        B ^ Dic Test Visualize Leaves Bar Line;
    (-------------------------------------------------------------------------)
    (There's another value which is of interest: the number of internal nodes
    which the DIC library has to maintain in order to keep its radix tree.
    Whereas [dic number of leaves] keeps a counter to 'real' entries only, the
    counter [dic number of nodes] counts /all/ nodes of the tree, whether
    internal only or a real leaf. Thus a subtraction tells us the internal nodes
    only, which we visualize now exactly as above, only that we draw them a bar
    lower and in red rather than in green. Typically, this bar is just somewhat
    smaller than the first bar with the number of leaves. This is because the
    radix tree will be pretty well balanced due to the random bitstreams. The
    bar /never/ may exceed the width of the leaves bar though: this would mean
    that we had more internal nodes than leaves, which conceptionally is not
    possible in radix trees: if it nevertheless happens, then there is a
    programming flaw, missing the chance to coalesce stacked internal nodes.
    Should the bar shrink to a far lesser size than the leaves bar, this would
    indicate that most nodes are real leaves. This happens frequently with e.g.
    ASCII text files, where the left branch of nodes is favoured over the right
    branch, because lowercase ASCII characters start out with a 0 bit. However,
    in this test setup it is unlikely to happen. If it still does, it must be
    interpreted as a bad quality random number generation, which is extremely
    unlikely to be the case.)
        A = [dic number of nodes];      (All nodes INCLUDING leaves)
        A - [dic number of leaves];     (Internal nodes only)
        A / DIC TEST ENTRIES PER PIXEL; (Required horizontal pixels)
        C = A;                          (Save this number, need often)
    (E is already the position to draw the next pixel to, no need to calculate
    the value.)

    (Loop over the whole bar's height)
        B = DIC TEST FILL BAR HEIGHT;   (All bars have the same height)
    "Dic Test Visualize Nodes Bar Line"

    (Draw A red pixels to symbolize the internal nodes bar)
    "Dic Test Visualize Nodes Bar Exist"
        [E] = 00 FF0000h;               (Draw pixel)
        E + 1;                          (Next address to draw to)
        A ^ Dic Test Visualize Nodes Bar Exist;

    (The rest of the line consists of DIC TEST SCREEN WIDTH-C black pixels:
    such we cancel out a formerly longer bar.)
        A = DIC TEST SCREEN WIDTH;
        A - C;
    "Dic Test Visualize Nodes Bar Empty"
        [E] = 00 000000h;               (Draw pixel)
        E + 1;                          (Next address to draw to)
        A ^ Dic Test Visualize Nodes Bar Empty;

    (Restore A for the next line)
        A = C;

    (Next line of the fill bar)
        B ^ Dic Test Visualize Nodes Bar Line;
    (-------------------------------------------------------------------------)
    (A third bar measures the quality of branch prediction. With random data,
    as used in this test, this value will fluctuate around 50%.)

(To avoid overflows we would need to reset the counters when they exceed
32 bit, i.e. as soon as the total is smaller than the correct predictions.
However, this would cause sudden rejumps to 50%. It is better to divide both
counters by the same constant in order to keep the relation.)
? [dic number correct pred] + FFC0 0000h -> Dic Test Visualize Large Values;
? [dic number incorrect pred] - FFC0 0000h -> Dic Test Visualize Small Values;
"Dic Test Visualize Large Values"   (Values which cause overflow when mtp 512)
[dic number correct pred] > 12;
[dic number incorrect pred] > 12;
"Dic Test Visualize Small Values"

    (The variable [dic number correct pred] is set in relation to the sum of
    the two variables [dic number correct pred] and [dic number incorrect pred].)
        C = [dic number correct pred];
        A = C;                              (Correct predictions only)
        C + [dic number incorrect pred];    (All predictions)
        ? C > 0 -> Dic Test Visualize Values Valid;
    (Better omit an invalid division, but adjust for intended bar height)
        E + DIC TEST FILL BAR HEIGHT mtp DIC TEST SCREEN WIDTH;
        -> Dic Test Visualize Memory Quality;
    "Dic Test Visualize Values Valid"
        A * DIC TEST SCREEN WIDTH;          (100% is whole screen width)
        A / C;                              (Effective percentage * screen width)
        C = A;                          (Save this number, need often)
    (E is already the position to draw the next pixel to, no need to calculate
    the value.)

    (Loop over the whole bar's height)
        B = DIC TEST FILL BAR HEIGHT;   (All bars have the same height)
    "Dic Test Visualize Predictor Bar Line"

    (Draw A yellow pixels to symbolize the prediction quality bar)
    "Dic Test Visualize Predictor Bar Exist"
        [E] = 00 FFFF00h;               (Draw pixel)
        E + 1;                          (Next address to draw to)
        A ^ Dic Test Visualize Predictor Bar Exist;
    (The rest of the line consists of DIC TEST SCREEN WIDTH-C black pixels:
    such we cancel out a formerly longer bar.)
        A = DIC TEST SCREEN WIDTH;
        A - C;
    "Dic Test Visualize Predictor Bar Empty"
        [E] = 00 000000h;               (Draw pixel)
        E + 1;                          (Next address to draw to)
        A ^ Dic Test Visualize Predictor Bar Empty;
    (Restore A for the next line)
        A = C;

    (Next line of the predictor bar)
        B ^ Dic Test Visualize Predictor Bar Line;
    (-------------------------------------------------------------------------)
    "Dic Test Visualize Memory Quality"

    (The following two bars require the call to an expensive function: it is
    called only every 8th time we call this visualization routine, and since
    it is called every 4k loops only, that means that an update occurs every
    32k loops only. If you want the bars progress more smootly, reduce to
    11b = every 4th time, or 1b = every 2nd time, or comment out the following
    instruction altogether to have it done each time. But beware, the call to
    'Dsa Fragmentation' slows the test down significantly.)
        ? [dic test visualizations] + 111b -> Dic Test Visualize No Memory Bars;

    (The next 16 pixels are used to show what percentage of the totally
    allocated memory is actually used. The total allocated memory can be
    obtained by the constant DIC TEST RAM SIZE. The effectively used memory
    can be calculated after a call to 'Dsa Fragmentation', which returns
    various data about the allocated memory.)
        => Dic Local Dsa Data;          (Switch to DIC's local DSA Data)
        => Dsa Fragmentation;
        => Dic Global Dsa Data;          (Switch to DIC's global DSA Data)
        A -->; B -->; C -->;            (Need values also for next bar)

    (Output:    A:  Free and reusable RAM below the memory pool, in units
                B:  Totally allocated and free RAM below the memory pool, units
                C:  Size of memory pool with free RAM, in units
    Used memory is B - A. Similarly to above bars, we need to calculate the width
    of the memory bar such, that complete memory usage means a full bar extending
    to the right edge. The constant DIC TEST BYTES PER PIXEL helps us to calculate
    that width.)
        A - B;
        A +-;
        A / DIC TEST BYTES PER PIXEL;
        C = A;                          (Save this number, need often)
    (E is already the position to draw the next pixel to, no need to calculate
    the value.)

    (Loop over the whole bar's height)
        B = DIC TEST FILL BAR HEIGHT;   (All bars have the same height)
    "Dic Test Visualize Memory Bar Line"

    (Draw A blue pixels to symbolize the used memory bar)
    "Dic Test Visualize Memory Bar Exist"
        [E] = 00 0000FFh;               (Draw pixel)
        E + 1;                          (Next address to draw to)
        A ^ Dic Test Visualize Memory Bar Exist;

    (The rest of the line consists of DIC TEST SCREEN WIDTH-C black pixels:
    such we cancel out a formerly longer bar.)
        A = DIC TEST SCREEN WIDTH;
        A - C;
    "Dic Test Visualize Memory Bar Empty"
        [E] = 00 000000h;               (Draw pixel)
        E + 1;                          (Next address to draw to)
        A ^ Dic Test Visualize Memory Bar Empty;

    (Restore A for the next line)
        A = C;

    (Next line of the fill bar)
        B ^ Dic Test Visualize Memory Bar Line;
        <-- C; <-- B; <-- A;            (Values from 'Dsa Fragmentation')
    (-------------------------------------------------------------------------)
    (The last bar measures the overall fragmentation of the available memory.)
    (Registers: A:  Free and reusable RAM below the memory pool, in units
                B:  Totally allocated and free RAM below the memory pool, units
                C:  Size of memory pool with free RAM, in units
    Calculation of overall fragmentation as a fraction of the screen width:
    A * DIC TEST SCREEN WIDTH / {B + C}. We make sure B+C is not 0. although
    there is no reason that it ever should be 0. However, it's a division, and
    Intel's don't divide by 0. Note, that B + C is not exactly the same as the
    constant DIC TEST RAM SIZE: from the whole allocated RAM, a usually pretty
    small portion is used for the DSA library's AVL manager controlling free
    chunks. DIC TEST RAM SIZE includes this AVL manager, whereas B+C does not.
    Such B+C tells us what effectively is available. However, the AVL manager
    does not require much space with this test scenario : it's max. 108 units
    only having memory chunks between 1 and 18 units.)
        A * DIC TEST SCREEN WIDTH;
        B + C;                          (If 0 we have no fragmentation at all)
        ? B = 0 -> Dic Test Visualize Fragmentation None;
        A / B;
        C = A;                          (Save this number, need often)
    (E is already the position to draw the next pixel to, no need to calculate
    the value.)

    (Loop over the whole bar's height)
        B = DIC TEST FILL BAR HEIGHT;   (All bars have the same height)
    "Dic Test Visualize Fragmentation Bar Line"

    (Draw A cyan pixels to symbolize the fragmentation memory bar)
        ? A = 0 -> Dic Test Visualize Fragmentation Bar None Exist;
    "Dic Test Visualize Fragmentation Bar Exist"
        [E] = 00 00FFFFh;               (Draw pixel)
        E + 1;                          (Next address to draw to)
        A ^ Dic Test Visualize Fragmentation Bar Exist;
    "Dic Test Visualize Fragmentation Bar None Exist"

    (The rest of the line consists of DIC TEST SCREEN WIDTH-C black pixels:
    such we cancel out a formerly longer bar.)
        A = DIC TEST SCREEN WIDTH;
        A - C;
        ? A = 0 -> Dic Test Visualize Fragmentation Bar None Empty;
    "Dic Test Visualize Fragmentation Bar Empty"
        [E] = 00 000000h;               (Draw pixel)
        E + 1;                          (Next address to draw to)
        A ^ Dic Test Visualize Fragmentation Bar Empty;
    "Dic Test Visualize Fragmentation Bar None Empty"

    (Restore A for the next line)
        A = C;

    (Next line of the fill bar)
        B ^ Dic Test Visualize Fragmentation Bar Line;
    "Dic Test Visualize Fragmentation None"
    (-------------------------------------------------------------------------)
    "Dic Test Visualize No Memory Bars"

    (What follows is drawing the counter symbols.)

    (No need to draw new symbols if nothing changed.)
        ? [dic test last millions] = [dic test loop millions]
                                        -> Dic Test Visualize Counters Drawn;

    (Store the last drawn state so that we can detect if something changed.)
        [dic test last millions] = [dic test loop millions];

    (For every million loops we draw a symbol in the 5th 'line'. The number
    of millions is counted in [dic test loop millions]. However, there are
    more counters, all dealing with a magnitude larger numbers, up to billions.
    We draw them in different colors.)

    (E must be calculated, we possibly skipped drawing the memory bars and thus
    E may not be were we expect it to be.)
        E = 5;                          (Skip space for 4 bars)
        E * DIC TEST FILL BAR HEIGHT;   (All bars have the same height)
        E + 4;                          (4 pixels distance from lowest bar)
        E * DIC TEST SCREEN WIDTH;      (Relative start of actual line)
        E + 1;                          (1 pixel distance from left edge)
        E + dic test window;            (Absolute address for first symbol)

    (Our symbols shall be small squares of DIC TEST FILL BAR HEIGHT-4 pixels
    edge length. There shall be as many symbols as there are whole millions.)
        A = [dic test loop millions];
        ? A = 0 -> Dic Test Visualize Draw No Million Symbols;
        [dic test symbols color] = 00 FFFF00h;  (Yellow for millions)
    "Dic Test Visualize Draw Million Symbol"
    (E is at the start of a symbol, i.e. at its upper left corner. Draw a
    square of DIC TEST FILL BAR HEIGHT-4 pixels edge length.)
        => Dic Test Draw Square;        (Draws square at address E)
    (The next symbol starts 2 pixels to the right of the right edge of the
    just drawn symbol.)
        E + DIC TEST FILL BAR HEIGHT minus 4 plus 2;
        A ^ Dic Test Visualize Draw Million Symbol;
    (No need to update the other symbols)
        -> Dic Test Visualize Counters Drawn;

    "Dic Test Visualize Draw No Million Symbols"
    (We only can have 0 millions at the start or when a new tenmillion symbol
    is needed. In E is the start of the million symbols not needed anymore.
    Clear the DIC TEST FILL BAR HEIGHT minus 4 lines.)
        => Dic Test Clear Symbols;

    (E is already in position to draw the tenmillion symbols now. And such all
    repeats for the tenmillions.)
        A = [dic test loop tenmillions];
        ? A = 0 -> Dic Test Visualize Draw No Tenmillion Symbols;
        [dic test symbols color] = 00 00FF00h;  (Green for tenmillions)
    "Dic Test Visualize Draw Tenmillion Symbol"
        => Dic Test Draw Square;        (Draws square at address E)
        E + DIC TEST FILL BAR HEIGHT minus 4 plus 2;
        A ^ Dic Test Visualize Draw Tenmillion Symbol;
        -> Dic Test Visualize Counters Drawn;
    "Dic Test Visualize Draw No Tenmillion Symbols"
        => Dic Test Clear Symbols;

    (And for the hundredmillions)
        A = [dic test loop hundredmillions];
        ? A = 0 -> Dic Test Visualize Draw No Hundredmillion Symbols;
        [dic test symbols color] = 00 FF0000h;  (Red for hundredmillions)
    "Dic Test Visualize Draw Hundredmillion Symbol"
        => Dic Test Draw Square;        (Draws square at address E)
        E + DIC TEST FILL BAR HEIGHT minus 4 plus 2;
        A ^ Dic Test Visualize Draw Hundredmillion Symbol;
        -> Dic Test Visualize Counters Drawn;
    "Dic Test Visualize Draw No Hundredmillion Symbols"
        => Dic Test Clear Symbols;

    (Eventually for the billions)
        A = [dic test loop billions];
        ? A = 0 -> Dic Test Visualize Draw No Billion Symbols;
        [dic test symbols color] = 00 FF00FFh;  (Magenta for billions)
    "Dic Test Visualize Draw Billion Symbol"
        => Dic Test Draw Square;        (Draws square at address E)
        E + DIC TEST FILL BAR HEIGHT minus 4 plus 2;
        A ^ Dic Test Visualize Draw Billion Symbol;
        -> Dic Test Visualize Counters Drawn;
    "Dic Test Visualize Draw No Billion Symbols"
        => Dic Test Clear Symbols;
    (-------------------------------------------------------------------------)
    "Dic Test Visualize Counters Drawn"

    (Finally draw a vertical bar each eigth of screen width in white lines)
        E = dic test window;            (Upper left edge of fill bar)

        B = 8;                          (4 lines)
    "Dic Test Visualize Draw Line"
        E + DIC TEST SCREEN WIDTH div 8;    (Each eigth of screen width)
    (Draw a vertical line)

    (The 2nd line goes down to the bottom, is also right edge of symbols)
        C = DIC TEST SCREEN HEIGHT;         (Assume is 2nd line)
        ? B = 7 -> Dic Test Visualize Draw Not Second Line;
        C = DIC TEST FILL BAR HEIGHT mtp 5; (5 bars high)
    "Dic Test Visualize Draw Not Second Line"
        E -->;                              (Need E back)
        E -;                                (Line at /end/ not start of eigth)
    "Dic Test Visualize Draw Pixel of Line"
        [E] + 00 FFFFFFh;
        E + DIC TEST SCREEN WIDTH;
        C ^ Dic Test Visualize Draw Pixel of Line;
        <-- E;
        B ^ Dic Test Visualize Draw Line;

    (A last horizontal white lien to optically divide bars from counter symbols)
        E = dic test window;            (Upper left edge of fill bar)
        E + DIC TEST FILL BAR HEIGHT mtp DIC TEST SCREEN WIDTH mtp 5;
        B = DIC TEST SCREEN WIDTH;
    "Dic Test Visualize Separator"
        [E] = 00 FFFFFFh;
        E + 1;
        B ^ Dic Test Visualize Separator;

    (-------------------------------------------------------------------------)
    (Update the screen.)
        [Display Command] = RETRACE;
        isocall;
    (-------------------------------------------------------------------------)
        leave;
    (=========================================================================)

(*****************************************************************************)
"Dic Test Draw Square"

    (=========================================================================)
    (Called from 'Dic Test Visualize')
    (-------------------------------------------------------------------------)
    (At address E draw a square of DIC TEST FILL BAR HEIGHT-4 edge length.)
        B = DIC TEST FILL BAR HEIGHT minus 4;
        E -->;                          (Need start of symbol back)
    "Dic Test Draw Square Line"
        C = DIC TEST FILL BAR HEIGHT minus 4;
        E -->;                          (Need start of line back)
    "Dic Test Draw Square Pixel"
        [E] = [dic test symbols color];
        E +;
        C ^ Dic Test Draw Square Pixel;
        <-- E;                          (Former start of line)
        E + DIC TEST SCREEN WIDTH;      (Start of next line)
        B ^ Dic Test Draw Square Line;
        <-- E;                          (Drawn symbol's start)
        leave;
    (=========================================================================)

(*****************************************************************************)
"Dic Test Clear Symbols"

    (=========================================================================)
    (Called from 'Dic Test Visualize')
    (-------------------------------------------------------------------------)
    (Starting at address E we clear all max. 9 symbols of that line. E will be
    in the starting position of the next symbol line when leaving.)
        A = DIC TEST FILL BAR HEIGHT minus 4;
    "Dic Test Visualize Clear Millions Line"
        B = DIC TEST FILL BAR HEIGHT minus 4 plus 2;
        B * 9;                          (Clear all 9 symbols)
        E -->;
    "Dic Test Visualize Clear Millions Pixel"
        [E] = 00 000000h;
        E +;
        B ^ Dic Test Visualize Clear Millions Pixel;
        <-- E;
        E + DIC TEST SCREEN WIDTH;      (Next line to clear)
        A ^ Dic Test Visualize Clear Millions Line;
    (Advance two lines to separate symbol lines from each other.)
        E + DIC TEST SCREEN WIDTH;
        E + DIC TEST SCREEN WIDTH;
        leave;
    (=========================================================================)

(*****************************************************************************)

Linoleum Syntax Highlighting produced with LSH (© 2007 by Herbert Glarner)