Interrupt Handling
The following section demonstrates how to configure the interrupt related functionality for a MARK application. The example sources can be found in the ada_examples.ss/<view>/interrupts/.
This section consists of the following topics:
- Ada.Interrupts.Names
- Enabling Interrupts
- Protected Objects
- Improving the Quality of Generated Code
- Vads Exec V_Interrupts.Attach_Isr
Ada.Interrupts.NamesIn the systems_programming.ss view the ada.interrupts.names package contains the names of all the interrupts used in the system.
It may be necessary to tailor your board support package including ada.interrupts.names to your specific implementation.
In order to support the package Ada.Interrupts, each interrupt must be either reserved or available for attaching interrupt handlers. In the systems_programming.ss view the package Apex_Systems_Programming.Interrupts_Id can be edited. This package contains an array of interrupts (Interrupt_Ids) and an indication if these interrupts should be reserved (Interrupt_Ids_Reserved := True) or if they should not be reserved (Interrupt_Ids_Reserved := False). All other interrupts are treated in the opposite fashion.
Ada.Interrupts.Rational.Set_Reserve_Handler
It is possible to change the value of one of the previously reserved handlers by making a call to the Rational specific procedure Set_Reserve_Handler.
For example, the "power" example uses the Decrementer interrupt which is normally reserved for use by delay clauses. The following code fragment makes the Decrementer a non reserved interrupt to allow a handler to be attached.
Was_Decrementer_Reserved : Boolean := Ada.Interrupts.Rational.Set_Reserve_Handler (False, Ada.Interrupts.Names.Decrementer);
Enabling InterruptsBy default, interrupts are enabled after kernel initialization. It is possible to disable interrupts until the interrupt handlers have been installed by the application. The application will then explicitly enable interrupts.
In the krn_conf.ss view, the constant USER_INTR_STATUS in the V_Krn_Conf package is set to the interrupt status instantiated for the execution of the user program.
The default must be changed from:
USER_INTR_STATUS : constant krn_defs.intr_status_t := krn_defs.ENABLE_INTR_STATUS;
USER_INTR_STATUS : constant krn_defs.intr_status_t := krn_defs.DISABLE_INTR_STATUS;
In the test program, add the following code to enable interrupts. It is assumed that the handlers will be attached during library level package elaboration. The rts_vads_exec.ss view must be imported. This is where the V_Interrupts package is located.
with V_Interrupts; -- in rts_vads_exec procedure Protected_Main is Old_Interrupt_Status : V_Interrupts.Interrupt_Status_T; begin Old_Interrupt_Status := V_Interrupts.Set_Interrupt_Status (V_Interrupts.Enable_Interrupt);
Protected ObjectsThere are two ways to attach handlers to interrupts. The Ada 95 protected object mechanism provides language support for attaching handlers.
See ada_examples.ss for an example.
Improving the Quality of Generated CodeThere are two mechanisms that can be used to increase the quality of the generated code:
- Add pragmas that explicitly allow the compiler to generate better code.
- Choose an Interrupt_Handler_Wrapper that exactly fits the parameters of the handler.
Pragmas
Use care when suppressing compiler generated checks. The application must be carefully checked to empirically prove the runtime checks are not required.
The pragma Suppress(All_Checks) can be applied to the package spec and body so that no stack checks or constraint checks are generated by the compiler. This pragma can not suppress elaboration due to required LRM language semantics.
The pragma Suppress_Elaboration_Checks can be added immediately following the "end Package_Name;" statement in the package body and spec.
Choosing the right Interrupt_Handler_Wrapper
The following is an explanation on choosing the right wrappers. To summarize, there are two variables: floating point (True/False) and Additional interrupt locking required (True/False). In this case, the PowerPC blocks interrupts when an interrupt is generated so additional locking is not required. The interrupt handler does not use floating point. See Apex_Systems_Programming.Interrupt_Wrappers.
Vads Exec V_Interrupts.Attach_IsrAlternatively the Vads Exec service Attach_Isr can be called to attach a handler to an interrupt. The above example has been changed to use Attach_Isr instead of protected objects.
with All_Contribution; with V_Interrupts; -- in rts_vads_exec with Interfaces; with Attach_Package; -- package that provides the interrupt handlers procedure Attach_Main is -- This is the main subprogram used to demonstrate the usage -- of interrupt wrappers and attaching handlers. use type Interfaces.Unsigned_32; Old_Interrupt_Status : V_Interrupts.Interrupt_Status_T; Count : Interfaces.Unsigned_32; begin -- The interrupt handlers are attached explicitly using the -- rts_vads_exec V_Interrupts services to do the attach. V_Interrupts.Attach_Isr (Attach_Package.Interrupt_Id, Attach_Package.Interrupt_Handler'Address); -- It is possible to to begin execution of this user -- application with interrupts disabled by changing the code -- in krn_conf.ss//v_krn_conf.2.ada. The value of -- User_Intr_Status must be set to disable all interrupts. -- For the mvme16xx kernel configuration the code changes -- are something like this: -- from: -- -- User_Intr_Status : constant Krn_Defs.Intr_Status_T := -- Io_Conf.User_Intr_Mask; -- -- to: -- -- User_Intr_Status : constant Krn_Defs.Intr_Status_T := -- Io_Conf.All_Intr_Mask; -- -- It is now safe to enable the external interrupts Old_Interrupt_Status := V_Interrupts.Set_Interrupt_Status (V_Interrupts.Enable_Interrupt); -- Wait for 5 interrupts while Attach_Package.Interrupt_Count < 5 loop -- Get a temporary copy of the Interrupt_Count. Count := Attach_Package.Interrupt_Count; -- Trigger the interrupt Attach_Package.Trigger_Interrupt; -- Wait for the Interrupt_Count to change before -- continuing. This will avoid triggering the interrupt -- more then once per interrupt. while Count = Attach_Package.Interrupt_Count loop null; end loop; end loop; end Attach_Main; ----------------------------------------------------------------- pragma Main; with System; with Interfaces; with V_Interrupts; with V_Cpu_Conf; package Attach_Package is -- Warning: the Interrupt_Id being exported by this package is -- the Decrementer. Use of the Interrupt_Id will take the -- Decrementer interrupt and make delay clauses unusable! pragma Suppress (All_Checks); -- The Decrementer is normally reserved for use as a timer -- for the implementation of the ada "Delay" clauses The -- Decrementer is therefore reserved. However, this -- application is going to take this interrupt instead. Interrupt_Id : V_Interrupts.Vector_Id := V_Cpu_Conf.I_Decrement; -- Interrupt_Handler is the export procedure that can be -- attached to an interrupt. procedure Decrementer; procedure Interrupt_Handler is new V_Interrupts.Isr (Decrementer); -- Cause an interrupt to happen at some time in the -- future. procedure Trigger_Interrupt; -- Number of Decrementer interrupts that have been -- handled. function Interrupt_Count return Interfaces.Unsigned_32; end Attach_Package; ---------------------------------------------------------------------- pragma Suppress_Elaboration_Checks; with System.Machine_Code; package body Attach_Package is pragma Suppress (All_Checks); use type Interfaces.Unsigned_32; -- Number of decrementer interrupts. The_Decrementer_Count : Interfaces.Unsigned_32 := 0; -- The decrementer value used when triggering the -- decrementer interrupt. The_Number_Of_Ticks : Interfaces.Unsigned_32 := 16#1_000#; procedure Set_Decrementer_Machine_Code (Ticks : Interfaces.Unsigned_32) is -- Poke a tick value directly into the decrementer -- register. use System.Machine_Code; begin Code_2'(Mtspr, Dec, R3); end Set_Decrementer_Machine_Code; procedure Decrementer is -- Interrupt handler begin The_Decrementer_Count := The_Decrementer_Count + 1; end Decrementer; function Interrupt_Count return Interfaces.Unsigned_32 is -- Return number of decrementer interrupts begin return The_Decrementer_Count; end Interrupt_Count; procedure Trigger_Interrupt is -- Trigger the next decrementer interrupt begin Set_Decrementer_Machine_Code (The_Number_Of_Ticks); end Trigger_Interrupt; end Attach_Package; pragma Suppress_Elaboration_Checks;
Rational Software Corporation http://www.rational.com support@rational.com techpubs@rational.com Copyright © 1993-2001, Rational Software Corporation. All rights reserved. |