

***************
Runtime library
***************

This chapter describes the supplied C runtime library, adapted from the
Apache NuttX library.

Design considerations
======================

The original Apache NuttX library is a collection of routines from the
C standard library, POSIX standard, and other components common in
real-time operating systems.

It is a scalable and highly configurable runtime library that works in
both 8-bits and 32-bits environments.

The adapted version becomes a Standard C library, with POSIX and RTOS-style
components either removed or disabled.

Apart from that, the following are the key changes:

* Replaced header files closely related to the compiler (e.g., ``stddef.h``,
  ``stdarg.h``, ``setjmp.h``, ``stdint.h``).

* Internal names are changed to start with either double underscores or a
  single underscore followed by a capital letter. This avoids namespace
  pollution, as such identifiers are reserved for the compiler vendor.

* The stub interface uses names prefixed by ``_Stub`` instead of ``up_`` for
  clarity and to avoid namespace pollution.

.. note::

   The Apache NuttX library's configuration utility, designed for environmental
   tailoring, is not used here; the build system is different. This allows
   the library to be used without extensive configuration, as the compiler
   is known and target-board-specific matters are excluded. Some library
   functions have different versions to reduce memory footprint by making
   certain capabilities optional (e.g., formatters; see :ref:`library-on-a-diet`).

Using the library
=================

The C library consists of header files that are immediately available
to use by the compiler and can be included:

.. code-block:: C

   #include <stdio.h>

   int main () {
     printf("Hello World!\n");
     return 0;
   }

When linking, the C library does not need to be explicitly added on the
command line, as the linker automatically finds the correct C runtime
library by examining the settings used during C object file compilation:

$ ln68k main.o linker-rules.scm

C library variants matching different compiler settings are provided in
the installation directory; the appropriate one is automatically selected.

The linker detects mixing object files compiled with different settings
or incompatible third-party libraries. This relies on matching runtime
attributes in object files. A mismatch results in a descriptive linker error.

.. index:: library; files, C library, debug library, runtime library

Provided library files
======================

The following table lists the provided ready to use library files:

.. table:: Library variants
 :widths: 12 4 4 5 5
 :column-dividers: none single single single none
 :column-alignment: left left left left left

 +-----------------------------------------+-----------+------------+---------------+--------------+
 |Library name                             |Code model | Data model |Size of double |Target system |
 +=========================================+===========+============+===============+==============+
 | ``clib-68000-sc-sd.a``                  |Small      |Small       |32 bits        |Generic       |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-lc-sd.a``                  |Large      |Small       |32 bits        |Generic       |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-sc-ld.a``                  |Small      |Large       |32 bits        |Generic       |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-lc-ld.a``                  |Large      |Large       |32 bits        |Generic       |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-sc-fod.a``                 |Small      |Far-only    |32 bits        |Generic       |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-lc-fod.a``                 |Large      |Far-only    |32 bits        |Generic       |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-sc-sd-double64.a``         |Small      |Small       |64 bits        |Generic       |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-lc-sd-double64.a``         |Large      |Small       |64 bits        |Generic       |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-sc-ld-double64.a``         |Small      |Large       |64 bits        |Generic       |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-lc-ld-double64.a``         |Large      |Large       |64 bits        |Generic       |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-sc-fod-double64.a``        |Small      |Far-only    |64 bits        |Generic       |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-lc-fod-double64.a``        |Large      |Far-only    |64 bits        |Generic       |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-sc-sd-amiga.a``            |Small      |Small       |32 bits        |Amiga         |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-lc-sd-amiga.a``            |Large      |Small       |32 bits        |Amiga         |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-sc-ld-amiga.a``            |Small      |Large       |32 bits        |Amiga         |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-lc-ld-amiga.a``            |Large      |Large       |32 bits        |Amiga         |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-sc-fod-amiga.a``           |Small      |Far-only    |32 bits        |Amiga         |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-lc-fod-amiga.a``           |Large      |Far-only    |32 bits        |Amiga         |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-sc-sd-double64-amiga.a``   |Small      |Small       |64 bits        |Amiga         |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-lc-sd-double64-amiga.a``   |Large      |Small       |64 bits        |Amiga         |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-sc-ld-double64-amiga.a``   |Small      |Large       |64 bits        |Amiga         |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-lc-ld-double64-amiga.a``   |Large      |Large       |64 bits        |Amiga         |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-sc-fod-double64-amiga.a``  |Small      |Far-only    |64 bits        |Amiga         |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-lc-fod-double64-amiga.a``  |Large      |Far-only    |64 bits        |Amiga         |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-sc-sd-a2560u.a``           |Small      |Small       |32 bits        |A2560U        |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-lc-sd-a2560u.a``           |Large      |Small       |32 bits        |A2560U        |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-sc-ld-a2560u.a``           |Small      |Large       |32 bits        |A2560U        |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-lc-ld-a2560u.a``           |Large      |Large       |32 bits        |A2560U        |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-sc-fod-a2560u.a``          |Small      |Far-only    |32 bits        |A2560U        |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-lc-fod-a2560u.a``          |Large      |Far-only    |32 bits        |A2560U        |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-sc-sd-double64-a2560u.a``  |Small      |Small       |64 bits        |A2560U        |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-lc-sd-double64-a2560u.a``  |Large      |Small       |64 bits        |A2560U        |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-sc-ld-double64-a2560u.a``  |Small      |Large       |64 bits        |A2560U        |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-lc-ld-double64-a2560u.a``  |Large      |Large       |64 bits        |A2560U        |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-sc-fod-double64-a2560u.a`` |Small      |Far-only    |64 bits        |A2560U        |
 +-----------------------------------------+-----------+------------+---------------+--------------+
 | ``clib-68000-lc-fod-double64-a2560u.a`` |Large      |Far-only    |64 bits        |A2560U        |
 +-----------------------------------------+-----------+------------+---------------+--------------+

