[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

mips64orion _CPU_ISR_Set_level



joel at oarcorp.com writes:
 > 
 > What do you think will be required to get the mips port into a similar
 > organization.  
 > 
 > > I am still somewhat confused about _CPU_ISR_Set_level and how important is it 
 > > to support interrupt levels for the mips architecture. I see some architectures
 > > support multiple levels if the CPU allows an easy way to do so, otherwise it
 > > just enables and disables interrupts. I could certainly go either way, but I'm
 > > just not sure what the "best" way to go is, knowing that there is no one best way.
 > 
 > _CPU_ISR_Set_level does what it has to as best it can for a port. :)
 > 
 > The i386 just recognizes on and off as well.  THe set level implementation
 > for the i386 is this:
 > 
 > #define _CPU_ISR_Set_level( _new_level ) \
 >   { \
 >     if ( _new_level ) asm volatile ( "cli" ); \
 >     else              asm volatile ( "sti" ); \
 >   }
 > 

Hi,

I have a mostly complete MIPS TX39 port of rtems that I am not
actively using nor working on.  The interrupt handling is complete,
however.

The following is from exec/score/cpu/mipstx39/cpu.c 
I believe that it works for any mips 3000 variant.  The 4000's
have a somewhat different status register format, but this is close.

If somebody wants the whole tree, I'll gladly send it to you.
It was built on 4.0 Beta IIRC.

Eric Blossom

----------------------------------------------------------------

/*PAGE
 *
 *  _CPU_ISR_Set_level
 */

/*
 * 
 * map task level to status register imask bits like this
 *
 *	task level	sr imask bits
 *	0		11111111	// all interrupts enabled
 *	1		11111110	// sw0 disabled
 * 	2		11111100	// sw1, sw0 disabled
 *	3		11111000	// int0, sw1, sw0 disabled
 *	4		11110000	// int1, int0, sw1, sw0 disabled
 *	5		11100000	// int2, int1, int0, sw1, sw0 disabled
 *	6		11000000	// int3, int2, int1, int0, sw1, sw0 disabled
 *	7		10000000	// int4, int3, int2, int1, int0, sw1, sw0 disabled
 *	8		00000000	// all interrupts disabled
 */

unsigned32 
_CPU_ISR_Compute_sr_imask (unsigned32 new_level)
{
  unsigned32	mask;
  
  if (new_level > 8)
    new_level = 8;

  mask = (0xff >> new_level) << new_level;
  return (mask << 8) | SR_IEc;
}

void _CPU_ISR_Set_level( unsigned32 new_level )
{
  unsigned32	sr;

  sr = mfc0_status ();
  sr &= ~SR_INTMASK;
  sr |= _CPU_ISR_Compute_sr_imask (new_level);
  mtc0_status (sr);
}

/*
 *
 *  _CPU_ISR_Get_level
 *
 *  This routine returns the current interrupt level.
 */
 
unsigned32 _CPU_ISR_Get_level( void )
{
  unsigned32	mask;
  unsigned32	i;
  
  mask = mfc0_status () >> 8;

  for (i = 0; i < 8; i++){
    if (mask & 0x1)
      return i;
    mask >>= 1;
  }

  return i;
}

/* -*-C-*-
*******************************************************************************
*
* File:         tx39_cp0.h
* RCS:          $Id: $
* Description:  tx39 Coprocessor 0 defs
* Author:       Eric Blossom
* Created:      Sat Sep 26 22:38:32 1998
* Modified:     Fri Dec  4 16:33:28 1998 (eric) eb at baton.starium.com
* Language:     C
* Package:      N/A
* Status:       Experimental (Do Not Distribute)
*
*******************************************************************************
*/

#ifndef _TX39_CP0_H_
#define	_TX39_CP0_H_

/*
 * Coprocessor 0 registers
 */

