⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 intc.c

📁 realview22.rar
💻 C
📖 第 1 页 / 共 2 页
字号:
/* intc.c - Memory veneer that implements RPS interrupt controller.
 * Copyright (C) Advanced RISC Machines Limited, 1998-1999.
 * Copyright (C) ARM Limited, 1999 - 2001. All rights reserved.
 *
 * RCS $Revision: 1.5.4.6 $
 * Checkin $Date: 2001/08/24 12:57:48 $
 * Revising $Author: lmacgreg $
 */

#include <string.h>             /* for memset */
#define ModelName(IntCtrl)
#include "minperip.h"
#include "armul_bus.h" 




/* Debugging verbosity */
#if !defined(NDEBUG)
# if 1
# else
#  define VERBOSE
#  define VERBOSE_ACCESS
# endif
#endif

/* **************************** */
/* Static function declarations */
/* **************************** */

static ARMul_BusPeripAccessFunc IntCtrl_Access;

/* 
 * Interrupt controller peripheral register/signal structure 
 * Refer to ARM Specification ARM DDI 0062D for HW details.
*/
typedef struct {
  unsigned long  IRQStatus;
  unsigned long  IRQRawStatus;
  unsigned long  IRQEnable;
  unsigned long  IRQEnableClear;
  unsigned long  IRQSoft;
  unsigned long  FIQStatus;
  unsigned long  FIQRawStatus;
  unsigned long  FIQEnable;
  unsigned long  FIQEnableClear;
  int nIRQ;
  int nFIQ;
} intc;


/* 
 * Interrupt controller local state structure.
 * This allows multiple instantiations of a peripheral to be made
 * if necessary.
*/
BEGIN_STATE_DECL(IntCtrl)
  intc  myIntc;                 /* Reference to intc struct above */
  bool warn;                    /* Warn users about invalid register accesses*/
  int waits;                    /* Number of idle cycles before access */
  int waitStates;               /* stored number of wait states */
  int accessState;              /* Current access state */
    ARMul_BusPeripAccessRegistration my_bpar;
END_STATE_DECL(IntCtrl)


static GenericAccessFunc SignalInterruptChange;

static void InitialiseState(IntCtrlState *intcs);
static void FIQUpdate(IntCtrlState *intcs);
static void IRQUpdate(IntCtrlState *intcs);


#ifndef ARMulCnf_Warn
# define ARMulCnf_Warn (tag_t)"WARN"
#endif
#ifndef ARMulCnf_Waits
# define ARMulCnf_Waits (tag_t)"WAITS"
#endif

static unsigned Intc_ConfigEvents(void *handle, void *data)
{
  IntCtrlState *top=(IntCtrlState *)handle;  
  ARMul_Event *evt = (ARMul_Event *)data;
  if (evt->event == ConfigEvent_Reset)
  {
        InitialiseState(top);
        IRQUpdate(top);
        FIQUpdate(top);
  }
     
  return FALSE;

}


BEGIN_INIT(IntCtrl)
{
    Hostif_PrettyPrint(state->hostif, state->config, ", IntCtrl");
    state->warn =  ToolConf_DLookupBool(config, ARMulCnf_Warn, FALSE);
    state->waitStates = ToolConf_DLookupUInt(config, ARMulCnf_Waits, 0 /*1*/);

    if (state->warn)
    {
        Hostif_PrettyPrint(state->hostif,state->config," (warn on)");
    }

    if ( state->waitStates < 0   || state->waitStates > 30)
    {
        Hostif_PrettyPrint(state->hostif,state->config, 
                            "(Intc Error: Invalid wait state value "
                            "- defaulting to zero waits)");
        state->waitStates = 0;
    }

    /*
     * Attach it to the core so that other peripherals can
     * find and use the intc.
     */
    if (ARMulif_InstallNewInterruptController(&state->coredesc,
                                            SignalInterruptChange,
                                            state )
        == NULL)
    {
        Hostif_RaiseError(state->hostif,
                          "CORE FAILED TO REGISTER INTERRUPT-CONTROLLER\n");
    }
      /*
       * NOTE: The intc must currently be given a lower Plugin number
       * than its clients.
       * Later, the clients should connect at ColdBoot time,
       * or check that they have an interrupt-controller.
       */

      /*
       * The interrupt-handler used in ARMulator is purely
       * a reset-handler.
       */
    
    /* Ask for the default bus. */
 
    ARMulif_ReadBusRange(&state->coredesc, state->hostif,
                           ToolConf_FlatChild(config, (tag_t)"RANGE"),
                           &state->my_bpar,  
                           0x0a000000,0x110,"");
      {
          ARMul_Bus *bus = state->my_bpar.bus;
          ARMul_BusPeripAccessRegistration *regn = &state->my_bpar;
          regn->access_func = IntCtrl_Access;
          regn->access_handle = state;
          regn->capabilities = PeripAccessCapability_Minimum;
          (void)bus->bus_registerPeripFunc(BusRegAct_Insert, regn);
      }
      
}
{
   
    /* Initialise the intc structure */
    InitialiseState(state);
    ARMulif_InstallEventHandler(&state->coredesc,
                                ConfigEventSel,
                                Intc_ConfigEvents, state);
}
END_INIT(IntCtrl)

