

************
Data storage
************

This chapter discusses controlling data placement and its impact on
application efficiency.

The 65816 has an address range of 16MB code and data space. Even
though the address space 16MB, it can be seen as a sequence of 64K
address ranges. While address calculations can cross 64K
bank boundaries, this is not the most efficient way to utilize the 65816.
Additionally, a single function must fit within a single 64K bank.

64K banks
=========

There are 256 such 64K banks on the 65816 numbered ``00`` to ``FF``
hexadecimal. The first bank ``00`` is special in that the system
stack and the direct page must be located in it. Certain vectors, such
as the reset and interrupt vectors also reside in bank ``00``.

.. note::

   Do not confuse the term bank here with a banked memory system where
   it often is used to refer to an address range which acts as a
   window to a larger memory area. A bank in the 65816 refers to a 64K
   memory area.

.. index:: direct page

Direct page
-----------

The direct page is 256 byte large and can be located anywhere in the
first 64K of memory. The compiler reserves 32 bytes from the direct page for
pseudo registers, forming the *tiny* area which uses the ``tiny``
attribute. The 65816 has several efficient addressing modes related
to this area, providing shorter instructions compared
to other areas.

.. index:: registers; pseudo, pseudo registers, direct page; pseudo registers

The ``DP`` (direct page) register is 16 bits and points to the start
of the direct page. This register is set up before the ``main()``
function is called and is expected to remain fixed while the
application is running.

.. index:: near bank

Near bank
---------

The near bank is the bank pointed to by the *data bank register*. This
is a single 64K bank that is in the middle of addressing efficiency.

The ``DB`` or data bank register is an 8 bit register that points to
the active near bank. This register is set up before the ``main()``
function is called and is expected to remain fixed for the duration
of the execution.

In the Small data model the near bank must be the same bank as the
CPU stack, which is always in bank ``00``.
This is because the default pointer is 16 bits wide in the Small
data model and it must be possible to point to a data object either on
the stack or the default static storage area.

Ways to store data
==================

Data can be allocated as *auto*, *static*, or on the *heap*. Variable
scope and the need for allocation during runtime determine placement.

As a general rule, use auto-allocated variables whenever possible.
This offers the compiler maximum flexibility for resource allocation
closest to the core, which typically results in the most efficient
data access.

.. index:: variables; auto, auto variables
.. index:: local variables, variables; local

Auto variables
--------------

Auto variables include function parameters and local variables not
defined with ``static``. The compiler attempts to allocate these in
processor registers or direct page pseudo registers; otherwise, the stack is used.

Auto variables are allocated only when used. Their registers can be
reused for other auto variables or temporary data once no longer
needed. This reuse also applies to stack locations.

Auto variables can have multiple *live ranges*; a variable with the
same name might be used in distinct parts of a function. Internally,
these are treated as different variables and may be allocated to
various locations, potentially not existing between live ranges.

All auto variables associated with a function are deallocated upon
function exit.

.. note::

   If you take the address of an auto variable, you can pass its
   pointer to other functions, which is useful for temporary storage.
   However, avoid using such pointers outside their scope, as auto
   variables are deallocated on function exit. Be aware that taking an
   address allocates the variable on the stack, potentially increasing
   access cost compared to other auto variables.

.. index:: variables; static, static variables
.. index:: variables; global, global variables

Static variables
-----------------

Global, module, or function static variables are allocated in global
memory, occupying space for the application's duration.

Their visibility varies. A global variable is universally visible but
requires ``extern`` for use. A module static variable, declared with
``static`` at file scope, is visible within one compilation unit.
A static local variable within a function's scope is only visible
there, retaining its value across function calls. Use ``static`` to
differentiate it from an auto variable.

.. index:: variables; dynamic

Dynamically allocated
----------------------

A dynamically allocated variable is retrieved from a *heap* using the
*malloc* function. This is useful when the required data size is
unknown at program startup.

.. note::

   Dynamically allocated variables are a potential problem in memory
   constrained systems if the program is left running for a long time
   due to heap fragmentation.

.. index:: address spaces

Address spaces
==============

The compiler provides multiple *address spaces*, which are addressable
memory areas with specific properties:

* Address width for pointers

* Width of the associated integral index type

* Different instruction sequences for accessing various address spaces

* An extension keyword or type attribute name

* Section names tied to the address space for linking control

Address space attributes are always active in the compiler.

The Calypsi C compiler tool chain provides five address spaces, tiny (direct page), near
(64K), far,  far24 and huge. The latter three can address the full
16MB range where far and far24 limit object size to 64K minus one.

All unqualified pointers are either 16 or 24 bits wide, depending on
the selected data model.

.. index:: tiny; address space, address space; tiny

Tiny address space
------------------

