1 /*
2 ANSI C Runtime Library
3
4 Copyright 1983-2000 Green Hills Software, Inc.
5
6 This program is the property of Green Hills Software, Inc,
7 its contents are proprietary information and no part of it
8 is to be disclosed to anyone except employees of Green Hills
9 Software, Inc., or as agreed in writing signed by the President
10 of Green Hills Software, Inc.
11 */
12
13 /* This file contains i960 Profiling routines working on the Intel MON960 */
14
15 #if defined(__i960)
16 #include "indos.h"
17 #include "ind_exit.h"
18 static int ProfCount; /* number of entries in ProfBuf */
19
20 /* A larger ProfBuf means more samples collected on the target before stopping
21 * to send them up to 960SERV - more target memory traded for faster profiling.
22 */
23
24 static unsigned int ProfBuf[100]; /* array of PC samples */
25
26 /* Someday, rewrite the following asm() code to use SVR4 ASM PROCS */
27
28 /*------------------------------------------------------*/
29 /* mon960 system calls to enable and disable tracing */
30 /*------------------------------------------------------*/
31 #ifndef __EDG__
32 #pragma ghs Xkeepsaverestore
33 #endif
34 /* This pragma turns off leaf routine optimization. This is ensures */
35 /* that arguments to the following asm routines don't get clobbered. */
36
37 /* enable trace fault by setting 1st bit in PC */
38
trace_enable(void)39 static void trace_enable(void)
40 {
41 asm(" mov 1, g0");
42 asm(" modpc 1, 1, g0"); /* set bit 0 (TE) of PC */
43 asm(" or g0, g0, g0"); /* nop */
44 asm(" or g0, g0, g0"); /* nop */
45 asm(" or g0, g0, g0"); /* nop */
46 }
47
48 /* disable trace fault by clearing 1st bit in PC */
trace_disable(void)49 static void trace_disable(void)
50 {
51 asm(" mov 0, g0");
52 asm(" modpc 1, 1, g0");
53 asm(" or g0, g0, g0"); /* nop */
54 asm(" or g0, g0, g0"); /* nop */
55 asm(" or g0, g0, g0"); /* nop */
56 }
57
58
59 /*-----------------------------------------------------------------*/
60 /* timer class: set, initialize, terminate, and service interrupts */
61 /*-----------------------------------------------------------------*/
62
63 /* This pragma turns off leaf routine optimization. This is ensures */
64 /* that arguments to the following asm routines don't get clobbered. */
65
timer_set(int client,int timer,void * isr)66 static void timer_set(int client, int timer, void *isr)
67 {
68 asm(" lda 249, g4");
69 asm(" calls g4");
70 }
71
timer_init(int freq)72 static void timer_init(int freq)
73 {
74 asm(" lda 243, g4");
75 asm(" calls g4");
76 }
77
timer_term(void)78 static void timer_term(void)
79 {
80 asm(" lda 246, g4");
81 asm(" calls g4");
82 }
83
84 /*--------------------------------------*/
85 /* timer ISR: interrupt service routine */
86 /*--------------------------------------*/
87
88 /* MON960 calls this profiling Interrupt Service Routine for each timer */
89 /* expiration/interrupt. IP is the user IP when the interrupt happens. */
90 /* A "good" frequency does not interrupt too often: about 50-60 Hz. */
91 /* The timer interrupts at 1000 Hz. Every 20th interrupt yields 50 Hz. */
92
timer_isr(unsigned int IP)93 static void timer_isr(unsigned int IP)
94 {
95 static int cnt;
96
97 if (++cnt < 20) return;
98 cnt = 0;
99
100 ProfBuf[ProfCount++] = IP; /* works first time since */
101 /* ProfCount is 0 (in BSS) */
102
103 /* if the profile buffer is full, write it out */
104
105 if (ProfCount >= sizeof(ProfBuf)/sizeof(ProfBuf[0])) {
106 /* allow the special syscall bp by enabling trace faults */
107 trace_enable();
108
109 /* write the full profile buffer to the host server */
110 __ghs_syscall(17 /* SYSCALL_MANPROF */, ProfBuf, ProfCount);
111
112 trace_disable();
113 ProfCount = 0;
114 }
115 }
116
117 #ifndef __EDG__
118 #pragma ghs Zkeepsaverestore
119 #endif
120
_stopmon(void)121 static void _stopmon(void)
122 {
123 if (ProfCount)
124 __ghs_syscall(17 /* SYSCALL_MANPROF */, ProfBuf, ProfCount);
125 timer_term();
126 }
127
_startmon960(void)128 void _startmon960(void)
129 {
130 /* These two variables are defined in crt0.960 */
131 extern int _gh_pflag;
132 static struct __GHS_AT_EXIT gae;
133
134 /* 960SERV sets _gh_pflag to 1 to enable profiling. */
135
136 if (!_gh_pflag) return;
137
138 /* On program exit, run the _stopmon cleanup routine. */
139
140 gae.func = _stopmon;
141 __ghs_at_exit(&gae);
142 gae.func = _stopmon;
143
144 timer_set(0, 0, (void *) timer_isr);
145
146 /* The default timer frequency value is 2, meaning 1000 Hz */
147 /* (an interrupt every 1 ms). Intel told us that 1000 Hz */
148 /* is the ONLY frequency currently supported by mon960. */
149
150 timer_init(2);
151 }
152 #endif /* __i960 */
153