BEGIN_EXIT(IntCtrl)
END_EXIT(IntCtrl)


 


/*
 * ARMulator callbacks
 */



 
/* 
Function Name: SignalInterruptChange
Parameters: void *handle - This should be the IntcState handle from MemInit
         This handle is available from the interrupt controller interface
        structure, which itself can be obtained using 
        ARMul_GetInterruptControllerIF
        int sourceNumber - The incoming interrupt signal line number.
                        See ARM DDI 0062D Table 3-1 Interrupt Controller
                        Defined Bits for predefined connections.
        int value - The state of the interrupt signal. Active HIGH.
Return: Always returns 1 to indicate success - deliberately left open in case 
        future usage changes.
Description: Function to receive incoming interrupt signal changes.
        sourceNumber = 0 always indicates an FIQ, although this may be
        remapped in software to an IRQ.
        On receiving an interrupt signal the FIQ/IRQRawStatus is updated,
        the FIQ/IRQStatus is then updated ( w.r.t FIQ/IRQEnable )
        Finally the nIrq and nFiq signals are set according to the
        FIQ/IRQStatus register values.
*/

static unsigned  SignalInterruptChange(GenericAccessCallback *myCB,
                                       ARMword address, ARMword *data,
                                       unsigned type)
{
    IntCtrlState *intcs = (IntCtrlState*)myCB->handle;
    ARMword value = *data;
    int sourceNumber = address;
    int intState = value ? 1 : 0;

    (void)type;

    /* Note that in the RPS Spec ONLY interrupt source 0 may cause a FIQ */
    if ( sourceNumber == 0)
    {
    /* Update the FIQRawStatus register. There is only 1 bit slice for FIQ
    so we can cheat - not worrying about separate setting/clearing code
    as we have to do for IRQ below. If you base a new intc on this code
    then you will have to copy and modify the IRQ setting/clearing code
    for FIQ.*/
        intcs->myIntc.FIQRawStatus = intState; 
 
        /* Update FIQ register chain */  
        FIQUpdate (intcs);    
    }
    else
    {
        /* Update IRQRawStatus register - either setting or clearing a bit */
        if ( intState )
        {
            /* Set the specified bit */
            intcs->myIntc.IRQRawStatus |= (1 << sourceNumber);
        }
        else
        {
            /* Clear the specified bit */
            intcs->myIntc.IRQRawStatus &= ~(1 << sourceNumber);
        }
        /* Update IRQ register chain */
        IRQUpdate(intcs);
    }
    return RDIError_NoError;
}




/*
Function Name: IRQUpdate
Parameters:  ARMul_State *state - This has to be the original ARMul_State.
             IntcState *intcs - This HAS to be the IntcState - interrupt 
             controller interface structure, which itself can be obtained using 
             ARMul_GetInterruptControllerIF
Return: void
Description: This function is called whenever any of the IRQ registers 
             are changed or whenever a new IRQ signal has arrived.
             We have to do two things;
             1. Make the IRQStatus using IRQRawStatus & Enable.
             2. Set the nIrq signal
*/
void IRQUpdate(IntCtrlState *intcs)
{
  /* Make the IRQStatus using IRQRawStatus & IRQEnable */
    intcs->myIntc.IRQStatus = intcs->myIntc.IRQRawStatus & intcs->myIntc.IRQEnable;
#ifdef VERBOSE
    printf("\n**** Sending SignalIRQ = %lx *****\n",intcs->myIntc.IRQStatus);
#endif
    ARMulif_SetSignal(&intcs->coredesc, RDIPropID_ARMSignal_IRQ,
                    intcs->myIntc.IRQStatus ? Signal_On : Signal_Off);
}



/*
Function Name: FIQUpdate
Parameters: ARMul_State *state - This has to be the original ARMul_State.
            IntcState *intc - This HAS to be the IntcState - interrupt 
        controller interface structure, which itself can be obtained using 
        ARMul_GetInterruptControllerIF
Return: void
Description: This function is called whenever any of the FIQ registers is
         changed or whenever a new IRQ signal has arrived.
   We have to do two things;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -