Main Page

main.c
1 /*
2 * $Id: main.c,v 1.40 2004/04/17 00:03:51 troth Exp $
3 *
4 ****************************************************************************
5 *
6 * simulavr - A simulator for the Atmel AVR family of microcontrollers.
7 * Copyright (C) 2001, 2002, 2003, 2004 Theodore A. Roth
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 ****************************************************************************
24 */
25
26 #include <config.h>
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <errno.h>
32
33 #include "avrerror.h"
34 #include "avrmalloc.h"
35 #include "avrclass.h"
36 #include "utils.h"
37 #include "callback.h"
38 #include "op_names.h"
39
40 #include "storage.h"
41 #include "flash.h"
42
43 #include "vdevs.h"
44 #include "memory.h"
45 #include "stack.h"
46 #include "register.h"
47 #include "sram.h"
48 #include "eeprom.h"
49 #include "timers.h"
50 #include "ports.h"
51
52 #include "avrcore.h"
53
54 #include "devsupp.h"
55 #include "display.h"
56
57 #include "gdb.h"
58 #include "gnu_getopt.h"
59
60 /****************************************************************************\
61 *
62 * global variables (keep them to a minimum)
63 *
64 \****************************************************************************/
65
66 static char *global_device_type = NULL;
67
68 static int global_eeprom_image_type = FFMT_BIN;
69 static char *global_eeprom_image_file = NULL;
70
71 static int global_flash_image_type = FFMT_BIN;
72 static char *global_flash_image_file = NULL;
73
74 static int global_gdbserver_mode = 0;
75 static int global_gdbserver_port = 1212; /* default port number */
76 static int global_gdb_debug = 0;
77
78 static char *global_disp_prog = NULL;
79 static int global_disp_without_xterm = 0;
80
81 static int global_dump_core = 0;
82
83 static int global_clock_freq = 8000000; /* Default is 8 MHz. */
84
85 /* If the user needs more than LEN_BREAK_LIST on the command line, they've got
86 bigger problems. */
87
88 #define LEN_BREAK_LIST 50
89 static int global_break_count = 0;
90 static int global_break_list[LEN_BREAK_LIST];
91
92 static AvrCore *global_core = NULL;
93
94 /* *INDENT-OFF* */
95 static GdbComm_T global_gdb_comm[1] = {{
96 .user_data = NULL, /* user_data: will be global_core later */
97
98 .read_reg = (CommFuncReadReg) avr_core_gpwr_get,
99 .write_reg = (CommFuncWriteReg) avr_core_gpwr_set,
100
101 .read_sreg = (CommFuncReadSREG) avr_core_sreg_get,
102 .write_sreg = (CommFuncWriteSREG) avr_core_sreg_set,
103
104 .read_pc = (CommFuncReadPC) avr_core_PC_get,
105 .write_pc = (CommFuncWritePC) avr_core_PC_set,
106 .max_pc = (CommFuncMaxPC) avr_core_PC_max,
107
108 .read_sram = (CommFuncReadSRAM) avr_core_mem_read,
109 .write_sram = (CommFuncWriteSRAM) avr_core_mem_write,
110
111 .read_flash = (CommFuncReadFlash) avr_core_flash_read,
112 .write_flash = (CommFuncWriteFlash) avr_core_flash_write,
113 .write_flash_lo8 = (CommFuncWriteFlashLo8) avr_core_flash_write_lo8,
114 .write_flash_hi8 = (CommFuncWriteFlashHi8) avr_core_flash_write_hi8,
115
116 .insert_break = (CommFuncInsertBreak) avr_core_insert_breakpoint,
117 .remove_break = (CommFuncRemoveBreak) avr_core_remove_breakpoint,
118 .enable_breakpts = (CommFuncEnableBrkpts) avr_core_enable_breakpoints,
119 .disable_breakpts = (CommFuncDisableBrkpts) avr_core_disable_breakpoints,
120
121 .step = (CommFuncStep) avr_core_step,
122 .reset = (CommFuncReset) avr_core_reset,
123
124 .io_fetch = (CommFuncIORegFetch) avr_core_io_fetch,
125
126 .irq_raise = (CommFuncIrqRaise) avr_core_irq_raise,
127 }};
128
129 static char *usage_fmt_str =
130 "\nUsage: %s [OPTIONS]... [flash_image]\n" "\n"
131 "Simulate an avr device. The optional flash_image file is loaded\n"
132 "into the flash program memory space of the device.\n" "\n" "Options:\n"
133 " -h, --help : Show this message\n"
134 " -D, --debug : Debug instruction output\n"
135 " -v, --version : Print out the version number and exit\n"
136 " -g, --gdbserver : Run as a gdbserver process\n"
137 " -G, --gdb-debug : Print out debug messages for gdbserver\n"
138 " -p, --port <port> : Listen for gdb connection on TCP port\n"
139 " -d, --device <dev> : Specify device type\n"
140 " -e, --eeprom-image <img> : Specify an eeprom image file\n"
141 " -E, --eeprom-type <type> : Specify the type of the eeprom image file\n"
142 " -F, --flash-type <type> : Specify the type of the flash image file\n"
143 " -L, --list-devices : Print supported devices to stdout and exit\n"
144 " -P, --disp-prog <prog> : Display register and memory info with prog\n"
145 " -X, --without-xterm : Don't start disp prog in an xterm\n"
146 " -C, --core-dump : Dump a core memory image to file on exit\n"
147 " -c, --clock-freq <freq> : Set the simulated mcu clock freqency (in Hz)\n"
148 " -B, --breakpoint <addr> : Set a breakpoint (address is a byte address)\n"
149 "\n" "If the image file types for eeprom or flash images are not given,\n"
150 "the default file type is binary.\n" "\n"
151 "If you wish to run the simulator in gdbserver mode, you do not\n"
152 "have to specify a flash-image file since the program can be loaded\n"
153 "from gdb via the `load` command.\n" "\n"
154 "If '--port' option is given, and '--gdbserver' is not, port is ignored\n"
155 "\n" "If running in gdbserver mode and port is not specified, a default\n"
156 "port of 1212 is used.\n" "\n"
157 "If using the '--breakpoint' option, note the simulator will terminate when\n"
158 "the address is hit if you are not running in gdbserver mode. This feature\n"
159 "not intended for use in gdbserver mode. It is really intended for testing\n"
160 "the simulator itself, but may be useful for testing avr programs too.\n"
161 "\n" "Currently available device types:\n";
162
163 /* *INDENT-ON* */
164
165 /*
166 * Print usage message.
167 */
168 static void
169 usage (char *prog)
170 {
171 fprintf (stdout, usage_fmt_str, prog);
172 dev_supp_list_devices (stdout);
173 fprintf (stdout, "\n");
174
175 exit (1);
176 }
177
178 /* *INDENT-OFF* */
179 static struct option long_opts[] = {
180 /* name, has_arg, flag, val */
181 { "help", 0, 0, 'h' },
182 { "debug", 0, 0, 'D' },
183 { "version", 0, 0, 'v' },
184 { "gdbserver", 0, 0, 'g' },
185 { "gdb-debug", 0, 0, 'G' },
186 { "port", 1, 0, 'p' },
187 { "device", 1, 0, 'd' },
188 { "eeprom-type", 1, 0, 'E' },
189 { "eeprom-image", 1, 0, 'e' },
190 { "flash-type", 1, 0, 'F' },
191 { "list-devices", 0, 0, 'L' },
192 { "disp-prog", 1, 0, 'P' },
193 { "without-xterm", 1, 0, 'X' },
194 { "core-dump", 0, 0, 'C' },
195 { "clock-freq", 1, 0, 'c' },
196 { "breakpoint", 1, 0, 'B' },
197 { NULL, 0, 0, 0 }
198 };
199 /* *INDENT-ON* */
200
201 /*
202 * Parse the command line arguments.
203 */
204 static void
205 parse_cmd_line (int argc, char **argv)
206 {
207 int c;
208 char *prog = argv[0];
209 char *basename;
210 int option_index;
211 char dummy_char;
212 int break_addr;
213
214 opterr = 0; /* disable default error message */
215
216 while (1)
217 {
218 c = getopt_long (argc, argv, "hgGvDLd:e:E:F:p:P:XCc:B:", long_opts,
219 &option_index);
220 if (c == -1)
221 break; /* no more options */
222
223 switch (c)
224 {
225 case 'h':
226 case '?':
227 usage (prog);
228 case 'g':
229 global_gdbserver_mode = 1;
230 break;
231 case 'G':
232 global_gdb_debug = 1;
233 break;
234 case 'p':
235 global_gdbserver_port = atoi (optarg);
236 break;
237 case 'v':
238 printf ("\n%s version %s\n", PACKAGE, VERSION);
239 printf ("Copyright 2001, 2002, 2003, 2004"
240 " Theodore A. Roth.\n");
241 printf ("\n%s is free software, covered by the GNU General "
242 "Public License,\n", PACKAGE);
243 printf ("and you are welcome to change it and/or distribute "
244 "copies of it under\n");
245 printf ("the conditions of the GNU General Public License."
246 "\n\n");
247 exit (0);
248 case 'D':
249 global_debug_inst_output = 1;
250 break;
251 case 'd':
252 global_device_type = optarg;
253 break;
254 case 'e':
255 global_eeprom_image_file = avr_strdup (optarg);
256 break;
257 case 'E':
258 break;
259 global_eeprom_image_type = str2ffmt (optarg);
260 case 'F':
261 global_flash_image_type = str2ffmt (optarg);
262 break;
263 case 'L':
264 dev_supp_list_devices (stdout);
265 exit (0);
266 case 'P':
267 global_disp_prog = avr_strdup (optarg);
268 break;
269 case 'X':
270 global_disp_without_xterm = 1;
271 break;
272 case 'C':
273 global_dump_core = 1;
274 break;
275 case 'c':
276 if (sscanf (optarg, "%d%c", &global_clock_freq, &dummy_char)
277 != 1)
278 {
279 avr_error ("Invalid clock value: %s", optarg);
280 }
281 avr_warning ("Clock frequency option is not yet "
282 "implemented.\n");
283 break;
284 case 'B':
285 if (sscanf (optarg, "%i%c", &break_addr, &dummy_char) != 1)
286 {
287 avr_error ("Ignoring invalid break addres: %s", optarg);
288 }
289
290 if (global_break_count < LEN_BREAK_LIST)
291 {
292 global_break_list[global_break_count] = break_addr;
293 global_break_count++;
294 }
295 else
296 {
297 avr_warning ("Too many break points: igoring %s\n",
298 optarg);
299 }
300
301 break;
302 default:
303 avr_error ("getop() did something screwey");
304 }
305 }
306
307 if ((optind + 1) == argc)
308 global_flash_image_file = argv[optind];
309 else if (optind != argc)
310 usage (prog);
311
312 /* FIXME: Issue a warning and bail out if user selects a file format type
313 we haven't implemented yet. */
314
315 if ((global_eeprom_image_type != FFMT_BIN)
316 || (global_flash_image_type != FFMT_BIN))
317 {
318 fprintf (stderr,
319 "Only the bin file format is currently "
320 "implemented. Sorry.\n");
321 exit (1);
322 }
323
324 /* If user didn't specify a device type, see if it can be gleaned from the
325 name of the program. */
326
327 if (global_device_type == NULL)
328 {
329 /* find the last '/' in dev_name */
330 basename = strrchr (prog, '/');
331 if (basename == NULL)
332 /* no slash in dev_name */
333 global_device_type = prog;
334 else
335 global_device_type = ++basename;
336 }
337 }
338
339 uint8_t
340 ext_port_rd (int addr)
341 {
342 int data;
343 char line[80];
344
345 while (1)
346 {
347 fprintf (stderr, "\nEnter a byte of data to read into 0x%04x: ",
348 addr);
349
350 /* try to read in a line of input */
351 if (fgets (line, sizeof (line), stdin) == NULL)
352 continue;
353
354 /* try to parse the line for a byte of data */
355 if (sscanf (line, "%i\n", &data) != 1)
356 continue;
357
358 break;
359 }
360 return (uint8_t) (data & 0xff);
361 }
362
363 void
364 ext_port_wr (int addr, uint8_t val)
365 {
366 fprintf (stderr, "writing 0x%02x to 0x%04x\n", val, addr);
367 fflush (stderr);
368 }
369
370 /* This is called whenever the program terminates via a call to exit(). */
371
372 void
373 atexit_cleanup (void)
374 {
375 FILE *dump;
376
377 if (global_dump_core)
378 {
379 if ((dump = fopen ("core_avr_dump.core", "w")) == NULL)
380 {
381 /* can't call avr_error here since it could have called us */
382 fprintf (stderr, "fopen failed: core_avr_dump.core: %s\n",
383 strerror (errno));
384 }
385 else
386 {
387 avr_core_dump_core (global_core, dump);
388 fclose (dump);
389 }
390 }
391
392 class_unref ((AvrClass *)global_core);
393 }
394
395 /*
396 * Symlinks should be created for each supported device to the
397 * simulavr program.
398 */
399 int
400 main (int argc, char **argv)
401 {
402 int i;
403 int flash_sz = 0, sram_sz = 0, eeprom_sz = 0;
404 int sram_start = 0;
405
406 parse_cmd_line (argc, argv);
407
408 global_core = avr_core_new (global_device_type);
409 if (global_core == NULL)
410 {
411 avr_warning ("Device not supported: %s\n", global_device_type);
412 exit (1);
413 }
414
415 avr_message ("Simulating clock frequency of %d Hz\n", global_clock_freq);
416
417 avr_core_get_sizes (global_core, &flash_sz, &sram_sz, &sram_start,
418 &eeprom_sz);
419 display_open (global_disp_prog, global_disp_without_xterm, flash_sz,
420 sram_sz, sram_start, eeprom_sz);
421 avr_core_io_display_names (global_core);
422
423 /* Send initial clock cycles to display */
424 display_clock (0);
425
426 /* install my_atexit to be called when exit() is called */
427 if (atexit (atexit_cleanup))
428 avr_error ("Failed to install exit handler");
429
430 #if 0
431 /* Add external device hooks to ports */
432 avr_core_add_ext_rd_wr (global_core, PORT_B_BASE, ext_port_rd,
433 ext_port_wr);
434 avr_core_add_ext_rd_wr (global_core, PORT_C_BASE, ext_port_rd,
435 ext_port_wr);
436 avr_core_add_ext_rd_wr (global_core, PORT_D_BASE, ext_port_rd,
437 ext_port_wr);
438 #endif
439
440 /* Load program into flash */
441 if (global_flash_image_file)
442 avr_core_load_program (global_core, global_flash_image_file,
443 global_flash_image_type);
444
445 /* Load eeprom data image into eeprom */
446 if (global_eeprom_image_file)
447 avr_core_load_eeprom (global_core, global_eeprom_image_file,
448 global_eeprom_image_type);
449
450 for (i = 0; i < global_break_count; i++)
451 {
452 /* Note that we interpret the break address from the user as a byte
453 address instead of a word address. This makes it easier on the user
454 since binutils, gcc and gdb all work in terms of byte addresses. */
455
456 avr_message ("Setting breakpoint at 0x%x.\n", global_break_list[i]);
457 avr_core_insert_breakpoint (global_core, global_break_list[i] / 2);
458 }
459
460 if (global_gdbserver_mode == 1)
461 {
462 global_gdb_comm->user_data = global_core;
463 gdb_interact (global_gdb_comm, global_gdbserver_port,
464 global_gdb_debug);
465 }
466 else
467 {
468 if (global_flash_image_file)
469 /* Run the program */
470 avr_core_run (global_core);
471 else
472 fprintf (stderr, "No program was specified to be run.\n");
473 }
474
475 display_close (); /* close down the display coprocess */
476
477 exit (0);
478 return 0;
479 }
avr_core_dump_core
void avr_core_dump_core(AvrCore *core, FILE *f_core)
Dump the contents of the entire CPU core.
Definition: avrcore.c:1294
avr_core_step
int avr_core_step(AvrCore *core)
Process a single program instruction, all side effects and peripheral stimulii.
Definition: avrcore.c:1093
display_open
int display_open(char *prog, int no_xterm, int flash_sz, int sram_sz, int sram_start, int eeprom_sz)
Open a display as a coprocess.
Definition: display.c:85
avr_core_run
void avr_core_run(AvrCore *core)
Start the processing of instructions by the simulator.
Definition: avrcore.c:1150
avr_core_reset
void avr_core_reset(AvrCore *core)
Sets the simulated CPU back to its initial state.
Definition: avrcore.c:1204
display_close
void display_close(void)
Close a display and send coprocess a quit message.
Definition: display.c:181
gdb_interact
void gdb_interact(GdbComm_T *comm, int port, int debug_on)
Start interacting with gdb.
Definition: gdbserver.c:1320
avr_core_get_sizes
void avr_core_get_sizes(AvrCore *core, int *flash, int *sram, int *sram_start, int *eeprom)
Query the sizes of the 3 memory spaces: flash, sram, and eeprom.
Definition: avrcore.c:572
avr_core_load_eeprom
int avr_core_load_eeprom(AvrCore *core, char *file, int format)
Load a program from an input file.
Definition: avrcore.c:1314
avr_core_enable_breakpoints
void avr_core_enable_breakpoints(AvrCore *core)
Enable breakpoints.
Definition: avrcore.c:968
dev_supp_list_devices
void dev_supp_list_devices(FILE *fp)
Print a list of supported devices to a file pointer.
Definition: devsupp.c:292
avr_core_remove_breakpoint
void avr_core_remove_breakpoint(AvrCore *core, int pc)
Removes a break point.
Definition: avrcore.c:898
avr_core_disable_breakpoints
void avr_core_disable_breakpoints(AvrCore *core)
Disable breakpoints.
Definition: avrcore.c:955
avr_core_irq_raise
void avr_core_irq_raise(AvrCore *core, unsigned int irq)
Raises an irq by adding it&#39;s data to the irq_pending list.
Definition: avrcore.c:854
avr_strdup
char * avr_strdup(const char *s)
Wrapper for strdup().
Definition: avrmalloc.c:168
avr_warning
#define avr_warning(fmt, args...)
Print a warning message to stderr.
Definition: avrerror.c:46
avr_core_new
AvrCore * avr_core_new(char *dev_name)
Allocate a new AvrCore object.
Definition: avrcore.c:355
str2ffmt
int str2ffmt(char *str)
Utility function to convert a string to a FileFormatType code.
Definition: utils.c:50
class_unref
void class_unref(AvrClass *klass)
Decrements the reference count for the klass object.
Definition: avrclass.c:120
avr_error
#define avr_error(fmt, args...)
Print an error message to stderr and terminate program.
Definition: avrerror.c:50
global_debug_inst_output
int global_debug_inst_output
Flag for enabling output of instruction debug messages.
Definition: avrcore.c:64
avr_core_add_ext_rd_wr
void avr_core_add_ext_rd_wr(AvrCore *core, int addr, PortFP_ExtRd ext_rd, PortFP_ExtWr ext_wr)
For adding external read and write callback functions.
Definition: avrcore.c:1244
avr_core_io_display_names
void avr_core_io_display_names(AvrCore *core)
Displays all registers.
Definition: avrcore.c:733
avr_core_load_program
int avr_core_load_program(AvrCore *core, char *file, int format)
Load a program from an input file.
Definition: avrcore.c:1307
display_clock
void display_clock(int clock)
Update the time in the display.
Definition: display.c:255
avr_core_insert_breakpoint
void avr_core_insert_breakpoint(AvrCore *core, int pc)
Inserts a break point.
Definition: avrcore.c:884
avr_message
#define avr_message(fmt, args...)
Print an ordinary message to stdout.
Definition: avrerror.c:42

Automatically generated by Doxygen 1.8.12 on Sun Apr 2 2017.