📄 epic.c
字号:
/*
* file: epic.c
*
* PowerPC 8240 interrupt controller support
* for UCOS-II
*
* Author: Ernie Price
* eprice@bitwise.net
*
*/
#include "includes.h"
#define PRIO (--pri << 16) // used by epic_InitEPIC
typedef struct irqHandler_t
{
INT32U arg;
void (*handler)(INT32U);
} irqHandler_t;
static irqHandler_t interruptHandlers[MAX_HANDLERS + 1];
#define epicwd(x) \
INT32U x; \
INT32U dum##x[3]
#define epicres(n, x) \
INT32U res##n[x]
/***********************************************************************
The EPIC hardware structure
It is broken into three parts to avoid indexes over 64 Kb
*/
#pragma pack (0,0,1) // treat as little-endian
volatile struct epicA
{
epicwd (FRR); // Feature reporting register (FRR) NIRQ, NCPU, VID
epicres (1, 4); // Reserved
epicwd (GCR); // Global configuration register (GCR) R (reset), M (mode)
#define EPIC_RESET (1 << 31)
#define EPIC_MODE (1 << 29)
epicwd (EICR); // epic interrupt configuration register (EICR) R (clock ratio), SIE
epicres (2, 16); // 0x4_1040 - 0x4_1070 Reserved
epicwd (EVI); // epic vendor identification register (EVI) STEP, DEVICE_ID, VENDOR_ID
epicwd (PI); // Processor initialization register (PI) P0
epicres (3, 16); // 0x4_10A0 - 0x4_10D0 Reserved
epicwd (SVR); // Spurious vector register (SVR) VECTOR
epicwd (TFRR); // Timer frequency reporting register (TFRR) TIMER_FREQ
struct
{
epicwd (GTCCR); // Global timer current count register (GTCCR0) T (toggle), COUNT
epicwd (GTBCR); // Global timer base count register (GTBCR0) CI, BASE_COUNT
epicwd (GTVPR); // Global timer vector/priority register (GTVPR0) M, A, PRIORITY, VECTOR
epicwd (GTDR); // Global timer destination register (GTDR0) P0
} tmr[4];
};
volatile struct epicB
{
union
{
struct
{
epicwd (IVPR); // IRQ0 vector/priority register (IVPR0) M, A, P, S, PRIORITY, VECTOR
#define IMASK (1 << 31)
#define ACTIVE (1 << 30)
#define ACT_HIGH (1 << 23)
#define LVL_SENS (1 << 22)
#define DEF_LOW (IMASK | LVL_SENS)
epicwd (IDR); // IRQ0 destination register (IDR0) P0
} Irq[5];
struct
{
epicwd (SVPR); // Serial interrupt 0 vector/priority register (SVPR0) M, A, P, S, PRIORITY, VECTOR
epicwd (SDR); // Serial interrupt 0 destination register (SDR0) P0
} Ser[16];
} x;
epicres (1, 776); // 0x5_0400 - 0x5_1010 Reserved
struct
{
epicwd (IIVPR); // I2C interrupt vector/priority register (IIVPR0) M, A, PRIORITY, VECTOR
epicwd (IIDR); // I2C interrupt destination register (IIDR0) P0
} IDM[10];
};
volatile struct epicC
{
epicwd (PCTPR); // Processor current task priority register (PCTPR) TASKP
epicres (1, 4);
epicwd (IACK); // Processor interrupt acknowledge register (IACK) VECTOR
epicwd (EOI); // Processor end-of-interrupt register (EOI) EOI_CODE
};
#pragma pack (0)
static struct epicA *epicA = (struct epicA *)(EUMB_BASE + 0x41000);
static struct epicB *epicB = (struct epicB *)(EUMB_BASE + 0x50200);
static struct epicC *epicC = (struct epicC *)(EUMB_BASE + 0x60080);
// End EPIC hardware structure
/*
\brief Initializes the EPIC
*/
void epic_InitEPIC(void)
{
INT32S i, pri = 16;
epicA->GCR = EPIC_RESET; // reset the controller
DelayNusec(10);
for (i = 0; i < 5; i++)
epicB->x.Irq[i].IVPR = DEF_LOW | PRIO; // set IRQ0 - IRQ4 behavior
epicB->x.Irq[IRQ3].IVPR |= ACT_HIGH; // for the 16C550 on SBC8240
epicB->IDM[I2C - I2C].IIVPR = IMASK | PRIO; // set I2C behavior
epicB->IDM[DMA0 - I2C].IIVPR = IMASK | PRIO; // set DMA0 behavior
epicB->IDM[MSGU - I2C].IIVPR = IMASK | PRIO; // set Msg Unit behavior
epicB->IDM[UART0 - I2C].IIVPR = IMASK | PRIO; // set UART0 behavior on 8241/5
epicA->tmr[TMR0 - TMR0].GTVPR = IMASK | PRIO; // set TMR0 behavior
epicA->SVR = MAX_HANDLERS;
epicA->GCR = EPIC_MODE; // mixed mode
epicC->PCTPR = 0; // allow interrupts
}
/*
\brief Returns a pointer to the specified vector priority register
*/
static INT32U *GetAddrVPR(INT32U intLevel)
{
if (intLevel < I2C) // irq0 - irq4
return &epicB->x.Irq[intLevel].IVPR;
if (intLevel < TMR0) // internal I2C, DMA, UART, etc
return &epicB->IDM[intLevel - I2C].IIVPR;
if (intLevel < MAX_HANDLERS) // timers
return &epicA->tmr[intLevel - TMR0].GTVPR;
return (INT32U*)0; // no such interrupt
}
/*
\brief Fetches the IRQ vector from the epic and invokes the handler
*/
void EIE_Hdlr(void)
{
INT32U epicIntSrc;
epicIntSrc = epicC->IACK; // fetch highest priority vector
if (epicIntSrc != MAX_HANDLERS)
{
irqHandler_t *hndlentry;
hndlentry = &interruptHandlers[epicIntSrc];
(*hndlentry->handler) (hndlentry->arg);
}
epicC->EOI = 0;
}
/*
\brief Enables the interrupt for the specified vector
*/
void epic_EnableInterrupt(INT32U vector)
{
INT32U *ptrVPR, value;
MSR_SAVE;
ptrVPR = GetAddrVPR(vector);
if (ptrVPR)
{
OS_ENTER_CRITICAL();
value = RE_LONG(ptrVPR);
value |= vector;
value &= ~IMASK;
RE_LONG(ptrVPR) = value;
OS_EXIT_CRITICAL();
}
}
/*
\brief Disables the interrupt for the specified vector
*/
void epic_DisbleInterrupt(INT32U vector)
{
INT32U *ptrVPR, value;
MSR_SAVE;
ptrVPR = GetAddrVPR(vector);
if (ptrVPR)
{
OS_ENTER_CRITICAL();
value = RE_LONG(ptrVPR);
value |= IMASK;
RE_LONG(ptrVPR) = value;
OS_EXIT_CRITICAL();
}
}
/*
\brief Adds an IRQ handler and enables the interrupt for it
*/
void epic_AddHandler(
INT32U id, // Interrupt vector number
void (*handler) (), // Pointer to Interrupt Handler Function
INT32U arg // Argument to pass to the Handler
)
{
MSR_SAVE;
if (id >= MAX_HANDLERS)
return;
OS_ENTER_CRITICAL();
interruptHandlers[id].handler = handler;
interruptHandlers[id].arg = arg;
epic_EnableInterrupt(id);
OS_EXIT_CRITICAL();
}
/* End of Source */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -