Symbian3/PDK/Source/GUID-E0DCBDCF-C056-53E5-A375-778327F848E4.dita
author Dominic Pinkman <Dominic.Pinkman@Nokia.com>
Thu, 11 Mar 2010 18:02:22 +0000
changeset 3 46218c8b8afa
parent 1 25a17d01db0c
child 5 f345bda72bc4
permissions -rw-r--r--
week 10 bug fix submission (SF PDK version): Bug 1892, Bug 1897, Bug 1319. Also 3 or 4 documents were found to contain code blocks with SFL, which has been fixed. Partial fix for broken links, links to Forum Nokia, and the 'Symbian platform' terminology issues.

<?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 OS 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 OS 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>