Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Driver development guide #343

Open
wants to merge 9 commits into
base: freedom-metal-next
Choose a base branch
from
Prev Previous commit
Next Next commit
doc: Update docs for freedom-metal-next
Include more APIs.
Fix exception/interrupt discussion.

Signed-off-by: Keith Packard <[email protected]>
  • Loading branch information
keith-packard committed Oct 1, 2020
commit 56d4870436123028f45fa649bebe50a536057f69
4 changes: 2 additions & 2 deletions Doxyfile
Original file line number Diff line number Diff line change
Expand Up @@ -813,7 +813,7 @@ WARN_LOGFILE =
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.

INPUT = metal
INPUT = metal sifive-blocks/metal

# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
Expand Down Expand Up @@ -888,7 +888,7 @@ FILE_PATTERNS = *.c \
# be searched for input files as well.
# The default value is: NO.

RECURSIVE = NO
RECURSIVE = YES

# The EXCLUDE tag can be used to specify files and/or directories that should be
# excluded from the INPUT source files. This way you can easily exclude a
Expand Down
2 changes: 2 additions & 0 deletions doc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#
# Documentation Build

export RELEASE_TAG ?= unreleased

.PHONY: all
all: html pdf

Expand Down
6 changes: 6 additions & 0 deletions doc/sphinx/apiref/atomic.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Atomics
=======

.. doxygenfile:: metal/atomic.h
:project: metal

20 changes: 20 additions & 0 deletions doc/sphinx/apiref/clock.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,23 @@ Clocks
.. doxygenfile:: metal/clock.h
:project: metal

Abstract Clock Devices
----------------------

.. doxygenfile:: metal/drivers/fixed_clock.h
:project: metal

.. doxygenfile:: metal/drivers/fixed_factor_clock.h
:project: metal

SiFive Clock Devices
--------------------

.. doxygenfile:: metal/drivers/sifive_fe310_g000_hfrosc.h
:project: metal

.. doxygenfile:: metal/drivers/sifive_fe310_g000_hfxosc.h
:project: metal

.. doxygenfile:: metal/drivers/sifive_fe310_g000_lfrosc.h
:project:metal
6 changes: 6 additions & 0 deletions doc/sphinx/apiref/csr.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
CSR
===

.. doxygenfile:: metal/csr.h
:project: metal

5 changes: 5 additions & 0 deletions doc/sphinx/apiref/exception.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Exception Handlers
==================

.. doxygenfile:: metal/exception.h
:project: metal
6 changes: 6 additions & 0 deletions doc/sphinx/apiref/hpm.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Hardware Performance Monitors
=============================

.. doxygenfile:: metal/hpm.h
:project: metal

6 changes: 6 additions & 0 deletions doc/sphinx/apiref/i2c.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
I2C
===

.. doxygenfile:: metal/i2c.h
:project: metal

4 changes: 2 additions & 2 deletions doc/sphinx/apiref/init.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Constructors and Destructors
============================
Constructors
============

.. doxygenfile:: metal/init.h
:project: metal
Expand Down
5 changes: 5 additions & 0 deletions doc/sphinx/apiref/interrupt.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,8 @@ Interrupts
.. doxygenfile:: metal/interrupt.h
:project: metal

.. doxygenfile:: metal/drivers/riscv_cpu_intc.h
:project: metal

.. doxygenfile:: metal/drivers/riscv_plic0.h
:project: metal
5 changes: 5 additions & 0 deletions doc/sphinx/apiref/io.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Input/Output declarations
=========================

.. doxygenfile:: metal/io.h
:project: metal
6 changes: 0 additions & 6 deletions doc/sphinx/apiref/memory.rst

This file was deleted.

5 changes: 5 additions & 0 deletions doc/sphinx/apiref/privilege.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Privilege Modes
===============

.. doxygenfile:: metal/privilege.h
:project: metal
6 changes: 6 additions & 0 deletions doc/sphinx/apiref/pwm.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
PWM
===

.. doxygenfile:: metal/pwm.h
:project: metal

5 changes: 5 additions & 0 deletions doc/sphinx/apiref/riscv.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
RISC-V Processor Definitions
============================

