Main Page | File List | Globals | Related Pages

main.c

00001 /* 00002 * $Id: main.c,v 1.38 2003/12/02 03:56:46 troth Exp $ 00003 * 00004 **************************************************************************** 00005 * 00006 * simulavr - A simulator for the Atmel AVR family of microcontrollers. 00007 * Copyright (C) 2001, 2002, 2003 Theodore A. Roth 00008 * 00009 * This program is free software; you can redistribute it and/or modify 00010 * it under the terms of the GNU General Public License as published by 00011 * the Free Software Foundation; either version 2 of the License, or 00012 * (at your option) any later version. 00013 * 00014 * This program is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 * GNU General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU General Public License 00020 * along with this program; if not, write to the Free Software 00021 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00022 * 00023 **************************************************************************** 00024 */ 00025 00026 #include <config.h> 00027 00028 #include <stdio.h> 00029 #include <stdlib.h> 00030 #include <string.h> 00031 #include <errno.h> 00032 00033 #include "avrerror.h" 00034 #include "avrmalloc.h" 00035 #include "avrclass.h" 00036 #include "utils.h" 00037 #include "callback.h" 00038 #include "op_names.h" 00039 00040 #include "storage.h" 00041 #include "flash.h" 00042 00043 #include "vdevs.h" 00044 #include "memory.h" 00045 #include "stack.h" 00046 #include "register.h" 00047 #include "sram.h" 00048 #include "eeprom.h" 00049 #include "timers.h" 00050 #include "ports.h" 00051 00052 #include "avrcore.h" 00053 00054 #include "devsupp.h" 00055 #include "display.h" 00056 00057 #include "gdb.h" 00058 #include "gnu_getopt.h" 00059 00060 /****************************************************************************\ 00061 * 00062 * global variables (keep them to a minimum) 00063 * 00064 \****************************************************************************/ 00065 00066 static char *global_device_type = NULL; 00067 00068 static int global_eeprom_image_type = FFMT_BIN; 00069 static char *global_eeprom_image_file = NULL; 00070 00071 static int global_flash_image_type = FFMT_BIN; 00072 static char *global_flash_image_file = NULL; 00073 00074 static int global_gdbserver_mode = 0; 00075 static int global_gdbserver_port = 1212; /* default port number */ 00076 static int global_gdb_debug = 0; 00077 00078 static char *global_disp_prog = NULL; 00079 static int global_disp_without_xterm = 0; 00080 00081 static int global_dump_core = 0; 00082 00083 static int global_clock_freq = 8000000; /* Default is 8 MHz. */ 00084 00085 /* If the user needs more than LEN_BREAK_LIST on the command line, they've got 00086 bigger problems. */ 00087 00088 #define LEN_BREAK_LIST 50 00089 static int global_break_count = 0; 00090 static int global_break_list[LEN_BREAK_LIST]; 00091 00092 static AvrCore *global_core = NULL; 00093 00094 /* *INDENT-OFF* */ 00095 static GdbComm_T global_gdb_comm[1] = {{ 00096 .user_data = NULL, /* user_data: will be global_core later */ 00097 00098 .read_reg = (CommFuncReadReg) avr_core_gpwr_get, 00099 .write_reg = (CommFuncWriteReg) avr_core_gpwr_set, 00100 00101 .read_sreg = (CommFuncReadSREG) avr_core_sreg_get, 00102 .write_sreg = (CommFuncWriteSREG) avr_core_sreg_set, 00103 00104 .read_pc = (CommFuncReadPC) avr_core_PC_get, 00105 .write_pc = (CommFuncWritePC) avr_core_PC_set, 00106 .max_pc = (CommFuncMaxPC) avr_core_PC_max, 00107 00108 .read_sram = (CommFuncReadSRAM) avr_core_mem_read, 00109 .write_sram = (CommFuncWriteSRAM) avr_core_mem_write, 00110 00111 .read_flash = (CommFuncReadFlash) avr_core_flash_read, 00112 .write_flash = (CommFuncWriteFlash) avr_core_flash_write, 00113 .write_flash_lo8 = (CommFuncWriteFlashLo8) avr_core_flash_write_lo8, 00114 .write_flash_hi8 = (CommFuncWriteFlashHi8) avr_core_flash_write_hi8, 00115 00116 .insert_break = (CommFuncInsertBreak) avr_core_insert_breakpoint, 00117 .remove_break = (CommFuncRemoveBreak) avr_core_remove_breakpoint, 00118 .enable_breakpts = (CommFuncEnableBrkpts) avr_core_enable_breakpoints, 00119 .disable_breakpts = (CommFuncDisableBrkpts) avr_core_disable_breakpoints, 00120 00121 .step = (CommFuncStep) avr_core_step, 00122 .reset = (CommFuncReset) avr_core_reset, 00123 00124 .io_fetch = (CommFuncIORegFetch) avr_core_io_fetch, 00125 00126 .irq_raise = (CommFuncIrqRaise) avr_core_irq_raise, 00127 }}; 00128 00129 static char *usage_fmt_str = 00130 "\nUsage: %s [OPTIONS]... [flash_image]\n" "\n" 00131 "Simulate an avr device. The optional flash_image file is loaded\n" 00132 "into the flash program memory space of the device.\n" "\n" "Options:\n" 00133 " -h, --help : Show this message\n" 00134 " -D, --debug : Debug instruction output\n" 00135 " -v, --version : Print out the version number and exit\n" 00136 " -g, --gdbserver : Run as a gdbserver process\n" 00137 " -G, --gdb-debug : Print out debug messages for gdbserver\n" 00138 " -p, --port <port> : Listen for gdb connection on TCP port\n" 00139 " -d, --device <dev> : Specify device type\n" 00140 " -e, --eeprom-image <img> : Specify an eeprom image file\n" 00141 " -E, --eeprom-type <type> : Specify the type of the eeprom image file\n" 00142 " -F, --flash-type <type> : Specify the type of the flash image file\n" 00143 " -L, --list-devices : Print supported devices to stdout and exit\n" 00144 " -P, --disp-prog <prog> : Display register and memory info with prog\n" 00145 " -X, --without-xterm : Don't start disp prog in an xterm\n" 00146 " -C, --core-dump : Dump a core memory image to file on exit\n" 00147 " -c, --clock-freq <freq> : Set the simulated mcu clock freqency (in Hz)\n" 00148 " -B, --breakpoint <addr> : Set a breakpoint (address is a byte address)\n" 00149 "\n" "If the image file types for eeprom or flash images are not given,\n" 00150 "the default file type is binary.\n" "\n" 00151 "If you wish to run the simulator in gdbserver mode, you do not\n" 00152 "have to specify a flash-image file since the program can be loaded\n" 00153 "from gdb via the `load` command.\n" "\n" 00154 "If '--port' option is given, and '--gdbserver' is not, port is ignored\n" 00155 "\n" "If running in gdbserver mode and port is not specified, a default\n" 00156 "port of 1212 is used.\n" "\n" 00157 "If using the '--breakpoint' option, note the simulator will terminate when\n" 00158 "the address is hit if you are not running in gdbserver mode. This feature\n" 00159 "not intended for use in gdbserver mode. It is really intended for testing\n" 00160 "the simulator itself, but may be useful for testing avr programs too.\n" 00161 "\n" "Currently available device types:\n"; 00162 00163 /* *INDENT-ON* */ 00164 00165 /* 00166 * Print usage message. 00167 */ 00168 static void 00169 usage (char *prog) 00170 { 00171 fprintf (stdout, usage_fmt_str, prog); 00172 dev_supp_list_devices (stdout); 00173 fprintf (stdout, "\n"); 00174 00175 exit (1); 00176 } 00177 00178 /* *INDENT-OFF* */ 00179 static struct option long_opts[] = { 00180 /* name, has_arg, flag, val */ 00181 { "help", 0, 0, 'h' }, 00182 { "debug", 0, 0, 'D' }, 00183 { "version", 0, 0, 'v' }, 00184 { "gdbserver", 0, 0, 'g' }, 00185 { "gdb-debug", 0, 0, 'G' }, 00186 { "port", 1, 0, 'p' }, 00187 { "device", 1, 0, 'd' }, 00188 { "eeprom-type", 1, 0, 'E' }, 00189 { "eeprom-image", 1, 0, 'e' }, 00190 { "flash-type", 1, 0, 'F' }, 00191 { "list-devices", 0, 0, 'L' }, 00192 { "disp-prog", 1, 0, 'P' }, 00193 { "without-xterm", 1, 0, 'X' }, 00194 { "core-dump", 0, 0, 'C' }, 00195 { "clock-freq", 1, 0, 'c' }, 00196 { "breakpoint", 1, 0, 'B' }, 00197 { NULL, 0, 0, 0 } 00198 }; 00199 /* *INDENT-ON* */ 00200 00201 /* 00202 * Parse the command line arguments. 00203 */ 00204 static void 00205 parse_cmd_line (int argc, char **argv) 00206 { 00207 int c; 00208 char *prog = argv[0]; 00209 char *basename; 00210 int option_index; 00211 char dummy_char; 00212 int break_addr; 00213 00214 opterr = 0; /* disable default error message */ 00215 00216 while (1) 00217 { 00218 c = getopt_long (argc, argv, "hgGvDLd:e:E:F:p:P:XCc:B:", long_opts, 00219 &option_index); 00220 if (c == -1) 00221 break; /* no more options */ 00222 00223 switch (c) 00224 { 00225 case 'h': 00226 case '?': 00227 usage (prog); 00228 case 'g': 00229 global_gdbserver_mode = 1; 00230 break; 00231 case 'G': 00232 global_gdb_debug = 1; 00233 break; 00234 case 'p': 00235 global_gdbserver_port = atoi (optarg); 00236 break; 00237 case 'v': 00238 printf ("\n%s version %s\n", PACKAGE, VERSION); 00239 printf ("Copyright 2001, 2002, 2003 Theodore A. Roth.\n"); 00240 printf ("\n%s is free software, covered by the GNU General " 00241 "Public License,\n", PACKAGE); 00242 printf ("and you are welcome to change it and/or distribute " 00243 "copies of it under\n"); 00244 printf ("the conditions of the GNU General Public License." 00245 "\n\n"); 00246 exit (0); 00247 case 'D': 00248 global_debug_inst_output = 1; 00249 break; 00250 case 'd': 00251 global_device_type = optarg; 00252 break; 00253 case 'e': 00254 global_eeprom_image_file = avr_strdup (optarg); 00255 break; 00256 case 'E': 00257 break; 00258 global_eeprom_image_type = str2ffmt (optarg); 00259 case 'F': 00260 global_flash_image_type = str2ffmt (optarg); 00261 break; 00262 case 'L': 00263 dev_supp_list_devices (stdout); 00264 exit (0); 00265 case 'P': 00266 global_disp_prog = avr_strdup (optarg); 00267 break; 00268 case 'X': 00269 global_disp_without_xterm = 1; 00270 break; 00271 case 'C': 00272 global_dump_core = 1; 00273 break; 00274 case 'c': 00275 if (sscanf (optarg, "%d%c", &global_clock_freq, &dummy_char) 00276 != 1) 00277 { 00278 avr_error ("Invalid clock value: %s", optarg); 00279 } 00280 avr_warning ("Clock frequency option is not yet " 00281 "implemented.\n"); 00282 break; 00283 case 'B': 00284 if (sscanf (optarg, "%i%c", &break_addr, &dummy_char) != 1) 00285 { 00286 avr_error ("Ignoring invalid break addres: %s", optarg); 00287 } 00288 00289 if (global_break_count < LEN_BREAK_LIST) 00290 { 00291 global_break_list[global_break_count] = break_addr; 00292 global_break_count++; 00293 } 00294 else 00295 { 00296 avr_warning ("Too many break points: igoring %s\n", 00297 optarg); 00298 } 00299 00300 break; 00301 default: 00302 avr_error ("getop() did something screwey"); 00303 } 00304 } 00305 00306 if ((optind + 1) == argc) 00307 global_flash_image_file = argv[optind]; 00308 else if (optind != argc) 00309 usage (prog); 00310 00311 /* FIXME: Issue a warning and bail out if user selects a file format type 00312 we haven't implemented yet. */ 00313 00314 if ((global_eeprom_image_type != FFMT_BIN) 00315 || (global_flash_image_type != FFMT_BIN)) 00316 { 00317 fprintf (stderr, 00318 "Only the bin file format is currently " 00319 "implemented. Sorry.\n"); 00320 exit (1); 00321 } 00322 00323 /* If user didn't specify a device type, see if it can be gleaned from the 00324 name of the program. */ 00325 00326 if (global_device_type == NULL) 00327 { 00328 /* find the last '/' in dev_name */ 00329 basename = strrchr (prog, '/'); 00330 if (basename == NULL) 00331 /* no slash in dev_name */ 00332 global_device_type = prog; 00333 else 00334 global_device_type = ++basename; 00335 } 00336 } 00337 00338 uint8_t 00339 ext_port_rd (int addr) 00340 { 00341 int data; 00342 char line[80]; 00343 00344 while (1) 00345 { 00346 fprintf (stderr, "\nEnter a byte of data to read into 0x%04x: ", 00347 addr); 00348 00349 /* try to read in a line of input */ 00350 if (fgets (line, sizeof (line), stdin) == NULL) 00351 continue; 00352 00353 /* try to parse the line for a byte of data */ 00354 if (sscanf (line, "%i\n", &data) != 1) 00355 continue; 00356 00357 break; 00358 } 00359 return (uint8_t) (data & 0xff); 00360 } 00361 00362 void 00363 ext_port_wr (int addr, uint8_t val) 00364 { 00365 fprintf (stderr, "writing 0x%02x to 0x%04x\n", val, addr); 00366 } 00367 00368 /* This is called whenever the program terminates via a call to exit(). */ 00369 00370 void 00371 atexit_cleanup (void) 00372 { 00373 FILE *dump; 00374 00375 if (global_dump_core) 00376 { 00377 if ((dump = fopen ("core_avr_dump.core", "w")) == NULL) 00378 { 00379 /* can't call avr_error here since it could have called us */ 00380 fprintf (stderr, "fopen failed: core_avr_dump.core: %s\n", 00381 strerror (errno)); 00382 } 00383 else 00384 { 00385 avr_core_dump_core (global_core, dump); 00386 fclose (dump); 00387 } 00388 } 00389 00390 class_unref ((AvrClass *)global_core); 00391 } 00392 00393 /* 00394 * Symlinks should be created for each supported device to the 00395 * simulavr program. 00396 */ 00397 int 00398 main (int argc, char **argv) 00399 { 00400 int i; 00401 int flash_sz = 0, sram_sz = 0, eeprom_sz = 0; 00402 int sram_start = 0; 00403 00404 parse_cmd_line (argc, argv); 00405 00406 global_core = dev_supp_create_core (global_device_type); 00407 if (global_core == NULL) 00408 { 00409 avr_warning ("Device not supported: %s\n", global_device_type); 00410 exit (1); 00411 } 00412 00413 avr_message ("Simulating clock frequency of %d Hz\n", global_clock_freq); 00414 00415 avr_core_get_sizes (global_core, &flash_sz, &sram_sz, &sram_start, 00416 &eeprom_sz); 00417 display_open (global_disp_prog, global_disp_without_xterm, flash_sz, 00418 sram_sz, sram_start, eeprom_sz); 00419 avr_core_io_display_names (global_core); 00420 00421 /* install my_atexit to be called when exit() is called */ 00422 if (atexit (atexit_cleanup)) 00423 avr_error ("Failed to install exit handler"); 00424 00425 /* Add external device hooks to ports */ 00426 avr_core_add_ext_rd_wr (global_core, PORT_B, ext_port_rd, ext_port_wr); 00427 avr_core_add_ext_rd_wr (global_core, PORT_C, ext_port_rd, ext_port_wr); 00428 avr_core_add_ext_rd_wr (global_core, PORT_D, ext_port_rd, ext_port_wr); 00429 00430 /* Load program into flash */ 00431 if (global_flash_image_file) 00432 avr_core_load_program (global_core, global_flash_image_file, 00433 global_flash_image_type); 00434 00435 /* Load eeprom data image into eeprom */ 00436 if (global_eeprom_image_file) 00437 avr_core_load_eeprom (global_core, global_eeprom_image_file, 00438 global_eeprom_image_type); 00439 00440 for (i = 0; i < global_break_count; i++) 00441 { 00442 /* Note that we interpret the break address from the user as a byte 00443 address instead of a word address. This makes it easier on the user 00444 since binutils, gcc and gdb all work in terms of byte addresses. */ 00445 00446 avr_message ("Setting breakpoint at 0x%x.\n", global_break_list[i]); 00447 avr_core_insert_breakpoint (global_core, global_break_list[i] / 2); 00448 } 00449 00450 if (global_gdbserver_mode == 1) 00451 { 00452 global_gdb_comm->user_data = global_core; 00453 gdb_interact (global_gdb_comm, global_gdbserver_port, 00454 global_gdb_debug); 00455 } 00456 else 00457 { 00458 if (global_flash_image_file) 00459 /* Run the program */ 00460 avr_core_run (global_core); 00461 else 00462 fprintf (stderr, "No program was specified to be run.\n"); 00463 } 00464 00465 display_close (); /* close down the display coprocess */ 00466 00467 exit (0); 00468 return 0; 00469 }

Automatically generated by Doxygen 1.3.8 on 11 Aug 2004.