//==========================================================================
//
//      sam9_misc.c
//
//      HAL misc board support code for ARM9/SAM9
//
//==========================================================================
// ####ECOSGPLCOPYRIGHTBEGIN####                                            
// -------------------------------------------                              
// This file is part of eCos, the Embedded Configurable Operating System.   
// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
// Copyright (C) 2003, 2004, 2005, 2007 eCosCentric Limited                 
//
// eCos 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 2 or (at your option) any later      
// version.                                                                 
//
// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,    
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
//
// As a special exception, if other files instantiate templates or use      
// macros or inline functions from this file, or you compile this file      
// and link it with other works to produce a work based on this file,       
// this file does not by itself cause the resulting work to be covered by   
// the GNU General Public License. However the source code for this file    
// must still be made available in accordance with section (3) of the GNU   
// General Public License v2.                                               
//
// This exception does not invalidate any other reasons why a work based    
// on this file might be covered by the GNU General Public License.         
// -------------------------------------------                              
// ####ECOSGPLCOPYRIGHTEND####                                              
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s):    eCosCentric
// Contributors: nickg, hmt, Travis C. Furrer <furrer@mit.edu>, jskov
// Date:         2007-09-21
// Purpose:      HAL board support
// Description:  Implementations of HAL board interfaces
//
//####DESCRIPTIONEND####
//
//========================================================================*/

#include <pkgconf/hal.h>
#include <pkgconf/system.h>
#include CYGBLD_HAL_PLATFORM_H

#include <cyg/infra/cyg_type.h>         // base types
#include <cyg/infra/cyg_trac.h>         // tracing macros
#include <cyg/infra/cyg_ass.h>          // assertion macros

#include <cyg/hal/hal_io.h>             // IO macros
#include <cyg/hal/hal_arch.h>           // Register state info
#include <cyg/hal/hal_diag.h>
#include <cyg/hal/hal_intr.h>           // Interrupt names
#include <cyg/hal/hal_cache.h>
#include <cyg/hal/sam9.h>         // Platform specifics

#include <cyg/infra/diag.h>             // diag_printf

//
// CPU specific initialization
//

__externC void hal_default_irq_vsr(void);
__externC void hal_default_fiq_vsr(void);

void
_sam9_hardware_init(void)
{
    int i;

#ifndef CYGSEM_HAL_USE_ROM_MONITOR
    // Only do this if we are not running under a ROM monitor,
    // otherwise we are likely to mess up any interrupts that the
    // monitor has enabled, for example for Ctrl-C handling.
    HAL_WRITE_UINT32(_AIC_ICCR, 0xFFFFFFFF);  // Clear all interrupts
    HAL_WRITE_UINT32(_AIC_IDCR, 0xFFFFFFFF);  // Disable all interrupts

    // Clear system device interrupts

    HAL_WRITE_UINT32( _PMC_IDR, 0xffffffff );
#endif

    // If using the AIC, reset all VSRs to our own default FIQ/IRQ VSRs
    // (potentially stealing them back from the ROM monitor in the process)
#if CYGINT_HAL_SAM9_AIC_VSR
    HAL_WRITE_UINT32(_AIC_SVR, (CYG_ADDRESS)hal_default_fiq_vsr);  // FIQ vector
    // Reset all the IRQ vectors
    for (i = 1;  i < 32;  i++) {
        HAL_WRITE_UINT32(_AIC_SVR+(i*4), (CYG_ADDRESS)hal_default_irq_vsr);
#else
    // If not using the AIC we store the vector *number*, so that it can be retrieved more
    // easily in hal_IRQ_handler below.
    for (i = 0;  i < 32;  i++) {
        HAL_WRITE_UINT32(_AIC_SVR+(i*4), i);  // Vector
#endif
        HAL_WRITE_UINT32(_AIC_SMR+(i*4), 3);  // Priority. 0 == lowest, 7 == highest. Level-sensitive.
    }

  /* Setup the Reset controller. Allow user resets */
  HAL_WRITE_UINT32(_RST_RMR, _RST_RMR_URSTEN | (10 << 8) | _RST_RMR_KEY);
    
#if defined(CYGSEM_HAL_VIRTUAL_VECTOR_CLAIM_DELAY_US)
    // When this config is providing delay functionality, and the kernel is
    // included, then the kernel clock will be used. But use can happen before
    // the clock is initialised by the kernel. So we initialise it here.
    // Update: in fact we need to initialise this at any time we're handling
    // delays, so the PIT gets running.
    hal_clock_initialize( CYGNUM_HAL_RTC_PERIOD );
#endif
}

// -------------------------------------------------------------------------
    
void
hal_clock_initialize(cyg_uint32 period)
{
  cyg_uint32 pivr, pimr, piv;

  CYG_ASSERT(period <= 0xfffff, "Invalid HAL clock configuration");

  // The PITC has an annoying design flaw - it cannot be reset
  // once enabled. And if you need to reduce the period from
  // its earlier value, and the current timer value is above
  // that period, then the timer has to go right to the top and
  // wrap before anything will happen.
  // It also causes problems in hal_if.c's delay_us function because
  // you get returned clock values way in excess of the period.
  // The solution is for the first programming of the period here,
  // to set the clock to trigger effectively straight away so it
  // resets to 0.

  piv = period-1;

  // First we note whether the timer had already been enabled or not.
  HAL_READ_UINT32(_PITC_PIMR, pimr);

  // Now disable timer so that it can't wrap without us noticing.
  // But to make things nicer against the hardware, we may as well
  // use the correct desired period so that it can stop there if
  // it's close.
  HAL_WRITE_UINT32(_PITC_PIMR, piv);

  // Had timer been enabled before?
  if ( pimr & _PITC_PIMR_PITEN )
  {
      CYG_INTERRUPT_STATE intstate;

      // It was, so let's read the value and check against the period.
      // We disable interrupts to guarantee our calculations don't
      // get ruined.

      HAL_DISABLE_INTERRUPTS(intstate);

      HAL_READ_UINT32(_PITC_PIVR, pivr);
      if ((pivr & 0xfffff) >= piv)
      {
          cyg_uint32 fake_piv;

          // So this *is* the bad case to handle specially.

          fake_piv = (pivr&0xfffff)+20; // 20 extra ticks includes a decent margin.

          // Set this new PIV, and let it get hit, after which it gets disabled.
          HAL_WRITE_UINT32(_PITC_PIMR, fake_piv);

          // We can re-enable ints while we wait, even though it isn't long.
          HAL_RESTORE_INTERRUPTS(intstate);

          do {
              HAL_READ_UINT32(_PITC_PIVR, pivr);
          } while ((pivr & 0xfffff) >= piv);
      } else {
          HAL_RESTORE_INTERRUPTS(intstate);
      }
  }


  /* Can now correctly set Period Interval timer and enable interrupt */
  HAL_WRITE_UINT32(_PITC_PIMR, 
                   piv |  
                   _PITC_PIMR_PITEN |
                   _PITC_PIMR_PITIEN);
  
  // Read the value from the PIVR register to clear any pending interrupt
  HAL_READ_UINT32(_PITC_PIVR, pivr);
}

// This routine is called during a clock interrupt.
void
hal_clock_reset(cyg_uint32 vector, cyg_uint32 period)
{
  cyg_uint32 reg;
  
  CYG_ASSERT(period <= 0xfffff, "Invalid HAL clock configuration");
  
  // Check that the PIT has the right period.
  HAL_READ_UINT32(_PITC_PIMR, reg);
  if ((reg & 0xfffff) != (period - 1)){
    HAL_WRITE_UINT32(_PITC_PIMR, 
                     (period - 1) |  
                     _PITC_PIMR_PITEN |
                     _PITC_PIMR_PITIEN);
  }

  /* Read the value register so that we clear the interrupt */
  HAL_READ_UINT32(_PITC_PIVR, reg);
}

// Read the current value of the clock, returning the number of hardware
// "ticks" that have occurred (i.e. how far away the current value is from
// the start)
void
hal_clock_read(cyg_uint32 *pvalue)
{
  cyg_uint32 ir;
  
  HAL_READ_UINT32(_PITC_PIIR, ir);
  *pvalue = ir & 0xfffff;
}

// -------------------------------------------------------------------------
//
// Delay for some number of micro-seconds
// PIT is clocked at MCLK / 16
//

void hal_delay_us(cyg_int32 usecs)
{
  cyg_int64 ticks;
  cyg_uint32 val1, val2;
  cyg_uint32 piv;
  
  // Calculate how many PIT ticks the required number of microseconds
  // equate to. We do this calculation in 64 bit arithmetic to avoid
  // overflow.
  ticks = (((cyg_uint64)usecs) * 
           ((cyg_uint64)CYGARC_HAL_ARM_ARM9_SAM9_MCK))/16/1000000LL;
  
  // Calculate the wrap around period. 
  HAL_READ_UINT32(_PITC_PIMR, piv);
  piv = (piv & 0xfffff) - 1; 
  
  hal_clock_read(&val1);
  while (ticks > 0)
  {

    // A short delay is needed here on some variants. It is not
    // exactly clear why, or why such a small delay makes such a
    // difference.
    __asm__ volatile ("nop; nop; nop; nop\n");
      
    hal_clock_read(&val2);
    if (val2 < val1)
      ticks -= ((piv + val2) - val1); //overflow occurred
    else 
      ticks -= (val2 - val1);
    val1 = val2;
  }
}    

// ----------------------------------------------------------------------------
// Profiling support. This uses TC1.

#ifdef CYGPKG_PROFILE_GPROF
#include <cyg/profile/profile.h>
#include <cyg/hal/drv_api.h>

static cyg_interrupt    profile_interrupt;
static cyg_handle_t     profile_handle;

static  void
profile_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
{
    CYG_UNUSED_PARAM(cyg_vector_t, vector);
    CYG_UNUSED_PARAM(cyg_ucount32, count);
    CYG_UNUSED_PARAM(cyg_addrword_t, data);
}

static cyg_uint32
profile_isr(cyg_vector_t vector, cyg_addrword_t data, HAL_SavedRegisters* regs)
{
    cyg_uint32  clock_stat;
    HAL_READ_UINT32(SAM9_TC1 + _TC_SR, clock_stat);
    __profile_hit(regs->pc);
    return CYG_ISR_HANDLED;
}

int
hal_enable_profile_timer(int resolution)
{
    // The requested resolution is in microseconds. Rather than try to
    // figure out the platform's frequency we use the existing
    // calculations for the system clock. We have
    // CYGNUM_HAL_RTC_PERIOD for a value corresponding to
    // (CYGNUM_HAL_RTC_NUMERATOR / CYGNUM_HAL_RTC_DENOMINATOR)
    // nanoseconds. This gives:
    cyg_uint32 profile_period = (cyg_uint32)(((long long)resolution * (long long)CYGNUM_HAL_RTC_PERIOD * (long long)CYGNUM_HAL_RTC_DENOMINATOR * 1000ll) \
        / (long long) CYGNUM_HAL_RTC_NUMERATOR);
    if (profile_period > 65535) {
        profile_period = 65535;
    }
    resolution = (int)(((long long)profile_period * (long long)CYGNUM_HAL_RTC_NUMERATOR) /
        ((long long)CYGNUM_HAL_RTC_PERIOD * (long long)CYGNUM_HAL_RTC_DENOMINATOR * 1000ll));
      
    cyg_drv_interrupt_create( CYGNUM_HAL_INTERRUPT_TC1, 1, 0, (cyg_ISR_t*) &profile_isr, &profile_dsr, &profile_handle, &profile_interrupt);
    cyg_drv_interrupt_attach(profile_handle);
    
    HAL_WRITE_UINT32(SAM9_TC1 + _TC_CMR, _TC_CMR_WAVESEL_UP_AUTO | _TC_CMR_WAVE | 3);
    HAL_WRITE_UINT32(SAM9_TC1 + _TC_RC,  profile_period);
    HAL_WRITE_UINT32(SAM9_TC1 + _TC_CCR, _TC_CCR_CLKEN | _TC_CCR_SWTRG);
    HAL_WRITE_UINT32(SAM9_TC1 + _TC_IDR, ~_TC_SR_CPCS);
    HAL_WRITE_UINT32(SAM9_TC1 + _TC_IER, _TC_SR_CPCS);
    cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_TC1);
    return resolution;
}
#endif

