diff -r 4816d766a08a -r f345bda72bc4 Symbian3/PDK/Source/GUID-8B8CAEED-A89D-53B3-A311-51CF45B334B1.dita --- a/Symbian3/PDK/Source/GUID-8B8CAEED-A89D-53B3-A311-51CF45B334B1.dita Tue Mar 30 11:42:04 2010 +0100 +++ b/Symbian3/PDK/Source/GUID-8B8CAEED-A89D-53B3-A311-51CF45B334B1.dita Tue Mar 30 11:56:28 2010 +0100 @@ -1,178 +1,178 @@ - - - - - -IRQ -and FIQ DispatchersThe ASSP must supply two dispatcher functions, one for IRQ interrupts, -and one for FIQ interrupts. -

The following example code is a simple dispatcher for IRQ interrupts. -It assumes a simplistic interrupt controller that provides 32 interrupt sources, -and has a 32-bit pending-interrupt register where a 'one' bit indicates a -pending interrupt and all ones are cleared when the register is read.

-void IrqDispatch() - { - TUint32 pendingIrqs = TheAssp::IrqPendingRegister(); - // for the purposes of this example we assume that reading - // this register also clears the pending flags - - TInt index = 0; - while( pendingIrqs ) - { - // while there is at least one pending IRQ - if( pendingIrqs & 1 ) - { - // the next interrupt is pending - dispatch it - (IsrHandlers[index].iIsr)(IsrHandlers[index].iPtr); - } - ++index; - pendingIrqs >>= 1; - } - } - -

The code assumes that the interrupt source represented by the low order -bit in the pending-interrupt register is represented by interrupt ID number -0 etc.

-

When implementing the dispatcher it is usual to write it in C++ initially, -but once you have it working you would probably want to rewrite it in assembler -to gain maximum efficiency for what is a time-critical section of code.

-
Dealing with -chained interrupts

There are two considerations when dealing with chained -interrupts:

    -
  1. how to identify interrupts -on the lower priority chained controllers

  2. -
  3. how to handle the dispatch -of a chained interrupt.

  4. -

The first point is a question of allocating locations in your ISR -table for the secondary controllers so that the interrupt ID identifies which hardware controller the interrupt is -on. For example, if each interrupt controller handles 32 interrupt sources, -you could make the first 32 IDs refer to the highest-level controller, the -next 32 refer to one of the second-level controllers etc.

There is -no need to change the Interrupt::Bind() and Interrupt::Unbind() functions, -although you may need to consider extending the Interrupt::Enable() and Interrupt::Disable() functions -to enable and disable the chain interrupt in a higher-level interrupt controller, -if necessary.

There are at least two ways of dispatching a chained -interrupt:

Dispatching a chained interrupt (1)

One -way of dispatching a chained interrupt is simply to make it a special case -in the main interrupt dispatcher. For example:

void IrqDispatch() - { - TUint32 pendingIrqs = TheAssp::IrqPendingRegister(); - - TInt index = 0; - while( pendingIrqs ) - { - if( pendingIrqs & 1 ) - { - if( index == EMainIntChainIrq ) - { - // second-level controller is signalling - SecondLevelIrqDispatch(); - } - else - { - // call ISR - (IsrHandlers[index].iIsr)(IsrHandlers[index].iPtr); - } - } - ++index; - pendingIrqs >>= 1; - } - } -

This approach works for a simple case, for example, where -there is only a main and secondary interrupt controller. It is does not scale -well because the special cases in the dispatcher become an overhead on the -dispatch of normal, unchained interrupts as the number and depth of the chaining -increases.

Dispatching a chained interrupt (2)

A better -way of handling chained interrupts is to bind an ISR to the interrupt source -in the main interrupt controller and use it to dispatch the chained interrupt. -This is far more scalable because you can bind any number of ISRs without -having to add special cases to any of the interrupt dispatchers.

The -dispatcher code could then be re-implemented as:

void IrqDispatch() - // MAIN IRQ DISPATCHER, FIRST-LEVEL INTERRUPT - { - TUint32 pendingIrqs = TheAssp::IrqPendingRegister(); - - TInt index = 0; - while( pendingIrqs ) - { - if( pendingIrqs & 1 ) - { - (IsrHandlers[index].iIsr)(IsrHandlers[index].iPtr); - } - ++index; - pendingIrqs >>= 1; - } - } - void SecondLevelIrqDispatch( TAny* /* aParam */ ) - { - TUint32 pendingIrqs = TheAssp::SecondLevelIrqPendingRegister(); - - TInt index = EStartOfSecondLevelIntId; - while( pendingIrqs ) - { - if( pendingIrqs & 1 ) - { - (IsrHandlers[index].iIsr)(IsrHandlers[index].iPtr); - } - ++index; - pendingIrqs >>= 1; - } - } - void InitialiseSecondLevelDispatch() - // Bind and enable the second-level dispatcher - { - Interrupt::Bind(EMainIntChainIrq,SecondLevelIrqDispatch,NULL); - Interrupt::Enable( EMainIntChainIrq ); - } - -Interrupt sources - -
    -
  • The second level dispatcher, SecondLevelIrqDispatch(), -is itself an ISR, and takes a TAny * parameter, but is -not needed in this specific example. It reads the interrupt pending register -of the second-level interrupt controller. Note, however, that the TAny * -parameter may be useful when the second level dispatcher is in the variant -as opposed to the ASSP. In that case you have separate interrupt IDs for variant -level interrupts and separate ISR tables. The TAny * parameter -can point to the appropriate ISR table. Alternatively the TAny * -can point to a data block containing IO addresses - especially useful if you -have many I/O devices mapped as hardware chunks. See the code in ...\assabet\specific\variant.cpp.

  • -
  • The index count starts -at offset EStartOfSecondLevelIntId into the ISR table, where -the second-level interrupt ISRs are located. In this example, this symbol -would equate to 32.

  • -
  • EMainIntChainIrq is -the interrupt ID of the chained interrupt source to the main interrupt controller.

  • -
-
Dealing with multiple interrupt sources

The case -where multiple peripherals are connected to the same interrupt source can -be handled through the technique of pseudo interrupt sources. This involves -assigning pseudo-interrupt IDs in the ISR table to correspond to each of the -peripherals that is attached to the interrupt line, i.e. ISRs are bound to -these pseudo-interrupt sources.

Dealing with pseudo interrupt sources -is, in essence, a special case of Chained -interrupts.

The dispatcher can do one of two things:

    -
  • examine the peripheral -hardware to determine which of the interrupts are pending, and then call the -appropriate ISR

  • -
  • call all the ISRs and -leave them to determine whether their peripheral is actually signalling an -interrupt.

  • -

As usual, it is entirely up to you to choose the ID numbers for these -pseudo-interrupts.

There should be no need to alter the implementations -of Interrupt::Bind() or Interrupt::Unbind() but -you will need some special handling in Interrupt::Enable() to -enable the true interrupt source, and Interrupt::Disable() to -disable this interrupt source.

Dispatching the interrupt can be done -in either of the two ways described in dealing with chained interrupts. Making use of a special case in the main interrupt -dispatcher is acceptable for simple cases, but for more complicated cases -with large numbers of pseudo-interrupts or a combination of chained and pseudo-interrupts, -it is better to use an ISR dispatcher bound to the true interrupt source.

+ + + + + +IRQ +and FIQ DispatchersThe ASSP must supply two dispatcher functions, one for IRQ interrupts, +and one for FIQ interrupts. +

The following example code is a simple dispatcher for IRQ interrupts. +It assumes a simplistic interrupt controller that provides 32 interrupt sources, +and has a 32-bit pending-interrupt register where a 'one' bit indicates a +pending interrupt and all ones are cleared when the register is read.

+void IrqDispatch() + { + TUint32 pendingIrqs = TheAssp::IrqPendingRegister(); + // for the purposes of this example we assume that reading + // this register also clears the pending flags + + TInt index = 0; + while( pendingIrqs ) + { + // while there is at least one pending IRQ + if( pendingIrqs & 1 ) + { + // the next interrupt is pending - dispatch it + (IsrHandlers[index].iIsr)(IsrHandlers[index].iPtr); + } + ++index; + pendingIrqs >>= 1; + } + } + +

The code assumes that the interrupt source represented by the low order +bit in the pending-interrupt register is represented by interrupt ID number +0 etc.

+

When implementing the dispatcher it is usual to write it in C++ initially, +but once you have it working you would probably want to rewrite it in assembler +to gain maximum efficiency for what is a time-critical section of code.

+
Dealing with +chained interrupts

There are two considerations when dealing with chained +interrupts:

    +
  1. how to identify interrupts +on the lower priority chained controllers

  2. +
  3. how to handle the dispatch +of a chained interrupt.

  4. +

The first point is a question of allocating locations in your ISR +table for the secondary controllers so that the interrupt ID identifies which hardware controller the interrupt is +on. For example, if each interrupt controller handles 32 interrupt sources, +you could make the first 32 IDs refer to the highest-level controller, the +next 32 refer to one of the second-level controllers etc.

There is +no need to change the Interrupt::Bind() and Interrupt::Unbind() functions, +although you may need to consider extending the Interrupt::Enable() and Interrupt::Disable() functions +to enable and disable the chain interrupt in a higher-level interrupt controller, +if necessary.

There are at least two ways of dispatching a chained +interrupt:

Dispatching a chained interrupt (1)

One +way of dispatching a chained interrupt is simply to make it a special case +in the main interrupt dispatcher. For example:

void IrqDispatch() + { + TUint32 pendingIrqs = TheAssp::IrqPendingRegister(); + + TInt index = 0; + while( pendingIrqs ) + { + if( pendingIrqs & 1 ) + { + if( index == EMainIntChainIrq ) + { + // second-level controller is signalling + SecondLevelIrqDispatch(); + } + else + { + // call ISR + (IsrHandlers[index].iIsr)(IsrHandlers[index].iPtr); + } + } + ++index; + pendingIrqs >>= 1; + } + } +

This approach works for a simple case, for example, where +there is only a main and secondary interrupt controller. It is does not scale +well because the special cases in the dispatcher become an overhead on the +dispatch of normal, unchained interrupts as the number and depth of the chaining +increases.

Dispatching a chained interrupt (2)

A better +way of handling chained interrupts is to bind an ISR to the interrupt source +in the main interrupt controller and use it to dispatch the chained interrupt. +This is far more scalable because you can bind any number of ISRs without +having to add special cases to any of the interrupt dispatchers.

The +dispatcher code could then be re-implemented as:

void IrqDispatch() + // MAIN IRQ DISPATCHER, FIRST-LEVEL INTERRUPT + { + TUint32 pendingIrqs = TheAssp::IrqPendingRegister(); + + TInt index = 0; + while( pendingIrqs ) + { + if( pendingIrqs & 1 ) + { + (IsrHandlers[index].iIsr)(IsrHandlers[index].iPtr); + } + ++index; + pendingIrqs >>= 1; + } + } + void SecondLevelIrqDispatch( TAny* /* aParam */ ) + { + TUint32 pendingIrqs = TheAssp::SecondLevelIrqPendingRegister(); + + TInt index = EStartOfSecondLevelIntId; + while( pendingIrqs ) + { + if( pendingIrqs & 1 ) + { + (IsrHandlers[index].iIsr)(IsrHandlers[index].iPtr); + } + ++index; + pendingIrqs >>= 1; + } + } + void InitialiseSecondLevelDispatch() + // Bind and enable the second-level dispatcher + { + Interrupt::Bind(EMainIntChainIrq,SecondLevelIrqDispatch,NULL); + Interrupt::Enable( EMainIntChainIrq ); + } + +Interrupt sources + +
    +
  • The second level dispatcher, SecondLevelIrqDispatch(), +is itself an ISR, and takes a TAny * parameter, but is +not needed in this specific example. It reads the interrupt pending register +of the second-level interrupt controller. Note, however, that the TAny * +parameter may be useful when the second level dispatcher is in the variant +as opposed to the ASSP. In that case you have separate interrupt IDs for variant +level interrupts and separate ISR tables. The TAny * parameter +can point to the appropriate ISR table. Alternatively the TAny * +can point to a data block containing IO addresses - especially useful if you +have many I/O devices mapped as hardware chunks. See the code in ...\assabet\specific\variant.cpp.

  • +
  • The index count starts +at offset EStartOfSecondLevelIntId into the ISR table, where +the second-level interrupt ISRs are located. In this example, this symbol +would equate to 32.

  • +
  • EMainIntChainIrq is +the interrupt ID of the chained interrupt source to the main interrupt controller.

  • +
+
Dealing with multiple interrupt sources

The case +where multiple peripherals are connected to the same interrupt source can +be handled through the technique of pseudo interrupt sources. This involves +assigning pseudo-interrupt IDs in the ISR table to correspond to each of the +peripherals that is attached to the interrupt line, i.e. ISRs are bound to +these pseudo-interrupt sources.

Dealing with pseudo interrupt sources +is, in essence, a special case of Chained +interrupts.

The dispatcher can do one of two things:

    +
  • examine the peripheral +hardware to determine which of the interrupts are pending, and then call the +appropriate ISR

  • +
  • call all the ISRs and +leave them to determine whether their peripheral is actually signalling an +interrupt.

  • +

As usual, it is entirely up to you to choose the ID numbers for these +pseudo-interrupts.

There should be no need to alter the implementations +of Interrupt::Bind() or Interrupt::Unbind() but +you will need some special handling in Interrupt::Enable() to +enable the true interrupt source, and Interrupt::Disable() to +disable this interrupt source.

Dispatching the interrupt can be done +in either of the two ways described in dealing with chained interrupts. Making use of a special case in the main interrupt +dispatcher is acceptable for simple cases, but for more complicated cases +with large numbers of pseudo-interrupts or a combination of chained and pseudo-interrupts, +it is better to use an ISR dispatcher bound to the true interrupt source.

\ No newline at end of file