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

Subversion Repositories openrisc

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

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

powered by: WebSVN 2.1.0

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