This is the user's manual for ReconOS, a programming and execution environment for CPU/FPGA systems based on multithreaded programming.
Developed within the context of a university research project and a PhD thesis, ReconOS is a way to bring some of the convenience of a software-like programming model to the detail-ridden world of reconfigurable hardware design. With ReconOS, you can model a concurrent application for reconfigurable systems-on-chip (rSoC) using both software and hardware threads. The interactions between all threads are handled through common POSIX-like abstractions such as mailboxes, semaphores, or shared memory, hiding the complexities of bus access protocols, memory spaces, register files and interrupt handling.
Note: This document is in a very early design stage – it thus may contain inaccuracies and missing a considerable amount of content. If you spot inconsistencies or would otherwise like to contribute to the documentation, please visit the ReconOS repository on GitHub and the reconos-devel mailing list.
The vision behind this project is to raise design productivity and flexibility for dynamically reconfigurable (FPGA-based) systems to a level currently achieved only for processor-based systems. To this end, we are developing ReconOS, an operating system designed to alleviate the difficulty of programming reconfigurable hardware by offering common service abstractions for both hardware and software tasks. ReconOS provides application programmers with an RTOS-like programming model that abstracts away from the device details and an execution model that performs hardware multitasking on current FPGA technology. The importance of the ReconOS project stems from the fact that hardware reconfigurability will become an essential feature of future architectures and applications, especially networked embedded systems. While the underlying hardware technology already evolves, there is a lack of appropriate design tools. ReconOS intends to address this problem and to build the necessary foundation for these future applications. Furthermore, an extension to the basic ReconOS system aims to take the usability of dynamically reconfigurable hardware to the next level while maintaining efficiency. We think this can be reached by looking into the areas of higher-level front ends and system monitoring, both of which have not been sufficiently investigated yet in the context of reconfigurable hardware, as well as into the novel idea of adaptive run-time systems.
These instructions will guide you step-by-step through the process of setting up a development box including all the tools you need.
The ReconOS tool chain depends on quite a few other tools, both commercial and open-source. While we try to rely on as much free software as possible, some of the tools (most notably the FPGA synthesis and implementation tools) are not, and will probably never be, available for free. In some cases, we will provide links to free evaluation versions or alternatives to our preferred choices.
ReconOS requires that the following commercial FPGA tools be installed.
ReconOS heavily relies on Python for the automated parts of its tool chain. It requires the following software:
DRAFT
This guide will lead you through the steps necessary for building a static design using ReconOS. We will be using a simple example with one slot containing a static hardware thread. As application we implement a sorter. In a first step, the application generates random data. In a next step, the data is divided into chunks of 8 Kbyte. These chunks will be sorted by either the hardware thread or a software thread using the bubble sort algorithm. The chunks will then be merged, such that in the end the entire data is sorted. To ensure correctness, the application checks, if the data is sorted correctly.
This howto will assume that you already have checked out the ReconOS repository and build all required tools and libraries. Refer to the documentation pages that cover these topics: Installation. Furthermore, this tutorial assumes that you have a Xilinx XUPV2P board with a compatible memory module installed.
First we create the structure of the project. This is easily done by using the command
reconos_mkprj.py <project_name>
This creates the typical ReconOS Projekt environment with the sw and hw directory. Now we have to change the project settings. From this point, we assume that $WORK describes the path to your project folder.
file: <project_name>.rprj
The line beginning with STATIC-THREADS has to be edited, because we add a hardware thread that can sort 8 KBytes of data. Name the thread sort8k by adding this to the line.
Note:This tutorial creates the multicore environment on the XUP-Board. If you want to create it for the virtex4 , you have to change the reference design in the project file.
Now edit the layout file:
hw/<project_name>.lyt
Delete everything except the TARGET definition. The final file should look like this (for the XUP-Board):
target
device XC2VP30
family xc2vp
end
In a last step, set the environment variable $HW_THREADS
source $WORK/settings.sh
After this, the project structure is ready to be worked with.
In this tutorial, we will use an existing simple example thread that sorts 8 kbytes of data. The thread waits for a message from an incoming message queue containing the address of the data chunk and sends a message to an outgoing queue when sorting is done. The thread is composed in two VHDL files that can be found under $RECONOS/demos/sort_demo/src/bubble_sorter.vhd and $RECONOS/demos/sort_demo/src/sort8k.vhd. Copy both files to the $PROJECT_NAME/hw directory:
cp $RECONOS/demos/sort_demo/src/*.vhd $WORK/hw/*.vhd
Have a look at the VHDL code - most threads will be of a similar structure. sort8k.vhd contains the synchronous state machine that is connected to the operating system interface (OSIF), i.e. waiting for messages, while bubble_sorter.vhd contains the user logic for sorting the data.
cd $WORK/hw/hw_threads
reconos_addwthread.py sort8k sort8k ../bubble_sorter.vhd ../sort8k.vhd
The arguments to the reconos_addwthread.py script are the hardware thread's entity name, the user logic entity's name (often the same as the one before), and the source files sorted after dependency such that the top file comes last. The script now creates an EDK pcore that contains the interface structures necessary to connect our hardware thread to the already instantiated OSIF.
Note that you can instantiate the same hardware thread multiple times.
To generate the hardware design you first copy a reference design and insert static threads. This is done by the following command:
cd $WORK/hw
make static-threads
Now we create the software libraries and the final bitstream. This can be done using the Xilinx Platform Studio (XPS).
You have to open the project which can be found in $WORK/hw/edk-static/system.xmp.
Compile the software drivers and library functions into a BSP, using the Software->Generate libraries and BSPs menu item. This will generate the Xilinx headers and particularly libxil.a which we will need when compiling the eCos library. You need to regenerate this BSP whenever you change the hardware architecture (e.g. add OSIFs/slots, peripherals, change the memory map, etc.).
Finally, generate the bitstream, using the Hardware->Generate Bitstream menu item.
Alternativly, you can also use the makefile to do these steps
cd $WORK/hw
make bits-static
Now copy the software part of the demo application into your project.
cp -r $RECONOS/demos/sort_demo/src/sw $WORK/sw
ReconOS extends the embedded operating system eCos that is composed of packages. The eCos configuration file sort.ecc defines the eCos configuration. (You can modify it using the configtool.)
cd $WORK/sw
make mrproper setup
Compile the software part of the application and link them into an executable.
make clean ecos
In a new shell, start the minicom modem, such that the print-functions, which are called by the software part of application and forwarded through the serial port to your computer, is shown to you.
minicom
When you have uploaded an executable, the print output will be shown here.
To configure the FPGA with your hardware design, you have to download the bitstream to the board.
cd $WORK/sw
dow ../hw/edk-static/implementation/system.bit
We have four different executables, which you can test.
dow sort_ecos_st_sw.elf
dow sort_ecos_mt_sw.elf
dow sort_ecos_st_hw.elf
dow sort_ecos_mt_hw.elf
In order to connect hardware components (either as VHDL modules or as black-box netlists) as threads to a ReconOS system, they need to conform to a set of requirements. In particular, hardware threads need to expose a strict interface, which is used to connect them to their OS Interface, and to conform to a certain signalling protocol on this interface, which is most conveniently done by structuring all OS interactions in a dedicated state machine description.
The former requirement is easily satisfied by reusing a common VHDL port template for all hardware threads (which may be extensible with specially annotated user ports). The latter requires the use of a predefined set of VHDL functions and procedures to ensure proper synchronization with the OSIF and to invoke the individual operating system calls from within the hardware component. This set of VHDL callables, when used in a structured fashion within the hardware thread's OS Synchronization State Machine, mirrors the OS kernel's API as closely as possible and allows transparent interaction with the operating system's services and other threads.
The ReconOS hardware thread API, together with the OS Interface, provides a hardware thread written in VHDL with the capabilities to call kernel functions (or "system calls"). To implement blocking system calls, these VHDL procedures have to be called in a finite state machine that is written in a specific way. You can read more about this state machine in Hardware Thread FSM.
This section describes the procedure prototypes without going into implementation details. It is meant to serve as a reference when writing hardware threads. To understand how the internals of the hardware thread / OS communications work, see Execution Model.
The interface a hardware thread has to have is detailed in Hardware Thread Interface.
The datatypes and procedures for communication between a user task and the ReconOS OS interface are defined in /hw/pcores/reconos_$RECONOS_VERSION/hdl/vhdl/reconos_pkg.vhd. This package must be included in every ReconOS hardware thread, for example:
library reconos_v2_01_a;
use reconos_v2_01_a.reconos_pkg.all;
for version 2.01.a.
ReconOS defines two records for hardware thread / OS communication, one for each direction:
-- OS to task communication
type osif_os2task_t is record
-- [...]
end record;
-- task to OS communication
type osif_task2os_t is record
-- [...]
end record;
The actual contents of these records are not important to the thread developer—they are manipulated through the ReconOS hardware API calls. The i_osif and o_osif ports in every HardwareThread entity have to be passed to the API calls.
There are constants for the binary encoding of all ReconOS commands passed between hardware threads and the OS interface. They are listed in the system call overview table for reference and debugging purposes. When writing hardware threads, you do not need to specifiy these—they are implicitly encoded in the hardware API procedures.
Other constants include the bit width of the different osif fields, which can be interesting for thread designers, e.g. for determining the width of values read from memory. Which is fixed at 32 bits, but anyway...
-- width of OSIF commands, data and status registers
constant C_OSIF_CMD_WIDTH : natural := 8;
constant C_OSIF_DATA_WIDTH : natural := 32;
constant C_OSIF_STATUS_WIDTH : natural := C_OSIF_DATA_WIDTH;
constant C_OSIF_NUM_STATUS_REGS : natural := 2; -- access latency and busy load
-- number of bits in communication records
constant C_OSIF_OS2TASK_REC_WIDTH : natural := C_OSIF_CMD_WIDTH + C_OSIF_DATA_WIDTH + 3 + 2;
constant C_OSIF_TASK2OS_REC_WIDTH : natural := C_OSIF_CMD_WIDTH + C_OSIF_DATA_WIDTH + 2;
-- maximum steps a multicycle command can take
constant C_MAX_MULTICYCLE_STEPS : natural := 4;
-- common constants
constant C_RECONOS_FAILURE : std_logic_vector(0 to C_OSIF_DATA_WIDTH-1) := X"00000000";
ReconOS hardware system calls can be split into two classes: blocking and non-blocking calls. The meaning of 'blocking' here is a little different than in the context of software system calls. A 'blocking' call will halt the execution of the synchronization state machine (and thus all OS interaction) until the corresponding software call (initiated by the delegate thread) returns. This way the hardware thread will also block while the delegate thread is blocking, but it is also necessary, for example, to transfer the return value of a call back to the hardware thread. Other system calls (e.g. semaphore_post()) that are 'software-nonblocking' and do not return anything will be 'hardware-nonblocking', thus allowing the state machine to continue as soon as the delegate thread has relayed the call to the eCos kernel.
In essence, every 'software-blocking' call is also 'hardware-blocking', but additionally all 'software-nonblocking' calls with a return value also have to be 'hardware-blocking'.
We also have to distinguish between "single-cycle" and "multi-cycle" commands. Multi-cycle commands are used if the communication between the thread and the OSIF cannot be completed in a single cycle. This is the case, for example, if the OSIF needs more than 32 bits of data, or if the OSIF will return a value to the thread upon completion. These commands have to be used in a certain way, which is described in Multi Cycle Commands.
System calls that return a value usually exist in two variants, e.g. reconos_read() and reconos_read_s(). The first flavour returns the return value in a variable, so that it can be evaluated in the same state of the synchronization FSM. The _s() variety is a convenience wrapper which returns the return value in a signal, so that it can be directly connected to a separate process. This introduces one cycle of latency. The table below lists only the 'non-_s()' variant.
Some of the commands (such as memory accesses) are handled directly in hardware, while others (like calls to kernel synchronization primitives) have to be handled in software. See the ExecutionModel for details.
Most programming model objects (like mutexes or semaphores) are referenced by a handle. This handle is usually encoded as a 32 bit value, which is transferred to software and translated into the actual address of the object. See ResourceHandling for details.
NOTE: There can be only one OS command per state in the synchronization state machine!
The following table shows all available system calls, their associated constants and binary encodings (for debugging/simulation purposes), where applicable:
| command | binary encoding | symbolic name | software-blocking | hardware-blocking | multi-cycle | handled in SW
|
|---|---|---|---|---|---|---|
| reconos_sem_post | 0x00 | OSIF_CMD_SEM_POST | X
| |||
| reconos_sem_wait | 0x81 | OSIF_CMD_SEM_WAIT | X | X | X
| |
| reconos_write | 0x49 | OSIF_CMD_WRITE | X |
| ||
| reconos_read | 0x48 | OSIF_CMD_READ | X |
| ||
| reconos_write_burst | 0x4B | OSIF_CMD_WRITE_BURST | X |
| ||
| reconos_read_burst | 0x4A | OSIF_CMD_READ_BURST | X |
| ||
| reconos_get_init_data | 0x40 | OSIF_CMD_GET_INIT_DATA | X |
| ||
| reconos_mutex_lock | 0x82 | OSIF_CMD_MUTEX_LOCK | X | X | X | X
|
| reconos_mutex_trylock | 0x83 | OSIF_CMD_MUTEX_TRYLOCK | X | X | X
| |
| reconos_mutex_unlock | 0x02 | OSIF_CMD_MUTEX_UNLOCK | X
| |||
| reconos_mutex_release | 0x03 | OSIF_CMD_MUTEX_RELEASE | X
| |||
| reconos_cond_wait | 0x84 | OSIF_CMD_COND_WAIT | X | X | X | X
|
| reconos_cond_signal | 0x04 | OSIF_CMD_COND_SIGNAL | X
| |||
| reconos_cond_broadcast | 0x05 | OSIF_CMD_COND_BROADCAST | X
| |||
| reconos_mbox_get | 0x85 | OSIF_CMD_MBOX_GET | X | X | X | (X)
|
| reconos_mbox_tryget | 0x86 | OSIF_CMD_MBOX_TRYGET | X | X | (X)
| |
| reconos_mbox_put | 0x87 | OSIF_CMD_MBOX_PUT | X | X | X | (X)
|
| reconos_mbox_tryput | 0x88 | OSIF_CMD_MBOX_TRYPUT | X | X | (X)
| |
| reconos_begin |
| |||||
| reconos_ready |
| |||||
| reconos_reset |
| |||||
| reconos_thread_exit | 0xF0 | OSIF_CMD_THREAD_EXIT | X | X
|
The following is a short description of the individual function calls:
procedure reconos_sem_post (signal osif_task2os : out osif_task2os_t;
osif_os2task : in osif_os2task_t;
handle : in std_logic_vector(0 to C_OSIF_DATA_WIDTH-1));
Posts (increments) the semaphore identified by handle.
| Parameter | Description
|
|---|---|
osif_task2os | record of communication signals to the OS interface
|
osif_os2task | record of communication signals from the OS interface
|
handle | the thread-local identifier for the semaphore to post
|
Example (inside the synchronization FSM process):
...
case state is
...
when STATE_POST =>
reconos_sem_post(o_osif, i_osif, C_MY_SEMAPHORE);
state <= STATE_IDLE;
...
procedure reconos_sem_wait (signal osif_task2os : out osif_task2os_t;
osif_os2task : in osif_os2task_t;
handle : in std_logic_vector(0 to C_OSIF_DATA_WIDTH-1));
Waits for (then decrements) the semaphore identified by handle. Blocks until semaphore becomes available.
| Parameter | Description
|
|---|---|
osif_task2os | record of communication signals to the OS interface
|
osif_os2task | record of communication signals from the OS interface
|
handle | the thread-local identifier for the semaphore to wait on
|
Example (inside the synchronization FSM process):
...
case state is
...
when STATE_WAIT =>
reconos_sem_wait(o_osif, i_osif, C_MY_SEMAPHORE);
state <= STATE_READ;
...
procedure reconos_write (variable completed : out boolean;
signal osif_task2os : out osif_task2os_t;
signal osif_os2task : in osif_os2task_t;
address : in std_logic_vector(0 to C_OSIF_DATA_WIDTH-1);
data : in std_logic_vector(0 to C_OSIF_DATA_WIDTH-1));
Writes a single word (32 Bits) to system memory.
| Parameter | Description
|
|---|---|
completed | variable to indicate completion of this MultiCycle command
|
osif_task2os | record of communication signals to the OS interface
|
osif_os2task | record of communication signals from the OS interface
|
address | address to write to (can be memory or memory-mapped peripheral)
|
data | data word to write
|
Example (inside the synchronization FSM process):
...
variable done : boolean;
...
begin
...
case state is
...
when STATE_WRITE =>
reconos_write(done, o_osif, i_osif, my_address, my_data);
if done then
state <= STATE_DO_SOMETHING;
end if;
...
procedure reconos_read (variable completed : out boolean;
signal osif_task2os : out osif_task2os_t;
signal osif_os2task : in osif_os2task_t;
address : in std_logic_vector(0 to C_OSIF_DATA_WIDTH-1);
variable data : out std_logic_vector(0 to C_OSIF_DATA_WIDTH-1));
procedure reconos_read_s (variable completed : out boolean;
signal osif_task2os : out osif_task2os_t;
signal osif_os2task : in osif_os2task_t;
address : in std_logic_vector(0 to C_OSIF_DATA_WIDTH-1);
signal data : out std_logic_vector(0 to C_OSIF_DATA_WIDTH-1));
Reads a single word (32 Bits) from system memory. reconos_read() reads into a variable for immediate evaluation, while reconos_read_s() reads into a signal for evaluation in a different process.
| Parameter | Description
|
|---|---|
completed | variable to indicate completion of this MultiCycle command
|
osif_task2os | record of communication signals to the OS interface
|
osif_os2task | record of communication signals from the OS interface
|
address | address to read from (can be memory or memory-mapped peripheral)
|
data | data word (signal/variable) to read into
|
Example 1 (inside the synchronization FSM process):
...
variable done : boolean;
variable my_data : std_logic_vector(0 to C_OSIF_DATA_WIDTH-1);
...
begin
...
case state is
...
when STATE_READ =>
reconos_read(done, o_osif, i_osif, my_address, my_data);
if done then
if my_data = SOME_VALUE then
state <= STATE_DO_SOMETHING;
else
state <= STATE_DO_SOMETHING_ELSE;
end if;
end if;
...
Example 2 (inside the synchronization FSM process):
signal my_data : std_logic_vector(0 to C_OSIF_DATA_WIDTH-1);
...
fsm_proc : process(...)
...
variable done : boolean;
...
begin
...
case state is
...
when STATE_READ =>
reconos_read_s(done, o_osif, i_osif, my_address, my_data);
if done then
state <= STATE_DO_SOMETHING;
end if;
...
end process;
...
some_other_proc : process(...)
...
begin
...
if my_data = SOME_VALUE then
...
end if;
...
end process
procedure reconos_write_burst (variable completed : out boolean;
signal osif_task2os : out osif_task2os_t;
signal osif_os2task : in osif_os2task_t;
my_address : in std_logic_vector(0 to C_OSIF_DATA_WIDTH-1);
target_address : in std_logic_vector(0 to C_OSIF_DATA_WIDTH-1));
Writes / copies a burst of 32 words (32x32 Bits) from the local burst RAM to system memory.
| Parameter | Description
|
|---|---|
completed | variable to indicate completion of this MultiCycle command
|
osif_task2os | record of communication signals to the OS interface
|
osif_os2task | record of communication signals from the OS interface
|
my_address | address in the local RAM to get data from (byte address)
|
target_address | address in the system memory space to write data to (byte address)
|
Example 1 (inside the synchronization FSM process):
...
variable done : boolean;
...
begin
...
case state is
...
when STATE_WRITE_BURST =>
reconos_write_burst(done, o_osif, i_osif, local_address, global_address);
if done then
state <= STATE_DO_SOMETHING;
end if;
...
*Example 2* (inside the synchronization FSM process, type conversions omitted for simplicity):
...
variable done : boolean;
variable count : natural;
...
begin
...
case state is
...
when STATE_WRITE_BURST =>
reconos_write_burst(done, o_osif, i_osif, local_address + count, global_address + count);
if done then
count := count + 128;
if count > MAX_COUNT then
state <= STATE_DO_SOMETHING;
end if;
end if;
...
procedure reconos_read_burst (variable completed : out boolean;
signal osif_task2os : out osif_task2os_t;
signal osif_os2task : in osif_os2task_t;
my_address : in std_logic_vector(0 to C_OSIF_DATA_WIDTH-1);
target_address : in std_logic_vector(0 to C_OSIF_DATA_WIDTH-1));
Reads / copies a burst of 32 words (32x32 Bits) from the system memory space to local burst RAM.
| Parameter | Description
|
|---|---|
completed | variable to indicate completion of this MultiCycle command
|
osif_task2os | record of communication signals to the OS interface
|
osif_os2task | record of communication signals from the OS interface
|
my_address | address in the local RAM to write data to (byte address)
|
target_address | address in the system memory space to get data from (byte address)
|
Example 1 (inside the synchronization FSM process):
...
variable done : boolean;
...
begin
...
case state is
...
when STATE_READ_BURST =>
reconos_read_burst(done, o_osif, i_osif, local_address, global_address);
if done then
state <= STATE_DO_SOMETHING;
end if;
...
Example 2 (inside the synchronization FSM process, type conversions omitted for simplicity):
...
variable done : boolean;
variable count : natural;
...
begin
...
case state is
...
when STATE_READ_BURST =>
reconos_read_burst(done, o_osif, i_osif, local_address + count, global_address + count);
if done then
count := count + 128;
if count > MAX_COUNT then
state <= STATE_DO_SOMETHING;
end if;
end if;
...
procedure reconos_get_init_data (variable completed : out boolean;
signal osif_task2os : out osif_task2os_t;
signal osif_os2task : in osif_os2task_t;
variable data : out std_logic_vector(0 to C_OSIF_DATA_WIDTH-1));
procedure reconos_get_init_data_s (variable completed : out boolean;
signal osif_task2os : out osif_task2os_t;
signal osif_os2task : in osif_os2task_t;
signal data : out std_logic_vector(0 to C_OSIF_DATA_WIDTH-1));
Reads the thread initialization data (32 bit) from the OS interface. This data is passed to the OSIF on hardware thread initialization (see reconos_hwthread_create). reconos_get_init_data() returns a variable for immediate evaluation, while reconos_get_init_data_s() returns a signal for evaluation in a separate process.
| Parameter | Description
|
|---|---|
completed | variable to indicate completion of this MultiCycle command
|
osif_task2os | record of communication signals to the OS interface
|
osif_os2task | record of communication signals from the OS interface
|
data | variable / signal to store initialization data in
|
Example 1 (inside the synchronization FSM process):
...
variable done : boolean;
variable my_data : std_logic_vector(0 to C_OSIF_DATA_WIDTH-1);
...
begin
...
case state is
...
when STATE_INIT =>
reconos_get_init_data(done, o_osif, i_osif, my_data);
if done then
if my_data = SOME_VALUE then
state <= STATE_DO_SOMETHING;
else
state <= STATE_DO_SOMETHING_ELSE;
end if;
end if;
...
Example 2 (inside the synchronization FSM process):
signal my_data : std_logic_vector(0 to C_OSIF_DATA_WIDTH-1);
...
fsm_proc : process(...)
...
variable done : boolean;
...
begin
...
case state is
...
when STATE_INIT =>
reconos_get_init_data_s(done, o_osif, i_osif, my_data);
if done then
state <= STATE_DO_SOMETHING;
end if;
...
end process;
...
some_other_proc : process(...)
...
begin
...
if my_data = SOME_VALUE then
...
end if;
...
end process
procedure reconos_mutex_lock(variable completed : out boolean;
variable success : out boolean;
signal osif_task2os : out osif_task2os_t;
signal osif_os2task : in osif_os2task_t;
handle : in std_logic_vector(0 to C_OSIF_DATA_WIDTH-1));
Locks a mutex. reconos_mutex_lock() will block until mutex becomes available, lock it, and return. If unsuccessful (e.g. on error or thread termination) success will be false.
| Parameter | Description
|
|---|---|
completed | variable to indicate completion of this MultiCycle command
|
success | variable to indicate success of the mutex lock operation
|
osif_task2os | record of communication signals to the OS interface
|
osif_os2task | record of communication signals from the OS interface
|
handle | handle of the mutex to lock
|
Example (inside the synchronization FSM process):
...
variable done : boolean;
variable okay : boolean;
...
begin
...
case state is
...
when STATE_LOCK =>
reconos_mutex_lock(done, okay, o_osif, i_osif, C_MY_MUTEX);
if done and okay then -- note: this will loop forever on error
state <= STATE_DO_SOMETHING;
end if;
...
procedure reconos_mutex_trylock(variable completed : out boolean;
variable success : out boolean;
signal osif_task2os : out osif_task2os_t;
signal osif_os2task : in osif_os2task_t;
handle : in std_logic_vector(0 to C_OSIF_DATA_WIDTH-1));
Locks a mutex, if available. reconos_mutex_trylock() will lock the mutex indicated by handle, if and only if it is available, and return true in success. Otherwise (e.g. mutex is already locked, an error occurred or the thread terminates) success will be false.
| Parameter | Description
|
|---|---|
completed | variable to indicate completion of this MultiCycle command
|
success | variable to indicate success of the mutex trylock operation
|
osif_task2os | record of communication signals to the OS interface
|
osif_os2task | record of communication signals from the OS interface
|
handle | handle of the mutex to lock
|
Example (inside the synchronization FSM process):
...
variable done : boolean;
variable okay : boolean;
...
begin
...
case state is
...
when STATE_LOCK =>
reconos_mutex_trylock(done, okay, o_osif, i_osif, C_MY_MUTEX);
if done then
if okay then
state <= STATE_DO_SOMETHING;
else
state <= STATE_DO_SOMETHING_ELSE;
end if;
end if;
...
procedure reconos_mutex_unlock(signal osif_task2os : out osif_task2os_t;
signal osif_os2task : in osif_os2task_t;
handle : in std_logic_vector(0 to C_OSIF_DATA_WIDTH-1));
Unlocks a mutex.
| Parameter | Description
|
|---|---|
osif_task2os | record of communication signals to the OS interface
|
osif_os2task | record of communication signals from the OS interface
|
handle | handle of the mutex to unlock
|
Example (inside the synchronization FSM process):
...
begin
...
case state is
...
when STATE_UNLOCK =>
reconos_mutex_unlock(o_osif, i_osif, C_MY_MUTEX);
state <= STATE_DO_SOMETHING;
...
procedure reconos_mutex_release(signal osif_task2os : out osif_task2os_t;
signal osif_os2task : in osif_os2task_t;
handle : in std_logic_vector(0 to C_OSIF_DATA_WIDTH-1));
Releases a mutex (i.e. wakes all threads waiting on it, which will get a return value of false).
| Parameter | Description
|
|---|---|
osif_task2os | record of communication signals to the OS interface
|
osif_os2task | record of communication signals from the OS interface
|
handle | handle of the mutex to release
|
Example (inside the synchronization FSM process):
...
begin
...
case state is
...
when STATE_RELEASE =>
reconos_mutex_release(o_osif, i_osif, C_MY_MUTEX);
state <= STATE_DO_SOMETHING;
...
procedure reconos_cond_wait(variable completed : out boolean;
variable success : out boolean;
signal osif_task2os : out osif_task2os_t;
signal osif_os2task : in osif_os2task_t;
handle : in std_logic_vector(0 to C_OSIF_DATA_WIDTH-1));
Waits on a condition variable. reconos_cond_wait() will block until a change of the condition variable referenced by handle is signalled. If unsuccessful (e.g. on error or thread termination) success will be false.
| Parameter | Description
|
|---|---|
completed | variable to indicate completion of this MultiCycle command
|
success | variable to indicate success of the cond_wait operation
|
osif_task2os | record of communication signals to the OS interface
|
osif_os2task | record of communication signals from the OS interface
|
handle | handle of the condvar to wait on
|
TODO
Example (inside the synchronization FSM process):
...
variable done : boolean;
variable okay : boolean;
...
begin
...
case state is
...
when STATE_WAIT =>
reconos_cond_wait(done, okay, o_osif, i_osif, C_MY_CONDVAR);
if done and okay then -- note: this will loop forever on error
state <= STATE_DO_SOMETHING;
end if;
...
procedure reconos_cond_signal(signal osif_task2os : out osif_task2os_t;
signal osif_os2task : in osif_os2task_t;
handle : in std_logic_vector(0 to C_OSIF_DATA_WIDTH-1));
Signals a change of a condition variable, i.e. wakes up the next thread waiting on that condition variable.
| Parameter | Description
|
|---|---|
osif_task2os | record of communication signals to the OS interface
|
osif_os2task | record of communication signals from the OS interface
|
handle | handle of the condvar to signal
|
Example (inside the synchronization FSM process):
...
begin
...
case state is
...
when STATE_SIGNAL =>
reconos_cond_signal(o_osif, i_osif, C_MY_MUTEX);
state <= STATE_DO_SOMETHING;
...
procedure reconos_cond_broadcast(signal osif_task2os : out osif_task2os_t;
signal osif_os2task : in osif_os2task_t;
handle : in std_logic_vector(0 to C_OSIF_DATA_WIDTH-1));
Broadcasts a change of a condition variable, i.e. wakes all threads waiting on that condition variable.
| Parameter | Description
|
|---|---|
osif_task2os | record of communication signals to the OS interface
|
osif_os2task | record of communication signals from the OS interface
|
handle | handle of the condvar to broadcast
|
Example (inside the synchronization FSM process):
...
begin
...
case state is
...
when STATE_SIGNAL =>
reconos_cond_broadcast(o_osif, i_osif, C_MY_MUTEX);
state <= STATE_DO_SOMETHING;
...
procedure reconos_mbox_get(variable completed : out boolean;
variable success : out boolean;
signal osif_task2os : out osif_task2os_t;
signal osif_os2task : in osif_os2task_t;
handle : in std_logic_vector(0 to C_OSIF_DATA_WIDTH-1);
variable data : out std_logic_vector(0 to C_OSIF_DATA_WIDTH-1));
procedure reconos_mbox_get_s(variable completed : out boolean;
variable success : out boolean;
signal osif_task2os : out osif_task2os_t;
signal osif_os2task : in osif_os2task_t;
handle : in std_logic_vector(0 to C_OSIF_DATA_WIDTH-1);
signal data : out std_logic_vector(0 to C_OSIF_DATA_WIDTH-1));
Retrieves a 32bit value from the specified message box. The call may block if the message box is empty.
This call can also be handled in hardware, if the message box is mapped to a hardware FIFO connected to the executing thread's OSIF (see Message Boxes). If the call is handled in software, it will block until the return value arrives.
reconos_mbox_get() returns the value from the message box in a variable for immediate evaluation, while reconos_mbox_get_s() returns a signal for evaluation in a separate process.
| Parameter | Description
|
|---|---|
completed | variable to indicate completion of this MultiCycle command
|
success | signals whether the call succeeded. A failure can for example mean that the blocking call was interrupted by a signal
|
osif_task2os | record of communication signals to the OS interface
|
osif_os2task | record of communication signals from the OS interface
|
handle | the handle (resource number) of the message box
|
data | variable / signal to store initialization data in
|
Example 1 (inside the synchronization FSM process):
...
constant C_MBOX_HANDLE : std_logic_vector(0 to C_OSIF_DATA_WIDTH-1) := X"00000001"
...
variable success : boolean;
variable done : boolean;
variable my_data : std_logic_vector(0 to C_OSIF_DATA_WIDTH-1);
...
begin
...
case state is
...
when STATE_GET =>
reconos_mbox_get(done, success, o_osif, i_osif, C_MBOX_HANDLE, my_data);
if done then
if success then
if my_data = SOME_VALUE then
state <= STATE_DO_SOMETHING;
else
state <= STATE_DO_SOMETHING_ELSE;
else -- no success
state <= HANDLE_ERROR;
end if;
end if;
...
Example 2 (inside the synchronization FSM process):
...
constant C_MBOX_HANDLE : std_logic_vector(0 to C_OSIF_DATA_WIDTH-1) := X"00000001"
...
variable done : boolean;
variable my_data : std_logic_vector(0 to C_OSIF_DATA_WIDTH-1);
...
begin
...
case state is
...
when STATE_GET =>
reconos_mbox_get(done, success, o_osif, i_osif, C_MBOX_HANDLE, my_data);
if done then
if success then
state <= STATE_DO_SOMETHING;
else -- no success
state <= HANDLE_ERROR;
end if;
end if;
...
some_other_proc : process(...)
...
begin
...
if my_data = SOME_VALUE then
...
end if;
...
end process
procedure reconos_mbox_tryget(variable completed : out boolean;
variable success : out boolean;
signal osif_task2os : out osif_task2os_t;
signal osif_os2task : in osif_os2task_t;
handle : in std_logic_vector(0 to C_OSIF_DATA_WIDTH-1);
variable data : out std_logic_vector(0 to C_OSIF_DATA_WIDTH-1));
procedure reconos_mbox_tryget_s(variable completed : out boolean;
variable success : out boolean;
signal osif_task2os : out osif_task2os_t;
signal osif_os2task : in osif_os2task_t;
handle : in std_logic_vector(0 to C_OSIF_DATA_WIDTH-1);
signal data : out std_logic_vector(0 to C_OSIF_DATA_WIDTH-1));
Retrieves a 32bit value from the specified message box. The call will not block if the message box is empty, but fail (success = false).
This call can also be handled in hardware, if the message box is mapped to a hardware FIFO connected to the executing thread's OSIF (see Message Boxes). If the call is handled in software, it will block until the return value arrives.
reconos_mbox_tryget() returns the value from the message box in a variable for immediate evaluation, while reconos_mbox_tryget_s() returns a signal for evaluation in a separate process.
| Parameter | Description
|
|---|---|
completed | variable to indicate completion of this MultiCycle command
|
success | signals whether the call succeeded.
|
osif_task2os | record of communication signals to the OS interface
|
osif_os2task | record of communication signals from the OS interface
|
handle | the handle (resource number) of the message box
|
data | variable / signal to store initialization data in
|
Example 1 (inside the synchronization FSM process):
...
constant C_MBOX_HANDLE : std_logic_vector(0 to C_OSIF_DATA_WIDTH-1) := X"00000001"
...
variable success : boolean;
variable done : boolean;
variable my_data : std_logic_vector(0 to C_OSIF_DATA_WIDTH-1);
...
begin
...
case state is
...
when STATE_GET =>
reconos_mbox_tryget(done, success, o_osif, i_osif, C_MBOX_HANDLE, my_data);
if done then
if success then
if my_data = SOME_VALUE then
state <= STATE_DO_SOMETHING;
else
state <= STATE_DO_SOMETHING_ELSE;
else -- no success
state <= HANDLE_ERROR;
end if;
end if;
...
Example 2 (inside the synchronization FSM process):
...
constant C_MBOX_HANDLE : std_logic_vector(0 to C_OSIF_DATA_WIDTH-1) := X"00000001"
...
variable done : boolean;
variable my_data : std_logic_vector(0 to C_OSIF_DATA_WIDTH-1);
...
begin
...
case state is
...
when STATE_GET =>
reconos_mbox_tryget(done, success, o_osif, i_osif, C_MBOX_HANDLE, my_data);
if done then
if success then
state <= STATE_DO_SOMETHING;
else -- no success
state <= HANDLE_ERROR;
end if;
end if;
...
some_other_proc : process(...)
...
begin
...
if my_data = SOME_VALUE then
...
end if;
...
end process
procedure reconos_mbox_put(variable completed : out boolean;
variable success : out boolean;
signal osif_task2os : out osif_task2os_t;
signal osif_os2task : in osif_os2task_t;
handle : in std_logic_vector(0 to C_OSIF_DATA_WIDTH-1);
data : in std_logic_vector(0 to C_OSIF_DATA_WIDTH-1));
Sends a 32bit value to the specified message box. The call may block if the message box is full.
This call can also be handled in hardware, if the message box is mapped to a hardware FIFO connected to the executing thread's OSIF (see Message Boxes). If the call is handled in software, it will block until the return value arrives.
| Parameter | Description
|
|---|---|
completed | variable to indicate completion of this MultiCycle command
|
success | signals whether the call succeeded. A failure can for example mean that the blocking call was interrupted by a signal
|
osif_task2os | record of communication signals to the OS interface
|
osif_os2task | record of communication signals from the OS interface
|
handle | the handle (resource number) of the message box
|
data | variable / signal to store initialization data in
|
Example (inside the synchronization FSM process):
...
constant C_MBOX_HANDLE : std_logic_vector(0 to C_OSIF_DATA_WIDTH-1) := X"00000001"
...
variable success : boolean;
variable done : boolean;
signal/variable my_data : std_logic_vector(0 to C_OSIF_DATA_WIDTH-1);
...
begin
...
case state is
...
when STATE_PUT =>
reconos_mbox_put(done, success, o_osif, i_osif, C_MBOX_HANDLE, my_data);
if done then
if success then
state <= STATE_DO_SOMETHING;
else -- no success
state <= HANDLE_ERROR;
end if;
end if;
...
procedure reconos_mbox_tryput(variable completed : out boolean;
variable success : out boolean;
signal osif_task2os : out osif_task2os_t;
signal osif_os2task : in osif_os2task_t;
handle : in std_logic_vector(0 to C_OSIF_DATA_WIDTH-1);
data : in std_logic_vector(0 to C_OSIF_DATA_WIDTH-1));
Sends a 32bit value to the specified message box. The call will not block if the message box is full, but fail (success = false).
This call can also be handled in hardware, if the message box is mapped to a hardware FIFO connected to the executing thread's OSIF (see Message Boxes). If the call is handled in software, it will block until the return value arrives.
| Parameter | Description
|
|---|---|
completed | variable to indicate completion of this MultiCycle command
|
success | signals whether the call succeeded.
|
osif_task2os | record of communication signals to the OS interface
|
osif_os2task | record of communication signals from the OS interface
|
handle | the handle (resource number) of the message box
|
data | variable / signal to store initialization data in
|
Example (inside the synchronization FSM process):
...
constant C_MBOX_HANDLE : std_logic_vector(0 to C_OSIF_DATA_WIDTH-1) := X"00000001"
...
variable success : boolean;
variable done : boolean;
variable/signal my_data : std_logic_vector(0 to C_OSIF_DATA_WIDTH-1);
...
begin
...
case state is
...
when STATE_PUT =>
reconos_mbox_tryput(done, success, o_osif, i_osif, C_MBOX_HANDLE, my_data);
if done then
if success then
state <= STATE_DO_SOMETHING;
else -- no success
state <= HANDLE_ERROR;
end if;
end if;
...
procedure reconos_begin (signal osif_task2os : out osif_task2os_t;
osif_os2task : osif_os2task_t);
Sets all OSIF signals to valid starting values. Used at the beginning of a synchronization state machine (see Hardware Thread FSM).
| Parameter | Description
|
|---|---|
osif_task2os | record of communication signals to the OS interface
|
osif_os2task | record of communication signals from the OS interface
|
Example:
...
fsm_proc : process(clk, reset)
...
begin
if reset = '1' then
...
reconos_reset(o_osif, i_osif);
...
elsif rising_edge(clk) then
...
reconos_begin(o_osif, i_osif);
...
if reconos_ready(i_osif) then
case state is
...
when STATE_SIGNAL =>
...
end if;
end if;
...
function reconos_ready (osif_os2task : osif_os2task_t) return boolean;
Returns true if the hardware thread is neither busy nor blocking. see Hardware Thread FSM and Execution Model for details.
| Parameter | Description
|
|---|---|
osif_os2task | record of communication signals from the OS interface
|
Example: see reconos_begin
procedure reconos_reset (signal osif_task2os : out osif_task2os_t;
osif_os2task : osif_os2task_t);
Resets all OSIF signals to their initialization values. Used in the asynchronous reset block of a [[ReconOSHardwareTaskFSM][synchronization state machine]].
| Parameter | Description
|
|---|---|
osif_task2os | record of communication signals to the OS interface
|
osif_os2task | record of communication signals from the OS interface
|
Example: see reconos_begin
procedure reconos_thread_exit (signal osif_task2os : out osif_task2os_t;
osif_os2task : in osif_os2task_t;
retval : in std_logic_vector(0 to C_OSIF_DATA_WIDTH-1));
Causes the hardware thread to terminate itself. Depending on whether it was created using reconos_hwthread_create() or rthread_create() (eCos or POSIX), it uses cyg_thread_exit() or pthread_exit(), respectively. The latter can pass a return value to possible joiner threads.
| Parameter | Description
|
|---|---|
osif_task2os | record of communication signals to the OS interface
|
osif_os2task | record of communication signals from the OS interface
|
retval | the return value to be passed to possible joiners (POSIX) or printed on diag (eCos)
|
Example (inside the synchronization FSM process):
...
case state is
...
when STATE_EXIT =>
reconos_thread_exit(o_osif, i_osif, X"00000000");
...
This is a list of topics which have not been placed properly within the manual's outline.
TODO
TODO