OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [orpsocv2/] [bench/] [sysc/] [src/] [Or1200MonitorSC.cpp] - Blame information for rev 397

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 6 julius
// ----------------------------------------------------------------------------
2
 
3
// SystemC OpenRISC 1200 Monitor: implementation
4
 
5
// Copyright (C) 2008  Embecosm Limited <info@embecosm.com>
6
 
7
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
8 44 julius
// Contributor Julius Baxter <jb@orsoc.se>
9 6 julius
 
10
// This file is part of the cycle accurate model of the OpenRISC 1000 based
11
// system-on-chip, ORPSoC, built using Verilator.
12
 
13
// This program is free software: you can redistribute it and/or modify it
14
// under the terms of the GNU Lesser General Public License as published by
15
// the Free Software Foundation, either version 3 of the License, or (at your
16
// option) any later version.
17
 
18
// This program is distributed in the hope that it will be useful, but WITHOUT
19
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
21
// License for more details.
22
 
23
// You should have received a copy of the GNU Lesser General Public License
24
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
25
 
26
// ----------------------------------------------------------------------------
27
 
28 57 julius
// $Id$
29 6 julius
 
30
#include <iostream>
31
#include <iomanip>
32 44 julius
#include <fstream>
33 52 julius
#include <sys/types.h>
34
#include <netinet/in.h>
35 44 julius
using namespace std;
36
 
37 6 julius
#include "Or1200MonitorSC.h"
38 44 julius
#include "OrpsocMain.h"
39 6 julius
 
40 63 julius
#include <errno.h>
41
int monitor_to_gdb_pipe[2][2]; // [0][] - monitor to gdb, [1][] - gdb to monitor, [][0] - read, [][1] - write
42 6 julius
 
43
SC_HAS_PROCESS( Or1200MonitorSC );
44
 
45
//! Constructor for the OpenRISC 1200 monitor
46
 
47
//! @param[in] name  Name of this module, passed to the parent constructor.
48
//! @param[in] accessor  Accessor class for this Verilated ORPSoC model
49
 
50
Or1200MonitorSC::Or1200MonitorSC (sc_core::sc_module_name   name,
51 49 julius
                                  OrpsocAccess             *_accessor,
52 51 julius
                                  MemoryLoad               *_memoryload,
53 49 julius
                                  int argc,
54
                                  char *argv[]) :
55 6 julius
  sc_module (name),
56 51 julius
  accessor (_accessor),
57
  memoryload(_memoryload)
