Commit c3685082 authored by Federico Vaga's avatar Federico Vaga

doc: first documentation

Signed-off-by: Federico Vaga's avatarFederico Vaga <federico.vaga@cern.ch>
parent a4a8ca36
......@@ -39,13 +39,9 @@ The Mock Turtle framework includes the following components:
- Up to 8 soft-CPUs
- input channels (Host to Mock Turtle - hmq)
- communication with the host system (input, output)
- output channels (Mock Turtle to Host - hmq)
- remote input channels (network to Mock Turtle - rmq)
- remote output channels (Mock Turtle to network -rmq)
- communication with remote systems (input, output)
- Software
......
......@@ -69,7 +69,7 @@ struct trtl_fw_variable svec_variables[] = {
struct trtl_fw_application app = {
.name = "svec-svec",
.name = "manualsvec",
.version = {
.rt_id = RT_APPLICATION_ID,
.rt_version = RT_VERSION(1, 0),
......
_*
doxygen-trtl-output/
......@@ -12,9 +12,20 @@ BUILDDIR = _build
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
.PHONY: help Makefile doxygen doxygen-clean
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
$(MAKE) doxygen TARGET=$@
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
GIT_VERSION = $(shell cd $(src); git describe --dirty --long --tags)
doxygen:
ifeq ($(TARGET),clean)
@echo "Remove Doxygen files"
@rm -rf doxygen-trtl-output
else
GIT_VERSION=$(GIT_VERSION) EXCLUDE_FILES=$(EXCLUDE_FILES) doxygen ./doxygen-trtl-config
endif
.. _the-mock-turtle-architecture:
===============================
The Mock Turtle Architecture
===============================
......@@ -17,9 +17,10 @@
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
import os
import sys
sys.path.append(os.path.abspath('../software/lib/PyMockTurtle'))
sys.path.append(os.path.abspath('../software/lib/'))
# -- General configuration ------------------------------------------------
......@@ -31,8 +32,12 @@
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = ['sphinx.ext.todo',
'sphinx.ext.coverage']
extensions = ['sphinx.ext.autodoc',
'sphinx.ext.todo',
'sphinx.ext.graphviz',
'sphinx.ext.coverage',
'breathe',
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
......@@ -48,7 +53,7 @@ master_doc = 'index'
# General information about the project.
project = 'Mock Turtle'
copyright = '2018, Federico Vaga <federico.vaga@cern.ch>, Tomasz Wlostowski <Tomasz.Wlostowski@cern.ch>'
copyright = 'CERN 2018'
author = 'Federico Vaga <federico.vaga@cern.ch>, Tomasz Wlostowski <Tomasz.Wlostowski@cern.ch>'
# The version info for the project you're documenting, acts as replacement for
......@@ -67,6 +72,8 @@ release = '4.0.0'
# Usually you set "language" from the command line for these cases.
language = None
highlight_language = 'none'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
......@@ -190,3 +197,8 @@ epub_copyright = copyright
epub_exclude_files = ['search.html']
breathe_projects = {
"trtl": "doxygen-trtl-output/xml/",
}
breathe_default_project = "trtl"
==========================
The *Alarm Clock* Demo
==========================
The *Alarm Clock* demo is a firmware program that makes use of the
*Host Message Queue* to receive configuration options and to send
messages to the host system.
This program makes use of the :ref:`sw:fw:frm` and shows the use
of *variables*. The application exports to the host a set of local
variables which are used to configure the application.
::
mockturtle-variable -D $DEVID
The application counts the number of internal iterations; this is represented
by the AC_TIME variable. According to the local variable AC_PERIOD_UPDATE it
periodically sends messages to the host system to notify the current time.
Using the variables AC_ALARM_EN and AC_ALARM_ITER, It is possible to enable and
configure an alarm which will produce a message.
The communication with the host happens through the message queues as described
in the following table.
.. list-table::
:widths: 1 1 2
:header-rows: 1
* - Direction
- Index
- Description
* - Input
- 0
- Receive configuration from the host
* - Output
- 0
- Send configuration to the host
* - Output
- 1
- Send notifications
.. literalinclude:: ../../demos/alarm_clock/firmware/fw-01/fw-ac.c
==============================
The *Data Generator* Demo
==============================
The *Data Generator* demo is a firmware program that pretends to be a
little acquisition system. It makes use of the *Host Message Queue* to
receive configuration options and to send messages to the host system.
This program makes use of the :ref:`sw:fw:frm` and shows the use
of *variables* and *buffers*. The application exports to the host a
set of local variables which are used to configure the application; it
also exports buffers for data array or structures.
::
mockturtle-variable -D $DEVID
mockturtle-buffer -D $DEVID
The application periodically generates data. The generation period can be
adjusted using the variable DG_PERIOD_UPDATE. The application generates
sequential values which can be adjusted using gain and offset; these 2
parameters are part of a data structure exported with the buffer DG_CONF.
Finally, it is possible to read the data from the buffer DG_DATA.
The communication with the host happens through the message queues as described
in the following table.
.. list-table::
:widths: 1 1 2
:header-rows: 1
* - Direction
- Index
- Description
* - Input
- 0
- Receive configuration from the host
* - Output
- 0
- Send configuration to the host
* - Output
- 1
- Send data to the host
.. literalinclude:: ../../demos/data_generator/firmware/fw-01/fw-dg.c
====================
The *FMC SVEC* Demo
====================
The *FMC SVEC* demo is a complete demo that uses hardware features from
the `FMC SVEC carrier`_. This demo offers an example of all layers, so it is
a good starting point to understand how to create a complete Mock Turtle
application.
The main aim of this demo is to handle the SVEC LEDs and LEMOs. The LEDs can be
turned *on* (*red*, *green*, *orange*) and *off*. The LEMOs can be set to *input*
or *output*; when output they can be set to *high* or *low* voltage; when
input it is possible to read their status (*high* or *low*).
.. todo::
add HDL description here
This demo has two firmwares. One is named *autosvec*, the other *manualsvec*.
The *autosvec* firmware runs autonomously without any communication with the host
system or a remote node and for this reason it is the simplest one
It does not use :ref:`sw:fw:frm` but only :ref:`sw:fw:lib`. This firmware does
the following things:
- it turns *on* and *off* all the LEDs one after the other;
- it reproduce on LEMO connector 2 whatever state is on LEMO connector 1
- it generates square signals on LEMO connectors 3
- it generates square signals on LEMO connectors 4
- it periodically prints messages on the console with the GPIO status (LEDs
and LEMOs)
.. literalinclude:: ../../demos/fmc-svec-carrier/software/firmware/fw-01/fw-svec.c
The *manualsvec* firmware offers a manual control of all LEDs and LEMOs.
It does use :ref:`sw:fw:frm`. This firmware does the following things:
- it exportes as :ref:`sw:fw:frm:var` the device peripheral registers
to configure LEDs and LEMOs
- to exports a local :ref:`sw:fw:frm:buf` where the user can read and write
(it is not used)
- it exports a local :ref:`variable <sw:fw:frm:var>` that can be used to
stop/start an *autosvec* firmware running on a different core.
.. literalinclude:: ../../demos/fmc-svec-carrier/software/firmware/fw-02/fw-svec.c
This firmware has also a support layer on the host side. This is not really necessary
because you can always uses the generic Mock Turtle tools
to :ref:`read/write variables <tools:mockturtle-variable>` and
to :ref:`read/write buffers <tools:mockturtle-buffer>`; but for the sake of make this
demos as complete as possible we added an host support layer which is made of a
C library and a C program. A part from the standard operations to open and close a
device, the library exports an API to handle the LEDs and LEMOs status and functions
to set/get a dummy data structure. This library is mainly a wrapper around
the Mock Turtle one.
.. literalinclude:: ../../demos/fmc-svec-carrier/software/lib/libsvec.c
At the end, the host program. This program is a command line tool that uses the
svec library described above to handle the SVEC board. Again, it gives users
the possibility to play with LEDs and LEMOs status.
.. literalinclude:: ../../demos/fmc-svec-carrier/software/tools/mockturtle-svec.c
.. _`FMC SVEC carrier`: https://www.ohwr.org/projects/svec/
==========================
The *Hello World* Demo
==========================
The *Hello World* demo is a firmware program that prints
over the serial interface the string ``"Hello World"`` and exit.
This program makes use of the :ref:`sw:fw:lib`.
::
minicom -D $TTYTRTL
# On a different shell instance
mockturtle-cpu-restart -D $DEVID -i $CPU_INDEX
.. literalinclude:: ../../demos/hello_world/firmware/fw-01/fw-hello.c
There is also the *Hello World* demo based on the :ref:`sw:fw:frm`.
This demo will print on the serial interface general informations
about the firmware application.
::
minicom -D $TTYTRTL
# On a different shell instance
mockturtle-cpu-restart -D $DEVID -i $CPU_INDEX
.. literalinclude:: ../../demos/hello_world_framework/firmware/fw-01/fw-hellofrm.c
============
The Demos
============
This is a collection of demo applications which main purpose is to
introduce the users to the Mock Turtle development. In the following
demos you will find some example code to run and test the applications.
You will notice the usage of environment variable; these variables, of
course, depend of your environment. Here a list of used variable
TRTL
This is the path to the root directory of the Mock Turtle project.
CROSS_COMPILE_TARGET
This is the path to the cross-compiler for the soft-CPU used by Mock Turtle.
DEVID
This is the device-id that uniquely identify a Mock Turtle instance. This
is an integer number in hexadecimal representation (e.g. 0x0201)
CPU_INDEX
This is used to select a Mock Turtle soft-CPU starting from 0.
TTYTRTL
This is the path to the TTY device in /dev (e.g. /dev/ttyTRTL0)
DEMO
This is the path to the demo application directory that you can find in the
``software/demos`` main directory.
In principle you can compile all the demos by running *make* in the main
directory. Then you can load the firmware using
:ref:`tools:mockturtle-firmware-loader` and restart the CPU with
:ref:`tools:mockturtle-cpu-restart`::
# Compile
make -C $DEMO
# Program
mockturtle-loader -D $DEVID -i $CPU_INDEX -f $DEMO/firmware/fw01/hello_world.bin
# Restart and start execution
mockturtle-cpu-restart -D $DEVID -i $CPU_INDEX
.. toctree::
:maxdepth: 2
:caption: Contents:
hello-world
data-generator
alarm-clock
fmc-svec-carrier
PROJECT_NAME = "Mock Turtle"
PROJECT_NUMBER = $(GIT_VERSION)
PROJECT_BRIEF = "Mock Turtle"
PROJECT_LOGO =
OUTPUT_DIRECTORY = doxygen-trtl-output
CREATE_SUBDIRS = YES
TAB_SIZE = 8
OPTIMIZE_OUTPUT_FOR_C = YES
EXTRACT_STATIC = YES
CASE_SENSE_NAMES = YES
WARN_NO_PARAMDOC = YES
INPUT = ../software/lib ../software/rt ../software/include
RECURSIVE = YES
EXCLUDE = ../software/rt/scripts ../software/lib/PyMockTurtle ../software/kernel
GENERATE_HTML = NO
GENERATE_LATEX = NO
GENERATE_XML = YES
trtl-rt-library
trtl-rt-framework
GIT_VERSION = $(shell cd $(src); git describe --dirty --long --tags)
DOC ?= ..
#FIXME glossary words lost during pandoc conversion
INPUT_SRC := $(DOC)/../rt/
INPUT_SRC += $(DOC)/../include/mockturtle-common.h
INPUT_SRC += $(DOC)/../lib/
INPUT_LIB := $(INPUT_SRC)
INPUT_LIB += $(DOC)/doxygen
FIRMWARE_LIBRARY := library-serial.md
FIRMWARE_LIBRARY += library-shared-memory.md
FIRMWARE_LIBRARY += library-message-queue.md
FIRMWARE_LIBRARY += library-utilities.md
FIRMWARE_LIBRARY += library.md
FIRMWARE_FRAMEWORK := framework.md
FIRMWARE_FRAMEWORK +=framework-action.md
FIRMWARE_FRAMEWORK += framework-buffer.md
FIRMWARE_FRAMEWORK += framework-common.md
FIRMWARE_FRAMEWORK += framework-variable.md
FIRMWARE_FRAMEWORK += framework-mqueue.md
FIRMWARE_FRAMEWORK += framework-debug.md
FIRMWARE := firmware.md
FIRMWARE += $(FIRMWARE_LIBRARY)
FIRMWARE += $(FIRMWARE_FRAMEWORK)
LINUX_HOST := linux.md
LINUX_HOST += linux-library.md
LINUX_HOST += linux-library-cpu.md
LINUX_HOST += linux-library-shm.md
LINUX_HOST += linux-library-hmq.md
all: doxy-fw-lib
PANDOC_OPTIONS := --listing --template default.latex -V documentclass=article -V fontsize=10pt -V papersize=a4paper
library.tex: $(DOC)/integration/software/firmware/library-introduction.tex $(DOC)/integration/software/firmware/library-configuration.tex
@pandoc $(PANDOC_OPTIONS) -f latex -o $@ $^
framework.tex: $(DOC)/integration/software/firmware/framework-introduction.tex $(DOC)/integration/software/firmware/framework-configuration.tex
@pandoc $(PANDOC_OPTIONS) -f latex -o $@ $^
firmware.tex: $(DOC)/integration/software/firmware-introduction.tex $(DOC)/integration/software/firmware-configuration.tex
@pandoc $(PANDOC_OPTIONS) -f latex -o $@ $^
%.tex: $(DOC)/integration/software/firmware/%.tex
@pandoc $(PANDOC_OPTIONS) -f latex -o $@ $<
%.tex: $(DOC)/integration/software/%.tex
@pandoc $(PANDOC_OPTIONS) -f latex -o $@ $<
%.md: %.tex
# Start by removing labels and ref from the tex file.
# They will not work and leave visible traces
@sed -i -e "s/\\label{.*}//g" -e "s/ref{.*}//g" $<
@pandoc --reference-links -o $@ $<
@if [ "$@" = "library.md" ] || [ "$@" = "framework.md" ]; then \
sed -i "1s/^/@ingroup firmware\n/" $@;\
fi
@sed -i "1s/^/@addtogroup $*\n/" $@
doxy-fw-lib: $(FIRMWARE) $(LINUX_HOST)
@GIT_VERSION="$(GIT_VERSION)" \
EXAMPLE_PATH="$(EXAMPLE_LIB)" \
INPUT="$(INPUT_LIB)" \
doxygen doxygen-trtl-rt-library
@rm -rf *.md *.tex
PROJECT_NAME = "White Rabbit Node Core - Software"
PROJECT_NAME = "Mock Turtle Firmware Framework"
PROJECT_NUMBER = $(GIT_VERSION)
PROJECT_BRIEF = $(BRIEF)
PROJECT_LOGO =
OUTPUT_DIRECTORY = $(OUTPUT)
OUTPUT_DIRECTORY = "trtl-rt-framework"
CREATE_SUBDIRS = YES
TAB_SIZE = 8
OPTIMIZE_OUTPUT_FOR_C = YES
......@@ -12,9 +12,10 @@ CASE_SENSE_NAMES = YES
WARN_NO_PARAMDOC = YES
INPUT = ../lib ../kernel/wrnc-user.h
INPUT = ../../rt/framework
RECURSIVE = YES
EXCLUDE = $(EXCLUDE_FILES)
EXCLUDE =
GENERATE_HTML = YES
GENERATE_LATEX = YES
COMPACT_LATEX = YES
PROJECT_NAME = "Mock Turtle Software"
PROJECT_NUMBER = $(GIT_VERSION)
PROJECT_BRIEF =
PROJECT_LOGO =
OUTPUT_DIRECTORY = "trtl-rt-library"
CREATE_SUBDIRS = YES
TAB_SIZE = 8
OPTIMIZE_OUTPUT_FOR_C = YES
EXTRACT_STATIC = YES
EXTRACT_ALL = YES
CASE_SENSE_NAMES = YES
WARN_NO_PARAMDOC = YES
INPUT = $(INPUT)
FILE_PATTERNS = *.c *.h *.md *.py
USE_MDFILE_AS_MAINPAGE = $(MAINPAGE)
RECURSIVE = YES
EXCLUDE =
EXAMPLE_PATH = $(EXAMPLE_PATH)
GENERATE_HTML = YES
GENERATE_LATEX = YES
COMPACT_LATEX = YES
HAVE_DOT = YES
CALL_GRAPH = YES
CALLER_GRAPH = YES
UML_LOOK = YES
\ No newline at end of file
========
Glossary
========
.. glossary::
Control System
It is a system that manage, commands, regulates the behaviour of a set
of devices.
Digital Signal Processing
The use of digital processing to perform a wide variety of signal
processing operations.
Embedded System
It is an autonomus system made of software, hardware (and gateware),
implementing dedicated functions
Firmware
It is an embedded software system running on the Mock Turtle soft-cpu.
Gateware
It is a bitstream which configures an FPGA, or the HDL sources
from which it was generated.
Gateware Core
It is an HDL component part of a more complex gateware design.
Hardware
It is a physical component.
Host
It is the system the hosts the hardware in use.
Host Application
It is an user space program.
HMQ
Host Message Queue
It is a message queue that connects the Mock Turtle to the host system.
MQ
Message Queue
It is a communication system based on queues with FIFO policy. Messages are
put on the queue and they are sent to the programmed destination. Each
message queue has two direction: input and output.
Mock Turtle supports two message queues: host and remote.
RTC
Real-Time Computing
It is an hardware and software system subject to time constraints.
RMQ
Remote Message Queue
It is a message queue that connects the Mock Turtle to a network.
SHM
Shared Memory
It is a memory shared among soft-CPUs and the host system.
Soft CPU
soft-cpu
It is an HDL implementation of a CPU running on an FPGA.
MQ Entry
TODO
User Space
It is a software running on the host and it is not in kernel mode.
This includes libraries and programs.
===============
The HDL Core
===============
.. toctree::
:maxdepth: 2
:caption: Contents:
<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill-opacity="1" color-rendering="auto" color-interpolation="auto" text-rendering="auto" stroke="black" stroke-linecap="square" width="225" stroke-miterlimit="10" shape-rendering="auto" stroke-opacity="1" fill="black" stroke-dasharray="none" font-weight="normal" stroke-width="1" height="372" font-family="'Dialog'" font-style="normal" stroke-linejoin="miter" font-size="12px" stroke-dashoffset="0" image-rendering="auto">
<!--Generated by ySVG 2.5-->
<defs id="genericDefs"/>
<g>
<defs id="defs1">
<clipPath clipPathUnits="userSpaceOnUse" id="clipPath1">
<path d="M0 0 L225 0 L225 372 L0 372 L0 0 Z"/>
</clipPath>
<clipPath clipPathUnits="userSpaceOnUse" id="clipPath2">
<path d="M394 140 L619 140 L619 512 L394 512 L394 140 Z"/>
</clipPath>
</defs>
<g fill="white" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="translate(-394,-140)" stroke="white">
<rect x="394" width="225" height="372" y="140" clip-path="url(#clipPath2)" stroke="none"/>
</g>
<g fill="silver" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,-394,-140)" stroke="silver">
<rect x="394" width="225" height="32" y="300" clip-path="url(#clipPath2)" stroke="none"/>
</g>
<g stroke-linecap="butt" transform="matrix(1,0,0,1,-394,-140)" fill="gray" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" stroke="gray" stroke-width="3" stroke-miterlimit="1.45">
<rect fill="none" x="394" width="225" height="32" y="300" clip-path="url(#clipPath2)"/>
</g>
<g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" font-family="sans-serif" transform="matrix(1,0,0,1,-394,-140)" stroke-linecap="butt">
<text x="497.0078" xml:space="preserve" y="320.1543" clip-path="url(#clipPath2)" stroke="none">API</text>
</g>
<g fill="rgb(255,204,153)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,-394,-140)" stroke="rgb(255,204,153)">
<rect x="394" width="99" height="32" y="220" clip-path="url(#clipPath2)" stroke="none"/>
</g>
<g stroke-linecap="butt" transform="matrix(1,0,0,1,-394,-140)" fill="rgb(255,102,0)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" stroke="rgb(255,102,0)" stroke-width="3" stroke-miterlimit="1.45">
<rect fill="none" x="394" width="99" height="32" y="220" clip-path="url(#clipPath2)"/>
</g>
<g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" font-family="sans-serif" transform="matrix(1,0,0,1,-394,-140)" stroke-linecap="butt">
<text x="399.8477" xml:space="preserve" y="240.1543" clip-path="url(#clipPath2)" stroke="none">Project Library</text>
</g>
<g fill="rgb(255,204,153)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,-394,-140)" stroke="rgb(255,204,153)">
<rect x="394" width="99" height="32" y="140" clip-path="url(#clipPath2)" stroke="none"/>
</g>
<g stroke-linecap="butt" transform="matrix(1,0,0,1,-394,-140)" fill="rgb(255,102,0)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" stroke="rgb(255,102,0)" stroke-width="3" stroke-miterlimit="1.45">
<rect fill="none" x="394" width="99" height="32" y="140" clip-path="url(#clipPath2)"/>
</g>
<g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" font-family="sans-serif" transform="matrix(1,0,0,1,-394,-140)" stroke-linecap="butt">
<text x="417.7568" xml:space="preserve" y="160.1543" clip-path="url(#clipPath2)" stroke="none">program</text>
</g>
<g fill="rgb(255,204,153)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,-394,-140)" stroke="rgb(255,204,153)">
<rect x="520" width="99" height="32" y="140" clip-path="url(#clipPath2)" stroke="none"/>
</g>
<g stroke-linecap="butt" transform="matrix(1,0,0,1,-394,-140)" fill="rgb(255,102,0)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" stroke="rgb(255,102,0)" stroke-width="3" stroke-miterlimit="1.45">
<rect fill="none" x="520" width="99" height="32" y="140" clip-path="url(#clipPath2)"/>
</g>
<g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" font-family="sans-serif" transform="matrix(1,0,0,1,-394,-140)" stroke-linecap="butt">
<text x="543.7568" xml:space="preserve" y="160.1543" clip-path="url(#clipPath2)" stroke="none">program</text>
<rect stroke-linecap="square" x="394" y="332" clip-path="url(#clipPath2)" width="225" height="75" stroke="none" stroke-miterlimit="10"/>
<rect x="394" y="332" clip-path="url(#clipPath2)" fill="none" width="225" height="75" stroke-width="3"/>
<text fill="silver" x="439.9404" xml:space="preserve" y="373.6543" clip-path="url(#clipPath2)" stroke="none">Mock Turtle Black Box</text>
</g>
<g fill="silver" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,-394,-140)" stroke="silver">
<rect x="394" width="225" height="32" y="407" clip-path="url(#clipPath2)" stroke="none"/>
</g>
<g stroke-linecap="butt" transform="matrix(1,0,0,1,-394,-140)" fill="gray" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" stroke="gray" stroke-width="3" stroke-miterlimit="1.45">
<rect fill="none" x="394" width="225" height="32" y="407" clip-path="url(#clipPath2)"/>
</g>
<g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" font-family="sans-serif" transform="matrix(1,0,0,1,-394,-140)" stroke-linecap="butt">
<text x="497.0078" xml:space="preserve" y="427.1543" clip-path="url(#clipPath2)" stroke="none">API</text>
</g>
<g fill="rgb(255,204,153)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,-394,-140)" stroke="rgb(255,204,153)">
<rect x="394" width="225" height="32" y="480" clip-path="url(#clipPath2)" stroke="none"/>
</g>
<g stroke-linecap="butt" transform="matrix(1,0,0,1,-394,-140)" fill="rgb(255,102,0)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" stroke="rgb(255,102,0)" stroke-width="3" stroke-miterlimit="1.45">
<rect fill="none" x="394" width="225" height="32" y="480" clip-path="url(#clipPath2)"/>
</g>
<g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" font-family="sans-serif" transform="matrix(1,0,0,1,-394,-140)" stroke-linecap="butt">
<text x="478.3281" xml:space="preserve" y="500.1543" clip-path="url(#clipPath2)" stroke="none">Firmware</text>
<path fill="none" d="M443.5 260 L443.5 291.9785" clip-path="url(#clipPath2)"/>
<path d="M443.5 252 L438.5 264 L443.5 261 L448.5 264 Z" clip-path="url(#clipPath2)" stroke="none"/>
<path d="M443.5 299.9785 L448.5 287.9785 L443.5 290.9785 L438.5 287.9785 Z" clip-path="url(#clipPath2)" stroke="none"/>
<path fill="none" d="M443.5 180 L443.5 212" clip-path="url(#clipPath2)"/>
<path d="M443.5 172 L438.5 184 L443.5 181 L448.5 184 Z" clip-path="url(#clipPath2)" stroke="none"/>
<path d="M443.5 220 L448.5 208 L443.5 211 L438.5 208 Z" clip-path="url(#clipPath2)" stroke="none"/>
<path fill="none" d="M569.5 180 L569.5 292.0029" clip-path="url(#clipPath2)"/>
<path d="M569.5 172 L564.5 184 L569.5 181 L574.5 184 Z" clip-path="url(#clipPath2)" stroke="none"/>
<path d="M569.5 300.0029 L574.5 288.0029 L569.5 291.0029 L564.5 288.0029 Z" clip-path="url(#clipPath2)" stroke="none"/>
<path fill="none" d="M506.5 447 L506.5 472" clip-path="url(#clipPath2)"/>
<path d="M506.5 439 L501.5 451 L506.5 448 L511.5 451 Z" clip-path="url(#clipPath2)" stroke="none"/>
<path d="M506.5 480 L511.5 468 L506.5 471 L501.5 468 Z" clip-path="url(#clipPath2)" stroke="none"/>
</g>
</g>
</svg>
<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill-opacity="1" color-rendering="auto" color-interpolation="auto" text-rendering="auto" stroke="black" stroke-linecap="square" width="256" stroke-miterlimit="10" shape-rendering="auto" stroke-opacity="1" fill="black" stroke-dasharray="none" font-weight="normal" stroke-width="1" height="214" font-family="'Dialog'" font-style="normal" stroke-linejoin="miter" font-size="12px" stroke-dashoffset="0" image-rendering="auto">
<!--Generated by ySVG 2.5-->
<defs id="genericDefs"/>
<g>
<defs id="defs1">
<clipPath clipPathUnits="userSpaceOnUse" id="clipPath1">
<path d="M0 0 L256 0 L256 214 L0 214 L0 0 Z"/>
</clipPath>
<clipPath clipPathUnits="userSpaceOnUse" id="clipPath2">
<path d="M292 298 L548 298 L548 512 L292 512 L292 298 Z"/>
</clipPath>
</defs>
<g fill="white" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="translate(-292,-298)" stroke="white">
<rect x="292" width="256" height="214" y="298" clip-path="url(#clipPath2)" stroke="none"/>
</g>
<g fill="rgb(153,204,255)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,-292,-298)" stroke="rgb(153,204,255)">
<rect x="292" width="256" height="96" y="298" clip-path="url(#clipPath2)" stroke="none"/>
</g>
<g stroke-linecap="butt" transform="matrix(1,0,0,1,-292,-298)" fill="navy" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" stroke="navy" stroke-width="3" stroke-miterlimit="1.45">
<rect fill="none" x="292" width="256" height="96" y="298" clip-path="url(#clipPath2)"/>
</g>
<g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" font-family="sans-serif" transform="matrix(1,0,0,1,-292,-298)" stroke-linecap="butt">
<text x="486.6963" xml:space="preserve" y="350.1543" clip-path="url(#clipPath2)" stroke="none">library</text>
</g>
<g fill="rgb(153,204,255)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,-292,-298)" stroke="rgb(153,204,255)">
<rect x="292" width="128" height="64" y="330" clip-path="url(#clipPath2)" stroke="none"/>
</g>
<g stroke-linecap="butt" transform="matrix(1,0,0,1,-292,-298)" fill="navy" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" stroke="navy" stroke-width="3" stroke-miterlimit="1.45">
<rect fill="none" x="292" width="128" height="64" y="330" clip-path="url(#clipPath2)"/>
</g>
<g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" font-family="sans-serif" transform="matrix(1,0,0,1,-292,-298)" stroke-linecap="butt">
<text x="323.6885" xml:space="preserve" y="366.1543" clip-path="url(#clipPath2)" stroke="none">framework</text>
</g>
<g fill="silver" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,-292,-298)" stroke="silver">
<rect x="298" width="250" height="64" y="448" clip-path="url(#clipPath2)" stroke="none"/>
</g>
<g stroke-linecap="butt" transform="matrix(1,0,0,1,-292,-298)" fill="gray" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" stroke="gray" stroke-width="3" stroke-miterlimit="1.45">
<rect fill="none" x="298" width="250" height="64" y="448" clip-path="url(#clipPath2)"/>
</g>
<g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" font-family="sans-serif" transform="matrix(1,0,0,1,-292,-298)" stroke-linecap="butt">
<text x="396.167" xml:space="preserve" y="484.1543" clip-path="url(#clipPath2)" stroke="none">firmware</text>
<path fill="none" d="M356 440.0088 L356 402" clip-path="url(#clipPath2)"/>
<path d="M356 448.0088 L361 436.0088 L356 439.0088 L351 436.0088 Z" clip-path="url(#clipPath2)" stroke="none"/>
<path d="M356 394 L351 406 L356 403 L361 406 Z" clip-path="url(#clipPath2)" stroke="none"/>
<path fill="none" d="M471 439.9773 L471 402.0345" clip-path="url(#clipPath2)"/>
<path d="M471 447.9773 L476 435.9773 L471 438.9773 L466 435.9773 Z" clip-path="url(#clipPath2)" stroke="none"/>
<path d="M471 394.0345 L466 406.0345 L471 403.0345 L476 406.0345 Z" clip-path="url(#clipPath2)" stroke="none"/>
</g>
</g>
</svg>
<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill-opacity="1" color-rendering="auto" color-interpolation="auto" text-rendering="auto" stroke="black" stroke-linecap="square" width="256" stroke-miterlimit="10" shape-rendering="auto" stroke-opacity="1" fill="black" stroke-dasharray="none" font-weight="normal" stroke-width="1" height="236" font-family="'Dialog'" font-style="normal" stroke-linejoin="miter" font-size="12px" stroke-dashoffset="0" image-rendering="auto">
<!--Generated by ySVG 2.5-->
<defs id="genericDefs"/>
<g>
<defs id="defs1">
<clipPath clipPathUnits="userSpaceOnUse" id="clipPath1">
<path d="M0 0 L256 0 L256 236 L0 236 L0 0 Z"/>
</clipPath>
<clipPath clipPathUnits="userSpaceOnUse" id="clipPath2">
<path d="M307 312 L563 312 L563 548 L307 548 L307 312 Z"/>
</clipPath>
</defs>
<g fill="white" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="translate(-307,-312)" stroke="white">
<rect x="307" width="256" height="236" y="312" clip-path="url(#clipPath2)" stroke="none"/>
</g>
<g fill="silver" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,-307,-312)" stroke="silver">
<rect x="307" width="256" height="96" y="312" clip-path="url(#clipPath2)" stroke="none"/>
</g>
<g stroke-linecap="butt" transform="matrix(1,0,0,1,-307,-312)" fill="gray" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" stroke="gray" stroke-width="3" stroke-miterlimit="1.45">
<rect fill="none" x="307" width="256" height="96" y="312" clip-path="url(#clipPath2)"/>
</g>
<g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" font-family="sans-serif" transform="matrix(1,0,0,1,-307,-312)" stroke-linecap="butt">
<text x="406.3213" xml:space="preserve" y="364.1543" clip-path="url(#clipPath2)" stroke="none">Programs</text>
</g>
<g fill="rgb(127,191,255)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,-307,-312)" stroke="rgb(127,191,255)">
<rect x="307" width="256" height="96" y="452" clip-path="url(#clipPath2)" stroke="none"/>
</g>
<g stroke-linecap="butt" transform="matrix(1,0,0,1,-307,-312)" fill="navy" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" stroke="navy" stroke-width="3" stroke-miterlimit="1.45">
<rect fill="none" x="307" width="256" height="96" y="452" clip-path="url(#clipPath2)"/>
</g>
<g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" font-family="sans-serif" transform="matrix(1,0,0,1,-307,-312)" stroke-linecap="butt">
<text x="313" xml:space="preserve" y="504.1543" clip-path="url(#clipPath2)" stroke="none">Driver</text>
</g>
<g fill="rgb(153,204,255)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,-307,-312)" stroke="rgb(153,204,255)">
<rect x="371" width="192" height="64" y="452" clip-path="url(#clipPath2)" stroke="none"/>
</g>
<g stroke-linecap="butt" transform="matrix(1,0,0,1,-307,-312)" fill="navy" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" stroke="navy" stroke-width="3" stroke-miterlimit="1.45">
<rect fill="none" x="371" width="192" height="64" y="452" clip-path="url(#clipPath2)"/>
</g>
<g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" font-family="sans-serif" transform="matrix(1,0,0,1,-307,-312)" stroke-linecap="butt">
<text x="377" xml:space="preserve" y="488.1543" clip-path="url(#clipPath2)" stroke="none">Library</text>
</g>
<g fill="rgb(178,216,255)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,-307,-312)" stroke="rgb(178,216,255)">
<rect x="435" width="128" height="32" y="452" clip-path="url(#clipPath2)" stroke="none"/>
</g>
<g stroke-linecap="butt" transform="matrix(1,0,0,1,-307,-312)" fill="navy" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" stroke="navy" stroke-width="3" stroke-miterlimit="1.45">
<rect fill="none" x="435" width="128" height="32" y="452" clip-path="url(#clipPath2)"/>
</g>
<g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" font-family="sans-serif" transform="matrix(1,0,0,1,-307,-312)" stroke-linecap="butt">
<text x="453.8096" xml:space="preserve" y="472.1543" clip-path="url(#clipPath2)" stroke="none">Python module</text>
</g>
<g stroke-linecap="butt" transform="matrix(1,0,0,1,-307,-312)" fill="rgb(153,153,153)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" stroke-dasharray="6,2" stroke="rgb(153,153,153)" stroke-miterlimit="1.45">
<path fill="none" d="M344.2719 416.0352 L344.2719 443.9783" clip-path="url(#clipPath2)"/>
<path d="M344.2719 408.0352 L339.2719 420.0352 L344.2719 417.0352 L349.2719 420.0352 Z" clip-path="url(#clipPath2)" stroke="none"/>
<path d="M344.2719 451.9783 L349.2719 439.9783 L344.2719 442.9783 L339.2719 439.9783 Z" clip-path="url(#clipPath2)" stroke="none"/>
<path fill="none" stroke-dasharray="none" d="M413 416.02 L413 443.9931" clip-path="url(#clipPath2)" stroke="black"/>
<path fill="black" stroke-dasharray="none" d="M413 408.02 L408 420.02 L413 417.02 L418 420.02 Z" clip-path="url(#clipPath2)" stroke="none"/>
<path fill="black" stroke-dasharray="none" d="M413 451.9931 L418 439.9931 L413 442.9931 L408 439.9931 Z" clip-path="url(#clipPath2)" stroke="none"/>
<path fill="none" stroke-dasharray="none" d="M499 416.0182 L499 444" clip-path="url(#clipPath2)" stroke="black"/>
<path fill="black" stroke-dasharray="none" d="M499 408.0182 L494 420.0182 L499 417.0182 L504 420.0182 Z" clip-path="url(#clipPath2)" stroke="none"/>
<path fill="black" stroke-dasharray="none" d="M499 452 L504 440 L499 443 L494 440 Z" clip-path="url(#clipPath2)" stroke="none"/>
</g>
</g>
</svg>
......@@ -7,11 +7,16 @@ Welcome to Mock Turtle's documentation!
=======================================
.. toctree::
:maxdepth: 2
:maxdepth: 1
:caption: Contents:
glossary
introduction
architecture
software/index
hdl/index
tools/index
demos/index
Indices and tables
......
.. _`sw:fw:frm`:
==================================
The Mock Turtle Firmware Framework
==================================
Mock Turtle firmware framework guides users development by
keeping them focused only on the core logic without the need to deal
with Mock Turtle architectural details.
This API is available by including ``mockturtle-framework.h`` in your source file.::
#include <mockturtle-framework.h>
We recommend this framework to develop Mock Turtle firmwares. You should
consider alternatives if you see that it’s consuming too much memory or
the performances are not enough for your application.
.. note::
This framework internally uses the :ref:`sw:fw:lib`
Application
===========
Firmwares developed with this framework need to be described by
:c:type:`trtl_fw_application`. You should declare a new :c:type:`trtl_fw_application`
and initialize it using :c:func:`trtl_fw_init` .::
#include <mockturtle-framework.h>
struct trtl_application app = {
.name = "myfirmware",
.fpga_id_compat = NULL,
.fpga_id_compat_n = 0,
.version = {
.id = 0x12345678,
.version = RT_VERSION(1, 0),
.git = GIT_VERSION,
},
};
int main()
{
trtl_dw_init(&app);
return 0;
}
The Mock Turtle is FPGA based, this means that the firmwares are
typically loaded by the host. The procedure is error prone, so it may
happen to load the wrong firmware with unpredictable consequences. To
limit the damage, the ``fpga_id_compat`` can be used to declare a
list of compatible gateware identifiers. The firmware framework will
refuse to execute the firmware when it is not compatible with the
gateware according to the given list. To disable this validation step, do
not provide a compatibility list (like in the example above).
.. doxygenstruct:: trtl_fw_application
:members:
.. doxygenstruct:: trtl_fw_version
:members:
.. doxygenfunction:: trtl_fw_init
Actions
========
The *action* is s function that get executed when a special message
arrives through a mq slot. In order words, an action is similar to an RPC.
The firmware framework relies on the :ref:`sw:proto:hmq` to make this work.
The mechanism is quite simple. The Mock Turtle message header has a
dedicated flag to mark a message as an RPC call
:c:macro:`TRTL_HMQ_HEADER_FLAG_RPC`. When this flag is set, the firmware
framework interprets the header’s message-id as action-id. Thus, the
correspondent function get executed.
This framework support up to :c:macro:`__TRTL_MSG_ID_MAX` actions.
Part of it (:c:macro:`__TRTL_MSG_ID_MAX_TRTL`) is reserved for internal use,
the rest (:c:macro:`__TRTL_MSG_ID_MAX_USER`) can be used to implement new
actions. The reserved IDs are at the end of the number space and they are
defined in :c:type:`trtl_msg_id`.
The declaration of a new user action consists in 4 steps:
#. enumerate the action IDs, share it with host;
#. implement the function to execute;
#. add the function to the action list, and map it to an action-id.
The framework uses the message id in :c:type:`trtl_hmq_header`
as action-id to execute the functions mapped here;
#. export the action list in the :c:type:`trtl_fw_application` data structure;
The framework does not execute actions automatically. Once the actions
are declared, the user must ask the framework to dispatch incoming actions.
This is performed by :c:func:`trtl_fw_mq_action_dispatch`, which listens for
RPC messages on a given mq. Here an example.::
#include <mockturtle-framework.h>
/* [POINT 1] */
enum id_actions {
MY_ACTION_ID = 0,
/* ... */
};
/* [POINT 2] */
static int my_action(struct trtl_msg *msg_i, struct trtl_msg *msg_o)
{
/* ... */
}
/* [POINT 3] */
static trtl_fw_action_t *actions[] = {
[MY_ACTION_ID] = my_action,
/* ... */
};
/* POINT [4]*/
struct trtl_application app = {
/* ... */
/* Export Actions */
.actions = actions,
.n_actions = ARRAY_SIZE(actions),
};
int main()
{
int err;
trtl_fw_init(&app);
while (1) {
/* ... */
err = trtl_fw_mq_action_dispatch(TRTL_HMQ, 0);
/* ... */
}
return 0;
}
.. doxygentypedef:: trtl_fw_action_t
.. doxygenfunction:: trtl_fw_mq_action_dispatch
.. _`sw:fw:frm:var`:
Variables
==========
The firmware framework offers the possibility to export local variables
to the host system. Variables must be declared using the
:c:type:`trtl_fw_variable` and then exported in your
:c:type:`trtl_fw_application`.
The mean of variable in this context is extended to any memory location:
local variable, Mock Turtle registers, device peripheral registers
and so on.
The framework handles the variable exchange as a special action.
Internally, the framework defines actions to write and to read
variables. This implies that :c:func:`trtl_fw_mq_action_dispatch` must
be used to dispatch incoming actions::
#include <mockturtle-framework.h>
#define REGISTER_TAI_SEC (CPU_LR_BASE + 0xC)
static int var1;
static int var2;
struct trtl_fw_variable variables[] = {
[0] = {
.addr = (void *)&var1,
.mask = 0xFFFFFFFF,
.offset = 0,
.flags = 0,
},
[1] = {
.addr = (void *)&var2,
.mask = 0xFFFFFFFF,
.offset = 0,
.flags = 0,
},
[2] = {
.addr = (void *)REGISTER_TAI_SEC,
.mask = 0xFFFFFFFF,
.offset = 0,
.flags = 0,
},
};
struct trtl_fw_application app = {
/* ... */
.variables = variables,
.n_variable = ARRAY_SIZE(variables),
};
int main()
{
/* ... */
while (1) {
trtl_fw_mq_action_dispatch(TRTL_HMQ, 0);
/* ... */
}
return 0;
}
The user can define any number of variables, the firmware framework does
not impose any constraint.
From the host you can read/write the variable by using the
:ref:`tools:mockturtle-variable` tool.::
$ mockturtle-variable -D 0xdead -i 0 read 0 0 0
[0] 0x00000100
[1] 0x00123fcb
[2] 0x003f42ca
In chapter :ref:`sw:lnx:lib:hmq` you can find the correspondent host API,
which in few words consists in two function: :c:func:`trtl_fw_variable_set`
and :c:func:`trtl_fw_variable_get`.
What we have seen till now it is handled automatically by this framework.
The user can send, asynchronously, variables of choice using the function
:c:func:`trtl_fw_mq_send_buf`.
.. doxygenfunction:: trtl_fw_mq_send_uint32
.. _`sw:fw:frm:buf`:
Buffers
========
The firmware framework offers the possibility to export local buffers to
the host system. The buffers must be declared using the
:c:type:`trtl_fw_buffer` and then exported in your
:c:type:`trtl_fw_application`.
The mean of buffer in this context is extended to any contiguous memory
location.
The framework handles the buffer exchange as a special action.
Internally, the framework defines actions to write and to read buffers.
This implies that :c:func:`trtl_fw_mq_action_dispatch` must
be used to dispatch incoming actions::
#include <mockturtle-framework.h>
static int buf1[32];
static int buf2[16];
struct trtl_fw_buffer buffers[] = {
[0] = {
.buf = buf1,
.size = sizeof(buf1),
},
[1] = {
.buf = buf2,
.size = sizeof(buf2),
},
};
/* ... */
struct trtl_fw_application app = {
/* ... */
.buffers = buffers,
.n_buffer = ARRAY_SIZE(buffers),
};
int main()
{
/* ... */
while (1) {
trtl_fw_mq_action_dispatch(TRTL_HMQ, 0);
/* ... */
}
return 0;
}
The user can define any number of buffers, the firmware framework does
not impose any constraint.
From the host you can read/write the buffer by using the
:ref:`tools:mockturtle-buffer` tool::
$ mockturtle-buffer -D 0xdead -i 0 read 0 32 1 16
Buffer 0 (32 bytes)
0000 : 0x00000001 0x34597332 0x12393903 0xf423a4c4
0004 : 0x00000005 0x32432ffe 0x432bbff3 0x2232342b
Buffer 1 (16 bytes)
0000 : 0x03fffffe 0x07fffffe 0x0ffffffe 0x1ffffffe
In chapter :ref:`sw:lnx:lib:hmq` you can find the correspondent host API,
which in few words consists in two function: :c:func:`trtl_fw_buffer_set`
and :c:func:`trtl_fw_buffer_get`.
What we have seen till now it is handled automatically by this framework.
The user can send, asynchronously, buffer of choice using the function
:c:func:`trtl_fw_mq_send_buf`.
.. doxygenfunction:: trtl_fw_mq_send_buf
Utilities
=========
This is a collection of miscellaneous function that can be of some helpers.
.. doxygenfunction:: trtl_fw_time
.. doxygenfunction:: trtl_fw_message_error
.. doxygenfunction:: trtl_fw_print_message
.. doxygenfunction:: trtl_fw_print_header
.. doxygenfunction:: trtl_fw_print_data
.. _`sw:fw:lib`:
====================================
The Mock Turtle Firmware Library
====================================
The Mock Turtle firmware library offers a set of macros and functions
for the basic interaction with Mock Turtle resources.
This API is available by including ``mockturtle-rt.h`` in your source file.::
#include <mockturtle-rt.h>
We strongly recommend users to use this library to develop any Mock
Turtle firmware.
.. warning::
Any firmware develop without this library will not receive any kind
of support.
Read And Write Memory Locations
===============================
This firmware library offers a set of function to read/write memory locations.
You can access local register with :c:func:`lr_readl()` and
:c:func:`lr_writel()`.
You can access device peripherals with :c:func:`dp_readl()` and
:c:func:`dp_writel()`.::
#include <mockturtle-rt.h>
/*
* List of device peripheral cores offsets from the point of view
* of the soft-cpu
*/
#define DP_CORE_1 0x1000
int main ()
{
int val;
/* Read a register from the device peripheral 1 */
lr_writel(0xBADCOFFE, DP_CORE_1 +0x4);
val = dp_readl(DP_CORE_1 + 0x4);
/* Read registers from the local soft-core */
lr_writel(0xDEADBEEF, 0x4);
val = lr_readl(0x4);
}
.. doxygenfunction:: dp_readl
.. doxygenfunction:: dp_writel
.. doxygenfunction:: lr_readl
.. doxygenfunction:: lr_writel
Each Mock Turtle core has a group of GPIO lines which can be used to access
external signals. You can handle the GPIO with the functions
:c:func:`gpio_set()`, :c:func:`gpio_clear()`, :c:func:`gpio_status()`.::
#include <mockturtle-rt.h>
int main ()
{
int val;
gpio_set(11); /* set BIT(11) to 1 */
val = gpio_status(11);
gpio_clear(11); /* set BIT(11) to 0 */
val = gpio_status(11);
}
.. doxygenfunction:: gpio_set
.. doxygenfunction:: gpio_clear
.. doxygenfunction:: gpio_status
All these functions are based on the generic :c:func:`readl()` and
:c:func:`writel()`.::
#include <mockturtle-rt.h>
int main ()
{
/* set GPIO 11 to 1 - using generic write */
writel((1 << 11), TRTL_ADDR_LR(MT_CPU_LR_REG_GPIO_SET));
/* set GPIO 11 to 1 */
gpio_set(11);
}
.. warning::
In order to keep your code clean and future proof, do not use generic
functions when a specific one is available. The example above makes it
evident.
.. doxygenfunction:: readl
.. doxygenfunction:: writel
Message Queue Utilities
=======================
Mock Turtle cores' main communication mechanism is the message queues.
The API is almost identical for both remote and host because most of these
functions have the *message queue type* argument to distinguish them.
You can handle the message queue with the commands: *claim*, *send*,
*discard*, *purge*. For each of these command there is a function that
you can call to execute that command: :c:func:`mq_claim`, :c:func:`mq_send`,
:c:func:`mq_discard`, :c:func:`mq_purge`. A part from performing active
actions on the message queue, sometimes we are interested only in their
status, expecialy we want to know if the message queue input channel is
*not empty* (it means that there is something to read) or the output channel
is *not full* (it means that there space for writing). You can check the queue
status with :c:func:`mq_poll_in` and :c:func:`mq_poll_out`.
The API usage is different for input and for output.
The typical procedure to send (output) messages over is the following.
#. *poll* the mq to see if there is at least an empty entry;
#. *claim* a mq in order to get exclusive access to it;
#. *map* the claimed mq slot in order to get the buffer where to write;
#. *write* your message;
#. *send* the data, which will also release the mq slot;
Here the output example.::
#define HMQ_NUM 0
struct trtl_fw_msg msg;
uint32_t status;
while ((mq_poll_out(TRTL_HMQ) & (1 << HMQ_NUM)) == 0)
; /* wait until queue not full */
mq_claim(TRTL_HMQ, HMQ_NUM);
mq_map_out_message(TRTL_HMQ, HMQ_NUM, &msg);
/* Play with the message queue entry */
mq_send(TRTL_HMQ, HMQ_NUM);
The typical procedure to receive (input) messages is the following.
#. *poll* the mq to see if there is available data on a slot;
#. *map* the mq slot in order to get the slot buffer;
#. *read* your data from the mapped buffer;
#. *discard* the slot, which will erase the data and point to the next
one;
Here the input example.::
#define HMQ_NUM 0
struct trtl_fw_msg msg;
uint32_t status;
while ((mq_poll_in(TRTL_HMQ) & (1 << HMQ_NUM)) == 0)
; /* wait until queue not empty */
mq_map_in_message(TRTL_HMQ, HMQ_NUM, &msg);
/* Play with the message queue entry */
mq_discard(TRTL_HMQ, HMQ_NUM);
The library does not perform any validation on the data you write in
the message. Any kind of overflow control is up to the user who can take
the payload size from the configuration rom using :c:func:`trtl_config_rom_get`.
On the host you can read the messages using the tool :ref:`tools:mockturtle-messages`
.. doxygenenum:: trtl_mq_type
.. doxygenfunction:: mq_poll_in
.. doxygenfunction:: mq_poll_out
.. doxygenfunction:: mq_claim
.. doxygenfunction:: mq_send
.. doxygenfunction:: mq_purge
.. doxygenfunction:: mq_discard
.. doxygenstruct:: trtl_fw_msg
:members:
.. doxygenfunction:: mq_map_out_message
.. doxygenfunction:: mq_map_in_message
These functions are enough to send and receive messages with both HMQ and RMQ.
Following a list of lower level functions which actually are used to implement
the ones above.
.. warning::
In principle, you should never use the lower level API. These functions
are used to provide services for the higher level API
.. doxygenfunction:: trtl_mq_base_address
.. doxygenfunction:: mq_map_out_header
.. doxygenfunction:: mq_map_out_buffer
.. doxygenfunction:: mq_map_in_header
.. doxygenfunction:: mq_map_in_buffer
Shared Memory
=============
This is a collection of functions and macros which purposes are:
- to read/write the Mock Turtle shared memory
- to perform atomic operations on the shared memory
In order to declare a variable in shared memory, instead of the local
soft-core RAM, you have to add ``SMEM`` before your variable declaration::
#include <mockturtle-rt.h>
SMEM int my_variable = 100;
Then you can use a shared memory variable as a normal variable::
#include <mockturtle-rt.h>
SMEM int my_variable = 100;
int main ()
{
int b = 5;
my_variable += 10; /* Not atomic operation */
b = my_variable;
}
The shared memory provides a set of atomic operations, to avoid race conditions
while different cores are writing. There is a dedicated API for such operations.
Here an example that uses all operations.::
#include <mockturtle-rt.h>
SMEM int my_variable = 100;
int main ()
{
int b = 5, t;
smem_atomic_add(&my_variable, 10);
smem_atomic_sub(&my_variable, 10);
smem_atomic_or(&my_variable, 0xF0);
smem_atomic_and_not(&my_variable, 0xF0);
smem_atomic_xor(&my_variable, 0xF0);
t = smem_atomic_test_and_set(&my_variable);
b = my_variable;
}
.. doxygenfunction:: smem_atomic_add
.. doxygenfunction:: smem_atomic_sub
.. doxygenfunction:: smem_atomic_or
.. doxygenfunction:: smem_atomic_and_not
.. doxygenfunction:: smem_atomic_xor
.. doxygenfunction:: smem_atomic_test_and_set
Serial Interface
=================
Over the serial interface you can print formatted string messages.
.. note::
Even if it is potentially possible to use the serial interface to
exchange binary data, this is not supported. The only supported use of
the *Serial Interface* is to send strings to the host system.
This API is based on :c:func:`pp_printf` and its different flavors:
:c:func:`pr_error`, :c:func:`pr_debug`.
Here an example::
#include <mockturtle-rt.h>
int main ()
{
pp_printf("Hello World\n");
pr_debug("%s:%d something here\n", __func__, __LINE__);
pr_error("%s:%d Error Message\n", __func__, __LINE__);
}
On the host side you can read the serial messages using any tool that
can read a TTY interface (e.g. ``cat``, ``minicom``).
Since the standard ``printf`` function is heavy, Mock Turtle offers
a light implementation named :c:func:`pp_printf`. This function relays on
function :c:func:`puts()` to send the strings over the serial interface.
.. doxygenfunction:: pp_printf
.. doxygenfunction:: pr_debug
.. doxygenfunction:: pr_error
.. doxygenfunction:: putchar
.. doxygenfunction:: puts
Host Notification
=================
Mock Turtle has a mechanism that allows firmwares to send arbitrary interrupts
to the host system. This mechanism is used by Mock Turtle software to deliver
special notifications; but this mechanism can be used as well by the user to
deliver custum notifications to their support layer.
The Mock Turtle notifications are enumerated
by :c:type:`trtl_cpu_notification`. The user must start their enumeration
after the value *__TRTL_CPU_NOTIFY_MAX*.
.. doxygenenum:: trtl_cpu_notification
Mock Turtle will deliver a notification to the host when the firmware calls
:c:func:`trtl_notify()` or, suggested for user's notification,
:c:func:`trtl_notify_user()`.
.. doxygenfunction:: trtl_notify
.. doxygenfunction:: trtl_notify_user
Miscellaneous Utilities
=======================
At the end, this chapter is a collection of helpers
.. doxygenfunction:: delay
.. doxygenfunction:: trtl_config_rom_get
.. doxygenfunction:: trtl_get_core_id
==============
The Software
==============
This section explains the Mock Turtle software architecture as wall as
the necessary steps to develop software layers on top of the Mock Turtle
ones.
The software integration discussion will assume that you have a general
understanding of :ref:`the-mock-turtle-architecture`
The Mock Turtle software consists in two main development domains: the
:ref:`sw:fw` and the :ref:`sw:lnx`
(libraries or applications).
The Mock Turtle software stack is made of different layers which main
objectives are:
- to manage the Mock Turtle cores from the host;
- to allow the firmware to access the Mock Turtle resources;
- to provide a communication infrastructure between firmware and host
- to provide a communication infrastructure with remote nodes
The development of a firmware is necessary to make the system work. In
the section :ref:`sw:fw` you will learn how to write a firmware using
the Mock Turtle API.
On the other hand, the development of a software support layer on the
host depends on your needs. If you need a custumized control/monitor
infrastructure for the firmware, then it is recommended to develop
your software support layer(s) on top of the Mock Turtle ones.
Keep in mind that :ref:`tools` can be used for basic control/monitor
operations. This means that for basic requirements you can directly use
the tools without developing any support layer.
We strongly recommend you to start the develpment of a new Mock Turtle
project by using the :ref:`tools:mockturtle-project-creator`.
Following a list of generic topics which are not specific to Linux
development of firmware development.
.. toctree::
:maxdepth: 1
:caption: Contents:
protocol
.. _`sw:lnx`:
Linux Development
=================
It includes an explaination about the host development (libraries or
applications) and the Mock Turtle API on a Linux host. Any future reference
to host in this section will assume a Linux host because it is the only
supported platform for the time being.
Mock Turtle offers 3 interfaces: a Pyhton module, a C library and
a Linux kernel interface. Mock Turtle users are not supposed to use
the driver interface directly.
.. graphviz::
:align: center
:caption: Mock Turtle Linux Interfaces.
digraph layers {
concentrate=true;
node [shape=rectangle, style=filled, penwidth=2];
edge [dir=both]
mt [shape=record, label="<d> driver | <l> library | <p> python", fillcolor=lightblue, color=blue];
usr [label="programs", fillcolor=lightgrey, color=gray];
usr -> mt:d [style=dotted, color=dimgrey];
usr -> mt:l;
usr->mt:p;
}
.. toctree::
:maxdepth: 2
:caption: Contents:
linux-driver
linux-library
linux-python
.. _`sw:fw`:
Firmware Development
====================
This section explains how to write firmwares using the Mock Turtle API.
The Mock Turtle offers 2 API for the firmware development:
:ref:`sw:fw:lib` and :ref:`sw:fw:frm`.
.. graphviz::
:align: center
:caption: Mock Turtle Firmware Interfaces.
digraph layers {
concentrate=true;
node [shape=rectangle, style=filled, penwidth=2];
edge [dir=both]
mt [shape=record, label="<f> framework | <l> library", fillcolor=lightblue, color=blue];
usr [label="user firmware", fillcolor=lightgrey, color=gray];
mt:f -> usr;
mt:l -> usr;
}
It is strongly recommended to use the library because it offers a set of
macros and functions that simplifies the access to the Mock Turtle
resources and to the external gateware cores. This will help mainly in
the development of the firmware core logic.
It is recommended to use the framework because it guides you in the
development by keeping you focused only on your core logic without the
need to deal with the Mock Turtle architecture details.
The framework usage, rather than precluding the user to use library
functions, is complementary to the library.
All the Mock Turtle firmware source code can be found in the directory
``/path/to/mockturtle/software/rt/``.
.. toctree::
:maxdepth: 2
:caption: Contents:
firmware-library
firmware-framework
Building
--------
Mock Turtle has a generic ``Makefile`` that you should include in your
``Makefile`` in order to import all the Mock Turtle building rules.::
TRTL ?= /path/to/mcokturtle/
TRTL_SW = $(TRTL)/software
# Mandatory
OBJS = source1.o
OBJS += source2.o
OBJDIR += some/local/directory
OUTPUT = firmware-name
# Optional (prefer default when possible)
CFLAGS_OPT := -O1
CFLAGS_DBG := -ggdb
EXTRA_CFLGAS :=
MOCKTURTLE_LDSCRIPT := myfirmware.ld
# INCLUDE GENERIC Makefile
include $(TRTL_SW)/rt/Makefile
Here the list of supported Makefile environment variables
OBJS
(Mandatory) List of object files to generate from sources with
the same name. The default is an empty variable, this mean that it
will not compile any source file.
OUTPUT
(Mandatory) Final binary name (the firmware).
CFLAGS_OPT
(Optional) Optimization level. The default is ``-Os``.
CFLAGS_DBG
(Optional). Debug information. The default is ``-ggdb``.
EXTRA_CFLAGS
(Optional) Extra compiler flags. The default is an empty string,
so no extra flags.
MOCKTURTLE_LDSCRIPT
(Optional ) Local path to the linker script.
The default is the standard Mock Turtle linker script.
Memory resources on Mock Turtle are very limited and the full framework
may take more space than needed. For this reason Mock Turtle has
*Kconfig* support which allows you to interactivly enable/disable both
library and framework. You should create a local ``Kconfig`` file in
your firmware directory; in this file you must include the generic
one offerd by Mock Turtle.::
mainmenu "Project Firmware Name"
comment "Project specific configuration"
# INCLUDE GENERIC Kconfig
source "Kconfig.mt"
The configuration options are not documented here. For more details
use the help messages provided by Kconfig: run ``make menuconfig``
from your firmware directory.
.. _`sw:lnx:drv`:
=========================
The Linux Device Driver
=========================
The Mock Turtle device driver is a software component that exposes the
Mock Turtle gateware core to the host. Any interaction with the Mock
Turtle gateware core pass trought the device driver. This implies that
if the driver does not support a Mock Turtle feature, neither the other
layers (the library or the Python module) will do.
Requirements
==============
The Mock Turtle device driver has been developed and tested on Linux
3.6. Other Linux versions might work as well but it is not guaranteed.
The FPGA address space must be visible on the host system. This requires
a driver for the FPGA carrier that export the FPGA address space to the
host.
Compile And Install
====================
The Mock Turtle device driver compilation and installation requires only
to execute ``make``.::
$ cd /path/to/mockturtle/software/kernel
$ export LINUX=/path/to/linux/sources
$ make
$ make install
Load Driver
=============
The Mock Turtle device driver module needs to be loaded in order to be
used.::
$ cd /path/to/mockturtle/software/kernel
$ sudo insmod mock-turtle.ko
Following the list of module parameters that can be used to custumize
the driver instance.
.. list-table::
:header-rows: 1
:widths: 25 25 50
* - Name
- Default Value
- Description
* - hmq_buf_max_msg
- 16
- Maximum number of messages stored by the driver for each direction
* - max_slot_con
- 8
- Maximum number of simultaneaus connection to the same HMQ channel
* - max_irq_loop
- 5
- Maximum number of messager to read in a single interrupt
Load Gateware
================
Of course, a Mock Turtle instance must exist on your FPGA in order to be able
to drive it. Loading the gateware bitstream depends on the FPGA carrier in use.
Just keep in mind that you must load the bitstream before adding a Mock Turtle
device instance in the Linux kernel. If you do not do so, you will get crashes
because the device driver will try to access something that has not been
loaded yet.
.. _integration:software:host:linux:platform:
Load Device
=============
The Mock Turtle device driver is based on the platform Linux subsystem
[1]_ . This means that you need a mechanism to load a platform device that
describes the Mock Turtle device. Typically, this mechanism involves the
development of a Linux module or the DeviceTree.
The Mock Turtle device driver expects 5 ``resources`` from the platform
device.
memory address
The gateware core base address within the virtual addres space.
hmq IRQ input
The Linux IRQ number to use for the hmq input.
hmq IRQ output
The Linux IRQ number to use for the hmq output.
console IRQ
The Linux IRQ number to use for the serial interface.
notification IRQ
The Linux IRQ number to use for Mock Turtle cores notifications.
Since not all developer knows how to write such module, you can use the
*platform-device-loader*. This application is part of the CERN BE-CO-HT tools
collection.
If you are not sure about how to write the Linux module to load your
platform device, consider to have a look at the source code templates
from the *platform-device-loader* tool.
Interfaces
==========
.. _`sw:drv:dev`:
Mock Turtle Device
------------------
The Mock Turtle driver exports a *char device* for each Mock Turtle.
In */dev/mockturtle* you will have devices named ``trtl-%04x``
(trtl-<device-id>).
You can find the cores *sysfs* attributes at::
/sys/class/mockturtle/trtl-%04x/
.. list-table::
:align: center
:header-rows: 1
:widths: 25 25 55
* - Name
- Direction
- Description
* - config-rom
- RO
- Binary data containing all the synthesis configuration
* - reset_mask
- RW
- Set or clear the soft-CPUs reset. It is a bit-mask where each bit
correspond to a soft-CPU (e.g. bit 0 -> soft-CPU 0)
* - smem_operation
- RW
- It sets the default operation mode for the shared memory writes
.. _`sw:drv:core`:
Mock Turtle Cores
-----------------
The Mock Turtle driver exports a *char device* for each Mock Turtle core.
All core instances will appear as child of a :ref:`sw:drv:dev`; in
*/dev/mockturtle* you will have devices named ``trtl-%04x-%02d``
(trtl-<device-id>-<cpu-index>). The main purpose of this interface is to
program (or rarely useful dump) firmwares into cores. These devices are
bidirectional, so you can: ``write(2)`` to program a firmware, ``read(2)``
to dump a firmware; ``lseek(2)`` to move to different locations.
Mock Turtle uses the standard TTY layer form the Linux kernel. Each
core has a dedicated serial interface which is used for communications
from the soft-CPU to the host system.
Linux TTY devices appear in the */dev* directory and they are named
*ttytrtl-%04x-%d*.
Since it is a standard TTY interface you can use the tool you like to read it.
For example::
minicom -D /dev/ttytrtl-0001-00
cat /dev/ttytrtl-0001-00
.. note::
The driver does not perform any data processing on the console. In other
words whatever the firmware application writes is replicated on this
interface.
You can find the cores *sysfs* attributes at::
/sys/class/mockturtle/trtl-%04x/trtl-%04x-%02d-%02d
.. list-table::
:align: center
:header-rows: 1
:widths: 25 25 55
* - Name
- Direction
- Description
* - reset
- RW
- It asserts (1) or de-asserts (0) the soft-CPU reset line
* - last_notifications
- RO
- It shows the last notification IDs received (last 128)
Host Message Queue
--------------------
The Mock Turtle driver exports a *char device* for each Mock Turtle HMQ.
All HMQ instances will appear as child of a :ref:`sw:drv:core`; in
*/dev/mockturtle/* you will have devices named ``trtl-%04x-%02d-%02d``
(trtl-<device-id>-<cpu-index>-<hmq-index>). The main purposes of this
interface is to exchange messages and configure filters. These devices
are bidirectional, so you can: ``write(2)`` to send messaged;
``read(2)`` to receive messages; ``poll(2)`` or ``select(2)`` to wait.
This *char device* has also a little set of ``ioctl(2)`` commands to configure
filters: :c:macro:`TRTL_IOCTL_MSG_FILTER_ADD`,
:c:macro:`TRTL_IOCTL_MSG_FILTER_CLEAN`.
.. doxygendefine:: TRTL_IOCTL_MSG_FILTER_ADD
.. doxygendefine:: TRTL_IOCTL_MSG_FILTER_CLEAN
You can find the HMQ *sysfs* attributes at::
/sys/class/mockturtle/trtl-%04x/trtl-%04x-%02d-%02d
.. list-table::
:align: center
:header-rows: 1
:widths: 25 25 55
* - Name
- Direction
- Description
* - empty
- RO
- 1 when the HMQ channel buffer is empty, 0 otherwise (hardware)
* - full
- RO
- 1 when the HMQ channel buffer is full, 0 otherwise (hardware)
* - flush
- WO
- When written it flushes the HMQ from all pending messages
* - statistics/received
- RO
- Total number of messages received through the HMQ channel
* - statistics/sent
- RO
- Total number of messages sent through the HMQ channel
.. [1] https://www.kernel.org/doc/Documentation/driver-model/platform.txt
.. _`sw:lnx:library`:
==============================
The Mock Turtle Linux Library
==============================
The Mock Turtle Library for host system development handles all the Mock
Turtle features and it makes them available to any user. The Mock Turtle
library mandate is to export all the Mock Turtle driver features to
user-space programs in a more user-friendly way without paying much in
terms of the flexibility that the driver offers.
The library layer covers all the driver features; for this reason, the
user should use only the library or the Python module. The user can
still access the Mock Turtle driver directly but it is strongly
discouraged.
Installation
============
Requirements
------------
The Mock Turtle library depends on:
- the standard C library and on;
- the Mock Turtle driver;
Compile And Install
-------------------
The Mock Turtle library can be installed in your environment by running::
cd /path/to/mockturtle/software/lib
make install
This will install both the static library and the shared object library.
When using the shared object library, you can skip the installation and
use the environment variable ``LD_LIBRARY_PATH`` to make the library
visible to your programs/libraries::
$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/mockturtle/software/lib
The CPU Management
==================
The Mock Turtle Linux library has a set of functions dedicated to the
CPU management. This means to be able to:
- load a binary into the memory of a soft-CPU
- dump the memory of a soft-CPU
- start/stop a soft-CPU
- reset/unreset a soft-CPU
The typical use of these functions is to load an executable file into
the soft-CPU. The following listing shows an example::
void progr_cpu(struct trtl_dev *trtl, unsigned int cpu_idx, char *file_name)
{
trtl_cpu_stop(trtl, cpu_idx);
trtl_cpu_disable(trtl, cpu_idx);
trtl_cpu_load_application_file(trtl, cpu_idx, file_name);
trtl_cpu_enable(trtl, cpu_idx);
trtl_cpu_start(trtl, cpu_idx);
}
Initialization
==============
The library initialization is done with function :c:func:`trtl_init()`.
You must initialize the library before calling any library function.
.. doxygenfunction:: trtl_init
Once you are completely done with Mock Turtle you should properly
close the library by calling :c:func:`trtl_exit()`
.. doxygenfunction:: trtl_exit
Open And Close Devices
======================
In order to be able to handle a Mock Turtle device you must open it
with one of the following functions :c:func:`trtl_open`,
:c:func:`trtl_open_by_id` or :c:func:`trtl_open_by_lun`. All these
functions return a device token which is required by most Mock Turtle
functions. When you do not want to use anymore the device, you should
close it with :c:func:`trtl_close`.
.. doxygenfunction:: trtl_open
.. doxygenfunction:: trtl_open_by_id
.. doxygenfunction:: trtl_open_by_lun
.. doxygenfunction:: trtl_close
Mock Turtle Cores Management
============================
Library support for cores' management is limited to the firmware loading
(dumping) and core enable/disable.
.. doxygenfunction:: trtl_cpu_load_application_raw
.. doxygenfunction:: trtl_cpu_dump_application_raw
.. doxygenfunction:: trtl_cpu_load_application_file
.. doxygenfunction:: trtl_cpu_dump_application_file
.. doxygenfunction:: trtl_cpu_enable
.. doxygenfunction:: trtl_cpu_disable
.. doxygenfunction:: trtl_cpu_is_enable
.. doxygenfunction:: trtl_cpu_reset_set
.. doxygenfunction:: trtl_cpu_reset_get
.. _`sw:lnx:lib:hmq`:
Host Message Queue and Messages
===============================
This library has a set of functions to handle HMQs and to send/receveice
messages to/from them.
Whenever you need to remove all the messages from the HMQ you can use
the function :c:func:`trtl_hmq_flush()`. The host system does not have
access to the RMQ. If what you want to achive is a complete flush of
all the message queues (host and remote) you should do it on firmware
side so that the complete flush happens synchronously.
.. doxygenfunction:: trtl_hmq_flush
The Mock Turtle driver has a basic message filtering mechanism. Each
user can add a set of filter on any host message queue. Mock Turtle
will deliver to the user only those messages which pass the filter.
Rembember that this is user filter, this means that on the same
host message queue, different users can have different filters.
.. doxygenfunction:: trtl_hmq_filter_add
.. doxygenfunction:: trtl_hmq_filter_clean
Then, there are the functions to exchange messages with firmwares
running on Mock Turtle. This API offers a minimum set of function
to allow users to send/receive synchronous/asynchronous messages.
This library does not have any knowledge about the message content,
it processes the header but the payload is transfered as is.
Any processing on the payload is left to the user. This is the rule
for most messages, anyway Mock Turtle offers a set of special messages
which are completely handled by Mock Turtle.
.. doxygenfunction:: trtl_msg_poll
.. doxygenfunction:: trtl_msg_sync
.. doxygenfunction:: trtl_msg_async_send
.. doxygenfunction:: trtl_msg_async_recv
Mock Turtle offers a set of special messages which can be used in
combination with the firmware framework to ease the development.
The idea behind these special messages is to offer an API for the most
common operation that you will perform with Mock Turtle. Of course,
you are always free to use the basic message exchange mechanism and
build on top of them your high level API.
.. doxygenfunction:: trtl_fw_ping
.. doxygenfunction:: trtl_fw_version
.. doxygenfunction:: trtl_fw_variable_set
.. doxygenfunction:: trtl_fw_variable_get
.. doxygenfunction:: trtl_fw_buffer_set
.. doxygenfunction:: trtl_fw_buffer_get
Shared Memory
=============
The Mock Turtle shared memory is accessible also from the host.
In some cases accessing the shared memory from host is necessary, but
this is not really encouraged as *normal usage* because it may affect
the Mock Turtle determinism. This API is limited to the basic function
to read and write: :c:func:`trtl_smem_write()`, :c:func:`trtl_smem_write()`.
.. doxygenfunction:: trtl_smem_read
.. doxygenfunction:: trtl_smem_write
Utilities
=========
This library offers a set of handlers.
.. doxygenfunction:: trtl_strerror
.. doxygenfunction:: trtl_count
.. doxygenfunction:: trtl_list
.. doxygenfunction:: trtl_list_free
.. doxygenfunction:: trtl_name_get
.. doxygenfunction:: trtl_print_header
.. doxygenfunction:: trtl_print_payload
.. doxygenfunction:: trtl_print_message
.. doxygenfunction:: trtl_hmq_fd
.. _`sw:lnx:python`:
===============================
The Mock Turtle Python Support
===============================
The Mock Turtle Python Module (*PyMockTurtle*) is a Python module that
wraps the Mock Turtle library described in :ref:`sw:lnx:library`.
Most of the features that the Linux library provides are as well
provided by the PyMockTurtle module.
Installation
============
Requirements
------------
PyMockTurtle depends on:
- Python 3.x;
- Python ctype
- Mock Turtle Linux library ``libmockturtle.so`` installed;
- Mock Turtle Linux driver loaded;
.. warning::
The module has been tested with Python 3.5. In principle it should work
as well on any 3.x version. Compatibility with Python 2.7 has not been
verified. Open an issue if you find Python version incompatibilities.
Install
-------
You can use the Makefile to install PyMockTurtle module::
cd /path/to/mockturtle/software/lib/PyMockTurtle
make install
Alternatively, you can use the *distutil* script that takes care of the module installation in your Python environment::
cd /path/to/mockturtle/software/lib/PyMockTurtle
python setup.py install
On a successful installation you should be able to import PyMockTurtle::
import PyMockTurtle
The installation is not mandatory. What is really important is that
both the shared object library and the Python module are visible to
the Python interpreter. You can use the environment variables
``PYTHONPATH`` and ``LD_LIBRARY_PATH`` to make them visible::
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/mock-turtle-sw/lib
export PYTHONPATH=$PYTHONPATH:/path/to/mock-turtle-sw/lib/PyMockTurtle
python3
>>> import PyMockTurtle
Distribution
------------
If you want to create a package for the distribution of this module, you
can use the ``sdist`` command::
cd /path/to/mock-turtle-sw/lib/PyMockTurtle
python setup.py sdist
This will create the dist directory in which you will find an archive
corrisponding to the version declared in the setup.py script.
.. _`sw:lnx:py:use`:
The PyMockTurlte Basic Usage
============================
The usage of this module is quite straight forward. The first thing
you have to to do is to create an instance for
:py:class:`PyMockTurtle.TrtlDevice`.
The instantiation process will autoconfigure the new object using the
information from the configuration ROM. This means that all the cores
(:py:class:`PyMockTurtle.TrtlCpu`) and the respective host message queues
(:py:class:`PyMockTurtle.TrtlHmq`) will be instanciated automaticaly.::
import PyMockTurtle
trtl = PyMockTurtle.TrtlDevice(0x1)
At this point it should be enough to have a look at :ref:`sw:lnx:py:api`
to start using the object.
.. _`sw:lnx:py:api`:
The PyMockTurtle API
====================
Here you can find the complete *PyMockTurtle* API. PyMockTurtle
exports a set of objects used to handle Mock Turtle components.
Then, it exports a set of *ctype* data structures used to exchange
information with the Mock Turtle layers.
.. note::
Since this Pyhton module is nothing more than a wrapper on top of
a C library, we suggest you to have a look at :ref:`sw:lnx:library`
for a better understanding of this API
PyMockTurtle Objects
--------------------
.. autoclass:: PyMockTurtle.TrtlDevice
:members:
.. autoclass:: PyMockTurtle.TrtlCpu
:members:
.. autoclass:: PyMockTurtle.TrtlHmq
:members:
.. autoclass:: PyMockTurtle.TrtlSmem
:members:
.. autoattribute:: MOD_DIRECT
.. autoattribute:: MOD_ADD
.. autoattribute:: MOD_SUB
.. autoattribute:: MOD_SET
.. autoattribute:: MOD_CLEAR
.. autoattribute:: MOD_FLIP
.. autoattribute:: MOD_TEST_AND_SET
PyMockTurtle Data Structures
----------------------------
.. autoclass:: PyMockTurtle.TrtlFirmwareVersion
:members:
.. autoclass:: PyMockTurtle.TrtlMessage
:members:
.. autoclass:: PyMockTurtle.TrtlHmqHeader
:members:
.. autoclass:: PyMockTurtle.TrtlConfig
:members:
.. autoclass:: PyMockTurtle.TrtlConfigMq
:members:
.. _`sw:common`:
===========================
Common Data Structures
===========================
When exchanging messages between two entities it is always handy
to have a protocol. Any Mock Turtle message queue has an header part and
a payload part. It is within the header part that users put the information
to handle the choosen protocol.
.. _`sw:cfg`:
Configuration ROM
===================
The *configuration ROM* is, indeed, a ROM where at synthesis time we put
information about the synthesis configuration. This configuration is the one
used to tailor Mock Turtle to fit users needs. The configuration can be read,
with different APIs, by both host system and firmwares.
.. doxygenstruct:: trtl_config_rom
:members:
.. doxygenstruct:: trtl_config_rom_mq
:members:
.. doxygendefine:: TRTL_CONFIG_ROM_MQ_SIZE_ENTRIES
.. doxygendefine:: TRTL_CONFIG_ROM_MQ_SIZE_PAYLOAD
.. doxygendefine:: TRTL_CONFIG_ROM_MQ_SIZE_HEADER
.. _`sw:proto:hmq`:
Host Message Queue Protocol
==============================
In order to standardize the message exchange between host and firmwares
a message header has been defined. This header is expected to be in the
message queue header buffer.
Different Mock Turtle layers make a different use of this message header.
The HDL code does not process the header, while the driver uses the
:c:member:`trtl_hmq_header.len` to optimize the amount of data copied.
This protocol is mostly used by libraries and firmwares, which are the
two end-points of Host Message Queue communication channel.
.. doxygenstruct:: trtl_hmq_header
:members:
.. doxygendefine:: TRTL_HMQ_HEADER_FLAG_SYNC
.. doxygendefine:: TRTL_HMQ_HEADER_FLAG_ACK
.. doxygendefine:: TRTL_HMQ_HEADER_FLAG_RPC
.. todo::
Should the framework/library handle sync_id and seq?
.. _`sw:proto:rmq`:
Remote Message Queue Protocol
-------------------------------
Within this project we have defined a protocol for the communication with
the host system. How to handle the communication with remote nodes is left
to the user who can chose among dozen of existing protocols (for example UDP).
.. _tools:
=======================
The Mock Turtle Tools
=======================
This section describes the Mock Turtle tools. The description is limited
to the main purpose of the tool, for more details use the tool’s help
message.
.. toctree::
:maxdepth: 2
:caption: Contents:
lsmockturtle
mockturtle-project-creator
mockturtle-firmware-loader
mockturtle-messages
mockturtle-smem
mockturtle-cpu-restart
mockturtle-tpu-probe
mockturtle-ping
mockturtle-variable
mockturtle-buffer
.. _tools:lsmockturtle:
=================
Mock Turtle List
=================
The Mock Turtle List application (*lsmockturtle*) shows the list of
available Mock Turtle devices. Optionally it shows the configuration ROM
content of each device.
.. _`tools:mockturtle-buffer`:
Mock Turtle Buffer
------------------
The Mock Turtle buffer application(\ *mockturtle-buffer*) allows the
user to read/write the buffers that a firmware exports. The tool works
only with those firmwares developed using the Mock Turtle firmware
framework described in section
`[software-integration:firmware-development:framework] <#software-integration:firmware-development:framework>`__.
.. _`tools:mockturtle-cpu-restart`:
=========================
Mock Turtle CPU Restart
=========================
The Mock Turtle CPU Restart application (*mockturtle-cpu-restart*) is
used to restart a soft-cpu. This will stop the firmware execution and
start it again from the ``main()`` function.
.. _`tools:mockturtle-firmware-loader`:
==============================
Mock Turtle Firmware Loader
==============================
The Mock Turtle Loader application (*mockturtle-firmware-loader*) allows
the user to load a firmware in a soft-cpu. It gives also the possibility
to dump the RAM content from a soft-cpu.
.. _`tools:mockturtle-messages`:
======================
Mock Turtle Messages
======================
The Mock Turtle Messages application (*mockturtle-messages*) can be used
to sniff the traffic over a hmq or to access the serial console of a
soft-cpu.
.. _tools:mockturtle-ping:
=================
Mock Turtle Ping
=================
The purpose of the Mock Turtle Ping application (*mockturtle-ping*) is
to be able to verify that a firmware is running. In addition, the
mockturtle-ping application provides information about the firmware
version running on a Mock Turtle soft-cpu. The tool works only with
those firmwares developed using the Mock Turtle firmware framework
described in section
`[software-integration:firmware-development:framework] <#software-integration:firmware-development:framework>`__.
.. _`tools:mockturtle-project-creator`:
============================
Mock Turtle Project Creator
============================
The process of setting up a new Mock Turtle project can takes hours the
first time if you do not know already what it is expected from the user.
Fortunatelly, this process can be automated and there is not much
knowledge in it.
The Mock Turtle Project Creator (*mockturtle-project-creator*) is a
Python script that creates a basic Mock Turtle project. This project
should be used to start the development of your project.
The generated Mock Turtle project is based on a template and it
includes:
- a project library on top of the Mock Turtle library for the
development of software support layer on Linux host (section
`[integration:software:host:linux:library] <#integration:software:host:linux:library>`__);
- a basic firmware based on the Mock Turtle firmware framework (section
`[software-integration:firmware-development:framework] <#software-integration:firmware-development:framework>`__);
- Makefiles to compile the project
Optionally, the mockturtle-project-creator can generate a git repository
with some initial commits. This will give the possibility to rollback to
the skeleton whenever you want.
.. _tools:mockturtle-smem:
=============================
Mock Turtle Shared Memory
=============================
The Mock Turtle Shared Memory application (*mockturtle-smem*) provides
access to the Mock Turtle shm. The user can read/write any location of
the shm using different access modes.
.. _tools:mockturtle-tpu-probe:
=======================
Mock Turtle TPU Probe
=======================
The Mock Turtle TPU Probe application (*mockturtle-tpu-probe*) is used
to inject TPU probes from an ELF file and to handle other TPU management
options.
.. _`tools:mockturtle-variable`:
=====================
Mock Turtle Variable
=====================
The Mock Turtle variable application(\ *mockturtle-variable*) allows the
user to read/write the variables that a firmware exports. The tool works
only with those firmwares developed using the Mock Turtle firmware
framework described in section
`[software-integration:firmware-development:framework] <#software-integration:firmware-development:framework>`__.
doc/README.md
\ No newline at end of file
......@@ -5,3 +5,13 @@ doxy-wrnc/
*.log
*.out
*~
*.acn
*.acr
*.alg
*.glo
*.glg
*.gls
*.idx
*.ist
*.eps
*.html
\ No newline at end of file
GIT_VERSION = $(shell cd $(src); git describe --dirty --long --tags)
O ?= doxy-wrnc
# Build the documentation with or without the internals details
ifdef SHOW_INTERNALS
EXCLUDE_FILES = ""
BRIEF = "API Documentation - With Internals"
else
EXCLUDE_FILES = "../lib/libwrnc-internal.h"
BRIEF = "API Documentation"
endif
all: doxygen latex
all: doxygen doc
doxygen:
GIT_VERSION=$(GIT_VERSION) EXCLUDE_FILES=$(EXCLUDE_FILES) BRIEF=$(BRIEF) \
OUTPUT=$(O) doxygen ./doxygen-wrnc-config
latex:
latex wrnc.tex
latex wrnc.tex
@which dvipdf > /dev/null; \
if [ $$? -eq 0 ]; then \
dvipdf wrnc.dvi; \
else \
@which dvipdf > /dev/null; \
if [ $$? -eq 0 ]; then \
dvipdfm wrnc.dvi; \
else \
echo "Cannot convert to pdf. dvipdf/dvipdfm missing"; \
fi \
fi \
$(MAKE) -C doxygen all
doc:
latex manual
makeglossaries manual
latex manual
makeglossaries manual # the glossary has internal references
latex manual
dvipdf manual.dvi
clean:
rm -rf $(O)
$(MAKE) -C doxygen
# Latex stuff
rm -f *.dvi *.aux *.out *.log *.backup *.pdf
rm -f *.dvi *.aux *.out *.log *.backup *.pdf *glo *ist *acn
.PHONY: doc doxygen clean
Mock Turtle
===========
The project provide the software necessary to access Mock Turtle
infrastructure on an FPGA.
The software stack for the Mock Turtle is made of:
- a driver that allow you to communication with the Mock Turtle CPUs over
the Host Message Queue mechanism. It exports also a debug interface.
- one library that ease the driver access from user-space
- a Python class that wrap the C library
- a set of command line tools to perform basic operations on the Mock Turtle
components
\ No newline at end of file
......@@ -30,16 +30,29 @@
#endif
/**
* Maximum number of supported message ID
*/
#define __TRTL_MSG_ID_MAX 128
/**
* Maximum number of supported Mock Turtle message ID
*/
#define __TRTL_MSG_ID_MAX_TRTL 32
/**
* Maximum number of supported user message ID
*/
#define __TRTL_MSG_ID_MAX_USER (__TRTL_MSG_ID_MAX - __TRTL_MSG_ID_MAX_TRTL)
/**
* It lists all notification's code.
* @enum trtl_cpu_notification
* It lists all Mock Turtle notification's code.
*/
enum trtl_cpu_notification {
TRTL_CPU_NOTIFY_APPLICATION = 0,
TRTL_CPU_NOTIFY_APPLICATION = 0, /**< anonymous application
notification (user) */
__TRTL_CPU_NOTIFY_MAX,
};
......@@ -82,18 +95,22 @@ enum trtl_msg_id {
/**
* HMQ header descriptor
* HMQ header descriptor. It helps the various software layers to process
* messages.
*/
struct trtl_hmq_header {
/* word 0 */
uint16_t rt_app_id; /**< Real-Time application unique identifier */
uint8_t flags;
uint8_t msg_id; /**< Message identifier */
uint16_t rt_app_id; /**< firmware application unique identifier.
Used to validate a message against the firmware
that receives it*/
uint8_t flags; /**< flags */
uint8_t msg_id; /**< It uniquely identify the message type. The
first __TRTL_MSG_ID_MAX_USER are free use */
/* word 1 */
uint16_t len; /**< message-length */
uint16_t len; /**< message-length in 32bit words */
uint16_t sync_id;/**< synchronous identifier */
/* word 2 */
uint32_t seq; /**< sequence number (automatically set by the library) */
uint32_t seq; /**< sequence number (automatically set by the library?) */
};
......@@ -220,9 +237,16 @@ enum trtl_ioctl_commands {
#define TRTL_IOCTL_SMEM_IO _IOWR(TRTL_IOCTL_MAGIC, TRTL_SMEM_IO, \
struct trtl_smem_io)
/**
* The IOCTL command to add a filter to an HMQ
*/
#define TRTL_IOCTL_MSG_FILTER_ADD _IOW(TRTL_IOCTL_MAGIC, \
TRTL_MSG_FILTER_ADD, \
struct trtl_msg_filter)
/**
* The IOCTL command to remove all filters from an HMQ
*/
#define TRTL_IOCTL_MSG_FILTER_CLEAN _IOW(TRTL_IOCTL_MAGIC, \
TRTL_MSG_FILTER_CLEAN, \
struct trtl_msg_filter)
......@@ -251,8 +275,22 @@ struct trtl_msg {
#define TRTL_CONFIG_ROM_MQ_HEADER_SHIFT 0
#define TRTL_CONFIG_ROM_MQ_HEADER_MASK 0x000000FF
/**
* It extracts the number of message queue entries from the sizes value
* in the configuration ROM
*/
#define TRTL_CONFIG_ROM_MQ_SIZE_ENTRIES(_size) (1 << ((_size & TRTL_CONFIG_ROM_MQ_ENTRIES_MASK) >> TRTL_CONFIG_ROM_MQ_ENTRIES_SHIFT))
/**
* It extracts the maximum payload size (32bit words) from the sizes value
* in the configuration ROM
*/
#define TRTL_CONFIG_ROM_MQ_SIZE_PAYLOAD(_size) (1 << ((_size & TRTL_CONFIG_ROM_MQ_PAYLOAD_MASK) >> TRTL_CONFIG_ROM_MQ_PAYLOAD_SHIFT))
/**
* It extracts the maximum header size (32bit words) from the sizes value in
* in the configuration ROM
*/
#define TRTL_CONFIG_ROM_MQ_SIZE_HEADER(_size) (1 << ((_size & TRTL_CONFIG_ROM_MQ_HEADER_MASK) >> TRTL_CONFIG_ROM_MQ_HEADER_SHIFT))
/**
......@@ -260,7 +298,8 @@ struct trtl_msg {
* Note that there is always an input and output channel for each declaration.
*/
struct trtl_config_rom_mq {
uint32_t sizes;
uint32_t sizes; /**< it contains the MQ sizes. Use the MACROs
to extract them */
uint32_t endpoint_id;
};
......@@ -279,8 +318,8 @@ struct trtl_config_rom {
uint32_t signature; /**< we expect to see a known value */
uint32_t version; /**< Mock Turtle version */
uint32_t pad1[1];
uint32_t clock_freq;
uint32_t flags;
uint32_t clock_freq; /**< clock frequency in Hz */
uint32_t flags; /**< miscellaneous flags */
uint32_t app_id; /**< Application ID */
uint32_t n_cpu; /**< number of CPU */
uint32_t smem_size; /**< shared memory size */
......@@ -288,8 +327,8 @@ struct trtl_config_rom {
uint32_t n_hmq[TRTL_MAX_CPU]; /**< number of HMQ for each CPU */
uint32_t n_rmq[TRTL_MAX_CPU]; /**< number of RMQ for each CPU */
uint32_t pad2[96];
struct trtl_config_rom_mq hmq[TRTL_MAX_CPU][TRTL_MAX_MQ_CHAN];
struct trtl_config_rom_mq rmq[TRTL_MAX_CPU][TRTL_MAX_MQ_CHAN];
struct trtl_config_rom_mq hmq[TRTL_MAX_CPU][TRTL_MAX_MQ_CHAN]; /**< HMQ config */
struct trtl_config_rom_mq rmq[TRTL_MAX_CPU][TRTL_MAX_MQ_CHAN]; /**< RMQ config */
};
......
......@@ -4,22 +4,12 @@
@copyright: Copyright (c) 2015 CERN
@license: GNU Library General Public License version 2 or later
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
SPDX-License-Identifier: LGPL-3.0-or-later
"""
from .PyMockTurtle import TrtlHmqHeader, TrtlMessage, TrtlConfig, \
TrtlCpu, TrtlHmq, TrtlSmem, TrtlDevice, \
TrtlFirmwareVersion, TrtlConfigMq, \
TRTL_CONFIG_ROM_MAX_CPU, \
TRTL_CONFIG_ROM_MAX_HMQ, \
TRTL_CONFIG_ROM_MAX_RMQ
......@@ -32,6 +22,8 @@ __all__ = (
"TrtlHmqHeader",
"TrtlMessage",
"TrtlConfig",
"TrtlConfigMq",
"TrtlFirmwareVersion",
"TRTL_CONFIG_ROM_MAX_CPU",
"TRTL_CONFIG_ROM_MAX_HMQ",
"TRTL_CONFIG_ROM_MAX_RMQ",
......
......@@ -9,11 +9,21 @@
#define __LIBTRTL_INTERNAL_H__
#include "libmockturtle.h"
/**
* Maximum size for device name
*/
#define TRTL_NAME_LEN 16
/**
* Maximum size for device path
*/
#define TRTL_PATH_LEN 64
/**
* Internal descriptor for a TRTL device
*/
struct trtl_desc {
uint32_t devid;
uint32_t devid; /**< device instance identifier */
uint32_t seq; /**< global sequence number for messages sent from
this instance*/
char name[TRTL_NAME_LEN]; /**< Name of the device */
......
......@@ -15,9 +15,9 @@
* Retrieve the current Real-Time Application version running. This is a
* synchronous message.
* @param[in] trtl device token
* @param[in] idx_cpu which CPU
* @param[in] idx_hmq which HMQ
* @param[out] version RT id, RT and GIT version
* @param[in] idx_cpu CPU index
* @param[in] idx_hmq HMQ index
* @param[out] version firmware version
* @return 0 on success, -1 on error and errno is set appropriately
*/
int trtl_fw_version(struct trtl_dev *trtl,
......@@ -43,8 +43,8 @@ int trtl_fw_version(struct trtl_dev *trtl,
/**
* It checks if firmware core is running and answering to messages
* @param[in] trtl device token
* @param[in] idx_cpu which CPU
* @param[in] idx_hmq which HMQ
* @param[in] idx_cpu CPU index
* @param[in] idx_hmq HMQ index
* @return 0 on success, -1 on error and errno is set appropriately
*/
int trtl_fw_ping(struct trtl_dev *trtl,
......@@ -91,9 +91,9 @@ int trtl_fw_ping(struct trtl_dev *trtl,
* This function will change the header content, in particular it will change
* the following fields: msg_id, len
* @param[in] trtl device token
* @param[in] idx_cpu
* @param[in] idx_hmq
* @param[in|out] variables on input variable indexes and values.
* @param[in] idx_cpu CPU index
* @param[in] idx_hmq HMQ index
* @param[in,out] variables on input variable indexes and values.
* On output variable indexes and values.
* @param[in] n_variables number of variables to set. In other words,
* the number of indexes you have in the 'variables' fields
......@@ -147,9 +147,9 @@ int trtl_fw_variable_set(struct trtl_dev *trtl,
* This function will change the header content, in particular it will change
* the following fields: msg_id, flags, len
* @param[in] trtl device token
* @param[in] idx_cpu
* @param[in] idx_hmq
* @param[in|out] variables on input variable indexes. On output variable
* @param[in] idx_cpu CPU index
* @param[in] idx_hmq HMQ index
* @param[in,out] variables on input variable indexes. On output variable
* indexes and values.
* @param[in] n_variables number of variables to set. In other words,
* the number of indexes you have in the 'variables' fields
......@@ -189,8 +189,9 @@ int trtl_fw_variable_get(struct trtl_dev *trtl,
* This function will change the header content, in particular it will change
* the following fields: msg_id, len
* @param[in] trtl device token
* @param[in|out] hdr header to send on input, header received on output
* @param[in|out] tlv structures to get on input, structures values on output
* @param[in] idx_cpu CPU index
* @param[in] idx_hmq HMQ index
* @param[in] tlv the complete buffer
* @param[in] n_tlv number of tlv structures
*/
int trtl_fw_buffer_set(struct trtl_dev *trtl,
......@@ -240,8 +241,10 @@ int trtl_fw_buffer_set(struct trtl_dev *trtl,
* This function will change the header content, in particular it will change
* the following fields: msg_id, flags, len
* @param[in] trtl device token
* @param[in|out] hdr header to send on input, header received on output
* @param[in|out] tlv structures to get on input, structures values on output
* @param[in] idx_cpu CPU index
* @param[in] idx_hmq HMQ index
* @param[in,out] tlv on input tlv with only the type,
* on output the complete buffer
* @param[in] n_tlv number of tlv structures
*/
int trtl_fw_buffer_get(struct trtl_dev *trtl,
......@@ -295,7 +298,7 @@ int trtl_fw_buffer_get(struct trtl_dev *trtl,
/**
* It prints the message header in a human readable format
* @param[in] h message header
* @param[in] msg message
*/
void trtl_print_header(struct trtl_msg *msg)
{
......@@ -316,8 +319,7 @@ void trtl_print_header(struct trtl_msg *msg)
/**
* It prints the payload in a human readable format according
* to the message type
* @param[in] h message header
* @param[in] buf message payload
* @param[in] msg message
*/
void trtl_print_payload(struct trtl_msg *msg)
{
......@@ -377,7 +379,7 @@ void trtl_print_payload(struct trtl_msg *msg)
* It prints a message in a human readable format. This function assumes
* that the message contains a Mock Turtle message header.
* According to the message ID the format may change
* @param[in] msg message to print
* @param[in] msg message
*/
void trtl_print_message(struct trtl_msg *msg)
{
......
......@@ -21,8 +21,21 @@
#include "libmockturtle-internal.h"
/**
* Buffer size for sysfs read
*/
#define TRTL_SYSFS_READ_LEN 32
/**
* The default timeout when communicating with the
* driver: HMQ
*/
const unsigned int trtl_default_timeout_ms = 1000;
/**
* Mock Turtle error code strings
*/
static char *trtl_error_str[] = {
"Cannot parse data from sysfs attribute",
"Invalid slot",
......@@ -37,11 +50,19 @@ static char *trtl_error_str[] = {
NULL,
};
enum trtl_msg_filter_predefiened {
TRTL_MSG_FILTER_ASYNC = 0,
TRTL_MSG_FILTER_SYNC,
/**
* Enumeration for predefined filters
*/
enum trtl_msg_filter_predefined {
TRTL_MSG_FILTER_ASYNC = 0, /**< filter for ASYNC messages */
TRTL_MSG_FILTER_SYNC, /**< filter for SYNC messages */
};
/**
* List predefined filters used within the library
*/
static struct trtl_msg_filter filters[] = {
[TRTL_MSG_FILTER_ASYNC] = {
.flags = 0,
......@@ -84,7 +105,7 @@ char *trtl_strerror(int err)
* you have to un-load (trtl_exit()) e reload (trtl_init()) the library.
* @return 0 on success, otherwise -1 and errno is appropriately set
*/
int trtl_init()
int trtl_init(void)
{
/* As you can see there is nothing to do because everything is
dynamical and does not require a special initialization.
......@@ -105,7 +126,7 @@ int trtl_init()
* you stop to use this library. Then, you cannot use functions from this
* library anymore.
*/
void trtl_exit()
void trtl_exit(void)
{
/* READ trtl_init() */
}
......@@ -186,12 +207,12 @@ void trtl_list_free(char **list)
}
/**
* It opens a TRTL device using a string descriptor. The descriptor correspond
* to the main char device name of the Mock-Turtle.
* @param[in] device name of the device to open
* @return the TRTL token, NULL on error and errno is appropriately set
*
* @return TRTL token, NULL on error and errno is appropriately set
*/
static struct trtl_dev *__trtl_open(const char *device)
{
......@@ -398,6 +419,12 @@ void trtl_close(struct trtl_dev *trtl)
/**
* Generic function that reads from a sysfs attribute
* @param[in] path where to read
* @param[out] buf destination buffer
* @param[in] len number of bytes to read
*
* @return the number of written bytes on success, -1 otherwise and
* errno is set appropriately
*/
static int trtl_sysfs_read(char *path, void *buf, size_t len)
{
......@@ -415,6 +442,12 @@ static int trtl_sysfs_read(char *path, void *buf, size_t len)
/**
* Generic function that writes to a sysfs attribute
* @param[in] path where to write
* @param[in] buf buffer to write
* @param[in] len number of bytes to write
*
* @return the number of written bytes on success, -1 otherwise and
* errno is set appropriately
*/
static int trtl_sysfs_write(char *path, void *buf, size_t len)
{
......@@ -431,6 +464,10 @@ static int trtl_sysfs_write(char *path, void *buf, size_t len)
/**
* Generic function that parse a string from a sysfs attribute
* @param[in] path where to read
* @param[in] fmt like scanf(3)
*
* @return 0 on success, -1 otherwise and errno is set appropriately
*/
static int trtl_sysfs_scanf(char *path, const char *fmt, ...)
{
......@@ -458,6 +495,10 @@ static int trtl_sysfs_scanf(char *path, const char *fmt, ...)
/**
* Generic function that build a string to be written in a sysfs attribute
* @param[in] path where to write
* @param[in] fmt like printf(3)
*
* @return 0 on success, -1 otherwise and errno is set appropriately
*/
static int trtl_sysfs_printf(char *path, const char *fmt, ...)
{
......@@ -499,6 +540,7 @@ int trtl_cpu_reset_get(struct trtl_dev *trtl, uint32_t *mask)
* Assert or de-assert the reset line of the TRTL CPUs
* @param[in] trtl device to use
* @param[in] mask bit mask of the reset-lines
*
* @return 0 on success, -1 otherwise and errno is set appropriately
*/
int trtl_cpu_reset_set(struct trtl_dev *trtl, uint32_t mask)
......@@ -520,6 +562,7 @@ int trtl_cpu_reset_set(struct trtl_dev *trtl, uint32_t mask)
* @param[in] index CPU index
* @param[in] code buffer containing the CPU firmware binary code
* @param[in] length code length
* @param[in] offset memory offset where to start to write the code
*
* The CPU must be in reset mode in order to be programmed. This is
* done automatically by the driver which will leave the CPU in
......@@ -535,10 +578,10 @@ int trtl_cpu_load_application_raw(struct trtl_dev *trtl,
unsigned int offset)
{
struct trtl_desc *wdesc = (struct trtl_desc *)trtl;
char path[TRTL_DEVICE_PATH_LEN];
char path[TRTL_PATH_LEN];
int fd, i = 0;
snprintf(path, TRTL_DEVICE_PATH_LEN, "%s/%s-%02d",
snprintf(path, TRTL_PATH_LEN, "%s/%s-%02d",
wdesc->path, wdesc->name, index);
fd = open(path, O_WRONLY);
if (fd < 0)
......@@ -560,6 +603,7 @@ int trtl_cpu_load_application_raw(struct trtl_dev *trtl,
* @param[in] index CPU index
* @param[out] code buffer containing the CPU firmware binary code
* @param[in] length code length
* @param[in] offset memory offset where to start to write the code
*
* For a reliable dump, the CPU must be in pause. This is done by
* the driver which then will set back the previous situation.
......@@ -573,10 +617,10 @@ int trtl_cpu_dump_application_raw(struct trtl_dev *trtl,
unsigned int offset)
{
struct trtl_desc *wdesc = (struct trtl_desc *)trtl;
char path[TRTL_DEVICE_PATH_LEN];
char path[TRTL_PATH_LEN];
int fd, i = 0, c = 100;
snprintf(path, TRTL_DEVICE_PATH_LEN, "%s/%s-%02d",
snprintf(path, TRTL_PATH_LEN, "%s/%s-%02d",
wdesc->path, wdesc->name, index);
fd = open(path, O_RDONLY);
if (fd < 0)
......@@ -706,6 +750,9 @@ static int trtl_dev_open(struct trtl_desc *wdesc)
* @param[in] wdesc device descriptor
* @param[in] addr memory address where start the operations
* @param[in, out] data value in/to the shared memory
* @param[in] count number of values in data
* @param[in] mod the write modifier to be used on output
* @param[in] is_input 1 for input, 0 for output
* @return 0 on success, -1 otherwise and errno is set appropriately
*/
static int trtl_smem_io(struct trtl_desc *wdesc,
......@@ -773,21 +820,6 @@ int trtl_smem_write(struct trtl_dev *trtl, uint32_t addr, uint32_t *data,
}
/**
* It binds a slot to manage only messages that comply with the given filter
* @param[in] trtl device to use
* @param[in] flt filters to apply
* @param[in] length number of filters
* @return 0 on success, -1 otherwise and errno is set appropriately
*/
int trtl_bind(struct trtl_dev *trtl, struct trtl_msg_filter *flt,
unsigned int length)
{
errno = ETRTL_NO_IMPLEMENTATION;
return -1;
}
/**
* It enables a CPU; in other words, it clear the reset line of a CPU.
* This function is a wrapper of trtl_cpu_reset_set() that allow you to safely
......@@ -1090,7 +1122,7 @@ int trtl_msg_sync(struct trtl_dev *trtl,
/**
* It waits for one of a set of Mock Turtle HMQ to become ready to perform I/O
* @param[in|out] poll specific Mock Turtle poll descriptor
* @param[in,out] trtlp specific Mock Turtle poll descriptor
* @param[in] npolls like in poll(2)
* @param[in] timeout like in poll(2)
* @return like poll(2)
......
......@@ -25,6 +25,10 @@ extern const unsigned int trtl_default_timeout_ms;
struct trtl_dev;
/**
* Maximum string len for sysfs paths
*/
#define TRTL_SYSFS_PATH_LEN 128
......@@ -32,9 +36,9 @@ struct trtl_dev;
* This structure mimic the pollfd structure for the Mock Turtle needs
*/
struct polltrtl {
struct trtl_dev *trtl;
unsigned int idx_cpu;
unsigned int idx_hmq;
struct trtl_dev *trtl; /**< device token */
unsigned int idx_cpu; /**< CPU index */
unsigned int idx_hmq; /**< HMQ index */
short events; /**< like in pollfd poll(2) */
short revents; /**< like in pollfd poll(2) */
};
......@@ -45,37 +49,12 @@ struct polltrtl {
* debug channel as (s)he wants.
*/
struct trtl_dbg {
struct trtl_dev *trtl; /**< token of the device */
unsigned int cpu_index; /**< CPU where read debug messages */
struct trtl_dev *trtl; /**< device token */
unsigned int cpu_index; /**< CPU index */
int fd; /**< file descriptor of the debug interface */
};
/**
* HMQ slot descriptor
* @deprecated it is not necessary anymore
*/
struct trtl_hmq {
struct trtl_dev *trtl; /**< where this slot belong to */
char syspath[TRTL_SYSFS_PATH_LEN];
unsigned int index; /* index of the slot. Note that we have
different kind of slot and each kind start
counting from 0*/
unsigned long flags; /**< flags associated to the slot */
int fd; /**< file descriptor */
};
#define TRTL_NAME_LEN 16
#define TRTL_PATH_LEN 32
#define TRTL_SYSFS_READ_LEN 32
#define TRTL_DEVICE_PATH_LEN 64
#define TRTL_HMQ_INCOMING (1 << 0)
#define TRTL_HMQ_OUTCOMING 0x0
/**
* Error codes for Mock-Turtle applications
*/
......@@ -163,18 +142,13 @@ extern int trtl_cpu_is_enable(struct trtl_dev *trtl, unsigned int index,
* @{
*/
/* FIXME to be tested */
extern int trtl_hmq_filter_add(struct trtl_dev *trtl,
unsigned int idx_cpu,
unsigned int idx_hmq,
struct trtl_msg_filter *filter);
/* FIXME to be tested */
extern int trtl_hmq_filter_clean(struct trtl_dev *trtl,
unsigned int idx_cpu,
unsigned int idx_hmq);
extern int trtl_bind(struct trtl_dev *trtl, struct trtl_msg_filter *flt,
unsigned int length);
extern int trtl_hmq_fd(struct trtl_dev *trtl,
unsigned int idx_cpu,
unsigned int idx_hmq);
......
......@@ -287,9 +287,9 @@ static inline trtl_fw_action_t *rt_action_get(unsigned int msg_id)
/**
* It runs the action associated with the given identifier
* @param[in] id action identifier
* @param[in] msg_i input message for the action
* @param[out] msg_o output message from the action
* @param[in] type MQ type
* @param[in] idx_mq MQ index
* @param[out] msg the incoming message
* @return 0 on success. Otherwise an error code
*
* If the action generates an error, the framework will send
......@@ -337,8 +337,8 @@ static inline int rt_action_run(enum trtl_mq_type type,
/**
* It dispatch messages coming from a given message queue.
* @param[in] mq_in MQ index within mq declaration in rt_application
* @todo provide support for remote queue
* @param[in] type MQ type
* @param[in] idx_mq MQ index
* @return 0 on success. -1 on error
*/
int trtl_fw_mq_action_dispatch(enum trtl_mq_type type, unsigned int idx_mq)
......@@ -590,12 +590,13 @@ static inline int trtl_fw_init_fpga(struct trtl_fw_application *app)
/**
* It validates the RMQ and the HMQ
* It initializes the RMQ and the HMQ
* @param[in] app the user application
* @return 0 on success. -EINVAL on error
*/
static inline int trtl_fw_init_mq(struct trtl_fw_application *app)
{
// TODO purge RMQ
return 0;
}
......@@ -641,16 +642,12 @@ static inline int trtl_fw_init_buffers(struct trtl_fw_application *app)
/**
* The function initializes the library and it does some compatibility check.
*
* Initialization
* - purge all the output host-message-queue
* It initializes the application and it does some compatibility check.
*
* compatibility checks:
* - check bitstream FPGA ID if compatibile with the application. The value in
* app->version.fpga_id will be updated with the FPGA ID from the bitstream
* - check bitstream FPGA ID if compatibile with the application.
* - purge remote message queue
*
* @param[in] app application declaration
* @param[in] app application to initialize
* @return 0 on success. -1 on error
*/
int trtl_fw_init(struct trtl_fw_application *app)
......
......@@ -58,7 +58,9 @@ struct trtl_fw_buffer {
/**
* Real-Time Application Descriptor
* Firmware Application Descriptor.
* It provides a set of useful information used by the framework to
* provide services to users.
*/
struct trtl_fw_application {
const char name[16]; /**< Firmware name*/
......@@ -78,7 +80,7 @@ struct trtl_fw_application {
unsigned int n_actions; /**< number of custum actions */
unsigned int seq; /** sequence number reference */
const struct trtl_config_rom *cfgrom;
const struct trtl_config_rom *cfgrom; /**< configuration ROM */
};
......@@ -101,7 +103,7 @@ extern int trtl_fw_mq_send_buf(enum trtl_mq_type type,
void *data);
extern int trtl_fw_mq_action_dispatch(enum trtl_mq_type type,
unsigned int idx_mq);
extern void trtl_fw_message_error(struct trtl_msg *msg, int err);
extern void trtl_fw_message_error(struct trtl_fw_msg *msg, int err);
#endif
/**@}*/
......@@ -12,6 +12,12 @@
#include "mockturtle-rt.h"
/**
* It sends a character to the UART interface
* @param[in] c the character to sent
* @return 0 on success (for the time being it does not fail)
*/
int putchar(int c)
{
lr_writel(c, MT_CPU_LR_REG_UART_CHR);
......@@ -35,7 +41,7 @@ int puts(const char *p)
char c;
while ((c = *(p++)))
putchar (c);
putchar(c);
return p - p_orig;
}
......@@ -243,7 +243,8 @@ static inline unsigned int gpio_status(int pin)
}
/**
* Wait n cycles
* Wait n cycles. This means that the wait can be different on
* different core with different clock.
* @todo: use Timing Unit, compute it accoring to CPU frequency
* @param[in] n number of cycles to wait
*/
......@@ -303,15 +304,22 @@ static inline uint32_t trtl_get_core_id(void)
return lr_readl(0);
}
/**
* Message queue slot base address input
*/
#define TRTL_MQ_SLOT_IN(slot) (TRTL_MQ_BASE_IN + ((slot) << 16))
// Outgoung slot base address, relative to BASE_HMQ
/**
* Message queue slot base address output
*/
#define TRTL_MQ_SLOT_OUT(slot) (TRTL_MQ_BASE_OUT + ((slot) << 16))
/**
* List of Message Queue types
*/
enum trtl_mq_type {
TRTL_HMQ = 0, /**< Host Message Queue - Host-Firmware communication */
TRTL_RMQ, /**< Remote Message Queue - Network-Firmware communication */
TRTL_HMQ = 0, /**< Host Message Queue - Host-Firmware */
TRTL_RMQ, /**< Remote Message Queue - Network-Firmware */
__TRTL_MAX_MQ_TYPE,
};
......@@ -319,6 +327,7 @@ enum trtl_mq_type {
/**
* It gets the Message Queue base address
* @param[in] type MQ type
* @return message queue base address
*/
static inline void *trtl_mq_base_address(enum trtl_mq_type type)
{
......@@ -329,8 +338,8 @@ static inline void *trtl_mq_base_address(enum trtl_mq_type type)
/**
* It writes on a Message Queue register
* @param[in] type MQ type to use
* @param[val] value to write
* @param[reg] reg register offset
* @param[in] val value to write
* @param[in] reg register offset
*/
static inline void mq_writel(enum trtl_mq_type type, uint32_t val, uint32_t reg)
{
......@@ -466,6 +475,7 @@ static inline void mq_map_in_message(enum trtl_mq_type type,
/**
* It gets the current MQ input status
* @param[in] type MQ type to use
* @return message queues input status bitmask
*/
static inline uint32_t mq_poll_in(enum trtl_mq_type type)
......@@ -479,6 +489,7 @@ static inline uint32_t mq_poll_in(enum trtl_mq_type type)
/**
* It gets the current MQ output status
* @param[in] type MQ type to use
* @return message queues output status bitmask
*/
static inline uint32_t mq_poll_out(enum trtl_mq_type type)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment