Symbian3/PDK/Source/GUID-E0DCBDCF-C056-53E5-A375-778327F848E4.dita
author Dominic Pinkman <Dominic.Pinkman@Nokia.com>
Tue, 30 Mar 2010 11:56:28 +0100
changeset 5 f345bda72bc4
parent 3 46218c8b8afa
child 14 578be2adaf3e
permissions -rw-r--r--
Week 12 contribution of PDK documentation_content. See release notes for details. Fixes Bug 2054, Bug 1583, Bug 381, Bug 390, Bug 463, Bug 1897, Bug 344, Bug 1319, Bug 394, Bug 1520, Bug 1522, Bug 1892"

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
<!-- This component and the accompanying materials are made available under the terms of the License 
"Eclipse Public License v1.0" which accompanies this distribution, 
and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
<!-- Initial Contributors:
    Nokia Corporation - initial contribution.
Contributors: 
-->
<!DOCTYPE concept
  PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
<concept id="GUID-E0DCBDCF-C056-53E5-A375-778327F848E4" xml:lang="en"><title>Asic
Class Tutorial</title><shortdesc>Provides a work through tutorial that allows you to port an Asic
implementation to the template variant. </shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody>
<p id="GUID-39010DA3-632A-5C27-92BF-9AA8B5966EAB">  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. </p>
<p>For a minimal port, it isn't necessary to provide implementations for the
entire <xref href="GUID-A83A7C3C-7DC0-3B9C-842F-70FCC751365D.dita"><apiname>Asic</apiname></xref> 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. </p>
<p>The <codeph>Asic</codeph> class is defined in<filepath>..\e32\include\kernel\arm\assp.h</filepath>.
For reference, the definition is: </p>
<codeblock id="GUID-B33CCD29-C6D2-5DC9-9302-A265E248E8DF" xml:space="preserve">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&amp; 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;
    };</codeblock>
<p>Taking the template port as a concrete example, the ASSP layer implementation
of the <xref href="GUID-A83A7C3C-7DC0-3B9C-842F-70FCC751365D.dita"><apiname>Asic</apiname></xref> class is defined and implemented by the <codeph>TemplateAssp</codeph> class,
and the Variant implemention is defined and implemented by the <codeph>Template</codeph> class. </p>
<section id="GUID-7F5D4AD6-0881-5942-9A86-A95C02125A28"><title>Asic::Init1()
implementation</title> <p><b>Entry
conditions</b> </p> <ul>
<li id="GUID-6B761E80-7B63-5F96-9852-65F7321D365B"><p>called in the context
of the initial (null) thread </p> </li>
<li id="GUID-B8211B76-1308-5372-8034-4B1B9CFE58F3"><p>interrupts are disabled </p> </li>
<li id="GUID-482B5E00-A25F-5966-90FB-B622F9C1AF99"><p>there is no kernel heap </p> </li>
<li id="GUID-6D985E4B-1A69-58B6-975D-7F696BB062C3"><p>memory management functions
are not available. </p> </li>
</ul> <p><b>What
the function should do</b> </p> <p>This is called during stage 1 of kernel
initialisation. </p> <p>In this function, you need to: </p> <ul>
<li id="GUID-D156866C-0BA0-58AE-9438-C4D1D2628D67"><p>initialise the real
time clock </p> </li>
<li id="GUID-7FB60E9E-938C-515E-803D-27DA1315040C"><p>initialise the interrupt
dispatcher before CPU interrupts are enabled. </p> </li>
<li id="GUID-D55DD2D9-3E45-5256-B1F4-E583706AED66"><p>set the threshold values
for cache maintenance. You can set separate values for: </p> <ul>
<li id="GUID-B3CEB2A4-4849-517F-A0E9-76A6018537B8"><p>purging (invalidating)
a cache </p> </li>
<li id="GUID-9DE85DFB-D789-565C-A944-EFBF987D457C"><p>cleaning a cache </p> </li>
<li id="GUID-0C638F72-1D6B-512D-88EB-7369240C776A"><p>flushing (i.e. cleaning
and invalidating) a cache. </p> </li>
</ul> <p>You use the <xref href="GUID-4425E698-EE8A-369B-92CD-09B1CBD2911F.dita#GUID-4425E698-EE8A-369B-92CD-09B1CBD2911F/GUID-81AA7412-9754-3020-9D77-14DEDD3196CA"><apiname>Cache::SetThresholds()</apiname></xref> interface to
set these values. </p> <p>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. </p> <p>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 <codeph>Cache::Init1()</codeph>. </p> <p>Note
that there is also a <xref href="GUID-4425E698-EE8A-369B-92CD-09B1CBD2911F.dita#GUID-4425E698-EE8A-369B-92CD-09B1CBD2911F/GUID-2DBD79A7-2061-3B89-89FA-B0DFC7AFFCF9"><apiname>Cache::GetThresholds()</apiname></xref> interface that
you may find useful. </p> </li>
<li id="GUID-DA94E963-6AA5-5084-8C19-77B7AD484A44"><p>set up the RAM zones.
For details, see the <xref href="GUID-C376486D-B9BF-5D00-8B1A-1527FC1F83AD.dita">RAM
Zone Tutorial</xref>. </p> </li>
</ul> <p>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. </p> <p>The kernel calls the Variant's <codeph>Init1()</codeph> function.
On the template port, this is the Variant layer's <codeph>Init1()</codeph>,
i.e. the functions <codeph>Template::Init1()</codeph>. The source for this
is in <filepath>...\template_variant\specific\variant.cpp</filepath>. </p> <codeblock id="GUID-E1247A9A-B7F7-5C0F-BD3B-A0E471FA4654" xml:space="preserve">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*)&amp;Kern::SuperPage()+0x1000);
     //
     TemplateAssp::Init1();
     }</codeblock> <p>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 <filepath>...\template_assp\assp.cpp</filepath>: </p> <codeblock id="GUID-1E90071E-6CB0-5B01-984C-AFCFD095CA64" xml:space="preserve">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.
     //
    }

   </codeblock> <p> <codeph>TemplateInterrupt::Init1();</codeph> is static
function that initialises the interrupt dispatcher. See <xref href="GUID-423537D5-2C8A-5C26-8D7B-60446E95F681.dita">Interrupt
Layer Initialisation</xref>. </p> </section>
<section id="GUID-F5275882-BBD0-561F-B617-683AA2004BB9"><title>Asic::Init3()
implementation</title> <p><b>Entry
conditions</b> </p> <ul>
<li id="GUID-9450694C-ADF3-52DE-AA58-4AFF53A1EEC6"><p>called in the context
of the supervisor thread </p> </li>
<li id="GUID-335F8A2E-0223-598E-AA23-F72E3BE84D76"><p>the kernel is ready
to handle interrupts </p> </li>
<li id="GUID-B198D669-9E88-5279-81A8-6A11F8EE3BFD"><p>the kernel heap and
memory management system is fully functional. </p> </li>
</ul> <p><b>What
the function should do</b> </p> <p>This is called during stage 3 of kernel
initialisation. </p> <p>In this function, you need to: </p> <ul>
<li id="GUID-38C35732-E79A-595C-9852-12D1FE30A081"><p>enable interrupt sources </p> </li>
<li id="GUID-D4F750D9-96B1-5AD1-AA66-2485D37B6323"><p>start the millisecond
tick timer. </p> </li>
<li id="GUID-390278B7-EF0F-59ED-A57D-54490655C97B"><p>Optionally, replace
the implementation used by <codeph>Kern::NanoWait()</codeph>. </p> </li>
</ul> <p>Any other general initialisation can also be done here. </p> <p>As
an example, on the template port, the function is implemented in the Variant
layer, by <codeph>Template::Init3()</codeph>. </p> <p><b>Millisecond
tick timer</b> </p> <p>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 <xref href="GUID-E0DCBDCF-C056-53E5-A375-778327F848E4.dita#GUID-E0DCBDCF-C056-53E5-A375-778327F848E4/GUID-917B420D-5F10-5190-97D2-9D2DAFD4FB76">Asic::MsTickPeriod()</xref> function. The <codeph>Init3()</codeph> function must be implemented to start
this. See <xref href="GUID-F84E18B8-5883-5A3A-A9DB-EC25BB86149F.dita">Kernel Timers</xref> for
background information. </p> <p>The template implementation is as follows: </p> <codeblock id="GUID-AF60AC52-5188-5911-9A03-A090D048ADA3" xml:space="preserve">EXPORT_C void TemplateAssp::Init3()
    {
    __KTRACE_OPT(KBOOT,Kern::Printf("TemplateAssp::Init3()"));

    TTemplate::Init3();

    NTimerQ&amp; m=*(NTimerQ*)NTimerQ::TimerAddress();
    iTimerQ=&amp;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,&amp;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);
    }</codeblock> <p><b>Servicing
