Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / legion / src / procs / sunsparc / debug / lockstep.c
CommitLineData
920dae64
AT
1/*
2* ========== Copyright Header Begin ==========================================
3*
4* OpenSPARC T2 Processor File: lockstep.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 2006 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
26 */
27#pragma ident "@(#)lockstep.c 1.5 06/10/25 SMI"
28
29#include <stdio.h>
30#include <stdlib.h>
31#include <unistd.h>
32#include <sys/types.h>
33#include <sys/ipc.h>
34#include <sys/shm.h>
35#include <assert.h>
36#include <string.h>
37#include <strings.h>
38
39#include "ss_common.h"
40#include "niagara.h"
41
42#if 1
43#define DBGP(s) do { s } while (0)
44#endif
45
46void dbg_lockstep(simcpu_t *sp, uint32_t rawi);
47void dbg_lockstep_parse(void);
48void dbg_lockstep_dump(void);
49
50static void dump_mismatch_data(simcpu_t *sp);
51static void dump_instn_data(simcpu_t *sp);
52static void dump_intregs(uint64_t *data);
53static void diff_intregs(uint64_t *intrega, uint64_t *intregb);
54
55#define MASTER 0xfeedface
56#define SLAVE 0xdeadbeef
57
58typedef char decoded_instn_str_t[256];
59
60uint64_t start_instn = 0x0;
61bool_t trace_all = false;
62bool_t is_master = false;
63uint64_t current_instn = 0x0;
64
65typedef struct INSTN_DATA {
66 uint64_t pc;
67 uint64_t npc;
68 uint64_t instn_cnt;
69 uint32_t rawi;
70 uint64_t intreg[NINT];
71 uint64_t cycle_target;
72} instn_data_t;
73
74typedef struct LOCKSTEP_DATA_T {
75 int flag;
76 instn_data_t prev_master;
77 instn_data_t master;
78 instn_data_t prev_slave;
79 instn_data_t slave;
80} lockstep_data_t;
81
82#define SHM_ID (getuid() | ('F'<<24))
83int shmfd;
84lockstep_data_t *ctrl_datap = NULL;
85
86 /*
87 * This will be called while parsing the conf file
88 * to allow this hook to parse specific options from
89 * the conf file.
90 *
91 * Format of lockstep directive is:
92 * debug_hook [lockstep] [mode] [start]
93 *
94 * [lockstep] - we've already parsed this. That's how we got here.
95 * [mode] - master or slave
96 * master writes its data to shm region and waits for
97 * slave to compare. Dump any mismatches when simulators
98 * fall out of lockstep.
99 * [start] - optional, when supplied we enter into lockstep mode
100 * from this instn count onwards
101 *
102 * We need to create a shared mem region to store the lockstep
103 * buffer so that the slave can see the %pc and reg state of the
104 * master and compare against its %pc and reg state.
105 */
106void
107dbg_lockstep_parse(void)
108{
109 lexer_tok_t tok;
110 int shmflg;
111 uint32_t shm_size = sizeof (lockstep_data_t);
112
113
114 DBGP(printf("\nInside dbg_lockstep_parse()"););
115
116 /* Parse mode */
117 tok = lex_get_token();
118
119 if (streq(lex.strp, "master"))
120 is_master = true;
121 else if (streq(lex.strp, "slave"))
122 is_master = false;
123 else
124 lex_fatal("Unknown lockstep mode [%s]\n", lex.strp);
125
126 /*
127 * see if next option is a ';' - otherwise parse star_instn
128 */
129 tok = lex_get_token();
130 if (tok == T_S_Colon) {
131 trace_all = true; /* no start instn so check all instns */
132 lex_unget();
133 } else {
134 lex_unget();
135 lex_get(T_Number); /* parse start */
136 start_instn = lex.val;
137
138 trace_all = false;
139
140 DBGP(printf("\nlockstep: start_instn=0x%llx", start_instn););
141 }
142
143 /*
144 * Setup shared mem segment
145 */
146 if (is_master)
147 shmflg = 0777 | IPC_CREAT;
148 else
149 shmflg = 0777;
150
151 if ((shmfd = shmget(SHM_ID, shm_size, shmflg)) < 0) {
152 perror("shmget");
153 exit(1);
154 }
155
156
157 if ((ctrl_datap = (lockstep_data_t *)shmat(shmfd, NULL, SHM_RND))
158 == (lockstep_data_t *)-1) {
159 perror("shmat");
160 exit(1);
161 }
162
163 if (is_master) {
164 memset(ctrl_datap, 0, sizeof (lockstep_data_t));
165 ctrl_datap->flag = MASTER; /* allow master to start */
166 }
167
168
169
170 /*
171 * return to parse_debug_hook() which will take care of
172 * parsing the last semi colon.
173 */
174}
175
176 /*
177 * This function will get called before each instruction
178 * gets executed in execloop().
179 */
180void
181dbg_lockstep(simcpu_t *sp, uint32_t rawi)
182{
183 sparcv9_cpu_t *v9p;
184
185 current_instn++;
186
187 /* Check to see if we are comparing instns yet */
188 if (trace_all == false) {
189 if (sp->cycle < start_instn)
190 return;
191 }
192
193 if (sp->cycle == start_instn) {
194 printf("lockstep: Turned on lockstep mode on instn=0x%llx",
195 start_instn); fflush(stdout);
196 }
197
198 while (1) {
199 if (is_master) {
200 /*
201 * MASTER Loop, entered on every instruction
202 */
203 if (ctrl_datap->flag == MASTER) { /* wait for flag to be set */
204
205 /* write master %pc etc. to shared mem */
206 ctrl_datap->master.pc = sp->pc;
207 ctrl_datap->master.npc = sp->npc;
208 ctrl_datap->master.instn_cnt = sp->total_instr;
209 ctrl_datap->master.rawi = rawi;
210 bcopy(sp->intreg, ctrl_datap->master.intreg,
211 (sizeof (uint64_t)) * NINT);
212 ctrl_datap->master.cycle_target = sp->cycle_target;
213
214 /* Signal slave that master has written data */
215 ctrl_datap->flag = SLAVE;
216
217 /* Hand cpu over to slave */
218 yield();
219
220 /* When cpu comes back, we return to exec_loop */
221 return;
222 } /* if */
223 } else {
224 /*
225 * SLAVE Loop
226 */
227 if (ctrl_datap->flag == SLAVE) {
228
229 /*
230 * Save slave data - so we can compare current data with
231 * data from previous instn.
232 */
233 ctrl_datap->slave.pc = sp->pc;
234 ctrl_datap->slave.npc = sp->npc;
235 ctrl_datap->slave.instn_cnt = sp->total_instr;
236 bcopy(sp->intreg, ctrl_datap->slave.intreg,
237 (sizeof (uint64_t)) * NINT);
238 ctrl_datap->slave.rawi = rawi;
239 ctrl_datap->slave.cycle_target = sp->cycle_target;
240
241 /*
242 * Compare Master instns and data with Slave instns
243 * and data. If they don't match, we have a problem!!
244 */
245
246 if (bcmp(&ctrl_datap->master, &ctrl_datap->slave,
247 sizeof (instn_data_t)) != 0) {
248 dump_mismatch_data(sp);
249 exit(1);
250 }
251
252 /* Save master data to prev_master */
253 bcopy(&ctrl_datap->master, &ctrl_datap->prev_master,
254 sizeof (instn_data_t));
255
256 /* Save slave data to prev_slave */
257 bcopy(&ctrl_datap->slave, &ctrl_datap->prev_slave,
258 sizeof (instn_data_t));
259
260 /* Signal master that slave has written data */
261 ctrl_datap->flag = MASTER;
262
263 /* Give up the cpu so master can do some work */
264 yield();
265
266 /* When cpu comes back, we return to exec_loop */
267 return;
268 } /* if */
269
270 } /* else */
271
272 /*
273 * Rather than have the MASTER legion spin in this while loop
274 * while the SLAVE is comparing data, why not hand the cpu
275 * over to the SLAVE process so it can complete it's work
276 * and return the flag to the MASTER legion.
277 */
278 yield();
279 } /* while */
280}
281
282void
283dbg_lockstep_dump(void)
284{
285 printf("\ndbg_lockstep_dump: mode=[%s] start=0x%llx instn_count=[0x%llx]",
286 is_master ? "master" : "slave", start_instn, current_instn);
287}
288
289static void
290dump_intregs(uint64_t *intreg)
291{
292 int i;
293
294 for (i = 0; i < 8; i++) {
295 printf("\ng%d=0x%016llx o%d=0x%016llx l%d=0x%016llx i%d=0x%016llx",
296 i, intreg[i],
297 i, intreg[i+8],
298 i, intreg[i+16],
299 i, intreg[i+24]);
300 }
301}
302
303static void
304diff_intregs(uint64_t *intrega, uint64_t *intregb)
305{
306 int i;
307
308 for (i = 0; i < 8; i++) {
309 if (intrega[i] != intregb[i]) {
310 printf("\n --> g%d=0x%016llx != g%d=0x%016llx",
311 i, intrega[i], i, intregb[i]);
312 }
313 if (intrega[i+8] != intregb[i+8]) {
314 printf("\n --> o%d=0x%016llx != o%d=0x%016llx",
315 i, intrega[i+8], i, intregb[i+8]);
316 }
317 if (intrega[i+16] != intregb[i+16]) {
318 printf("\n --> l%d=0x%016llx != l%d=0x%016llx",
319 i, intrega[i+16], i, intregb[i+16]);
320 }
321 if (intrega[i+24] != intregb[i+24]) {
322 printf("\n --> i%d=0x%016llx != i%d=0x%016llx",
323 i, intrega[i+24], i, intregb[i+24]);
324 }
325 }
326}
327
328static void
329dump_mismatch_data(simcpu_t *sp)
330{
331
332 printf("\nERROR: Instn OR Data Mismatch !!!");
333
334 /* XXX FIXME: could dump out deubg_log if there is one here */
335
336 printf("\nMismatch Instn (has not been executed yet) marked with ->");
337 dump_instn_data(sp);
338
339 printf("\nMaster registers:");
340 dump_intregs(ctrl_datap->master.intreg);
341
342 printf("\nSlave registers:");
343 dump_intregs(sp->intreg);
344
345 printf("\nDiffs:");
346 diff_intregs(ctrl_datap->master.intreg, sp->intreg);
347}
348
349static void
350dump_instn_data(simcpu_t *sp)
351{
352
353
354 decoded_instn_str_t master_instn_str;
355 decoded_instn_str_t prev_master_instn_str;
356 decoded_instn_str_t slave_instn_str;
357 decoded_instn_str_t prev_slave_instn_str;
358
359 sparcv9_idis(master_instn_str,
360 sizeof (decoded_instn_str_t),
361 ctrl_datap->master.rawi, sp->pc);
362
363 sparcv9_idis(prev_master_instn_str,
364 sizeof (decoded_instn_str_t),
365 ctrl_datap->prev_master.rawi, sp->pc);
366
367 sparcv9_idis(slave_instn_str,
368 sizeof (decoded_instn_str_t),
369 ctrl_datap->slave.rawi, sp->pc);
370
371 sparcv9_idis(prev_slave_instn_str,
372 sizeof (decoded_instn_str_t),
373 ctrl_datap->prev_slave.rawi, sp->pc);
374
375 printf("\n" \
376 " master instn#[0x%llx] pc[0x%llx] rawi[0x%08x] npc[0x%llx] "\
377 "target[0x%llx] - [%s]\n" \
378 " slave instn#[0x%llx] pc[0x%llx] rawi[0x%08x] npc[0x%llx] "\
379 "target[0x%llx] - [%s]\n" \
380 "-> master instn#[0x%llx] pc[0x%llx] rawi[0x%08x] npc[0x%llx] "\
381 "target[0x%llx] - [%s]\n" \
382 "-> slave instn#[0x%llx] pc[0x%llx] rawi[0x%08x] npc[0x%llx] "\
383 "target[0x%llx] - [%s]",
384
385 ctrl_datap->prev_master.instn_cnt,
386 ctrl_datap->prev_master.pc,
387 ctrl_datap->prev_master.rawi,
388 ctrl_datap->prev_master.npc,
389 ctrl_datap->prev_master.cycle_target,
390 prev_master_instn_str,
391
392 ctrl_datap->prev_slave.instn_cnt,
393 ctrl_datap->prev_slave.pc,
394 ctrl_datap->prev_slave.rawi,
395 ctrl_datap->prev_slave.npc,
396 ctrl_datap->prev_slave.cycle_target,
397 prev_slave_instn_str,
398
399 ctrl_datap->master.instn_cnt,
400 ctrl_datap->master.pc,
401 ctrl_datap->master.rawi,
402 ctrl_datap->master.npc,
403 ctrl_datap->master.cycle_target,
404 master_instn_str,
405
406 ctrl_datap->slave.instn_cnt,
407 ctrl_datap->slave.pc,
408 ctrl_datap->slave.rawi,
409 ctrl_datap->slave.npc,
410 ctrl_datap->slave.cycle_target,
411 slave_instn_str);
412}