|
1 <?xml version="1.0" encoding="utf-8"?> |
|
2 <!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. --> |
|
3 <!-- This component and the accompanying materials are made available under the terms of the License |
|
4 "Eclipse Public License v1.0" which accompanies this distribution, |
|
5 and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". --> |
|
6 <!-- Initial Contributors: |
|
7 Nokia Corporation - initial contribution. |
|
8 Contributors: |
|
9 --> |
|
10 <!DOCTYPE concept |
|
11 PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd"> |
|
12 <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 |
|
13 an Asic implementation to the template variant. </shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody> |
|
14 <p id="GUID-39010DA3-632A-5C27-92BF-9AA8B5966EAB"> This tutorial |
|
15 describes how to implement the Asic class. This is a pure virtual |
|
16 interface that is defined and called by the Kernel, but which must |
|
17 be implemented by the ASSP/Variant. The tutorial assumes that the |
|
18 ASSP/Variant is split into an ASSP layer and a Variant layer. </p> |
|
19 <p>For a minimal port, it isn't necessary to provide implementations |
|
20 for the entire <xref href="GUID-A83A7C3C-7DC0-3B9C-842F-70FCC751365D.dita"><apiname>Asic</apiname></xref> class to be able to test that |
|
21 the kernel boots, provided that those functions that are not fully |
|
22 implemented have a dummy function so that the code will build. </p> |
|
23 <p>The <codeph>Asic</codeph> class is defined in<filepath>..\e32\include\kernel\arm\assp.h</filepath>. For reference, the definition is: </p> |
|
24 <codeblock id="GUID-B33CCD29-C6D2-5DC9-9302-A265E248E8DF" xml:space="preserve">class Asic |
|
25 { |
|
26 public: |
|
27 // initialisation |
|
28 virtual TMachineStartupType StartupReason()=0; |
|
29 virtual void Init1()=0; |
|
30 virtual void Init3()=0; |
|
31 |
|
32 // debug |
|
33 virtual void DebugOutput(TUint aChar)=0; |
|
34 |
|
35 // power management |
|
36 virtual void Idle()=0; |
|
37 |
|
38 // timing |
|
39 virtual TInt MsTickPeriod()=0; |
|
40 virtual TInt SystemTimeInSecondsFrom2000(TInt& aTime)=0; |
|
41 virtual TInt SetSystemTimeInSecondsFrom2000(TInt aTime)=0; |
|
42 virtual TUint32 NanoWaitCalibration()=0; |
|
43 |
|
44 // HAL |
|
45 virtual TInt VariantHal(TInt aFunction, TAny* a1, TAny* a2)=0; |
|
46 |
|
47 // Machine configuration |
|
48 virtual TPtr8 MachineConfiguration()=0; |
|
49 };</codeblock> |
|
50 <p>Taking the template port as a concrete example, the ASSP layer |
|
51 implementation of the <xref href="GUID-A83A7C3C-7DC0-3B9C-842F-70FCC751365D.dita"><apiname>Asic</apiname></xref> class is defined and |
|
52 implemented by the <codeph>TemplateAssp</codeph> class, and the Variant |
|
53 implemention is defined and implemented by the <codeph>Template</codeph> class. </p> |
|
54 <section id="GUID-7F5D4AD6-0881-5942-9A86-A95C02125A28"><title>Asic::Init1() |
|
55 implementation</title> <p><b>Entry conditions</b> </p> <ul> |
|
56 <li id="GUID-6B761E80-7B63-5F96-9852-65F7321D365B"><p>called in the |
|
57 context of the initial (null) thread </p> </li> |
|
58 <li id="GUID-B8211B76-1308-5372-8034-4B1B9CFE58F3"><p>interrupts are |
|
59 disabled </p> </li> |
|
60 <li id="GUID-482B5E00-A25F-5966-90FB-B622F9C1AF99"><p>there is no |
|
61 kernel heap </p> </li> |
|
62 <li id="GUID-6D985E4B-1A69-58B6-975D-7F696BB062C3"><p>memory management |
|
63 functions are not available. </p> </li> |
|
64 </ul> <p><b>What the function should do</b> </p> <p>This is called during |
|
65 stage 1 of kernel initialisation. </p> <p>In this function, you need |
|
66 to: </p> <ul> |
|
67 <li id="GUID-D156866C-0BA0-58AE-9438-C4D1D2628D67"><p>initialise the |
|
68 real time clock </p> </li> |
|
69 <li id="GUID-7FB60E9E-938C-515E-803D-27DA1315040C"><p>initialise the |
|
70 interrupt dispatcher before CPU interrupts are enabled. </p> </li> |
|
71 <li id="GUID-D55DD2D9-3E45-5256-B1F4-E583706AED66"><p>set the threshold |
|
72 values for cache maintenance. You can set separate values for: </p> <ul> |
|
73 <li id="GUID-B3CEB2A4-4849-517F-A0E9-76A6018537B8"><p>purging (invalidating) |
|
74 a cache </p> </li> |
|
75 <li id="GUID-9DE85DFB-D789-565C-A944-EFBF987D457C"><p>cleaning a cache </p> </li> |
|
76 <li id="GUID-0C638F72-1D6B-512D-88EB-7369240C776A"><p>flushing (i.e. |
|
77 cleaning and invalidating) a cache. </p> </li> |
|
78 </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 |
|
79 to set these values. </p> <p>As an example of what the threshold values |
|
80 mean, if you purge a memory region from cache, and the size of that |
|
81 region is greater than the threshold value, then the entire cache |
|
82 is purged. If the size of that region is less than or equal to to |
|
83 the threshold value, then only the region is purged. </p> <p>The threshold |
|
84 values are platform specific, and you need to choose your values based |
|
85 on your own performance measurements. Symbian cannot make recommendations. |
|
86 If you choose not to set your own values, Symbian platform supplies |
|
87 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> |
|
88 <li id="GUID-DA94E963-6AA5-5084-8C19-77B7AD484A44"><p>set up the RAM |
|
89 zones. For details, see the <xref href="GUID-C376486D-B9BF-5D00-8B1A-1527FC1F83AD.dita">RAM Zone Tutorial</xref>. </p> </li> |
|
90 </ul> <p>Typically, you would also initialise any memory devices not |
|
91 initialised by the bootstrap. Any other initialisation that must happen |
|
92 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 |
|
93 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() |
|
94 { |
|
95 __KTRACE_OPT(KBOOT,Kern::Printf("Template::Init1()")); |
|
96 |
|
97 // |
|
98 // TO DO: (mandatory) |
|
99 // |
|
100 // Configure Memory controller and Memrory Bus parameters (in addition to what was done in the Bootstrap) |
|
101 // |
|
102 __KTRACE_OPT(KBOOT,Kern::Printf("Memory Configuration done")); |
|
103 |
|
104 // |
|
105 // TO DO: (optional) |
|
106 // |
|
107 // Inform the kernel of the RAM zone configuration via Epoc::SetRamZoneConfig(). |
|
108 // For devices that wish to reduce power consumption of the RAM IC(s) the callback functions |
|
109 // RamZoneCallback() and DoRamZoneCallback() will need to be implemented and passed |
|
110 // to Epoc::SetRamZoneConfig() as the parameter aCallback. |
|
111 // The kernel will assume that all RAM ICs are fully intialised and ready for use from boot. |
|
112 // |
|
113 |
|
114 // |
|
115 // TO DO: (optional) |
|
116 // |
|
117 // Initialise other critical hardware functions such as I/O interfaces, etc, not done by Bootstrap |
|
118 // |
|
119 // if CPU is Sleep-capable, and requires some preparation to be put in that state (code provided in Bootstrap), |
|
120 // the address of the idle code is writen at this location by the Bootstrap |
|
121 // e.g. |
|
122 // iIdleFunction=*(TLinAddr*)((TUint8*)&Kern::SuperPage()+0x1000); |
|
123 // |
|
124 TemplateAssp::Init1(); |
|
125 }</codeblock> <p>The last line is a call into the ASSP layer, |
|
126 which is implemented as shown below. On the template port, it is the |
|
127 ASSP layer that initialises the interrupt dispatcher and the real |
|
128 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() |
|
129 { |
|
130 __KTRACE_OPT(KBOOT,Kern::Printf("TemplateAssp::Init1()")); |
|
131 // |
|
132 // TO DO: (optional) |
|
133 // |
|
134 TemplateInterrupt::Init1(); // initialise the ASSP interrupt controller |
|
135 |
|
136 // |
|
137 // TO DO: (optional) |
|
138 // |
|
139 // Initialises any hardware blocks which require early initialisation, e.g. enable and power the LCD, set up |
|
140 // RTC clocks, disable DMA controllers. etc. |
|
141 // |
|
142 } |
|
143 |
|
144 </codeblock> <p> <codeph>TemplateInterrupt::Init1();</codeph> is |
|
145 static function that initialises the interrupt dispatcher. See <xref href="GUID-423537D5-2C8A-5C26-8D7B-60446E95F681.dita">Interrupt Layer Initialisation</xref>. </p> </section> |
|
146 <section id="GUID-F5275882-BBD0-561F-B617-683AA2004BB9"><title>Asic::Init3() |
|
147 implementation</title> <p><b>Entry conditions</b> </p> <ul> |
|
148 <li id="GUID-9450694C-ADF3-52DE-AA58-4AFF53A1EEC6"><p>called in the |
|
149 context of the supervisor thread </p> </li> |
|
150 <li id="GUID-335F8A2E-0223-598E-AA23-F72E3BE84D76"><p>the kernel is |
|
151 ready to handle interrupts </p> </li> |
|
152 <li id="GUID-B198D669-9E88-5279-81A8-6A11F8EE3BFD"><p>the kernel heap |
|
153 and memory management system is fully functional. </p> </li> |
|
154 </ul> <p><b>What the function should do</b> </p> <p>This is called during |
|
155 stage 3 of kernel initialisation. </p> <p>In this function, you need |
|
156 to: </p> <ul> |
|
157 <li id="GUID-38C35732-E79A-595C-9852-12D1FE30A081"><p>enable interrupt |
|
158 sources </p> </li> |
|
159 <li id="GUID-D4F750D9-96B1-5AD1-AA66-2485D37B6323"><p>start the millisecond |
|
160 tick timer. </p> </li> |
|
161 <li id="GUID-390278B7-EF0F-59ED-A57D-54490655C97B"><p>Optionally, |
|
162 replace the implementation used by <codeph>Kern::NanoWait()</codeph>. </p> </li> |
|
163 </ul> <p>Any other general initialisation can also be done here. </p> <p>As an example, on the template port, the function is implemented |
|
164 in the Variant layer, by <codeph>Template::Init3()</codeph>. </p> <p><b>Millisecond tick timer</b> </p> <p>The kernel expects that the |
|
165 kernel's tick handler routine will be called at a fixed microsecond |
|
166 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 |
|
167 is as follows: </p> <codeblock id="GUID-AF60AC52-5188-5911-9A03-A090D048ADA3" xml:space="preserve">EXPORT_C void TemplateAssp::Init3() |
|
168 { |
|
169 __KTRACE_OPT(KBOOT,Kern::Printf("TemplateAssp::Init3()")); |
|
170 |
|
171 TTemplate::Init3(); |
|
172 |
|
173 NTimerQ& m=*(NTimerQ*)NTimerQ::TimerAddress(); |
|
174 iTimerQ=&m; |
|
175 // |
|
176 // TO DO: (mandatory) |
|
177 // |
|
178 // If Hardware Timer used for System Ticks cannot give exactly the period required store the initial rounding value |
|
179 // here which is updated every time a match occurs. Note this leads to "wobbly" timers whose exact period change |
|
180 // but averages exactly the required value |
|
181 // e.g. |
|
182 // m.iRounding=-5; |
|
183 // |
|
184 |
|
185 TInt r=Interrupt::Bind(KIntIdOstMatchMsTimer,MsTimerTick,&m); // bind the System Tick interrupt |
|
186 if (r!=KErrNone) |
|
187 Kern::Fault("BindMsTick",r); |
|
188 |
|
189 // |
|
190 // TO DO: (mandatory) |
|
191 // |
|
192 // Clear any pending OST interrupts and enable any OST match registers. |
|
193 // If possible may reset the OST here (to start counting from a full period). Set the harwdare to produce an |
|
194 // interrupt on full count |
|
195 // |
|
196 |
|
197 r=Interrupt::Enable(KIntIdOstMatchMsTimer); // enable the System Tick interrupt |
|
198 if (r!=KErrNone) |
|
199 Kern::Fault("EnbMsTick",r); |
|
200 |
|
201 // |
|
202 // TO DO: (optional) |
|
203 // |
|
204 // Allocate physical RAM for video buffer, as per example below. However with some hardware, the Video Buffer |
|
205 // may not reside in main System memory, it may be dedicated memory. |
|
206 // |
|
207 // EXAMPLE ONLY |
|
208 TInt vSize=VideoRamSize(); |
|
209 r=Epoc::AllocPhysicalRam(2*vSize,TemplateAssp::VideoRamPhys); |
|
210 if (r!=KErrNone) |
|
211 Kern::Fault("AllocVRam",r); |
|
212 }</codeblock> <p><b>Servicing the timer interrupt</b> </p> <p>The timer interrupt |
|
213 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 |
|
214 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, |
|
215 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) |
|
216 { |
|
217 // Service 1ms tick interrupt |
|
218 asm("ldr ip, [r0, #%a0]" : : "i" _FOFF(NTimerQ,iRounding)); |
|
219 asm("ldr r2, __KHwBaseOst "); |
|
220 asm("adds ip, ip, #2 "); |
|
221 asm("ldr r3, __KOst1000HzTickMatchIncrement "); |
|
222 asm("subcs ip, ip, #5 "); |
|
223 asm("str ip, [r0, #%a0]" : : "i" _FOFF(NTimerQ,iRounding)); |
|
224 asm("addcs r3, r3, #1 "); |
|
225 asm("mov r1, #%a0" : : "i" ((TInt)(1<<KHwOstMatchMsTimer))); |
|
226 asm("str r1, [r2, #0x14] "); // clear interrupt |
|
227 asm("ldr r1, [r2, #%a0]" : : "i" ((TInt)KHwOstMatchMsTimer*4)); // r1=old match value |
|
228 asm("add r1, r1, r3 "); // step match value on |
|
229 asm("ldr ip, [r2, #0x10] "); // r3=system timer value |
|
230 asm("str r1, [r2, #%a0]" : : "i" ((TInt)KHwOstMatchMsTimer*4)); |
|
231 asm("cmp ip, r1 "); // compare to next match value |
|
232 |
|
233 #ifdef _DEBUG |
|
234 asm("addpl r1, ip, #10 "); // in DEBUG if timer>match value, set match value to timer + a bit |
|
235 asm("strpl r1, [r2, #%a0]" : : "i" ((TInt)KHwOstMatchMsTimer*4)); |
|
236 asm("b Tick__7NTimerQ "); // call interrupt handler anyway |
|
237 #else |
|
238 asm("bmi Tick__7NTimerQ "); // if timer<match value, OK - call interrupt handler |
|
239 #endif |
|
240 |
|
241 // otherwise we are late for the next tick so force a data abort exception... |
|
242 asm("mvn r2, #0x10000002 "); // r2=0xeffffffd |
|
243 asm("str r2, [r2] "); // die |
|
244 |
|
245 // Constant data embedded in code. |
|
246 asm("__KOst1000HzTickMatchIncrement: "); |
|
247 asm(".word %a0" : : "i" ((TInt)KOst1000HzTickMatchIncrement)); |
|
248 asm("__KHwBaseOst: "); |
|
249 asm(".word %a0" : : "i" ((TInt)KHwBaseOst)); |
|
250 }</codeblock> <p>Note that it is a requirement that the timer |
|
251 period should be an integral number of microseconds, even if the exact |
|
252 period is not 1000us. It is always possible to add code to the interrupt |
|
253 handler to achieve this average so that over a large number of ticks, |
|
254 the deviation from this average will tend to 0, by adjusting the exact |
|
255 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 |
|
256 periods of time within the kernel. You call this function and specify |
|
257 the number of nanoseconds. The function is, in effect, a shell that |
|
258 uses default implementation code provided by the generic platform. |
|
259 You can provide your own implementation in your port, and register |
|
260 this with the platform. This allows the wait functionality to be implemented |
|
261 in the best possible way for your platform, possibly by using a hardware |
|
262 timer whose frequency is independent of the CPU frequency. </p> <p>To replace the default implementation, you need to: </p> <ul> |
|
263 <li id="GUID-733329E1-99C5-56A4-B80F-FFCFD74F1320"><p>code your own |
|
264 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) |
|
265 { |
|
266 // Wait for aInterval nanoseconds |
|
267 }</codeblock> <p>where <codeph>AsicImpl</codeph> is the class that is ultimately derived from <codeph>Asic</codeph>. </p> </li> |
|
268 <li id="GUID-BDE8C5D6-6E6C-5B2E-9219-A8D5DC114EA2"><p>register this |
|
269 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> |
|
270 </ul> <p>You can see where this goes by looking at the template port |
|
271 at: <filepath>...\base\cedar\template\template_assp\template_assp.cpp</filepath> </p> </section> |
|
272 <section id="GUID-1028F2D0-BA8B-4880-9565-50C89EBD1685"><title>Asic::DebugOutput() |
|
273 implementation</title> <p>It is worth implementing this early so that |
|
274 it is possible to get trace output to see what the kernel is doing. |
|
275 This function is passed one character at a time. Normally this is |
|
276 sent to a UART, though it can be output through any convenient communications |
|
277 channel. </p> <p>On the template port, this is implemented in the |
|
278 Variant layer, by <codeph>Template::DebugOutput()</codeph> in <filepath>...\template_variant\specific\variant.cpp</filepath>. </p> </section> |
|
279 <section id="GUID-EEC48040-B7D7-406B-8138-4A1F646ED990"><title>Asic::Idle() |
|
280 implementation</title> <p>If no power management has been implemented, |
|
281 then this function is called when the system is to idle to allow power |
|
282 saving. This function can just return, until power management is implemented. |
|
283 Once power management has been implemented, then idling behaviour |
|
284 will be handled by the power controller, i.e. the Variant's implementation |
|
285 of the <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita"><apiname>DPowerController</apiname></xref> class </p> </section> |
|
286 <section id="GUID-917B420D-5F10-5190-97D2-9D2DAFD4FB76"><title>Asic::MsTickPeriod() |
|
287 implementation</title> <p>This function is used to return the number |
|
288 of microseconds per tick. To avoid timing drift, a tick frequency |
|
289 should be chosen that gives a round number of microseconds per tick. |
|
290 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 |
|
291 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() |
|
292 { |
|
293 // |
|
294 // TO DO: (mandatory) |
|
295 // |
|
296 // Return the OST tick period (System Tick) in microseconds ( 10E-06 s ). |
|
297 // |
|
298 return 1000; // EXAMPLE ONLY |
|
299 } |
|
300 </codeblock> <p>See also <xref href="GUID-F84E18B8-5883-5A3A-A9DB-EC25BB86149F.dita">Timers</xref>. </p> </section> |
|
301 <section id="GUID-1C8A7F79-8CD5-442E-A9A5-925C94E80773"><title>Asic::SystemTimeInSecondsFrom2000() |
|
302 implementation</title> <p>This is a function that the kernel |
|
303 uses to get the system time. Its signature is </p> <codeblock id="GUID-A1FF9777-D627-5409-B6CD-02F20F7A1889" xml:space="preserve">Tint SystemTimeInSecondsFrom2000(Tint& aTime);</codeblock> <p>An implementation must set the <codeph>aTime</codeph> reference |
|
304 to the number of seconds that have elapsed since the start of the |
|
305 year 2000. This is a positive number; a negative number is interpreted |
|
306 as time before 2000. </p> <p>For the template reference board, the |
|
307 implementation is as follows: </p> <codeblock id="GUID-C4812A82-C069-564B-972A-0922EAC00AAB" xml:space="preserve">EXPORT_C TInt TemplateAssp::SystemTimeInSecondsFrom2000(TInt& aTime) |
|
308 { |
|
309 aTime=(TInt)TTemplate::RtcData(); |
|
310 __KTRACE_OPT(KHARDWARE,Kern::Printf("RTC READ: %d",aTime)); |
|
311 return KErrNone; |
|
312 } |
|
313 </codeblock> <p>Until a real time clock is implemented, this function |
|
314 can just return <xref href="GUID-6CA4F1ED-7947-3087-B618-D35858FAA3BC.dita"><apiname>KErrNone</apiname></xref>. </p> <p>This function |
|
315 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 |
|
316 provided when the KHARDWARE bit in the kerneltrace flags is set for |
|
317 the debug build. </p> </section> |
|
318 <section id="GUID-F0AC3E98-345F-4491-9957-51B127437181"><title>Asic::SetSystemTimeInSecondsFrom2000() |
|
319 implementation</title> <p>This is a function that the kernel uses |
|
320 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 |
|
321 elapsed since the start of the year 2000. This is a positive number; |
|
322 a negative number is interpreted as time before 2000. </p> <p>For |
|
323 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) |
|
324 { |
|
325 // |
|
326 // TO DO: (optional) |
|
327 // |
|
328 // Check if the RTC is running and is stable |
|
329 // |
|
330 __KTRACE_OPT(KHARDWARE,Kern::Printf("Set RTC: %d",aTime)); |
|
331 TTemplate::SetRtcData(aTime); |
|
332 __KTRACE_OPT(KHARDWARE,Kern::Printf("RTC: %d",TTemplate::RtcData())); |
|
333 return KErrNone; |
|
334 } |
|
335 </codeblock> <p>Note that tracing output is provided when the KHARDWARE |
|
336 bit in the kerneltrace flags is set for the debug build. In this function, |
|
337 the trace output shows the value passed in from the kernel and then |
|
338 shows the value read back from the real time clock for verification. </p> </section> |
|
339 <section id="GUID-50BB6924-899F-4385-879E-19A2FC68657C"><title>Asic::NanoWaitCalibration() |
|
340 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 |
|
341 within the kernel. You call this function and specify the number of |
|
342 nanoseconds. You can either use the default implementation of this |
|
343 function, or you can provide your own. </p> <p>The default implementation |
|
344 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 |
|
345 of nanoseconds taken to execute 2 machine cycles. This is obviously |
|
346 dependent on the CPU clock speed, so if variants are likely to run |
|
347 at different speeds, then this should be implemented in the Variant |
|
348 layer. </p> <p>This approach cannot always take into account factors |
|
349 such as processor frequency scaling. An alternative approach is for |
|
350 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 |
|
351 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, |
|
352 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() |
|
353 { |
|
354 // |
|
355 // TO DO: (mandatory) |
|
356 // |
|
357 // Return the minimum time in nano-seconds that it takes to execute the following code: |
|
358 // nanowait_loop: |
|
359 // subs r0, r0, r1 |
|
360 // bhi nanowait_loop |
|
361 // |
|
362 // If accurate timings are required by the Base Port, then it should provide it's own implementation |
|
363 // of NanoWait which uses a hardware counter. (See Kern::SetNanoWaitHandler) |
|
364 // |
|
365 |
|
366 return 0; // EXAMPLE ONLY |
|
367 } |
|
368 </codeblock> </section> |
|
369 <section id="GUID-15F344C5-A1CC-45FC-AC94-27022A1DF448"><title>Asic::VariantHal() |
|
370 implementation</title> <p>You might find it useful to review <xref href="GUID-9AE254D4-AA60-579E-8D9D-F2797106A413.dita">User-Side Hardware |
|
371 Abstraction Technology</xref> first. </p> <p>This is the HAL handler |
|
372 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> |
|
373 <section id="GUID-2EEA143D-612C-47C5-B16C-22DAD1BC179E"><title>Asic::MachineConfiguration() |
|
374 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 |
|
375 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 |
|
376 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 |
|
377 layer: </p> <codeblock id="GUID-B75F631E-03DB-5C98-911F-1161842AA17F" xml:space="preserve">TPtr8 Template::MachineConfiguration() |
|
378 { |
|
379 return TPtr8((TUint8*)&Kern::MachineConfig(),sizeof(TActualMachineConfig),sizeof(TActualMachineConfig)); |
|
380 } |
|
381 </codeblock> <p>Here, the machine configuration information is represented |
|
382 by an object of type <codeph>TTemplateMachineConfig</codeph>, which |
|
383 derives from <codeph>TMachineConfig</codeph>. In effect, <codeph>TMachineConfig</codeph> represents information that is common to all, while the Variant |
|
384 can extend this to contain whatever information is appropriate. </p> <p>Note that <codeph>TActualMachineConfig</codeph> is a typedef |
|
385 for <codeph>TTemplateMachineConfig</codeph>. </p> </section> |
|
386 <section id="GUID-B1E39D8C-1562-4464-A316-144ED89935C9"><title>Asic::StartupReason() |
|
387 implementation</title> <p>If a startup reason is available from hardware |
|
388 or a preserved RAM location, it should be returned by the function. |
|
389 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() |
|
390 { |
|
391 __KTRACE_OPT(KBOOT,Kern::Printf("TemplateAssp::StartupReason")); |
|
392 #ifdef _DEBUG // REMOVE THIS |
|
393 TUint s = Kern::SuperPage().iHwStartupReason; |
|
394 __KTRACE_OPT(KBOOT,Kern::Printf("CPU page value %08x", s)); |
|
395 #endif // REMOVE THIS |
|
396 // |
|
397 // TO DO: (mandatory) |
|
398 // |
|
399 // Map the startup reason read from the Super Page to one of TMachineStartupType enumerated values |
|
400 // and return this |
|
401 // |
|
402 return EStartupCold; // EXAMPLE ONLY |
|
403 } |
|
404 </codeblock> </section> |
|
405 </conbody><related-links> |
|
406 <link href="GUID-984C2A0D-36BE-5A99-9D65-3F8791C669FF.dita#GUID-984C2A0D-36BE-5A99-9D65-3F8791C669FF/GUID-95C34114-F986-5428-9D40-5CF64429CDBD"> |
|
407 <linktext>ASSP/Variant Architecture</linktext></link> |
|
408 </related-links></concept> |