the timer interrupt</b> </p> <p>The timer interrupt service routine is required
only to call the <xref href="GUID-DFEAC0DA-E384-3249-BF6A-529A76C3AC34.dita#GUID-DFEAC0DA-E384-3249-BF6A-529A76C3AC34/GUID-DA340CB0-C334-3C17-B903-14B135ABDCF1"><apiname>Ntimer::TickQ()</apiname></xref> function and perform any
housekeeping necessary to ensure that the handler itself is called again after
the time reported by the <xref href="GUID-BCFC62D6-B87A-3319-8DA7-4BA64A9D0311.dita"><apiname>MsTickPeriod()</apiname></xref> routine. Since
the handler is called frequently, it is written in assembler for the fastest
execution. </p> <codeblock id="GUID-0770E505-10F8-582C-BCAA-BC99074FD906" xml:space="preserve">__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&lt;&lt;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&gt;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&lt;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));
    }</codeblock> <p>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 <xref href="GUID-F84E18B8-5883-5A3A-A9DB-EC25BB86149F.dita">Timers</xref></p> <p><b>NanoWait() implementation</b> </p> <p> <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-0EEAFE45-5C0D-32A9-AD64-CE3AB0AEE6B3"><apiname>Kern::NanoWait()</apiname></xref> 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. </p> <p>To
replace the default implementation, you need to: </p> <ul>
<li id="GUID-733329E1-99C5-56A4-B80F-FFCFD74F1320"><p>code your own function.
This has the same signature as <codeph>Kern::NanoWait()</codeph>: </p> <codeblock id="GUID-0AC0DC75-38C7-58A8-8A4F-4C5AA8F23A80" xml:space="preserve">void AsicImpl::DoNanoWait(TUint32 aInterval)
    {
    // Wait for aInterval nanoseconds
    }</codeblock> <p>where <codeph>AsicImpl</codeph> is the
class that is ultimately derived from <codeph>Asic</codeph>. </p> </li>
<li id="GUID-BDE8C5D6-6E6C-5B2E-9219-A8D5DC114EA2"><p>register this implementation
by adding the following call into your <codeph>Asic::Init3()</codeph> function: </p> <codeblock id="GUID-1A99C7D2-A550-5B39-9AE7-559AE7B13C3E" xml:space="preserve">Kern::SetNanoWaitHandler(AsicImpl::DoNanoWait);</codeblock> </li>
</ul> <p>You can see where this goes by looking at the template port at: <filepath>...\base\cedar\template\template_assp\template_assp.cpp</filepath>  </p> </section>
<section id="GUID-1028F2D0-BA8B-4880-9565-50C89EBD1685"><title>Asic::DebugOutput()
implementation</title> <p>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. </p> <p>On
the template port, this is implemented in the Variant layer, by <codeph>Template::DebugOutput()</codeph> in <filepath>...\template_variant\specific\variant.cpp</filepath>. </p> </section>
<section id="GUID-EEC48040-B7D7-406B-8138-4A1F646ED990"><title>Asic::Idle()
implementation</title> <p>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 <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita"><apiname>DPowerController</apiname></xref> class </p> </section>
<section id="GUID-917B420D-5F10-5190-97D2-9D2DAFD4FB76"><title>Asic::MsTickPeriod()
implementation</title> <p>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. </p> <p>On the template port, this function
is implemented in the ASSP layer, and can be found in the source file <filepath>...\template_assp\assp.cpp</filepath>.
It is a simple function that just returns the value. </p> <codeblock id="GUID-C0D88A32-974C-5824-8D9D-A9B6D7C45802" xml:space="preserve">EXPORT_C TInt TemplateAssp::MsTickPeriod()
    {
     // 
     // TO DO: (mandatory)
     //
     // Return the OST tick period (System Tick) in microseconds ( 10E-06 s ).
     //
     return 1000;   // EXAMPLE ONLY
    }