.. note::

   Libraries for 68020, 68060 and 68080 are also provided, by replacing 68000 with
   68020, 68060 or 68080 in the above listed libraries.

.. note::

   In addition to Amiga and A2560U shown above, there are also libraries for
   TOS and A2560K provided.

.. note::

   There is normally no need to specify the C library to use when
   linking. The linker is able to automatically pick the correct C
   library by inspecting the C object files.

.. index:: stubs interface, simulated I/O
.. _stubs-interface:

Stubs interface
================

How do you provide functions such as ``fopen()``, ``fprintf()``, or ``assert()``
when using a cross-compiler that may not know the final execution
environment of an application, or even have a file system?

Functions like ``fprintf()`` pass through several library layers, handling
formatting, buffered I/O, and stream interfaces. Ultimately, they output
characters to a display or file. This is managed by a simple stubs API
defined in the ``calypsi/stubs.h`` header file.

.. index:: semi-hosted

.. _semi-hosted:

Semi-hosting
-------------

Semi-hosting is the concept where the debugger implements operations,
such as I/O, on behalf of the target. This involves using a single
breakpoint where the target temporarily stops to exchange data with
the debugger, which performs the actual operation on the host. After
the operation, any return value is passed back, and execution resumes
on the target.

The Calypsi C compiler tool chain includes a semi-hosted debug implementation of the stubs API
within the standard C library. To enable semi-hosting, add the
``--semi-hosted`` command-line option to the linker.

File operations are performed in the host filesystem by the debugger
in a directory specified by the ``--semi-hosted-root`` command-line option,
which defaults to the current directory.

The standard streams ``stdin``, ``stdout`` and ``stderr`` are fully
supported. Depending on your IDE you may have a console window for
these streams.

Semi-hosting can be used during development for tracing or prototyping before
a real I/O system is implemented in the application. In a final application,
you will most likely use target-specific stub functions, not semi-hosted
variants.

.. note::

   Even if you implement some stub actions, you can still link with
   ``--semi-hosted`` for partial semi-hosted support. This allows you
   to implement a file system while retaining ``assert()`` through
   the semi-hosted mechanism. The C library's semi-hosted stubs are
   compiled with ``--weak-symbols``, so your implementations take
   precedence. Unimplemented stubs will use their weak semi-hosted
   variants.


Stubs header
------------

The ``calypsi/stubs.h`` file looks as follows:

.. literalinclude:: ../../../../lib/clib/include/calypsi/stubs.h
   :language: C

.. index:: streams

Custom I/O
----------

You can provide your own low-level I/O stubs. File descriptors
are integers indexing an internal lookup table (typically an array).
If the I/O system is used, the library statically allocates
the first three streams: ``stdin``, ``stdout``, and ``stderr``.
Additional file streams are dynamically allocated from the heap.

.. index:: C library; errno, errno; C library

Error handling
--------------

If a stub action encounters an error, it should return the negated
``errno`` value. The calling C library function then performs
appropriate error handling, setting ``errno`` to the corresponding
positive error code.

Examine use of library
======================

When working with a memory-constrained system, the risk of running
out of memory is always present. To help you understand memory
usage, the linker can generate a list file with
cross-reference information. This valuable tool details what is
placed in memory, its location, and why it occupies that space.

You can tell the linker to provide a list file in the following way::

$ ln68k main.o clib-68000-lc-sd.a linker-rules.scm --list-file=project.lst --cross-reference

This will result in a list file names ``project.lst`` which contains
several parts showing things such as:

* A summary of the memories

* An overview of sections and where they take space in the memories

* The object files used and from which library they have been
  extracted from

* Complete cross reference, showing where every section fragment is
  located with its size, together with:

  * What symbols are defined

  * What symbols are referenced

  * Who is referencing me

* An overall summary of total memory size


.. _library-on-a-diet:

Library on a diet
=================

If you use the C library in a memory-constrained system,
you may find it rapidly consumes code space. This is because the C
library provides substantial functionality, with many functions acting
as simple facades to complex underlying implementations.

There are ways to tune things to reduce the memory footprint. However,
first understand the current memory usage before making changes.

.. index:: print formatter, formatter; printf

Formatters
----------

The C library provides various ``printf()`` and ``scanf()`` variants,
each with different capabilities and memory requirements.

While you can specify a format function, the compiler inspects
used format strings and outputs this information to the object file.
The linker then automatically selects the smallest variant
compatible with those format strings.

.. note::

   Automatic format function selection requires using string literals
   in calls. This is good practice, as it also allows the compiler
   to validate argument list consistency with the format string.

If you for some reason have to override the formatter used and dictate
a specific one, you can do so using the ``--rtattr`` attribute which
for ``printf()`` would be::

$ ln68k --rtattr printf=nofloat files...

The default print formatter as mentioned above, is selected
automatically to match your needs. The following table
describes the available print formatters:

.. table:: Print formatters
 :widths: 2 1 1 1 1
 :column-dividers: none single single single single none
 :column-alignment: left left left left left

 +---------------------------------+---------------+-------------------+----------------+-------------+
 |Capability                       |printf=reduced | printf=medium     | printf=nofloat |printf=float |
 +=================================+===============+===================+================+=============+
 |basics, ``c d i o p s u X x %``  | yes           | yes               | yes            | yes         |
 +---------------------------------+---------------+-------------------+----------------+-------------+
 |format flag, ``0 + - #``         | no            | yes               | yes            | yes         |
 +---------------------------------+---------------+-------------------+----------------+-------------+
 |field width                      | no            | yes               | yes            | yes         |
 +---------------------------------+---------------+-------------------+----------------+-------------+
 |long long                        | no            | no                | yes            | yes         |
 +---------------------------------+---------------+-------------------+----------------+-------------+
 |float, ``e f g E F G``           | no            | no                | no             | yes         |
 +---------------------------------+---------------+-------------------+----------------+-------------+

.. index:: scan formatter, formatter; scanf

The ``scanf()`` function exits in three variants, mainly depending on if
you want support for floating point numbers or not:

.. table:: Read formatters
 :widths: 2 1 1 1
 :column-dividers: none single single single single none
 :column-alignment: left left left left left

 +---------------------------------+-------------+--------------+--------------+
 |Capability                       |scanf=medium |scanf=nofloat |scanf=float   |
 +=================================+=============+==============+==============+
 |basics, ``c d i o p s u X x %``  | yes         | yes          | yes          |
 +---------------------------------+-------------+--------------+--------------+
 |long long                        | no          | yes          | yes          |
 +---------------------------------+-------------+--------------+--------------+
 |float, ``e f g E F G``           | no          | no           | yes          |
 +---------------------------------+-------------+--------------+--------------+

.. note::

   An appropriate default formatter for ``scanf()`` is automatically
   picked by the linker based on the needs of your application.

.. index:: termination; simplification, exit

Reduced exit
------------

Terminating an application involves closing open files and executing
``atexit()`` functions. For embedded applications, which may never
exit, termination code can be redundant; closing files also adds
related code. An implicit call to ``exit()`` occurs when ``main()``
returns. If proper exit code is undesirable, you can exclude it.

The simplest way to reduce exit code overhead is to add
``--rtattr exit=simplified`` to the linker command line. This prevents
closing files or calling ``atexit()`` handlers. Instead, ``exit()``
will immediately jump to ``_Stub_exit()``, the lowest-level
termination routine.


Consider alternatives
---------------------

If the library still occupies too much space, consider replacing
certain functions with smaller, less flexible alternatives.

.. index:: library; replace function, C library; replace function, replace function; in C library

Override library functions
===========================

