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

Subversion Repositories openrisc

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

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 63 julius
          else if ((strcmp(argv[i], "-u")==0) ||
192
                   (strcmp(argv[i], "--bus-log")==0))
193
            {
194
              bus_trans_log_enabled = true;
195
              if (i+1 < argc)
196
                if(argv[i+1][0] != '-')
197
                  {
198
                    bus_trans_log_file = (argv[i+1]);
199
                    bus_trans_log_name_provided = true;
200
                  }
201
 
202
              if (!bus_trans_log_name_provided)
203
                bus_trans_log_file = bus_trans_default_log_name;
204
 
205
              // check for a log start delay
206
              if (i+2 < argc)
207
                if(argv[i+2][0] != '-')
208
                  {
209
                    // We have a bus transaction log start delay
210
                    bus_trans_log_start_delay_enable = true;
211
                    int time_val = atoi(argv[i+2]);
212
                    sc_time log_start_time(time_val,SC_NS);
213
                    bus_trans_log_start_delay = log_start_time;
214
                  }
215
            }
216 49 julius
        }
217
    }
218 63 julius
 
219 49 julius
 
220 63 julius
  if (!rsp_server_enabled)
221
    {
222
      monitor_to_gdb_pipe[0][0] = monitor_to_gdb_pipe[0][1] = NULL;
223
      monitor_to_gdb_pipe[1][0] = monitor_to_gdb_pipe[1][1] = NULL;
224
    }
225
 
226 57 julius
 
227
  // checkInstruction monitors the bus for special NOP instructionsl
228
  SC_METHOD (checkInstruction);
229
  sensitive << clk.pos();
230
  dont_initialize();
231
 
232 52 julius
 
233 51 julius
  if (profiling_enabled)
234
    {
235 63 julius
 
236 51 julius
      profileFile.open(profileFileName.c_str(), ios::out); // Open profiling log file
237
      if(profileFile.is_open())
238
        {
239
          // If the file was opened OK, then enabled logging and print a message.
240 63 julius
          profiling_enabled = true;
241 51 julius
          cout << "* Execution profiling enabled. Logging to " << profileFileName << endl;
242
        }
243
 
244
      // Setup profiling function
245
      SC_METHOD (callLog);
246
      sensitive << clk.pos();
247
      dont_initialize();
248
      start = clock();
249
    }
250 49 julius
 
251 63 julius
  if(logging_enabled)
252 49 julius
    {
253 63 julius
 
254
      /* Now open the file */
255
      if (binary_log_format)
256
        statusFile.open(logfileNameString.c_str(), ios::out | ios::binary);
257
      else
258
        statusFile.open(logfileNameString.c_str(), ios::out );
259
 
260
      /* Check the open() */
261
      if(statusFile.is_open() && binary_log_format)
262 49 julius
        {
263 63 julius
          cout << "* Processor execution logged in binary format to file: " << logfileNameString << endl;
264
          /* Write out a byte indicating whether there's register values too */
265
          statusFile.write((char*)&logging_regs, 1);
266
 
267 49 julius
        }
268 63 julius
      else if (statusFile.is_open() && !binary_log_format)
269
        cout << "* Processor execution logged to file: " << logfileNameString << endl;
270
      else
271
        /* Couldn't open */
272
        logging_enabled = false;
273 49 julius
 
274
    }
275 63 julius
 
276 51 julius
  if (logging_enabled)
277 63 julius
    {
278
      if (binary_log_format)
279
        {
280
          SC_METHOD (displayStateBinary);
281
        }
282
      else
283
        {
284
          SC_METHOD (displayState);
285
        }
286 51 julius
      sensitive << clk.pos();
287
      dont_initialize();
288
      start = clock();
289 63 julius
 
290 51 julius
    }
291 49 julius
 
292 63 julius
  if (monitor_for_crash)
293
    {
294
      cout << "* Crash monitor enabled" << endl;
295
    }
296
 
297 52 julius
  // Check sizes we were given from memory dump command line options first
298
  if (do_memdump)
299
    {
300
      if ((memdump_start > ORPSOC_SRAM_SIZE) || (memdump_end > ORPSOC_SRAM_SIZE) ||
301
          ((memdump_start > memdump_end) && (memdump_end != 0)))
302
        {
303 63 julius
          do_memdump = false;
304 52 julius
          cout << "* Memory dump addresses range incorrect. Limit of memory is 0x" << hex <<  ORPSOC_SRAM_SIZE << ". Memory dumping disabled." << endl;
305
        }
306
    }
307 49 julius
 
308 52 julius
  if (do_memdump)
309
    {
310
      // Were we given dump addresses? If not, we dump all of the memory
311
      // Size of memory isn't clearly defined in any one place. This could lead to
312
      // big problems when changing size of the RAM in simulation.
313
 
314
      if (memdump_start == 0 && memdump_end == 0)
315
        memdump_end = ORPSOC_SRAM_SIZE;
316
 
317
      if (memdump_start != 0 && memdump_end == 0)
318
        {
319
          // Probably just got the single memorydump param
320
          // Interpet as a length from 0
321
          memdump_end = memdump_start;
322
          memdump_start = 0;
323
        }
324
 
325
      if (memdump_start & 0x3) memdump_start &= ~0x3; // word-align the start address      
326
      if (memdump_end & 0x3) memdump_end = (memdump_end+4) & ~0x3; // word-align the start address
327
 
328
      memdump_start_addr = memdump_start;
329
      memdump_end_addr = memdump_end;
330 63 julius
    }
331
 
332
  if (bus_trans_log_enabled)
333
    {
334
      // Setup log file and register the bus monitoring function
335
      busTransLog.open(bus_trans_log_file.c_str(), ios::out );
336
 
337
      if (busTransLog.is_open())
338
        {
339
          cout << "* System bus transactions logged to file: " <<
340
            bus_trans_log_file;
341
 
342
          if (bus_trans_log_start_delay_enable)
343
            cout << ", on at " << bus_trans_log_start_delay.to_string();
344
          cout << endl;
345
        }
346
      else
347
        /* Couldn't open */
348
        bus_trans_log_enabled = false;
349
    }
350
 
351
  if (bus_trans_log_enabled)
352
    {
353
      // Setup profiling function
354
      SC_METHOD (busMonitor);
355
      sensitive << clk.pos();
356
      dont_initialize();
357
    }
358 49 julius
 
359 6 julius
}       // Or1200MonitorSC ()
360
 
361 49 julius
//! Print usage for the options of this module
362
void
363
Or1200MonitorSC::printUsage()
364
{
365 63 julius
  printf("\nLogging and diagnostic options:\n");
366
  printf("  -p, --profile [<file>]Enable execution profiling output to <file> (default is\n\t\t\t"DEFAULT_PROF_FILE")\n");
367
  printf("  -l, --log <file>\tLog processor execution to <file>\n");
368
  printf("      --log-noregs\tLog excludes register contents\n");
369
 
370
  printf("  -b, --binlog <file>\tGenerate binary format execution log (faster, smaller)\n");
371
 
372 49 julius
  printf("  -q, --quiet\t\tDisable the performance summary at end of simulation\n");
373 63 julius
  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");
374
  printf("  -c, --crash-monitor\tDetect when the processor has crashed and exit\n");
375
  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");
376
 
377 49 julius
}
378
 
379 6 julius
//! Method to handle special instrutions
380
 
381
//! These are l.nop instructions with constant values. At present the
382
//! following are implemented:
383
 
384
//! - l.nop 1  Terminate the program
385
//! - l.nop 2  Report the value in R3
386
//! - l.nop 3  Printf the string with the arguments in R3, etc
387
//! - l.nop 4  Print a character
388 57 julius
 
389
//#define OR1200_OR32_NOP_BITS_31_TO_26               6'b000101
390
#define OR1200_OR32_NOP               0x14000000
391
 
392 49 julius
extern int SIM_RUNNING;
393 6 julius
void
394
Or1200MonitorSC::checkInstruction()
395
{
396
  uint32_t  r3;
397
  double    ts;
398 63 julius
  uint32_t current_WbInsn, current_WbPC;
399 51 julius
 
400 52 julius
  cycle_count++;
401 57 julius
 
402
  /* Check if this counts as an "executed" instruction */
403
  if (!accessor->getWbFreeze())
404 63 julius
    {
405
      // Cache writeback stage instruction
406
      current_WbInsn = accessor->getWbInsn();
407
 
408
      if ((((current_WbInsn & 0xfc000000) != (uint32_t) OR1200_OR32_NOP) || !(current_WbInsn & (1<<16))) && !(accessor->getExceptFlushpipe() && accessor->getExDslot()))
409 57 julius
        insn_count++;
410 63 julius
      else
411
        // Exception version
412
        if (accessor->getExceptFlushpipe())
413
          insn_count++;
414
    }
415
 
416 6 julius
  // Check the instruction when the freeze signal is low.
417 52 julius
  if ((!accessor->getWbFreeze()) && (accessor->getExceptType() == 0))
418 6 julius
    {
419
      // Do something if we have l.nop
420 63 julius
      switch (current_WbInsn)
421 6 julius
        {
422
        case NOP_EXIT:
423
          r3 = accessor->getGpr (3);
424
          ts = sc_time_stamp().to_seconds() * 1000000000.0;
425
          std::cout << std::fixed << std::setprecision (2) << ts;
426
          std::cout << " ns: Exiting (" << r3 << ")" << std::endl;
427 49 julius
          perfSummary();
428 52 julius
          if (logging_enabled) statusFile.close();
429
          if (profiling_enabled) profileFile.close();
430 63 julius
          if (bus_trans_log_enabled) busTransLog.close();
431 52 julius
          memdump();
432 49 julius
          SIM_RUNNING=0;
433 6 julius
          sc_stop();
434
          break;
435
 
436
        case NOP_REPORT:
437
          ts = sc_time_stamp().to_seconds() * 1000000000.0;
438
          r3 = accessor->getGpr (3);
439
          std::cout << std::fixed << std::setprecision (2) << ts;
440
          std::cout << " ns: report (" << hex << r3 << ")" << std::endl;
441
          break;
442
 
443
        case NOP_PRINTF:
444
          ts = sc_time_stamp().to_seconds() * 1000000000.0;
445
          std::cout << std::fixed << std::setprecision (2) << ts;
446
          std::cout << " ns: printf" << std::endl;
447
          break;
448
 
449
        case NOP_PUTC:
450
          r3 = accessor->getGpr (3);
451
          std::cout << (char)r3 << std::flush;
452
          break;
453 63 julius
        case NOP_CNT_RESET:
454
          std::cout << "****************** counters reset ******************" << endl;
455
          std::cout << "since last reset: cycles " << cycle_count - cycle_count_rst << ", insn #" << insn_count - insn_count_rst << endl;
456
          std::cout << "****************** counters reset ******************" << endl;
457
          cycle_count_rst = cycle_count;
458
          insn_count_rst = insn_count;
459 64 julius
          /* 3 separate counters we'll use for various things */
460
        case NOP_CNT_RESET1:
461
          std::cout << "**** counter1 cycles: " << std::setfill('0') << std::setw(10) << cycle_count - cycles_1 << " resetting ********" << endl;
462
          cycles_1 = cycle_count;
463
          break;
464
        case NOP_CNT_RESET2:
465
          std::cout << "**** counter2 cycles: " << std::setfill('0') << std::setw(10) << cycle_count - cycles_2 << " resetting ********" << endl;
466
          cycles_2 = cycle_count;
467
          break;
468
        case NOP_CNT_RESET3:
469
          std::cout << "**** counter3 cycles: " << std::setfill('0') << std::setw(10) << cycle_count - cycles_3 << " resetting ********" << endl;
470
          cycles_3 = cycle_count;
471
          break;
472 6 julius
        default:
473
          break;
474
        }
475 63 julius
 
476
      if (monitor_for_crash)
477
        {
478
          current_WbPC = accessor->getWbPC();
479
          // Look at current instruction
480
          if (current_WbInsn == 0x00000000)
481
            {
482
              // Looks like we've jumped somewhere incorrectly
483
              lookslikewevecrashed_count++;
484
            }
485
#define CRASH_MONITOR_LOG_BAD_INSNS 1
486
#if CRASH_MONITOR_LOG_BAD_INSNS
487
 
488
          /* Log so-called "bad" instructions, or at least instructions we
489
          executed, no matter if they caused us to increment
490
          lookslikewevecrashed_count, this way we get them in our list too */
491
          if (((current_WbInsn & 0xfc000000) != (uint32_t) OR1200_OR32_NOP) || !(current_WbInsn & (1<<16)))
492
            {
493
              crash_monitor_buffer[crash_monitor_buffer_head][0] = current_WbPC;
494
              crash_monitor_buffer[crash_monitor_buffer_head][1] = current_WbInsn;
495
              /* Circular buffer */
496
              if(crash_monitor_buffer_head < CRASH_MONITOR_BUFFER_SIZE-1)
497
                crash_monitor_buffer_head++;
498
              else
499
                crash_monitor_buffer_head = 0;
500
 
501
            }
502
 
503
#else
504
          else if (((current_WbInsn & 0xfc000000) != (uint32_t) OR1200_OR32_NOP) || !(current_WbInsn & (1<<16)))
505
          {
506
 
507
              crash_monitor_buffer[crash_monitor_buffer_head][0] = current_WbPC;
508
              crash_monitor_buffer[crash_monitor_buffer_head][1] = current_WbInsn;
509
              /* Circular buffer */
510
              if(crash_monitor_buffer_head < CRASH_MONITOR_BUFFER_SIZE-1)
511
                crash_monitor_buffer_head++;
512
              else
513
                crash_monitor_buffer_head = 0;
514
 
515
              /* Reset this */
516
              lookslikewevecrashed_count  = 0;
517
            }
518
#endif    
519
          if (wait_for_stall_cmd_response)
520
            {
521
              // We've already crashed, and we're issued a command to stall the
522
              // processor to the system C debug unit interface, and we're
523
              // waiting for this debug unit to send back the message that we've
524
              // stalled.
525
              char readChar;
526
              int n = read(monitor_to_gdb_pipe[1][0], &readChar, sizeof(char));
527
              if (!( ((n < 0) && (errno == EAGAIN)) || (n==0) ))
528
                wait_for_stall_cmd_response = false; // We got response
529
              lookslikewevecrashed_count = 0;
530
 
531
            }
532
          else if (lookslikewevecrashed_count > 0)
533
            {
534
 
535
              if (lookslikewevecrashed_count >= CRASH_MONITOR_BUFFER_SIZE/4)
536
                {
537
                  /* Probably crashed. Bail out, print out buffer */
538
                  std::cout << "********************************************************************************"<< endl;
539
                  std::cout << "* Looks like processor crashed. Printing last " << CRASH_MONITOR_BUFFER_SIZE << " instructions executed:" << endl;
540
 
541
                  int crash_monitor_buffer_head_end = (crash_monitor_buffer_head > 0) ? crash_monitor_buffer_head - 1 : CRASH_MONITOR_BUFFER_SIZE-1;
542
                  while (crash_monitor_buffer_head != crash_monitor_buffer_head_end)
543
                    {
544
                      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;
545
 
546
                      if(crash_monitor_buffer_head < CRASH_MONITOR_BUFFER_SIZE-1)
547
                        crash_monitor_buffer_head++;
548
                      else
549
                        crash_monitor_buffer_head = 0;
550
                    }
551
                  std::cout << "********************************************************************************"<< endl;
552
 
553
                  if ( (monitor_to_gdb_pipe[0][0] != NULL))
554
                    {
555
                      // If GDB server is running, we'll pass control back to
556
                      // the debugger instead of just quitting.
557
                      char interrupt = 0x3; // Arbitrary
558
                      write(monitor_to_gdb_pipe[0][1],&interrupt,sizeof(char));
559
                      wait_for_stall_cmd_response = true;
560
                      lookslikewevecrashed_count = 0;
561
                      std::cout << "* Stalling processor and returning control to GDB"<< endl;
562
                      // 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.
563
                      // 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).
564
                      wait_for_stall_cmd_response = true;
565
 
566
                    }
567
                  else
568
                    {
569
                      // Close down sim end exit
570
                      ts = sc_time_stamp().to_seconds() * 1000000000.0;
571
                      std::cout << std::fixed << std::setprecision (2) << ts;
572
                      std::cout << " ns: Exiting (" << r3 << ")" << std::endl;
573
                      perfSummary();
574
                      if (logging_enabled) statusFile.close();
575
                      if (profiling_enabled) profileFile.close();
576
                      if (bus_trans_log_enabled) busTransLog.close();
577
                      memdump();
578
                      SIM_RUNNING=0;
579
                      sc_stop();
580
                    }
581
                }
582
            }
583
        }
584 6 julius
    }
585
}       // checkInstruction()
586
 