The *tiny* address space is 256 bytes of memory located somewhere
in the first 64K of memory. It has an address range ``0x00-0xff``.
This corresponds to the direct page on the 65816.

A tiny pointer is 16 bits wide and occupies two bytes when
stored in memory. While a single byte would suffice, the compiler uses
two bytes for efficiency.

Due to its 256-byte size and sharing with pseudo registers, the tiny
area has limited storage. However, careful use can lead to a more
efficient application.

.. index:: near; address space, address space; near

Near address space
------------------

The *near* address space is a single 64K bank. This address
space is not available in the Small data model. The bank can be
located to any 64K bank and is fixed to that bank.

A near memory pointer is 16 bits and occupies two bytes when stored in
memory.

.. index:: far; address space, address space; far

Far address space
-----------------

The *far* address space covers the entire 16MB address range. The only
limitation on far objects is that they must be at most 64K
(minus one byte) large.

A far memory pointer is 24 bits and occupies four bytes when stored
in memory.

.. index:: far24; address space, address space; far24

Far24 address space
-------------------

The *far24* address space cover the entire 16MB address range. The only
limitation on far24 objects are that they must be at most 64K (minus one
byte) large.

A far24 memory pointer is 24 bits and occupies three bytes when stored
in memory.

.. note::

   The only difference between far24 and far is that far24 is stored
   in memory without 32 bits padding. This is useful when hardware or
   API definitions require unpadded pointer storage. The generated code
   to store a 24 bits pointer is somewhat larger compared to
   a 32 bits pointer on the 65816.

.. index:: huge; address space, address space; huge

Huge address space
------------------

The *huge* address space covers the entire 16MB address range. The
maximum size of an object is 16MB (minus one byte).

A huge memory pointer is 24 bits and occupies four bytes when stored
in memory.

Summary
-------

The following table summarizes the available address spaces.

.. index:: keywords; address spaces, address spaces

.. _AddressSpaces:
.. table:: Address spaces
 :widths: 1 1 1 1 1
 :column-dividers: none single single single single none
 :column-alignment: left left left left left

 +-------------+-------------+----------------------+-------------+------------+
 |Memory type  |Keyword      |Address range         |Pointer size | Index type |
 +=============+=============+======================+=============+============+
 | Direct page | ``__tiny``  |``0x00-0xff``         |16 bits      |``int8_t``  |
 +-------------+-------------+----------------------+-------------+------------+
 | Near        | ``__near``  |``0x0000-0xffff``     |16 bits      |``int16_t`` |
 +-------------+-------------+----------------------+-------------+------------+
 | Far         | ``__far``   |``0x000000-0xffffff`` |32 bits      |``int16_t`` |
 +-------------+-------------+----------------------+-------------+------------+
 | Far24       | ``__far24`` |``0x000000-0xffffff`` |24 bits      |``int16_t`` |
 +-------------+-------------+----------------------+-------------+------------+
 | Huge        | ``__huge``  |``0x000000-0xffffff`` |32 bits      |``int32_t`` |
 +-------------+-------------+----------------------+-------------+------------+


.. index:: address space; syntax, type qualifier

Syntax
------

An address space attribute keyword such as ``__tiny`` is
a type qualifier. Syntactically it works the same as other C language
defined type qualifier, e.g. ``const`` and ``volatile``.

The following declaration defines four variables in the
Direct page address space:

.. code-block:: C

   __tiny int a, b;
   int __tiny c, d;

The ``__tiny`` type qualifier applies to the closest type,
``int`` in this example. In C, the order between type qualifiers and
types does not matter; they convey the same meaning.

.. index:: pointers

Pointers
--------

A pointer in C points to something in memory. Both the pointer itself
and what it points to have types. As an example, the type ``char *``
is a pointer to a ``char``.

Pointer types are easier to understand if you read them from right to
left. The ``*`` is a pointer, so ``char *`` reads from right to left
as "pointer to char". This order of reading is especially useful when
you mix in type qualifiers in pointer types, as it makes it a lot
easier to read and understand  what the type means.

.. code-block:: C

   int __attribute__((tiny)) * p1;
   long * __attribute__((tiny)) p2;

Here, ``p1`` is a pointer stored in default memory that points to an
``int`` in Direct page memory. ``p2`` is a pointer stored
in Direct page memory that points to a ``long`` in default
memory.

Structures
----------

You can place a structure in a specified address space. This means
that all its members are in that address space. You cannot override
individual structure members using an address space keyword. It is
however possible to have members of the structure that point to a
different address space.

.. code-block:: C

   struct tag {
     int __tiny * p;
     int value;
   };

   struct tag __tiny myTag;

This is however not allowed:

.. code-block:: C

   struct tag {
     int * __tiny p;     /* incorrect */
     int __tiny value;   /* incorrect */
   };
