summaryrefslogblamecommitdiffstats
path: root/c/src/lib/libcpu/mips/mongoosev/vectorisrs/vectorisrs.c
blob: 28ddf7f8b0e241a090859e41bf57de057cd513c3 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
















                                                           

                    
 
 









































                                                                                                   
                                  
        
                                      
                                                     
          
                                  

             
 











































                                                                                    
                                                           
 
                         
 

                               
 
                           
 
          
 









                                                                        
 









                                                     
 
 






                                                              
    






                                                             
    






                                                         
    






                                                                     
    






                                                                        
 




                                                                          
 
                                                                                        
 












                                                                       
 










                                                                                         
 
                           
 







                                                                             
 


                                                                        
 


                                                                      
 










                                                                        
 






                                                                   
 
 
 
      
/*
 *  ISR Vectoring support for the Synova Mongoose-V.
 *
 *  COPYRIGHT (c) 1989-2001.
 *  On-Line Applications Research Corporation (OAR).
 *
 *  The license and distribution terms for this file may be
 *  found in the file LICENSE in this distribution or at
 *  http://www.OARcorp.com/rtems/license.html.
 *
 *  $Id$
 */

#include <rtems.h>
#include <stdlib.h>
#include <libcpu/mongoose-v.h>

#include "iregdef.h"
#include "idtcpu.h"


#include <bspIo.h>  /* for printk */



int mips_default_isr( int vector )
{
  unsigned int sr, sr2;
  unsigned int cause;

  mips_get_sr( sr );
  mips_get_cause( cause );

  sr2 = sr & ~0xff;
  mips_set_sr(sr2);

  printk( "Unhandled isr exception: vector 0x%02x, cause 0x%08X, sr 0x%08X\n", vector, cause, sr );
  rtems_fatal_error_occurred(1);
  return 0;
}

/* userspace routine to assert either software interrupt */

int assertSoftwareInterrupt( unsigned32 n )
{
   if( n<2 )
   {
      unsigned32 c;

      mips_get_cause(c);
      c = ((n+1) << CAUSE_IPSHIFT);
      mips_set_cause(c);

      return n;
   }
   else return -1;
}






#define CALL_ISR(_vector,_frame) \
  do { \
    if( _ISR_Vector_table[_vector] ) \
      (_ISR_Vector_table[_vector])(_vector,_frame); \
    else \
      mips_default_isr(_vector); \
  } while (0)


//
// Instrumentation tweaks for isr timing measurement, turning them off
// via this #if will remove the code entirely from the RTEMS kernel.
//

#if 1
#define SET_ISR_FLAG( offset )	*((unsigned32 *)(0x8001e000+offset)) = 1;
#define CLR_ISR_FLAG( offset )	*((unsigned32 *)(0x8001e000+offset)) = 0;
#else
#define SET_ISR_FLAG( offset )
#define CLR_ISR_FLAG( offset )
#endif






static volatile unsigned32 _ivcause, _ivsr;


static unsigned32 READ_CAUSE(void) 
{
   mips_get_cause( _ivcause );
   _ivcause &= SR_IMASK;	// mask off everything other than the interrupt bits

   return ((_ivcause & (_ivsr & SR_IMASK)) >> CAUSE_IPSHIFT);
}



//
// This rather strangely coded routine enforces an interrupt priority
// scheme.  As it runs thru finding whichever interrupt caused it to get
// here, it test for other interrupts arriving in the meantime (maybe it
// occured while the vector code is executing for instance).  Each new
// interrupt will be served in order of its priority.  In an effort to
// minimize overhead, the cause register is only fetched after an
// interrupt is serviced.  Because of the intvect goto's, this routine
// will only exit when all interrupts have been serviced and no more
// have arrived, this improves interrupt latency at the cost of
// increasing scheduling jitter; though scheduling jitter should only
// become apparent in high interrupt load conditions.
//
void mips_vector_isr_handlers( CPU_Interrupt_frame *frame )
{
   unsigned32	cshifted;

   /* mips_get_sr( sr ); */
   _ivsr = frame->regs[ R_SR ];

   cshifted = READ_CAUSE();

  intvect:

   if( cshifted & 0x3 )
   {
      // making the software interrupt the highest priority is kind of
      // stupid, but it makes the bit testing lots easier.  On the other
      // hand, these ints are infrequently used and the testing overhead
      // is minimal.  Who knows, high-priority software ints might be
      // handy in some situation.

      /* unset both software int cause bits */
      mips_set_cause( _ivcause & ~(3 << CAUSE_IPSHIFT) );

      if ( cshifted & 0x01 )       /* SW[0] */
      {
	 CALL_ISR( MONGOOSEV_IRQ_SOFTWARE_1, frame );
      } 
      if ( cshifted & 0x02 )       /* SW[1] */
      {
	 CALL_ISR( MONGOOSEV_IRQ_SOFTWARE_2, frame );
      }
      cshifted = READ_CAUSE();
   }


   if ( cshifted & 0x04 )       /* IP[0] ==> INT0 == TIMER1 */
   {
      SET_ISR_FLAG( 0x4 );
      CALL_ISR( MONGOOSEV_IRQ_TIMER1, frame );
      CLR_ISR_FLAG( 0x4 );
      if( (cshifted = READ_CAUSE()) & 0x3 ) goto intvect;
   }
    
   if ( cshifted & 0x08 )       /* IP[1] ==> INT1 == TIMER2*/
   {
      SET_ISR_FLAG( 0x8 );
      CALL_ISR( MONGOOSEV_IRQ_TIMER2, frame );
      CLR_ISR_FLAG( 0x8 );
      if( (cshifted = READ_CAUSE()) & 0x7 ) goto intvect;
   }
    
   if ( cshifted & 0x10 )       /* IP[2] ==> INT2 */
   {
      SET_ISR_FLAG( 0x10 );
      CALL_ISR( MONGOOSEV_IRQ_INT2, frame );
      CLR_ISR_FLAG( 0x10 );
      if( (cshifted = READ_CAUSE()) & 0xf ) goto intvect;
   }
    
   if ( cshifted & 0x20 )       /* IP[3] ==> INT3 == FPU interrupt */
   {
      SET_ISR_FLAG( 0x20 );
      CALL_ISR( MONGOOSEV_IRQ_INT3, frame );
      CLR_ISR_FLAG( 0x20 );
      if( (cshifted = READ_CAUSE()) & 0x1f ) goto intvect;
   }
    
   if ( cshifted & 0x40 )       /* IP[4] ==> INT4, external interrupt */
   {
      SET_ISR_FLAG( 0x40 );
      CALL_ISR( MONGOOSEV_IRQ_INT4, frame );
      CLR_ISR_FLAG( 0x40 );
      if( (cshifted = READ_CAUSE()) & 0x3f ) goto intvect;
   }

   if ( cshifted & 0x80 )       /* IP[5] ==> INT5, peripheral interrupt */
   {
      unsigned32  bit;
      unsigned32  pf_icr, pf_mask, pf_reset = 0;
      unsigned32  i, m;

      pf_icr = MONGOOSEV_READ( MONGOOSEV_PERIPHERAL_FUNCTION_INTERRUPT_CAUSE_REGISTER );

/*
      for (bit=0, pf_mask = 1;    bit < 32;     bit++, pf_mask <<= 1 ) 
      {
	 if ( pf_icr & pf_mask )
	 {
	    SET_ISR_FLAG( 0x80 + (bit*4) );
	    CALL_ISR( MONGOOSEV_IRQ_PERIPHERAL_BASE + bit, frame );
	    CLR_ISR_FLAG( 0x80 + (bit*4) );
	    pf_reset |= pf_mask;
	    if( (cshifted = READ_CAUSE()) & 0xff ) break;
	 }
      } 
*/

      //
      // iterate thru 32 bits in 4 chunks of 8 bits each.  This lets us
      // quickly get past unasserted interrupts instead of flogging our
      // way thru a full 32 bits.  pf_mask shifts left 8 bits at a time
      // to serve as a interrupt cause test mask.
      //
      for( bit=0, pf_mask = 0xff;    (bit < 32 && pf_icr);     (bit+=8, pf_mask <<= 8) ) 
      {
	 if ( pf_icr & pf_mask )
	 {
	    // one or more of the 8 bits we're testing is high

	    m = (1 << bit);

	    // iterate thru the 8 bits, servicing any of the interrupts
	    for(i=0; (i<8 && pf_icr); (i++, m <<= 1))
	    {
	       if( pf_icr & m )
	       {
		  SET_ISR_FLAG( 0x80 + ((bit + i) * 4) );
		  CALL_ISR( MONGOOSEV_IRQ_PERIPHERAL_BASE + bit + i, frame );
		  CLR_ISR_FLAG( 0x80 + ((bit + i) * 4) );

		  // or each serviced interrupt into our interrupt clear
		  // mask
		  pf_reset |= m;

		  // xor off each int we service so we can immediately
		  // exit once we get the last one
		  pf_icr   %= m;

		  // if another interrupt has arrived, jump out right
		  // away but be sure to reset all the interrupts we've
		  // already serviced
		  //if( READ_CAUSE() & 0xff ) goto pfexit;
	       }
	    }
	 }
      }
     pfexit:
      MONGOOSEV_WRITE( MONGOOSEV_PERIPHERAL_STATUS_REGISTER, pf_reset );
   }

   //
   // this is a last ditch interrupt check, if an interrupt arrives
   // after this step, servicing it will incur the entire interrupt
   // overhead cost.
   //
   if( (cshifted = READ_CAUSE()) & 0xff ) goto intvect;
}



// eof