Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / cpus / vonk / n2 / lib / cpu / src / N2_Cpu.cc
CommitLineData
920dae64
AT
1// ========== Copyright Header Begin ==========================================
2//
3// OpenSPARC T2 Processor File: N2_Cpu.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/************************************************************************
22**
23** Copyright (C) 2006, Sun Microsystems, Inc.
24**
25** Sun considers its source code as an unpublished, proprietary
26** trade secret and it is available only under strict license provisions.
27** This copyright notice is placed here only to protect Sun in the event
28** the source is deemed a published work. Disassembly, decompilation,
29** or other means of reducing the object code to human readable form
30** is prohibited by the license agreement under which this code is
31** provided to the user or company in possession of this copy.
32**
33*************************************************************************/
34#include "N2_Cpu.h"
35#include "N2_Core.h"
36#include "N2_Strand.h"
37#include "SS_Signal.h"
38
39N2_Cpu::N2_Cpu( SS_Model& _model, const char* _name, uint_t strand_id_base )/*{{{*/
40 :
41 SS_Cpu(_model,_name),
42 mem_err_detector(&_model)
43{
44 uint_t i = 0;
45 for (uint_t c=0; c < N2_Model::NO_CORES_PER_CPU; c++)
46 {
47 char n[3] = "c%";
48 n[1] = '0' + c;
49 core[c] = new N2_Core(*this,n,strand_id_base + 8 * c);
50 if (core[c] == 0)
51 {
52 perror("malloc(new)");
53 exit(-1);
54 }
55
56 for (uint_t s=0; s < N2_Model::NO_STRANDS_PER_CORE; s++)
57 strand[i++] = core[c]->strand[s];
58 }
59 strand_count = N2_Model::NO_STRANDS_PER_CPU;
60
61 asi_map[0x41].add(0x00,this,&strand_available,
62 SS_SharedAsiCtrReg::ld64,0,
63 SS_SharedAsiCtrReg::rd64,set_strand_available);
64
65 asi_map[0x41].add(0x10,this,&strand_enable_status,
66 SS_SharedAsiCtrReg::ld64,0,
67 SS_SharedAsiCtrReg::rd64,0);
68
69 asi_map[0x41].add(0x20,this,&strand_enable,
70 SS_SharedAsiCtrReg::ld64,set_strand_enable,
71 SS_SharedAsiCtrReg::rd64,set_strand_enable);
72
73 asi_map[0x41].add(0x30,this,&xir_steering,
74 SS_SharedAsiCtrReg::ld64,set_xir_steering,
75 SS_SharedAsiCtrReg::rd64,set_xir_steering);
76
77 asi_map[0x41].add(0x38,this,&tick_enable,
78 SS_SharedAsiCtrReg::ld64,set_tick_enable,
79 SS_SharedAsiCtrReg::rd64,set_tick_enable);
80
81 asi_map[0x41].add(0x50,this,&strand_running,
82 SS_SharedAsiCtrReg::ld64,set_strand_running,
83 SS_SharedAsiCtrReg::rd64,set_strand_running);
84
85 asi_map[0x41].add(0x58,this,&strand_running_status,
86 SS_SharedAsiCtrReg::ld64,0,
87 SS_SharedAsiCtrReg::rd64,0);
88
89 asi_map[0x41].add(0x60,this,&strand_running,
90 0,set_strand_running_w1s,
91 0,set_strand_running_w1s);
92
93 asi_map[0x41].add(0x68,this,&strand_running,
94 0,set_strand_running_w1c,
95 0,set_strand_running_w1c);
96
97 asi_map[0x45].add(0x10,this,&overlap_mode,
98 0,SS_SharedAsiCtrReg::st64,
99 0,SS_SharedAsiCtrReg::wr64);
100
101 asi_map[0x45].add(0x18,this,&rst_vec_mask,
102 SS_SharedAsiCtrReg::ld64,rst_vec_st64,
103 SS_SharedAsiCtrReg::rd64,rst_vec_st64);
104
105 asi_map[0x73].add(0x0,this,0,
106 0,intr_w_st64,
107 0,intr_w_st64);
108
109 strand_enable_status.set_unmasked(~uint64_t(0));
110 strand_running_status.set_unmasked(1);
111 strand_available = ~uint64_t(0);
112 strand_enable = ~uint64_t(0);
113 strand_running = 1;
114 xir_steering = ~uint64_t(0);
115
116 change_running(strand_running_status());
117
118 for (uint_t s=0; s < N2_Model::NO_STRANDS_PER_CPU; s++)
119 strand[s]-> merge_asi_map();
120
121 hard_reset();
122}
123/*}}}*/
124
125void N2_Cpu::hard_reset()/*{{{*/
126{
127 for (uint_t c=0; c<N2_Model::NO_CORES_PER_CPU; c++)
128 core[c]->hard_reset();
129}
130/*}}}*/
131void N2_Cpu::warm_reset(bool intp)/*{{{*/
132{
133 for (uint_t c=0; c<N2_Model::NO_CORES_PER_CPU; c++)
134 core[c]->warm_reset(intp);
135}
136/*}}}*/
137void N2_Cpu::xtrn_reset()/*{{{*/
138{
139 xir_steering.lock();
140 for (uint_t s=0; s<N2_Model::NO_STRANDS_PER_CPU; s++)
141 if (xir_steering() & (uint64_t(1) << s))
142 strand[s]->xtrn_reset();
143 xir_steering.unlock();
144}
145/*}}}*/
146
147void N2_Cpu::snapshot( SS_SnapShot& ss )/*{{{*/
148{
149 char prefix[32];
150 get_name(prefix);
151
152 // First deal with the common base for snaphot.
153
154 SS_Cpu::snapshot(ss);
155
156 // Now handle the N2 specifics like CMP. Note we do not snapshot
157 // the strand_running_status, as it is restored by the call to
158 // strand_running_update on ss.do_load() below
159
160 strand_available.snapshot(ss,prefix);
161 strand_enable.snapshot(ss,prefix);
162 strand_enable_status.snapshot(ss,prefix);
163 strand_running.snapshot(ss,prefix);
164
165 // SS_Strand saves the running flags so we don;t have to call
166 // strand_running_update() here to propagate the running flags
167
168 xir_steering.snapshot(ss,prefix);
169 tick_enable.snapshot(ss,prefix);
170 tw_status.snapshot(ss,prefix);
171 overlap_mode.snapshot(ss,prefix);
172 intr_w.snapshot(ss,prefix);
173 rst_vec_mask.snapshot(ss,prefix);
174
175 for (int c=0; c<N2_Model::NO_CORES_PER_CPU; c++)
176 core[c]->snapshot(ss);
177
178 // Make sure that on snapshot load we propagate the strand running
179 // flags properly. E.g. the strands shoudl registers themselves
180 // with the TLB etc.
181
182 if (ss.do_load())
183 strand_running_update(0);
184}
185/*}}}*/
186
187void N2_Cpu::ras_enable(char*)/*{{{*/
188{
189 for (int c=0; c<N2_Model::NO_CORES_PER_CPU; c++)
190 core[c]->ras_enable(NULL);
191}
192/*}}}*/
193
194
195
196void N2_Cpu::strand_running_update( uint_t strand_id, int cosim, uint64_t data )/*{{{*/
197{
198 uint64_t chg, run;
199
200 strand_enable_status.lock();
201 strand_running.lock();
202 strand_running_status.lock();
203
204 chg = strand_running_status();
205
206 // In non cosim mode (0) update the running status directly.
207 // In cosim mode (1) we ignore the running status update and
208 // when we get a status update from rtl (2) we update it with data.
209 // This is done through the pli CMP_WRITE command.
210
211 if (cosim == 0)
212 strand_running_status.set_unmasked(strand_running() & strand_enable_status());
213 else if (cosim == 2)
214 strand_running_status.set_unmasked(data);
215
216 run = strand_running_status();
217
218 // The strand that wants to park every strand including itself will remain
219 // running. This is done to prevent the chip from stalling.
220
221 if (run == 0)
222 {
223 run = uint64_t(1) << (strand_id % BITS_PER_CMP_REGISTER);
224 strand_running_status.set_unmasked(run);
225 }
226
227 change_running(strand_running_status());
228
229 strand_running_status.unlock();
230 strand_running.unlock();
231 strand_enable_status.unlock();
232
233 // Find out which strands switched from running to parked or visa versa.
234 // Notify those strands through our signalling mechanism.
235
236 chg = chg ^ run;
237
238 for (int s = 0; s < 64; s++)
239 {
240 if ((chg >> s) & 1)
241 {
242 SS_Signal* sgn = SS_Signal::alloc(SS_Signal::RUNNING);
243 sgn->running = (run >> s) & 1;
244 strand[s]->post_signal(sgn);
245 }
246 }
247}
248/*}}}*/
249
250SS_AsiSpace::Error N2_Cpu::set_strand_available( SS_Node* _cpu, void*, SS_Strand* s, SS_Vaddr, uint64_t data )/*{{{*/
251{
252 N2_Cpu* cpu = (N2_Cpu*)_cpu;
253
254 cpu->strand_available.lock();
255 cpu->strand_enable.lock();
256 cpu->strand_enable_status.lock();
257 cpu->xir_steering.lock();
258
259 uint64_t byte = 0xff;
260 for (int i=0; i < 8; i++)
261 {
262 if ((data & byte) != byte)
263 data &= ~byte;
264 byte <<= 8;
265 }
266
267 cpu->strand_available.set_unmasked(data);
268 cpu->strand_enable_status.set_unmasked(cpu->strand_enable() & data);
269 cpu->xir_steering = data;
270
271 cpu->xir_steering.unlock();
272 cpu->strand_enable_status.unlock();
273 cpu->strand_enable.unlock();
274 cpu->strand_available.unlock();
275
276 cpu->strand_running_update(s->strand_id());
277
278 return SS_AsiSpace::OK;
279}
280/*}}}*/
281SS_AsiSpace::Error N2_Cpu::set_strand_enable( SS_Node* _cpu, void*, SS_Strand* s, SS_Vaddr, uint64_t data )/*{{{*/
282{
283 N2_Cpu* cpu = (N2_Cpu*)_cpu;
284
285 cpu->strand_available.lock();
286 cpu->strand_enable.lock();
287 cpu->strand_enable_status.lock();
288
289 uint64_t byte = 0xff;
290 for (int i=0; i < 8; i++)
291 {
292 if ((data & byte) != byte)
293 data &= ~byte;
294 byte <<= 8;
295 }
296
297 // Core 0 is the default enabled core if all are being disabled
298
299 if (data == 0)
300 data = 0xff;
301
302 cpu->strand_enable = data;
303 cpu->strand_enable_status.set_unmasked(cpu->strand_available() & data);
304
305 cpu->strand_enable.unlock();
306 cpu->strand_enable_status.unlock();
307 cpu->strand_available.unlock();
308
309 cpu->strand_running_update(s->strand_id());
310
311 return SS_AsiSpace::OK;
312}
313/*}}}*/
314SS_AsiSpace::Error N2_Cpu::set_strand_running( SS_Node* _cpu, void*, SS_Strand* s, SS_Vaddr, uint64_t data )/*{{{*/
315{
316 N2_Cpu* cpu = (N2_Cpu*)_cpu;
317
318 // In cosim we get CMP_WRITE pli messages to take care of
319 // timing issues, so just ignore the data here, it gets updated
320 // by the pli CMP_WRITE command.
321
322 if (!s->sim_state.cosim())
323 {
324 cpu->strand_running.lock();
325 cpu->strand_running = data;
326 cpu->strand_running.unlock();
327
328 cpu->strand_running_update(s->strand_id());
329 }
330
331 return SS_AsiSpace::OK;
332}
333/*}}}*/
334SS_AsiSpace::Error N2_Cpu::set_strand_running_w1s( SS_Node* _cpu, void*, SS_Strand* s, SS_Vaddr, uint64_t data )/*{{{*/
335{
336 N2_Cpu* cpu = (N2_Cpu*)_cpu;
337
338 // In cosim we get CMP_WRITE pli messages to take care of
339 // timing issues, so just ignore the data here, it gets updated
340 // by the pli CMP_WRITE command.
341
342 if (!s->sim_state.cosim())
343 {
344 cpu->strand_running.lock();
345 cpu->strand_running = cpu->strand_running() | data;
346 cpu->strand_running.unlock();
347
348 cpu->strand_running_update(s->strand_id());
349 }
350
351 return SS_AsiSpace::OK;
352}
353/*}}}*/
354SS_AsiSpace::Error N2_Cpu::set_strand_running_w1c( SS_Node* _cpu, void*, SS_Strand* s, SS_Vaddr, uint64_t data )/*{{{*/
355{
356 N2_Cpu* cpu = (N2_Cpu*)_cpu;
357
358 // In cosim we get CMP_WRITE pli messages to take care of
359 // timing issues, so just ignore the data here, it gets updated
360 // by the pli CMP_WRITE command.
361
362 if (!s->sim_state.cosim())
363 {
364 cpu->strand_running.lock();
365 cpu->strand_running = cpu->strand_running() &~ data;
366 cpu->strand_running.unlock();
367
368 cpu->strand_running_update(s->strand_id());
369 }
370
371 return SS_AsiSpace::OK;
372}
373/*}}}*/
374SS_AsiSpace::Error N2_Cpu::set_xir_steering( SS_Node* _cpu, void*, SS_Strand* s, SS_Vaddr, uint64_t data )/*{{{*/
375{
376 N2_Cpu* cpu = (N2_Cpu*)_cpu;
377
378 cpu->xir_steering.lock();
379 cpu->xir_steering = data & cpu->strand_enable_status();
380 cpu->xir_steering.unlock();
381
382 return SS_AsiSpace::OK;
383}
384/*}}}*/
385SS_AsiSpace::Error N2_Cpu::set_tick_enable( SS_Node* _cpu, void*, SS_Strand* s, SS_Vaddr, uint64_t data )/*{{{*/
386{
387 N2_Cpu* cpu = (N2_Cpu*)_cpu;
388
389 cpu->tick_enable.lock();
390 cpu->tick_enable = data;
391 cpu->tick_enable.unlock();
392
393 return SS_AsiSpace::OK;
394}
395/*}}}*/
396
397void N2_Cpu::set_stepping( uint_t strand_id )/*{{{*/
398{
399 // set_strand_stepping() is called when a virtual cpu
400 // instance is created. This is so when Vonk is used in SAM.
401 // In that environment we adjust the strand_available flag
402 // accordingly; mimicing what the service processor should do.
403
404 SS_Cpu::set_stepping(strand_id);
405
406 strand_available.lock();
407 strand_enable_status.lock();
408
409 // Note we don't round strand_available of to the nearest core set of bits.
410 strand_available = strand_stepping[0];
411 strand_enable_status.set_unmasked(strand_enable() & strand_available());
412
413 strand_available.unlock();
414 strand_enable_status.unlock();
415
416 // Set the first strand_id from sam.rc as running; order of sysconf cpu
417 // lines in the sam.rc file does matter.
418
419 strand_running_update(strand_id);
420}
421/*}}}*/
422
423SS_AsiSpace::Error N2_Cpu::intr_w_st64( SS_Node* _cpu, void*, SS_Strand* s, SS_Vaddr, uint64_t data )/*{{{*/
424{
425 N2_Cpu* cpu = (N2_Cpu*)_cpu;
426 cpu->intr_w.lock();
427 cpu->intr_w = data;
428 uint_t strand_id = cpu->intr_w.strand();
429
430 // If the strand that is addressed by the cross call is
431 // enabled it will receive the cross calls. Otherwise
432 // the crosscall is dropped. In case the strand that is
433 // called is parked, we unpark it first.
434 //
435 // In cosim mode we drop the crosscall. For timing reasons
436 // we wait for the DUT to send the cross call INTP packet.
437
438 if (!s->sim_state.cosim() && (cpu->strand_enable_status() & (1 << (strand_id % BITS_PER_CMP_REGISTER))))
439 {
440 cpu->strand_running_status.lock();
441 if ((cpu->strand_running_status() & (1 << (strand_id % BITS_PER_CMP_REGISTER))) == 0)
442 {
443 cpu->strand_running_status.unlock();
444 cpu->strand_running.lock();
445 cpu->strand_running = cpu->strand_running() | (1 << (strand_id % BITS_PER_CMP_REGISTER));
446 cpu->strand_running.unlock();
447 cpu->strand_running_update(s->strand_id());
448 }
449 else
450 cpu->strand_running_status.unlock();
451
452 SS_Signal* sgn = s->msg.make_signal(SS_Signal::EXTERNAL_INTERRUPT);
453 sgn->irq_type = cpu->intr_w.vector();
454 sgn->irq_raise = true;
455 cpu->strand[strand_id]->post_signal(sgn);
456 }
457
458 cpu->intr_w.unlock();
459 return SS_AsiSpace::OK;
460}
461/*}}}*/
462
463SS_AsiSpace::Error N2_Cpu::rst_vec_st64( SS_Node* _cpu, void*, SS_Strand*, SS_Vaddr va, uint64_t data )/*{{{*/
464{
465 N2_Cpu* cpu = (N2_Cpu*)_cpu;
466 cpu->rst_vec_mask.lock();
467 cpu->rst_vec_mask.set(data);
468 cpu->rst_vec_mask.unlock();
469
470 // Now set the reset vectors of all the strands ... do we need to place
471 // locks around this or can we get away with this?
472
473 for (int s =0; s < N2_Model::NO_STRANDS_PER_CPU; s++)
474 cpu->strand[s]->rstv_addr = data ? 0x0 : 0xfffffffff0000000;
475 return SS_AsiSpace::OK;
476}
477/*}}}*/