Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / legion / src / procs / sparcv9 / sparcv9core.c
CommitLineData
920dae64
AT
1/*
2* ========== Copyright Header Begin ==========================================
3*
4* OpenSPARC T2 Processor File: sparcv9core.c
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/*
24 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
26 */
27#pragma ident "@(#)sparcv9core.c 1.50 07/10/12 SMI"
28
29#include <stdio.h>
30#include <stdlib.h>
31#include <assert.h>
32
33
34 /*
35 * This module contains the core execution routines for a SPARC v9
36 * processor.
37 * These augment the generic instructions implemented in the
38 * core of the simulator.
39 *
40 * Moreover this module implements all the generic SPARC v9 operations
41 * from register window manipulations to ASI operations, as well
42 * as managing the processor traps, trap tables and execution state.
43 */
44
45
46#include "basics.h"
47#include "allocate.h"
48#include "simcore.h"
49#include "config.h"
50#include "tsparcv9.h"
51#include "tsparcv9internal.h"
52#include "sparcv9regs.h"
53#include "sparcv9cc.h"
54#include "sparcv9decode.h"
55#include "xicache.h"
56#include "magictraps.h"
57#include "breakpoint.h"
58#include "fatal.h"
59#include "bswap.h"
60
61#define ss_get_fsr(_sp) (_sp->v9_fsr_ctrl | (_sp->v9_fsr_tem<<V9_FSR_TEM_BIT) \
62 | _sp->v9_fsr_exc)
63
64
65 /*
66 * Prefines here ..
67 */
68
69
70
71 /*
72 * Initialisation support functions
73 */
74
75sparcv9_cpu_t *
76sparcv9_cpu_alloc(domain_t *domainp, config_proc_t *config_procp,
77 uint_t nwins, uint_t nglobals, uint_t maxtl, uint64_t ver,
78 bool_t has_fpu, void *magicptr)
79{
80 sparcv9_cpu_t *v9p;
81 simcpu_t *sp;
82 uint_t core_thread, i;
83
84 v9p = Xcalloc(1, sparcv9_cpu_t);
85
86 v9p->nwins = nwins;
87
88 /*
89 * nwins_mask needs to be a mask of the number of
90 * bits needed to store nwins. We use this mask
91 * when we write a new value of nwins to ensure
92 * that only th bits implemented by nwins in the
93 * chip get set.
94 */
95 i = 1;
96 while (i < nwins)
97 i <<= 1;
98 v9p->nwins_mask = (i - 1);
99
100 v9p->nglobals = nglobals;
101
102 v9p->globalsp = Xcalloc(8 * nglobals, uint64_t);
103 v9p->winsp = Xcalloc(16 * nwins, uint64_t);
104
105 v9p->active_window = -1;
106 v9p->active_global = -1;
107
108 ASSERT(maxtl < SPARCv9_TLSPACE);
109 v9p->maxtl = maxtl;
110 v9p->ver = ver;
111
112 v9p->has_fpu = has_fpu;
113 v9p->fpu_on = false; /* make all the FPU info be consistent */
114 v9p->pstate.fpu_enabled = v9p->has_fpu;
115 v9p->fprs.fef = false;
116
117 v9p->tl = 0;
118 v9p->gl = 0;
119 v9p->cwp = 0;
120 v9p->had_RED_trap = false;
121
122 sp = sim_cpu_alloc(config_procp, (void *)v9p);
123
124 /*
125 * Initialize stuff the simcpu_t
126 * is likely to use
127 */
128
129
130 /* setup the call backs for simcpu_t */
131
132 /* CPU specific fields - so force an error if not fixed */
133/* BEGIN CSTYLED */
134SANITY( sp->xic_miss = NULL; );
135SANITY( sp->xicachep = NULL; );
136
137SANITY( sp->xdc.miss = NULL; );
138/* END CSTYLED */
139XDCACHE_SANITY_CHECK();
140
141 sp->decodemep = sparcv9_decode_me;
142
143 sp->v9_ccr = 0; /* sparc v9 condition codes stored in simcpu_t */
144
145
146 v9p->simp = sp;
147 v9p->state = V9_UnInitialised; /* Need a trap to get rid of this */
148
149 return (v9p);
150}
151
152
153
154
155
156
157
158 /*
159 *
160 * Performance measurement functions
161 *
162 */
163
164
165void
166sparcv9_perf_dump(void *ptr)
167{
168#if PERFORMANCE_CHECK /* { */
169 sparcv9_cpu_t *v9p = ptr;
170 simcpu_t *sp;
171 uint_t t;
172 uint_t cid = v9p->simp->gid;
173 double scale;
174 simcycle_t icount;
175 uint64_t rtotal, utotal, ptotal, htotal;
176 uint64_t xic_hits, xic_misses, xdc_hits, xdc_misses;
177 uint64_t xic_flushes, xdc_flushes;
178
179 sp = v9p->simp;
180
181 /* Instruction counts */
182 icount = ICOUNT(sp);
183 scale = 100.0 / (double)icount;
184
185 PERF_ACCUMULATE_ICOUNT(v9p);
186
187 rtotal = v9p->perf.icount[V9_RED];
188 utotal = v9p->perf.icount[V9_User];
189 ptotal = v9p->perf.icount[V9_Priv];
190 htotal = v9p->perf.icount[V9_HyperPriv];
191
192 /* xdcache statistics */
193 xdc_hits = sp->xdc_hits - sp->prev_xdc_hits;
194 xdc_misses = sp->xdc_misses - sp->prev_xdc_misses;
195 xdc_flushes = sp->xdc_flushes - sp->prev_xdc_flushes;
196
197 /* xicache statistics */
198 sp->xic_hits = icount - sp->xic_misses;
199 xic_hits = sp->xic_hits - sp->prev_xic_hits;
200 xic_misses = sp->xic_misses - sp->prev_xic_misses;
201 xic_flushes = sp->xic_flushes - sp->prev_xic_flushes;
202
203 log_printf(cid, "Instn cnts: R=%llu (%.2llf%%), H=%llu (%.2llf%%), "
204 "P=%llu (%.2llf%%), U=%llu (%.2llf%%), Total=%llu\n",
205 rtotal, scale * (double)rtotal,
206 htotal, scale * (double)htotal,
207 ptotal, scale * (double)ptotal,
208 utotal, scale * (double)utotal,
209 rtotal + utotal + ptotal + htotal);
210
211 ASSERT((rtotal + utotal + ptotal + htotal) == ICOUNT(sp));
212
213 log_printf(cid, "xdcache: hits=%llu (%.2llf%%), "
214 "misses=%llu (%.2llf%%), "
215 "avg_hits=(%.2llf%%) flushes=%llu\n",
216 xdc_hits,
217 100.0 * xdc_hits / (double)(xdc_hits + xdc_misses),
218 xdc_misses,
219 100.0 * xdc_misses / (double)(xdc_hits + xdc_misses),
220 100.0 * sp->xdc_hits / (double)(sp->xdc_hits + sp->xdc_misses),
221 xdc_flushes);
222
223 log_printf(cid, "xicache: hits=%llu (%.2llf%%), "
224 "misses=%llu (%.2llf%%), "
225 "avg hits=(%.2llf%%) flushes=%llu\n",
226 xic_hits,
227 100.0 * xic_hits / (double)(xic_hits + xic_misses),
228 xic_misses,
229 100.0 * xic_misses / (double)(xic_hits + xic_misses),
230 100.0 * sp->xic_hits / (double)(sp->xic_hits + sp->xic_misses),
231 xic_flushes);
232
233 sp->prev_xdc_hits = sp->xdc_hits;
234 sp->prev_xdc_misses = sp->xdc_misses;
235 sp->prev_xdc_flushes = sp->xdc_flushes;
236 sp->prev_xic_hits = sp->xic_hits;
237 sp->prev_xic_misses = sp->xic_misses;
238 sp->prev_xic_flushes = sp->xic_flushes;
239
240 log_printf(cid, "Instn count delta : %llu pc : 0x%llx\n",
241 (uint64_t)icount - sp->prev_icount, sp->pc);
242 sp->prev_icount = (uint64_t)icount;
243#endif /* PERFORMANCE_CHECK } */
244}
245
246
247
248
249 /*
250 *
251 * Execution support functions (and instruction impls)
252 *
253 */
254
255
256
257
258
259
260
261
262
263
264
265
266
267 /*
268 *
269 * Debugger interface support functions
270 *
271 */
272
273
274
275
276bool_t
277sparcv9_regread(sparcv9_cpu_t *v9p, uint_t regnum, uint64_t *valp)
278{
279 simcpu_t *sp;
280 sparcv9_reg_t regn = regnum;
281 uint_t idx;
282
283 sp = v9p->simp;
284
285 /*
286 * Assume that everything we care about has
287 * been written back to the architectural
288 * register file.
289 */
290
291 assert(v9p->active_window == -1);
292 assert(v9p->active_global == -1);
293
294 if (regn >= Reg_sparcv9_g0 && regn <= Reg_sparcv9_g7) {
295 assert(v9p->gl < v9p->nglobals);
296 idx = 8*v9p->gl + (regn-Reg_sparcv9_g0);
297 *valp = v9p->globalsp[idx];
298 } else
299 if (regn >= Reg_sparcv9_r8 && regn <= Reg_sparcv9_r23) {
300 assert(v9p->cwp < v9p->nwins);
301 idx = (v9p->nwins - 1 - v9p->cwp) * 2 * V9_REG_GROUP +
302 (regn-Reg_sparcv9_r8);
303 *valp = v9p->winsp[idx];
304 } else
305 if (regn >= Reg_sparcv9_r24 && regn <= Reg_sparcv9_r31) {
306 assert(v9p->cwp < v9p->nwins);
307 idx = (v9p->cwp == 0) ? 0 :
308 (v9p->nwins - 1 - v9p->cwp) * 2 * V9_REG_GROUP;
309 idx += (regn-Reg_sparcv9_r24);
310 *valp = v9p->winsp[idx];
311 } else {
312 uint64_t val;
313 switch (regn) {
314 case Reg_sparcv9_pc: val = v9p->simp->pc; break;
315 case Reg_sparcv9_npc: val = v9p->simp->npc; break;
316 case Reg_sparcv9_ccr: val = sp->v9_ccr; break;
317#if 0 /* { */
318 case Reg_sparcv9_fsr:
319 case Reg_sparcv9_fprs:
320#endif /* } */
321 case Reg_sparcv9_y: val = sp->v9_y; break;
322 case Reg_sparcv9_asi: val = sp->v9_asi; break;
323#if 0 /* { */
324 case Reg_sparcv9_ver:
325 case Reg_sparcv9_tick:
326#endif /* } */
327 case Reg_sparcv9_pil: val = v9p->pil; break;
328 case Reg_sparcv9_pstate:
329 val = v9p->pstate.priv ? (1 << V9_PSTATE_PRIV_BIT) : 0;
330 val |= v9p->pstate.mm << V9_PSTATE_MM_BITS;
331 val |= v9p->pstate.int_enabled ?
332 (1 << V9_PSTATE_IE_BIT) : 0;
333 val |= v9p->pstate.fpu_enabled ?
334 (1 << V9_PSTATE_PEF_BIT) : 0;
335 val |= v9p->pstate.tle ? (1 << V9_PSTATE_TLE_BIT) : 0;
336 val |= v9p->pstate.cle ? (1 << V9_PSTATE_CLE_BIT) : 0;
337 val |= v9p->pstate.tct ? (1 << V9_PSTATE_TCT_BIT) : 0;
338 val |= v9p->pstate.addr_mask ?
339 (1<< V9_PSTATE_AM_BIT) : 0;
340 break;
341
342 case Reg_sparcv9_tstate:
343 if (v9p->tl == 0)
344 goto no_reg;
345 val = N_TSTATE(v9p, v9p->tl);
346 break;
347 case Reg_sparcv9_tba: val = v9p->tba; break;
348 case Reg_sparcv9_tl: val = v9p->tl; break;
349 case Reg_sparcv9_tt:
350 if (v9p->tl == 0)
351 goto no_reg;
352 val = N_TT(v9p, v9p->tl);
353 break;
354 case Reg_sparcv9_tpc:
355 if (v9p->tl == 0)
356 goto no_reg;
357 val = N_TPC(v9p, v9p->tl);
358 break;
359 case Reg_sparcv9_tnpc:
360 if (v9p->tl == 0)
361 goto no_reg;
362 val = N_TNPC(v9p, v9p->tl);
363 break;
364 case Reg_sparcv9_wstate:
365 val = v9p->wstate_normal << V9_WSTATE_NORMAL_BITS;
366 val |= v9p->wstate_other << V9_WSTATE_OTHER_BITS;
367 break;
368 case Reg_sparcv9_cwp: val = v9p->cwp; break;
369 case Reg_sparcv9_cansave: val = v9p->cansave; break;
370 case Reg_sparcv9_canrestore: val = v9p->canrestore; break;
371 case Reg_sparcv9_cleanwin: val = v9p->cleanwin; break;
372 case Reg_sparcv9_otherwin: val = v9p->otherwin; break;
373#if 0 /* { */
374 case Reg_sparcv9_asr16:
375 case Reg_sparcv9_asr17:
376 case Reg_sparcv9_asr18:
377 case Reg_sparcv9_asr19:
378 case Reg_sparcv9_asr20:
379 case Reg_sparcv9_asr21:
380 case Reg_sparcv9_asr22:
381 case Reg_sparcv9_asr23:
382 case Reg_sparcv9_asr24:
383 case Reg_sparcv9_asr25:
384 case Reg_sparcv9_asr26:
385 case Reg_sparcv9_asr27:
386 case Reg_sparcv9_asr28:
387 case Reg_sparcv9_asr29:
388 case Reg_sparcv9_asr30:
389 case Reg_sparcv9_asr31:
390 case Reg_sparcv9_icc:
391 case Reg_sparcv9_xcc:
392 case Reg_sparcv9_fcc0:
393 case Reg_sparcv9_fcc1:
394 case Reg_sparcv9_fcc2:
395 case Reg_sparcv9_fcc3:
396#endif /* } */
397
398 default:
399 no_reg:
400#if 0 /* { */
401 return (false); /* unknown / unsupported regnum */
402#endif /* } */
403 val = 0x0badcafedeadbeef;
404 break;
405 }
406 *valp = val;
407 }
408
409 return (true); /* ok */
410}
411
412
413 /* returns false on failure */
414
415bool_t
416sparcv9_regwrite(sparcv9_cpu_t *v9p, uint_t regnum, uint64_t val)
417{
418 sparcv9_reg_t regn = regnum;
419 uint_t idx;
420
421 if (regn >= Reg_sparcv9_g0 && regn <= Reg_sparcv9_g7) {
422 assert(v9p->gl < v9p->nglobals);
423 idx = 8*v9p->gl + (regn-Reg_sparcv9_g0);
424 v9p->globalsp[idx] = val;
425 } else
426 if (regn >= Reg_sparcv9_r8 && regn <= Reg_sparcv9_r23) {
427 assert(v9p->cwp < v9p->nwins);
428 idx = (v9p->nwins - 1 - v9p->cwp) * 2 * V9_REG_GROUP +
429 (regn-Reg_sparcv9_r8);
430 v9p->winsp[idx] = val;
431 } else
432 if (regn >= Reg_sparcv9_r24 && regn <= Reg_sparcv9_r31) {
433 assert(v9p->cwp < v9p->nwins);
434 idx = (v9p->cwp == 0) ?
435 0 : (v9p->nwins - 1 - v9p->cwp) * 2 * V9_REG_GROUP;
436 idx += (regn-Reg_sparcv9_r24);
437 v9p->winsp[idx] = val;
438 } else
439 switch (regn) {
440 case Reg_sparcv9_pc:
441 v9p->simp->pc = val;
442 break;
443 case Reg_sparcv9_npc:
444 v9p->simp->npc = val;
445 break;
446 case Reg_sparcv9_cwp:
447 /* saturate not wrap! */
448 v9p->cwp = val >= v9p->nwins ? v9p->nwins - 1 : val;
449 break;
450
451 default:
452 return (false); /* unknown / unsupported regnum */
453 }
454 return (true); /* OK */
455}
456
457
458
459
460
461
462 /*
463 * FIXME: Kludge - for the moment - only one set of breakpoints !
464 */
465
466bp_info_t *globalbpinfop;
467
468
469void
470sparcv9_set_break(sparcv9_cpu_t *v9p, tvaddr_t bpaddr)
471{
472 simcpu_t *sp;
473
474 if (globalbpinfop == NULL) globalbpinfop = breakpoint_init();
475
476 sp = v9p->simp;
477
478 breakpoint_insert(globalbpinfop, bpaddr,
479 DEFAULT_BP_CONTEXT /* FIXME */);
480
481 if (sp->bp_infop == NULL) sp->bp_infop = globalbpinfop;
482}
483
484void
485sparcv9_set_break_next(sparcv9_cpu_t *v9p)
486{
487 simcpu_t *sp;
488
489 if (globalbpinfop == NULL) globalbpinfop = breakpoint_init();
490
491 sp = v9p->simp;
492
493 breakpoint_insert_next(globalbpinfop);
494
495 if (sp->bp_infop == NULL) sp->bp_infop = globalbpinfop;
496}
497
498void
499sparcv9_clear_break_next(sparcv9_cpu_t *v9p)
500{
501 simcpu_t *sp;
502
503 if (globalbpinfop == NULL) globalbpinfop = breakpoint_init();
504
505 sp = v9p->simp;
506
507 breakpoint_clear_next(globalbpinfop);
508
509 if (sp->bp_infop == NULL) sp->bp_infop = globalbpinfop;
510}
511
512bool_t
513sparcv9_hit_break(sparcv9_cpu_t *v9p, tvaddr_t bpaddr)
514{
515 simcpu_t *sp;
516
517 sp = v9p->simp;
518 if (sp->bp_infop == (bp_info_t *)0)
519 return (false);
520
521 return breakpoint_find_by_addr(sp->bp_infop, bpaddr,
522 DEFAULT_BP_CONTEXT) != NULL;
523}
524
525void
526sparcv9_clear_break(sparcv9_cpu_t *v9p, tvaddr_t bpaddr)
527{
528 simcpu_t *sp;
529
530 sp = v9p->simp;
531 if (sp->bp_infop == (bp_info_t *)0)
532 return;
533
534 breakpoint_delete_by_addr(sp->bp_infop, bpaddr,
535 DEFAULT_BP_CONTEXT /* FIXME */);
536
537 if (sp->bp_infop->active_count == 0) sp->bp_infop = (bp_info_t *)0;
538}
539
540void
541sparcv9_print_break(sparcv9_cpu_t *v9p)
542{
543 simcpu_t *sp;
544
545 if (globalbpinfop == NULL)
546 globalbpinfop = breakpoint_init();
547
548 sp = v9p->simp;
549
550 breakpoint_print(globalbpinfop);
551
552 if (sp->bp_infop == NULL)
553 sp->bp_infop = globalbpinfop;
554}
555
556/*
557 * cache breakpoints in a text file
558 */
559void
560sparcv9_dump_break(sparcv9_cpu_t *v9p, FILE *fp)
561{
562 simcpu_t *sp;
563
564 if (globalbpinfop == NULL) {
565 globalbpinfop = breakpoint_init();
566 }
567
568 breakpoint_dump(globalbpinfop, fp);
569
570 sp = v9p->simp;
571 if (sp->bp_infop == NULL) {
572 sp->bp_infop = globalbpinfop;
573 }
574}
575
576/*
577 * restore breakpoints cached in a text file
578 */
579void
580sparcv9_restore_break(FILE *fp)
581{
582 if (globalbpinfop == NULL) {
583 globalbpinfop = breakpoint_init();
584 }
585
586 breakpoint_restore(globalbpinfop, fp);
587}
588
589
590
591
592 /*
593 *
594 * SPARC register windows could have been implemented better.
595 *
596 * So here's how they are implemented in Legion;
597 *
598 * For each window shuffle - we copy the old window frame out
599 * and copy the new one in to the working register file from
600 * the architectural (sparc) one. We could optmise the
601 * common case of incrementing or decrementing the ccurrent
602 * window pointer (cwp), but this version deals with all cases.
603 *
604 * The v9p->active_window tells us which frame is supposed to
605 * be in the simcpu_t register file, and new_window the
606 * window we want.
607 *
608 * If new_window == -1 we just want to write back into the
609 * architectural file. If v9p->active_window == -1 we need
610 * to retrieve from the architectural file.
611 *
612 * OK the mess is worse:
613 * regs 8-15 = outs
614 * 16-23 = locals
615 * 24-31 = ins.
616 *
617 * If cwp is incremented, the old outs become the new ins
618 * (yes I know it's backwards )
619 * Anyway so that the rotation works correctly ( and without
620 * decoding %g0 as sim register 31), we work our way down the
621 * architectural register array as we increment cwp.
622 * So what was register offset X becomes register offset X+16
623 * as we increment cwp.
624 *
625 * The only special case is (by our choice) window 0, which
626 * sits at (nwins-1)*16 as a base, but the ins (regs 24-31)
627 * are placed at the bottom of the architectural array
628 * starting at 0
629 *
630 */
631
632void
633sparcv9_active_window(simcpu_t *sp, uint_t new_window)
634{
635 sparcv9_cpu_t *v9p;
636 uint64_t *sim_regp, *arch_regp;
637 uint_t i;
638
639 v9p = (sparcv9_cpu_t *)(sp->specificp);
640
641 if (v9p->active_window == -1) goto load_window;
642
643 /* OK stash back the old window's contents */
644
645 arch_regp = &(v9p->winsp[(v9p->nwins -1 - v9p->active_window) *
646 2 * V9_REG_GROUP]);
647 sim_regp = &sp->intreg[V9_OUT_OFFSET];
648
649 if (v9p->active_window == 0) {
650
651 for (i = V9_REG_GROUP * 2; i > 0; i--) {
652 *arch_regp++ = *sim_regp++;
653 }
654
655 arch_regp = &v9p->winsp[0];
656 sim_regp = &sp->intreg[V9_IN_OFFSET];
657
658 for (i = V9_REG_GROUP; i > 0; i--) {
659 *arch_regp++ = *sim_regp++;
660 }
661 } else {
662 for (i = V9_REG_GROUP * 3; i > 0; i--) {
663 *arch_regp++ = *sim_regp++;
664 }
665 }
666
667 v9p->active_window = -1; /* tag our cached window state as invalid */
668
669load_window:;
670
671 if (new_window == -1)
672 return; /* bail out */
673
674 arch_regp = &(v9p->winsp[(v9p->nwins -1 - new_window)*2*V9_REG_GROUP]);
675 sim_regp = &sp->intreg[V9_OUT_OFFSET];
676
677 if (new_window == 0) {
678
679 for (i = V9_REG_GROUP * 2; i > 0; i--) {
680 *sim_regp++ = *arch_regp++;
681 }
682
683 arch_regp = &v9p->winsp[0];
684 sim_regp = &sp->intreg[V9_IN_OFFSET];
685
686 for (i = V9_REG_GROUP; i > 0; i--) {
687 *sim_regp++ = *arch_regp++;
688 }
689 } else {
690 for (i = V9_REG_GROUP * 3; i > 0; i--) {
691 *sim_regp++ = *arch_regp++;
692 }
693 }
694
695 v9p->active_window = new_window;
696}
697
698
699
700
701 /*
702 * Basically same story - except that the globals are easier
703 * to handle as there is no overlap.
704 */
705
706void
707sparcv9_active_globals(simcpu_t *sp, uint_t new_global)
708{
709 sparcv9_cpu_t *v9p;
710 uint64_t *sim_regp, *arch_regp;
711 uint_t i;
712
713 v9p = (sparcv9_cpu_t *)(sp->specificp);
714
715 if (v9p->active_global == -1) goto load_global;
716
717 /* OK stash back the old globals' contents */
718
719 arch_regp = &(v9p->globalsp[(v9p->active_global)*V9_GLOBAL_GROUP]);
720 sim_regp = &sp->intreg[V9_GLOBAL_OFFSET];
721
722 for (i = V9_GLOBAL_GROUP; i > 0; i--) {
723 *arch_regp++ = *sim_regp++;
724 }
725
726 v9p->active_global = -1; /* tag our cached global state as invalid */
727
728load_global:;
729
730 if (new_global == -1)
731 return; /* bail out */
732
733 arch_regp = &(v9p->globalsp[new_global*V9_GLOBAL_GROUP]);
734 sim_regp = &sp->intreg[V9_GLOBAL_OFFSET];
735
736 for (i = V9_GLOBAL_GROUP; i > 0; i--) {
737 *sim_regp++ = *arch_regp++;
738 }
739
740 v9p->active_global = new_global;
741}
742
743
744
745void
746sparcv9_save_instr(simcpu_t *sp, uint_t rdest_num, tvaddr_t newval)
747{
748 sparcv9_cpu_t *v9p = (sparcv9_cpu_t *)(sp->specificp);
749
750#if HYPERPRIVILEGED_USE_WARN /* { */
751 if (V9_RED == v9p->state || V9_HyperPriv == v9p->state)
752 EXEC_WARNING(("save instruction in hyperprivileged mode "
753 "(%%pc=0x%llx)", sp->pc));
754#endif /* HYPERPRIVILEGED_USE_WARN */ /* { */
755
756 /* Possible spill trap ? */
757 if (v9p->cansave == 0) {
758 sparcv9_trap_type_t tt;
759 if (v9p->otherwin != 0) {
760 tt = Sparcv9_trap_spill_0_other |
761 (v9p->wstate_other << 2);
762 } else {
763 tt = Sparcv9_trap_spill_0_normal |
764 (v9p->wstate_normal << 2);
765 }
766 v9p->post_precise_trap(sp, tt);
767 return;
768 }
769
770 /* clean win trap ? */
771 if ((v9p->cleanwin - v9p->canrestore) == 0) {
772 v9p->post_precise_trap(sp, Sparcv9_trap_clean_window);
773 return;
774 }
775
776 /* Increment the cwp */
777 v9p->cwp = INC_MOD(v9p->cwp, v9p->nwins);
778 v9p->cansave = DEC_MOD(v9p->cansave, v9p->nwins);
779 v9p->canrestore = INC_MOD(v9p->canrestore, v9p->nwins);
780 sparcv9_active_window(sp, v9p->cwp);
781
782 if (!Zero_Reg(rdest_num)) sp->intreg[rdest_num] = newval;
783
784 NEXT_INSTN(sp);
785}
786
787
788
789void
790sparcv9_restore_instr(simcpu_t *sp, uint_t rdest_num, tvaddr_t newval)
791{
792 sparcv9_cpu_t *v9p = (sparcv9_cpu_t *)(sp->specificp);
793
794#if HYPERPRIVILEGED_USE_WARN /* { */
795 if (V9_RED == v9p->state || V9_HyperPriv == v9p->state)
796 EXEC_WARNING(("restore instruction in hyperprivileged mode "
797 "(%%pc=0x%llx)", sp->pc));
798#endif /* HYPERPRIVILEGED_USE_WARN */ /* { */
799
800 if (v9p->canrestore == 0) {
801 sparcv9_trap_type_t tt;
802 if (v9p->otherwin != 0) {
803 tt = Sparcv9_trap_fill_0_other | (v9p->wstate_other<<2);
804 } else {
805 tt = Sparcv9_trap_fill_0_normal |
806 (v9p->wstate_normal<<2);
807 }
808 v9p->post_precise_trap(sp, tt);
809 return;
810 }
811
812 /* Decrement the cwp */
813 v9p->cwp = DEC_MOD(v9p->cwp, v9p->nwins);
814 v9p->cansave = INC_MOD(v9p->cansave, v9p->nwins);
815 v9p->canrestore = DEC_MOD(v9p->canrestore, v9p->nwins);
816 sparcv9_active_window(sp, v9p->cwp);
817
818 if (!Zero_Reg(rdest_num)) sp->intreg[rdest_num] = newval;
819
820 NEXT_INSTN(sp);
821}
822
823
824
825
826void
827sparcv9_return_instr(simcpu_t *sp, tvaddr_t targetpc)
828{
829 sparcv9_cpu_t *v9p = (sparcv9_cpu_t *)(sp->specificp);
830
831#if HYPERPRIVILEGED_USE_WARN /* { */
832 if (V9_RED == v9p->state || V9_HyperPriv == v9p->state)
833 EXEC_WARNING(("return instruction in hyperprivileged mode "
834 "(%%pc=0x%llx)", sp->pc));
835#endif /* HYPERPRIVILEGED_USE_WARN */ /* { */
836
837 if ((targetpc & 3) != 0) {
838 v9p->post_precise_trap(sp,
839 Sparcv9_trap_mem_address_not_aligned);
840 return;
841 }
842
843 if (v9p->canrestore == 0) {
844 sparcv9_trap_type_t tt;
845 if (v9p->otherwin != 0) {
846 tt = Sparcv9_trap_fill_0_other | (v9p->wstate_other<<2);
847 } else {
848 tt = Sparcv9_trap_fill_0_normal |
849 (v9p->wstate_normal<<2);
850 }
851 v9p->post_precise_trap(sp, tt);
852 return;
853 }
854
855 /* Decrement the cwp */
856 v9p->cwp = DEC_MOD(v9p->cwp, v9p->nwins);
857 v9p->cansave = INC_MOD(v9p->cansave, v9p->nwins);
858 v9p->canrestore = DEC_MOD(v9p->canrestore, v9p->nwins);
859 sparcv9_active_window(sp, v9p->cwp);
860
861 SET_PC_WITH_DS(sp, targetpc);
862}
863
864
865
866
867
868 /*
869 * Other misc instruction implementations
870 */
871
872void
873sparcv9_udiv64(simcpu_t *sp, uint_t rdest_num, uint64_t a, uint64_t b)
874{
875 if (b == (uint64_t)0) {
876 sparcv9_cpu_t *v9p = (sparcv9_cpu_t *)(sp->specificp);
877 v9p->post_precise_trap(sp, Sparcv9_trap_division_by_zero);
878 return;
879 }
880
881 if (!Zero_Reg(rdest_num)) sp->intreg[rdest_num] = a / b;
882
883 NEXT_INSTN(sp);
884}
885
886
887void
888sparcv9_trapcc(simcpu_t *sp, uint64_t tnum, uint_t cc, cond_type_t cond)
889{
890 uint_t ccr;
891 sparcv9_cpu_t *v9p = (sparcv9_cpu_t *)(sp->specificp);
892
893 if (V9_User == v9p->state)
894 tnum &= 0x7f;
895 else
896 tnum &= 0xff;
897
898 ccr = sp->v9_ccr;
899 if (cc) ccr >>= 4;
900
901 if ((sparcv9_cc_magic[cond] >> (ccr & 0xf)) & 1) {
902 sparcv9_cpu_t *v9p = (sparcv9_cpu_t *)(sp->specificp);
903
904 if (SS_MAGIC_TRAP_CC(cc) && SS_MAGIC_TRAP(sp, tnum)) {
905 NEXT_INSTN(sp);
906 return;
907 }
908
909 v9p->post_precise_trap(sp,
910 tnum + Sparcv9_trap_trap_instruction);
911 return;
912 }
913
914 NEXT_INSTN(sp);
915}
916
917
918
919
920
921
922
923 /*
924 * In the event an instruction implementation needs to generate
925 * a floating point exception, this function is called
926 */
927
928void
929sparcv9_deliver_ieee_exception(simcpu_t *sp)
930{
931 sparcv9_cpu_t *v9p = (sparcv9_cpu_t *)(sp->specificp);
932 uint64_t m;
933
934 sp->v9_fsr_ctrl &= ~V9_FSR_FTT_MASK;
935 sp->v9_fsr_ctrl |= SPARCv9_FTT_IEEE_754_exception << V9_FSR_FTT_SHIFT;
936
937 /* CEXC bits are modified by TEM bits when a trap is taken */
938 m = sp->v9_fsr_exc & sp->v9_fsr_tem &
939 (V9_FSR_OF_BIT|V9_FSR_UF_BIT|V9_FSR_NX_BIT);
940 if (m != 0) {
941 /* prioritize exception */
942 if (m & V9_FSR_OF_BIT)
943 m = V9_FSR_OF_BIT;
944 else if (m & V9_FSR_UF_BIT)
945 m = V9_FSR_UF_BIT;
946 sp->v9_fsr_exc &= ~(V9_FSR_OF_BIT|V9_FSR_UF_BIT|V9_FSR_NX_BIT);
947 sp->v9_fsr_exc |= m;
948 }
949
950/* BEGIN CSTYLED */
951DBGFSR( lprintf(sp->gid, "sparcv9_deliver_ieee_exception: pc=0x%llx, "
952 "fsr=0x%llx\n", sp->pc, ss_get_fsr(sp)); );
953/* END CSTYLED */
954
955 v9p->post_precise_trap(sp, Sparcv9_trap_fp_exception_ieee_754);
956}
957
958#ifndef FP_DECODE_DISABLED
959 /*
960 * In the event an instruction implementation needs to generate
961 * a floating point disabled exception, this function is called
962 */
963
964void
965sparcv9_deliver_fp_disabled_exception(simcpu_t *sp)
966{
967 sparcv9_cpu_t *v9p = (sparcv9_cpu_t *)(sp->specificp);
968
969 v9p->post_precise_trap(sp, Sparcv9_trap_fp_disabled);
970}
971#endif /* FP_DECODE_DISABLED */
972
973
974uint64_t
975sparcv9_invert_endianess(uint64_t *regp, uint32_t count)
976{
977 uint64_t new_reg;
978
979 switch (count) {
980 case 1:
981 new_reg = (uint64_t)BSWAP_8(*regp);
982 break;
983 case 2:
984 new_reg = (uint64_t)BSWAP_16(*regp);
985 break;
986 case 4:
987 new_reg = (uint64_t)BSWAP_32(*regp);
988 break;
989 case 8:
990 new_reg = (uint64_t)BSWAP_64(*regp);
991 break;
992 default:
993 fatal("sparcv9_invert_endianess() count of %d - not supported",
994 count);
995 }
996
997 return (new_reg);
998}
999
1000
1001 /*
1002 *
1003 * Functions and variables to assist with debugging
1004 * Legion's SPARC v9 support.
1005 *
1006 */
1007
1008
1009
1010char *sparcv9_state_name[] = {
1011 /* 0 is not a legit state - tells us allocated but not inited */
1012 "V9_UnInitialised",
1013 "V9_User",
1014 "V9_Priv",
1015 "V9_HyperPriv",
1016 "V9_RED",
1017 "V9_Error"
1018};
1019
1020void
1021ss_iflush_by_pa(simcpu_t *sp, uint64_t pa, uint_t gran)
1022{
1023 /*
1024 * The current xicache implementation is completely coherent
1025 * with memory. Therefore, there is no need to flush the
1026 * xicache upon a flush instruction.
1027 */
1028}
1029
1030#if !defined(NDEBUG) /* { */
1031
1032/*
1033 * Assumes log_lock() has been called.
1034 */
1035void
1036sparcv9_dump_intregs(simcpu_t *sp)
1037{
1038 uint_t i;
1039
1040 for (i = 0; i < 8; i++) {
1041 log_printf(sp->gid, "g%d=0x%016llx o%d=0x%016llx "
1042 "l%d=0x%016llx i%d=0x%016llx\n",
1043 i, sp->intreg[i],
1044 i, sp->intreg[i+8],
1045 i, sp->intreg[i+16],
1046 i, sp->intreg[i+24]);
1047 }
1048}
1049
1050
1051/*
1052 * dump out:
1053 * - Trap Stack
1054 * - global, out, local and in registers
1055 * - global level registers
1056 *
1057 * Assumes log_lock() has been called.
1058 */
1059void
1060sparcv9_dump_state(simcpu_t *sp)
1061{
1062 uint_t i;
1063 uint64_t *gp;
1064 sparcv9_cpu_t *v9p = (sparcv9_cpu_t *)(sp->specificp);
1065 uint_t id;
1066
1067 id = sp->gid;
1068
1069 /* dump current v9 CPU state */
1070 log_printf(id, "cpu %d : cycle=0x%llx state=%s : PC=0x%llx "
1071 "NPC=0x%llx TL=%d\n",
1072 id, sp->cycle, sparcv9_state_name[v9p->state], sp->pc,
1073 sp->npc, v9p->tl);
1074
1075 for (i = 1; i <= v9p->maxtl; i++)
1076 log_printf(id, "tstack: [%d]\tTSTATE=0x%llx\tTT=0x%llx\t"
1077 "TPC=0x%llx\tTNPC=0x%llx\tHTSTATE=0x%llx\n",
1078 i, N_TSTATE(v9p, i), N_TT(v9p, i), N_TPC(v9p, i),
1079 N_TNPC(v9p, i), N_HTSTATE(v9p, i));
1080
1081 sparcv9_dump_intregs(sp);
1082
1083 log_printf(id, "%%asi: 0x%llx : cwp=0x%x\n", sp->v9_asi, v9p->cwp);
1084 log_printf(id, "cansave=0x%x : canrestore=0x%x : otherwin=0x%x : "
1085 "cleanwin=0x%x : wstate other=0x%x, normal=0x%x\n",
1086 v9p->cansave, v9p->canrestore, v9p->otherwin, v9p->cleanwin,
1087 v9p->wstate_other, v9p->wstate_normal);
1088 if (v9p->gl > 0) {
1089 log_printf(id, "globals[%d (gl-1)]:\n", v9p->gl - 1);
1090 gp = &v9p->globalsp[(v9p->gl - 1) * V9_GLOBAL_GROUP];
1091 for (i = 1; i < V9_GLOBAL_GROUP; i++)
1092 log_printf(id, " %%g%d = 0x%016llx\n", i, gp[i]);
1093 }
1094}
1095
1096
1097void
1098sparcv9_dump_stack(simcpu_t *sp)
1099{
1100 uint_t i;
1101 uint64_t *gp;
1102 uint_t id = sp->gid;
1103 sparcv9_cpu_t *v9p;
1104 char ibuf[160];
1105
1106 v9p = (sparcv9_cpu_t *)sp->specificp;
1107
1108 log_printf(-1, "\n");
1109 log_printf(sp->gid, "[0x%llx:%s]\n",
1110 sp->cycle, sparcv9_state_name[v9p->state]);
1111
1112 for (i = 0; i < 8; i++) {
1113 log_printf(sp->gid, "g%d=0x%016llx o%d=0x%016llx "
1114 "l%d=0x%016llx i%d=0x%016llx\n",
1115 i, sp->intreg[i],
1116 i, sp->intreg[i+8],
1117 i, sp->intreg[i+16],
1118 i, sp->intreg[i+24]);
1119 }
1120
1121 if (v9p->tl > 0) {
1122 for (i = 1; i <= v9p->tl; i++) {
1123 log_printf(id, "tstack[%d]:\thtstate=0x%llx\t"
1124 "tstate=0x%llx\ttt=0x%llx\ttpc=0x%llx\t"
1125 "tnpc=0x%llx\n",
1126 i, N_HTSTATE(v9p, i), N_TSTATE(v9p, i),
1127 N_TT(v9p, i), N_TPC(v9p, i), N_TNPC(v9p, i));
1128 }
1129 }
1130 if (v9p->gl > 0) {
1131 for (i = 0; i < v9p->gl; i++) {
1132 gp = &v9p->globalsp[i * V9_GLOBAL_GROUP];
1133 log_printf(id, "global[%d]:\t%%g1=0x%llx %%g2=0x%llx "
1134 "%%g3=0x%llx %%g4=0x%llx %%g5=0x%llx %%g6=0x%llx "
1135 "%%g7=0x%llx\n",
1136 i, gp[1], gp[2], gp[3], gp[4], gp[5], gp[6], gp[7]);
1137 }
1138 }
1139}
1140
1141/*
1142 * trace output:
1143 * - current instruction (passed in)
1144 * - state
1145 * - Trap Stack
1146 * - global, out, local and in registers
1147 * - global level registers
1148 *
1149 * This function holds the log lock to ensure that all the output happens
1150 * atomically.
1151 *
1152 */
1153void
1154sparcv9_trace_output(simcpu_t *sp, uint32_t instn)
1155{
1156 sparcv9_cpu_t *v9p;
1157 char ibuf[160];
1158
1159 v9p = (sparcv9_cpu_t *)sp->specificp;
1160
1161
1162 log_lock();
1163
1164/* CSTYLED */
1165DBGEL( sparcv9_dump_stack(sp); );
1166
1167 sparcv9_idis(ibuf, 160, instn, sp->pc);
1168DBGELMIN(
1169 log_printf(sp->gid, "[0x%llx:%.6s] pc=0x%llx npc=0x%llx tl=%d gl=%d "
1170 "asi=0x%x instn=%08x: %s\n",
1171 sp->cycle, sparcv9_state_name[v9p->state],
1172 sp->pc, sp->npc, v9p->tl, v9p->gl, sp->v9_asi, instn, ibuf);
1173);
1174
1175 log_unlock();
1176}
1177
1178#endif /* } */
1179
1180
1181#if (INTERNAL_BUILD == 0) /* { */
1182/*
1183 * Dummy function to dis-assemble an instruction
1184 */
1185void sparcv9_idis(char * bufp, uint_t size, uint32_t instn, tvaddr_t address)
1186{
1187 snprintf(bufp, size, ".word\t0x%08x", instn);
1188}
1189#endif /* } */