1    /*
     2     * Copyright (c) 2015, Texas Instruments Incorporated
     3     * All rights reserved.
     4     *
     5     * Redistribution and use in source and binary forms, with or without
     6     * modification, are permitted provided that the following conditions
     7     * are met:
     8     *
     9     * *  Redistributions of source code must retain the above copyright
    10     *    notice, this list of conditions and the following disclaimer.
    11     *
    12     * *  Redistributions in binary form must reproduce the above copyright
    13     *    notice, this list of conditions and the following disclaimer in the
    14     *    documentation and/or other materials provided with the distribution.
    15     *
    16     * *  Neither the name of Texas Instruments Incorporated nor the names of
    17     *    its contributors may be used to endorse or promote products derived
    18     *    from this software without specific prior written permission.
    19     *
    20     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    21     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
    22     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
    23     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
    24     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    25     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    26     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
    27     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    28     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
    29     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
    30     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    31     */
    32    /*
    33     *  ======== Hwi.xdc ========
    34     *
    35     */
    36    package ti.sysbios.family.msp430;
    37    
    38    import xdc.rov.ViewInfo;
    39    import xdc.runtime.Diags;
    40    import xdc.runtime.Log;
    41    import xdc.runtime.Assert;
    42    import xdc.runtime.Error;
    43    
    44    import ti.sysbios.interfaces.IHwi;
    45    
    46    /*!
    47     *  ======== Hwi ========
    48     *  MSP430 Hardware Interrupt Manager
    49     *
    50     *  This module implements the generic Hwi module functions 
    51     *  Hwi_enable, Hwi_disable, and Hwi_restore as defined by
    52     *  {@link ti.sysbios.interfaces.IHwi IHwi}.
    53     *
    54     *  @p(html)
    55     *  <h3> Calling Context </h3>
    56     *  <table border="1" cellpadding="3">
    57     *    <colgroup span="1"></colgroup> <colgroup span="5" align="center"></colgroup>
    58     *
    59     *    <tr><th> Function                 </th><th>  Hwi   </th><th>  Swi   </th><th>  Task  </th><th>  Main  </th><th>  Startup  </th></tr>
    60     *    <!--                                                                                                                 -->
    61     *    <tr><td> {@link #clearInterrupt}   </td><td>   Y    </td><td>   Y    </td><td>   Y    </td><td>   Y    </td><td>   Y    </td></tr>
    62     *    <tr><td> {@link #create}           </td><td>   N    </td><td>   N    </td><td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
    63     *    <tr><td> {@link #disable}          </td><td>   Y    </td><td>   Y    </td><td>   Y    </td><td>   Y    </td><td>   Y    </td></tr>
    64     *    <tr><td> {@link #disableInterrupt} </td><td>   Y    </td><td>   Y    </td><td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
    65     *    <tr><td> {@link #enable}           </td><td>   Y    </td><td>   Y    </td><td>   Y    </td><td>   N    </td><td>   N    </td></tr>
    66     *    <tr><td> {@link #enableInterrupt}  </td><td>   Y    </td><td>   Y    </td><td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
    67     *    <tr><td> {@link #Params_init}      </td><td>   Y    </td><td>   Y    </td><td>   Y    </td><td>   Y    </td><td>   Y    </td></tr>
    68     *    <tr><td> {@link #restore}          </td><td>   Y    </td><td>   Y    </td><td>   Y    </td><td>   Y    </td><td>   Y    </td></tr>
    69     *    <tr><td> {@link #restoreInterrupt} </td><td>   Y    </td><td>   Y    </td><td>   Y    </td><td>   Y    </td><td>   Y    </td></tr>
    70     *    <tr><td> {@link #construct}        </td><td>   N    </td><td>   N    </td><td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
    71     *    <tr><td> {@link #delete}           </td><td>   N    </td><td>   N    </td><td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
    72     *    <tr><td> {@link #destruct}         </td><td>   N    </td><td>   N    </td><td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
    73     *    <tr><td> {@link #getHookContext}   </td><td>   Y    </td><td>   Y    </td><td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
    74     *    <tr><td> {@link #setFunc}          </td><td>   Y    </td><td>   Y    </td><td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
    75     *    <tr><td> {@link #setHookContext}   </td><td>   Y    </td><td>   Y    </td><td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
    76     *    <tr><td colspan="6"> Definitions: <br />
    77     *       <ul>
    78     *         <li> <b>Hwi</b>: API is callable from a Hwi thread. </li>
    79     *         <li> <b>Swi</b>: API is callable from a Swi thread. </li>
    80     *         <li> <b>Task</b>: API is callable from a Task thread. </li>
    81     *         <li> <b>Main</b>: API is callable during any of these phases: </li>
    82     *           <ul>
    83     *             <li> In your module startup after this module is started (e.g. Hwi_Module_startupDone() returns TRUE). </li>
    84     *             <li> During xdc.runtime.Startup.lastFxns. </li>
    85     *             <li> During main().</li>
    86     *             <li> During BIOS.startupFxns.</li>
    87     *           </ul>
    88     *         <li> <b>Startup</b>: API is callable during any of these phases:</li>
    89     *           <ul>
    90     *             <li> During xdc.runtime.Startup.firstFxns.</li>
    91     *             <li> In your module startup before this module is started (e.g. Hwi_Module_startupDone() returns FALSE).</li>
    92     *           </ul>
    93     *       </ul>
    94     *    </td></tr>
    95     *
    96     *  </table>
    97     *  @p
    98     *
    99     */
   100    
   101    
   102    @Template("./Hwi.xdt")  /* generates the vector table and the dispatcher */
   103    @ModuleStartup          /* generate a call to startup function */
   104    
   105    module Hwi inherits ti.sysbios.interfaces.IHwi 
   106    {
   107        /*! 
   108         *  The MSP430 supports up to 64 interrupts/exceptions.
   109         *
   110         *  The actual number supported is device specific and provided by
   111         *  the catalog device specification.
   112         */
   113        readonly config Int NUM_INTERRUPTS;
   114    
   115        // -------- Module Types --------
   116    
   117        /*! Hwi vector function type definition. */
   118        typedef Void (*VectorFuncPtr)(void);
   119    
   120         /*! @_nodoc */
   121        metaonly struct BasicView {
   122            Ptr         halHwiHandle;
   123            String      label;
   124            Int         intNum;
   125            String      fxn; 
   126            UArg        arg; 
   127            Ptr         irp; 
   128        };
   129        
   130        /*! @_nodoc */
   131        metaonly struct ModuleView {
   132            String      options[4];
   133            String      hwiStackPeak;
   134            SizeT       hwiStackSize;
   135            Ptr         hwiStackBase;
   136        };
   137    
   138        /*! @_nodoc */
   139        @Facet
   140        metaonly config ViewInfo.Instance rovViewInfo = 
   141            ViewInfo.create({
   142                viewMap: [
   143                    ['Basic',    {type: ViewInfo.INSTANCE, viewInitFxn: 'viewInitBasic',    structName: 'BasicView'}],
   144                    ['Module',   {type: ViewInfo.MODULE,   viewInitFxn: 'viewInitModule',   structName: 'ModuleView'}]
   145                ]
   146            });
   147        
   148        // -------- Module Parameters --------
   149    
   150        // Logs
   151    
   152        /*!
   153         *  Issued just prior to Hwi function invocation (with interrupts disabled)
   154         */
   155        config Log.Event LM_begin = {
   156            mask: Diags.USER1 | Diags.USER2,
   157            msg: "LM_begin: hwi: 0x%x, func: 0x%x, preThread: %d, intNum: %d, irp: 0x%x"
   158        };
   159    
   160        /*!
   161         *  Issued just after return from Hwi function (with interrupts disabled)
   162         */
   163        config Log.Event LD_end = {
   164            mask: Diags.USER2,
   165            msg: "LD_end: hwi: 0x%x"
   166        };
   167    
   168        // Asserts
   169    
   170        /*! Assert when bad maskSetting parameter provided */
   171        config Assert.Id A_unsupportedMaskingOption = {
   172            msg: "A_unsupportedMaskingOption: unsupported maskSetting."
   173        };
   174    
   175        // Errors
   176    
   177        /*!
   178         *  Error raised when Hwi is already defined
   179         */
   180        config Error.Id E_alreadyDefined = {
   181            msg: "E_alreadyDefined: Hwi already defined: intr# %d"
   182        };
   183    
   184        /*!
   185         *  Error raised when an unimplemented Hwi function is called
   186         *
   187         *  The MSP430 does not implement all of the functions defined
   188         *  by {@link ti.sysbios.interfaces.IHwi}.  If applications
   189         *  call such a function, an E_notImplemented error is raised
   190         *  with the name of the unimplemented function passed as an
   191         *  argument.  See {@link xdc.runtime.Error#raise}.
   192         */
   193        config Error.Id E_notImplemented = {
   194            msg: "E_notImplemented: Function not implemented: %s"
   195        };
   196    
   197        // configs
   198    
   199        /*!
   200         *  ======== fillVectors ========
   201         *  Plug all unused interrupt vectors
   202         *
   203         *  This parameter allows one to plug all unused interrupt vectors
   204         *  with a spin loop, to catch unexpected interrupts and "run away" code.
   205         */
   206        metaonly config Bool fillVectors = true;
   207    
   208        /*!
   209         *  ======== resetFunc ========
   210         *  Reset handler
   211         *
   212         *  This parameter specifies the interrupt service routine triggered on
   213         *  reset. The default is c_int00.
   214         */
   215        metaonly config VectorFuncPtr resetFunc;
   216    
   217        /*!
   218         *  ======== alwaysWake ========
   219         *  Always keep the CPU awake upon return from interrupt?
   220         *
   221         *  This parameter serves as a global 'switch' to control whether the
   222         *  CPU is kept awake (i.e., not allowed to return to a low power mode) at
   223         *  the end of servicing a hardware interrupt (Hwi) managed by SYS/BIOS.  
   224         *  The behavior of each interrupt instance can be controlled individually
   225         *  (see {@link #keepAwakeEnabled}); when set to true, this parameter serves
   226         *  as an override of the individual instance selection, to force keep awake 
   227         *  of the CPU. This parameter is provided to assist with debug, and to 
   228         *  ease use and transition of legacy code to work with SYS/BIOS.
   229         */
   230        metaonly config Bool alwaysWake = false;
   231    
   232        /*!
   233         *  ======== alwaysLog ========
   234         *  Always emit Log messages from interrupt stubs?
   235         *
   236         *  This parameter serves as a global 'switch' to control whether Log
   237         *  begin and end messages will be emitted from interrupt stubs.
   238         *  Note that the behavior of each interrupt instance can be controlled
   239         *  individually (see {@link #loggingEnabled}); when set to true, alwaysLog
   240         *  serves as an override of the individual instance selections, forcing 
   241         *  logging from the stubs of all configured interrupts.
   242         */
   243        metaonly config Bool alwaysLog = false;
   244    
   245        // -------- Module Functions --------
   246    
   247        /*!
   248         *  ======== disable ========
   249         *  Globally disable interrupts.
   250         *
   251         *  Hwi_disable globally disables hardware interrupts and returns an
   252         *  opaque key indicating whether interrupts were globally enabled or
   253         *  disabled on entry to Hwi_disable(). 
   254         *  The actual value of the key is target/device specific and is meant 
   255         *  to be passed to Hwi_restore(). 
   256         *
   257         *  Call Hwi_disable before a portion of a function that needs
   258         *  to run without interruption. When critical processing is complete, call
   259         *  Hwi_restore or Hwi_enable to reenable hardware interrupts.
   260         *
   261         *  Servicing of interrupts that occur while interrupts are disabled is
   262         *  postponed until interrupts are reenabled. However, if the same type 
   263         *  of interrupt occurs several times while interrupts are disabled, 
   264         *  the interrupt's function is executed only once when interrupts are 
   265         *  reenabled.
   266         *
   267         *  A context switch can occur when calling Hwi_enable or Hwi_restore if
   268         *  an enabled interrupt occurred while interrupts are disabled.
   269         *
   270         *  Hwi_disable may be called from main(). However, since Hwi interrupts
   271         *  are already disabled in main(), such a call has no effect.
   272         *
   273         *  @a(constraints)
   274         *  If a Task switching API such as 
   275         *  {@link ti.sysbios.knl.Semaphore#pend Semaphore_pend()}, 
   276         *  {@link ti.sysbios.knl.Semaphore#post Semaphore_post()},
   277         *  {@link ti.sysbios.knl.Task#sleep Task_sleep()}, or
   278         *  {@link ti.sysbios.knl.Task#yield Task_yield()} 
   279         *  is invoked which results in a context switch while
   280         *  interrupts are disabled, an embedded call to 
   281         *  {@link #enable Hwi_enable} occurs
   282         *  on the way to the new thread context which unconditionally re-enables
   283         *  interrupts. Interrupts will remain enabled until a subsequent 
   284         *  {@link #disable Hwi_disable}
   285         *  invocation.
   286         *
   287         *  Swis always run with interrupts enabled.
   288         *  See {@link ti.sysbios.knl.Swi#post Swi_post()} for a discussion Swis and
   289         *  interrupts.
   290         *
   291         *  @b(returns)     opaque key for use by Hwi_restore()
   292         */
   293        @Macro
   294        override UInt disable();
   295    
   296        /*!
   297         *  ======== enable ========
   298         */
   299        @Macro
   300        override UInt enable();
   301    
   302        /*!
   303         *  ======== restore ========
   304         */
   305        @Macro
   306        override Void restore(UInt key);
   307    
   308        /*!
   309         *  ======== inUseMeta ========
   310         *  @_nodoc
   311         *  Check for Hwi already in use
   312         *
   313         *  For internal SYS/BIOS use only. 
   314         *  Should be called prior to any internal Hwi.create().
   315         *
   316         *  @param(intNum)  interrupt number
   317         */
   318        metaonly Bool inUseMeta(UInt intNum);
   319    
   320        /*!
   321         *  ======== plugMeta ========
   322         *  Statically plug an interrupt vector with an ISR address
   323         *
   324         *  @param(intNum)  interrupt number
   325         *  @param(fxn)     pointer to ISR function
   326         */
   327        metaonly Void plugMeta(UInt intNum, Fxn fxn);
   328    
   329        /*!
   330         *  @_nodoc
   331         *  ======= logBegin ========
   332         *  Log the LM_begin from within Hwi module scope
   333         */
   334        Void logBegin(Log.Event evt, IArg a1, IArg a2, IArg a3, IArg a4, IArg a5);
   335    
   336        /*!
   337         *  @_nodoc
   338         *  ======= logEnd ========
   339         *  Log the LD_end from within Hwi module scope
   340         */
   341        Void logEnd(Log.Event evt, IArg a1);
   342    
   343    instance:
   344    
   345        /*! override maskSetting - Hwi does not manage nesting on 430 */
   346        override config IHwi.MaskingOption maskSetting = IHwi.MaskingOption_ALL;
   347    
   348        /*! 
   349         *  Does this interrupt support posting of Swis? Default is true.
   350         *
   351         *  If "true", the interrupt stub will disable the Swi scheduler upon stub
   352         *  entry, and restore it upon interrupt completion. 
   353         *
   354         *  If no Swi-scheduling APIs (for example, Swi_post()) are called from 
   355         *  within this interrupt's ISR function, then swiEnabled can be set to 
   356         *  "false".
   357         */
   358        metaonly config Bool swiEnabled = true;
   359    
   360        /*! 
   361         *  Does this interrupt support task pre-emption? Default is true.
   362         *
   363         *  If "true", the interrupt stub will disable the Task scheduler upon 
   364         *  stub entry, and restore it upon interrupt completion. 
   365         *
   366         *  If no Task-scheduling APIs (e.g., Semaphore_post()) are called from 
   367         *  within this interrupt's ISR function, then taskEnabled can be set to 
   368         *  "false".
   369         */
   370        metaonly config Bool taskEnabled = true;
   371    
   372        /*! 
   373         *  Switch to ISR stack for this interrupt? Default is true.
   374         *
   375         *  If "true", the SYS/BIOS interrupt/system stack will be used when 
   376         *  running this interrupt's ISR function (instead of the interrupted 
   377         *  Task's dedicated stack).  If "false", no switching to the 
   378         *  interrupt/system stack will occur for this interrupt. 
   379         *
   380         *  Note that this parameter is only relevant for the Task module; if 
   381         *  the Task module is not enabled in the application only a single stack
   382         *  is used (i.e., the "system/interrupt stack").
   383         */
   384        metaonly config Bool isrStackEnabled = true;
   385    
   386        /*! 
   387         *  Does this interrupt allow nesting by other interrupts? Default is 
   388         *  false.
   389         *
   390         *  Set to "true" if the configured ISR function will enable global 
   391         *  interrupts temporarily within the function, to allow other interrupts
   392         *  to nest on top of this interrupt.  If the ISR does not enable other
   393         *  interrupts, then leave as the default of "false".
   394         *
   395         */
   396        metaonly config Bool nestingEnabled = false;
   397    
   398        /*! 
   399         *  Does this interrupt support logging?
   400         *
   401         *  If set to true, {@link xdc.runtime.Log Log} statements are inserted
   402         *  into the generated interrupt stub that calls the user's interrupt
   403         *  function.  The stub posts an {@link #LM_begin} event at the beginning
   404         *  of the interrupt service routine and a {@link #LD_end} event after
   405         *  the user's function returns.
   406         *
   407         *  In addition to enabling this flag, you must also enable USER1 and/or
   408         *  USER2 logging for this module.  Otherwise, the events posted by the
   409         *  inserted Log statments will be ignored.
   410         */
   411        metaonly config Bool loggingEnabled = false;
   412    
   413        /*! 
   414         *  Does this interrupt support thread-type tracking? Default is true. 
   415         *
   416         *  If "true", this stub will enable full tracking of the execution 
   417         *  context.  For example, if the ISR function (or one of the functions
   418         *  it calls) were to call BIOS_getThreadType(), the returned value would be
   419         *  BIOS_ThreadType_Hwi.  
   420         *
   421         *  Setting this parameter to "false" will slightly reduce the interrupt 
   422         *  stub overhead, but may result in an incorrect thread type being 
   423         *  reported during the processing of the interrupt.
   424         */
   425        metaonly config Bool threadTypeEnabled = true;
   426    
   427        /*! 
   428         *  Should keep CPU awake following this interrupt? Default is false. 
   429         * 
   430         *  If "true", this interrupt stub will modify the status register (SR)
   431         *  value that was pushed onto the stack (automatically, at the start of
   432         *  servicing the interrupt), so that when it is restored by the RETI 
   433         *  instruction, the CPU will stay in the Active mode. 
   434         *
   435         *  If left as "false", the unmodified SR value will be restored by the
   436         *  RETI instruction, and the CPU may return to a previous low power mode
   437         *  (LPM) that was in effect when the interrupt was triggered. 
   438         */
   439        metaonly config Bool keepAwakeEnabled = false;
   440    
   441    internal:   /* not for client use */
   442    
   443        /*
   444         *  ======== postInit ========
   445         *  finish initializing static and dynamic Hwis
   446         */
   447        Int postInit(Object *hwi, Error.Block *eb);
   448    
   449        /*!
   450         *  ======== init ========
   451         *  Setup Hwi stack
   452         */
   453        Void init();
   454    
   455        /*!
   456         *  const array to hold all HookSet objects.
   457         */
   458        config HookSet hooks[length] = [];
   459    
   460        /*! Meta World Only Hwi Configuration Object. */
   461        metaonly struct InterruptObj {
   462            String name;            /* symbol used for vector table entry */
   463            Bool used;              /* Interrupt already defined? */
   464            Bool generateStub;      /* handler is generated? */
   465            Bool swiEnabled;
   466            Bool taskEnabled;
   467            Bool nestingEnabled;
   468            Bool isrStackEnabled;
   469            Bool lmBeginEnabled;
   470            Bool ldEndEnabled;
   471            Bool threadTypeEnabled;
   472            Bool keepAwakeEnabled;
   473            String handle;
   474            FuncPtr fxn;            /* "wrapped" ISR function */
   475            Fxn pfxn;               /* non "wrapped" ISR function */
   476            UArg arg;               /* Argument to fxn */
   477        };
   478    
   479        /*!
   480         * Meta-only array of interrupt objects.
   481         *
   482         * This meta-only array of Hwi config objects is initialized
   483         * in Hwi.xs:module$meta$init().
   484         */
   485        metaonly config InterruptObj interrupt[];
   486    
   487        struct Instance_State {
   488            Int             intNum;         // Interrupt number
   489            Irp             irp;            // current IRP
   490            Ptr             hookEnv[];
   491        };
   492     
   493        struct Module_State {
   494            Char        *taskSP;        // Temporary storage of interrupted
   495                                        // Task's SP during ISR execution
   496            /* ROM */
   497            Char        *isrStack;      // Points to isrStack address
   498        };
   499    }