display.c

Go to the documentation of this file.
00001 /*
00002  * $Id: display.c,v 1.14 2003/12/01 09:10:14 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 /**
00027  * \file display.c
00028  * \brief Interface for using display coprocesses.
00029  *
00030  * Simulavr has the ability to use a coprocess to display register and memory
00031  * values in near real time.
00032  */
00033 
00034 #include <config.h>
00035 
00036 #include <stdio.h>
00037 #include <string.h>
00038 #include <stdlib.h>
00039 #include <errno.h>
00040 #include <sys/types.h>
00041 #include <sys/wait.h>
00042 #include <unistd.h>
00043 #include <fcntl.h>
00044 #include <sys/ioctl.h>
00045 #include <signal.h>
00046 
00047 #include "avrerror.h"
00048 #include "avrmalloc.h"
00049 #include "display.h"
00050 
00051 enum
00052 {
00053     MAX_BUF = 1024,
00054 };
00055 
00056 /* I really don't want to use a global here, but I also don't want to have to
00057    track the pipe's fd in the core. */
00058 
00059 static int global_pipe_fd = -1;
00060 
00061 /* Need to store the child's pid so that we can kill and waitpid it when you
00062    close the display. Otherwise we have problems with zombies. */
00063 
00064 static pid_t global_child_pid = -1;
00065 
00066 /** \brief Open a display as a coprocess.
00067     \param prog        The program to use as a display coprocess.
00068     \param no_xterm    If non-zero, don't run the disply in an xterm.
00069     \param flash_sz    The size of the flash memory space in bytes.
00070     \param sram_sz     The size of the sram memory space in bytes.
00071     \param sram_start  The addr of the first byte of sram (usually 0x60 or
00072                        0x100).
00073     \param eeprom_sz   The size of the eeprom memory space in bytes.
00074 
00075     Try to start up a helper program as a child process for displaying
00076     registers and memory. If the prog argument is NULL, don't start up a
00077     display.
00078 
00079     Returns an open file descriptor of a pipe used to send data to
00080     the helper program. 
00081     
00082     Returns -1 if something failed. */
00083 
00084 int
00085 display_open (char *prog, int no_xterm, int flash_sz, int sram_sz,
00086               int sram_start, int eeprom_sz)
00087 {
00088     pid_t pid;
00089     int pfd[2];                 /* pipe file desc: pfd[0] is read, pfd[1] is
00090                                    write */
00091     int res;
00092 
00093     if (prog == NULL)
00094     {
00095         prog = getenv ("SIM_DISP_PROG");
00096         if (prog == NULL)
00097             return -1;
00098     }
00099 
00100     /* Open a pipe for writing from the simulator to the display program. 
00101        We don't want to use popen() since the display program might need to 
00102        use stdin/stdout for it's own uses. */
00103 
00104     res = pipe (pfd);
00105     if (res < 0)
00106     {
00107         avr_warning ("pipe failed: %s\n", strerror (errno));
00108         return -1;
00109     }
00110 
00111     /* Fork off a new process. */
00112 
00113     pid = fork ();
00114     if (pid < 0)
00115     {
00116         avr_warning ("fork failed: %s\n", strerror (errno));
00117         return -1;
00118     }
00119     else if (pid > 0)           /* parent process */
00120     {
00121         /* close the read side of the pipe */
00122         close (pfd[0]);
00123 
00124         /* remember the child's pid */
00125         global_child_pid = pid;
00126 
00127         global_pipe_fd = pfd[1];
00128         return global_pipe_fd;
00129     }
00130     else                        /* child process */
00131     {
00132         char pfd_env[20];
00133         char fl_sz[20], sr_sz[20], sr_start[20], eep_sz[20];
00134         char spfd[10];
00135 
00136         /* close the write side of the pipe */
00137         close (pfd[1]);
00138 
00139         /* setup the args for display program */
00140         snprintf (fl_sz, sizeof (fl_sz) - 1, "%d", flash_sz);
00141         snprintf (sr_sz, sizeof (sr_sz) - 1, "%d", sram_sz);
00142         snprintf (sr_start, sizeof (sr_start) - 1, "%d", sram_start);
00143         snprintf (eep_sz, sizeof (eep_sz) - 1, "%d", eeprom_sz);
00144         snprintf (spfd, sizeof (spfd) - 1, "%d", pfd[0]);
00145 
00146         /* set the SIM_PIPE_FD env variable */
00147         snprintf (pfd_env, sizeof (pfd_env), "SIM_PIPE_FD=%d", pfd[0]);
00148         putenv (pfd_env);
00149 
00150         /* The user can specify not to use an xterm since some display
00151            programs might not need (or want) to be run in an xterm. For
00152            example, a gtk+ program would be able to handle it's own
00153            windowing. Of course, starting 'prog' up with it's own xterm, will
00154            not hurt and 'prog' will put stdout/stderr there instead of mixing
00155            with simulavr's output. The default is to start prog in an
00156            xterm. */
00157 
00158         if (no_xterm)
00159         {
00160             execlp (prog, prog, "--pfd", spfd, fl_sz, sr_sz, sr_start, eep_sz,
00161                     NULL);
00162         }
00163         else
00164         {
00165             /* try to start up the display program in it's own xterm */
00166             execlp ("xterm", "xterm", "-geom", "100x50", "-e", prog, "--pfd",
00167                     spfd, fl_sz, sr_sz, sr_start, eep_sz, NULL);
00168         }
00169 
00170         /* if the exec returns, an error occurred */
00171         avr_warning ("exec failed: %s\n", strerror (errno));
00172         _exit (1);
00173     }
00174 
00175     return -1;                  /* should never get here */
00176 }
00177 
00178 /** \brief Close a display and send coprocess a quit message. */
00179 
00180 void
00181 display_close (void)
00182 {
00183     if (global_pipe_fd < 0)
00184         return;
00185 
00186     display_send_msg ("q");
00187     close (global_pipe_fd);
00188     global_pipe_fd = -1;
00189 
00190     kill (global_child_pid, SIGINT);
00191     waitpid (0, NULL, 0);
00192 }
00193 
00194 static unsigned char
00195 checksum (char *s)
00196 {
00197     unsigned char CC = 0;
00198     while (*s)
00199     {
00200         CC += *s;
00201         s++;
00202     }
00203 
00204     return CC;
00205 }
00206 
00207 /** \brief Encode the message and send to display.
00208     \param msg   The message string to be sent to the display process.
00209 
00210     Encoding is the same as that used by the gdb remote protocol: '\$...\#CC'
00211     where '...' is msg, CC is checksum. There is no newline termination for
00212     encoded messages.
00213 
00214     FIXME: TRoth: This should be a private function. It is only public so that
00215     dtest.c can be kept simple. dtest.c should be changed to avoid direct use
00216     of this function. [dtest.c has served it's purpose and will be retired
00217     soon.] */
00218 
00219 void
00220 display_send_msg (char *msg)
00221 {
00222     int len = strlen (msg) + 4 + 1;
00223     int res;
00224     char *enc_msg;              /* the encoded msg */
00225 
00226     enc_msg = avr_new0 (char, len + 1);
00227 
00228     snprintf (enc_msg, len, "$%s#%02x", msg, checksum (msg));
00229 #if defined(DISP_DEBUG_OUTPUT_ON)
00230     fprintf (stderr, "DISP: %s\n", enc_msg);
00231 #endif
00232 
00233     res = write (global_pipe_fd, enc_msg, len);
00234     if ((res < 0) && (errno == EINTR))
00235     {
00236         /* write() was interrupted, try again and if it still fails, let it be
00237            fatal. */
00238         avr_warning ("Interrupted write()\n");
00239         res = write (global_pipe_fd, enc_msg, len);
00240     }
00241     if (res < 0)
00242         avr_error ("write failed: %s\n", strerror (errno));
00243     if (res < len)
00244         avr_error ("incomplete write\n");
00245 
00246     avr_free (enc_msg);
00247 }
00248 
00249 static char global_buf[MAX_BUF + 1];
00250 
00251 /** \brief Update the time in the display.
00252     \param clock   The new time in number of clocks. */
00253 
00254 void
00255 display_clock (int clock)
00256 {
00257     if (global_pipe_fd < 0)
00258         return;
00259 
00260     snprintf (global_buf, MAX_BUF, "n%x", clock);
00261     global_buf[MAX_BUF] = '\0';
00262     display_send_msg (global_buf);
00263 }
00264 
00265 /** \brief Update the Program Counter in the display.
00266     \param val   The new value of the program counter. */
00267 
00268 void
00269 display_pc (int val)
00270 {
00271     if (global_pipe_fd < 0)
00272         return;
00273 
00274     snprintf (global_buf, MAX_BUF, "p%x", val);
00275     global_buf[MAX_BUF] = '\0';
00276     display_send_msg (global_buf);
00277 }
00278 
00279 /** \brief Update a register in the display.
00280     \param reg   The register number.
00281     \param val   The new value of the register. */
00282 
00283 void
00284 display_reg (int reg, uint8_t val)
00285 {
00286     if (global_pipe_fd < 0)
00287         return;
00288 
00289     snprintf (global_buf, MAX_BUF, "r%x:%02x", reg, val);
00290     global_buf[MAX_BUF] = '\0';
00291     display_send_msg (global_buf);
00292 }
00293 
00294 /** \brief Update an IO register in the display.
00295     \param reg   The IO register number.
00296     \param val   The new value of the register. */
00297 
00298 void
00299 display_io_reg (int reg, uint8_t val)
00300 {
00301     if (global_pipe_fd < 0)
00302         return;
00303 
00304     snprintf (global_buf, MAX_BUF, "i%x:%02x", reg, val);
00305     global_buf[MAX_BUF] = '\0';
00306     display_send_msg (global_buf);
00307 }
00308 
00309 /** \brief Specify a name for an IO register.
00310     \param reg    The IO register number.
00311     \param name   The symbolic name of the register.
00312 
00313     Names of IO registers may be different from device to device. */
00314 
00315 void
00316 display_io_reg_name (int reg, char *name)
00317 {
00318     if (global_pipe_fd < 0)
00319         return;
00320 
00321     snprintf (global_buf, MAX_BUF, "I%x:%s", reg, name);
00322     global_buf[MAX_BUF] = '\0';
00323     display_send_msg (global_buf);
00324 }
00325 
00326 /** \brief Update a block of flash addresses in the display.
00327     \param addr  Address of beginning of the block.
00328     \param len   Length of the block (number of words).
00329     \param vals  Pointer to an array of \a len words.
00330 
00331     The display will update each addr of the block to the coresponding value
00332     in the \a vals array.
00333 
00334     Each address in the flash references a single 16-bit wide word (or opcode
00335     or instruction). Therefore, flash addresses are aligned to 16-bit
00336     boundaries. It is simplest to consider the flash an array of 16-bit values
00337     indexed by the address. */
00338 
00339 void
00340 display_flash (int addr, int len, uint16_t * vals)
00341 {
00342     int bytes;
00343     int i;
00344 
00345     if (global_pipe_fd < 0)
00346         return;
00347 
00348     bytes = snprintf (global_buf, MAX_BUF, "f%x,%x:", addr, len);
00349 
00350     for (i = 0; i < len; i++)
00351     {
00352         if (MAX_BUF - bytes < 0)
00353             avr_error ("buffer overflow");
00354 
00355         bytes +=
00356             snprintf (global_buf + bytes, MAX_BUF - bytes, "%04x", vals[i]);
00357     }
00358 
00359     global_buf[MAX_BUF] = '\0';
00360     display_send_msg (global_buf);
00361 }
00362 
00363 /** \brief Update a block of sram addresses in the display.
00364     \param addr  Address of beginning of the block.
00365     \param len   Length of the block (number of bytes).
00366     \param vals  Pointer to an array of \a len bytes.
00367 
00368     The display will update each addr of the block to the coresponding value
00369     in the \a vals array. */
00370 
00371 void
00372 display_sram (int addr, int len, uint8_t * vals)
00373 {
00374     int bytes;
00375     int i;
00376 
00377     if (global_pipe_fd < 0)
00378         return;
00379 
00380     bytes = snprintf (global_buf, MAX_BUF, "s%x,%x:", addr, len);
00381 
00382     for (i = 0; i < len; i++)
00383     {
00384         if (MAX_BUF - bytes < 0)
00385             avr_error ("buffer overflow");
00386 
00387         bytes +=
00388             snprintf (global_buf + bytes, MAX_BUF - bytes, "%02x", vals[i]);
00389     }
00390 
00391     global_buf[MAX_BUF] = '\0';
00392     display_send_msg (global_buf);
00393 }
00394 
00395 /** \brief Update a block of eeprom addresses in the display.
00396     \param addr  Address of beginning of the block.
00397     \param len   Length of the block (number of bytes).
00398     \param vals  Pointer to an array of \a len bytes.
00399 
00400     The display will update each addr of the block to the coresponding value
00401     in the \a vals array. */
00402 
00403 void
00404 display_eeprom (int addr, int len, uint8_t * vals)
00405 {
00406     int bytes;
00407     int i;
00408 
00409     if (global_pipe_fd < 0)
00410         return;
00411 
00412     bytes = snprintf (global_buf, MAX_BUF, "e%x,%x:", addr, len);
00413 
00414     for (i = 0; i < len; i++)
00415     {
00416         if (MAX_BUF - bytes < 0)
00417             avr_error ("buffer overflow");
00418 
00419         bytes +=
00420             snprintf (global_buf + bytes, MAX_BUF - bytes, "%02x", vals[i]);
00421     }
00422 
00423     global_buf[MAX_BUF] = '\0';
00424     display_send_msg (global_buf);
00425 }

Automatically generated by Doxygen 1.4.7 on 28 Oct 2006.