58 6 julius
{
59 63 julius
  string logfileDefault(DEFAULT_EXEC_LOG_FILE);
60 49 julius
  string logfileNameString;
61 63 julius
  logging_enabled = false;
62
  logfile_name_provided = false;
63
  profiling_enabled = false;
64 51 julius
  string profileFileName(DEFAULT_PROF_FILE);
65 52 julius
  memdumpFileName = (DEFAULT_MEMDUMP_FILE);
66
  int memdump_start = 0; int memdump_end = 0;
67 63 julius
  do_memdump = false; // Default is not to do a dump of RAM at finish
68
  logging_regs = true; // Execution log includes register values by default
69
  bool rsp_server_enabled = false;
70
  wait_for_stall_cmd_response = false; // Default
71
  insn_count = insn_count_rst = 0;
72
  cycle_count = cycle_count_rst = 0;
73 52 julius
 
74 63 julius
  exit_perf_summary_enabled = true; // Simulation exit performance summary is 
75
                                    // on by default. Turn off with "-q" on the 
76
                                    // cmd line
77
  monitor_for_crash = false;
78
  lookslikewevecrashed_count = crash_monitor_buffer_head = 0;
79 49 julius
 
80 63 julius
  bus_trans_log_enabled = bus_trans_log_name_provided =
81
    bus_trans_log_start_delay_enable = false; // Default
82
  string bus_trans_default_log_name(DEFAULT_BUS_LOG_FILE);
83
  string bus_trans_log_file;
84 49 julius
 
85
  // Parse the command line options
86 63 julius
  bool cmdline_name_found = false;
87 49 julius
  if (argc > 1)
88
    {
89
      // Search through the command line parameters for the "-log" option
90
      for(int i=1; i < argc; i++)
91
        {
92
          if ((strcmp(argv[i], "-l")==0) ||
93
              (strcmp(argv[i], "--log")==0))
94
            {
95 63 julius
              logging_enabled = true;
96
              binary_log_format = false;
97
              if (i+1 < argc)
98
                if(argv[i+1][0] != '-')
99
                  {
100
                    logfileNameString = (argv[i+1]);
101
                    logfile_name_provided = true;
102
                  }
103
              if (!logfile_name_provided)
104
                logfileNameString = logfileDefault;
105 49 julius
            }
106 63 julius
          else if ((strcmp(argv[i], "--log-noregs")==0))
107
            {
108
              logging_regs = false;
109
            }
110
          else if ((strcmp(argv[i], "-b")==0) ||
111
                   (strcmp(argv[i], "--binlog")==0))
112
            {
113
              logging_enabled = true;
114
              binary_log_format = true;
115
              if (i+1 < argc)
116
                if(argv[i+1][0] != '-')
117
                  {
118
                    logfileNameString = (argv[i+1]);
119
                    logfile_name_provided = true;
120
                  }
121
              if (!logfile_name_provided)
122
                logfileNameString = logfileDefault;
123
 
124
            }
125
          else if ((strcmp(argv[i], "-c")==0) ||
126
                   (strcmp(argv[i], "--crash-monitor")==0))
127
            {
128
              monitor_for_crash = true;
129
            }
130 51 julius
          else if ((strcmp(argv[i], "-q")==0) ||
131
                   (strcmp(argv[i], "--quiet")==0))
132 49 julius
            {
133 63 julius
              exit_perf_summary_enabled = false;
134 49 julius
            }
135 51 julius
          else if ((strcmp(argv[i], "-p")==0) ||
136
                   (strcmp(argv[i], "--profile")==0))
137
            {
138 63 julius
              profiling_enabled = true;
139
              // Check for !end of command line and that next thing is not a 
140
              // command
141 51 julius
              if ((i+1 < argc)){
142
                if(argv[i+1][0] != '-')
143
                  profileFileName = (argv[i+1]);
144
              }
145
            }
146 63 julius
          else if ( (strcmp(argv[i], "-r")==0) ||
147
                    (strcmp(argv[i], "--rsp")==0) )
148
            {
149
              // We need to detect this here too
150
              rsp_server_enabled = true;
151
            }
152
 
153 52 julius
          else if ((strcmp(argv[i], "-m")==0) ||
154 53 julius
                   (strcmp(argv[i], "--memdump")==0))
155 52 julius
            {
156 63 julius
              do_memdump = true;
157
              // Check for !end of command line and that next thing is not a 
158
              // command or a memory address
159 52 julius
              if (i+1 < argc)
160
                {
161
                  if((argv[i+1][0] != '-') && (strncmp("0x", argv[i+1],2) != 0))
162
                    {
163
                      // Hopefully this is the filename we want to use.
164
                      // All addresses should have preceeding hex identifier 0x
165
                      memdumpFileName = argv[i+1];
166
                      // We've used this next index, can safely increment i
167
                      i++;
168
                    }
169
                }
170
              if (i+1 < argc)
171
                {
172
                  if((argv[i+1][0] != '-') && (strncmp("0x", argv[i+1],2) == 0))
173
                    {
174
                      // Hopefully this is is the start address
175
                      // All addresses should have preceeding hex identifier 0x
176
                      sscanf( argv[i+1], "0x%x", &memdump_start);
177
                      i++;
178
                    }
179
                }
180
              if (i+1 < argc)
181
                {
182
                  if((argv[i+1][0] != '-') && (strncmp("0x", argv[i+1],2) == 0))
183
                    {
184
                      // Hopefully this is is the end address
185
                      // All addresses should have preceeding hex identifier 0x
186
                      sscanf( argv[i+1], "0x%x", &memdump_end);
187
                      i++;
188
                    }
189
                }
190
            }
191 354 julius
          /*
192 63 julius
          else if ((strcmp(argv[i], "-u")==0) ||
193
                   (strcmp(argv[i], "--bus-log")==0))
194
            {
195
              bus_trans_log_enabled = true;
196
              if (i+1 < argc)
197
                if(argv[i+1][0] != '-')
198
                  {
199
                    bus_trans_log_file = (argv[i+1]);
200
                    bus_trans_log_name_provided = true;
201
                  }
202
 
203
              if (!bus_trans_log_name_provided)
204
                bus_trans_log_file = bus_trans_default_log_name;
205
 
206
              // check for a log start delay
207
              if (i+2 < argc)
208
                if(argv[i+2][0] != '-')
209
                  {
210
                    // We have a bus transaction log start delay
211
                    bus_trans_log_start_delay_enable = true;
212
                    int time_val = atoi(argv[i+2]);
213
                    sc_time log_start_time(time_val,SC_NS);
214
                    bus_trans_log_start_delay = log_start_time;
215
                  }
216
            }
217 354 julius
          */
218 49 julius
        }
219
    }
220 63 julius
 
221 49 julius
 
222 63 julius
  if (!rsp_server_enabled)
223
    {
224
      monitor_to_gdb_pipe[0][0] = monitor_to_gdb_pipe[0][1] = NULL;
225
      monitor_to_gdb_pipe[1][0] = monitor_to_gdb_pipe[1][1] = NULL;
226
    }
227
 
228 57 julius
 
229
  // checkInstruction monitors the bus for special NOP instructionsl
230
  SC_METHOD (checkInstruction);
231
  sensitive << clk.pos();
232
  dont_initialize();
233
 
234 52 julius
 
235 51 julius
  if (profiling_enabled)
236
    {
237 63 julius
 
238 51 julius
      profileFile.open(profileFileName.c_str(), ios::out); // Open profiling log file
239
      if(profileFile.is_open())
240
        {
241
          // If the file was opened OK, then enabled logging and print a message.
242 63 julius
          profiling_enabled = true;
243 51 julius
          cout << "* Execution profiling enabled. Logging to " << profileFileName << endl;
244
        }
245
 
246
      // Setup profiling function
247
      SC_METHOD (callLog);
248
      sensitive << clk.pos();
249
      dont_initialize();
250
      start = clock();
251
    }
252 49 julius
 
253 63 julius
  if(logging_enabled)
254 49 julius
    {
255 63 julius
 
256
      /* Now open the file */
257
      if (binary_log_format)
258
        statusFile.open(logfileNameString.c_str(), ios::out | ios::binary);
259
      else
260
        statusFile.open(logfileNameString.c_str(), ios::out );
261
 
262
      /* Check the open() */
263
      if(statusFile.is_open() && binary_log_format)
264 49 julius
        {
265 63 julius
          cout << "* Processor execution logged in binary format to file: " << logfileNameString << endl;
266
          /* Write out a byte indicating whether there's register values too */
267
          statusFile.write((char*)&logging_regs, 1);
268
 
269 49 julius
        }
270 63 julius
      else if (statusFile.is_open() && !binary_log_format)
271
        cout << "* Processor execution logged to file: " << logfileNameString << endl;
272
      else
273
        /* Couldn't open */
274
        logging_enabled = false;
275 49 julius
 
276
    }
277 63 julius
 
278 51 julius
  if (logging_enabled)
279 63 julius
    {
280
      if (binary_log_format)
281
        {
282
          SC_METHOD (displayStateBinary);
283
        }
284
      else
285
        {
286
          SC_METHOD (displayState);
287
        }
288 51 julius
      sensitive << clk.pos();
289
      dont_initialize();
290
      start = clock();
291 63 julius
 
292 51 julius
    }
293 49 julius
 
294 63 julius
  if (monitor_for_crash)
295
    {
296
      cout << "* Crash monitor enabled" << endl;
297
    }
298
 
299 52 julius
  // Check sizes we were given from memory dump command line options first
300
  if (do_memdump)
301
    {
302
      if ((memdump_start > ORPSOC_SRAM_SIZE) || (memdump_end > ORPSOC_SRAM_SIZE) ||
303
          ((memdump_start > memdump_end) && (memdump_end != 0)))
304
        {
305 63 julius
          do_memdump = false;
306 52 julius
          cout << "* Memory dump addresses range incorrect. Limit of memory is 0x" << hex <<  ORPSOC_SRAM_SIZE << ". Memory dumping disabled." << endl;
307
        }
308
    }
309 49 julius
 
310 52 julius
  if (do_memdump)
311
    {
312
      // Were we given dump addresses? If not, we dump all of the memory
313
      // Size of memory isn't clearly defined in any one place. This could lead to
314
      // big problems when changing size of the RAM in simulation.
315
 
316
      if (memdump_start == 0 && memdump_end == 0)
317
        memdump_end = ORPSOC_SRAM_SIZE;
318
 
319
      if (memdump_start != 0 && memdump_end == 0)
320
        {
321
          // Probably just got the single memorydump param
322
          // Interpet as a length from 0
323
          memdump_end = memdump_start;
324
          memdump_start = 0;
325
        }
326
 
327
      if (memdump_start & 0x3) memdump_start &= ~0x3; // word-align the start address      
328
      if (memdump_end & 0x3) memdump_end = (memdump_end+4) & ~0x3; // word-align the start address
329
 
330
      memdump_start_addr = memdump_start;
331
      memdump_end_addr = memdump_end;
332 63 julius
    }
333 353 julius
 
334
  /*
335 63 julius
  if (bus_trans_log_enabled)
336
    {
337
      // Setup log file and register the bus monitoring function
338
      busTransLog.open(bus_trans_log_file.c_str(), ios::out );
339
 
340
      if (busTransLog.is_open())
341
        {
342
          cout << "* System bus transactions logged to file: " <<
343
            bus_trans_log_file;
344
 
345
          if (bus_trans_log_start_delay_enable)
346
            cout << ", on at " << bus_trans_log_start_delay.to_string();
347
          cout << endl;
348
        }
349
      else
350 353 julius
        // Couldn't open
351 63 julius
        bus_trans_log_enabled = false;
352
    }
353
 
354 353 julius
 
355 63 julius
  if (bus_trans_log_enabled)
356
    {
357
      // Setup profiling function
358
      SC_METHOD (busMonitor);
359
      sensitive << clk.pos();
360
      dont_initialize();
361
    }
362 353 julius
  */
363 49 julius
 
364 6 julius
}       // Or1200MonitorSC ()
365
 
