00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <iostream>
00027 #include <sstream>
00028 #include <string>
00029 #include <map>
00030 using namespace std;
00031
00032 #include <stdio.h>
00033 #include <stdlib.h>
00034 #ifndef _MSC_VER
00035 # include <getopt.h>
00036 #else
00037 # include "../getopt/getopt.h"
00038 # define VERSION "(git-snapshot)"
00039 #endif
00040
00041 #include "config.h"
00042
00043 #include "global.h"
00044 #include "flash.h"
00045 #include "avrdevice.h"
00046 #include "avrfactory.h"
00047 #include "gdb.h"
00048 #include "ui/ui.h"
00049 #include "systemclock.h"
00050 #include "ui/lcd.h"
00051 #include "ui/keyboard.h"
00052 #include "traceval.h"
00053 #include "ui/scope.h"
00054 #include "string2.h"
00055 #include "helper.h"
00056 #include "specialmem.h"
00057 #include "irqsystem.h"
00058
00059 #include "dumpargs.h"
00060
00061 const char *SplitOffsetFile(const char *arg,
00062 const char *name,
00063 int base,
00064 unsigned long *offset)
00065 {
00066 char *end;
00067
00068 if(!StringToUnsignedLong(arg, offset, &end, base)) {
00069 cerr << name << ": offset is not a number" << endl;
00070 exit(1);
00071 }
00072
00073 if(!*end) {
00074 cerr << name << ": argument ends before filename" << endl;
00075 exit(1);
00076 }
00077 if(*end != ',') {
00078 cerr << name << ": argument does not have comma before filename" << endl;
00079 exit(1);
00080 }
00081 ++end;
00082 if(!*end) {
00083 cerr << name << ": argument has comma but no filename" << endl;
00084 exit(1);
00085 }
00086
00087 return end;
00088 }
00089
00090 const char Usage[] =
00091 "AVR-Simulator Version " VERSION "\n"
00092 "-u run with user interface for external pin\n"
00093 " handling at port 7777\n"
00094 "-f --file <name> load elf-file <name> for simulation in simulated target\n"
00095 "-d --device <name> simulate device <name> \n"
00096 "-g --gdbserver listen for GDB connection on TCP port defined by -p\n"
00097 "-G --gdb-debug listen for GDB connection and write debug info\n"
00098 " --gdb-stdin for use with GDB as 'target remote | ./simulavr'\n"
00099 "-m <nanoseconds> maximum run time of <nanoseconds>\n"
00100 "-M disable messages for bad I/O and memory references\n"
00101 "-p <port> use <port> for gdb server\n"
00102 "-t --trace <file> enable trace outputs to <file>\n"
00103 "-n --nogdbwait do not wait for gdb connection\n"
00104 "-F --cpufrequency set the cpu frequency to <Hz> \n"
00105 "-s --irqstatistic prints statistic informations about irq usage after simulation\n"
00106 " is stopped\n"
00107 "-W --writetopipe <offset>,<file>\n"
00108 " add a special pipe register to device at\n"
00109 " IO-Offset and opens <file> for writing\n"
00110 "-R --readfrompipe <offset>,<file>\n"
00111 " add a special pipe register to device at IO-offset\n"
00112 " and opens <file> for reading\n"
00113 "-a --writetoabort <offset>\n"
00114 " add a special register at IO-offset\n"
00115 " which aborts simulator run\n"
00116 "-e --writetoexit <offset>\n"
00117 " add a special register at IO-offset\n"
00118 " which exits simulator run\n"
00119 "-V --verbose output some hints to console\n"
00120 "-T --terminate <label> or <address>\n"
00121 " stops simulation if PC runs on <label> or <address>\n"
00122 "-B --breakpoint <label> or <address>\n"
00123 " same as -T for backward compatibility\n"
00124 "-c <tracing-option> Enables a tracer with a set of options. The format for\n"
00125 " <tracing-option> is:\n"
00126 " <tracer>[:further-options ...]\n"
00127 "-o <trace-value-file> Specifies a file into which all available trace value names\n"
00128 " will be written.\n"
00129 "-v --version print out version and exit immediately\n"
00130 "-h --help print this help\n"
00131 "\n";
00132
00133 int main(int argc, char *argv[]) {
00134 int c;
00135 bool gdbserver_flag = 0;
00136 string filename("unknown");
00137 string devicename("unknown");
00138 string tracefilename("unknown");
00139 long global_gdbserver_port = 1212;
00140 int global_gdb_debug = 0;
00141 bool globalWaitForGdbConnection = true;
00142 int userinterface_flag = 0;
00143 unsigned long long fcpu = 4000000;
00144 unsigned long long maxRunTime = 0;
00145 UserInterface *ui;
00146
00147 unsigned long writeToPipeOffset = 0x20;
00148 unsigned long readFromPipeOffset = 0x21;
00149 unsigned long writeToAbort = 0;
00150 unsigned long writeToExit = 0;
00151 string readFromPipeFileName = "";
00152 string writeToPipeFileName = "";
00153
00154 vector<string> terminationArgs;
00155
00156 vector<string> tracer_opts;
00157 bool tracer_dump_avail = false;
00158 string tracer_avail_out;
00159
00160 while (1) {
00161
00162 int option_index = 0;
00163 static struct option long_options[] = {
00164 {"file", 1, 0, 'f'},
00165 {"device", 1, 0, 'd'},
00166 {"gdbserver", 0, 0, 'g'},
00167 {"gdb-debug", 0, 0, 'G'},
00168 {"debug-gdb", 0, 0, 'G'},
00169 {"maxruntime", 1, 0, 'm'},
00170 {"nogdbwait", 0, 0, 'n'},
00171 {"trace", 1, 0, 't'},
00172 {"version", 0, 0, 'v'},
00173 {"cpufrequency", 1, 0, 'F'},
00174 {"readfrompipe", 1, 0, 'R'},
00175 {"writetopipe", 1, 0, 'W'},
00176 {"writetoabort", 1, 0, 'a'},
00177 {"writetoexit", 1, 0, 'e'},
00178 {"verbose", 0, 0, 'V'},
00179 {"terminate", 1, 0, 'T'},
00180 {"breakpoint", 1, 0, 'B'},
00181 {"irqstatistic", 0, 0, 's'},
00182 {"help", 0, 0, 'h'},
00183 {0, 0, 0, 0}
00184 };
00185
00186 c = getopt_long(argc, argv, "a:e:f:d:gGm:p:t:uxyzhvnisF:R:W:VT:B:c:o:", long_options, &option_index);
00187 if(c == -1)
00188 break;
00189
00190 switch(c) {
00191 case 'B':
00192 case 'T':
00193 terminationArgs.push_back(optarg);
00194 break;
00195
00196 case 'V':
00197 global_verbose_on = 1;
00198 break;
00199
00200 case 'R':
00201 readFromPipeFileName =
00202 SplitOffsetFile(optarg, "readFromPipe", 16, &readFromPipeOffset);
00203 break;
00204
00205 case 'W':
00206 writeToPipeFileName =
00207 SplitOffsetFile(optarg, "writeToPipe", 16, &writeToPipeOffset);
00208 break;
00209
00210 case 'a':
00211 if(!StringToUnsignedLong(optarg, &writeToAbort, NULL, 16)) {
00212 cerr << "writeToAbort is not a number" << endl;
00213 exit(1);
00214 }
00215 break;
00216
00217 case 'e':
00218 if(!StringToUnsignedLong(optarg, &writeToExit, NULL, 16)) {
00219 cerr << "writeToExit is not a number" << endl;
00220 exit(1);
00221 }
00222 break;
00223
00224 case 'F':
00225 if(!StringToUnsignedLongLong(optarg, &fcpu, NULL, 10)) {
00226 cerr << "frequency is not a number" << endl;
00227 exit(1);
00228 }
00229 if(fcpu == 0) {
00230 cerr << "frequency is zero" << endl;
00231 exit(1);
00232 }
00233 if(global_verbose_on)
00234 printf("Running with CPU frequency: %1.4f MHz (%lld Hz)\n",
00235 fcpu/1000000.0, fcpu);
00236 break;
00237
00238 case 'm':
00239 if(!StringToUnsignedLongLong( optarg, &maxRunTime, NULL, 10)) {
00240 cerr << "maxRunTime is not a number" << endl;
00241 exit(1);
00242 }
00243 if(maxRunTime == 0) {
00244 cerr << "maxRunTime is zero" << endl;
00245 exit(1);
00246 }
00247 if(global_verbose_on)
00248 cout << "Maximum Run Time: " << maxRunTime << endl;
00249 break;
00250
00251 case 'u':
00252 if(global_verbose_on)
00253 cout << "Run with User Interface at Port 7777" << endl;
00254 userinterface_flag = 1;
00255 break;
00256
00257 case 'f':
00258 if(global_verbose_on)
00259 cout << "File to load: " << optarg << endl;
00260 filename = optarg;
00261 break;
00262
00263 case 'd':
00264 if(global_verbose_on)
00265 cout << "Device to simulate: " << optarg << endl;
00266 devicename = optarg;
00267 break;
00268
00269 case 'g':
00270 if(global_verbose_on)
00271 cout << "Running as gdb-server" << endl;
00272 gdbserver_flag = 1;
00273 break;
00274
00275 case 'G':
00276 if(global_verbose_on)
00277 cout << "Running with debug information from gdbserver" << endl;
00278 global_gdb_debug = 1;
00279 gdbserver_flag = 1;
00280 break;
00281
00282 case 'p':
00283 if(!StringToLong( optarg, &global_gdbserver_port, NULL, 10)) {
00284 cerr << "GDB Server Port is not a number" << endl;
00285 exit(1);
00286 }
00287 if(global_verbose_on)
00288 cout << "Running on port: " << optarg << endl;
00289 break;
00290
00291 case 't':
00292 if(global_verbose_on)
00293 cout << "Running in Trace Mode" << endl;
00294 sysConHandler.SetTraceFile(optarg, 1000000);
00295 break;
00296
00297 case 'v':
00298 cout << "SimulAVR " << VERSION << endl
00299 << "See documentation for copyright and distribution terms" << endl
00300 << endl;
00301 exit(0);
00302 break;
00303
00304 case 'n':
00305 cout << "We will NOT wait for a gdb connection, "
00306 "simulation starts now!" << endl;
00307 globalWaitForGdbConnection = false;
00308 break;
00309
00310 case 'c':
00311 tracer_opts.push_back(optarg);
00312 break;
00313
00314 case 'o':
00315 tracer_dump_avail = true;
00316 tracer_avail_out = optarg;
00317 break;
00318
00319 case 's':
00320 enableIRQStatistic = true;
00321 break;
00322
00323 default:
00324 cout << Usage
00325 << "Supported devices:" << endl
00326 << AvrFactory::supportedDevices() << endl;
00327 exit(0);
00328 }
00329 }
00330
00331
00332 DumpManager *dman = DumpManager::Instance();
00333 dman->SetSingleDeviceApp();
00334
00335
00336 AvrDevice *dev1 = AvrFactory::instance().makeDevice(devicename.c_str());
00337
00338
00339
00340 if(tracer_dump_avail) {
00341 ShowRegisteredTraceValues(tracer_avail_out);
00342 exit(0);
00343 }
00344
00345
00346 SetDumpTraceArgs(tracer_opts, dev1);
00347
00348 if(!gdbserver_flag && filename == "unknown") {
00349 cerr << "Specify either --file <executable> or --gdbserver (or --gdb-stdin)" << endl;
00350 exit(1);
00351 }
00352
00353
00354 if(readFromPipeFileName != "") {
00355 if(global_verbose_on)
00356 cout << "Add ReadFromPipe-Register at 0x"
00357 << hex << readFromPipeOffset
00358 << " and read from file: " << readFromPipeFileName << endl;
00359 dev1->ReplaceIoRegister(readFromPipeOffset,
00360 new RWReadFromFile(dev1, "FREAD", readFromPipeFileName.c_str()));
00361 }
00362
00363 if(writeToPipeFileName != "") {
00364 if(global_verbose_on)
00365 cout << "Add WriteToPipe-Register at 0x"
00366 << hex << writeToPipeOffset
00367 << " and write to file: " << writeToPipeFileName << endl;
00368 dev1->ReplaceIoRegister(writeToPipeOffset,
00369 new RWWriteToFile(dev1, "FWRITE", writeToPipeFileName.c_str()));
00370 }
00371
00372 if(writeToAbort) {
00373 if(global_verbose_on)
00374 cout << "Add WriteToAbort-Register at 0x" << hex
00375 << writeToAbort << endl;
00376 dev1->ReplaceIoRegister(writeToAbort, new RWAbort(dev1, "ABORT"));
00377 }
00378
00379 if(writeToExit) {
00380 if(global_verbose_on)
00381 cout << "Add WriteToExit-Register at 0x" << hex << writeToExit << endl;
00382 dev1->ReplaceIoRegister(writeToExit, new RWExit(dev1, "EXIT"));
00383 }
00384
00385 if(filename != "unknown" ) {
00386 dev1->Load(filename.c_str());
00387 }
00388
00389
00390 vector<string>::iterator ii;
00391 for(ii = terminationArgs.begin(); ii != terminationArgs.end(); ii++) {
00392 if(global_verbose_on)
00393 cout << "Termination or Breakpoint Symbol: " << *ii << endl;
00394 dev1->RegisterTerminationSymbol((*ii).c_str());
00395 }
00396
00397
00398 ui = (userinterface_flag == 1) ? new UserInterface(7777) : NULL;
00399
00400 dev1->SetClockFreq(1000000000 / fcpu);
00401
00402 if(sysConHandler.GetTraceState())
00403 dev1->trace_on = 1;
00404
00405 dman->start();
00406
00407 if(gdbserver_flag == 0) {
00408 SystemClock::Instance().Add(dev1);
00409 if(maxRunTime == 0) {
00410 SystemClock::Instance().Endless();
00411 } else {
00412 SystemClock::Instance().Run(maxRunTime);
00413 }
00414 } else {
00415 if(global_verbose_on)
00416 cout << "Going to gdb..." << endl;
00417 GdbServer gdb1(dev1, global_gdbserver_port, global_gdb_debug, globalWaitForGdbConnection);
00418 SystemClock::Instance().Add(&gdb1);
00419 SystemClock::Instance().Endless();
00420 }
00421
00422 dman->stopApplication();
00423
00424
00425 delete ui;
00426 delete dev1;
00427
00428 return 0;
00429 }
00430