// -------------------------------------------------------------------------
// Decode a system interrupt. Not all systems have all interrupts. So
// code will only be generated for those interrupts which have a
// defined value.

static int sys_irq_handler(void)
{
  cyg_uint32 sr, mr;

  // Periodic Interrupt Timer Controller
  HAL_READ_UINT32(_PITC_PISR, sr);

  if (sr & _PITC_PISR_PITS) {
    return CYGNUM_HAL_INTERRUPT_PITC;
  }

  // Debug Unit
  HAL_READ_UINT32((AT91_DEBUG + AT91_US_CSR), sr);
  HAL_READ_UINT32((AT91_DEBUG + AT91_US_IMR), mr);
  if (sr & mr) {
    return CYGNUM_HAL_INTERRUPT_DEBUG;
  }

  /* Real Time Timer. Check the interrupt is enabled, not that just
     the status indicates there is an interrupt. It takes a while for
     the status bit to clear. */
  HAL_READ_UINT32(_RTTC_RTSR, sr);
  HAL_READ_UINT32(_RTTC_RTMR, mr);
  if (((mr & _RTTC_RTMR_ALMIEN) &&
       (sr & _RTTC_RTSR_ALMS)) ||
      ((mr & _RTTC_RTMR_RTTINCIEN) &&
       (sr & _RTTC_RTSR_RTTINC))) {
    return CYGNUM_HAL_INTERRUPT_RTTC;
  }

  // Power Management Controller
  HAL_READ_UINT32(_PMC_IMR, mr);
  HAL_READ_UINT32(_PMC_SR, sr);
  if ((sr & mr) & 
      (_PMC_SR_MOSCS   |
       _PMC_SR_LOCKA   |
       _PMC_SR_LOCKB   |
       _PMC_SR_MCKRDY  |
       _PMC_SR_PCK0RDY |
       _PMC_SR_PCK1RDY |
       _PMC_SR_PCK2RDY |
       _PMC_SR_PCK3RDY)) {
    return CYGNUM_HAL_INTERRUPT_PMC;
  }

  // Watchdog Timer Controller
  HAL_READ_UINT32(_WDTC_WDSR, sr);
  HAL_READ_UINT32(_WDTC_WDMR, mr);
  if ((mr & _WDTC_WDMR_FIEN) &&
      sr & (_WDTC_WDSR_UNDER |
            _WDTC_WDSR_ERROR)) {
    return CYGNUM_HAL_INTERRUPT_WDTC;
  }

  // Reset Controller
  HAL_READ_UINT32(_RST_RSR, sr);
  HAL_READ_UINT32(_RST_RMR, mr);
  if (((mr & _RST_RMR_URSTIEN) && (sr & _RST_RSR_USER)) ||  
      ((mr & _RST_RMR_BODIEN) && (sr & _RST_RSR_BROWN)))
    return CYGNUM_HAL_INTERRUPT_RSTC;
  
  return CYGNUM_HAL_INTERRUPT_NONE;
}

