Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / system / blaze / include / workerthread.h
CommitLineData
920dae64
AT
1/*
2* ========== Copyright Header Begin ==========================================
3*
4* OpenSPARC T2 Processor File: workerthread.h
5* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
6* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
7*
8* The above named program is free software; you can redistribute it and/or
9* modify it under the terms of the GNU General Public
10* License version 2 as published by the Free Software Foundation.
11*
12* The above named program is distributed in the hope that it will be
13* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15* General Public License for more details.
16*
17* You should have received a copy of the GNU General Public
18* License along with this work; if not, write to the Free Software
19* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
20*
21* ========== Copyright Header End ============================================
22*/
23/* standard includes */
24#include <pthread.h>
25#include <synch.h>
26#include <signal.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <errno.h>
30#include <assert.h>
31#include <list>
32
33/* project includes */
34#include "types.h"
35#include "blaze_globals.h"
36#include "ui.h"
37#include "system.h"
38#include "system_impl.h"
39#include "atomic.h"
40#include "tracemod.h"
41#include "prioque.h"
42#include "cpu_interface.h"
43#include "vtracer_async_queue.h"
44
45
46extern "C" {
47 static inline void * system_worker_thread (void * arg);
48};
49
50class WorkerThread {
51
52 static Vcpu * first_cpu;
53
54 static volatile uint64_t GlobalTimeUsecs;
55 //
56 // each workerthread maintains a local copy time variable, which is
57 // used for comparison in doEventQueueCallbacks()
58 //
59 volatile uint64_t simTime;
60
61
62 // approximate tick count per cpu/strand. only for "mips" ui-cmd,
63 // this is currently Broken ~!~
64 static volatile int64_t GlobalTicks;
65
66
67 static WorkerThread * wrkthds; // worker thread array
68 static volatile int numThds; // total number of workerthreads
69
70 pthread_t tid; // the real worker thread
71 int worker_id; // 0..numthds-1
72 int num_cpus; // # of vcpu's assigned to this workerthread
73 Vcpu *cpus[MAX_MP]; // pointers to vcpu's assigned to this thread,
74 // index = [0 ... num_cpus - 1]
75
76 EventQue * eq; // per worker thread event queue
77
78 static pthread_key_t key; // to bind the eq to workerthread's private data
79
80 int64_t done_x_1024[MAX_MP];
81
82 WorkerThread(){
83 called_from_stept = false;
84 KillThread = false;
85 Nusecs = Ninstrs = Ncycles = 0;
86 sema_init (&KICK,0, USYNC_THREAD, NULL);
87 assert (pthread_create (&tid,NULL, &system_worker_thread, (void*)this) == 0);
88 eq = new EventQue();
89 /////assert (pthread_setspecific(key,(void *) this) == 0);
90 simTime = GlobalTimeUsecs;
91 }
92
93 ~WorkerThread(){
94 sema_destroy (&KICK);
95 delete eq;
96 }
97
98
99 sema_t KICK; // <--- KICK semaphores
100 bool KillThread;
101 static int64_t Nusecs; /* stept microseconds */
102 static int64_t Ninstrs; /* stepi instruction count */
103 static int64_t Ncycles; /* for exec-driven mode */
104
105 static volatile int BarrierCount;
106 static volatile int BarrierLock;
107 static volatile int BarrierTemp;
108 static volatile uint64_t step_remainder; /* see note in .cc for explanation */
109
110 static volatile uint64_t stick_incr;
111 // to allow for stick frequencies that are not a multiple of 10^6
112 static volatile uint64_t stick_remainder;
113
114 void stepi(uint64_t n);
115 void stept(uint64_t usecs);
116 void stepc(int64_t ncycles);
117 int barrier();
118 static void kill_worker_threads ();
119
120 bool called_from_stept;
121
122 void killThread(){
123 KillThread = true;
124 sema_post (&KICK);
125 }
126
127 void doEventqueCallbacks (){
128 Event_t event;
129
130 while (! eq->empty()
131 && eq->top_time() <= simTime ) {
132
133 eq->get_top (&event);
134 (*(EventFunc_T*)event.pq_cbfunc) (event.pq_cbarg1, event.pq_cbarg2);
135 }
136 }
137
138
139 void doTrace() {
140 if (cpus[0] == first_cpu) {
141 while (trace_async_queue->getsize()) {
142 VCPU_AsyncData async_rec;
143 trace_async_queue->dequeue(&async_rec);
144 first_cpu->sys_intf.vtrace->async(&async_rec);
145 } // if this is the first cpu in the system
146 }
147
148 // write sync records to all cpus. Use GlobalTimeUsecs as a possible seq #
149 vtracer_syncinfo syncinfo;
150 syncinfo.synctype = vtracer_syncinfo::synctype_LOCAL;
151 syncinfo.syncid = GlobalTimeUsecs;
152 syncinfo.data = 0;
153 int i;
154 for (i=0; i<num_cpus; i++) {
155 syncinfo.cpuid = cpus[i]->id();
156 cpus[i]->sys_intf.vtrace->sync(&syncinfo);
157 }
158
159 }
160
161
162public:
163 // external interface exported by workerthreads
164
165 void run_workerThread(){
166 assert (pthread_setspecific(key,(void *) this) == 0);
167 for (;;) {
168 sema_wait (&KICK); // --------------------------------- STANDBY !!!
169
170 if (KillThread) {
171 pthread_exit (0);
172 tid = 0;
173 }
174 if (Nusecs)
175 stept(Nusecs);
176 else if(Ninstrs)
177 stepi(Ninstrs);
178 else if (Ncycles)
179 stepc(Ncycles);
180 }
181 }
182 static void kick_stepi(uint64_t n){
183 // initialize the stick related variabled
184 stick_incr = the_arch.stick_freq/1000000ull;
185
186 if(!wrkthds)
187 create_worker_threads (SYSTEM_get_ncpu(),SYSTEM_get_cpus_per_thread(),\
188 SYSTEM_get_numthreads());
189 Ninstrs = n; Nusecs = 0; Ncycles = 0;
190 for (int i = 0; i < numThds; i++)
191 sema_post (&wrkthds[i].KICK);
192 }
193
194 static void kick_stept(uint64_t usecs){
195 // initialize the stick related variabled
196 stick_incr = the_arch.stick_freq/1000000ull;
197
198 if(!wrkthds)
199 create_worker_threads (SYSTEM_get_ncpu(),SYSTEM_get_cpus_per_thread(), \
200 SYSTEM_get_numthreads());
201 Nusecs = usecs; Ninstrs = 0; Ncycles = 0;
202 for (int i = 0; i < numThds; i++)
203 sema_post (&wrkthds[i].KICK);
204 }
205
206 static void kick_stepc(int64_t ncycles) {
207 stick_incr = the_arch.stick_freq/1000000ull;
208 if (!wrkthds)
209 create_worker_threads(SYSTEM_get_ncpu(), SYSTEM_get_ncpu(), 1);
210
211 Ncycles = ncycles; Nusecs = Ninstrs = 0;
212 sema_post(&wrkthds[0].KICK);
213 }
214
215 void info(){
216 ui->verbose("sid = {");
217 for (int j=0; j < num_cpus; j++)
218 {
219 if (j>0) ui->verbose (",");
220 ui->verbose ("%d", cpus[j]->id());
221 }
222 ui->verbose ("} \n");
223 }
224
225
226
227 static void registerEvent (uint64_t stime,
228 EventFunc_T* callbackfunc, void* arg1, void* arg2,
229 UnloadFunc_T* unloadfunc,
230 const char * debugstring)
231 {
232 WorkerThread * wt = (WorkerThread*) pthread_getspecific (key);
233 EventQue * myeq = wt ? wt->eq : 0;
234 if (!myeq) {
235
236 if (!wrkthds) {
237
238 create_worker_threads(SYSTEM_get_ncpu(),
239 SYSTEM_get_cpus_per_thread(),
240 SYSTEM_get_numthreads());
241 }
242 myeq = wrkthds[0].eq;
243 }
244
245 myeq->insert_callback ( stime, (void*)callbackfunc, arg1, arg2,
246 (void*)unloadfunc, debugstring,
247 (wt ? wt->worker_id : -1));/*more debug*/
248 }
249
250
251 static void doEventqueUnloads ()
252 {
253 for (int i = 0; i < numThds; i++)
254 wrkthds[i].eq->unload();
255 }
256
257
258 static void doEventquePrint ()
259 {
260 for (int i = 0; i < numThds; i++)
261 wrkthds[i].eq->print ();
262 }
263
264
265
266
267 static void create_worker_threads (int NumCpus, int cpusPerThread, int numThreads);
268
269 // store any needed parameter in the form of NAME VALUE pair in fp
270 static void dump(FILE * fp);
271 // restore parameters stored in the form of NAME VALUE pair from fp
272 static int restore(char * line);
273
274
275 static uint64_t get_time(){
276 WorkerThread * wt = (WorkerThread*) pthread_getspecific(key);
277
278 return (wt ? wt->simTime : GlobalTimeUsecs);
279 }
280
281
282 static int64_t get_ticks(){ return GlobalTicks;}
283
284
285 static volatile int64_t u_instrs; // for "mips" ui command
286 static volatile int64_t k_instrs;
287
288 static volatile int64_t u_intervals; // ditto
289 static volatile int64_t k_intervals;
290};
291
292extern "C" {
293 static inline void * system_worker_thread (void * arg){
294 WorkerThread * sp = (WorkerThread*) arg;
295 sp->run_workerThread();
296 return 0;
297 }
298};
299