#define	C0_CONFIG	$3	/* processor config		*/
#define	C0_CACHE	$7	/* cache locking		*/
#define	C0_BADVADDR	$8	/* last virtual addr triggering error */
#define	C0_SR		$12	/* status register 		*/
#define	C0_CAUSE	$13	/* cause register		*/
#define C0_EPC		$14	/* exception error addr		*/
#define	C0_PRID		$15	/* processor revision ID	*/
#define	C0_DEBUG	$16	/* debug exception control	*/
#define	C0_DEPC		$17	/* PC for debug exception	*/

/*
 * Not all TX39 family members have TLB's
 */
#define	C0_INDEX	$0	/* TLB Index register		*/
#define	C0_RANDOM	$1	/* TLB Random register		*/
#define	C0_TLBLO	$2	/* TLB EntryLo register		*/
#define	C0_TLBHI	$10	/* TLB EntryHi register		*/


/*
 * C callable access routines for all CP0 registers.
 *    These macros generate inline assembly code for functions of the form
 *
 *      int  mfc0_<foo> (void);
 *      void mtc0_<foo> (int v);
 *
 *    Where <foo> is 
 *	config, cache, badvaddr, status, cause, epc, prid, debug, depc
 */
#define	MFC0(reg,dst) asm("mfc0 %0," #reg "; nop" : "=r" (dst))
#define	MTC0(reg,src) asm("nop; mtc0 %0," #reg "; nop" :: "r" (src))

#define	DEF_MFX(name, regno) \
inline static int mfc0_ ## name (void){int r; MFC0 (regno, r); return r;}

#define	DEF_MTX(name, regno) \
inline static void mtc0_ ## name (int v){MTC0 (regno, v);}

#define	DEF_MXX(name, regno) DEF_MFX(name, regno) DEF_MTX(name, regno)

#ifndef ASM

DEF_MXX (config, $3)
DEF_MXX (cache, $7)
DEF_MXX (badvaddr, $8)
DEF_MXX (status, $12)
DEF_MXX (cause, $13)
DEF_MXX (epc, $14)
DEF_MXX (prid, $15)
DEF_MXX (debug, $16)
DEF_MXX (depc, $17)

DEF_MXX (index, $0)
DEF_MXX (random, $1)
DEF_MXX (tlblo, $2)
DEF_MXX (tlbhi, $10)

#endif /* !ASM */

/*
 * status register bits
 */

#define	SR_IEc		0x00000001	/* Intr Enabled current 1 = enabled 	*/
#define	SR_KUc		0x00000002	/* Kernel/User current  1 = User 	*/
#define	SR_IEp		0x00000004	/* Intr Enabled prev 	*/
#define	SR_KUp		0x00000008	/* Kernel/User prev	*/
#define	SR_IEo		0x00000010	/* Intr Enabled old	*/
#define	SR_KUo		0x00000020	/* Kernel/User old	*/
#define	SR_INTMASK	0x0000ff00	/* interupt enable mask	*/
#define	SR_NMI		0x00100000	/* Non-maskable int (write 1 to clear) */
#define	SR_TS		0x00200000	/* TLB shutdown			*/
#define	SR_BEV		0x00400000	/* Bootstrap exception vector	*/
#define	SR_RE		0x02000000	/* Reverse Endian in user mode	*/
#define	SR_CU0		0x10000000	/* mark CP0 usable	*/
#define	SR_CU1		0x20000000	/* mark CP1 usable	*/
#define	SR_CU2		0x40000000	/* mark CP2 usable	*/
#define	SR_CU3		0x80000000	/* mark CP3 usable	*/


/*
 * config register bits
 */

