\section{Writing Yosys extensions in C++} \begin{frame} \sectionpage \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{Program Components and Data Formats} \begin{frame}{\subsecname} \begin{center} \begin{tikzpicture}[scale=0.6, every node/.style={transform shape}] \tikzstyle{process} = [draw, fill=green!10, rectangle, minimum height=3em, minimum width=10em, node distance=15em] \tikzstyle{data} = [draw, fill=blue!10, ellipse, minimum height=3em, minimum width=7em, node distance=15em] \node[process] (vlog) {Verilog Frontend}; \node[process, dashed, fill=green!5] (vhdl) [right of=vlog] {VHDL Frontend}; \node[process] (ilang) [right of=vhdl] {Other Frontends}; \node[data] (ast) [below of=vlog, node distance=5em, xshift=7.5em] {AST}; \node[process] (astfe) [below of=ast, node distance=5em] {AST Frontend}; \node[data] (rtlil) [below of=astfe, node distance=5em, xshift=7.5em] {RTLIL}; \node[process] (pass) [right of=rtlil, node distance=5em, xshift=7.5em] {Passes}; \node[process] (vlbe) [below of=rtlil, node distance=7em, xshift=-13em] {Verilog Backend}; \node[process] (ilangbe) [below of=rtlil, node distance=7em, xshift=0em] {ILANG Backend}; \node[process, fill=green!5] (otherbe) [below of=rtlil, node distance=7em, xshift=+13em] {Other Backends}; \draw[-latex] (vlog) -- (ast); \draw[-latex] (vhdl) -- (ast); \draw[-latex] (ast) -- (astfe); \draw[-latex] (astfe) -- (rtlil); \draw[-latex] (ilang) -- (rtlil); \draw[latex-latex] (rtlil) -- (pass); \draw[-latex] (rtlil) -- (vlbe); \draw[-latex] (rtlil) -- (ilangbe); \draw[-latex] (rtlil) -- (otherbe); \end{tikzpicture} \end{center} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{Simplified RTLIL Entity-Relationship Diagram} \begin{frame}{\subsecname} Between passses and frontends/backends the design is stored in Yosys' internal RTLIL (RTL Intermediate Language) format. For writing Yosys extensions it is key to understand this format. \bigskip \begin{center} \begin{tikzpicture}[scale=0.6, every node/.style={transform shape}] \tikzstyle{entity} = [draw, fill=gray!10, rectangle, minimum height=3em, minimum width=7em, node distance=5em, font={\ttfamily}] \node[entity] (design) {RTLIL::Design}; \node[entity] (module) [right of=design, node distance=11em] {RTLIL::Module} edge [-latex] node[above] {\tiny 1 \hskip3em N} (design); \node[entity] (process) [fill=green!10, right of=module, node distance=10em] {RTLIL::Process} (process.west) edge [-latex] (module); \node[entity] (memory) [fill=red!10, below of=process] {RTLIL::Memory} edge [-latex] (module); \node[entity] (wire) [fill=blue!10, above of=process] {RTLIL::Wire} (wire.west) edge [-latex] (module); \node[entity] (cell) [fill=blue!10, above of=wire] {RTLIL::Cell} (cell.west) edge [-latex] (module); \node[entity] (case) [fill=green!10, right of=process, node distance=10em] {RTLIL::CaseRule} edge [latex-latex] (process); \node[entity] (sync) [fill=green!10, above of=case] {RTLIL::SyncRule} edge [-latex] (process); \node[entity] (switch) [fill=green!10, below of=case] {RTLIL::SwitchRule} edge [-latex] (case); \draw[latex-] (switch.east) -- ++(1em,0) |- (case.east); \end{tikzpicture} \end{center} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{RTLIL without memories and processes} \begin{frame}[fragile]{\subsecname} After the commands {\tt proc} and {\tt memory} (or {\tt memory -nomap}), we are left with a much simpler version of RTLIL: \begin{center} \begin{tikzpicture}[scale=0.6, every node/.style={transform shape}] \tikzstyle{entity} = [draw, fill=gray!10, rectangle, minimum height=3em, minimum width=7em, node distance=5em, font={\ttfamily}] \node[entity] (design) {RTLIL::Design}; \node[entity] (module) [right of=design, node distance=11em] {RTLIL::Module} edge [-latex] node[above] {\tiny 1 \hskip3em N} (design); \node[entity] (wire) [fill=blue!10, right of=module, node distance=10em] {RTLIL::Wire} (wire.west) edge [-latex] (module); \node[entity] (cell) [fill=blue!10, above of=wire] {RTLIL::Cell} (cell.west) edge [-latex] (module); \end{tikzpicture} \end{center} \bigskip Many commands simply choose to only work on this simpler version: \begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont] for (RTLIL::Module *module : design->selected_modules() { if (module->has_memories_warn() || module->has_processes_warn()) continue; .... } \end{lstlisting} For simplicity we only discuss this version of RTLIL in this presentation. \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{Using dump and show commands} \begin{frame}{\subsecname} \begin{itemize} \item The {\tt dump} command prints the design (or parts of it) in ILANG format. This is a text representation of RTLIL. \bigskip \item The {\tt show} command visualizes how the components in the design are connected. \end{itemize} \bigskip When trying to understand what a command does, create a small test case and look at the output of {\tt dump} and {\tt show} before and after the command has been executed. \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{The RTLIL Data Structures} \begin{frame}{\subsecname} The RTLIL data structures are simple structs utilizing {\tt pool<>} and {\tt dict<>} containers (drop-in replacements for {\tt std::unordered\_set<>} and {\tt std::unordered\_map<>}). \bigskip \begin{itemize} \item Most operations are performed directly on the RTLIL structs without setter or getter functions. \bigskip \item In debug builds a consistency checker is run over the in-memory design between commands to make sure that the RTLIL representation is intact. \bigskip \item Most RTLIL structs have helper methods that perform the most common operations. \end{itemize} \bigskip See {\tt yosys/kernel/rtlil.h} for details. \end{frame} \subsubsection{RTLIL::IdString} \begin{frame}{\subsubsecname}{} {\tt RTLIL::IdString} in many ways behave like a {\tt std::string}. It is used for names of RTLIL objects. Internally a RTLIL::IdString object is only a single integer. \medskip The first character of a {\tt RTLIL::IdString} specifies if the name is {\it public\/} or {\it private\/}: \medskip \begin{itemize} \item {\tt RTLIL::IdString[0] == '\textbackslash\textbackslash'}: \\ This is a public name. Usually this means it is a name that was declared in a Verilog file. \bigskip \item {\tt RTLIL::IdString[0] == '\$'}: \\ This is a private name. It was assigned by Yosys. \end{itemize} \bigskip Use the {\tt NEW\_ID} macro to create a new unique private name. \end{frame} \subsubsection{RTLIL::Design and RTLIL::Module} \begin{frame}[t, fragile]{\subsubsecname} The {\tt RTLIL::Design} and {\tt RTLIL::Module} structs are the top-level RTLIL data structures. Yosys always operates on one active design, but can hold many designs in memory. \bigskip \begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++] struct RTLIL::Design { dict modules_; ... }; struct RTLIL::Module { RTLIL::IdString name; dict wires_; dict cells_; std::vector connections_; ... }; \end{lstlisting} (Use the various accessor functions instead of directly working with the {\tt *\_} members.) \end{frame} \subsubsection{The RTLIL::Wire Structure} \begin{frame}[t, fragile]{\subsubsecname} Each wire in the design is represented by a {\tt RTLIL::Wire} struct: \medskip \begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++] struct RTLIL::Wire { RTLIL::IdString name; int width, start_offset, port_id; bool port_input, port_output; ... }; \end{lstlisting} \medskip \hfil\begin{tabular}{p{3cm}l} {\tt width} \dotfill & The total number of bits. E.g. 10 for {\tt [9:0]}. \\ {\tt start\_offset} \dotfill & The lowest bit index. E.g. 3 for {\tt [5:3]}. \\ {\tt port\_id} \dotfill & Zero for non-ports. Positive index for ports. \\ {\tt port\_input} \dotfill & True for {\tt input} and {\tt inout} ports. \\ {\tt port\_output} \dotfill & True for {\tt output} and {\tt inout} ports. \\ \end{tabular} \end{frame} \subsubsection{RTLIL::State and RTLIL::Const} \begin{frame}[t, fragile]{\subsubsecname} The {\tt RTLIL::State} enum represents a simple 1-bit logic level: \smallskip \begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++] enum RTLIL::State { S0 = 0, S1 = 1, Sx = 2, // undefined value or conflict Sz = 3, // high-impedance / not-connected Sa = 4, // don't care (used only in cases) Sm = 5 // marker (used internally by some passes) }; \end{lstlisting} \bigskip The {\tt RTLIL::Const} struct represents a constant multi-bit value: \smallskip \begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++] struct RTLIL::Const { std::vector bits; ... }; \end{lstlisting} \bigskip Notice that Yosys is not using special {\tt VCC} or {\tt GND} driver cells to represent constants. Instead constants are part of the RTLIL representation itself. \end{frame} \subsubsection{The RTLIL::SigSpec Structure} \begin{frame}[t, fragile]{\subsubsecname} The {\tt RTLIL::SigSpec} struct represents a signal vector. Each bit can either be a bit from a wire or a constant value. \bigskip \begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++] struct RTLIL::SigBit { RTLIL::Wire *wire; union { RTLIL::State data; // used if wire == NULL int offset; // used if wire != NULL }; ... }; struct RTLIL::SigSpec { std::vector bits_; // LSB at index 0 ... }; \end{lstlisting} \bigskip The {\tt RTLIL::SigSpec} struct has a ton of additional helper methods to compare, analyze, and manipulate instances of {\tt RTLIL::SigSpec}. \end{frame} \subsubsection{The RTLIL::Cell Structure} \begin{frame}[t, fragile]{\subsubsecname (1/2)} The {\tt RTLIL::Cell} struct represents an instance of a module or library cell. \smallskip The ports of the cell are associated with {\tt RTLIL::SigSpec} instances and the parameters are associated with {\tt RTLIL::Const} instances: \bigskip \begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++] struct RTLIL::Cell { RTLIL::IdString name, type; dict connections_; dict parameters; ... }; \end{lstlisting} \bigskip The {\tt type} may refer to another module in the same design, a cell name from a cell library, or a cell name from the internal cell library: \begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{6pt}{7pt}\selectfont] $not $pos $neg $and $or $xor $xnor $reduce_and $reduce_or $reduce_xor $reduce_xnor $reduce_bool $shl $shr $sshl $sshr $lt $le $eq $ne $eqx $nex $ge $gt $add $sub $mul $div $mod $pow $logic_not $logic_and $logic_or $mux $pmux $slice $concat $lut $assert $sr $dff $dffsr $adff $dlatch $dlatchsr $memrd $memwr $mem $fsm $_NOT_ $_AND_ $_OR_ $_XOR_ $_MUX_ $_SR_NN_ $_SR_NP_ $_SR_PN_ $_SR_PP_ $_DFF_N_ $_DFF_P_ $_DFF_NN0_ $_DFF_NN1_ $_DFF_NP0_ $_DFF_NP1_ $_DFF_PN0_ $_DFF_PN1_ $_DFF_PP0_ $_DFF_PP1_ $_DFFSR_NNN_ $_DFFSR_NNP_ $_DFFSR_NPN_ $_DFFSR_NPP_ $_DFFSR_PNN_ $_DFFSR_PNP_ $_DFFSR_PPN_ $_DFFSR_PPP_ $_DLATCH_N_ $_DLATCH_P_ $_DLATCHSR_NNN_ $_DLATCHSR_NNP_ $_DLATCHSR_NPN_ $_DLATCHSR_NPP_ $_DLATCHSR_PNN_ $_DLATCHSR_PNP_ $_DLATCHSR_PPN_ $_DLATCHSR_PPP_ \end{lstlisting} \end{frame} \begin{frame}[t, fragile]{\subsubsecname (2/2)} Simulation models (i.e. {\it documentation\/} :-) for the internal cell library: \smallskip \hskip2em {\tt yosys/techlibs/common/simlib.v} and \\ \hskip2em {\tt yosys/techlibs/common/simcells.v} \bigskip The lower-case cell types (such as {\tt \$and}) are parameterized cells of variable width. This so-called {\it RTL Cells\/} are the cells described in {\tt simlib.v}. \bigskip The upper-case cell types (such as {\tt \$\_AND\_}) are single-bit cells that are not parameterized. This so-called {\it Internal Logic Gates} are the cells described in {\tt simcells.v}. \bigskip The consistency checker also checks the interfaces to the internal cell library. If you want to use private cell types for your own purposes, use the {\tt \$\_\_}-prefix to avoid name collisions. \end{frame} \subsubsection{Connecting wires or constant drivers} \begin{frame}[t, fragile]{\subsubsecname} Additional connections between wires or between wires and constants are modelled using {\tt RTLIL::Module::connections}: \bigskip \begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++] typedef std::pair RTLIL::SigSig; struct RTLIL::Module { ... std::vector connections_; ... }; \end{lstlisting} \bigskip {\tt RTLIL::SigSig::first} is the driven signal and {\tt RTLIL::SigSig::second} is the driving signal. Example usage (setting wire {\tt foo} to value {\tt 42}): \begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++] module->connect(module->wire("\\foo"), RTLIL::SigSpec(42, module->wire("\\foo")->width)); \end{lstlisting} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{Creating modules from scratch} \begin{frame}[t, fragile]{\subsecname} Let's create the following module using the RTLIL API: \smallskip \begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=Verilog] module absval(input signed [3:0] a, output [3:0] y); assign y = a[3] ? -a : a; endmodule \end{lstlisting} \smallskip \begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++] RTLIL::Module *module = new RTLIL::Module; module->name = "\\absval"; RTLIL::Wire *a = module->addWire("\\a", 4); a->port_input = true; a->port_id = 1; RTLIL::Wire *y = module->addWire("\\y", 4); y->port_output = true; y->port_id = 2; RTLIL::Wire *a_inv = module->addWire(NEW_ID, 4); module->addNeg(NEW_ID, a, a_inv, true); module->addMux(NEW_ID, a, a_inv, RTLIL::SigSpec(a, 1, 3), y); module->fixup_ports(); \end{lstlisting} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{Modifying modules} \begin{frame}{\subsecname} Most commands modify existing modules, not create new ones. When modifying existing modules, stick to the following DOs and DON'Ts: \begin{itemize} \item Do not remove wires. Simply disconnect them and let a successive {\tt clean} command worry about removing it. \item Use {\tt module->fixup\_ports()} after changing the {\tt port\_*} properties of wires. \item You can safely remove cells or change the {\tt connections} property of a cell, but be careful when changing the size of the {\tt SigSpec} connected to a cell port. \item Use the {\tt SigMap} helper class (see next slide) when you need a unique handle for each signal bit. \end{itemize} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
/*
    ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
                 2011,2012 Giovanni Di Sirio.

    This file is part of ChibiOS/RT.

    ChibiOS/RT is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.

    ChibiOS/RT 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/**
 * @file    chqueues.h
 * @brief   I/O Queues macros and structures.
 *
 * @addtogroup io_queues
 * @{
 */