// -------------------------------------------------------------------------
// UART interrupt mask manipulation
//
// Write the IDR and IER of a UART. For the DEBUG UART, the values are
// preserved and used to implement the whole device mask/unmask
// functionality. This is not needed for the other UARTs since they
// also have their own vectors which can be masked; the DEBUG UART has
// to share a vector with several other devices.

static cyg_uint32 hal_debug_imr, hal_debug_masked;

__externC void hal_debug_write_idr( CYG_ADDRESS base, cyg_uint32 idr )
{
    if( base == AT91_DEBUG )
    {
        hal_debug_imr &= ~idr;
        if( hal_debug_masked )
            return;
    }
    HAL_WRITE_UINT32(base + AT91_US_IDR, idr);
}

__externC void hal_debug_write_ier( CYG_ADDRESS base, cyg_uint32 ier )
{
    if( base == AT91_DEBUG )
    {
        hal_debug_imr |= ier;
        if( hal_debug_masked )
            return;
    }
    HAL_WRITE_UINT32(base + AT91_US_IER, ier);
}

// -------------------------------------------------------------------------
// System Interrupt Masking
//
// This currently only deals with the PIT and DEBUG UART. The Watchdog
// cannot be changed since its Mode Register is write-once, so it is
// ignored. All others are either ignored or raise an assertion failure.