#define	CP0CFG_DRSIZE_MASK	0x00000003	/* data burst refill size (see DCBR) */
#define	  CP0CFG_DRSIZE_4	  0x00000000	/*   4 words	*/
#define	  CP0CFG_DRSIZE_8	  0x00000001	/*   8 words	*/
#define	  CP0CFG_DRSIZE_16	  0x00000002	/*  16 words	*/
#define	  CP0CFG_DRSIZE_32	  0x00000003	/*  32 words	*/
#define	CP0CFG_IRSIZE_MASK	0x0000000c	/* inst burst refill size */
#define	  CP0CFG_IRSIZE_4	  0x00000000	/*   4 words	*/
#define	  CP0CFG_IRSIZE_8	  0x00000004	/*   8 words	*/
#define	  CP0CFG_IRSIZE_16	  0x00000008	/*  16 words	*/
#define	  CP0CFG_IRSIZE_32	  0x0000000c	/*  32 words	*/
#define	CP0CFG_DCE		0x00000010	/* Data Cache Enable			*/
#define	CP0CFG_ICE		0x00000020	/* Instruction Cache Enable		*/
#define	CP0CFG_DCBR		0x00000040	/* Data Cache Burst Refill		*/
#define	CP0CFG_LOCK		0x00000080	/* lock config register			*/
#define	CP0CFG_HALT		0x00000100	/* enter Halt mode			*/
#define	CP0CFG_DOZE		0x00000200	/* enter Doze mode			*/
#define	CP0CFG_RF_MASK		0x00000c00	/* reduced frequency 			*/
#define	CP0CFG_WBON		0x00001000	/* write back mode on (3920 core)	*/
#define	CP0CFG_CWFON		0x00002000	/* critical word first mode (3920 core)	*/

#define	CP0CFG_DCS_SHIFT	16
#define	CP0CFG_DCS_MASK		0x7
#define	CP0CFG_ICS_SHIFT	19
#define	CP0CFG_ICS_MASK		0x7


#endif /* _TX39_CP0_H_ */


// small excerpt from cpu.h

/* ISR handler macros */

/*
 *  Disable all interrupts for an RTEMS critical section.  The previous
 *  state is returned in _isr_cookie.
 */

#define _CPU_ISR_Disable( _isr_cookie )			\
  do {							\
    int _t1_ = 0;					\
    _isr_cookie = 0;					\
    asm volatile ("				      \n\
	.set noreorder				      \n\
	mfc0	%0, $12				      \n\
	not	%1, %2				      \n\
	and	%1, %1, %0			      \n\
	mtc0	%1, $12				      \n\
	and	%0, %2				      \n\
	.set reorder				      \n\
    "							\
    : "=&r" (_isr_cookie), "=&r" (_t1_)			\
    : "r" (/*SR_INTMASK*/ 0x0000ff00)			\
    );							\
  } while (0)

/*
 *  Enable interrupts to the previous state (returned by _CPU_ISR_Disable).
 *  This indicates the end of an RTEMS critical section.  The parameter
 *  _isr_cookie is not modified.
 */

#define _CPU_ISR_Enable( _isr_cookie )			\
  do {							\
    int _t1_ = 0;					\
    asm volatile ("				      \n\
	.set noreorder				      \n\
	mfc0	%0, $12				      \n\
	nop					      \n\
	or	%0, %1				      \n\
	mtc0	%0, $12				      \n\
	.set reorder				      \n\
    "							\
    : "=&r" (_t1_)					\
    : "r" (_isr_cookie)					\
    );							\
  } while (0)

/*
 *  This temporarily restores the interrupt to _level before immediately
 *  disabling them again.  This is used to divide long RTEMS critical
 *  sections into two or more parts.  The parameter _level is not
 *  modified.
 */

#define _CPU_ISR_Flash( _isr_cookie )			\
  do {							\
    int	_discard_;					\
    _CPU_ISR_Enable (_isr_cookie);			\
    _CPU_ISR_Disable (_discard_);			\
  } while (0)

/*
 *  Map interrupt level in task mode onto the hardware that the CPU
 *  actually provides.  Currently, interrupt levels which do not
 *  map onto the CPU in a generic fashion are undefined.  Someday,
 *  it would be nice if these were "mapped" by the application
 *  via a callout.  For example, m68k has 8 levels 0 - 7, levels
 *  8 - 255 would be available for bsp/application specific meaning.
 *  This could be used to manage a programmable interrupt controller
 *  via the rtems_task_mode directive.
 *
 *  The get routine usually must be implemented as a subroutine.
 */

unsigned32 _CPU_ISR_Compute_sr_imask (unsigned32 new_level);
void _CPU_ISR_Set_level( unsigned32 new_level );
unsigned32 _CPU_ISR_Get_level( void );