</codeblock> <p>See also <xref href="GUID-F84E18B8-5883-5A3A-A9DB-EC25BB86149F.dita">Timers</xref>. </p> </section>
<section id="GUID-1C8A7F79-8CD5-442E-A9A5-925C94E80773"><title>Asic::SystemTimeInSecondsFrom2000()
          implementation</title> <p>This is a function that the kernel uses
to get the system time. Its signature is </p> <codeblock id="GUID-A1FF9777-D627-5409-B6CD-02F20F7A1889" xml:space="preserve">Tint SystemTimeInSecondsFrom2000(Tint&amp; aTime);</codeblock> <p>An implementation must set the <codeph>aTime</codeph> 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. </p> <p>For
the template reference board, the implementation is as follows: </p> <codeblock id="GUID-C4812A82-C069-564B-972A-0922EAC00AAB" xml:space="preserve">EXPORT_C TInt TemplateAssp::SystemTimeInSecondsFrom2000(TInt&amp; aTime)
     {
      aTime=(TInt)TTemplate::RtcData();
      __KTRACE_OPT(KHARDWARE,Kern::Printf("RTC READ: %d",aTime));
      return KErrNone;
     }
</codeblock> <p>Until a real time clock is implemented, this function can
just return <xref href="GUID-6CA4F1ED-7947-3087-B618-D35858FAA3BC.dita"><apiname>KErrNone</apiname></xref>. </p> <p>This function calls the register
access functions in the <codeph>TTemplate</codeph> class. See <filepath>...\template_assp\template_assp.cpp</filepath> for
implementation details. </p> <p>Note that tracing output is provided when
the KHARDWARE bit in the kerneltrace flags is set for the debug build. </p> </section>
<section id="GUID-F0AC3E98-345F-4491-9957-51B127437181"><title>Asic::SetSystemTimeInSecondsFrom2000()
implementation</title> <p>This is a function that the kernel uses to set the
system time. Its signature is </p> <codeblock id="GUID-B965C38C-A65E-5E54-BE09-C81300B59EDC" xml:space="preserve">Tint SetSystemTimeInSecondsFrom2000(Tint aTime);</codeblock> <p>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. </p> <p>For the template reference board,
the implementation is as follows: </p> <codeblock id="GUID-89BFC844-B053-51B7-9ACA-81B19E63414B" xml:space="preserve">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;
    }
</codeblock> <p>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. </p> </section>
<section id="GUID-50BB6924-899F-4385-879E-19A2FC68657C"><title>Asic::NanoWaitCalibration()
 implementation</title> <p>The function <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-0EEAFE45-5C0D-32A9-AD64-CE3AB0AEE6B3"><apiname>Kern::NanoWait()</apiname></xref> 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. </p> <p>The
default implementation provided by Symbian platform that <codeph>Kern::NanoWait()</codeph> uses
is a busy loop that is calibrated by calling <codeph>Asic::NanoWaitCalibration()</codeph>. <codeph>NanoWaitCalibration()</codeph> 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. </p> <p>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 <codeph>Kern::NanoWait()</codeph>. Note that you do not replace <codeph>Kern::NanoWait()</codeph> itself
as this is a shell function that results in a call to the the implementation.
See <xref href="GUID-E0DCBDCF-C056-53E5-A375-778327F848E4.dita#GUID-E0DCBDCF-C056-53E5-A375-778327F848E4/GUID-F5275882-BBD0-561F-B617-683AA2004BB9">Asic::Init3()</xref> for
detail on how to replace the implementation. </p> <p>On the template port, <codeph>Asic::NanoWaitCalibration()</codeph> is
implemented in the ASSP layer, and not in the Variant layer, and can be found
in the source file <filepath>...\template_assp\assp.cpp</filepath>. It is
a simple function that just returns the value. </p> <codeblock id="GUID-68298BF1-EAE7-507D-9B5B-DDACE6C19799" xml:space="preserve">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
    }
