📄 sma_priority_driver.c
字号:
/**********************************************************************
* $Workfile: SMA_priority_driver.c $
* $Revision: 1.4 $
* $Author: KovitzP $
* $Date: Jun 06 2002 08:37:28 $
*
* Project: Useful functions for SOC devices.
*
* Description:
* This module contains functions for parsing status bits with
* constant latency and software assignable priorities.
* Provided functions are:
* priority_init_handlers()--create priority encoding environment
* priority_install_handler()--associate a status bit with a
* priority and a handler function
* priority_remove_handler()--de-associate a status bit with a
* prioirty and a handler function
* priority_get_priority()--return the priority of a status bit
* priority_get_handler()--return the handler function pointer for a
* status bit
*
* Also,the following macro (see priority_driver.h) assists in
* making parser functions.
* MAKE_DISPATCHER8()
* MAKE_DISPATCHER16()
* MAKE_DISPATCHER24()
* MAKE_DISPATCHER32()
*
* Purpose and Algorithm:
* Many peripherals report status based on a single status register
* that can be up to 32 bits wide. Interrupt handlers often have
* to parse these bits to figure out the appropriate response
* to a particular interrupt. The traditional parser looks like
* this:
*
* status = read_status_register();
* if (status && _BIT(0))
* {
* handle_bit_0()
* }
* else if (status & _BIT(1) )
* {
* handle_bit_1();
* }
* .....
* else if (status & _BIT(31) )
* {
* handle_bit_31();
* }
*
* There are a two main problems with this structure. First,
* this is a linear search algorithm. Figuring out which bit is
* set is an O(N) operation. Latency in handling a particular
* condition is proportional to the place in the parsing loop.
*
* Second, the priority of a particular status bit is fixed in
* the handler function and cannot change at run-time. Figuring
* out the priority of a particular status bit requires reading
* the entire code section of the parser.
*
* The functions in this module attempt to address both problems.
* The family of functions provided here support the following
* algorith for parsing status bits:
*
* 1 status = read_status_register();
* 2 priority = priority_encode[status];
* 3 handler_list[priority]();
*
* To understand this algorithm, start with line 3. The priority
* of any condition is a number {0,1,2,..). The lower the number,
* the higher the priority. Each condition that can set a status bit
* is assigned a priority. Each condition that can set a status bit
* has an associated handler function. The pointers to the handler
* functions are stored in the handler_list[] array. Handler function
* pointers are sorted by the priority number of their associated
* status bits.
*
* The purpose of line 2 is to convert any combination of set bits
* into the single, highest priority. Notice that line 2 seems to
* ignore the fact that the status register bits have individual
* identities. Rather, the status register is treated as an integer
* array index.
*
* For example, if the status register contents contains bits 1 and 3
* set, then the integer value in the status variable is 9.
* If the condition that set bit 1 is higher priority than the
* condition that set bit 3, then priority_encode[9] will contain
* the priority number that corresponds to the condition that
* set bit 1 (9 is 0b1001, i.e. bits 3 and 1 set). This makes the
* priority search algorithm O(1) instead of O(N).
*
* There are two complications. First, the number of entries in the
* priority_encode[] array grows as 2^(number of status bits). For
* a 32-bit status register, the priority_encode[] array would be
* too large to be practical. To get around this complication, these
* functions divide the status register into 8-bit sections. For a
* 32-bit status register, the parsing algorithm looks like this:
*
* 10 status = read_status_register();
* 11 priority0 = priority_encode0[status & _BITMASK(8)];
* 12 priority1 = priority_encode1[ (status >> 8 ) & _BITMASK(8)];
* 13 priority2 = priority_encode2[ (status >> 16) & _BITMASK(8)];
* 14 priority3 = priority_encode3[ (status >> 24) & _BITMASK(8)];
* 15 if (priority0 < priority1)
* 16 priority4 = priority0;
* 17 else
* 18 priority4 = prioirty1
* 19 if (priority2 < priority3)
* 20 priority5 = priority2;
* 21 else
* 22 priority5 = prioirty3;
* 23 if (priority4 < priority5)
* 24 priority = priority4;
* 25 else
* 26 priority = prioirty5
* 27 handler_list[priority]();
*
* For 32 possible status bits, the above algorithm is much
* faster than the worst case linear search latency. Also, the
* parsing latency is the same no matter what the priority. The cost
* is a table of 33 function pointers and 4 256-entry priority encode
* tables. As an added benefit, priorities are assignable at run-
* time rather than at compile time.
*
* Some details: The functions in this module use priority numbers
* {0,1,2,3,...,number of status bits - 1, number of status bits).
* Since the priority numbers start with 0, there would seem to be
* an extra priority value. The highest legal priority number is
* number of status bits - 1. The number of status bits prioirty
* number is called illegal_prioirty. When the priority_encode[]
* array is created, all elements are initialized to contain the
* value illegal_priority. The element handler_list[illegal_priority]
* contains a pointer to a function for handling unhandled status
* bits. The illegal_priority handler should, at a minimum, disable
* the source that asserts the illegal status bit so that the
* unhandled status won't happen again.
*
* Revision History:
* $Log: //smaicnt2/pvcs/VM/CHIPS/archives/SOC/Source/SMA_priority_driver.c-arc $
*
* Rev 1.4 Jun 06 2002 08:37:28 KovitzP
* Added missing line breaks and added note to 2nd revision 1.0
* in the Revision History.
*
* Rev 1.3 Jun 05 2002 19:59:12 MaysR
* Corrected error in structure initialization. Was initializing
* unused handler to zero instead of unhandled function address.
*
* Rev 1.2 Mar 28 2002 14:18:22 lij
* Add SHARP Legal Header
*
* Rev 1.1 07 Mar 2002 09:26:50 kovitzp
* repaired a bug in priority_init_driver() that was causing writes to
* address 0 if any of the priority_encode arrays pointers were
* NULL.
*
* Rev 1.0 Jan 31 2002 10:48:14 SuryanG
* Initial revision. (Renamed to SMA_priority_driver.c).
*
* Rev 1.2 Jan 31 2002 10:10:50 KovitzP
* Added default handler argument so that inadvertant source
* triggers after a source handler is removed will not cause a
* problem.
*
* Rev 1.1 Jan 03 2002 16:10:14 KovitzP
* Corrected typos in rebuild_priority_encode()
*
* Rev 1.0 Dec 28 2001 13:26:02 KovitzP
* Initial revision.
*
* SHARP MICROELECTRONICS OF THE AMERICAS MAKES NO REPRESENTATION
* OR WARRANTIES WITH RESPECT TO THE PERFORMANCE OF THIS SOFTWARE,
* AND SPECIFICALLY DISCLAIMS ANY RESPONSIBILITY FOR ANY DAMAGES,
* SPECIAL OR CONSEQUENTIAL, CONNECTED WITH THE USE OF THIS SOFTWARE.
*
* SHARP MICROELECTRONICS OF THE AMERICAS PROVIDES THIS SOFTWARE SOLELY
* FOR THE PURPOSE OF SOFTWARE DEVELOPMENT INCORPORATING THE USE OF A
* SHARP MICROCONTROLLER OR SYSTEM-ON-CHIP PRODUCT. USE OF THIS SOURCE
* FILE IMPLIES ACCEPTANCE OF THESE CONDITIONS.
*
* COPYRIGHT (C) 2001 SHARP MICROELECTRONICS OF THE AMERICAS, INC.
* CAMAS, WA
*********************************************************************/
#include "SMA_priority_driver.h"
/**********************************************************************
*
* Function: priority_init_driver
*
* Purpose:
* Initialize the IRQ dispatcher and handler function arrays to a known
* state so that handlers may be subsequently installed. Set up the
* IRQ exception vector so that any IRQ exception will vector to
* the LH7A400_IRQ_handler fuction.
*
* Processing:
* Associate each source with no handler function handlers[source]=0
* and with illegal priority priorities[source] = ILLEGAL_PRIORITY.
* Make all priority encode tables priority_encode0...
* 3[all combinations] = nsources (illegal priority).
*
* Parameters:
* prio: a pointer to a PRIORITY_DATA structure initalized as follows:
* nsources contains the number of status bits to parse
* priorities points to an array of INT_8 with nsources + 1
* elements
* priority_encode3 is NULL if nsources <= 24 else points to an
* array of INT_8 containing 2^(nsources - 24)
* elements
* priority_encode2 is NULL if nsources <= 16 else points to an
* array of INT_8 containing 8 elements if
* nsources > 24 else points to an array of
* INT_8 containing 2^(nsources - 16) elements
* priority_encode1 is NULL if nsources <= 8 else points to an
* array of INT_8 containing 8 elements if
* nsources > 16 else points to an array of
* INT_8 containing 2^(nsources - 8) elements
* priority_encode0 points to an array of INT_8 containing 8
* elements if nsources > 8 else points to an
* array of INT_8 containing 2^(nsources)
* elements.
* handlers points to an array of nsources + 1 pointers
* to functions that take no arguments and
* that return nothing.
* fp: a pointer to the default handler
*
* Outputs:
* all arrays in the prio structure initialized to the no handlers
* installed state.
*
* Returns: Nothing
*
* Notes:
* You must call this function before installing any IRQ handlers and
* before enabling IRQ interrupts.
*
**********************************************************************/
void priority_init_driver(PRIORITY_DATA * const prio,
void (*fp)(void))
{
INT_32 i;
INT_32 nsources0, nsources1, nsources2, nsources3;
/* divide the sources into groups of 8 */
nsources3 = prio->nsources - 24;
nsources2 = 8;
nsources1 = 8;
nsources0 = 8;
if (nsources3 <= 0)
{
nsources3 = 0;
nsources2 = prio->nsources - 16;
if (nsources2 <= 0 )
{
nsources2 = 0;
nsources1 = prio->nsources - 8;
if (nsources1 <= 0 )
{
nsources1 = 0;
nsources0 = prio->nsources;
}
}
}
for (i = 0; i < prio->nsources; i++)
{
prio->priorities[i] = prio->nsources; // an illegal priority
prio->handlers[i] = fp;
}
prio->priorities[prio->nsources] = prio->nsources;
prio->handlers[prio->nsources] = fp;
if (nsources3 > 0)
{
prio->priority_encode3[0] = prio->nsources;
}
for (i = 1; i < _BIT(nsources3); i++)
{
prio->priority_encode3[i] = prio->nsources; // illegal priority
}
if (nsources2 > 0)
{
prio->priority_encode2[0] = prio->nsources;
}
for (i = 1; i < _BIT(nsources2); i++)
{
prio->priority_encode2[i] = prio->nsources; // illegal priority
}
if (nsources1 > 0)
{
prio->priority_encode1[0] = prio->nsources;
}
for (i = 1; i < _BIT(nsources1); i++)
{
prio->priority_encode1[i] = prio->nsources; // illegal priority
}
if (nsources0 > 0)
{
prio->priority_encode0[0] = prio->nsources;
}
for (i = 1; i < _BIT(nsources0); i++)
{
prio->priority_encode0[i] = prio->nsources; // illegal priority
}
}
/**********************************************************************
*
* Function: rebuild_priority_encode
*
* Purpose:
* Assign values to the priority_encode arrays so that a dispatcher
* can call the highest priority handler function. This function is
* usually called after assigned a new priority to a source in the
* prio->priorities array; this function makes the
* prio->priority_encodex[] arrays reflect what is stored in the
* prio->priorities[] array.
*
* Processing:
* This function uses the following algorithm: for each priority
* encode array index, look at the index as a binary number. For
* each bit in that index that is equal to one, check the priority of
* the associated interrupt source. Assign to the priority encode array
* at the index location the highest priority of all the sources
* that correspond to a bit of the index being set. Note that if
* the source has no handler associated with it, its priority will be
* ILLEGAL_PRIORITY==prio->nsources. prio->nsources is always
* a higher number (lower priority) than any valid priority.
*
* Parameters:
* prio: a constant pointer to the PRIORITY_DATA structure containing
* the priority encode arrays.
*
* Outputs: None
*
* Returns: Nothing
*
* Notes:
* The structure pointed to by prio must be initialized by the
* priority_init_driver() function before this function is called.
*
**********************************************************************/
static void rebuild_priority_encode(PRIORITY_DATA * const prio)
{
UNS_32 i,j,source,mask,not_masked;
INT_32 nsources0, nsources1, nsources2, nsources3;
/* divide the sources into groups of 8 */
nsources3 = prio->nsources - 24;
nsources2 = 8;
nsources1 = 8;
nsources0 = 8;
if (nsources3 <= 0)
{
nsources3 = 0;
nsources2 = prio->nsources - 16;
if (nsources2 <= 0 )
{
nsources2 = 0;
nsources1 = prio->nsources - 8;
if (nsources1 <= 0 )
{
nsources1 = 0;
nsources0 = prio->nsources;
}
}
}
for (i = 1; i < _BIT(nsources0); i++)
{
for (source = 0; source < nsources0; source ++)
{
mask = 1 << source;
prio->priority_encode0[mask] = prio->priorities[source];
if ( (mask & i) == mask)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -