1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
32
33 34 35
36
37 package ti.uia.family.dm.dra7xx;
38
39 import ti.uia.loggers.LoggerStopMode;
40 import xdc.rov.ViewInfo;
41 import xdc.runtime.Assert;
42 import xdc.runtime.Diags;
43 import xdc.runtime.Log;
44 import xdc.runtime.Types;
45
46 /*!
47 * ======== TimestampProvider ========
48 * System-wide timestamp provider
49 *
50 * This timestamp provider is used by UIA to provide a common time
51 * base for all processors. This allows System Analyzer to correlate
52 * the log events from all processors to a common time base. Event
53 * correlation is required for the multi-core execution graph. Use
54 * this module as the global timestamp proxy for the
55 * {@link ti.uia.runtime.LogSync} module.
56 *
57 * This module requires the use of a timer to provide a common system
58 * tick. The timer needs to have access to the 32 KHz clock. Not all
59 * timers are suitable for use by this module. See the {@link #timerId}
60 * configuration parameter for a list of recommended timers. Exactly one
61 * processor must be the owner of the timer. See {@link #owner} for details.
62 *
63 * Ledgers are used internally by this module to keep track of the
64 * other processors in the system. The ledgers are shared across
65 * processor boundaries. You must provide the base address of a ledger
66 * so that all processors know where to find it. See the {@link #ledgers}
67 * configuration parameter for details. There are two types of ledgers:
68 * a group ledger, and a private ledger. One group ledger is mandatory,
69 * private ledgers are typically used by the EVE processors. Ledgers are
70 * defined by the role used to access them. See the {@link #Role}
71 * enumeration for details.
72 *
73 * @a(Configuration Example)
74 *
75 * This is a four processor example: DSP1 DSP2 EVE1 EVE2. In this example,
76 * DSP1 is to be the owner of the timer. Three ledgers will be used, one
77 * group ledger and two private ledgers. The group ledger is used by DSP1
78 * and DSP2. One private ledger is used by DSP1 and EVE1. The other private
79 * ledger is used by DSP2 and EVE2.
80 *
81 * Add the following to your DSP1 configuration script.
82 *
83 * @p(code)
84 * // add Timer3 (id=2) to SYS/BIOS available mask //
85 * var TimerSupport = xdc.useModule('ti.sysbios.family.shared.vayu.TimerSupport');
86 * TimerSupport.availMask |= (0x1 << 2);
87 *
88 * // configure timestamp proxy //
89 * var TimestampProvider = xdc.useModule('ti.uia.family.dm.dra7xx.TimestampProvider');
90 * TimestampProvider.timerId = 2;
91 * TimestampProvider.owner = true;
92 * TimestampProvider.eventId = 65;
93 * TimestampProvider.cpuIntrNum = 13;
94 * TimestampProvider.syncInterval = 33;
95 *
96 * // group ledger
97 * TimestampProvider.ledgers.$add(
98 * new TimestampProvider.Ledger({
99 * role: TimestampProvider.Ledger_PEER,
100 * base: 0x40500000,
101 * size: 2, // DSP1 DSP2
102 * index: 0 // DSP1
103 * })
104 * );
105 *
106 * // eve1 ledger
107 * TimestampProvider.ledgers.$add(
108 * new TimestampProvider.Ledger({
109 * role: TimestampProvider.Role_USER,
110 * base: 0x42020000
111 * })
112 * );
113 *
114 * // enable event correlation
115 * var LogSync = xdc.useModule('ti.uia.runtime.LogSync');
116 * LogSync.GlobalTimestampProxy = TimestampProvider;
117 * LogSync.enableEventCorrelationForJTAG = true;
118 * @p
119 * Add the following to your DSP2 configuration script.
120 *
121 * @p(code)
122 * // configure timestamp proxy for event correlation
123 * var TimestampProvider = xdc.useModule('ti.uia.family.dm.dra7xx.TimestampProvider');
124 *
125 * TimestampProvider.timerId = 2;
126 * TimestampProvider.owner = false; // DSP1 is owner
127 * TimestampProvider.eventId = 65;
128 * TimestampProvider.cpuIntrNum = 13;
129 * TimestampProvider.syncInterval = 33;
130 *
131 * // group ledger
132 * TimestampProvider.ledgers.$add(
133 * new TimestampProvider.Ledger({
134 * role: TimestampProvider.Role_PEER,
135 * base: 0x40500000,
136 * size: 2, // DSP1 DSP2
137 * index: 1 // DSP2
138 * })
139 * );
140 *
141 * // eve2 ledger
142 * TimestampProvider.ledgers.$add(
143 * new TimestampProvider.Ledger({
144 * role: TimestampProvider.Role_USER,
145 * base: 0x42120000
146 * })
147 * );
148 *
149 * // enable event correlation
150 * var LogSync = xdc.useModule('ti.uia.runtime.LogSync');
151 * LogSync.GlobalTimestampProxy = TimestampProvider;
152 * LogSync.enableEventCorrelationForJTAG = true;
153 * @p
154 * Add the following to your EVE1 configuration script.
155 *
156 * @p(code)
157 * // configure timestamp proxy for event correlation
158 * var TimestampProvider = xdc.useModule('ti.uia.family.dm.dra7xx.TimestampProvider');
159 *
160 * TimestampProvider.timerId = 2;
161 * TimestampProvider.owner = false; // DSP1 is owner
162 * TimestampProvider.eventId = 35;
163 * TimestampProvider.cpuIntrNum = 9;
164 * TimestampProvider.syncInterval = 33;
165 *
166 * // use private ledger, role = owner
167 * TimestampProvider.ledgers.$add(
168 * new TimestampProvider.Ledger({
169 * role: TimestampProvider.Role_OWNER,
170 * base: 0x40020000
171 * })
172 * );
173 *
174 * // enable event correlation
175 * var LogSync = xdc.useModule('ti.uia.runtime.LogSync');
176 * LogSync.GlobalTimestampProxy = TimestampProvider;
177 * LogSync.enableEventCorrelationForJTAG = true;
178 * @p
179 * Add the following to your EVE2 configuration script.
180 *
181 * @p(code)
182 * // configure timestamp proxy for event correlation
183 * var TimestampProvider = xdc.useModule('ti.uia.family.dm.dra7xx.TimestampProvider');
184 *
185 * TimestampProvider.timerId = 2;
186 * TimestampProvider.owner = false; // DSP1 is owner
187 * TimestampProvider.eventId = 35;
188 * TimestampProvider.cpuIntrNum = 9;
189 * TimestampProvider.syncInterval = 33;
190 *
191 * // use private ledger, role = owner
192 * TimestampProvider.ledgers.$add(
193 * new TimestampProvider.Ledger({
194 * role: TimestampProvider.Role_OWNER,
195 * base: 0x40020000
196 * })
197 * );
198 *
199 * // enable event correlation
200 * var LogSync = xdc.useModule('ti.uia.runtime.LogSync');
201 * LogSync.GlobalTimestampProxy = TimestampProvider;
202 * LogSync.enableEventCorrelationForJTAG = true;
203 * @p
204 *
205 * @a(CPU Frequency Configuration)
206 *
207 * In order for event correlation to be accurate, the cpu frequency must
208 * be set as accurately as possible. This module can be used to determine
209 * you actual cpu frequency.
210 *
211 * Enable the timestamp sample buffer with the {@link #estCpuFreq}
212 * configuration parameter. Run your program continuously for 30 seconds.
213 * Use ROV to view the cpu frequency in the TimestampProvider module view.
214 *
215 * Once you have determined your cpu frequency, use that value to configure
216 * the SYS/BIOS cpu frequency.
217 *
218 * @p(code)
219 * var BIOS = xdc.useModule('ti.sysbios.BIOS');
220 * BIOS.cpuFreq = { hi: 0, lo: 609024002 };
221 * @p
222 *
223 * Hint: disable the {@link #estCpuFreq} when done to reduce your data
224 * footprint.
225 */
226
227 @ModuleStartup
228 @Template("./TimestampProvider.xdt")
229
230 module TimestampProvider inherits ti.uia.runtime.IUIATimestampProvider
231 {
232 /*!
233 * ======== timerId ========
234 * Identify which timer to use as the timestamp clock source
235 *
236 * The timers are named Timer1-Timer16; their corresponding ids
237 * are 0-15 (e.g. for Timer3, use id=2). Not all timers are
238 * appropriate clock sources for this module. Use one of the
239 * following timers:
240 *
241 * @p(html)
242 * <table>
243 * <style scoped>th,td {padding:4px}</style>
244 * <tr style="text-align:left; background-color:LightGray">
245 * <th>Timer Name</th>
246 * <th>Description</th>
247 * </tr>
248 * <tr>
249 * <td>Timer[3,4,9,11,13,14,15,16]</td>
250 * <td>PD_L4PER power domain</td>
251 * </tr>
252 * <tr>
253 * <td>Timer[5,6,7,8]</td>
254 * <td>PD_IPU power domain</td>
255 * </tr>
256 * </table>
257 * @p
258 *
259 * All executables must use the same timer in order to support
260 * event correlation in System Analyzer.
261 */
262 config UInt timerId;
263
264 /*!
265 * ======== owner ========
266 * Determine ownership of the timer
267 *
268 * When set to true, the timer will be enabled and configured
269 * during the boot phase. The owner should run before any other
270 * processor using this same timer. Only one processor should
271 * be configured as the owner of the timer. This processor will
272 * also listen for the timer interrupt and acknowledge it.
273 *
274 * When set to false, it is expected that another processor will
275 * enable and configure the timer. This processor will simply
276 * listen for the timer interrupt and acknowledge it.
277 *
278 * Note: The ARP32 does not support timer ownership. This config
279 * param must always be false when running on the ARP32.
280 */
281 config Bool owner;
282
283 /*!
284 * ======== eventId ========
285 * Specify interrupt controller event to receive timer interrupt
286 *
287 * The eventId specifies which interrupt controller event should
288 * receive the timer interrupt. This value is used to route the
289 * timer interrupt through the Interrupt Crossbar to the interrupt
290 * controller event. It is also used to route the interrupt event
291 * to the cpu interrupt specified in {@link #cpuIntrNum}.
292 *
293 * The following table indicates possible event ids, but this is
294 * device specific. Please consult your manual.
295 *
296 * @p(html)
297 * <table>
298 * <style scoped>th,td {padding:4px}</style>
299 * <tr style="text-align:left; background-color:LightGray">
300 * <th>Processor</th>
301 * <th>Event ID</th>
302 * </tr>
303 * <tr>
304 * <td>DSP</td>
305 * <td>63-78, 81</td>
306 * </tr>
307 * <tr>
308 * <td>EVE</td>
309 * <td>32-39</td>
310 * </tr>
311 * </table>
312 * @p
313 */
314 config Int eventId;
315
316 /*!
317 * ======== cpuIntrNum ========
318 * Specify cpu interrupt to receive timer interrupt
319 *
320 * For accurate event correlation in System Analyzer, it is
321 * recommended not to share this interrupt.
322 *
323 * The following table indicates possible interrupt numbers, but
324 * this is device specific. Please consult your manual.
325 *
326 * @p(html)
327 * <table>
328 * <style scoped>th,td {padding:4px}</style>
329 * <tr style="text-align:left; background-color:LightGray">
330 * <th>Processor</th>
331 * <th>Timer ID</th>
332 * </tr>
333 * <tr>
334 * <td>DSP</td>
335 * <td>4-15</td>
336 * </tr>
337 * <tr>
338 * <td>EVE</td>
339 * <td>8-11</td>
340 * </tr>
341 * </table>
342 * @p
343 */
344 config Int cpuIntrNum;
345
346 /*!
347 * ======== syncInterval ========
348 * Specify the interval for logging sync events
349 *
350 * UIA Sync events are used by System Analyzer to correlate the
351 * events from each processor onto a global time base. Only the
352 * last sync event is actually used.
353 *
354 * This configuration parameter specifies how frequently the sync
355 * events should be raised. In order to maintain accurate event
356 * correlation, you should raise one sync event within each log
357 * data window. For example, if your log buffer contains 100 ms
358 * of data, then you should raise a sync event each 0.1 seconds
359 * (100 ms = 0.1 sec).
360 *
361 * Each syncInterval is 0.001953125 seconds. Divide the data window
362 * by this value to get the syncInterval (round down).
363 *
364 * @p(code)
365 * 0.1 sec / 0.001953125 sec = 51.2
366 *
367 * TimestampProvider.syncInterval = 51;
368 * @p
369 *
370 * When using multiple logger instances, the data window for each
371 * instance is probably different. Use System Analyzer to measure
372 * the data overlap of your region of interest. Use the length of
373 * this region to calculate the syncInterval.
374 *
375 * The syncInterval should be as large as possible to reduce logging
376 * overhead, yet small enough to yield accurate event correlation.
377 */
378 config UInt syncInterval = 50;
379
380 /*!
381 * ======== estCpuFreq ========
382 * Estimate the cpu frequency using timestamp sample buffer
383 *
384 * When enabled, this module will save timestamps in the sample
385 * buffer which are then used to calculate an estimate of the
386 * cpu frequency. Run the processor continuously for 30 seconds
387 * to ensure the sample buffer is full. Open ROV and select the
388 * Module tab. The calculated cpu frequency is displayed in the
389 * estCpuFreq column. The timestamp samples are displayed in the
390 * Sample Buffer tab.
391 *
392 * Set this config param to false to reduce the data footprint in
393 * your released product.
394 */
395 config Bool estCpuFreq = false;
396
397 /*!
398 * ======== Role ========
399 * Define roles for each ledger instance
400 *
401 * There may be multiple ledger instances in a system. There are
402 * two types of ledgers: 1. a group ledger, and 2. a private ledger.
403 * A group ledger may have two or more users. A private ledger has
404 * exactly two users. When a processor creates a private ledger,
405 * that processor may not create any additional ledgers of any type.
406 * A private ledger is typicaly used by the ARP32 processor.
407 *
408 * The ledger type is identified by the role used to access it.
409 *
410 * @p(html)
411 * <div class="xdocText"><dl>
412 * <dt>Role_PEER</dt>
413 * <dd>
414 * This role is used to access a group ledger instance. This
415 * ledger instance is used by multiple processors. The ledger
416 * is an array of GroupLedgerElem elements. Each processor
417 * uses one entry in the ledger. The size of the ledger must
418 * equal the number of users.<br><br>
419 *
420 * All users of this ledger are peers. The ledger is not created
421 * by any processor, it must be defined in the memory map.<br><br>
422 * </dd>
423 *
424 * <dt>Role_OWNER</dt>
425 * <dd>
426 * This role is used to access a private ledger. This ledger
427 * is used by only two processors: the local processor (the
428 * owner) and a remote processor (the user). The ledger is
429 * allocated in the local processor's memory map. This same
430 * ledger must be defined by a Role_USER role on one other
431 * processor.<br><br>
432 * </dd>
433 *
434 * <dt>Role_USER</dt>
435 * <dd>
436 * This role is used to access a private ledger. This role is the
437 * complement of the Role_OWNER role. When using a private ledger,
438 * the actual ledger is created by the other processor.<br><br>
439 *
440 * A processor using the Role_USER role, will access the ledger with
441 * the given address, but it does not allocate the ledger.<br><br>
442 *
443 * It is possible to access multiple private ledgers from the
444 * same processor. Each Role_USER corresponds to a private ledger
445 * created by another processor.<br><br>
446 * </dd>
447 * </dl>
448 * @p
449 */
450 enum Role {
451 Role_PEER = 0x01, /*! shared by multiple processors */
452 Role_OWNER = 0x02, /*! shared with one remote processor */
453 Role_USER = 0x03 /*! shared with one remote processor */
454 };
455
456 /*!
457 * ======== Ledger ========
458 * Define a ledger used in the system
459 *
460 * A ledger is used to keep track of which processors are running.
461 * Depending on the ledger role, there can be two or more users of
462 * the same ledger instance. You can define multiple ledgers. See
463 * {@link #ledgers} for examples of creating ledgers.
464 *
465 * @field(role)
466 * Defines how this processor will be using the ledger. The role
467 * also implicitly defines which type of ledger is created. See
468 * the {@link #Role} enumeration for details.
469 *
470 * @field(base)
471 * The base address of the ledger as seen by the local processor.
472 *
473 * @field(size)
474 * The number of users of the current ledger. When adding a new
475 * user to a ledger, be sure to update this value for all processors
476 * using the same ledger.
477 *
478 * @field(index)
479 * The entry index in the ledger to be used by this processor. Each
480 * processor must have its own unique entry. The index is zero based
481 * (as in array indexing). Index values range from 0 - (size-1).
482 */
483 struct Ledger {
484 Role role; /*! role used to access the ledger */
485 Ptr base; /*! base address of the ledger */
486 Int size; /*! number of users */
487 Int index; /*! entry assigned to this processor */
488 };
489
490 /*!
491 * ======== ledgers ========
492 * Define the ledgers to be managed by this processor
493 *
494 * Ledgers are used to keep track of the other processors. This
495 * is needed to support the auto-logging feature and to issue
496 * LogSync events. Each processor must define at least one ledger.
497 *
498 * There are two types of ledgers: a group ledger, and a private
499 * ledger. See the {@link #Role} enumeration for details.
500 *
501 * Use as few ledgers as possible. However, some system constraints
502 * will require additional ledgers. For example, the EVE processors
503 * have very slow data access to on-chip or external memory. Therefore,
504 * we recommend that each EVE processor use a private ledger. Place
505 * the private ledger in DMEM to ensure fast memory access.
506 *
507 * Add the following to your EVE1 configuration script.
508 *
509 * @p(code)
510 * var TimestampProvider = xdc.useModule('ti.uia.family.dm.dra7xx.TimestampProvider');
511 *
512 * // use private ledger, role = owner
513 * TimestampProvider.ledgers.$add(
514 * new TimestampProvider.Ledger({
515 * role: TimestampProvider.Role_OWNER,
516 * base: 0x40020000
517 * })
518 * );
519 * @p
520 *
521 * Each private ledger has exactly two users: an owner (Role_OWNER)
522 * and a user (Role_USER). In the example above, the EVE would always
523 * be the owner. Typically, the DSP would be the corresponding user.
524 *
525 * Add the following to your DSP1 configuration script.
526 *
527 * @p(code)
528 * var TimestampProvider = xdc.useModule('ti.uia.family.dm.dra7xx.TimestampProvider');
529 *
530 * // eve1 ledger, role = user
531 * TimestampProvider.ledgers.$add(
532 * new TimestampProvider.Ledger({
533 * role: TimestampProvider.Role_USER,
534 * base: 0x42020000
535 * })
536 * );
537 * @p
538 *
539 * Note in the example above, the EVE defines the ledger address
540 * using its local address (e.g. 0x40020000). However, the DSP must
541 * use the interconnect address (e.g. 0x42020000).
542 *
543 * For the remaining processors in the system, you could use one
544 * group ledger. All processors using the same group must agree on
545 * the ledger address, and the number of entries. Each processor must
546 * be assigned its own entry in the ledger.
547 *
548 * The following example defines a single group ledger used by two
549 * processors: DSP1 and DSP2. Add the following to your DSP1
550 * configuration script.
551 *
552 * @p(code)
553 * var TimerSupport = xdc.useModule('ti.sysbios.family.shared.vayu.TimerSupport');
554 *
555 * // group ledger, role = peer
556 * TimestampProvider.ledgers.$add(
557 * new TimestampProvider.Ledger({
558 * role: TimestampProvider.Ledger_PEER,
559 * base: 0x40500000,
560 * size: 2, // DSP1 DSP2
561 * index: 0 // DSP1
562 * })
563 * );
564 * @p
565 * Add the following to your DSP2 configuration script.
566 *
567 * @p(code)
568 * var TimerSupport = xdc.useModule('ti.sysbios.family.shared.vayu.TimerSupport');
569 *
570 * // group ledger, role = peer
571 * TimestampProvider.ledgers.$add(
572 * new TimestampProvider.Ledger({
573 * role: TimestampProvider.Role_PEER,
574 * base: 0x40500000,
575 * size: 2, // DSP1 DSP2
576 * index: 1 // DSP2
577 * })
578 * );
579 * @p
580 *
581 * It is also possible to partition the remaining processors into
582 * groups and assign a group ledger to each processor group. This
583 * might be done to support independent application domains. However,
584 * one requirement is that the processor which owns the timer must
585 * participate in all group ledgers. For example, if DSP1 has
586 *
587 * @p(code)
588 * TimestampProvider.owner = true;
589 * @p
590 *
591 * then DSP1 must participate in all group ledgers (i.e. Role_PEER).
592 */
593 config Ledger ledgers[length];
594
595 /*!
596 * ======== L_latch ========
597 * Log event raised at the end of the timer isr
598 *
599 * The timer isr maintains a global tick value used by System
600 * Analyzer to correlate the log events across processor boundaries.
601 * This event is raised at the end of the timer isr. The latch count
602 * should be the same on all processors. The isr timestamp is also
603 * reported. This value can be used to measure the accuracy of the
604 * event correlation. The isr timestamp is captured at the very
605 * beginning of the timer isr.
606 */
607 config Log.Event L_latch = {
608 mask: Diags.INFO,
609 msg: "L_latch: latch=0x%x:0x%x, isr ts=0x%x:0x%x"
610 };
611
612
613 /*!
614 * ======== L_suspend ========
615 * Log event raised when loggers are to be suspended
616 *
617 * The module has determined that the system state is not nominal. To
618 * preserve the events in the log buffers leading up to this point,
619 * the loggers will be suspended. This event is raised shortly before
620 * the loggers are actually suspended.
621 */
622 config Log.Event L_suspend = {
623 mask: Diags.INFO,
624 msg: "L_suspend: loggers suspended"
625 };
626
627 /*! @_nodoc */
628 override metaonly config Bool canCpuCyclesPerTickBeChanged = false;
629
630 /*! @_nodoc */
631 override metaonly config Bool canFrequencyBeChanged = false;
632
633 /*! @_nodoc */
634 override metaonly config UInt32 cpuCyclesPerTick = 0;
635
636 internal:
637
638 const UInt GBL_FREQ = 200000000;
639
640
641 const UInt TPRD = 64;
642
643
644 const UInt TSSZ = (1 << 6);
645
646
647 const UInt GBLTC = 100;
648
649
650 const UInt LEGSZ = 16;
651
652
653 const UInt LOGSZ = 6;
654
655
656 const UInt TIMEOUT = 1200;
657
658
659 config UInt SPINCNT;
660
661
662 struct GroupLedgerElem {
663 UInt32 masterLC_hi;
664 UInt32 masterLC_lo;
665 UInt32 latch;
666 Bool nominal;
667 }
668
669
670 struct PrivateLedger {
671 UInt32 userLC;
672 Bool nominal;
673 UInt32 ownerLC;
674 }
675
676 677 678 679 680 681 682
683 config Assert.Id A_badRole = {
684 msg: "A_badRole: unknown ledger role"
685 };
686
687 688 689 690 691 692 693 694
695 config Assert.Id A_noGroupLedger = {
696 msg: "A_noGroupLedger: unable to find a group ledger"
697 };
698
699 700 701 702 703 704 705
706 config Assert.Id A_badLoggerState = {
707 msg: "A_badLoggerState: logger state should not be both pause and resume at the same time."
708 };
709
710 711 712 713
714 Void enableTimer();
715
716 717 718 719
720 Void startTimer();
721
722 723 724
725 @DirectCall
726 Void isr();
727
728 729 730 731
732 @DirectCall
733 Void grpRolloverIsr(UArg baseAddr);
734
735 736 737 738
739 @DirectCall
740 Void pvtRolloverIsr(UArg baseAddr);
741
742 743 744 745
746 Void pauseLoggers();
747
748 749 750 751
752 Void resumeLoggers();
753
754 /*! @_nodoc */
755 metaonly struct ModuleView {
756 String latchCount;
757 String estCpuFreq;
758 }
759
760 /*! @_nodoc */
761 metaonly struct SampleBufferView {
762 UInt serial;
763 String tsHi;
764 String tsLo;
765 }
766
767 /*! @_nodoc */
768 @Facet
769 metaonly config ViewInfo.Instance rovViewInfo =
770 ViewInfo.create({
771 viewMap: [
772 ['Module',
773 {
774 type: ViewInfo.MODULE,
775 viewInitFxn: 'viewInitModule',
776 structName: 'ModuleView'
777 }
778 ],
779 ['Sample Buffer',
780 {
781 type: ViewInfo.MODULE_DATA,
782 viewInitFxn: 'viewInitSampleBuffer',
783 structName: 'SampleBufferView'
784 }
785 ]
786 ]
787 });
788
789
790 struct Module_State {
791 Ptr timer;
792 Types.Timestamp64 latch;
793 Bool logging;
794 PrivateLedger * ledgerPvt;
795 Int count;
796 LoggerStopMode.Handle loggers[LOGSZ];
797 UInt tshead;
798 Types.Timestamp64 tsbuf[];
799 }
800 }