static void hal_sysirq_mask( int vector, int mask )
{
    cyg_uint32 mr;

    if( vector == CYGNUM_HAL_INTERRUPT_PITC )
    {
        // Periodic Interrupt Timer Controller
        HAL_READ_UINT32(_PITC_PIMR, mr);
        mr &= ~_PITC_PIMR_PITIEN;
        if( !mask )
            mr |= _PITC_PIMR_PITIEN;
        HAL_WRITE_UINT32(_PITC_PIMR, mr);
        return;
    }

    if( vector == CYGNUM_HAL_INTERRUPT_DEBUG )
    {
        // Debug Unit
        hal_debug_masked = mask;
        if( mask )
            HAL_WRITE_UINT32(AT91_DEBUG + AT91_US_IDR, hal_debug_imr);
        else
            HAL_WRITE_UINT32(AT91_DEBUG + AT91_US_IER, hal_debug_imr);
        return;
    }

    if( vector == CYGNUM_HAL_INTERRUPT_WDTC )
    {
        // Watchdog Timer Controller
        return;
    }

    if( vector == CYGNUM_HAL_INTERRUPT_RTTC )
    {
        // Real Time Clock
        CYG_FAIL("RTTC Interrupt mask not currently supported");
    }

    if( vector == CYGNUM_HAL_INTERRUPT_PMC )
    {
        // Power Management Controller
        CYG_FAIL("PMC Interrupt mask not currently supported");
    }

    if( vector == CYGNUM_HAL_INTERRUPT_RSTC )
    {
        // Reset Controller
        CYG_FAIL("RSTC Interrupt mask not currently supported");
    }

}

// -------------------------------------------------------------------------

// This routine is called to respond to a hardware interrupt (IRQ).  It
// should interrogate the hardware and return the IRQ vector number.

int hal_IRQ_handler(void)
{
    cyg_uint32 vec;

#if CYGINT_HAL_SAM9_AIC_VSR
    // Get the interrupt number.
    HAL_READ_UINT32( _AIC_ISR, vec );
#else
    // If not using the AIC directly, the vector number will have been stored
    // as the SVR for that vector, so can be retrieved with the IVR.
    // We don't just read the ISR because that doesn't work unless the IVR
    // has been read first, which would mean a dummy read.
    HAL_READ_UINT32( _AIC_IVR, vec );
#endif

    if( vec == CYGNUM_HAL_INTERRUPT_SYSTEM )
        vec = sys_irq_handler();

    // This interrupt controller won't allow another interrupt to occur
    // until the EOI register has been written (it supports up to 8 'stacked'
    // interrupts.  However, this doesn't work well with the eCos interrupt
    // strategy which may not complete an interrupt handling until much
    // later since this is typically done by a DSR (or in the case of the
    // network stacks, even a thread)  By simply resetting this here, we
    // tell the AIC to generate new interrupts as soon as they occur.  The
    // eCos method of masking/unmasking individual interrupts then handles
    // the details.
    HAL_WRITE_UINT32(_AIC_EOICR, 1);
    return vec;
}

//
// Interrupt control
//

void hal_interrupt_mask(int vector)
{
    CYG_ASSERT(vector <= CYGNUM_HAL_ISR_MAX &&
               vector >= CYGNUM_HAL_ISR_MIN , "Invalid vector");
   if( vector >= 32 )
   {
       hal_sysirq_mask( vector, 1 );
       return;
   }

    HAL_WRITE_UINT32(_AIC_IDCR, (1 << vector));
}

void hal_interrupt_unmask(int vector)
{
    CYG_ASSERT(vector <= CYGNUM_HAL_ISR_MAX &&
               vector >= CYGNUM_HAL_ISR_MIN , "Invalid vector");

   if( vector >= 32 )
   {
       // If any SYSTEM interrupt is unmasked, force the SYSTEM
       // interrupt to high level detection and unmask the SYSTEM
       // vector in the AIC.
       hal_interrupt_configure(CYGNUM_HAL_INTERRUPT_SYSTEM, true, true);
       HAL_WRITE_UINT32(_AIC_IECR, 
                        (1 <<CYGNUM_HAL_INTERRUPT_SYSTEM));
       hal_sysirq_mask( vector, 0 );
       return;
   }

    HAL_WRITE_UINT32(_AIC_IECR, (1 << vector));
}