366 49 julius
//! Print usage for the options of this module
367
void
368
Or1200MonitorSC::printUsage()
369
{
370 63 julius
  printf("\nLogging and diagnostic options:\n");
371
  printf("  -p, --profile [<file>]Enable execution profiling output to <file> (default is\n\t\t\t"DEFAULT_PROF_FILE")\n");
372
  printf("  -l, --log <file>\tLog processor execution to <file>\n");
373
  printf("      --log-noregs\tLog excludes register contents\n");
374
 
375
  printf("  -b, --binlog <file>\tGenerate binary format execution log (faster, smaller)\n");
376
 
377
  printf("  -m, --memdump <file> <0xstartaddr> <0xendaddr>\n\t\t\tDump data between <0xstartaddr> and <0xendaddr> from\n\t\t\tthe system's RAM to <file> in binary format on exit\n");
378
  printf("  -c, --crash-monitor\tDetect when the processor has crashed and exit\n");
379 354 julius
/*
380 63 julius
  printf("  -u, --bus-log <file> <val>\n\t\t\tLog the wishbone bus transactions to <file>, opt. start\n\t\t\tafter <val> ns\n\n");
381 354 julius
*/
382 63 julius
 
383 49 julius
}
384
 
385 6 julius
//! Method to handle special instrutions
386
 
387
//! These are l.nop instructions with constant values. At present the
388
//! following are implemented:
389
 
390
//! - l.nop 1  Terminate the program
391
//! - l.nop 2  Report the value in R3
392
//! - l.nop 3  Printf the string with the arguments in R3, etc
393
//! - l.nop 4  Print a character
394 57 julius
 
395
//#define OR1200_OR32_NOP_BITS_31_TO_26               6'b000101
396
#define OR1200_OR32_NOP               0x14000000
397
 
398 49 julius
extern int SIM_RUNNING;
399 6 julius
void
400
Or1200MonitorSC::checkInstruction()
401
{
402
  uint32_t  r3;
403
  double    ts;
404 63 julius
  uint32_t current_WbInsn, current_WbPC;
405 51 julius
 
406 52 julius
  cycle_count++;
407 57 julius
 
408
  /* Check if this counts as an "executed" instruction */
409
  if (!accessor->getWbFreeze())
410 63 julius
    {
411
      // Cache writeback stage instruction
412
      current_WbInsn = accessor->getWbInsn();
413
 
414
      if ((((current_WbInsn & 0xfc000000) != (uint32_t) OR1200_OR32_NOP) || !(current_WbInsn & (1<<16))) && !(accessor->getExceptFlushpipe() && accessor->getExDslot()))
415 57 julius
        insn_count++;
416 63 julius
      else
417
        // Exception version
418
        if (accessor->getExceptFlushpipe())
419
          insn_count++;
420
    }
421
 
422 6 julius
  // Check the instruction when the freeze signal is low.
423 52 julius
  if ((!accessor->getWbFreeze()) && (accessor->getExceptType() == 0))
424 6 julius
    {
425
      // Do something if we have l.nop
426 63 julius
      switch (current_WbInsn)
427 6 julius
        {
428
        case NOP_EXIT:
429
          r3 = accessor->getGpr (3);
430
          ts = sc_time_stamp().to_seconds() * 1000000000.0;
431
          std::cout << std::fixed << std::setprecision (2) << ts;
432
          std::cout << " ns: Exiting (" << r3 << ")" << std::endl;
433 49 julius
          perfSummary();
434 52 julius
          if (logging_enabled) statusFile.close();
435
          if (profiling_enabled) profileFile.close();
436 63 julius
          if (bus_trans_log_enabled) busTransLog.close();
437 52 julius
          memdump();
438 49 julius
          SIM_RUNNING=0;
439 6 julius
          sc_stop();
440
          break;
441
 
442
        case NOP_REPORT:
443
          ts = sc_time_stamp().to_seconds() * 1000000000.0;
444
          r3 = accessor->getGpr (3);
445
          std::cout << std::fixed << std::setprecision (2) << ts;
446
          std::cout << " ns: report (" << hex << r3 << ")" << std::endl;
447
          break;
448
 
449
        case NOP_PRINTF:
450
          ts = sc_time_stamp().to_seconds() * 1000000000.0;
451
          std::cout << std::fixed << std::setprecision (2) << ts;
452 66 julius
          std::cout << " ns: printf: ";
453
          simPrintf(accessor->getGpr (4), accessor->getGpr (3));
454 6 julius
          break;
455
 
456
        case NOP_PUTC:
457
          r3 = accessor->getGpr (3);
458
          std::cout << (char)r3 << std::flush;
459
          break;
460 63 julius
        case NOP_CNT_RESET:
461
          std::cout << "****************** counters reset ******************" << endl;
462
          std::cout << "since last reset: cycles " << cycle_count - cycle_count_rst << ", insn #" << insn_count - insn_count_rst << endl;
463
          std::cout << "****************** counters reset ******************" << endl;
464
          cycle_count_rst = cycle_count;
465
          insn_count_rst = insn_count;
466 64 julius
          /* 3 separate counters we'll use for various things */
467
        case NOP_CNT_RESET1:
468
          std::cout << "**** counter1 cycles: " << std::setfill('0') << std::setw(10) << cycle_count - cycles_1 << " resetting ********" << endl;
469
          cycles_1 = cycle_count;
470
          break;
471
        case NOP_CNT_RESET2:
472
          std::cout << "**** counter2 cycles: " << std::setfill('0') << std::setw(10) << cycle_count - cycles_2 << " resetting ********" << endl;
473
          cycles_2 = cycle_count;
474
          break;
475
        case NOP_CNT_RESET3:
476
          std::cout << "**** counter3 cycles: " << std::setfill('0') << std::setw(10) << cycle_count - cycles_3 << " resetting ********" << endl;
477
          cycles_3 = cycle_count;
478
          break;
479 6 julius
        default:
480
          break;
481
        }
482 63 julius
 
483
      if (monitor_for_crash)
484
        {
485
          current_WbPC = accessor->getWbPC();
486
          // Look at current instruction
487
          if (current_WbInsn == 0x00000000)
488
            {
489
              // Looks like we've jumped somewhere incorrectly
490
              lookslikewevecrashed_count++;
491
            }
492
#define CRASH_MONITOR_LOG_BAD_INSNS 1
493
#if CRASH_MONITOR_LOG_BAD_INSNS
494
 
495
          /* Log so-called "bad" instructions, or at least instructions we
496
          executed, no matter if they caused us to increment
497
          lookslikewevecrashed_count, this way we get them in our list too */
498
          if (((current_WbInsn & 0xfc000000) != (uint32_t) OR1200_OR32_NOP) || !(current_WbInsn & (1<<16)))
499
            {
500
              crash_monitor_buffer[crash_monitor_buffer_head][0] = current_WbPC;
501
              crash_monitor_buffer[crash_monitor_buffer_head][1] = current_WbInsn;
502
              /* Circular buffer */
503
              if(crash_monitor_buffer_head < CRASH_MONITOR_BUFFER_SIZE-1)
504
                crash_monitor_buffer_head++;
505
              else
506
                crash_monitor_buffer_head = 0;
507
 
508
            }
509
 
510
#else
511
          else if (((current_WbInsn & 0xfc000000) != (uint32_t) OR1200_OR32_NOP) || !(current_WbInsn & (1<<16)))
512
          {
513
 
514
              crash_monitor_buffer[crash_monitor_buffer_head][0] = current_WbPC;
515
              crash_monitor_buffer[crash_monitor_buffer_head][1] = current_WbInsn;
516
              /* Circular buffer */
517
              if(crash_monitor_buffer_head < CRASH_MONITOR_BUFFER_SIZE-1)
518
                crash_monitor_buffer_head++;
519
              else
520
                crash_monitor_buffer_head = 0;
521
 
522
              /* Reset this */
523
              lookslikewevecrashed_count  = 0;
524
            }
525
#endif    
526
          if (wait_for_stall_cmd_response)
527
            {
528
              // We've already crashed, and we're issued a command to stall the
529
              // processor to the system C debug unit interface, and we're
530
              // waiting for this debug unit to send back the message that we've
531
              // stalled.
532
              char readChar;
533
              int n = read(monitor_to_gdb_pipe[1][0], &readChar, sizeof(char));
534
              if (!( ((n < 0) && (errno == EAGAIN)) || (n==0) ))
535
                wait_for_stall_cmd_response = false; // We got response
536
              lookslikewevecrashed_count = 0;
537
 
538
            }
539
          else if (lookslikewevecrashed_count > 0)
540
            {
541
 
542
              if (lookslikewevecrashed_count >= CRASH_MONITOR_BUFFER_SIZE/4)
543
                {
544
                  /* Probably crashed. Bail out, print out buffer */
545
                  std::cout << "********************************************************************************"<< endl;
546
                  std::cout << "* Looks like processor crashed. Printing last " << CRASH_MONITOR_BUFFER_SIZE << " instructions executed:" << endl;
547
 
548
                  int crash_monitor_buffer_head_end = (crash_monitor_buffer_head > 0) ? crash_monitor_buffer_head - 1 : CRASH_MONITOR_BUFFER_SIZE-1;
549
                  while (crash_monitor_buffer_head != crash_monitor_buffer_head_end)
550
                    {
551
                      std::cout << "* PC: " << std::setfill('0') << hex << std::setw(8) << crash_monitor_buffer[crash_monitor_buffer_head][0] << "  INSN: " << std::setfill('0') << hex << std::setw(8) << crash_monitor_buffer[crash_monitor_buffer_head][1] << endl;
552
 
553
                      if(crash_monitor_buffer_head < CRASH_MONITOR_BUFFER_SIZE-1)
554
                        crash_monitor_buffer_head++;
555
                      else
556
                        crash_monitor_buffer_head = 0;
557
                    }
558
                  std::cout << "********************************************************************************"<< endl;
559
 
560
                  if ( (monitor_to_gdb_pipe[0][0] != NULL))
561
                    {
562
                      // If GDB server is running, we'll pass control back to
563
                      // the debugger instead of just quitting.
564
                      char interrupt = 0x3; // Arbitrary
565
                      write(monitor_to_gdb_pipe[0][1],&interrupt,sizeof(char));
566
                      wait_for_stall_cmd_response = true;
567
                      lookslikewevecrashed_count = 0;
568
                      std::cout << "* Stalling processor and returning control to GDB"<< endl;
569
                      // Problem: the debug unit interface's stalling the processor over the simulated JTAG bus takes a while, in the meantime this monitor will continue running and keep triggering the crash detection code. We must somehow wait until the processor is stalled, or circumvent this crash detection output until we detect that the processor is stalled.
570
                      // Solution: Added another pipe, when we want to wait for preocssor to stall, we set wait_for_stall_cmd_response=true, then each time we get back to this monitor function we simply poll the pipe until we're stalled. (A blocking read didn't work - this function never yielded and the RSP server handling function never got called).
571
                      wait_for_stall_cmd_response = true;
572
 
573
                    }
574
                  else
575
                    {
576
                      // Close down sim end exit
577
                      ts = sc_time_stamp().to_seconds() * 1000000000.0;
578
                      std::cout << std::fixed << std::setprecision (2) << ts;
579
                      std::cout << " ns: Exiting (" << r3 << ")" << std::endl;
580
                      perfSummary();
581
                      if (logging_enabled) statusFile.close();
582
                      if (profiling_enabled) profileFile.close();
583
                      if (bus_trans_log_enabled) busTransLog.close();
584
                      memdump();
585
                      SIM_RUNNING=0;
586
                      sc_stop();
587
                    }
588
                }
589
            }
590
        }
591 6 julius
    }
592
}       // checkInstruction()
593
 
594 44 julius
 
595 51 julius
//! Method to log execution in terms of calls and returns
596
 
597
void
598
Or1200MonitorSC::callLog()
599
{
600
  uint32_t  exinsn, delaypc;
601
  uint32_t o_a; // operand a
602
  uint32_t o_b; // operand b
603
  struct label_entry *tmp;
604
 
605
  // Instructions should be valid when freeze is low and there are no exceptions
606
  //if (!accessor->getExFreeze())
607
  if ((!accessor->getWbFreeze()) && (accessor->getExceptType() == 0))
608
    {
609
      //exinsn = accessor->getExInsn();// & 0x3ffffff;
610
      exinsn = accessor->getWbInsn();
611
      // Check the instruction
612
      switch((exinsn >> 26) & 0x3f) { // Check Opcode - top 6 bits
613
      case 0x1:
614
        /* Instruction: l.jal */
615
        o_a = (exinsn >> 0) & 0x3ffffff;
616
        if(o_a & 0x02000000) o_a |= 0xfe000000;
617
 
618
        //delaypc = accessor->getExPC() + (o_a * 4); // PC we're jumping to
619
        delaypc = accessor->getWbPC() + (o_a * 4); // PC we're jumping to
620
        // Now we have info about where we're jumping to. Output the info, with label if possible
621
        // We print the PC we're jumping from + 8 which is the return address
622
        if ( tmp = memoryload->get_label (delaypc) )
623
          profileFile << "+" << std::setfill('0') << hex << std::setw(8) << cycle_count << " " << hex << std::setw(8) << accessor->getWbPC() + 8 << " " << hex << std::setw(8) << delaypc << " " << tmp->name << endl;
624
        else
625
          profileFile << "+" << std::setfill('0') << hex << std::setw(8) << cycle_count << " " << hex << std::setw(8) << accessor->getWbPC() + 8 << " " << hex << std::setw(8) << delaypc << " @" << hex << std::setw(8) << delaypc << endl;
626
 
627
        break;
628
      case 0x11:
629
        /* Instruction: l.jr */
630
        // Bits 15-11 contain register number
631
        o_b = (exinsn >> 11) & 0x1f;
632
        if (o_b == 9) // l.jr r9 is typical return
633
          {
634
            // Now get the value in this register
635
            delaypc = accessor->getGpr(o_b);
636
            // Output this jump
637
            profileFile << "-" << std::setfill('0') << hex << std::setw(8) << cycle_count << " "  << hex << std::setw(8) << delaypc << endl;
638
          }
639
        break;
640
      case 0x12:
641
        /* Instruction: l.jalr */
642
        o_b = (exinsn >> 11) & 0x1f;
643
        // Now get the value in this register
644
        delaypc = accessor->getGpr(o_b);
645
        // Now we have info about where we're jumping to. Output the info, with label if possible
646
        // We print the PC we're jumping from + 8 which is the return address
647
        if ( tmp = memoryload->get_label (delaypc) )
648
          profileFile << "+" << std::setfill('0') << hex << std::setw(8) << cycle_count << " " << hex << std::setw(8) << accessor->getWbPC() + 8 << " " << hex << std::setw(8) << delaypc << " " << tmp->name << endl;
649
        else
650
          profileFile << "+" << std::setfill('0') << hex << std::setw(8) << cycle_count << " " << hex << std::setw(8) << accessor->getWbPC() + 8 << " " << hex << std::setw(8) << delaypc << " @" << hex << std::setw(8) << delaypc << endl;
651
 
652
        break;
653
 
654
      }
655
    }
656 57 julius
}       // callLog()
657 51 julius
 