587 44 julius
 
588 51 julius
//! Method to log execution in terms of calls and returns
589
 
590
void
591
Or1200MonitorSC::callLog()
592
{
593
  uint32_t  exinsn, delaypc;
594
  uint32_t o_a; // operand a
595
  uint32_t o_b; // operand b
596
  struct label_entry *tmp;
597
 
598
  // Instructions should be valid when freeze is low and there are no exceptions
599
  //if (!accessor->getExFreeze())
600
  if ((!accessor->getWbFreeze()) && (accessor->getExceptType() == 0))
601
    {
602
      //exinsn = accessor->getExInsn();// & 0x3ffffff;
603
      exinsn = accessor->getWbInsn();
604
      // Check the instruction
605
      switch((exinsn >> 26) & 0x3f) { // Check Opcode - top 6 bits
606
      case 0x1:
607
        /* Instruction: l.jal */
608
        o_a = (exinsn >> 0) & 0x3ffffff;
609
        if(o_a & 0x02000000) o_a |= 0xfe000000;
610
 
611
        //delaypc = accessor->getExPC() + (o_a * 4); // PC we're jumping to
612
        delaypc = accessor->getWbPC() + (o_a * 4); // PC we're jumping to
613
        // Now we have info about where we're jumping to. Output the info, with label if possible
614
        // We print the PC we're jumping from + 8 which is the return address
615
        if ( tmp = memoryload->get_label (delaypc) )
616
          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;
617
        else
618
          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;
619
 
620
        break;
621
      case 0x11:
622
        /* Instruction: l.jr */
623
        // Bits 15-11 contain register number
624
        o_b = (exinsn >> 11) & 0x1f;
625
        if (o_b == 9) // l.jr r9 is typical return
626
          {
627
            // Now get the value in this register
628
            delaypc = accessor->getGpr(o_b);
629
            // Output this jump
630
            profileFile << "-" << std::setfill('0') << hex << std::setw(8) << cycle_count << " "  << hex << std::setw(8) << delaypc << endl;
631
          }
632
        break;
633
      case 0x12:
634
        /* Instruction: l.jalr */
635
        o_b = (exinsn >> 11) & 0x1f;
636
        // Now get the value in this register
637
        delaypc = accessor->getGpr(o_b);
638
        // Now we have info about where we're jumping to. Output the info, with label if possible
639
        // We print the PC we're jumping from + 8 which is the return address
640
        if ( tmp = memoryload->get_label (delaypc) )
641
          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;
642
        else
643
          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;
644
 
645
        break;
646
 
647
      }
648
    }
649 57 julius
}       // callLog()
650 51 julius
 
651
 
652 44 julius
//! Method to output the state of the processor
653
 
654
//! This function will output to a file, if enabled, the status of the processor
655 57 julius
//! This copies what the verilog testbench module, or1200_monitor does in it its
656
//! process which calls the display_arch_state tasks. This is designed to be 
657
//! identical to that process, so the output is identical
658 63 julius
 
659 44 julius
void
660
Or1200MonitorSC::displayState()
661
{
662
  // Output the state if we're not frozen and not flushing during a delay slot
663 57 julius
  if (!accessor->getWbFreeze())
664 44 julius
    {
665 57 julius
      if ((((accessor->getWbInsn() & 0xfc000000) != (uint32_t) OR1200_OR32_NOP) || !(accessor->getWbInsn() & (1<<16))) && !(accessor->getExceptFlushpipe() && accessor->getExDslot()))
666
        {
667
          // Print PC, instruction
668
          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;
669 44 julius
        }
670 63 julius
      // Exception version
671
      else if (accessor->getExceptFlushpipe())
672
        {
673
          // Print PC, instruction, indicate it caused an exception
674
          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;
675
        }
676 57 julius
      else
677 63 julius
        return;
678
    }
679
  else
680
    return;
681
 
682
  if (logging_regs)
683
    {
684
      // Print general purpose register contents
685
      for (int i=0; i<32; i++)
686 57 julius
        {
687 63 julius
          if ((i%4 == 0)&&(i>0)) statusFile << endl;
688
          statusFile << std::setfill('0');
689
          statusFile << "GPR" << dec << std::setw(2) << i << ": " <<  hex << std::setw(8) << (uint32_t) accessor->getGpr(i) << "  ";
690 57 julius
        }
691 63 julius
      statusFile << endl;
692 57 julius
 
693 63 julius
      statusFile << "SR   : " <<  hex << std::setw(8) << (uint32_t) accessor->getSprSr() << "  ";
694
      statusFile << "EPCR0: " <<  hex << std::setw(8) << (uint32_t) accessor->getSprEpcr() << "  ";
695
      statusFile << "EEAR0: " <<  hex << std::setw(8) << (uint32_t) accessor->getSprEear() << "  ";
696
      statusFile << "ESR0 : " <<  hex << std::setw(8) << (uint32_t) accessor->getSprEsr() << endl;
697 57 julius
 
698 44 julius
    }
699 57 julius
 
700 44 julius
  return;
701 57 julius
 
702 44 julius
}       // displayState()
703
 
704 63 julius
//! Method to output the state of the processor in binary format
705
//! File format is simply first byte indicating whether register
706
//! data is included, and then structs of the following type
707
struct s_binary_output_buffer{
708
  long long insn_count;
709
  uint32_t pc;
710
  uint32_t insn;
711
  char exception;
712
  uint32_t regs[32];
713
  uint32_t sr;
714
  uint32_t epcr0;
715
  uint32_t eear0;
716
  uint32_t eser0;
717
} __attribute__((__packed__));
718
 
719
struct s_binary_output_buffer_sans_regs{
720
  long long insn_count;
721
  uint32_t pc;
722
  uint32_t insn;
723
  char exception;
724
} __attribute__((__packed__));
725
 
726
void
727
Or1200MonitorSC::displayStateBinary()
728
{
729
  struct s_binary_output_buffer outbuf;
730
 
731
  // Output the state if we're not frozen and not flushing during a delay slot
732
  if (!accessor->getWbFreeze())
733
    {
734
      if ((((accessor->getWbInsn() & 0xfc000000) != (uint32_t) OR1200_OR32_NOP) || !(accessor->getWbInsn() & (1<<16))) && !(accessor->getExceptFlushpipe() && accessor->getExDslot()))
735
        {
736
          outbuf.insn_count = insn_count;
737
          outbuf.pc = (uint32_t) accessor->getWbPC();
738
          outbuf.insn = (uint32_t) accessor->getWbInsn();
739
          outbuf.exception = 0;
740
        }
741
      // Exception version
742
      else if (accessor->getExceptFlushpipe())
743
        {
744
          outbuf.insn_count = insn_count;
745
          outbuf.pc = (uint32_t) accessor->getExPC();
746
          outbuf.insn = (uint32_t) accessor->getExInsn();
747
          outbuf.exception = 1;
748
        }
749
      else
750
        return;
751
    }
752
  else
753
    return;
754
 
755
  if (logging_regs)
756
    {
757
      // Print general purpose register contents
758
      for (int i=0; i<32; i++)
759
          outbuf.regs[i] = (uint32_t) accessor->getGpr(i);
760
 
761
      outbuf.sr = (uint32_t) accessor->getSprSr();
762
      outbuf.epcr0 = (uint32_t) accessor->getSprEpcr();
763
      outbuf.eear0 = (uint32_t) accessor->getSprEear();
764
      outbuf.eser0 = (uint32_t) accessor->getSprEsr();
765
 
766
      statusFile.write((char*)&outbuf, sizeof(struct s_binary_output_buffer));
767
 
768
    }
769
  else
770
    statusFile.write((char*)&outbuf, sizeof(struct s_binary_output_buffer_sans_regs));
771
 
772
 
773
 
774
  return;
775
 
776
}       // displayStateBinary()
777
 
778 44 julius
//! Function to calculate the number of instructions performed and the time taken
779
void
780
Or1200MonitorSC::perfSummary()
781
{
782 49 julius
  if (exit_perf_summary_enabled)
783
    {
784
      double ts;
785
      ts = sc_time_stamp().to_seconds() * 1000000000.0;
786
      int cycles = ts / (BENCH_CLK_HALFPERIOD*2); // Number of clock cycles we had
787
 
788
      clock_t finish = clock();
789
      double elapsed_time = (double(finish)-double(start))/CLOCKS_PER_SEC;
790
      // It took elapsed_time seconds to do insn_count instructions. Divide insn_count by the time to get instructions/second.
791
      double ips = (insn_count/elapsed_time);
792
      double mips = (insn_count/elapsed_time)/1000000;
793
      int hertz = (int) ((cycles/elapsed_time)/1000);
794 57 julius
      std::cout << "* Or1200Monitor: simulated " << sc_time_stamp() << ", time elapsed: " << elapsed_time << " seconds" << endl;
795 49 julius
      std::cout << "* Or1200Monitor: simulated " << dec << cycles << " clock cycles, executed at approx " << hertz << "kHz" << endl;
796 63 julius
      std::cout << "* Or1200Monitor: simulated " << insn_count << " instructions, insn/sec. = " << ips /*<< ", mips = " << mips*/ << endl;
797 49 julius
    }
798
  return;
799
}       // perfSummary
800 44 julius
 
801 52 julius
 
802
//! Dump contents of simulation's RAM to file
803
void
804
Or1200MonitorSC::memdump()
805
{
806
  if (!do_memdump) return;
807
  uint32_t current_word;
808
  int size_words = (memdump_end_addr/4) - (memdump_start_addr/4);
809
  if (!(size_words > 0)) return;
810
 
811
  // First try opening the file
812
  memdumpFile.open(memdumpFileName.c_str(), ios::binary); // Open memorydump file
813
  if(memdumpFile.is_open())
814
    {
815
      // If we could open the file then turn on logging
816
      cout << "* Dumping system RAM from  0x" << hex << memdump_start_addr << "-0x" << hex << memdump_end_addr << " to file " << memdumpFileName << endl;
817
 
818
      // Convert memdump_start_addr to word address
819
      memdump_start_addr = memdump_start_addr / 4;
820
      while (size_words)
821
        {
822
          // Read the data from the simulation memory
823
          current_word = accessor->get_mem(memdump_start_addr);
824
          //cout << hex << current_word << " ";
825
          /*
826
          cout << hex << ((current_word >> 24 ) & 0xff) << " ";
827
          cout << hex << ((current_word >> 16) & 0xff) << " ";
828
          cout << hex << ((current_word >> 8 ) & 0xff) << " " ;
829
          cout << hex << ((current_word >> 0 ) & 0xff) << " ";
830
          */
831
          // Change from whatever endian the host is (most
832
          // cases little) to big endian
833
          current_word = htonl(current_word);
834
          memdumpFile.write((char*) &current_word, 4);
835
          memdump_start_addr++; size_words--;
836
        }
837
 
838
      // Ideally we've now finished piping out the data
839
      // not 100% about the endianess of this.
840
    }
841
  memdumpFile.close();
842
 
843
}
844 63 julius
 
845
 
846
void
847
Or1200MonitorSC::busMonitor()
848
{
849
 
850
  // This is for the wb_conmax module. Presumably other Wishbone bus arbiters 
851
  // will need this section of the code to be re-written appropriately, along 
852
  // with the relevent functions in the OrpsocAccess module.
853
 
854
  static busLogStates busLogState = BUS_LOG_IDLE;
855
  static int currentMaster = -1;
856
  static uint32_t currentAddr = 0, currentDataIn = 0;
857
  static uint32_t currentSel = 0, currentSlave = 0;
858
  static bool currentWe = false;
859
  static int cyclesWaited = 0;
860
 
861
  if (bus_trans_log_start_delay_enable)
862
    {
863
      if (sc_time_stamp() >= bus_trans_log_start_delay)
864
        {
865
          // No longer waiting
866
          bus_trans_log_start_delay_enable = false;
867
          cout << "* System log now enabled (time =  " << bus_trans_log_start_delay.to_string() << ")" << endl;
868
        }
869
 
870
      if (bus_trans_log_start_delay_enable)
871
        return;
872
    }
873
 
874
  switch ( busLogState )
875
    {
876
    case BUS_LOG_IDLE:
877
      {
878
        // Check the current granted master's cyc and stb inputs
879
        uint32_t gnt = accessor->getWbArbGrant();
880
        if (accessor->getWbArbMastCycI(gnt) && accessor->getWbArbMastStbI(gnt) &&
881
            !accessor->getWbArbMastAckO(gnt))
882
          {
883
            currentAddr = accessor->getWbArbMastAdrI(gnt);
884
            currentDataIn = accessor->getWbArbMastDatI(gnt);
885
            currentSel = (uint32_t) accessor->getWbArbMastSelI(gnt);
886
            currentSlave = (uint32_t)accessor->getWbArbMastSlaveSelDecoded(gnt)-1;
887
            currentWe = accessor->getWbArbMastWeI(gnt);
888
            currentMaster = gnt;
889
            busLogState = BUS_LOG_WAIT_FOR_ACK;
890
            cyclesWaited = 0;
891
          }
892
      }
893
 
894
      break;
895
 
896
    case BUS_LOG_WAIT_FOR_ACK:
897
 
898
      cyclesWaited++;
899
 
900
      // Check for ACK
901
      if (accessor->getWbArbMastAckO(currentMaster))
902
        {
903
          // Transaction completed
904
          busTransLog << sc_time_stamp() << " M" << currentMaster << " ";
905
          if (currentWe)
906
            busTransLog << " W " << hex << currentSel << " " << hex << std::setfill('0') << std::setw(8) << currentAddr << " S" << dec <<  currentSlave << " " << hex << std::setw(8) << currentDataIn << " " << dec << cyclesWaited << endl;
907
          else
908
            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;
909
 
910
          busLogState = BUS_LOG_IDLE;
911
        }
912
 
913
      break;
914
 
915
    }
916
 
917
  return;
918
 
919
}       // busMonitor ()

powered by: WebSVN 2.1.0

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