Commit | Line | Data |
---|---|---|
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 | ||
39 | N2_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 | ||
125 | void 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 | /*}}}*/ | |
131 | void 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 | /*}}}*/ | |
137 | void 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 | ||
147 | void 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 | ||
187 | void 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 | ||
196 | void 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 | ||
250 | SS_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 | /*}}}*/ | |
281 | SS_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 | /*}}}*/ | |
314 | SS_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 | /*}}}*/ | |
334 | SS_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 | /*}}}*/ | |
354 | SS_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 | /*}}}*/ | |
374 | SS_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 | /*}}}*/ | |
385 | SS_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 | ||
397 | void 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 | ||
423 | SS_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 | ||
463 | SS_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 | /*}}}*/ |