avr: Trace no longer a singleton
[avr-sim.git] / src / avr-sim.cpp
blobdc40341c00026fd082db1e7aacd1881da7c7e0da
1 /*
2 * avr-sim: An atmel AVR simulator
3 * Copyright (C) 2008 Tom Haber
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "config.h"
21 #include <iostream>
22 #include <getopt.h>
23 #include <errno.h>
24 #include <cstring>
26 #ifdef _POSIX_SOURCE
27 # include <signal.h>
28 # include <setjmp.h>
30 # define TIOCGWINSZ
31 # include <sys/ioctl.h>
32 #endif
34 #include "VerboseInfo.h"
35 #include "SimulationClock.h"
36 #include "GdbServer.h"
38 #include "BfdProgram.h"
39 #include "HexProgram.h"
41 #ifdef ENABLE_SCRIPTING
42 #include "ScriptEngine.h"
43 #endif
45 #include "Trace.h"
46 #include "Device.h"
47 #include "DeviceSettings.h"
49 using namespace avr;
51 #define AVR_SIM_VERSION "0.1"
53 enum ProgramType {
54 #ifdef HAVE_LIBBFD
55 PROG_BFD,
56 #endif
57 PROG_HEX,
58 PROG_NONE
61 ProgramType defaultProgramType =
62 #ifdef HAVE_LIBBFD
63 PROG_BFD; // Default Bfd
64 #else
65 PROG_HEX; // Default Hex
66 #endif
68 static void list_supported_devices() {
69 unsigned int lineLength = 80;
72 const char *p = getenv("COLUMNS");
73 if( (p != 0) && (*p != '\0') ) {
74 errno = 0;
75 unsigned long int tmp_ulong = strtoul(p, NULL, 10);
77 if( errno == 0 )
78 lineLength = tmp_ulong;
82 #ifdef TIOCGWINSZ
84 struct winsize ws;
86 if( (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1)
87 && (0 < ws.ws_col) && (ws.ws_col == (size_t) ws.ws_col) )
88 lineLength = ws.ws_col;
90 #endif
92 DeviceSettings::listAll(lineLength);
95 static void print_usage() {
96 std::cout << "AVR-Simulator"<< std::endl
97 << "-u run with user interface for external pin handling at port 7777\n"
98 << "-f --file <name> load file <name> for simulation in simulated target\n"
99 #ifdef HAVE_LIBBFD
100 << "-b --bfd-file specified filename is a bfd file (elf,coff)\n"
101 #endif
102 << "-x --hex-file specified filename is a hex file\n"
103 << "-d --device <device name> simulate <device name>\n"
104 << "-a --analyzer <name> add analyzer <name> (scripts are added using script:<script>)\n"
105 << "-s --scriptconfig <filename> config file for scripts\n"
106 << "-g --gdbserver running as gdb-server\n"
107 << "-p <port> change <port> for gdb server to port\n"
108 << "-t --trace <file name> enable trace outputs into <file name>\n"
109 << "-l --listtrace <file name> list trace outputs from <file name>\n"
110 << "-F --cpufrequence set the cpu frequence to <Hz>\n"
111 << "-c --clockticks set the number of clocks ticks to execute\n"
112 << "-v --verbose output some hints to console\n"
113 << "-h --help outputs this\n"
114 << std::endl;
116 std::cout << "Supported devices:"<< std::endl;
117 list_supported_devices();
118 std::cout << std::endl;
120 #ifdef HAVE_LIBBFD
121 std::cout << "Bfd file loading is enabled" << std::endl;
122 #endif
123 #if defined(HAVE_LUA) && defined(ENABLE_SCRIPTING)
124 std::cout << "Lua scripting is enabled" << std::endl;
125 #endif
127 exit(0);
130 static sim::SimulationClock simclock;
132 #ifdef _POSIX_SOURCE
133 static void signal_handler(int /*sig*/) {
134 simclock.finish();
137 static void enable_signal_handler(int sig = SIGINT) {
138 struct sigaction action;
139 action.sa_flags = 0;
140 action.sa_handler = signal_handler;
141 sigemptyset( &action.sa_mask );
143 sigaction( sig, &action, 0 );
145 #endif
147 #ifdef ENABLE_SCRIPTING
148 struct IsScript {
149 bool operator ()(const char *str) {
150 const char *scriptPrefix = "script:";
151 return strncmp( str, scriptPrefix, strlen(scriptPrefix) ) == 0;
155 static bool HaveScripts(const std::list<const char *> & analyzers) {
156 return ( std::find_if(analyzers.begin(), analyzers.end(), IsScript()) != analyzers.end() );
158 #endif
160 static void addAnalyzers(Device & dev, const std::list<const char *> & names) {
161 std::list<const char *>::const_iterator it;
162 for(it = names.begin(); it != names.end(); ++it)
163 dev.addAnalyzer( *it );
166 int main(int argc, char *argv[]) {
167 const char *devicename = "atmega162";
168 const char *filename = 0;
169 const char *listtrace = 0;
170 const char *tracefile = 0;
171 unsigned long long fcpu = 0;
172 bool gdbserver = false;
173 int gdbserver_port = 1234;
174 sim::ClockOffset clockTicks = 0;
175 ProgramType programType = PROG_NONE;
177 std::list<const char *> analyzers;
178 const char *scriptconfig = 0;
180 static struct option long_options[] = {
181 { "file", 1, 0, 'f' },
182 #ifdef HAVE_LIBBFD
183 { "bfd-file", 0, 0, 'b' },
184 #endif
185 { "hex-file", 0, 0, 'x' },
186 { "device", 1, 0, 'd' },
187 { "analyzer", 1, 0, 'a' },
188 { "scriptconfig", 1, 0, 's' },
189 { "gdb", 0, 0, 'g' },
190 { "gdbserver", 0, 0, 'g' },
191 { "gdbport", 1, 0, 'p' },
192 { "trace", 1, 0, 't' },
193 { "listtrace", 1, 0, 'l' },
194 { "version", 0, 0, 'V' },
195 { "cpufrequency", 1, 0, 'F' },
196 { "verbose", 0, 0, 'v' },
197 { "help", 0, 0, 'h' },
198 { 0, 0, 0, 0 }
201 int c;
202 while ( (c = getopt_long (argc, argv, "vd:F:f:xba:s:gp:t:l:c:Vh",
203 long_options, 0)) != -1) {
205 switch (c ) {
206 case 'v':
207 info.increaseVerbosity();
208 break;
210 case 'd':
211 devicename = optarg;
212 info(INFO) << "Device to simulate "
213 << devicename << std::endl;
214 break;
216 case 'F':
217 fcpu = strtoll(optarg, NULL, 10);
218 info(INFO) << "Running with CPU frequency: "<< fcpu
219 << std::endl;
220 break;
222 case 'f':
223 filename = optarg;
224 info(INFO) << "File to load "<< filename << std::endl;
225 break;
227 case 'x':
228 if( programType != PROG_NONE ) {
229 std::cerr << "Multiple file types specified!" << std::endl;
230 exit(1);
233 programType = PROG_HEX;
234 info(INFO) << "Program file type is hex" << std::endl;
235 break;
237 #ifdef HAVE_LIBBFD
238 case 'b':
239 if( programType != PROG_NONE ) {
240 std::cerr << "Multiple file types specified!" << std::endl;
241 exit(1);
244 programType = PROG_BFD;
245 info(INFO) << "Program file type is bfd" << std::endl;
246 break;
247 #endif
249 case 'a':
250 analyzers.push_back( optarg );
251 info(INFO) << "Adding analyzer "<< optarg << std::endl;
252 break;
254 case 's':
255 scriptconfig = optarg;
256 info(INFO) << "Using configfile "<< scriptconfig << std::endl;
257 break;
259 case 'g':
260 gdbserver = true;
261 info(INFO) << "Running as gdb-server"<< std::endl;
262 break;
264 case 'p':
265 gdbserver_port = atoi(optarg);
266 info(INFO) << "Running gdb-server on port: "
267 << gdbserver_port << std::endl;
268 break;
270 case 't':
271 tracefile = optarg;
272 info(INFO) << "Running in Trace Mode"<< std::endl;
273 break;
275 case 'l':
276 listtrace = optarg;
277 info(INFO) << "Listing Trace"<< std::endl;
278 break;
280 case 'c':
281 clockTicks = strtoll(optarg, NULL, 10);
282 info(INFO) << "Ending executing after "<< clockTicks
283 << " clock ticks" << std::endl;
284 break;
286 case 'V': {
287 std::cout << "Simulavr++ "<< AVR_SIM_VERSION << std::endl;
288 std::cout
289 << "See documentation for copyright and distribution terms"
290 << std::endl;
291 std::cout << std::endl;
292 exit(0);
294 break;
296 default:
297 print_usage();
301 #ifdef ENABLE_SCRIPTING
302 ScriptEngine *vm = 0;
303 if( HaveScripts(analyzers) /*|| scripted peripherals */ )
304 vm = new ScriptEngine();
305 #endif
307 if( programType == PROG_NONE )
308 programType = defaultProgramType;
310 Program *program = 0;
311 if( programType == PROG_HEX )
312 program = new HexProgram();
313 #ifdef HAVE_LIBBFD
314 else if( programType == PROG_BFD )
315 program = new BfdProgram();
316 #endif
318 int ret = EXIT_SUCCESS;
319 try {
320 //SimulationClock simclock; this is global now for signal_handlers
321 Device dev( simclock, devicename );
323 #ifdef _POSIX_SOURCE
324 if( ! gdbserver )
325 enable_signal_handler(SIGINT);
326 #endif
328 #ifdef ENABLE_SCRIPTING
329 if( vm != 0 )
330 vm->setProgram( *program );
331 #endif
333 if( filename != 0 ) {
334 program->load( filename );
335 dev.load( *program );
338 if( tracefile != 0 )
339 dev.trace( tracefile );
341 if( clockTicks != 0 )
342 simclock.setMaxTicks( clockTicks );
344 if( fcpu != 0 )
345 dev.setClockFrequency( fcpu );
347 if( analyzers.size() != 0 )
348 addAnalyzers( dev, analyzers );
350 if( scriptconfig != 0 ) {
351 #ifdef ENABLE_SCRIPTING
352 if( vm != 0 ) {
353 vm->loadConfig( scriptconfig );
354 } else
355 std::cerr << "Warning: scriptconfig specified but no VM" << std::endl;
356 #else
357 std::cerr << "Warning: scriptconfig specified but scripting disabled" << std::endl;
358 #endif
362 if( listtrace != 0 ) {
363 Trace tracer;
364 tracer.list( listtrace, std::cout, dev);
365 } else if( gdbserver ) {
366 GdbServer gdb( simclock, gdbserver_port );
367 gdb.add( &dev );
368 gdb.exec();
369 } else {
370 simclock.exec();
373 } catch( util::Exception & ex ) {
374 std::cerr << ex.message() << std::endl;
375 ex.printStackTrace( std::cerr );
376 ret = EXIT_FAILURE;
377 } catch( std::exception & ex ) {
378 std::cerr << ex.what() << std::endl;
379 ret = EXIT_FAILURE;
380 } catch( ... ) {
381 std::cerr << "Caught unknown exception" << std::endl;
382 ret = EXIT_FAILURE;
385 if( program != 0 )
386 delete program;
388 #ifdef ENABLE_SCRIPTING
389 if( vm != 0 )
390 delete vm;
391 #endif
393 info(INFO) << "Simulation ran for " << simclock.ticks()
394 << " clock ticks" << std::endl;
396 return ret;