#ifndef _CHQUEUES_H_
#define _CHQUEUES_H_

#if CH_USE_QUEUES || defined(__DOXYGEN__)

/**
 * @name    Queue functions returned status value
 * @{
 */
#define Q_OK            RDY_OK      /**< @brief Operation successful.       */
#define Q_TIMEOUT       RDY_TIMEOUT /**< @brief Timeout condition.          */
#define Q_RESET         RDY_RESET   /**< @brief Queue has been reset.       */
#define Q_EMPTY         -3          /**< @brief Queue empty.                */
#define Q_FULL          -4          /**< @brief Queue full,                 */
/** @} */

/**
 * @brief   Type of a generic I/O queue structure.
 */
typedef struct GenericQueue GenericQueue;

/** @brief Queue notification callback type.*/
typedef void (*qnotify_t)(GenericQueue *qp);

/**
 * @brief   Generic I/O queue structure.
 * @details This structure represents a generic Input or Output asymmetrical
 *          queue. The queue is asymmetrical because one end is meant to be
 *          accessed from a thread context, and thus can be blocking, the other
 *          end is accessible from interrupt handlers or from within a kernel
 *          lock zone (see <b>I-Locked</b> and <b>S-Locked</b> states in
 *          @ref system_states) and is non-blocking.
 */
struct GenericQueue {
  ThreadsQueue          q_waiting;  /**< @brief Queue of waiting threads.   */
  size_t                q_counter;  /**< @brief Resources counter.          */
  uint8_t               *q_buffer;  /**< @brief Pointer to the queue buffer.*/
  uint8_t               *q_top;     /**< @brief Pointer to the first location
                                                after the buffer.           */
  uint8_t               *q_wrptr;   /**< @brief Write pointer.              */
  uint8_t               *q_rdptr;   /**< @brief Read pointer.               */
  qnotify_t             q_notify;   /**< @brief Data notification callback. */
  void                  *q_link;    /**< @brief Application defined field.  */
};

/**
 * @name    Macro Functions
 * @{
 */
/**
 * @brief   Returns the queue's buffer size.
 *
 * @param[in] qp        pointer to a @p GenericQueue structure.
 * @return              The buffer size.
 *
 * @iclass
 */
#define chQSizeI(qp) ((size_t)((qp)->q_top - (qp)->q_buffer))

/**
 * @brief   Queue space.
 * @details Returns the used space if used on an input queue or the empty
 *          space if used on an output queue.
 *
 * @param[in] qp        pointer to a @p GenericQueue structure.
 * @return              The buffer space.
 *
 * @iclass
 */
#define chQSpaceI(qp) ((qp)->q_counter)

/**
 * @brief   Returns the queue application-defined link.
 * @note    This function can be called in any context.
 *
 * @param[in] qp        pointer to a @p GenericQueue structure.
 * @return              The application-defined link.
 *
 * @special
 */
#define chQGetLink(qp) ((qp)->q_link)
/** @} */

/**
 * @extends GenericQueue
 *
 * @brief   Type of an input queue structure.
 * @details This structure represents a generic asymmetrical input queue.
 *          Writing to the queue is non-blocking and can be performed from
 *          interrupt handlers or from within a kernel lock zone (see
 *          <b>I-Locked</b> and <b>S-Locked</b> states in @ref system_states).
 *          Reading the queue can be a blocking operation and is supposed to
 *          be performed by a system thread.
 */
typedef GenericQueue InputQueue;

/**
 * @name    Macro Functions
 * @{
 */
/**
 * @brief   Returns the filled space into an input queue.
 *
 * @param[in] iqp       pointer to an @p InputQueue structure
 * @return              The number of full bytes in the queue.
 * @retval 0            if the queue is empty.
 *
 * @iclass
 */
#define chIQGetFullI(iqp) chQSpaceI(iqp)

/**
 * @brief   Returns the empty space into an input queue.
 *
 * @param[in] iqp       pointer to an @p InputQueue structure
 * @return              The number of empty bytes in the queue.
 * @retval 0            if the queue is full.
 *
 * @iclass
 */
#define chIQGetEmptyI(iqp) (chQSizeI(iqp) - chQSpaceI(iqp))

/**
 * @brief   Evaluates to @p TRUE if the specified input queue is empty.
 *
 * @param[in] iqp       pointer to an @p InputQueue structure.
 * @return              The queue status.
 * @retval FALSE        The queue is not empty.
 * @retval TRUE         The queue is empty.
 *
 * @iclass
 */
#define chIQIsEmptyI(iqp) ((bool_t)(chQSpaceI(iqp) <= 0))

/**
 * @brief   Evaluates to @p TRUE if the specified input queue is full.
 *
 * @param[in] iqp       pointer to an @p InputQueue structure.
 * @return              The queue status.
 * @retval FALSE        The queue is not full.
 * @retval TRUE         The queue is full.
 *
 * @iclass
 */
#define chIQIsFullI(iqp) ((bool_t)(((iqp)->q_wrptr == (iqp)->q_rdptr) &&   \
                                   ((iqp)->q_counter != 0)))

/**
 * @brief   Input queue read.
 * @details This function reads a byte value from an input queue. If the queue
 *          is empty then the calling thread is suspended until a byte arrives
 *          in the queue.
 *
 * @param[in] iqp       pointer to an @p InputQueue structure
 * @return              A byte value from the queue.
 * @retval Q_RESET      if the queue has been reset.
 *
 * @api
 */