.. doxygenfile:: metal/riscv.h
:project: metal
4 changes: 2 additions & 2 deletions doc/sphinx/apiref/spi.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
SPIs
=====
SPI
===

.. doxygenfile:: metal/spi.h
:project: metal
Expand Down
5 changes: 2 additions & 3 deletions doc/sphinx/apiref/uart.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
UARTs
=====
UART
====

.. doxygenfile:: metal/uart.h
:project: metal

2 changes: 1 addition & 1 deletion doc/sphinx/devguide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Developer Guide
===============

.. toctree::
:maxdepth: 1
:hidden:
:glob:

devguide/*
Expand Down
66 changes: 25 additions & 41 deletions doc/sphinx/devguide/exceptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,8 @@ application.
Initializing the CPU
--------------------

When the user application enters the ``main()`` function, the Freedom Metal
framework has not yet performed the initialization necessary to register
exception handlers. If this initialization is not performed before an exception
occurs, any exception will cause the CPU to spin in a tight loop until reset.

To initialize the Freedom Metal exception handlers, initialize CPU interrupts:

.. code-block:: C

struct metal_cpu *cpu0 = metal_cpu_get(0);
if(!cpu) {
/* There was an error acquiring the CPU hart 0 handle */
}

struct metal_interrupt *cpu_int = metal_cpu_interrupt_controller(cpu0);
if(!cpu_int) {
/* There was an error acquiring the CPU interrupt controller */
}

metal_interrupt_init(cpu_int);

The Freedom Metal interrupt API is further documented in :doc:`/devguide/interrupts`
and :doc:`/apiref/interrupt`.
When the user application enters the ``main()`` function, the Freedom
Metal framework has already set up the exception handlers.

Defining an Exception Handler
-----------------------------
Expand All @@ -42,36 +21,41 @@ Exception handlers must conform to the following function signature:
:project: metal
:no-link:

Therefore, an example exception handler might look like:
Therefore, an exception handler for the illegal instruction exception
would look like:

.. code-block:: C