You may sometimes need to override a library function. Consider using
an alternative function with a different name rather than replacing a
standard one. Replacing a library function is appropriate if you have
a more suitable application-specific implementation, especially when
other library functions call it.

To replace a library function, add a new source file to your project
using the same function name and prototype, then build your application normally.

.. note::

   Function replacement works because library functions use weak
   symbols. Your replacement functions are non-weak by default,
   taking precedence over library functions during linking.

.. index:: system startup, C startup, startup
.. _system-startup:

C startup
=========

The initial system configuration is performed by the *C startup*
object which is included in the standard C library.

The C startup is responsible for setting up the execution
environment before giving control to the ``main()`` function.
This typically includes setting up the stack pointer and providing initial
values to static variables.

The C startup object also contains a couple of small optional sections that
are only included if needed. They are responsible for initializing
optional parts of the runtime system, such as the heap and the file
streams.

If you do not use functions such as ``malloc()``, the heap is not
needed and the code to initialize the heap memory system is
omitted. The same happens for file streams. If there are no file
streams used, the code related to initializing and terminating them
are omitted.
This is done in order to reduce the memory footprint of the final
application.

In case you want to study the source code of the C startup it
can be found at ``src/lib/lowlevel/cstartup.s`` under the installation
directory.

.. index:: C startup; replacing, startup; custom
.. index:: system startup; customizing, customizing; system startup

Customizing the startup
-----------------------

In many cases the default C startup will work fine without any
changes. However, there are a couple of typical situations
when some custom configuration is needed. One example is that the
memory system needs to be configured immediately at power on, or if
your application is going to run under an operating system that may
impose special rules on initialization and termination.

If you only need to run some code to perform early initialization
of the hardware you can provide your own ``__low_level_init()``
function which is called early in the C startup object,
before any static C variables are given their start values.

If you need to make actual changes to the C startup object the
easiest way is to copy the existing one to your project, make changes
as required and include it in your build system.

To be able to properly suppress the C startup object in the C library
you need to provide a different value for the ``cstartup`` runtime
attribute in your own ``cstartup.s``. The ``cstartup.s`` assembly
source file starts with:

.. code-block:: ca65

    ;;; C startup variant, change attribute value if you make your own
            .rtmodel cstartup,"normal"

You need to change the value ``normal`` to something else. What value
you use does not matter so much, but using a descriptive value
is probably a good idea:

.. code-block:: ca65

    ;;; C startup variant, change attribute value if you make your own
            .rtmodel cstartup,"mycustom"

The modified C startup source file needs to be included in your build
system. The linker also needs to be informed that it should use a
specific C startup object, which is done using the ``--cstartup`` command
line option:

.. code-block:: console

   % ln68k <object-files> <your-startup.o> clib-68000-lc-sd.a --cstartup=mycustom

.. note::

   The C startup object has been carefully crafted to have a small
   footprint and to properly initialize the C runtime system. Even
   though it makes calls to handle the file system, initialize data
   areas and the heap, it is done in such way that the actual code is
   only included in the final application if these subsystems are used.

   A good understanding of the tools and the provided C runtime is
   needed in order to make non-trivial changes to the C startup
   object. Incorrectly made changes may cause linker errors, unused
   subsystem being pulled in, or result in a runtime that is not
   properly initialized.

.. index:: time; functions; date; functions

Time and date
=============

The provided C library implements the functions and definitions in the
``time.h`` system header file. The time related types are defined as
64-bit types to avoid the year 2038 problem and reduce issues with
overflow.


Providing a time
----------------

C defines two functions ``clock()`` and ``time()`` that provides a
concept of a time. The library provides a default implementation for
them that returns a value with all bits set, which means that the
time is not available.

To use actual times you will need to provide your own implementation of
``clock()`` or ``time()`` and include it in your project.

The ``CLOCKS_PER_SEC`` macro is set to ``1000`` by the ``stdint.h``
header file.

.. index:: library; building, C library; building, building; C library
.. _library-rebuild:

Rebuilding the C library
========================

The C library is designed to allow for a great deal of configuration
without resorting to rebuild it. Situations where you may need to
rebuild the C library are when you need a specific variant build, or
to enable debug information to debug the library itself.

For the most part, building the library is straightforward, but there
are certain files that needs to be built in certain ways,
e.g. variants of ``printf()``. To make it easier to build a variant
C library there are build scripts provided in the ``library-build``
folder in the installation directory.

There is one build file for each library variant that are included in
the installation. Select one that has a similar configuration
as a starting point.
It is a good idea to make copy of the build script and modify it
to suit your needs.


