Main Page | File List | Globals | Related Pages

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.3.8 on 11 Aug 2004.