658
 
659 44 julius
//! Method to output the state of the processor
660
 
661
//! This function will output to a file, if enabled, the status of the processor
662 57 julius
//! This copies what the verilog testbench module, or1200_monitor does in it its
663
//! process which calls the display_arch_state tasks. This is designed to be 
664
//! identical to that process, so the output is identical
665 63 julius
 
666 44 julius
void
667
Or1200MonitorSC::displayState()
668
{
669
  // Output the state if we're not frozen and not flushing during a delay slot
670 57 julius
  if (!accessor->getWbFreeze())
671 44 julius
    {
672 57 julius
      if ((((accessor->getWbInsn() & 0xfc000000) != (uint32_t) OR1200_OR32_NOP) || !(accessor->getWbInsn() & (1<<16))) && !(accessor->getExceptFlushpipe() && accessor->getExDslot()))
673
        {
674
          // Print PC, instruction
675
          statusFile << "\nEXECUTED("<< std::setfill(' ') << std::setw(11) << dec << insn_count << "): " << std::setfill('0') << hex << std::setw(8) << accessor->getWbPC() << ":  " << hex << std::setw(8) << accessor->getWbInsn() <<  endl;
676 44 julius
        }
677 63 julius
      // Exception version
678
      else if (accessor->getExceptFlushpipe())
679
        {
680
          // Print PC, instruction, indicate it caused an exception
681
          statusFile << "\nEXECUTED("<< std::setfill(' ') << std::setw(11) << dec << insn_count << "): " << std::setfill('0') << hex << std::setw(8) << accessor->getExPC() << ":  " << hex << std::setw(8) << accessor->getExInsn() << "  (exception)" << endl;
682
        }
683 57 julius
      else
684 63 julius
        return;
685
    }
686
  else
687
    return;
688
 
689
  if (logging_regs)
690
    {
691
      // Print general purpose register contents
692
      for (int i=0; i<32; i++)
693 57 julius
        {
694 63 julius
          if ((i%4 == 0)&&(i>0)) statusFile << endl;
695
          statusFile << std::setfill('0');
696
          statusFile << "GPR" << dec << std::setw(2) << i << ": " <<  hex << std::setw(8) << (uint32_t) accessor->getGpr(i) << "  ";
697 57 julius
        }
698 63 julius
      statusFile << endl;
699 57 julius
 
700 63 julius
      statusFile << "SR   : " <<  hex << std::setw(8) << (uint32_t) accessor->getSprSr() << "  ";
701
      statusFile << "EPCR0: " <<  hex << std::setw(8) << (uint32_t) accessor->getSprEpcr() << "  ";
702
      statusFile << "EEAR0: " <<  hex << std::setw(8) << (uint32_t) accessor->getSprEear() << "  ";
703
      statusFile << "ESR0 : " <<  hex << std::setw(8) << (uint32_t) accessor->getSprEsr() << endl;
704 57 julius
 
705 44 julius
    }
706 57 julius
 
707 44 julius
  return;
708 57 julius
 
709 44 julius
}       // displayState()
710
 
711 63 julius
//! Method to output the state of the processor in binary format
712
//! File format is simply first byte indicating whether register
713
//! data is included, and then structs of the following type
714
struct s_binary_output_buffer{
715
  long long insn_count;
716
  uint32_t pc;
717
  uint32_t insn;
718
  char exception;
719
  uint32_t regs[32];
720
  uint32_t sr;
721
  uint32_t epcr0;
722
  uint32_t eear0;
723
  uint32_t eser0;
724
} __attribute__((__packed__));
725
 
726
struct s_binary_output_buffer_sans_regs{
727
  long long insn_count;
728
  uint32_t pc;
729
  uint32_t insn;
730
  char exception;
731
} __attribute__((__packed__));
732
 
733
void
734
Or1200MonitorSC::displayStateBinary()
735
{
736
  struct s_binary_output_buffer outbuf;
737
 
738
  // Output the state if we're not frozen and not flushing during a delay slot
739
  if (!accessor->getWbFreeze())
740
    {
741
      if ((((accessor->getWbInsn() & 0xfc000000) != (uint32_t) OR1200_OR32_NOP) || !(accessor->getWbInsn() & (1<<16))) && !(accessor->getExceptFlushpipe() && accessor->getExDslot()))
742
        {
743
          outbuf.insn_count = insn_count;
744
          outbuf.pc = (uint32_t) accessor->getWbPC();
745
          outbuf.insn = (uint32_t) accessor->getWbInsn();
746
          outbuf.exception = 0;
747
        }
748
      // Exception version
749
      else if (accessor->getExceptFlushpipe())
750
        {
751
          outbuf.insn_count = insn_count;
752
          outbuf.pc = (uint32_t) accessor->getExPC();
753
          outbuf.insn = (uint32_t) accessor->getExInsn();
754
          outbuf.exception = 1;
755
        }
756
      else
757
        return;
758
    }
759
  else
760
    return;
761
 
762
  if (logging_regs)
763
    {
764
      // Print general purpose register contents
765
      for (int i=0; i<32; i++)
766
          outbuf.regs[i] = (uint32_t) accessor->getGpr(i);
767
 
768
      outbuf.sr = (uint32_t) accessor->getSprSr();
769
      outbuf.epcr0 = (uint32_t) accessor->getSprEpcr();
770
      outbuf.eear0 = (uint32_t) accessor->getSprEear();
771
      outbuf.eser0 = (uint32_t) accessor->getSprEsr();
772
 
773
      statusFile.write((char*)&outbuf, sizeof(struct s_binary_output_buffer));
774
 
775
    }
776
  else
777
    statusFile.write((char*)&outbuf, sizeof(struct s_binary_output_buffer_sans_regs));
778
 
779
 
780
 
781
  return;
782
 
783
}       // displayStateBinary()
784
 
785 44 julius
//! Function to calculate the number of instructions performed and the time taken
786
void
787
Or1200MonitorSC::perfSummary()
788
{
789 49 julius
  if (exit_perf_summary_enabled)
790
    {
791
      double ts;
792
      ts = sc_time_stamp().to_seconds() * 1000000000.0;
793
      int cycles = ts / (BENCH_CLK_HALFPERIOD*2); // Number of clock cycles we had
794
 
795
      clock_t finish = clock();
796
      double elapsed_time = (double(finish)-double(start))/CLOCKS_PER_SEC;
797
      // It took elapsed_time seconds to do insn_count instructions. Divide insn_count by the time to get instructions/second.
798
      double ips = (insn_count/elapsed_time);
799
      double mips = (insn_count/elapsed_time)/1000000;
800
      int hertz = (int) ((cycles/elapsed_time)/1000);
801 57 julius
      std::cout << "* Or1200Monitor: simulated " << sc_time_stamp() << ", time elapsed: " << elapsed_time << " seconds" << endl;
802 49 julius
      std::cout << "* Or1200Monitor: simulated " << dec << cycles << " clock cycles, executed at approx " << hertz << "kHz" << endl;
803 63 julius
      std::cout << "* Or1200Monitor: simulated " << insn_count << " instructions, insn/sec. = " << ips /*<< ", mips = " << mips*/ << endl;
804 49 julius
    }
805
  return;
806
}       // perfSummary
807 44 julius
 
808 52 julius
 
809
//! Dump contents of simulation's RAM to file
810
void
811
Or1200MonitorSC::memdump()
812
{
813
  if (!do_memdump) return;
814
  uint32_t current_word;
815
  int size_words = (memdump_end_addr/4) - (memdump_start_addr/4);
816
  if (!(size_words > 0)) return;
817
 
818
  // First try opening the file
819
  memdumpFile.open(memdumpFileName.c_str(), ios::binary); // Open memorydump file
820
  if(memdumpFile.is_open())
821
    {
822
      // If we could open the file then turn on logging
823
      cout << "* Dumping system RAM from  0x" << hex << memdump_start_addr << "-0x" << hex << memdump_end_addr << " to file " << memdumpFileName << endl;
824
 
825
      while (size_words)
826
        {
827
          // Read the data from the simulation memory
828 66 julius
          current_word = accessor->get_mem32(memdump_start_addr);
829 52 julius
          // Change from whatever endian the host is (most
830
          // cases little) to big endian
831
          current_word = htonl(current_word);
832
          memdumpFile.write((char*) &current_word, 4);
833 66 julius
          memdump_start_addr+=4; size_words--;
834 52 julius
        }
835
 
836
      // Ideally we've now finished piping out the data
837
      // not 100% about the endianess of this.
838
    }
839
  memdumpFile.close();
840
 
841
}
842 63 julius
 
843 353 julius
/*
844 63 julius
void
845
Or1200MonitorSC::busMonitor()
846
{
847
 
848
  // This is for the wb_conmax module. Presumably other Wishbone bus arbiters
849
  // will need this section of the code to be re-written appropriately, along
850
  // with the relevent functions in the OrpsocAccess module.
851
 
852
  static busLogStates busLogState = BUS_LOG_IDLE;
853
  static int currentMaster = -1;
854
  static uint32_t currentAddr = 0, currentDataIn = 0;
855
  static uint32_t currentSel = 0, currentSlave = 0;
856
  static bool currentWe = false;
857
  static int cyclesWaited = 0;
858
 
859
  if (bus_trans_log_start_delay_enable)
860
    {
861
      if (sc_time_stamp() >= bus_trans_log_start_delay)
862
        {
863
          // No longer waiting
864
          bus_trans_log_start_delay_enable = false;
865
          cout << "* System log now enabled (time =  " << bus_trans_log_start_delay.to_string() << ")" << endl;
866
        }
867
 
868
      if (bus_trans_log_start_delay_enable)
869
        return;
870
    }
871
 
872
  switch ( busLogState )
873
    {
874
    case BUS_LOG_IDLE:
875
      {
876
        // Check the current granted master's cyc and stb inputs
877
        uint32_t gnt = accessor->getWbArbGrant();
878
        if (accessor->getWbArbMastCycI(gnt) && accessor->getWbArbMastStbI(gnt) &&
879
            !accessor->getWbArbMastAckO(gnt))
880
          {
881
            currentAddr = accessor->getWbArbMastAdrI(gnt);
882
            currentDataIn = accessor->getWbArbMastDatI(gnt);
883
            currentSel = (uint32_t) accessor->getWbArbMastSelI(gnt);
884
            currentSlave = (uint32_t)accessor->getWbArbMastSlaveSelDecoded(gnt)-1;
885
            currentWe = accessor->getWbArbMastWeI(gnt);
886
            currentMaster = gnt;
887
            busLogState = BUS_LOG_WAIT_FOR_ACK;
888
            cyclesWaited = 0;
889
          }
890
      }
891
 
892
      break;
893
 
894
    case BUS_LOG_WAIT_FOR_ACK:
895
 
896
      cyclesWaited++;
897
 
898
      // Check for ACK
899
      if (accessor->getWbArbMastAckO(currentMaster))
900
        {
901
          // Transaction completed
902
          busTransLog << sc_time_stamp() << " M" << currentMaster << " ";
903
          if (currentWe)
904
            busTransLog << " W " << hex << currentSel << " " << hex << std::setfill('0') << std::setw(8) << currentAddr << " S" << dec <<  currentSlave << " " << hex << std::setw(8) << currentDataIn << " " << dec << cyclesWaited << endl;
905
          else
906
            busTransLog << " R " << hex << currentSel << " " << hex << std::setfill('0') << std::setw(8) << currentAddr << " S" << dec << currentSlave << " "  << hex << std::setw(8) << accessor->getWbArbMastDatO(currentMaster) << " " << dec << cyclesWaited << endl;
907
 
908
          busLogState = BUS_LOG_IDLE;
909
        }
910
 
911
      break;
912
 
913
    }
914
 
915
  return;
916
 
917
}       // busMonitor ()
918 353 julius
*/
919 66 julius
void
920
Or1200MonitorSC::simPrintf(uint32_t stackaddr, uint32_t regparam)
921
{
922
 
923
  //cerr << hex << stackaddr << " " << regparam << endl;
924
#define FMTLEN 2000
925
  char fmtstr[FMTLEN];
926
  uint32_t arg;
927
  oraddr_t argaddr;
928
  char *fmtstrend;
929
  char *fmtstrpart = fmtstr;
930
  int tee_exe_log;
931
 
932
  /*simgetstr (stackaddr, regparam);*/
933
  /* Get the format string*/
934
  uint32_t fmtaddr;
935
  int i;
936
  fmtaddr = regparam;
937
 
938
  i = 0;
939
  while (accessor->get_mem8(fmtaddr) != '\0')
940
    {
941
      fmtstr[i++] = accessor->get_mem8(fmtaddr);
942
      fmtaddr++;
943
      if (i == FMTLEN - 1)
944
        break;
945
    }
946
  fmtstr[i] = '\0';
947
 
948
 
949
  argaddr = stackaddr;
950
  int index, last_index;
951
  index = last_index = 0;
952
  char tmp_char;
953
  while (1)
954
    {
955
      /* Look for the next format argument, or end of string */
956
      while (!(fmtstrpart[index] == '\0' || fmtstrpart[index] == '%'))
957
        index++;
958
 
959
      if (fmtstrpart[index] == '\0' && index == last_index)
960
        /* We had something like "%d\0", so we're done*/
961
        return;
962
 
963
      if (fmtstrpart[index] == '\0')
964
        {
965
          /* Final printf */
966
          printf("%s", (char*) fmtstrpart + last_index);
967
          return;
968
        }
969
      else
970
        {
971
          /* We have a section between last_index and index that we should print out*/
972
          fmtstrpart[index] = '\0'; /* Replace % with \0 for now */
973
          printf ("%s",fmtstrpart + last_index);
974
          fmtstrpart[index] = '%'; /* Replace the % */
975
        }
976
 
977
      last_index = index; /* last_index now pointing at the % */
978
 
979
      /* Now extract the part that requires formatting */
980
      /* Look for the end of the format argument*/
981
      while (!(fmtstrpart[index] == 'd' || fmtstrpart[index] == 'i'
982
               || fmtstrpart[index] == 'o' || fmtstrpart[index] == 'u'
983
               || fmtstrpart[index] == 'x' || fmtstrpart[index] == 'X'
984
               || fmtstrpart[index] == 'f' || fmtstrpart[index] == 'e'
985
               || fmtstrpart[index] == 'E' || fmtstrpart[index] == 'g'
986
               || fmtstrpart[index] == 'G' || fmtstrpart[index] == 'c'
987
               || fmtstrpart[index] == 's' || fmtstrpart[index] == '\0'
988
               || fmtstrpart[index+1] == '%'))
989
        index++;
990
 
991
      if (fmtstrpart[index] == '\0')
992
        {
993
          // Error
994
          return;
995
        }
996
      else if (fmtstrpart[index] == '%' && fmtstrpart[index+1] == '%')
997
        {
998
          /* Deal with the %% case to print a single % */
999
          index++;
1000
          printf("%%");
1001
        }
1002
      else
1003
        {
1004
          /* We now will print the part that requires the next argument */
1005
          /* Same trick, but this time remember what the char was */
1006
          tmp_char = fmtstrpart[index+1];
1007
          fmtstrpart[index+1] = '\0'; /* Replace % with \0 for now */
1008
          /* Check what we're printing*/
1009
          if (fmtstrpart[index] == 's')
1010
            {
1011
              /* It's a string, so pull it out of memory into a local char*
1012
                 and pass it to printf() */
1013
              int tmp_string_len, z;
1014
              /* Assume stackaddr already pointing at appropriate value*/
1015
              oraddr_t ormem_str_ptr = accessor->get_mem32(argaddr);
1016
 
1017
              while (accessor->get_mem8(ormem_str_ptr++) != '\0')
1018
                tmp_string_len++;
1019
              tmp_string_len++; /* One for terminating char */
1020
 
1021
              char* str = (char *) malloc (tmp_string_len);
1022
              if (str == NULL) return; /* Malloc failed, bigger issues than printf'ing out of sim */
1023
              ormem_str_ptr = accessor->get_mem32(argaddr); /* Reset start pointer value*/
1024
              for (z=0;z<tmp_string_len;z++)
1025
                str[z] = accessor->get_mem8(ormem_str_ptr+z);
1026
 
1027
              printf (fmtstrpart + last_index, str);
1028
              free (str);
1029
            }
1030
          else
1031
            {
1032
              /*
1033
                 Some other kind of variable, pull it off the stack and print
1034
                 it out. Assume stackaddr already pointing at appropriate
1035
                 value
1036
              */
1037
              arg = accessor->get_mem32(argaddr);
1038
              printf (fmtstrpart + last_index, arg);
1039
            }
1040
          argaddr+= 4; /* Increment argument pointer in stack */
1041
          fmtstrpart[index+1] = tmp_char; /* Replace the char we took out */
1042
        }
1043
      index++;
1044
      last_index = index;
1045
    }
1046
 
1047
  return;
1048
}       // simPrintf ()

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.