#define chIQGet(iqp) chIQGetTimeout(iqp, TIME_INFINITE)
/** @} */

/**
 * @brief   Data part of a static input queue initializer.
 * @details This macro should be used when statically initializing an
 *          input queue that is part of a bigger structure.
 *
 * @param[in] name      the name of the input queue variable
 * @param[in] buffer    pointer to the queue buffer area
 * @param[in] size      size of the queue buffer area
 * @param[in] inotify   input notification callback pointer
 * @param[in] link      application defined pointer
 */
#define _INPUTQUEUE_DATA(name, buffer, size, inotify, link) {               \
  _THREADSQUEUE_DATA(name),                                                 \
  0,                                                                        \
  (uint8_t *)(buffer),                                                      \
  (uint8_t *)(buffer) + (size),                                             \
  (uint8_t *)(buffer),                                                      \
  (uint8_t *)(buffer),                                                      \
  (inotify),                                                                \
  (link)                                                                    \
}

/**
 * @brief   Static input queue initializer.
 * @details Statically initialized input queues require no explicit
 *          initialization using @p chIQInit().
 *
 * @param[in] name      the name of the input queue variable
 * @param[in] buffer    pointer to the queue buffer area
 * @param[in] size      size of the queue buffer area
 * @param[in] inotify   input notification callback pointer
 * @param[in] link      application defined pointer
 */
#define INPUTQUEUE_DECL(name, buffer, size, inotify, link)                  \
  InputQueue name = _INPUTQUEUE_DATA(name, buffer, size, inotify, link)

/**
 * @extends GenericQueue
 *
 * @brief   Type of an output queue structure.
 * @details This structure represents a generic asymmetrical output queue.
 *          Reading from the queue is non-blocking and can be performed from
 *          interrupt handlers or from within a kernel lock zone (see
 *          <b>I-Locked</b> and <b>S-Locked</b> states in @ref system_states).
 *          Writing the queue can be a blocking operation and is supposed to
 *          be performed by a system thread.
 */
typedef GenericQueue OutputQueue;

/**
 * @name    Macro Functions
 * @{
 */
/**
 * @brief   Returns the filled space into an output queue.
 *
 * @param[in] oqp       pointer to an @p OutputQueue structure
 * @return              The number of full bytes in the queue.
 * @retval 0            if the queue is empty.
 *
 * @iclass
 */
#define chOQGetFullI(oqp) (chQSizeI(oqp) - chQSpaceI(oqp))

/**
 * @brief   Returns the empty space into an output queue.
 *
 * @param[in] iqp       pointer to an @p OutputQueue structure
 * @return              The number of empty bytes in the queue.
 * @retval 0            if the queue is full.
 *
 * @iclass
 */
#define chOQGetEmptyI(iqp) chQSpaceI(oqp)

