diff -r 4816d766a08a -r f345bda72bc4 Symbian3/PDK/Source/GUID-E0DCBDCF-C056-53E5-A375-778327F848E4.dita --- a/Symbian3/PDK/Source/GUID-E0DCBDCF-C056-53E5-A375-778327F848E4.dita Tue Mar 30 11:42:04 2010 +0100 +++ b/Symbian3/PDK/Source/GUID-E0DCBDCF-C056-53E5-A375-778327F848E4.dita Tue Mar 30 11:56:28 2010 +0100 @@ -1,432 +1,433 @@ - - - - - -Asic -Class TutorialProvides a work through tutorial that allows you to port an Asic -implementation to the template variant. -

This tutorial describes -how to implement the Asic class. This is a pure virtual interface that is -defined and called by the Kernel, but which must be implemented by the ASSP/Variant. -The tutorial assumes that the ASSP/Variant is split into an ASSP layer and -a Variant layer.

-

For a minimal port, it isn't necessary to provide implementations for the -entire Asic class to be able to test that the kernel boots, -provided that those functions that are not fully implemented have a dummy -function so that the code will build.

-

The Asic class is defined in..\e32\include\kernel\arm\assp.h. -For reference, the definition is:

-class Asic - { -public: - // initialisation - virtual TMachineStartupType StartupReason()=0; - virtual void Init1()=0; - virtual void Init3()=0; - - // debug - virtual void DebugOutput(TUint aChar)=0; - - // power management - virtual void Idle()=0; - - // timing - virtual TInt MsTickPeriod()=0; - virtual TInt SystemTimeInSecondsFrom2000(TInt& aTime)=0; - virtual TInt SetSystemTimeInSecondsFrom2000(TInt aTime)=0; - virtual TUint32 NanoWaitCalibration()=0; - - // HAL - virtual TInt VariantHal(TInt aFunction, TAny* a1, TAny* a2)=0; - - // Machine configuration - virtual TPtr8 MachineConfiguration()=0; - }; -

Taking the template port as a concrete example, the ASSP layer implementation -of the Asic class is defined and implemented by the TemplateAssp class, -and the Variant implemention is defined and implemented by the Template class.

-
Asic::Init1() -implementation

Entry -conditions

    -
  • called in the context -of the initial (null) thread

  • -
  • interrupts are disabled

  • -
  • there is no kernel heap

  • -
  • memory management functions -are not available.

  • -

What -the function should do

This is called during stage 1 of kernel -initialisation.

In this function, you need to:

    -
  • initialise the real -time clock

  • -
  • initialise the interrupt -dispatcher before CPU interrupts are enabled.

  • -
  • set the threshold values -for cache maintenance. You can set separate values for:

      -
    • purging (invalidating) -a cache

    • -
    • cleaning a cache

    • -
    • flushing (i.e. cleaning -and invalidating) a cache.

    • -

    You use the Cache::SetThresholds() interface to -set these values.

    As an example of what the threshold values mean, -if you purge a memory region from cache, and the size of that region is greater -than the threshold value, then the entire cache is purged. If the size of -that region is less than or equal to to the threshold value, then only the -region is purged.

    The threshold values are platform specific, and -you need to choose your values based on your own performance measurements. -Symbian cannot make recommendations. If you choose not to set your own values, -Symbian OS supplies a set of default values, which are set by Cache::Init1().

    Note -that there is also a Cache::GetThresholds() interface that -you may find useful.

  • -
  • set up the RAM zones. -For details, see the RAM -Zone Tutorial.

  • -

Typically, you would also initialise any memory devices not initialised -by the bootstrap. Any other initialisation that must happen early on should -also be done here.

The kernel calls the Variant's Init1() function. -On the template port, this is the Variant layer's Init1(), -i.e. the functions Template::Init1(). The source for this -is in ...\template_variant\specific\variant.cpp.

void Template::Init1() - { - __KTRACE_OPT(KBOOT,Kern::Printf("Template::Init1()")); - - // - // TO DO: (mandatory) - // - // Configure Memory controller and Memrory Bus parameters (in addition to what was done in the Bootstrap) - // - __KTRACE_OPT(KBOOT,Kern::Printf("Memory Configuration done")); - - // - // TO DO: (optional) - // - // Inform the kernel of the RAM zone configuration via Epoc::SetRamZoneConfig(). - // For devices that wish to reduce power consumption of the RAM IC(s) the callback functions - // RamZoneCallback() and DoRamZoneCallback() will need to be implemented and passed - // to Epoc::SetRamZoneConfig() as the parameter aCallback. - // The kernel will assume that all RAM ICs are fully intialised and ready for use from boot. - // - - // - // TO DO: (optional) - // - // Initialise other critical hardware functions such as I/O interfaces, etc, not done by Bootstrap - // - // if CPU is Sleep-capable, and requires some preparation to be put in that state (code provided in Bootstrap), - // the address of the idle code is writen at this location by the Bootstrap - // e.g. - // iIdleFunction=*(TLinAddr*)((TUint8*)&Kern::SuperPage()+0x1000); - // - TemplateAssp::Init1(); - }

The last line is a call into the ASSP layer, which is -implemented as shown below. On the template port, it is the ASSP layer that -initialises the interrupt dispatcher and the real time clock. The source for -this is in ...\template_assp\assp.cpp:

EXPORT_C void TemplateAssp::Init1() - { - __KTRACE_OPT(KBOOT,Kern::Printf("TemplateAssp::Init1()")); - // - // TO DO: (optional) - // - TemplateInterrupt::Init1(); // initialise the ASSP interrupt controller - - // - // TO DO: (optional) - // - // Initialises any hardware blocks which require early initialisation, e.g. enable and power the LCD, set up - // RTC clocks, disable DMA controllers. etc. - // - } - -

TemplateInterrupt::Init1(); is static -function that initialises the interrupt dispatcher. See Interrupt -Layer Initialisation.

-
Asic::Init3() -implementation

Entry -conditions

    -
  • called in the context -of the supervisor thread

  • -
  • the kernel is ready -to handle interrupts

  • -
  • the kernel heap and -memory management system is fully functional.

  • -

What -the function should do

This is called during stage 3 of kernel -initialisation.

In this function, you need to:

    -
  • enable interrupt sources

  • -
  • start the millisecond -tick timer.

  • -
  • Optionally, replace -the implementation used by Kern::NanoWait().

  • -

Any other general initialisation can also be done here.

As -an example, on the template port, the function is implemented in the Variant -layer, by Template::Init3().

Millisecond -tick timer

The kernel expects that the kernel's tick handler routine -will be called at a fixed microsecond period, the value of which is returned -by the implementation of Asic::MsTickPeriod() function. The Init3() function must be implemented to start -this. See Kernel Timers for -background information.

The template implementation is as follows:

EXPORT_C void TemplateAssp::Init3() - { - __KTRACE_OPT(KBOOT,Kern::Printf("TemplateAssp::Init3()")); - - TTemplate::Init3(); - - NTimerQ& m=*(NTimerQ*)NTimerQ::TimerAddress(); - iTimerQ=&m; - // - // TO DO: (mandatory) - // - // If Hardware Timer used for System Ticks cannot give exactly the period required store the initial rounding value - // here which is updated every time a match occurs. Note this leads to "wobbly" timers whose exact period change - // but averages exactly the required value - // e.g. - // m.iRounding=-5; - // - - TInt r=Interrupt::Bind(KIntIdOstMatchMsTimer,MsTimerTick,&m); // bind the System Tick interrupt - if (r!=KErrNone) - Kern::Fault("BindMsTick",r); - - // - // TO DO: (mandatory) - // - // Clear any pending OST interrupts and enable any OST match registers. - // If possible may reset the OST here (to start counting from a full period). Set the harwdare to produce an - // interrupt on full count - // - - r=Interrupt::Enable(KIntIdOstMatchMsTimer); // enable the System Tick interrupt - if (r!=KErrNone) - Kern::Fault("EnbMsTick",r); - - // - // TO DO: (optional) - // - // Allocate physical RAM for video buffer, as per example below. However with some hardware, the Video Buffer - // may not reside in main System memory, it may be dedicated memory. - // - // EXAMPLE ONLY - TInt vSize=VideoRamSize(); - r=Epoc::AllocPhysicalRam(2*vSize,TemplateAssp::VideoRamPhys); - if (r!=KErrNone) - Kern::Fault("AllocVRam",r); - }

Servicing -the timer interrupt

The timer interrupt service routine is required -only to call the Ntimer::TickQ() function and perform any -housekeeping necessary to ensure that the handler itself is called again after -the time reported by the MsTickPeriod() routine. Since -the handler is called frequently, it is written in assembler for the fastest -execution.

__NAKED__ void MsTimerTick(TAny* aPtr) - { - // Service 1ms tick interrupt - asm("ldr ip, [r0, #%a0]" : : "i" _FOFF(NTimerQ,iRounding)); - asm("ldr r2, __KHwBaseOst "); - asm("adds ip, ip, #2 "); - asm("ldr r3, __KOst1000HzTickMatchIncrement "); - asm("subcs ip, ip, #5 "); - asm("str ip, [r0, #%a0]" : : "i" _FOFF(NTimerQ,iRounding)); - asm("addcs r3, r3, #1 "); - asm("mov r1, #%a0" : : "i" ((TInt)(1<<KHwOstMatchMsTimer))); - asm("str r1, [r2, #0x14] "); // clear interrupt - asm("ldr r1, [r2, #%a0]" : : "i" ((TInt)KHwOstMatchMsTimer*4)); // r1=old match value - asm("add r1, r1, r3 "); // step match value on - asm("ldr ip, [r2, #0x10] "); // r3=system timer value - asm("str r1, [r2, #%a0]" : : "i" ((TInt)KHwOstMatchMsTimer*4)); - asm("cmp ip, r1 "); // compare to next match value - -#ifdef _DEBUG - asm("addpl r1, ip, #10 "); // in DEBUG if timer>match value, set match value to timer + a bit - asm("strpl r1, [r2, #%a0]" : : "i" ((TInt)KHwOstMatchMsTimer*4)); - asm("b Tick__7NTimerQ "); // call interrupt handler anyway -#else - asm("bmi Tick__7NTimerQ "); // if timer<match value, OK - call interrupt handler -#endif - - // otherwise we are late for the next tick so force a data abort exception... - asm("mvn r2, #0x10000002 "); // r2=0xeffffffd - asm("str r2, [r2] "); // die - - // Constant data embedded in code. - asm("__KOst1000HzTickMatchIncrement: "); - asm(".word %a0" : : "i" ((TInt)KOst1000HzTickMatchIncrement)); - asm("__KHwBaseOst: "); - asm(".word %a0" : : "i" ((TInt)KHwBaseOst)); - }

Note that it is a requirement that the timer period should -be an integral number of microseconds, even if the exact period is not 1000us. -It is always possible to add code to the interrupt handler to achieve this -average so that over a large number of ticks, the deviation from this average -will tend to 0, by adjusting the exact number of ticks from tick to tick. -See also Timers

NanoWait() implementation

Kern::NanoWait() is -a function that can be called if you want to wait for very short periods of -time within the kernel. You call this function and specify the number of nanoseconds. -The function is, in effect, a shell that uses default implementation code -provided by the generic platform. You can provide your own implementation -in your port, and register this with the platform. This allows the wait functionality -to be implemented in the best possible way for your platform, possibly by -using a hardware timer whose frequency is independent of the CPU frequency.

To -replace the default implementation, you need to:

    -
  • code your own function. -This has the same signature as Kern::NanoWait():

    void AsicImpl::DoNanoWait(TUint32 aInterval) -    { -    // Wait for aInterval nanoseconds -    }

    where AsicImpl is the class that is -ultimately derived from Asic.

  • -
  • register this implementation -by adding the following call into your Asic::Init3() function:

    Kern::SetNanoWaitHandler(AsicImpl::DoNanoWait);
  • -

You can see where this goes by looking at the template port at: ...\base\cedar\template\template_assp\template_assp.cpp

-
Asic::DebugOutput() implementation

It is worth -implementing this early so that it is possible to get trace output to see -what the kernel is doing. This function is passed one character at a time. -Normally this is sent to a UART, though it can be output through any convenient -communications channel.

On the template port, this is implemented -in the Variant layer, by Template::DebugOutput() in ...\template_variant\specific\variant.cpp.

-
Asic::Idle() implementation

If no power management -has been implemented, then this function is called when the system is to idle -to allow power saving. This function can just return, until power management -is implemented. Once power management has been implemented, then idling behaviour -will be handled by the power controller, i.e. the Variant's implementation -of the DPowerController class

-
Asic::MsTickPeriod() -implementation

This function is used to return the number of microseconds -per tick. To avoid timing drift, a tick frequency should be chosen that gives -a round number of microseconds per tick. The function can return zero until -the tick timer has been implemented.

On the template port, this function -is implemented in the ASSP layer, and can be found in the source file ...\template_assp\assp.cpp. -It is a simple function that just returns the value.

EXPORT_C TInt TemplateAssp::MsTickPeriod() - { - // - // TO DO: (mandatory) - // - // Return the OST tick period (System Tick) in microseconds ( 10E-06 s ). - // - return 1000; // EXAMPLE ONLY - } -

See also Timers.

-
Asic::SystemTimeInSecondsFrom2000() implementation

This -is a function that the kernel uses to get the system time. Its signature is

Tint SystemTimeInSecondsFrom2000(Tint& aTime);

An -implementation must set the aTime reference to the number -of seconds that have elapsed since the start of the year 2000. This is a positive -number; a negative number is interpreted as time before 2000.

For -the template reference board, the implementation is as follows:

EXPORT_C TInt TemplateAssp::SystemTimeInSecondsFrom2000(TInt& aTime) - { - aTime=(TInt)TTemplate::RtcData(); - __KTRACE_OPT(KHARDWARE,Kern::Printf("RTC READ: %d",aTime)); - return KErrNone; - } -

Until a real time clock is implemented, this function can -just return KErrNone.

This function calls the register -access functions in the TTemplate class. See ...\template_assp\template_assp.cpp for -implementation details.

Note that tracing output is provided when -the KHARDWARE bit in the kerneltrace flags is set for the debug build.

-
Asic::SetSystemTimeInSecondsFrom2000() implementation

This -is a function that the kernel uses to set the system time. Its signature is

Tint SetSystemTimeInSecondsFrom2000(Tint aTime);

This -sets the real time clock to the number of seconds that have elapsed since -the start of the year 2000. This is a positive number; a negative number is -interpreted as time before 2000.

For the template reference board, -the implementation is as follows:

EXPORT_C TInt TemplateAssp::SetSystemTimeInSecondsFrom2000(TInt aTime) - { - // - // TO DO: (optional) - // - // Check if the RTC is running and is stable - // - __KTRACE_OPT(KHARDWARE,Kern::Printf("Set RTC: %d",aTime)); - TTemplate::SetRtcData(aTime); - __KTRACE_OPT(KHARDWARE,Kern::Printf("RTC: %d",TTemplate::RtcData())); - return KErrNone; - } -

Note that tracing output is provided when the KHARDWARE bit -in the kerneltrace flags is set for the debug build. In this function, the -trace output shows the value passed in from the kernel and then shows the -value read back from the real time clock for verification.

-
Asic::NanoWaitCalibration() implementation

The -function Kern::NanoWait() can be called if you want to -wait for very short periods of time within the kernel. You call this function -and specify the number of nanoseconds. You can either use the default implementation -of this function, or you can provide your own.

The default implementation -provided by Symbian OS that Kern::NanoWait() uses is a busy -loop that is calibrated by calling Asic::NanoWaitCalibration(). NanoWaitCalibration() should -return the number of nanoseconds taken to execute 2 machine cycles. This is -obviously dependent on the CPU clock speed, so if variants are likely to run -at different speeds, then this should be implemented in the Variant layer.

This -approach cannot always take into account factors such as processor frequency -scaling. An alternative approach is for the Variant to supply its own implementation -to be used by Kern::NanoWait(). Note that you do not replace Kern::NanoWait() itself -as this is a shell function that results in a call to the the implementation. -See Asic::Init3() for -detail on how to replace the implementation.

On the template port, Asic::NanoWaitCalibration() is -implemented in the ASSP layer, and not in the Variant layer, and can be found -in the source file ...\template_assp\assp.cpp. It is -a simple function that just returns the value.

EXPORT_C TUint32 TemplateAssp::NanoWaitCalibration() - { - // - // TO DO: (mandatory) - // - // Return the minimum time in nano-seconds that it takes to execute the following code: - // nanowait_loop: - // subs r0, r0, r1 - // bhi nanowait_loop - // - // If accurate timings are required by the Base Port, then it should provide it's own implementation - // of NanoWait which uses a hardware counter. (See Kern::SetNanoWaitHandler) - // - - return 0; // EXAMPLE ONLY - } -
-
Asic::VariantHal() implementation

You might find -it useful to review User-Side -Hardware Abstraction Technology first.

This is the HAL handler -for the HAL group THalFunctionGroup::EHalGroupVariant.

-
Asic::MachineConfiguration() implementation

This -returns a TPtr8 descriptor representing an area containing -machine configuration information.

The address of this object is obtained -by calling Kern::MachineConfig(). However, the Variant -(either the ASSP layer or the Variant layer or both) is responsible for the -content.

In the template port, the function is implemented in the -Variant layer:

TPtr8 Template::MachineConfiguration() - { - return TPtr8((TUint8*)&Kern::MachineConfig(),sizeof(TActualMachineConfig),sizeof(TActualMachineConfig)); - } -

Here, the machine configuration information is represented -by an object of type TTemplateMachineConfig, which derives -from TMachineConfig. In effect, TMachineConfig represents -information that is common to all, while the Variant can extend this to contain -whatever information is appropriate.

Note that TActualMachineConfig is -a typedef for TTemplateMachineConfig.

-
Asic::StartupReason() implementation

If a startup -reason is available from hardware or a preserved RAM location, it should be -returned by the function. The default is to return EStartupColdReset.

On -the template port, this is implemented in the ASSP layer:

EXPORT_C TMachineStartupType TemplateAssp::StartupReason() - { - __KTRACE_OPT(KBOOT,Kern::Printf("TemplateAssp::StartupReason")); - #ifdef _DEBUG // REMOVE THIS - TUint s = Kern::SuperPage().iHwStartupReason; - __KTRACE_OPT(KBOOT,Kern::Printf("CPU page value %08x", s)); - #endif // REMOVE THIS - // - // TO DO: (mandatory) - // - // Map the startup reason read from the Super Page to one of TMachineStartupType enumerated values - // and return this - // - return EStartupCold; // EXAMPLE ONLY - } -
-
- -ASSP/Variant Architecture -Implementing -the ASSP Register -Using the -ASSP Register -ASSP Kernel -Extension Overview + + + + + +Asic +Class TutorialProvides a work through tutorial that allows you to port an Asic +implementation to the template variant. +

This tutorial describes +how to implement the Asic class. This is a pure virtual interface that is +defined and called by the Kernel, but which must be implemented by the ASSP/Variant. +The tutorial assumes that the ASSP/Variant is split into an ASSP layer and +a Variant layer.

+

For a minimal port, it isn't necessary to provide implementations for the +entire Asic class to be able to test that the kernel boots, +provided that those functions that are not fully implemented have a dummy +function so that the code will build.

+

The Asic class is defined in..\e32\include\kernel\arm\assp.h. +For reference, the definition is:

+class Asic + { +public: + // initialisation + virtual TMachineStartupType StartupReason()=0; + virtual void Init1()=0; + virtual void Init3()=0; + + // debug + virtual void DebugOutput(TUint aChar)=0; + + // power management + virtual void Idle()=0; + + // timing + virtual TInt MsTickPeriod()=0; + virtual TInt SystemTimeInSecondsFrom2000(TInt& aTime)=0; + virtual TInt SetSystemTimeInSecondsFrom2000(TInt aTime)=0; + virtual TUint32 NanoWaitCalibration()=0; + + // HAL + virtual TInt VariantHal(TInt aFunction, TAny* a1, TAny* a2)=0; + + // Machine configuration + virtual TPtr8 MachineConfiguration()=0; + }; +

Taking the template port as a concrete example, the ASSP layer implementation +of the Asic class is defined and implemented by the TemplateAssp class, +and the Variant implemention is defined and implemented by the Template class.

+
Asic::Init1() +implementation

Entry +conditions

    +
  • called in the context +of the initial (null) thread

  • +
  • interrupts are disabled

  • +
  • there is no kernel heap

  • +
  • memory management functions +are not available.

  • +

What +the function should do

This is called during stage 1 of kernel +initialisation.

In this function, you need to:

    +
  • initialise the real +time clock

  • +
  • initialise the interrupt +dispatcher before CPU interrupts are enabled.

  • +
  • set the threshold values +for cache maintenance. You can set separate values for:

      +
    • purging (invalidating) +a cache

    • +
    • cleaning a cache

    • +
    • flushing (i.e. cleaning +and invalidating) a cache.

    • +

    You use the Cache::SetThresholds() interface to +set these values.

    As an example of what the threshold values mean, +if you purge a memory region from cache, and the size of that region is greater +than the threshold value, then the entire cache is purged. If the size of +that region is less than or equal to to the threshold value, then only the +region is purged.

    The threshold values are platform specific, and +you need to choose your values based on your own performance measurements. +Symbian cannot make recommendations. If you choose not to set your own values, +Symbian platform supplies a set of default values, which are set by Cache::Init1().

    Note +that there is also a Cache::GetThresholds() interface that +you may find useful.

  • +
  • set up the RAM zones. +For details, see the RAM +Zone Tutorial.

  • +

Typically, you would also initialise any memory devices not initialised +by the bootstrap. Any other initialisation that must happen early on should +also be done here.

The kernel calls the Variant's Init1() function. +On the template port, this is the Variant layer's Init1(), +i.e. the functions Template::Init1(). The source for this +is in ...\template_variant\specific\variant.cpp.

void Template::Init1() + { + __KTRACE_OPT(KBOOT,Kern::Printf("Template::Init1()")); + + // + // TO DO: (mandatory) + // + // Configure Memory controller and Memrory Bus parameters (in addition to what was done in the Bootstrap) + // + __KTRACE_OPT(KBOOT,Kern::Printf("Memory Configuration done")); + + // + // TO DO: (optional) + // + // Inform the kernel of the RAM zone configuration via Epoc::SetRamZoneConfig(). + // For devices that wish to reduce power consumption of the RAM IC(s) the callback functions + // RamZoneCallback() and DoRamZoneCallback() will need to be implemented and passed + // to Epoc::SetRamZoneConfig() as the parameter aCallback. + // The kernel will assume that all RAM ICs are fully intialised and ready for use from boot. + // + + // + // TO DO: (optional) + // + // Initialise other critical hardware functions such as I/O interfaces, etc, not done by Bootstrap + // + // if CPU is Sleep-capable, and requires some preparation to be put in that state (code provided in Bootstrap), + // the address of the idle code is writen at this location by the Bootstrap + // e.g. + // iIdleFunction=*(TLinAddr*)((TUint8*)&Kern::SuperPage()+0x1000); + // + TemplateAssp::Init1(); + }

The last line is a call into the ASSP layer, which is +implemented as shown below. On the template port, it is the ASSP layer that +initialises the interrupt dispatcher and the real time clock. The source for +this is in ...\template_assp\assp.cpp:

EXPORT_C void TemplateAssp::Init1() + { + __KTRACE_OPT(KBOOT,Kern::Printf("TemplateAssp::Init1()")); + // + // TO DO: (optional) + // + TemplateInterrupt::Init1(); // initialise the ASSP interrupt controller + + // + // TO DO: (optional) + // + // Initialises any hardware blocks which require early initialisation, e.g. enable and power the LCD, set up + // RTC clocks, disable DMA controllers. etc. + // + } + +

TemplateInterrupt::Init1(); is static +function that initialises the interrupt dispatcher. See Interrupt +Layer Initialisation.

+
Asic::Init3() +implementation

Entry +conditions

    +
  • called in the context +of the supervisor thread

  • +
  • the kernel is ready +to handle interrupts

  • +
  • the kernel heap and +memory management system is fully functional.

  • +

What +the function should do

This is called during stage 3 of kernel +initialisation.

In this function, you need to:

    +
  • enable interrupt sources

  • +
  • start the millisecond +tick timer.

  • +
  • Optionally, replace +the implementation used by Kern::NanoWait().

  • +

Any other general initialisation can also be done here.

As +an example, on the template port, the function is implemented in the Variant +layer, by Template::Init3().

Millisecond +tick timer

The kernel expects that the kernel's tick handler routine +will be called at a fixed microsecond period, the value of which is returned +by the implementation of Asic::MsTickPeriod() function. The Init3() function must be implemented to start +this. See Kernel Timers for +background information.

The template implementation is as follows:

EXPORT_C void TemplateAssp::Init3() + { + __KTRACE_OPT(KBOOT,Kern::Printf("TemplateAssp::Init3()")); + + TTemplate::Init3(); + + NTimerQ& m=*(NTimerQ*)NTimerQ::TimerAddress(); + iTimerQ=&m; + // + // TO DO: (mandatory) + // + // If Hardware Timer used for System Ticks cannot give exactly the period required store the initial rounding value + // here which is updated every time a match occurs. Note this leads to "wobbly" timers whose exact period change + // but averages exactly the required value + // e.g. + // m.iRounding=-5; + // + + TInt r=Interrupt::Bind(KIntIdOstMatchMsTimer,MsTimerTick,&m); // bind the System Tick interrupt + if (r!=KErrNone) + Kern::Fault("BindMsTick",r); + + // + // TO DO: (mandatory) + // + // Clear any pending OST interrupts and enable any OST match registers. + // If possible may reset the OST here (to start counting from a full period). Set the harwdare to produce an + // interrupt on full count + // + + r=Interrupt::Enable(KIntIdOstMatchMsTimer); // enable the System Tick interrupt + if (r!=KErrNone) + Kern::Fault("EnbMsTick",r); + + // + // TO DO: (optional) + // + // Allocate physical RAM for video buffer, as per example below. However with some hardware, the Video Buffer + // may not reside in main System memory, it may be dedicated memory. + // + // EXAMPLE ONLY + TInt vSize=VideoRamSize(); + r=Epoc::AllocPhysicalRam(2*vSize,TemplateAssp::VideoRamPhys); + if (r!=KErrNone) + Kern::Fault("AllocVRam",r); + }

Servicing +the timer interrupt

The timer interrupt service routine is required +only to call the Ntimer::TickQ() function and perform any +housekeeping necessary to ensure that the handler itself is called again after +the time reported by the MsTickPeriod() routine. Since +the handler is called frequently, it is written in assembler for the fastest +execution.

__NAKED__ void MsTimerTick(TAny* aPtr) + { + // Service 1ms tick interrupt + asm("ldr ip, [r0, #%a0]" : : "i" _FOFF(NTimerQ,iRounding)); + asm("ldr r2, __KHwBaseOst "); + asm("adds ip, ip, #2 "); + asm("ldr r3, __KOst1000HzTickMatchIncrement "); + asm("subcs ip, ip, #5 "); + asm("str ip, [r0, #%a0]" : : "i" _FOFF(NTimerQ,iRounding)); + asm("addcs r3, r3, #1 "); + asm("mov r1, #%a0" : : "i" ((TInt)(1<<KHwOstMatchMsTimer))); + asm("str r1, [r2, #0x14] "); // clear interrupt + asm("ldr r1, [r2, #%a0]" : : "i" ((TInt)KHwOstMatchMsTimer*4)); // r1=old match value + asm("add r1, r1, r3 "); // step match value on + asm("ldr ip, [r2, #0x10] "); // r3=system timer value + asm("str r1, [r2, #%a0]" : : "i" ((TInt)KHwOstMatchMsTimer*4)); + asm("cmp ip, r1 "); // compare to next match value + +#ifdef _DEBUG + asm("addpl r1, ip, #10 "); // in DEBUG if timer>match value, set match value to timer + a bit + asm("strpl r1, [r2, #%a0]" : : "i" ((TInt)KHwOstMatchMsTimer*4)); + asm("b Tick__7NTimerQ "); // call interrupt handler anyway +#else + asm("bmi Tick__7NTimerQ "); // if timer<match value, OK - call interrupt handler +#endif + + // otherwise we are late for the next tick so force a data abort exception... + asm("mvn r2, #0x10000002 "); // r2=0xeffffffd + asm("str r2, [r2] "); // die + + // Constant data embedded in code. + asm("__KOst1000HzTickMatchIncrement: "); + asm(".word %a0" : : "i" ((TInt)KOst1000HzTickMatchIncrement)); + asm("__KHwBaseOst: "); + asm(".word %a0" : : "i" ((TInt)KHwBaseOst)); + }

Note that it is a requirement that the timer period should +be an integral number of microseconds, even if the exact period is not 1000us. +It is always possible to add code to the interrupt handler to achieve this +average so that over a large number of ticks, the deviation from this average +will tend to 0, by adjusting the exact number of ticks from tick to tick. +See also Timers

NanoWait() implementation

Kern::NanoWait() is +a function that can be called if you want to wait for very short periods of +time within the kernel. You call this function and specify the number of nanoseconds. +The function is, in effect, a shell that uses default implementation code +provided by the generic platform. You can provide your own implementation +in your port, and register this with the platform. This allows the wait functionality +to be implemented in the best possible way for your platform, possibly by +using a hardware timer whose frequency is independent of the CPU frequency.

To +replace the default implementation, you need to:

    +
  • code your own function. +This has the same signature as Kern::NanoWait():

    void AsicImpl::DoNanoWait(TUint32 aInterval) +    { +    // Wait for aInterval nanoseconds +    }

    where AsicImpl is the +class that is ultimately derived from Asic.

  • +
  • register this implementation +by adding the following call into your Asic::Init3() function:

    Kern::SetNanoWaitHandler(AsicImpl::DoNanoWait);
  • +

You can see where this goes by looking at the template port at: ...\base\cedar\template\template_assp\template_assp.cpp

+
Asic::DebugOutput() +implementation

It is worth implementing this early so that it is +possible to get trace output to see what the kernel is doing. This function +is passed one character at a time. Normally this is sent to a UART, though +it can be output through any convenient communications channel.

On +the template port, this is implemented in the Variant layer, by Template::DebugOutput() in ...\template_variant\specific\variant.cpp.

+
Asic::Idle() +implementation

If no power management has been implemented, then +this function is called when the system is to idle to allow power saving. +This function can just return, until power management is implemented. Once +power management has been implemented, then idling behaviour will be handled +by the power controller, i.e. the Variant's implementation of the DPowerController class

+
Asic::MsTickPeriod() +implementation

This function is used to return the number of microseconds +per tick. To avoid timing drift, a tick frequency should be chosen that gives +a round number of microseconds per tick. The function can return zero until +the tick timer has been implemented.

On the template port, this function +is implemented in the ASSP layer, and can be found in the source file ...\template_assp\assp.cpp. +It is a simple function that just returns the value.

EXPORT_C TInt TemplateAssp::MsTickPeriod() + { + // + // TO DO: (mandatory) + // + // Return the OST tick period (System Tick) in microseconds ( 10E-06 s ). + // + return 1000; // EXAMPLE ONLY + } +

See also Timers.

+
Asic::SystemTimeInSecondsFrom2000() + implementation

This is a function that the kernel uses +to get the system time. Its signature is

Tint SystemTimeInSecondsFrom2000(Tint& aTime);

An implementation must set the aTime reference to the +number of seconds that have elapsed since the start of the year 2000. This +is a positive number; a negative number is interpreted as time before 2000.

For +the template reference board, the implementation is as follows:

EXPORT_C TInt TemplateAssp::SystemTimeInSecondsFrom2000(TInt& aTime) + { + aTime=(TInt)TTemplate::RtcData(); + __KTRACE_OPT(KHARDWARE,Kern::Printf("RTC READ: %d",aTime)); + return KErrNone; + } +

Until a real time clock is implemented, this function can +just return KErrNone.

This function calls the register +access functions in the TTemplate class. See ...\template_assp\template_assp.cpp for +implementation details.

Note that tracing output is provided when +the KHARDWARE bit in the kerneltrace flags is set for the debug build.

+
Asic::SetSystemTimeInSecondsFrom2000() +implementation

This is a function that the kernel uses to set the +system time. Its signature is

Tint SetSystemTimeInSecondsFrom2000(Tint aTime);

This sets the real time clock to the number of seconds that have elapsed +since the start of the year 2000. This is a positive number; a negative number +is interpreted as time before 2000.

For the template reference board, +the implementation is as follows:

EXPORT_C TInt TemplateAssp::SetSystemTimeInSecondsFrom2000(TInt aTime) + { + // + // TO DO: (optional) + // + // Check if the RTC is running and is stable + // + __KTRACE_OPT(KHARDWARE,Kern::Printf("Set RTC: %d",aTime)); + TTemplate::SetRtcData(aTime); + __KTRACE_OPT(KHARDWARE,Kern::Printf("RTC: %d",TTemplate::RtcData())); + return KErrNone; + } +

Note that tracing output is provided when the KHARDWARE bit +in the kerneltrace flags is set for the debug build. In this function, the +trace output shows the value passed in from the kernel and then shows the +value read back from the real time clock for verification.

+
Asic::NanoWaitCalibration() + implementation

The function Kern::NanoWait() can +be called if you want to wait for very short periods of time within the kernel. +You call this function and specify the number of nanoseconds. You can either +use the default implementation of this function, or you can provide your own.

The +default implementation provided by Symbian platform that Kern::NanoWait() uses +is a busy loop that is calibrated by calling Asic::NanoWaitCalibration(). NanoWaitCalibration() should +return the number of nanoseconds taken to execute 2 machine cycles. This is +obviously dependent on the CPU clock speed, so if variants are likely to run +at different speeds, then this should be implemented in the Variant layer.

This +approach cannot always take into account factors such as processor frequency +scaling. An alternative approach is for the Variant to supply its own implementation +to be used by Kern::NanoWait(). Note that you do not replace Kern::NanoWait() itself +as this is a shell function that results in a call to the the implementation. +See Asic::Init3() for +detail on how to replace the implementation.

On the template port, Asic::NanoWaitCalibration() is +implemented in the ASSP layer, and not in the Variant layer, and can be found +in the source file ...\template_assp\assp.cpp. It is +a simple function that just returns the value.

EXPORT_C TUint32 TemplateAssp::NanoWaitCalibration() + { + // + // TO DO: (mandatory) + // + // Return the minimum time in nano-seconds that it takes to execute the following code: + // nanowait_loop: + // subs r0, r0, r1 + // bhi nanowait_loop + // + // If accurate timings are required by the Base Port, then it should provide it's own implementation + // of NanoWait which uses a hardware counter. (See Kern::SetNanoWaitHandler) + // + + return 0; // EXAMPLE ONLY + } +
+
Asic::VariantHal() +implementation

You might find it useful to review User-Side +Hardware Abstraction Technology first.

This is the HAL handler +for the HAL group THalFunctionGroup::EHalGroupVariant.

+
Asic::MachineConfiguration() + implementation

This returns a TPtr8 descriptor +representing an area containing machine configuration information.

The +address of this object is obtained by calling Kern::MachineConfig(). +However, the Variant (either the ASSP layer or the Variant layer or both) +is responsible for the content.

In the template port, the function +is implemented in the Variant layer:

TPtr8 Template::MachineConfiguration() + { + return TPtr8((TUint8*)&Kern::MachineConfig(),sizeof(TActualMachineConfig),sizeof(TActualMachineConfig)); + } +

Here, the machine configuration information is represented +by an object of type TTemplateMachineConfig, which derives +from TMachineConfig. In effect, TMachineConfig represents +information that is common to all, while the Variant can extend this to contain +whatever information is appropriate.

Note that TActualMachineConfig is +a typedef for TTemplateMachineConfig.

+
Asic::StartupReason() +implementation

If a startup reason is available from hardware or +a preserved RAM location, it should be returned by the function. The default +is to return EStartupColdReset.

On the template port, +this is implemented in the ASSP layer:

EXPORT_C TMachineStartupType TemplateAssp::StartupReason() + { + __KTRACE_OPT(KBOOT,Kern::Printf("TemplateAssp::StartupReason")); + #ifdef _DEBUG // REMOVE THIS + TUint s = Kern::SuperPage().iHwStartupReason; + __KTRACE_OPT(KBOOT,Kern::Printf("CPU page value %08x", s)); + #endif // REMOVE THIS + // + // TO DO: (mandatory) + // + // Map the startup reason read from the Super Page to one of TMachineStartupType enumerated values + // and return this + // + return EStartupCold; // EXAMPLE ONLY + } +
+
+ +ASSP/Variant Architecture +Implementing +the ASSP Register +Using the +ASSP Register +ASSP Kernel +Extension Overview
\ No newline at end of file