blob: 130d932d3f96906e0eb77e56ded398c1ea70e865 [file] [log] [blame]
<!--
Documentation/_templates/layout.html
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership. The
ASF licenses this file to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
-->
<!DOCTYPE html>
<html class="writer-html5" lang="en">
<head>
<meta charset="utf-8" /><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Smaller Vector Tables &mdash; NuttX latest documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/css/theme.css" />
<link rel="stylesheet" type="text/css" href="../_static/copybutton.css" />
<link rel="stylesheet" type="text/css" href="../_static/design-style.1e8bd061cd6da7fc9cf755528e8ffc24.min.css" />
<link rel="stylesheet" type="text/css" href="../_static/custom.css" />
<link rel="shortcut icon" href="../_static/favicon.ico"/>
<script src="../_static/jquery.js"></script>
<script src="../_static/_sphinx_javascript_frameworks_compat.js"></script>
<script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script>
<script src="../_static/doctools.js"></script>
<script src="../_static/sphinx_highlight.js"></script>
<script src="../_static/clipboard.min.js"></script>
<script src="../_static/copybutton.js"></script>
<script src="../_static/design-tabs.js"></script>
<script src="../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" />
<link rel="next" title="How to port" href="port.html" />
<link rel="prev" title="Signaling Semaphores and Priority Inheritance" href="signaling_sem_priority_inheritance.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../index.html" class="icon icon-home"> NuttX
</a>
<!-- this version selector is quite ugly, should be probably replaced by something
more modern -->
<div class="version-selector">
<select onchange="javascript:location.href = this.value;">
<option value="../../latest" selected="selected">latest</option>
<option value="../../10.0.0" >10.0.0</option>
<option value="../../10.0.1" >10.0.1</option>
<option value="../../10.1.0" >10.1.0</option>
<option value="../../10.2.0" >10.2.0</option>
<option value="../../10.3.0" >10.3.0</option>
<option value="../../11.0.0" >11.0.0</option>
<option value="../../12.0.0" >12.0.0</option>
<option value="../../12.1.0" >12.1.0</option>
<option value="../../12.2.0" >12.2.0</option>
<option value="../../12.2.1" >12.2.1</option>
<option value="../../12.3.0" >12.3.0</option>
<option value="../../12.4.0" >12.4.0</option>
<option value="../../12.5.0" >12.5.0</option>
<option value="../../12.5.1" >12.5.1</option>
<option value="../../12.6.0" >12.6.0</option>
<option value="../../12.7.0" >12.7.0</option>
<option value="../../12.8.0" >12.8.0</option>
<option value="../../12.9.0" >12.9.0</option>
<option value="../../12.10.0" >12.10.0</option>
<option value="../../12.11.0" >12.11.0</option>
</select>
</div>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Table of Contents</span></p>
<ul class="current">
<li class="toctree-l1"><a class="reference internal" href="../index.html">Home</a></li>
<li class="toctree-l1"><a class="reference internal" href="../introduction/index.html">Introduction</a></li>
<li class="toctree-l1"><a class="reference internal" href="../quickstart/index.html">Getting Started</a></li>
<li class="toctree-l1"><a class="reference internal" href="../contributing/index.html">Contributing</a></li>
<li class="toctree-l1"><a class="reference internal" href="../introduction/inviolables.html">The Inviolable Principles of NuttX</a></li>
<li class="toctree-l1"><a class="reference internal" href="../platforms/index.html">Supported Platforms</a></li>
<li class="toctree-l1"><a class="reference internal" href="../components/index.html">OS Components</a></li>
<li class="toctree-l1"><a class="reference internal" href="../applications/index.html">Applications</a></li>
<li class="toctree-l1"><a class="reference internal" href="../implementation/index.html">Implementation Details</a></li>
<li class="toctree-l1"><a class="reference internal" href="../reference/index.html">API Reference</a></li>
<li class="toctree-l1"><a class="reference internal" href="../faq/index.html">FAQ</a></li>
<li class="toctree-l1"><a class="reference internal" href="../debugging/index.html">Debugging</a></li>
<li class="toctree-l1 current"><a class="reference internal" href="index.html">Guides</a><ul class="current">
<li class="toctree-l2"><a class="reference internal" href="nfs.html">NFS Client How-To</a></li>
<li class="toctree-l2"><a class="reference internal" href="usbtrace.html">USB Device Trace</a></li>
<li class="toctree-l2"><a class="reference internal" href="simulator.html">Simulator</a></li>
<li class="toctree-l2"><a class="reference internal" href="rndis.html">How to use RNDIS</a></li>
<li class="toctree-l2"><a class="reference internal" href="drivers.html">Drivers</a></li>
<li class="toctree-l2"><a class="reference internal" href="cpp_cmake.html">C++ Example using CMake</a></li>
<li class="toctree-l2"><a class="reference internal" href="pysimcoder.html">pysimCoder integration with NuttX</a></li>
<li class="toctree-l2"><a class="reference internal" href="customboards.html">Custom Boards How-To</a></li>
<li class="toctree-l2"><a class="reference internal" href="customapps.html">Custom Apps How-to</a></li>
<li class="toctree-l2"><a class="reference internal" href="citests.html">Running CI Test Locally</a></li>
<li class="toctree-l2"><a class="reference internal" href="zerolatencyinterrupts.html">High Performance: Zero Latency Interrupts, Maskable Nested Interrupts</a></li>
<li class="toctree-l2"><a class="reference internal" href="fortify.html">Fortify</a></li>
<li class="toctree-l2"><a class="reference internal" href="nestedinterrupts.html">Nested Interrupts</a></li>
<li class="toctree-l2"><a class="reference internal" href="ofloader.html">Open Flash Loader</a></li>
<li class="toctree-l2"><a class="reference internal" href="testingtcpip.html">Testing TCP/IP Network Stacks</a></li>
<li class="toctree-l2"><a class="reference internal" href="automounter.html">Auto-Mounter</a></li>
<li class="toctree-l2"><a class="reference internal" href="stm32nullpointer.html">STM32 Null Pointer Detection</a></li>
<li class="toctree-l2"><a class="reference internal" href="stm32ccm.html">STM32 CCM Allocator</a></li>
<li class="toctree-l2"><a class="reference internal" href="etcromfs.html">etc romfs</a></li>
<li class="toctree-l2"><a class="reference internal" href="thread_local_storage.html">Thread Local Storage</a></li>
<li class="toctree-l2"><a class="reference internal" href="devicetree.html">Device Tree</a></li>
<li class="toctree-l2"><a class="reference internal" href="changing_systemclockconfig.html">Changing the System Clock Configuration</a></li>
<li class="toctree-l2"><a class="reference internal" href="usingkernelthreads.html">Using Kernel Threads</a></li>
<li class="toctree-l2"><a class="reference internal" href="armv7m_runtimestackcheck.html">ARMv7-M Run Time Stack Checking</a></li>
<li class="toctree-l2"><a class="reference internal" href="include_files_board_h.html">Including Files in board.h</a></li>
<li class="toctree-l2"><a class="reference internal" href="specialstuff_in_nuttxheaderfiles.html">Why can’t I put my special stuff in NuttX header files?</a></li>
<li class="toctree-l2"><a class="reference internal" href="kernel_threads_with_custom_stacks.html">Kernel Threads with Custom Stacks</a></li>
<li class="toctree-l2"><a class="reference internal" href="versioning_and_task_names.html">Versioning and Task Names</a></li>
<li class="toctree-l2"><a class="reference internal" href="logging_rambuffer.html">Logging to a RAM Buffer</a></li>
<li class="toctree-l2"><a class="reference internal" href="ipv6.html">IPv6</a></li>
<li class="toctree-l2"><a class="reference internal" href="integrate_newlib.html">Integrating with Newlib</a></li>
<li class="toctree-l2"><a class="reference internal" href="protected_build.html">NuttX Protected Build</a></li>
<li class="toctree-l2"><a class="reference internal" href="platform_directories.html">Platform Directories</a></li>
<li class="toctree-l2"><a class="reference internal" href="port_drivers_to_stm32f7.html">Porting Drivers to the STM32 F7</a></li>
<li class="toctree-l2"><a class="reference internal" href="semihosting.html">Semihosting</a></li>
<li class="toctree-l2"><a class="reference internal" href="renode.html">Run NuttX on Renode</a></li>
<li class="toctree-l2"><a class="reference internal" href="signal_events_interrupt_handlers.html">Signaling Events from Interrupt Handlers</a></li>
<li class="toctree-l2"><a class="reference internal" href="signaling_sem_priority_inheritance.html">Signaling Semaphores and Priority Inheritance</a></li>
<li class="toctree-l2 current"><a class="current reference internal" href="#">Smaller Vector Tables</a><ul>
<li class="toctree-l3"><a class="reference internal" href="#software-irq-remapping">Software IRQ Remapping</a><ul>
<li class="toctree-l4"><a class="reference internal" href="#irq-attach"><code class="docutils literal notranslate"><span class="pre">irq_attach()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="#irq-dispatch"><code class="docutils literal notranslate"><span class="pre">irq_dispatch()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="#irq-initialize"><code class="docutils literal notranslate"><span class="pre">irq_initialize()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="#g-mapirq"><code class="docutils literal notranslate"><span class="pre">g_mapirq[]</span></code></a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="#hardware-vector-remapping">Hardware Vector Remapping</a></li>
<li class="toctree-l3"><a class="reference internal" href="#vector-definitions">Vector Definitions</a><ul>
<li class="toctree-l4"><a class="reference internal" href="#interrupt-handler-definitions">Interrupt Handler Definitions</a></li>
<li class="toctree-l4"><a class="reference internal" href="#a-complication">A Complication</a></li>
<li class="toctree-l4"><a class="reference internal" href="#dubious-performance-improvements">Dubious Performance Improvements</a></li>
<li class="toctree-l4"><a class="reference internal" href="#complexity-and-generalizability">Complexity and Generalizability</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="port.html">How to port</a></li>
<li class="toctree-l2"><a class="reference internal" href="updating_release_system_elf.html">Updating a Release System with ELF Programs</a></li>
<li class="toctree-l2"><a class="reference internal" href="partially_linked_elf.html">ELF Programs – With Symbol Tables</a></li>
<li class="toctree-l2"><a class="reference internal" href="fully_linked_elf.html">ELF Programs – No Symbol Tables</a></li>
<li class="toctree-l2"><a class="reference internal" href="building_nuttx_with_app_out_of_src_tree.html">Building NuttX with Applications Outside the Source Tree</a></li>
<li class="toctree-l2"><a class="reference internal" href="building_uclibcpp.html">Building uClibc++</a></li>
<li class="toctree-l2"><a class="reference internal" href="custom_app_directories.html">Custom Application Directories</a></li>
<li class="toctree-l2"><a class="reference internal" href="multiple_nsh_sessions.html">Multiple NSH Sessions</a></li>
<li class="toctree-l2"><a class="reference internal" href="nsh_network_link_management.html">NSH Network Link Management</a></li>
<li class="toctree-l2"><a class="reference internal" href="ram_rom_disks.html">RAM Disks and ROM Disks</a></li>
<li class="toctree-l2"><a class="reference internal" href="reading_can_msgs.html">Reading CAN Messages</a></li>
<li class="toctree-l2"><a class="reference internal" href="remove_device_drivers_nsh.html">Removing Device Drivers with NSH</a></li>
<li class="toctree-l2"><a class="reference internal" href="rust.html">Rust in NuttX</a></li>
<li class="toctree-l2"><a class="reference internal" href="optee.html">Interfacing with OP-TEE</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../glossary.html">Glossary</a></li>
<li class="toctree-l1"><a class="reference internal" href="../logos/index.html">NuttX Logos</a></li>
<li class="toctree-l1"><a class="reference internal" href="../_tags/tagsindex.html">Tags</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../index.html">NuttX</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="index.html">Guides</a></li>
<li class="breadcrumb-item active">Smaller Vector Tables</li>
<li class="wy-breadcrumbs-aside">
<a href="https://github.com/apache/nuttx/blob/master/Documentation/guides/smaller_vector_tables.rst" class="fa fa-github"> Edit on GitHub</a>
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<section id="smaller-vector-tables">
<h1>Smaller Vector Tables<a class="headerlink" href="#smaller-vector-tables" title="Permalink to this heading"></a></h1>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>Migrated from:
<a class="reference external" href="https://cwiki.apache.org/confluence/display/NUTTX/Smaller+Vector+Tables">https://cwiki.apache.org/confluence/display/NUTTX/Smaller+Vector+Tables</a></p>
</div>
<p>One of the largest OS data structures is the vector table,
<code class="docutils literal notranslate"><span class="pre">g_irqvector[]</span></code>. This is the table that holds the vector
information when <code class="docutils literal notranslate"><span class="pre">irq_attach()</span></code> is called and used to
dispatch interrupts by <code class="docutils literal notranslate"><span class="pre">irq_dispatch()</span></code>. Recent changes
have made that table even larger, for 32-bit arm the
size of that table is given by:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">nbytes</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">number_of_interrupts</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="p">(</span><span class="mi">2</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">sizeof</span><span class="p">(</span><span class="kt">void</span><span class="w"> </span><span class="o">*</span><span class="p">))</span>
</pre></div>
</div>
<p>We will focus on the STM32 for this discussion to keep
things simple. However, this discussion applies to all
architectures.</p>
<p>The number of (physical) interrupt vectors supported by
the MCU hardwared given by the definition <code class="docutils literal notranslate"><span class="pre">NR_IRQ</span></code> which
is provided in a header file in <code class="docutils literal notranslate"><span class="pre">arch/arm/include/stm32</span></code>.
This is, by default, the value of <code class="docutils literal notranslate"><span class="pre">number_of_interrupts</span></code>
in the above equation.</p>
<p>For a 32-bit ARM like the STM32 with, say, 100 interrupt
vectors, this size would be 800 bytes of memory. That is
not a lot for high-end MCUs with a lot of RAM memory,
but could be a show stopper for MCUs with minimal RAM.</p>
<p>Two approaches for reducing the size of the vector tables
are described below. Both depend on the fact that not all
interrupts are used on a given MCU. Most of the time,
the majority of entries in <code class="docutils literal notranslate"><span class="pre">g_irqvector[]</span></code> are zero because
only a small number of interrupts are actually attached
and enabled by the application. If you know that certain
IRQ numbers are not going to be used, then it is possible
to filter those out and reduce the size to the number of
supported interrupts.</p>
<p>For example, if the actual number of interrupts used were
20, the the above requirement would go from 800 bytes to
160 bytes.</p>
<section id="software-irq-remapping">
<h2>Software IRQ Remapping<a class="headerlink" href="#software-irq-remapping" title="Permalink to this heading"></a></h2>
<p><cite>[On March 3, 2017, support for this “Software IRQ Remapping”
as included in the NuttX repository.]</cite></p>
<p>One of the simplest way of reducing the size of
<code class="docutils literal notranslate"><span class="pre">g_irqvector[]</span></code> would be to remap the large set of physical
interrupt vectors into a much small set of interrupts that
are actually used. For the sake of discussion, let’s
imagine two new configuration settings:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">CONFIG_ARCH_MINIMAL_VECTORTABLE</span></code>: Enables IRQ mapping</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">CONFIG_ARCH_NUSER_INTERRUPTS</span></code>: The number of IRQs after mapping.</p></li>
</ul>
<p>Then it could allocate the interrupt vector table to be
size <code class="docutils literal notranslate"><span class="pre">CONFIG_IRQ_NMAPPED_IRQ</span></code> instead of the much bigger
<code class="docutils literal notranslate"><span class="pre">NR_IRQS</span></code>:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cp">#ifdef CONFIG_ARCH_MINIMAL_VECTORTABLE</span>
<span class="k">struct</span><span class="w"> </span><span class="nc">irq_info_s</span><span class="w"> </span><span class="n">g_irqvector</span><span class="p">[</span><span class="n">CONFIG_ARCH_NUSER_INTERRUPTS</span><span class="p">];</span>
<span class="cp">#else</span>
<span class="k">struct</span><span class="w"> </span><span class="nc">irq_info_s</span><span class="w"> </span><span class="n">g_irqvector</span><span class="p">[</span><span class="n">NR_IRQS</span><span class="p">];</span>
<span class="cp">#endif</span>
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">g_irqvector[]</span></code> table is accessed in only three places:</p>
<section id="irq-attach">
<h3><code class="docutils literal notranslate"><span class="pre">irq_attach()</span></code><a class="headerlink" href="#irq-attach" title="Permalink to this heading"></a></h3>
<p><code class="docutils literal notranslate"><span class="pre">irq_attach()</span></code> receives the physical vector number along
with the information needed later to dispatch interrupts:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="kt">int</span><span class="w"> </span><span class="nf">irq_attach</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">irq</span><span class="p">,</span><span class="w"> </span><span class="n">xcpt_t</span><span class="w"> </span><span class="n">isr</span><span class="p">,</span><span class="w"> </span><span class="n">FAR</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="o">*</span><span class="n">arg</span><span class="p">);</span>
</pre></div>
</div>
<p>Logic in <code class="docutils literal notranslate"><span class="pre">irq_attach()</span></code> would map the incoming physical
vector number to a table index like:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cp">#ifdef CONFIG_ARCH_MINIMAL_VECTORTABLE</span>
<span class="kt">int</span><span class="w"> </span><span class="n">ndx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_irqmap</span><span class="p">[</span><span class="n">irq</span><span class="p">];</span>
<span class="cp">#else</span>
<span class="kt">int</span><span class="w"> </span><span class="n">ndx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">irq</span><span class="p">;</span>
<span class="cp">#endif</span>
</pre></div>
</div>
<p>where <code class="docutils literal notranslate"><span class="pre">up_mapirq[]</span></code> is an array indexed by the physical
interrupt vector number and contains the new, mapped
interrupt vector table index. This array must be
provided by platform-specific code.</p>
<p><code class="docutils literal notranslate"><span class="pre">irq_attach()</span></code> would this use this index to set the <code class="docutils literal notranslate"><span class="pre">g_irqvector[]</span></code>.</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">g_irqvector</span><span class="p">[</span><span class="n">ndx</span><span class="p">].</span><span class="n">handler</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">isr</span><span class="p">;</span>
<span class="n">g_irqvector</span><span class="p">[</span><span class="n">ndx</span><span class="p">].</span><span class="n">arg</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">arg</span><span class="p">;</span>
</pre></div>
</div>
</section>
<section id="irq-dispatch">
<h3><code class="docutils literal notranslate"><span class="pre">irq_dispatch()</span></code><a class="headerlink" href="#irq-dispatch" title="Permalink to this heading"></a></h3>
<p><code class="docutils literal notranslate"><span class="pre">irq_dispatch()</span></code> is called by MCU logic when an interrupt is received:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"> </span><span class="nf">irq_dispatch</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">irq</span><span class="p">,</span><span class="w"> </span><span class="n">FAR</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="o">*</span><span class="n">context</span><span class="p">);</span>
</pre></div>
</div>
<p>Where, again irq is the physical interrupt vector number.</p>
<p><code class="docutils literal notranslate"><span class="pre">irq_dispatch()</span></code> would do essentially the same thing as
<code class="docutils literal notranslate"><span class="pre">irq_attach()</span></code>. First it would map the irq number to
a table index:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cp">#ifdef CONFIG_ARCH_MINIMAL_VECTORTABLE</span>
<span class="kt">int</span><span class="w"> </span><span class="n">ndx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_irqmap</span><span class="p">[</span><span class="n">irq</span><span class="p">];</span>
<span class="cp">#else</span>
<span class="kt">int</span><span class="w"> </span><span class="n">ndx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">irq</span><span class="p">;</span>
<span class="cp">#endif</span>
</pre></div>
</div>
<p>Then dispatch the interrupt handling to the attached
interrupt handler. NOTE that the physical vector
number is passed to the handler so it is completely
unaware of the underlying <cite>shell</cite> game:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">vector</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_irqvector</span><span class="p">[</span><span class="n">ndx</span><span class="p">].</span><span class="n">handler</span><span class="p">;</span>
<span class="n">arg</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_irqvector</span><span class="p">[</span><span class="n">ndx</span><span class="p">].</span><span class="n">arg</span><span class="p">;</span>
<span class="n">vector</span><span class="p">(</span><span class="n">irq</span><span class="p">,</span><span class="w"> </span><span class="n">context</span><span class="p">,</span><span class="w"> </span><span class="n">arg</span><span class="p">);</span>
</pre></div>
</div>
</section>
<section id="irq-initialize">
<h3><code class="docutils literal notranslate"><span class="pre">irq_initialize()</span></code><a class="headerlink" href="#irq-initialize" title="Permalink to this heading"></a></h3>
<p><code class="docutils literal notranslate"><span class="pre">irq_initialize()</span></code>: simply set the <code class="docutils literal notranslate"><span class="pre">g_irqvector[]</span></code> table
a known state on power-up. It would only have to distinguish
the difference in sizes.</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cp">#ifdef CONFIG_ARCH_MINIMAL_VECTORTABLE</span>
<span class="cp"># define TAB_SIZE CONFIG_ARCH_NUSER_INTERRUPTS</span>
<span class="cp">#else</span>
<span class="cp"># define TAB_SIZE NR_IRQS</span>
<span class="cp">#endif</span>
<span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">TAB_SIZE</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span>
</pre></div>
</div>
</section>
<section id="g-mapirq">
<h3><code class="docutils literal notranslate"><span class="pre">g_mapirq[]</span></code><a class="headerlink" href="#g-mapirq" title="Permalink to this heading"></a></h3>
<p>An implementation of <code class="docutils literal notranslate"><span class="pre">up_mapirq()</span></code> might be something like:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;nuttx/irq.h&gt;</span>
<span class="k">const</span><span class="w"> </span><span class="n">irq_mapped_t</span><span class="w"> </span><span class="n">g_irqmap</span><span class="p">[</span><span class="n">NR_IRQS</span><span class="p">]</span><span class="w"> </span><span class="o">=</span>
<span class="p">{</span>
<span class="p">...</span><span class="w"> </span><span class="n">IRQ</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="n">index</span><span class="w"> </span><span class="n">mapping</span><span class="w"> </span><span class="n">values</span><span class="w"> </span><span class="p">...</span>
<span class="p">};</span>
</pre></div>
</div>
<p><code class="docutils literal notranslate"><span class="pre">g_irqmap[]</span></code> is a array of mapped irq table indices. It
contains the mapped index value and is itself indexed
by the physical interrupt vector number. It provides
an <code class="docutils literal notranslate"><span class="pre">irq_mapped_t</span></code> value in the range of 0 to
<code class="docutils literal notranslate"><span class="pre">CONFIG_ARCH_NUSER_INTERRUPTS</span></code> that is the new, mapped
index into the vector table. Unsupported IRQs would
simply map to an out of range value like <code class="docutils literal notranslate"><span class="pre">IRQMAPPED_MAX</span></code>.
So, for example, if <code class="docutils literal notranslate"><span class="pre">g_irqmap[37]</span> <span class="pre">==</span> <span class="pre">24</span></code>, then the hardware
interrupt vector 37 will be mapped to the interrupt vector
table at index 24. if <code class="docutils literal notranslate"><span class="pre">g_irqmap[42]</span> <span class="pre">==</span> <span class="pre">IRQMAPPED_MAX</span></code>, then
hardware interrupt vector 42 is not used and if it occurs
will result in an unexpected interrupt crash.</p>
</section>
</section>
<section id="hardware-vector-remapping">
<h2>Hardware Vector Remapping<a class="headerlink" href="#hardware-vector-remapping" title="Permalink to this heading"></a></h2>
<p><cite>[This technical approach is discussed here but is
discouraged because of technical “Complications” and
“Dubious Performance Improvements” discussed at the
end of this section.]</cite></p>
<p>Most ARMv7-M architectures support two mechanism for handling interrupts:</p>
<ul class="simple">
<li><p>The so-called <cite>common</cite> vector handler logic enabled with
<code class="docutils literal notranslate"><span class="pre">CONFIG_ARMV7M_CMNVECTOR=y</span></code> that can be found in
<code class="docutils literal notranslate"><span class="pre">arch/arm/src/armv7-m/</span></code>, and</p></li>
<li><p>MCU-specific interrupt handling logic. For the
STM32, this logic can be found at <code class="docutils literal notranslate"><span class="pre">arch/arm/src/stm32/gnu/stm32_vectors.S</span></code>.</p></li>
</ul>
<p>The <cite>common</cite> vector logic is slightly more efficient,
the MCU-specific logic is slightly more flexible.</p>
<p>If we don’t use the <cite>common</cite> vector logic enabled with
<code class="docutils literal notranslate"><span class="pre">CONFIG_ARMV7M_CMNVECTOR=y</span></code>, but instead the more
flexible MCU-specific implementation, then we can
also use this to map the large set of hardware
interrupt vector numbers to a smaller set of software
interrupt numbers. This involves minimal changes to
the OS and does not require any magic software lookup
table. But is considerably more complex to implement.</p>
<p>This technical approach requires changes to three files:</p>
<ul class="simple">
<li><p>A new header file at <code class="docutils literal notranslate"><span class="pre">arch/arm/include/stm32</span></code>, say
<code class="docutils literal notranslate"><span class="pre">xyz_irq.h</span></code> for the purposes of this discussion.
This new header file is like the other IRQ definition
header files in that directory except that it
defines only the IRQ number of the interrupts after
remapping. So, instead of having the 100 IRQ number
definitions of the original IRQ header file based on
the physical vector numbers, this header file would
define <code class="docutils literal notranslate"><span class="pre">only</span></code> the small set of 20 <code class="docutils literal notranslate"><span class="pre">mapped</span></code> IRQ numbers in
the range from 0 through 19. It would also set <code class="docutils literal notranslate"><span class="pre">NR_IRQS</span></code>
to the value 20.</p></li>
<li><p>A new header file at <code class="docutils literal notranslate"><span class="pre">arch/arm/src/stm32/hardware</span></code>, say
<code class="docutils literal notranslate"><span class="pre">xyz_vector.h</span></code>. It would be similar to the other vector
definitions files in that directory: It will consist
of a sequence of 100 <code class="docutils literal notranslate"><span class="pre">VECTOR</span></code> and <code class="docutils literal notranslate"><span class="pre">UNUSED</span></code> macros. It will
define <code class="docutils literal notranslate"><span class="pre">VECTOR</span></code> entries for the 20 valid interrupts and
80 <code class="docutils literal notranslate"><span class="pre">UNUSED</span></code> entries for the unused interrupt vector numbers.
More about this below.</p></li>
<li><p>Modification of the <code class="docutils literal notranslate"><span class="pre">stm32_vectors.S</span></code> file. These changes
are trivial and involve only the conditional inclusion
of the new, special <code class="docutils literal notranslate"><span class="pre">xyz_vectors.h</span></code> header file.</p></li>
</ul>
<p><strong>REVISIT</strong>: This needs to be updated. Neither the <code class="docutils literal notranslate"><span class="pre">xyz_vector.h</span></code>
files nor the <code class="docutils literal notranslate"><span class="pre">stm32_vectors.S</span></code> exist in the current realization.
This has all been replaced with the common vector handling at
<code class="docutils literal notranslate"><span class="pre">arch/arm/src/armv7-m</span></code>.</p>
</section>
<section id="vector-definitions">
<h2>Vector Definitions<a class="headerlink" href="#vector-definitions" title="Permalink to this heading"></a></h2>
<p>In <code class="docutils literal notranslate"><span class="pre">arch/arm/src/stm32/gnu/stm32_vector.S</span></code>, notice that the
<code class="docutils literal notranslate"><span class="pre">xyz_vector.h</span></code> file will be included twice. Before each
inclusion, the macros <code class="docutils literal notranslate"><span class="pre">VECTOR</span></code> and <code class="docutils literal notranslate"><span class="pre">UNUSED</span></code> are defined.</p>
<p>The first time that <code class="docutils literal notranslate"><span class="pre">xyz_vector.h</span></code> included, it defines the
hardware vector table. The hardware vector table consists
of <code class="docutils literal notranslate"><span class="pre">NR_IRQS</span></code> 32-bit addresses in an array. This is
accomplished by setting:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cp">#undef VECTOR</span>
<span class="cp">#define VECTOR(l,i) .word l</span>
<span class="cp">#undef UNUSED</span>
<span class="cp">#define UNUSED(i) .word stm32_reserved</span>
</pre></div>
</div>
<p>Then including <code class="docutils literal notranslate"><span class="pre">xyz_vector.h</span></code>. So consider the following
definitions in the original file:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="p">...</span>
<span class="n">VECTOR</span><span class="p">(</span><span class="n">stm32_usart1</span><span class="p">,</span><span class="w"> </span><span class="n">STM32_IRQ_USART1</span><span class="p">)</span><span class="w"> </span><span class="cm">/* Vector 16+37: USART1 global interrupt */</span>
<span class="n">VECTOR</span><span class="p">(</span><span class="n">stm32_usart2</span><span class="p">,</span><span class="w"> </span><span class="n">STM32_IRQ_USART2</span><span class="p">)</span><span class="w"> </span><span class="cm">/* Vector 16+38: USART2 global interrupt */</span>
<span class="n">VECTOR</span><span class="p">(</span><span class="n">stm32_usart3</span><span class="p">,</span><span class="w"> </span><span class="n">STM32_IRQ_USART3</span><span class="p">)</span><span class="w"> </span><span class="cm">/* Vector 16+39: USART3 global interrupt */</span>
<span class="p">...</span>
</pre></div>
</div>
<p>Suppose that we wanted to support only USART1 and that
we wanted to have the IRQ number for USART1 to be 12.
That would be accomplished in the <code class="docutils literal notranslate"><span class="pre">xyz_vector.h</span></code> header
file like this:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="p">...</span>
<span class="n">VECTOR</span><span class="p">(</span><span class="n">stm32_usart1</span><span class="p">,</span><span class="w"> </span><span class="n">STM32_IRQ_USART1</span><span class="p">)</span><span class="w"> </span><span class="cm">/* Vector 16+37: USART1 global interrupt */</span>
<span class="n">UNUSED</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="cm">/* Vector 16+38: USART2 global interrupt */</span>
<span class="n">UNUSED</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="cm">/* Vector 16+39: USART3 global interrupt */</span>
<span class="p">...</span>
</pre></div>
</div>
<p>Where the value of <code class="docutils literal notranslate"><span class="pre">STM32_IRQ_USART1</span></code> was defined to
be 12 in the <code class="docutils literal notranslate"><span class="pre">arch/arm/include/stm32/xyz_irq.h</span></code> header
file. When <code class="docutils literal notranslate"><span class="pre">xyz_vector.h</span></code> is included by <code class="docutils literal notranslate"><span class="pre">stm32_vectors.S</span></code>
with the above definitions for <code class="docutils literal notranslate"><span class="pre">VECTOR</span></code> and <code class="docutils literal notranslate"><span class="pre">UNUSED</span></code>, the
following would result:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="p">...</span>
<span class="p">.</span><span class="n">word</span><span class="w"> </span><span class="n">stm32_usart1</span>
<span class="p">.</span><span class="n">word</span><span class="w"> </span><span class="n">stm32_reserved</span>
<span class="p">.</span><span class="n">word</span><span class="w"> </span><span class="n">stm32_reserved</span>
<span class="p">...</span>
</pre></div>
</div>
<p>These are the settings for vector 53, 54, and 55,
respectively. The entire vector table would be populated
in this way. <code class="docutils literal notranslate"><span class="pre">stm32_reserved</span></code>, if called would result in
an “unexpected ISR” crash. <code class="docutils literal notranslate"><span class="pre">stm32_usart1</span></code>, if called will
process the USART1 interrupt normally as we will see below.</p>
<section id="interrupt-handler-definitions">
<h3>Interrupt Handler Definitions<a class="headerlink" href="#interrupt-handler-definitions" title="Permalink to this heading"></a></h3>
<p>in the vector table, all of the valid vectors are set to
the address of a <cite>handler</cite> function. All unused vectors
are force to vector to <code class="docutils literal notranslate"><span class="pre">stm32_reserved</span></code>. Currently, only
vectors that are not supported by the hardware are
marked <code class="docutils literal notranslate"><span class="pre">UNUSED</span></code>, but you can mark any vector <code class="docutils literal notranslate"><span class="pre">UNUSED</span></code> in
order to eliminate it.</p>
<p>The second time that <code class="docutils literal notranslate"><span class="pre">xyz_vector.h</span></code> is included by
<code class="docutils literal notranslate"><span class="pre">stm32_vector.S</span></code>, the <cite>handler</cite> functions are generated.
Each of the valid vectors point to the matching handler
function. In this case, you do NOT have to provide
handlers for the <code class="docutils literal notranslate"><span class="pre">UNUSED</span></code> vectors, only for the used
<code class="docutils literal notranslate"><span class="pre">VECTOR</span></code> vectors. All of the unused vectors will go
to the common <code class="docutils literal notranslate"><span class="pre">stm32_reserved</span></code> handler. The remaining
set of handlers is very sparse.</p>
<p>These are the values of <code class="docutils literal notranslate"><span class="pre">UNUSED</span></code> and <code class="docutils literal notranslate"><span class="pre">VECTOR</span></code> macros on the
second time the <code class="docutils literal notranslate"><span class="pre">xzy_vector.h</span></code> is included by <code class="docutils literal notranslate"><span class="pre">stm32_vectors.S</span></code>:</p>
<div class="highlight-asm notranslate"><div class="highlight"><pre><span></span><span class="na">.macro</span><span class="w"> </span><span class="no">HANDLER</span><span class="p">,</span><span class="w"> </span><span class="no">label</span><span class="p">,</span><span class="w"> </span><span class="no">irqno</span>
<span class="w"> </span><span class="na">.thumb_func</span>
<span class="nl">label:</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="no">r0</span><span class="p">,</span><span class="w"> </span><span class="c1">#\irqno</span>
<span class="w"> </span><span class="nf">b</span><span class="w"> </span><span class="no">exception_common</span>
<span class="na">.endm</span>
<span class="c1">#undef VECTOR</span>
<span class="c1">#define VECTOR(l,i) HANDLER l, i</span>
<span class="c1">#undef UNUSED</span>
<span class="c1">#define UNUSED(i)</span>
</pre></div>
</div>
<p>In the above USART1 example, a single handler would be
generated that will provide the IRQ number 12. Remember
that 12 is the expansion of the macro <code class="docutils literal notranslate"><span class="pre">STM32_IRQ_USART1</span></code>
that is provided in the <code class="docutils literal notranslate"><span class="pre">arch/arm/include/stm32/xyz_irq.h</span></code>
header file:</p>
<div class="highlight-asm notranslate"><div class="highlight"><pre><span></span><span class="w"> </span><span class="na">.thumb_func</span>
<span class="nl">stm32_usart1:</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="no">r0</span><span class="p">,</span><span class="w"> </span><span class="mi">#12</span>
<span class="w"> </span><span class="nf">b</span><span class="w"> </span><span class="no">exception_common</span>
</pre></div>
</div>
<p>Now, when vector 16+37 occurs it is mapped to IRQ 12
with no significant software overhead.</p>
</section>
<section id="a-complication">
<h3>A Complication<a class="headerlink" href="#a-complication" title="Permalink to this heading"></a></h3>
<p>A complication in the above logic has been noted by David Sidrane:
When we access the NVIC in <code class="docutils literal notranslate"><span class="pre">stm32_irq.c</span></code> in order to enable
and disable interrupts, the logic requires the physical
vector number in order to select the NVIC register and
the bit(s) the modify in the NVIC register.</p>
<p>This could be handled with another small IRQ lookup table
(20 <code class="docutils literal notranslate"><span class="pre">uint8_t</span></code> entries in our example situation above). But
then this approach is not so much better than the <cite>Software
Vector Mapping</cite> described about which does not suffer from
this problem. Certainly enabling/disabling interrupts in a
much lower rate operation and at least does not put the
lookup in the critical interrupt path.</p>
<p>Another option suggested by David Sidrane is equally ugly:</p>
<ul class="simple">
<li><p>Don’t change the <code class="docutils literal notranslate"><span class="pre">arch/arm/include/stm32</span></code> IRQ definition file.</p></li>
<li><p>Instead, encode the IRQ number so that it has both
the index and physical vector number:</p></li>
</ul>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="p">...</span>
<span class="n">VECTOR</span><span class="p">(</span><span class="n">stm32_usart1</span><span class="p">,</span><span class="w"> </span><span class="n">STM32_IRQ_USART1</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="mi">8</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">STM32_INDEX_USART1</span><span class="p">)</span>
<span class="n">UNUSED</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="n">UNUSED</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="p">...</span>
</pre></div>
</div>
<p>The STM32_INDEX_USART1 would have the value 12 and
STM32_IRQ_USART1 would be as before (53). This encoded
value would be received by <code class="docutils literal notranslate"><span class="pre">irq_dispatch()</span></code> and it would
decode both the index and the physical vector number.
It would use the index to look up in the <code class="docutils literal notranslate"><span class="pre">g_irqvector[]</span></code>
table but would pass the physical vector number to the
interrupt handler as the IRQ number.</p>
<p>A lookup would still be required in <code class="docutils literal notranslate"><span class="pre">irq_attach()</span></code> in
order to convert the physical vector number back to
an index (100 <code class="docutils literal notranslate"><span class="pre">uint8_t</span></code> entries in our example). So
some lookup is unavoidable.</p>
<p>Based upon these analysis, my recommendation is that
we do not consider the second option any further. The
first option is cleaner, more portable, and generally
preferable.is well worth that.</p>
</section>
<section id="dubious-performance-improvements">
<h3>Dubious Performance Improvements<a class="headerlink" href="#dubious-performance-improvements" title="Permalink to this heading"></a></h3>
<p>The intent of this second option was to provide a higher
performance mapping of physical interrupt vectors to IRQ
numbers compared to the pure software mapping of option 1. However,
in order to implement this approach, we had
to use the less efficient, non-common vector handling
logic. That logic is not terribly less efficient, the
cost is probably only a 16 bit load immediate instruction
and branch to another location in FLASH (which will cause
the CPU pipeline to be flushed).</p>
<p>The variant of option 2 where both the physical vector number
and vector table index are encoded would require even more
processing in <code class="docutils literal notranslate"><span class="pre">irq_dispatch()</span></code> in order to decode the
physical vector number and vector table index.
Possible just AND and SHIFT instructions.</p>
<p>However, the minimal cost of the first pure software
mapping approach was possibly as small as a single
indexed byte fetch from FLASH in <code class="docutils literal notranslate"><span class="pre">irq_attach()</span></code>.
Indexing is, of course, essentially <cite>free</cite> in the ARM
ISA, the primary cost would be the FLASH memory access.
So my first assessment is that the performance of both
approaches is the essentially the same. If anything, the
first approach is possibly the more performant if
implemented efficiently.</p>
<p>Both options would require some minor range checking in
<code class="docutils literal notranslate"><span class="pre">irq_attach()</span></code> as well.</p>
<p>Because of this and because of the simplicity of the
first option, I see no reason to support or consider
this second option any further.</p>
</section>
<section id="complexity-and-generalizability">
<h3>Complexity and Generalizability<a class="headerlink" href="#complexity-and-generalizability" title="Permalink to this heading"></a></h3>
<p>Option 2 is overly complex; it depends on a deep understanding
on how the MCU interrupt logic works and on a high level of
Thumb assembly language skills.</p>
<p>Another problem with option 2 is that really only applies to
the Cortex-M family of processors and perhaps others that
support interrupt vectored interrupts in a similar fashion.
It is not a general solution that can be used with any CPU
architectures.</p>
<p>And even worse, the MCU-specific interrupt handling logic
that this support depends upon is is very limited. As soon
as the common interrupt handler logic was added, I stopped
implementing the MCU specific logic in all newer ARMv7-M
ports. So that MCU specific interrupt handler logic is
only present for EFM32, Kinetis, LPC17, SAM3/4, STM32,
Tiva, and nothing else. Very limited!</p>
<p>These are further reasons why option 2 is no recommended and
will not be supported explicitly.</p>
</section>
</section>
</section>
</div>
</div>
<footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer">
<a href="signaling_sem_priority_inheritance.html" class="btn btn-neutral float-left" title="Signaling Semaphores and Priority Inheritance" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a>
<a href="port.html" class="btn btn-neutral float-right" title="How to port" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a>
</div>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2023, The Apache Software Foundation.</p>
</div>
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>