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