</codeblock> </section>
<section id="GUID-15F344C5-A1CC-45FC-AC94-27022A1DF448"><title>Asic::VariantHal()
implementation</title> <p>You might find it useful to review <xref href="GUID-9AE254D4-AA60-579E-8D9D-F2797106A413.dita">User-Side
Hardware Abstraction Technology</xref> first. </p> <p>This is the HAL handler
for the HAL group <xref href="GUID-66A851A0-2A0C-3624-AEC1-22F6629FABF7.dita#GUID-66A851A0-2A0C-3624-AEC1-22F6629FABF7/GUID-3FA061DE-68F8-3948-96B3-5AFC989DBDE1"><apiname>THalFunctionGroup::EHalGroupVariant</apiname></xref>. </p> </section>
<section id="GUID-2EEA143D-612C-47C5-B16C-22DAD1BC179E"><title>Asic::MachineConfiguration()
          implementation</title> <p>This returns a <xref href="GUID-C0D29B11-1535-3D11-B318-B18D30A6120B.dita"><apiname>TPtr8</apiname></xref> descriptor
representing an area containing machine configuration information. </p> <p>The
address of this object is obtained by calling <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-4DAE5199-1EB0-31D1-BA06-8F47E96EEADE"><apiname>Kern::MachineConfig()</apiname></xref>.
However, the Variant (either the ASSP layer or the Variant layer or both)
is responsible for the content. </p> <p>In the template port, the function
is implemented in the Variant layer: </p> <codeblock id="GUID-B75F631E-03DB-5C98-911F-1161842AA17F" xml:space="preserve">TPtr8 Template::MachineConfiguration()
    {
     return TPtr8((TUint8*)&amp;Kern::MachineConfig(),sizeof(TActualMachineConfig),sizeof(TActualMachineConfig));
    }
</codeblock> <p>Here, the machine configuration information is represented
by an object of type <codeph>TTemplateMachineConfig</codeph>, which derives
from <codeph>TMachineConfig</codeph>. In effect, <codeph>TMachineConfig</codeph> represents
information that is common to all, while the Variant can extend this to contain
whatever information is appropriate. </p> <p>Note that <codeph>TActualMachineConfig</codeph> is
a typedef for <codeph>TTemplateMachineConfig</codeph>. </p> </section>
<section id="GUID-B1E39D8C-1562-4464-A316-144ED89935C9"><title>Asic::StartupReason()
implementation</title> <p>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 <codeph>EStartupColdReset</codeph>. </p> <p>On the template port,
this is implemented in the ASSP layer: </p> <codeblock id="GUID-FC4FFA46-804D-5A7F-B7CA-DDDC72C60041" xml:space="preserve">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
    }
</codeblock> </section>
</conbody><related-links>
<link href="GUID-984C2A0D-36BE-5A99-9D65-3F8791C669FF.dita#GUID-984C2A0D-36BE-5A99-9D65-3F8791C669FF/GUID-95C34114-F986-5428-9D40-5CF64429CDBD">
<linktext>ASSP/Variant Architecture</linktext></link>
<link href="GUID-B498EDA0-677E-5521-9E4F-24D7C2048F2E.dita"><linktext>Implementing
the ASSP                 Register</linktext></link>
<link href="GUID-5194A7B6-471B-5BCF-8569-16A3BA59000A.dita"><linktext>Using the
ASSP Register</linktext></link>
<link href="GUID-77DF7A6B-F01D-5B9F-9C7A-662A04ED8BE7.dita"><linktext>ASSP Kernel
Extension                 Overview</linktext></link>
</related-links></concept>