- Main Page
- Related Pages
- Files

# main.c

    00001 /*
    00002  * $Id: main.c,v 1.40 2004/04/17 00:03:51 troth Exp $
    00003  *
    00004  ****************************************************************************
    00005  *
    00006  * simulavr - A simulator for the Atmel AVR family of microcontrollers.
    00007  * Copyright (C) 2001, 2002, 2003, 2004  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, 2004"
    00240                         "  Theodore A. Roth.\n");
    00241                 printf ("\n%s is free software, covered by the GNU General "
    00242                         "Public License,\n", PACKAGE);
    00243                 printf ("and you are welcome to change it and/or distribute "
    00244                         "copies of it under\n");
    00245                 printf ("the conditions of the GNU General Public License."
    00246                         "\n\n");
    00247                 exit (0);
    00248             case 'D':
    00249                 global_debug_inst_output = 1;
    00250                 break;
    00251             case 'd':
    00252                 global_device_type = optarg;
    00253                 break;
    00254             case 'e':
    00255                 global_eeprom_image_file = avr_strdup (optarg);
    00256                 break;
    00257             case 'E':
    00258                 break;
    00259                 global_eeprom_image_type = str2ffmt (optarg);
    00260             case 'F':
    00261                 global_flash_image_type = str2ffmt (optarg);
    00262                 break;
    00263             case 'L':
    00264                 dev_supp_list_devices (stdout);
    00265                 exit (0);
    00266             case 'P':
    00267                 global_disp_prog = avr_strdup (optarg);
    00268                 break;
    00269             case 'X':
    00270                 global_disp_without_xterm = 1;
    00271                 break;
    00272             case 'C':
    00273                 global_dump_core = 1;
    00274                 break;
    00275             case 'c':
    00276                 if (sscanf (optarg, "%d%c", &global_clock_freq, &dummy_char)
    00277                     != 1)
    00278                 {
    00279                     avr_error ("Invalid clock value: %s", optarg);
    00280                 }
    00281                 avr_warning ("Clock frequency option is not yet "
    00282                              "implemented.\n");
    00283                 break;
    00284             case 'B':
    00285                 if (sscanf (optarg, "%i%c", &break_addr, &dummy_char) != 1)
    00286                 {
    00287                     avr_error ("Ignoring invalid break addres: %s", optarg);
    00288                 }
    00289
    00290                 if (global_break_count < LEN_BREAK_LIST)
    00291                 {
    00292                     global_break_list[global_break_count] = break_addr;
    00293                     global_break_count++;
    00294                 }
    00295                 else
    00296                 {
    00297                     avr_warning ("Too many break points: igoring %s\n",
    00298                                  optarg);
    00299                 }
    00300
    00301                 break;
    00302             default:
    00303                 avr_error ("getop() did something screwey");
    00304         }
    00305     }
    00306
    00307     if ((optind + 1) == argc)
    00308         global_flash_image_file = argv[optind];
    00309     else if (optind != argc)
    00310         usage (prog);
    00311
    00312     /* FIXME: Issue a warning and bail out if user selects a file format type
    00313        we haven't implemented yet. */
    00314
    00315     if ((global_eeprom_image_type != FFMT_BIN)
    00316         || (global_flash_image_type != FFMT_BIN))
    00317     {
    00318         fprintf (stderr,
    00319                  "Only the bin file format is currently "
    00320                  "implemented. Sorry.\n");
    00321         exit (1);
    00322     }
    00323
    00324     /* If user didn't specify a device type, see if it can be gleaned from the
    00325        name of the program. */
    00326
    00327     if (global_device_type == NULL)
    00328     {
    00329         /* find the last '/' in dev_name */
    00330         basename = strrchr (prog, '/');
    00331         if (basename == NULL)
    00332             /* no slash in dev_name */
    00333             global_device_type = prog;
    00334         else
    00335             global_device_type = ++basename;
    00336     }
    00337 }
    00338
    00339 uint8_t
    00340 ext_port_rd (int addr)
    00341 {
    00342     int data;
    00343     char line[80];
    00344
    00345     while (1)
    00346     {
    00347         fprintf (stderr, "\nEnter a byte of data to read into 0x%04x: ",
    00348                  addr);
    00349
    00350         /* try to read in a line of input */
    00351         if (fgets (line, sizeof (line), stdin) == NULL)
    00352             continue;
    00353
    00354         /* try to parse the line for a byte of data */
    00355         if (sscanf (line, "%i\n", &data) != 1)
    00356             continue;
    00357
    00358         break;
    00359     }
    00360     return (uint8_t) (data & 0xff);
    00361 }
    00362
    00363 void
    00364 ext_port_wr (int addr, uint8_t val)
    00365 {
    00366     fprintf (stderr, "writing 0x%02x to 0x%04x\n", val, addr);
    00367     fflush (stderr);
    00368 }
    00369
    00370 /* This is called whenever the program terminates via a call to exit(). */
    00371
    00372 void
    00373 atexit_cleanup (void)
    00374 {
    00375     FILE *dump;
    00376
    00377     if (global_dump_core)
    00378     {
    00379         if ((dump = fopen ("core_avr_dump.core", "w")) == NULL)
    00380         {
    00381             /* can't call avr_error here since it could have called us */
    00382             fprintf (stderr, "fopen failed: core_avr_dump.core: %s\n",
    00383                      strerror (errno));
    00384         }
    00385         else
    00386         {
    00387             avr_core_dump_core (global_core, dump);
    00388             fclose (dump);
    00389         }
    00390     }
    00391
    00392     class_unref ((AvrClass *)global_core);
    00393 }
    00394
    00395 /*
    00396  * Symlinks should be created for each supported device to the
    00397  * simulavr program.
    00398  */
    00399 int
    00400 main (int argc, char **argv)
    00401 {
    00402     int i;
    00403     int flash_sz = 0, sram_sz = 0, eeprom_sz = 0;
    00404     int sram_start = 0;
    00405
    00406     parse_cmd_line (argc, argv);
    00407
    00408     global_core = avr_core_new (global_device_type);
    00409     if (global_core == NULL)
    00410     {
    00411         avr_warning ("Device not supported: %s\n", global_device_type);
    00412         exit (1);
    00413     }
    00414
    00415     avr_message ("Simulating clock frequency of %d Hz\n", global_clock_freq);
    00416
    00417     avr_core_get_sizes (global_core, &flash_sz, &sram_sz, &sram_start,
    00418                         &eeprom_sz);
    00419     display_open (global_disp_prog, global_disp_without_xterm, flash_sz,
    00420                   sram_sz, sram_start, eeprom_sz);
    00421     avr_core_io_display_names (global_core);
    00422
    00423     /* Send initial clock cycles to display */
    00424     display_clock (0);
    00425
    00426     /* install my_atexit to be called when exit() is called */
    00427     if (atexit (atexit_cleanup))
    00428         avr_error ("Failed to install exit handler");
    00429
    00430 #if 0
    00431     /* Add external device hooks to ports */
    00432     avr_core_add_ext_rd_wr (global_core, PORT_B_BASE, ext_port_rd,
    00433                             ext_port_wr);
    00434     avr_core_add_ext_rd_wr (global_core, PORT_C_BASE, ext_port_rd,
    00435                             ext_port_wr);
    00436     avr_core_add_ext_rd_wr (global_core, PORT_D_BASE, ext_port_rd,
    00437                             ext_port_wr);
    00438 #endif
    00439
    00440     /* Load program into flash */
    00441     if (global_flash_image_file)
    00442         avr_core_load_program (global_core, global_flash_image_file,
    00443                                global_flash_image_type);
    00444
    00445     /* Load eeprom data image into eeprom */
    00446     if (global_eeprom_image_file)
    00447         avr_core_load_eeprom (global_core, global_eeprom_image_file,
    00448                               global_eeprom_image_type);
    00449
    00450     for (i = 0; i < global_break_count; i++)
    00451     {
    00452         /* Note that we interpret the break address from the user as a byte
    00453            address instead of a word address. This makes it easier on the user
    00454            since binutils, gcc and gdb all work in terms of byte addresses. */
    00455
    00456         avr_message ("Setting breakpoint at 0x%x.\n", global_break_list[i]);
    00457         avr_core_insert_breakpoint (global_core, global_break_list[i] / 2);
    00458     }
    00459
    00460     if (global_gdbserver_mode == 1)
    00461     {
    00462         global_gdb_comm->user_data = global_core;
    00463         gdb_interact (global_gdb_comm, global_gdbserver_port,
    00464                       global_gdb_debug);
    00465     }
    00466     else
    00467     {
    00468         if (global_flash_image_file)
    00469             /* Run the program */
    00470             avr_core_run (global_core);
    00471         else
    00472             fprintf (stderr, "No program was specified to be run.\n");
    00473     }
    00474
    00475     display_close ();           /* close down the display coprocess */
    00476
    00477     exit (0);
    00478     return 0;
    00479 }

Automatically generated by Doxygen 1.5.5 on 7 Nov 2008.