Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / analyzers / trapcount / trapcount.cc
CommitLineData
920dae64
AT
1// ========== Copyright Header Begin ==========================================
2//
3// OpenSPARC T2 Processor File: trapcount.cc
4// Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
5// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
6//
7// The above named program is free software; you can redistribute it and/or
8// modify it under the terms of the GNU General Public
9// License version 2 as published by the Free Software Foundation.
10//
11// The above named program is distributed in the hope that it will be
12// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14// General Public License for more details.
15//
16// You should have received a copy of the GNU General Public
17// License along with this work; if not, write to the Free Software
18// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19//
20// ========== Copyright Header End ============================================
21/* icq: TRACER INSTR TRAP TLB
22 *
23 * trapcount.cc
24 *
25 *
26 * the Good:
27 * the Bad:
28 * and the Ugly:
29 * numcpus = g_nvcpu_max; system.h, non-transferable to trace reader :-(.
30 * UI_(un)register... ui.h, non-transferable to trace reader :-(.
31 */
32
33// standard C includes -------------------------------
34#include <stdio.h>
35
36// standard C++/STL includes -------------------------------
37
38// project includes -------------------------------
39#include "system.h" // need g_nvcpus <--- NG.
40#include "ui.h" // need UI_register and UI_unregister <--- NG.
41
42
43
44// program includes -------------------------------
45#include "../../system/util/include/atomic.h" // Argh!!!...
46#include "my_sparc.h"
47#include "sc_strings.h"
48#include "tt_strings.h"
49#include "trapcount.h"
50
51// boilerplate -------------------------------
52
53
54// local definitions -------------------------------
55#define BAD14 1 /* can't count 0x04e traps as interval timer any more */
56
57
58// global variables -------------------------------
59
60 // global state
61static int CountingOn = 1;
62
63 // feature options
64
65
66 // debug options
67static int DEBUG = 0;
68static int VERBOSE = 0;
69
70
71// global functions -------------------------------
72
73
74#if 0 /* we want more flexibility that Safari/Serengeti constraints allow */
75// from Serengeti Specification (an implementation of Safari Bus)
76 // lower 5-bits are AgentId
77#define ISCPUID(x) (((x) & 0x1f) < 24) // AgentIDs 0..23 = cpus
78#define ISSCHIZOID(x) (((x) & 0x1f) >= 24) // AgentIDs 24..31 = schizos
79 // and upper 4-bits are NodeId.
80#else
81// x = SystemId = NodeId<<5+AgentId
82#define ISCPUID(x) (get_vcpu(x) != NULL)
83#define ISSCHIZOID(x) (get_vcpu(x) == NULL)
84#endif
85
86
87
88
89#define UNPACKINOAID(i) (((i >> 4) & 0x1e0) | 0x18 | ((i >> 6) & 0x7))
90
91
92
93// ===================================================================== MODULE
94
95
96static const char * mode_names[10];
97
98static trapcount * the_trapcount = NULL;
99
100extern "C" void * vtracer_init (const char * instname) // --------- module init
101{
102 if (the_trapcount == NULL) {
103 the_trapcount = new trapcount (instname);
104 UI_register_cmd_2 ("trapcount", "", trapcount::trapcount_ui_cmds, NULL);
105 } else
106 fprintf(stderr, "Error: trapcount already module_init'ed\n");
107 return (void*) the_trapcount;
108}
109
110extern "C" void vtracer_fini () // -------------------------------- module fini
111{
112 if (the_trapcount != NULL) {
113 UI_invalidate_cmd ("trapcount"); /* aka: UI_unregister_cmd */
114 delete the_trapcount;
115 the_trapcount = NULL;
116 } else
117 fprintf(stderr, "Error: trapcount already module_fini'ed\n");
118}
119
120
121
122
123Counters::Counters () // -------------------------------------------- ctor
124{
125 Reset ();
126}
127
128
129void Counters::Reset ()
130{
131 instrcount = 0LL;
132 hypercount = 0LL;
133 kernelcount = 0LL;
134 usercount = 0LL;
135 for (int i=0; i<MAX_TRAPTYPES; i++) traptypecount[i] = 0LL;
136 for (int i=0; i<MAX_SYSCALLS; i++) syscallscount[i] = 0LL;
137 for (int i=0; i<MAX_NCPUS; i++) mondoxcalcount[i] = 0LL;
138 // for (int i=0; i<MAX_INOS; i++) mondoinocount[i] = 0LL;
139 for (inoiter ip=mondoinocount.begin();
140 ip!=mondoinocount.end();
141 ip++)
142 ip->second = 0LL;
143 // alternatively...
144 // mondoinocount.erase (mondoinocount.begin(), mondoinocount.end());
145}
146
147
148
149
150
151
152
153trapcount::trapcount (const char * tmp_modname) // ======================= CTOR
154{
155 printf("trapcount::ctor (modname=>\"%s\"), numcpus=%d \n",
156 tmp_modname, g_nvcpu);
157
158 mode_names[MODE_NONE] = "none";
159 mode_names[MODE_AGGREGATE] = "aggregate";
160 mode_names[MODE_BY_CPU] = "cpu";
161 mode_names[MODE_BY_MMUCNTX] = "mmucntx";
162 mode_names[MODE_BY_THREAD] = "thread";
163
164 intervalsCounter = 0;
165
166 mode = MODE_NONE;
167 configure_for_mode (MODE_BY_CPU); // <--- default mode <---
168
169 numcpus = g_nvcpu; /* system.h - cpu_interface.h (argh!) */
170 // numschizos = ???; /* need to know all Agent IDs ??? ... */
171}
172
173trapcount::~trapcount () // ============================================== DTOR
174{
175}
176
177/*static*/
178int trapcount::trapcount_ui_cmds (void*notused, int argc, char *argv[])
179{
180 if (strcmp (argv[0], "trapcount") != 0) return 0;
181
182 if (argc == 1) { // status
183 printf ("trapcount: counting = %s, mode = %s.\n",
184 (CountingOn ? "on" : "off"),
185 mode_names[the_trapcount->mode]);
186 return 1;
187 }
188
189 if (argc >= 2 && strcmp (argv[1], "mode") == 0) { // mode
190 if (argc >= 3) {
191 if (strcmp (argv[2], "aggregate") == 0)
192 the_trapcount->configure_for_mode (MODE_AGGREGATE);
193 else if (strcmp (argv[2], "cpu") == 0)
194 the_trapcount->configure_for_mode (MODE_BY_CPU);
195 else if (strcmp (argv[2], "mmucntx") == 0)
196 the_trapcount->configure_for_mode (MODE_BY_MMUCNTX);
197 else if (strcmp (argv[2], "thread") == 0)
198 the_trapcount->configure_for_mode (MODE_BY_THREAD);
199 else
200 printf (" * unrecognized mode arg\n");
201 }
202 fprintf (stderr, "trapcount mode is %s\n",
203 mode_names[ the_trapcount->mode ]);
204 return 1;
205 }
206
207 if (argc >= 2 && strcmp (argv[1], "peek") == 0) { // peek
208 the_trapcount->printCounts (0/*dont reset*/);
209 return 1;
210 }
211
212 if (argc >= 2 && (strcmp (argv[1], "print") == 0 // print
213 || strcmp (argv[1], "stats") == 0)) { // stats
214 the_trapcount->printCounts (1/*do reset*/);
215 return 1;
216 }
217
218 if (argc >= 2 && strcmp (argv[1], "debug") == 0) { // debug
219 if (argc == 3) { DEBUG = (int) strtol (argv[2], NULL, 0); }
220 fprintf (stderr, "trapcount debug level is %d\n", DEBUG);
221 return 1;
222 }
223
224 if (strcmp (argv[1], "on") == 0) { // On/Off
225 CountingOn = 1;
226 return 1;
227 }
228 if (strcmp (argv[1], "off") == 0) {
229 CountingOn = 0;
230 return 1;
231 }
232
233
234
235
236 return 0;
237}
238
239
240
241int trapcount::attach (VTracer_SAM_intf * sam_intf)
242{
243 return 0; // do nothing...
244}
245
246
247
248// -------- friendly reminder --------
249//class Counters {
250//public:
251// int64 instrcount,
252// kernelcount,
253// usercount;
254// int64 traptypecount[ MAX_TRAPTYPES ];
255// int64 syscallscount[ MAX_SYSCALLS ];
256// int64 mondoxcalcount[ MAX_NCPUS ];
257// //int64 mondoinocount[ MAX_INOS ];
258// inoarray64_t mondoinocount;
259//
260// Counters ();
261//};
262
263
264void trapcount::printCounts (int reset) // ======================= print counts
265{
266 switch (mode) {
267
268 case MODE_AGGREGATE: {
269
270 printf (" aggregate: %12lld-instrs %12lld-kernel %12lld-user \n",
271 aggregate->instrcount,
272 aggregate->kernelcount,
273 aggregate->usercount);
274
275 for (int i=0; i<MAX_TRAPTYPES; i++)
276 if (aggregate->traptypecount[ i ])
277 printf (" tt-0x%03x %12lld %s\n",
278 i,
279 aggregate->traptypecount[ i ],
280 tt_names[ i ]);
281
282 for (int i=0; i<MAX_SYSCALLS; i++)
283 if (aggregate->syscallscount[ i ])
284 printf (" sc-0x%03x %12lld %s\n",
285 i,
286 aggregate->syscallscount[ i ],
287 sc_names[ i ]);
288
289 for (inoiter ip=aggregate->mondoinocount.begin();
290 ip!=aggregate->mondoinocount.end();
291 ip++)
292 if (ip->second != 0) /*aggregate->mondoinocount[i] != 0)*/
293 printf (" zm-0x%03x %12lld (%02x,%02x) \n",
294 ip->first, /*i,*/
295 ip->second, /*aggregate->mondoinocount[ i ],*/
296 ip->first >> 6, /*i >> 6,*/ // NodeID and AgentID
297 ip->first & 0x3f); /*i & 0x3f);*/ // DeviceNo
298
299 for (int i=0; i<MAX_NCPUS; i++)
300 if (aggregate->mondoxcalcount[ i ])
301 printf (" xm-0x%03x %12lld \n",
302 i,
303 aggregate->mondoxcalcount[ i ]);
304
305 if (reset) aggregate->Reset ();
306 printf ("\n");
307
308 } break;
309
310 case MODE_BY_CPU: {
311 // someday: put each cpu in a column...
312
313 for (int j=0; j<numcpus; j++) {
314
315 printf (" cpu[%d]::: %12lld-instrs %12lld-kernel %12lld-user \n",
316 j,
317 cpus[j].instrcount,
318 cpus[j].kernelcount,
319 cpus[j].usercount);
320
321 for (int i=0; i<MAX_TRAPTYPES; i++)
322 if (cpus[j].traptypecount[ i ])
323 printf (" tt-0x%03x %12lld %s\n",
324 i,
325 cpus[j].traptypecount[ i ],
326 tt_names[ i ]);
327
328 for (int i=0; i<MAX_SYSCALLS; i++)
329 if (cpus[j].syscallscount[ i ])
330 printf (" sc-0x%03x %12lld %s\n",
331 i,
332 cpus[j].syscallscount[ i ],
333 sc_names[ i ]);
334
335 for (inoiter ip=cpus[j].mondoinocount.begin();
336 ip!=cpus[j].mondoinocount.end();
337 ip++)
338 if (ip->second != 0) /*cpus[j].mondoinocount[i] != 0)*/
339 printf (" md-0x%03x %12lld (%02x,%02x) \n",
340 ip->first, /*i,*/
341 ip->second, /*cpus[j]->mondoinocount[ i ],*/
342 ip->first >> 6, /*i >> 6,*/ // NodeID and AgentID
343 ip->first & 0x3f); /*i & 0x3f);*/ // DeviceNo
344
345 for (int i=0; i<MAX_NCPUS; i++)
346 if (cpus[j].mondoxcalcount[ i ])
347 printf (" md-0x%03x %12lld \n",
348 i,
349 cpus[j].mondoxcalcount[ i ]);
350
351
352 if (reset) cpus[j].Reset ();
353 printf ("\n");
354
355 }/*end-for-cpu*/
356
357 } break;
358
359 default:
360 printf ("printing mode %s not currently supported\n", mode_names[mode]);
361 }
362}
363
364
365
366void trapcount::configure_for_mode (modes newmode) // ======= configure mode
367{
368 if (newmode == mode)
369 return; // we're already there...
370
371 // allocate new counters
372 //
373 switch (newmode) {
374 case MODE_NONE:
375 break;
376 case MODE_AGGREGATE:
377 aggregate = new Counters;
378 break;
379 case MODE_BY_CPU:
380 cpus = new Counters[MAX_NCPUS]; // array, be careful at delete!
381 break;
382 case MODE_BY_MMUCNTX:
383 mmucntxs = new MmucntxCounters;
384 break;
385 case MODE_BY_THREAD:
386 threads = new ThreadCounters;
387 break;
388 default:
389 mode = MODE_NONE;
390 fprintf(stderr, "Trapcount error: unimplemented mode\n");
391 }
392
393 // warning: deleting the old counters creates a race condition...
394 // which is worse (fatal!) than the alternative, a memory leak...
395#if 0
396 // deallocate previous counters
397 //
398 switch (mode) {
399 case MODE_NONE:
400 break;
401 case MODE_AGGREGATE:
402 delete aggregate;
403 aggregate = NULL;
404 break;
405 case MODE_BY_CPU:
406 delete [] cpus;
407 cpus = NULL;
408 break;
409 case MODE_BY_MMUCNTX:
410 delete mmucntxs;
411 mmucntxs = NULL;
412 break;
413 case MODE_BY_THREAD:
414 delete threads;
415 threads = NULL;
416 break;
417 default:
418 fprintf(stderr, "Trapcount error: unimplemented mode\n");
419 }
420#endif
421
422 // finally, update mode
423 //
424 mode = newmode;
425}
426
427
428
429// ================================= TRACER =================================
430
431
432
433int trapcount::instr (VCPU_Instruction * vi) // ======================== INSTR
434{
435 if (!CountingOn) return 0;
436
437 if (vi->ifetch_trap) { // fake instruction in case analyzer needs pc
438 return 0;
439 }
440
441 if (vi->annul) { // annulled (non-executed) delay slot instr
442 return 0;
443 }
444
445 // being consistent with HW-perf-counters and cpustat, which do not count
446 // annulled, mispredicted, or trapped instructions - only retired ones.
447 //
448 if (vi->dmmu_trap
449 || vi->exception) {
450 return 0;
451 }
452
453
454#if 0
455 spix_sparc_inst_t spixter; spixter.inst = rsp->instr.instr;
456 spix_sparc_iop_t iop =
457 spix_sparc_iop(SPIX_SPARC_V9, &((rsp->instr).instr));
458 if (iop == SPIX_SPARC_IOP_WRASR) {
459
460 switch (spixter.memarithr.rd) {
461 case ASR_SSI: /*0x14*/
462 fprintf (stderr, "SET_SOFTINT = 0x08x\n", ???);
463 case ASR_CSI: /*0x15*/
464 fprintf (stderr, "CLR_SOFTINT = 0x08x\n", ???);
465 case ASR_SFTINT: /*0x16*/
466 fprintf (stderr, "WR_SOFTINT = 0x08x\n", ???);
467 }
468 }
469#endif
470
471
472 if (mode == MODE_AGGREGATE) {
473 ++ aggregate->instrcount;
474
475 if (vi->hpstate & HPSTATE_PRIV) {
476 ++ aggregate->hypercount;
477 } else if (vi->pstate & PSTATE_PRIV) {
478 ++ aggregate->kernelcount;
479 } else {
480 ++ aggregate->usercount;
481 }
482 } else if (mode == MODE_BY_CPU) {
483 ++ cpus[ vi->cpuid ].instrcount;
484
485 if (vi->hpstate & HPSTATE_PRIV) {
486 ++ aggregate->hypercount;
487 } else if (vi->pstate & PSTATE_PRIV) {
488 ++ cpus[ vi->cpuid ].kernelcount;
489 } else {
490 ++ cpus[ vi->cpuid ].usercount;
491 }
492#if 0
493 } else if (mode == MODE_BY_MMUCNTX) {
494 ++ mmucntxs[ ??? ]->instrcount;
495
496 if (vi->pstate & PSTATE_PRIV) {
497 } else if (vi->hpstate & HPSTATE_PRIV) {
498 ++ aggregate->hypercount;
499 ++ mmucntxs[ ??? ]->kernelcount;
500 } else {
501 ++ mmucntxs[ ??? ]->usercount;
502 }
503 } else if (mode == MODE_BY_THREAD) {
504#endif
505 } else {
506 }
507 return 0;
508
509}/*instr*/
510
511
512
513int trapcount::trap (VCPU_Trap * vt) // ================================ TRAP
514{
515 if (!CountingOn) return 0;
516
517 if (DEBUG) {
518
519 if (!VERBOSE) { /* these are too obnoxious to display normally... */
520 if (vt->tno >= 0x080 && vt->tno <= 0x0ff) /* window-miss */
521 return 0;
522 if (vt->tno >= 0x024 && vt->tno <= 0x027) /* clean-win */
523 return 0;
524 if (vt->tno >= 0x064 && vt->tno <= 0x06f) /* tlb-miss */
525 return 0;
526 }
527
528 fprintf(stderr, "[cpu-%d] Trap 0x%03x %s ",
529 vt->cpuid, vt->tno, tt_names[vt->tno]);
530
531 if (vt->tno == 0x108 || vt->tno == 0x140) {
532 fprintf(stderr, " %d %s",
533 vt->syscallno, sc_names[ vt->syscallno ]);
534 }
535
536 if (vt->tno == 0x060) {
537 if (ISCPUID(vt->intrsid))
538 fprintf(stderr, " xcl SID = %d", vt->intrsid);
539 else
540// @@@
541 fprintf(stderr, " dev INO = 0x%03x (%02x,%02x)",
542 vt->intrino, (vt->intrino >> 6), (vt->intrino & 0x3f));
543 }
544
545#if !BAD14 /* Solaris uses level-14 for pci_pbm_dma_sync signalling, Yeuch! */
546 if (vt->tno == 0x04e && vt->cpuid == 0) {
547 fprintf(stderr," interval-timer count = %lld",
548 intervalsCounter+1);
549 }
550#endif
551
552 fprintf(stderr, "\n");
553
554 return 0;
555 }/*debug*/
556
557
558 if (mode == MODE_AGGREGATE) {
559
560 atomic_add_64 (&aggregate->traptypecount[ vt->tno ], +1);
561
562 if (vt->tno == 0x108/*syscall32*/ || vt->tno == 0x140/*syscall64*/) {
563
564 atomic_add_64 (&aggregate->syscallscount[ vt->syscallno ], +1);
565
566 } else if (vt->tno == 0x060/*mondo*/) {
567
568 if (ISCPUID(vt->intrsid))
569 atomic_add_64 (&aggregate->mondoxcalcount[ vt->intrsid ], +1);
570 else
571// @@@
572 atomic_add_64 (&aggregate->mondoinocount[ vt->intrino ], +1);
573
574 }
575
576 } else if (mode == MODE_BY_CPU) {
577
578 atomic_add_64 (&cpus[ vt->cpuid ].traptypecount[ vt->tno ], +1);
579
580 if (vt->tno == 0x108/*syscall32*/ || vt->tno == 0x140/*syscall64*/) {
581
582 atomic_add_64 (&cpus[ vt->cpuid ].syscallscount[ vt->syscallno ], +1);
583
584 } else if (vt->tno == 0x060/*mondo*/) {
585
586 if (ISCPUID(vt->intrsid))
587 atomic_add_64 (&cpus[ vt->cpuid ].mondoxcalcount[ vt->intrsid ], +1);
588 else
589// @@@
590 atomic_add_64 (&cpus[ vt->cpuid ].mondoinocount[ vt->intrino ], +1);
591
592 }
593#if 0
594 } else if (mode == MODE_BY_MMUCNTX) {
595
596 atomic_add_64 (&mmucntxs[ vt->??? ]->traptypecount[ vt->tno ], +1);
597
598 if (vt->tno == 0x108/*syscall32*/ || vt->tno == 0x140/*syscall64*/) {
599
600 atomic_add_64 (&mmucntxs[ vt->??? ]->syscallscount[ vt->syscallno ], +1);
601
602 } else if (vt->tno == 0x060/*mondo*/) {
603
604 if (ISCPUID(vt->intrsid))
605 atomic_add_64 (&mmucntxs[ vt->??? ]->mondoxcalcount[ vt->intrsid ], +1);
606 else
607// @@@
608 atomic_add_64 (&mmucntxs[ vt->??? ]->mondoinocount[ vt->intrino ], +1);
609
610 }
611
612 } else if (mode == MODE_BY_THREAD) {
613
614 atomic_add_64 (&threads[ vt->??? ]->traptypecount[ vt->tno ], +1);
615
616 if (vt->tno == 0x108/*syscall32*/ || vt->tno == 0x140/*syscall64*/) {
617
618 atomic_add_64 (&threads[ vt->??? ]->syscallscount[ vt->syscallno ], +1);
619
620 } else if (vt->tno == 0x060/*mondo*/) {
621
622 if (ISCPUID(vt->intrsid))
623 atomic_add_64 (&threads[ vt->??? ]->mondoxcalcount[ vt->intrsid ], +1);
624 else
625// @@@
626 atomic_add_64 (&threads[ vt->??? ]->mondoinocount[ vt->intrino ], +1);
627
628 }
629
630 } else if (mode == MODE_SEL_CPU) {
631
632 } else if (mode == MODE_SEL_MMUCNTX) {
633
634 } else if (mode == MODE_SEL_THREAD) {
635#endif
636 }
637
638#if !BAD14
639 if (vt->tno == 0x04e && vt->cpuid == 0) {
640 ++ intervalsCounter;
641 if ((intervalsCounter % 100) == 0) {
642 fprintf(stderr, "trapcount info: Solaris Seconds = %lld\n",
643 intervalsCounter/100);
644 //
645 // later this is where we'll format output
646 // according to the current `mode'.
647 //
648 }
649 }
650#endif
651
652 return 0;
653}
654
655
656
657// when a tlb entry is updated automatically by a hw-table-walk...
658//
659int trapcount::tlb (VCPU_TLB * ti) // ================================== TLB
660{
661 if (!CountingOn) return 0;
662
663 return 0;
664}
665
666
667
668// these are dma and string records generated (asynchronously)
669// by device simulators
670//
671int trapcount::async (VCPU_AsyncData * di) // ========================== ASYNC
672{
673 if (!CountingOn) return 0;
674
675 return 0;
676}
677
678
679
680// local- and global- time-sync records
681//
682int trapcount::sync (VCPU_Sync * si) // ================================ SYNC
683{
684 if (!CountingOn) return 0;
685
686 return 0;
687}
688
689
690
691
692
693
694
695// ----- out-of-place and/or misnamed functions ... ? -----
696//
697
698int trapcount::process_ui_cmd (int argc, char *argv[])
699{
700 return 1;
701}
702
703int trapcount::parse_args_v4(int argc, const char * tmp_argv[])
704{
705 return 1;
706}
707
708int trapcount::parse_args_v5(int argc, const char * tmp_argv[])
709{
710 return 1;
711}
712
713void trapcount::trace_on()
714{
715}
716
717void trapcount::print_status()
718{
719}
720
721void trapcount::trace_off()
722{
723}
724
725
726
727
728#if 0 // ---------------- implementation notes ---------------- //
729/*
730 * Mondo-Interrupts:
731 *
732 * Cross-cpu interrupts are Mondo (0x060) traps with
733 * IRSR (Interrupt Receive Status Register)
734 * contains the source [NodeId, x, AgentId]
735 * IRDR0 (Interrupt Receive Data Register #0)
736 * contains the entry point address of
737 * the requested service function !!!
738 *
739 * External interrupts are also Mondo (0x060) traps with
740 * IRSR (Interrupt Receive Status Register)
741 * contains the source [NodeId, x, AgentId]
742 * IRDR0 (Interrupt Receive Data Register #0)
743 * contains the (Solaris assigned) INO
744 * of the device, where:
745 * INO = NodeID << 11 | AgentID << 6 | DeviceNo
746 *
747 * the IRSR contains a "busy-bit" in between the NodeID and AgentID
748 * so the combined SystemID is not in contiguous bits :-(((.
749 * the INO does not, its SystemID are contiguous bits :-)!
750 *
751 *
752 *
753 * Not to be confused with SoftInts which are traps 0x041...0x04f
754 *
755 * Note that SoftInt 0x04e is (oxymoronically) hardware generated,
756 * and is the stick interval timer.
757 * Except...., in S10 the INO-DeviceID 0x035 interrupts come from Schizo
758 * for the pci_pbm_dma_sync() calls in the drivers, and they also set
759 * SoftInt 0x04e :-(((((!~ Yeuch!!!
760 *
761 *
762 */
763#endif