void my_exception_handler(struct metal_cpu *cpu, int ecode) {
void metal_exception_illegal_instruction_handler(struct metal_cpu cpu, int ecode) {
/* Contents of handler */
}

Registering an Exception Handler
--------------------------------

Exception handlers are registered with a given CPU hart for an individual exception
code.
Exception handlers are registered by name at link time. Define a
function using the appropriate name and it will be called whenever
that exception is raised. The names of the available exception
handlers are:

.. code-block:: C

/* CPU Hart 0's interrupt controller must be initialized
* if it is not already */
struct metal_cpu *cpu0 = metal_cpu_get(0);

int rc = metal_cpu_exception_register(cpu0,
<my_ecode>, /* Set to your desired value */
my_exception_handler);
if(rc != 0) {
/* Failed to register exception handler */
}
void metal_exception_instruction_address_misaligned_handler(struct metal_cpu cpu, int ecode);
void metal_exception_instruction_address_fault_handler(struct metal_cpu cpu, int ecode);
void metal_exception_illegal_instruction_handler(struct metal_cpu cpu, int ecode);
void metal_exception_breakpoint_handler(struct metal_cpu cpu, int ecode);
void metal_exception_load_address_misaligned_handler(struct metal_cpu cpu, int ecode);
void metal_exception_load_access_fault_handler(struct metal_cpu cpu, int ecode);
void metal_exception_store_amo_address_misaligned_handler(struct metal_cpu cpu, int ecode);
void metal_exception_store_amo_access_fault_handler(struct metal_cpu cpu, int ecode);
void metal_exception_ecall_from_u_mode_handler(struct metal_cpu cpu, int ecode);
void metal_exception_ecall_from_s_mode_handler(struct metal_cpu cpu, int ecode);
void metal_exception_default_handler(struct metal_cpu cpu, int ecode);
void metal_exception_ecall_from_m_mode_handler(struct metal_cpu cpu, int ecode);
void metal_exception_instruction_page_fault_handler(struct metal_cpu cpu, int ecode);
void metal_exception_load_page_fault_handler(struct metal_cpu cpu, int ecode);
void metal_exception_store_amo_page_fault_handler(struct metal_cpu cpu, int ecode);

A single exception handler may be used for multiple exception codes. For this reason,
exception handlers receive the exception code as the ``ecode`` parameter and may use
this to determine how to handle the exception.

Returing Execution after a Faulting Instruction
-----------------------------------------------
Expand All @@ -82,7 +66,7 @@ the faulting instruction using the following method:

.. code-block:: C

void return_after_fault(struct metal_cpu *cpu, int ecode)
void metal_exception_load_access_fault_handler(struct metal_cpu cpu, int ecode)
{
/* Get the faulting instruction address */
uintptr_t epc = metal_cpu_get_exception_pc(cpu);
Expand Down
72 changes: 22 additions & 50 deletions doc/sphinx/devguide/init.rst
Original file line number Diff line number Diff line change
@@ -1,29 +1,23 @@
Constructors and Destructors
============================
Constructors
============

Metal implements a mechanism for registering constructors and destructors to
run before main and upon exit. The purpose of the Metal init API is to provide
a unified mechanism for registering constructors for both users and drivers,
as well as to provide a mechanism for manually overriding or disabling the
constructors/destructors entirely.
Metal implements a mechanism for registering constructors to run
before main. The purpose of the Metal init API is to provide a unified
mechanism for registering constructors for both users and drivers, as
well as to provide a mechanism for manually overriding or disabling
the constructors entirely.

Defining a Constructor/Destructor
Defining a Constructor
---------------------------------

Constructors and destructors can be defined with the following macros:
Constructors can be defined with the following macros:

.. doxygendefine:: METAL_CONSTRUCTOR
:project: metal

.. doxygendefine:: METAL_CONSTRUCTOR_PRIO
:project: metal

.. doxygendefine:: METAL_DESTRUCTOR
:project: metal

.. doxygendefine:: METAL_DESTRUCTOR_PRIO
:project: metal

For example:

.. code-block:: C
Expand All @@ -32,28 +26,25 @@ For example:
puts("Hello from before main!\n");
}

METAL_DESTRUCTOR_PRIO(destructor_goodbye, METAL_INIT_HIGHEST_PRIORITY) {
puts("Program exiting, goodbye.\n");
METAL_CONSTRUCTOR_PRIO(constructor_hello_early, METAL_INIT_HIGHEST_PRIORITY) {
puts("Hello from earliest constructor.\n");
}

The above sample defines the functions ``constructor_hello()`` and
``constructor_goodbye()`` and registers them to be run by ``metal_init()`` and
``metal_fini()``.
``constructor_hello_early()`` and registers them to be run by ``metal_init()``.

.. doxygenfunction:: metal_init
:project: metal

.. doxygenfunction:: metal_fini
:project: metal

Default Behavior
----------------

By default, Metal constructors and destructors are run before main and upon exit
respectively. This ensures that constructors defined by Metal and
Metal device drivers are called by default before ``main()``. For example, targets
with the "sifive,uart0" UART device set as ``stdout-path`` automatically configure
the UART's clock divider to the requested baud rate using a Metal constructor.
By default, Metal constructors are run before main. This ensures that
constructors defined by Metal and Metal device drivers are called by
default before ``main()``. For example, targets with the
"sifive,uart0" UART device set as ``stdout-path`` automatically
configure the UART's clock divider to the requested baud rate using a
Metal constructor.

The default control flow looks like the following:

Expand All @@ -71,39 +62,20 @@ The default control flow looks like the following:
* ...
* main

* ...

* exit

* ...
* metal_fini_run

* metal_fini

* destructor_1
* destructor_2
* ...

* ...

Note ``metal_init_run()`` and ``metal_fini_run()`` in the above flow graph.
Note ``metal_init_run()`` in the above flow graph.

.. doxygenfunction:: metal_init_run
:project: metal

.. doxygenfunction:: metal_fini_run
:project: metal

The purpose of these wrapper functions is to allow manual override by application
code.

Preventing Constructors/Destructors from Running
Preventing Constructors from Running
------------------------------------------------

You can prevent Metal constructors and destructors from running by redifining
``metal_init_run()`` and ``metal_fini_run()`` in your application:
You can prevent Metal constructors from running by redefining
``metal_init_run()`` in your application:

.. code-block:: C

void metal_init_run() {}
void metal_fini_run() {}
Loading