void hal_interrupt_acknowledge(int vector)
{
    CYG_ASSERT(vector <= CYGNUM_HAL_ISR_MAX &&
               vector >= CYGNUM_HAL_ISR_MIN , "Invalid vector");
#if 0 // Not here
    {
        cyg_uint32 val;
        *_tb++ = 0xDEADDEAD;
        HAL_READ_UINT32(_AIC_ISR, val);  *_tb++ = val;
        HAL_READ_UINT32(_AIC_IPR, val);  *_tb++ = val;
        HAL_READ_UINT32(_AIC_IMR, val);  *_tb++ = val;
    }
    HAL_WRITE_UINT32(_AIC_EOICR, (1 << vector));
    {
        cyg_uint32 val;
        *_tb++ = 0xB00BB00B;
        HAL_READ_UINT32(_AIC_ISR, val);  *_tb++ = val;
        HAL_READ_UINT32(_AIC_IPR, val);  *_tb++ = val;
        HAL_READ_UINT32(_AIC_IMR, val);  *_tb++ = val;
    }
#endif

    // Acknowledge and cancel PIO interrupts by reading the relevant
    // controller's ISR.
    {
        cyg_uint32 isr;
        if( vector == CYGNUM_HAL_INTERRUPT_PIOA )
            HAL_READ_UINT32( SAM9_PIOA+_PIO_ISR, isr );
        else if( vector == CYGNUM_HAL_INTERRUPT_PIOB )
            HAL_READ_UINT32( SAM9_PIOB+_PIO_ISR, isr );
        else if( vector == CYGNUM_HAL_INTERRUPT_PIOC )
            HAL_READ_UINT32( SAM9_PIOC+_PIO_ISR, isr );
    }
}

void hal_interrupt_configure(int vector, int level, int up)
{
    cyg_uint32 smr;
    CYG_ASSERT(vector <= CYGNUM_HAL_ISR_MAX &&
               vector >= CYGNUM_HAL_ISR_MIN, "Invalid vector");

    if( vector >= CYGNUM_HAL_INTERRUPT_DEBUG )
        vector = CYGNUM_HAL_INTERRUPT_SYSTEM;

    HAL_READ_UINT32(_AIC_SMR + 4*vector, smr );
    if (level)
        smr &= ~0x00000020; // clear edge bit of SRCTYPE
    else // edge triggered
        smr |= 0x00000020; // set edge bit of SRCTYPE
    if (up)
        smr |= 0x00000040; // set high level/rising edge bit of SRCTYPE
    else // edge triggered
        smr &= ~0x00000040; // clear high level/rising edge bit of SRCTYPE
    HAL_WRITE_UINT32(_AIC_SMR + 4*vector, smr );
}

void hal_interrupt_set_level(int vector, int level)
{
    cyg_uint32 smr;
    CYG_ASSERT(vector <= CYGNUM_HAL_ISR_MAX &&
               vector >= CYGNUM_HAL_ISR_MIN, "Invalid vector");
    CYG_ASSERT(level <= 7 &&
               level >= 0, "Invalid interrupt priority level");

    if( vector >= CYGNUM_HAL_INTERRUPT_DEBUG )
        vector = CYGNUM_HAL_INTERRUPT_SYSTEM;
    
    HAL_READ_UINT32(_AIC_SMR + 4*vector, smr );
    smr &= ~0x00000007; // clear PRIOR
    smr |= level & 0x7;
    HAL_WRITE_UINT32(_AIC_SMR + 4*vector, smr );
}

//--------------------------------------------------------------------------
//
// Reset the processor/board
//

void cyg_hal_sam9_reset(void)
{
    HAL_WRITE_UINT32(_RST_RCR,
                     _RST_RCR_PROCRST |                   
                     _RST_RCR_ICERST  |
                     _RST_RCR_PERRST  |
                     _RST_RCR_KEY);
    while(1) CYG_EMPTY_STATEMENT;
}

//--------------------------------------------------------------------------
// End sam9_misc.c