/**
 * @brief   Evaluates to @p TRUE if the specified output queue is empty.
 *
 * @param[in] oqp       pointer to an @p OutputQueue structure.
 * @return              The queue status.
 * @retval FALSE        The queue is not empty.
 * @retval TRUE         The queue is empty.
 *
 * @iclass
 */
#define chOQIsEmptyI(oqp) ((bool_t)(((oqp)->q_wrptr == (oqp)->q_rdptr) &&   \
                                    ((oqp)->q_counter != 0)))

/**
 * @brief   Evaluates to @p TRUE if the specified output queue is full.
 *
 * @param[in] oqp       pointer to an @p OutputQueue structure.
 * @return              The queue status.
 * @retval FALSE        The queue is not full.
 * @retval TRUE         The queue is full.
 *
 * @iclass
 */
#define chOQIsFullI(oqp) ((bool_t)(chQSpaceI(oqp) <= 0))

/**
 * @brief   Output queue write.
 * @details This function writes a byte value to an output queue. If the queue
 *          is full then the calling thread is suspended until there is space
 *          in the queue.
 *
 * @param[in] oqp       pointer to an @p OutputQueue structure
 * @param[in] b         the byte value to be written in the queue
 * @return              The operation status.
 * @retval Q_OK         if the operation succeeded.
 * @retval Q_RESET      if the queue has been reset.
 *
 * @api
 */
#define chOQPut(oqp, b) chOQPutTimeout(oqp, b, TIME_INFINITE)
 /** @} */

/**
 * @brief   Data part of a static output queue initializer.
 * @details This macro should be used when statically initializing an
 *          output queue that is part of a bigger structure.
 *
 * @param[in] name      the name of the output queue variable
 * @param[in] buffer    pointer to the queue buffer area
 * @param[in] size      size of the queue buffer area
 * @param[in] onotify   output notification callback pointer
 * @param[in] link      application defined pointer
 */
#define _OUTPUTQUEUE_DATA(name, buffer, size, onotify, link) {              \
  _THREADSQUEUE_DATA(name),                                                 \
  (size),                                                                   \
  (uint8_t *)(buffer),                                                      \
  (uint8_t *)(buffer) + (size),                                             \
  (uint8_t *)(buffer),                                                      \
  (uint8_t *)(buffer),                                                      \
  (onotify),                                                                \
  (link)                                                                    \
}

/**
 * @brief   Static output queue initializer.
 * @details Statically initialized output queues require no explicit
 *          initialization using @p chOQInit().
 *
 * @param[in] name      the name of the output queue variable
 * @param[in] buffer    pointer to the queue buffer area
 * @param[in] size      size of the queue buffer area
 * @param[in] onotify   output notification callback pointer
 * @param[in] link      application defined pointer
 */
#define OUTPUTQUEUE_DECL(name, buffer, size, onotify, link)                 \
  OutputQueue name = _OUTPUTQUEUE_DATA(name, buffer, size, onotify, link)

#ifdef __cplusplus
extern "C" {
#endif
  void chIQInit(InputQueue *iqp, uint8_t *bp, size_t size, qnotify_t infy,
                void *link);
  void chIQResetI(InputQueue *iqp);
  msg_t chIQPutI(InputQueue *iqp, uint8_t b);
  msg_t chIQGetTimeout(InputQueue *iqp, systime_t time);
  size_t chIQReadTimeout(InputQueue *iqp, uint8_t *bp,
                         size_t n, systime_t time);

  void chOQInit(OutputQueue *oqp, uint8_t *bp, size_t size, qnotify_t onfy,
                void *link);
  void chOQResetI(OutputQueue *oqp);
  msg_t chOQPutTimeout(OutputQueue *oqp, uint8_t b, systime_t time);
  msg_t chOQGetI(OutputQueue *oqp);
  size_t chOQWriteTimeout(OutputQueue *oqp, const uint8_t *bp,
                          size_t n, systime_t time);
#ifdef __cplusplus
}
#endif
#endif /* CH_USE_QUEUES */

#endif /* _CHQUEUES_H_ */

/** @} */