📄 intc.c
字号:
/* 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 + -