* ========== Copyright Header Begin ==========================================
* OpenSPARC T2 Processor File: lockstep.c
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
* The above named program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License version 2 as published by the Free Software Foundation.
* The above named program is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* You should have received a copy of the GNU General Public
* License along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
* ========== Copyright Header End ============================================
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
#pragma ident "@(#)lockstep.c 1.5 06/10/25 SMI"
#define DBGP(s) do { s } while (0)
void dbg_lockstep(simcpu_t
*sp
, uint32_t rawi
);
void dbg_lockstep_parse(void);
void dbg_lockstep_dump(void);
static void dump_mismatch_data(simcpu_t
*sp
);
static void dump_instn_data(simcpu_t
*sp
);
static void dump_intregs(uint64_t *data
);
static void diff_intregs(uint64_t *intrega
, uint64_t *intregb
);
#define MASTER 0xfeedface
typedef char decoded_instn_str_t
[256];
uint64_t start_instn
= 0x0;
bool_t trace_all
= false;
bool_t is_master
= false;
uint64_t current_instn
= 0x0;
typedef struct INSTN_DATA
{
typedef struct LOCKSTEP_DATA_T
{
instn_data_t prev_master
;
#define SHM_ID (getuid() | ('F'<<24))
lockstep_data_t
*ctrl_datap
= NULL
;
* This will be called while parsing the conf file
* to allow this hook to parse specific options from
* Format of lockstep directive is:
* debug_hook [lockstep] [mode] [start]
* [lockstep] - we've already parsed this. That's how we got here.
* [mode] - master or slave
* master writes its data to shm region and waits for
* slave to compare. Dump any mismatches when simulators
* [start] - optional, when supplied we enter into lockstep mode
* from this instn count onwards
* We need to create a shared mem region to store the lockstep
* buffer so that the slave can see the %pc and reg state of the
* master and compare against its %pc and reg state.
uint32_t shm_size
= sizeof (lockstep_data_t
);
DBGP(printf("\nInside dbg_lockstep_parse()"););
if (streq(lex
.strp
, "master"))
else if (streq(lex
.strp
, "slave"))
lex_fatal("Unknown lockstep mode [%s]\n", lex
.strp
);
* see if next option is a ';' - otherwise parse star_instn
trace_all
= true; /* no start instn so check all instns */
lex_get(T_Number
); /* parse start */
DBGP(printf("\nlockstep: start_instn=0x%llx", start_instn
););
* Setup shared mem segment
shmflg
= 0777 | IPC_CREAT
;
if ((shmfd
= shmget(SHM_ID
, shm_size
, shmflg
)) < 0) {
if ((ctrl_datap
= (lockstep_data_t
*)shmat(shmfd
, NULL
, SHM_RND
))
== (lockstep_data_t
*)-1) {
memset(ctrl_datap
, 0, sizeof (lockstep_data_t
));
ctrl_datap
->flag
= MASTER
; /* allow master to start */
* return to parse_debug_hook() which will take care of
* parsing the last semi colon.
* This function will get called before each instruction
* gets executed in execloop().
dbg_lockstep(simcpu_t
*sp
, uint32_t rawi
)
/* Check to see if we are comparing instns yet */
if (trace_all
== false) {
if (sp
->cycle
< start_instn
)
if (sp
->cycle
== start_instn
) {
printf("lockstep: Turned on lockstep mode on instn=0x%llx",
start_instn
); fflush(stdout
);
* MASTER Loop, entered on every instruction
if (ctrl_datap
->flag
== MASTER
) { /* wait for flag to be set */
/* write master %pc etc. to shared mem */
ctrl_datap
->master
.pc
= sp
->pc
;
ctrl_datap
->master
.npc
= sp
->npc
;
ctrl_datap
->master
.instn_cnt
= sp
->total_instr
;
ctrl_datap
->master
.rawi
= rawi
;
bcopy(sp
->intreg
, ctrl_datap
->master
.intreg
,
(sizeof (uint64_t)) * NINT
);
ctrl_datap
->master
.cycle_target
= sp
->cycle_target
;
/* Signal slave that master has written data */
ctrl_datap
->flag
= SLAVE
;
/* Hand cpu over to slave */
/* When cpu comes back, we return to exec_loop */
if (ctrl_datap
->flag
== SLAVE
) {
* Save slave data - so we can compare current data with
* data from previous instn.
ctrl_datap
->slave
.pc
= sp
->pc
;
ctrl_datap
->slave
.npc
= sp
->npc
;
ctrl_datap
->slave
.instn_cnt
= sp
->total_instr
;
bcopy(sp
->intreg
, ctrl_datap
->slave
.intreg
,
(sizeof (uint64_t)) * NINT
);
ctrl_datap
->slave
.rawi
= rawi
;
ctrl_datap
->slave
.cycle_target
= sp
->cycle_target
;
* Compare Master instns and data with Slave instns
* and data. If they don't match, we have a problem!!
if (bcmp(&ctrl_datap
->master
, &ctrl_datap
->slave
,
sizeof (instn_data_t
)) != 0) {
/* Save master data to prev_master */
bcopy(&ctrl_datap
->master
, &ctrl_datap
->prev_master
,
/* Save slave data to prev_slave */
bcopy(&ctrl_datap
->slave
, &ctrl_datap
->prev_slave
,
/* Signal master that slave has written data */
ctrl_datap
->flag
= MASTER
;
/* Give up the cpu so master can do some work */
/* When cpu comes back, we return to exec_loop */
* Rather than have the MASTER legion spin in this while loop
* while the SLAVE is comparing data, why not hand the cpu
* over to the SLAVE process so it can complete it's work
* and return the flag to the MASTER legion.
printf("\ndbg_lockstep_dump: mode=[%s] start=0x%llx instn_count=[0x%llx]",
is_master
? "master" : "slave", start_instn
, current_instn
);
dump_intregs(uint64_t *intreg
)
for (i
= 0; i
< 8; i
++) {
printf("\ng%d=0x%016llx o%d=0x%016llx l%d=0x%016llx i%d=0x%016llx",
diff_intregs(uint64_t *intrega
, uint64_t *intregb
)
for (i
= 0; i
< 8; i
++) {
if (intrega
[i
] != intregb
[i
]) {
printf("\n --> g%d=0x%016llx != g%d=0x%016llx",
i
, intrega
[i
], i
, intregb
[i
]);
if (intrega
[i
+8] != intregb
[i
+8]) {
printf("\n --> o%d=0x%016llx != o%d=0x%016llx",
i
, intrega
[i
+8], i
, intregb
[i
+8]);
if (intrega
[i
+16] != intregb
[i
+16]) {
printf("\n --> l%d=0x%016llx != l%d=0x%016llx",
i
, intrega
[i
+16], i
, intregb
[i
+16]);
if (intrega
[i
+24] != intregb
[i
+24]) {
printf("\n --> i%d=0x%016llx != i%d=0x%016llx",
i
, intrega
[i
+24], i
, intregb
[i
+24]);
dump_mismatch_data(simcpu_t
*sp
)
printf("\nERROR: Instn OR Data Mismatch !!!");
/* XXX FIXME: could dump out deubg_log if there is one here */
printf("\nMismatch Instn (has not been executed yet) marked with ->");
printf("\nMaster registers:");
dump_intregs(ctrl_datap
->master
.intreg
);
printf("\nSlave registers:");
dump_intregs(sp
->intreg
);
diff_intregs(ctrl_datap
->master
.intreg
, sp
->intreg
);
dump_instn_data(simcpu_t
*sp
)
decoded_instn_str_t master_instn_str
;
decoded_instn_str_t prev_master_instn_str
;
decoded_instn_str_t slave_instn_str
;
decoded_instn_str_t prev_slave_instn_str
;
sparcv9_idis(master_instn_str
,
sizeof (decoded_instn_str_t
),
ctrl_datap
->master
.rawi
, sp
->pc
);
sparcv9_idis(prev_master_instn_str
,
sizeof (decoded_instn_str_t
),
ctrl_datap
->prev_master
.rawi
, sp
->pc
);
sparcv9_idis(slave_instn_str
,
sizeof (decoded_instn_str_t
),
ctrl_datap
->slave
.rawi
, sp
->pc
);
sparcv9_idis(prev_slave_instn_str
,
sizeof (decoded_instn_str_t
),
ctrl_datap
->prev_slave
.rawi
, sp
->pc
);
" master instn#[0x%llx] pc[0x%llx] rawi[0x%08x] npc[0x%llx] "\
"target[0x%llx] - [%s]\n" \
" slave instn#[0x%llx] pc[0x%llx] rawi[0x%08x] npc[0x%llx] "\
"target[0x%llx] - [%s]\n" \
"-> master instn#[0x%llx] pc[0x%llx] rawi[0x%08x] npc[0x%llx] "\
"target[0x%llx] - [%s]\n" \
"-> slave instn#[0x%llx] pc[0x%llx] rawi[0x%08x] npc[0x%llx] "\
ctrl_datap
->prev_master
.instn_cnt
,
ctrl_datap
->prev_master
.pc
,
ctrl_datap
->prev_master
.rawi
,
ctrl_datap
->prev_master
.npc
,
ctrl_datap
->prev_master
.cycle_target
,
ctrl_datap
->prev_slave
.instn_cnt
,
ctrl_datap
->prev_slave
.pc
,
ctrl_datap
->prev_slave
.rawi
,
ctrl_datap
->prev_slave
.npc
,
ctrl_datap
->prev_slave
.cycle_target
,
ctrl_datap
->master
.instn_cnt
,
ctrl_datap
->master
.cycle_target
,
ctrl_datap
->slave
.instn_cnt
,
ctrl_datap
->slave
.cycle_target
,