"I am a person who works hard and plays hard."

Yuan Wei
Second Year Graduate Student Department of Computer Science
University of Virginia Charlottesville, VA 22903
Email: yw3f@cs.virginia.edu


Source Code Analysis

Main Page   Compound List   File List   Compound Members   File Members  

eio.c

Go to the documentation of this file.
00001 /*
00002  * eio.c - external interfaces to external I/O f\iles
00003  *
00004  * This file is a part of the SimpleScalar tool suite written by
00005  * Todd M. Austin as a part of the Multiscalar Research Project.
00006  *  
00007  * The tool suite is currently maintained by Doug Burger and Todd M. Austin.
00008  * 
00009  * Copyright (C) 1997, 1998 by Todd M. Austin
00010  *
00011  * This source file is distributed "as is" in the hope that it will be
00012  * useful.  The tool set comes with no warranty, and no author or
00013  * distributor accepts any responsibility for the consequences of its
00014  * use. 
00015  * 
00016  * Everyone is granted permission to copy, modify and redistribute
00017  * this tool set under the following conditions:
00018  * 
00019  *    This source code is distributed for non-commercial use only. 
00020  *    Please contact the maintainer for restrictions applying to 
00021  *    commercial use.
00022  *
00023  *    Permission is granted to anyone to make or distribute copies
00024  *    of this source code, either as received or modified, in any
00025  *    medium, provided that all copyright notices, permission and
00026  *    nonwarranty notices are preserved, and that the distributor
00027  *    grants the recipient permission for further redistribution as
00028  *    permitted by this document.
00029  *
00030  *    Permission is granted to distribute this file in compiled
00031  *    or executable form under the same conditions that apply for
00032  *    source code, provided that either:
00033  *
00034  *    A. it is accompanied by the corresponding machine-readable
00035  *       source code,
00036  *    B. it is accompanied by a written offer, with no time limit,
00037  *       to give anyone a machine-readable copy of the corresponding
00038  *       source code in return for reimbursement of the cost of
00039  *       distribution.  This written offer must permit verbatim
00040  *       duplication by anyone, or
00041  *    C. it is distributed by someone who received only the
00042  *       executable form, and is accompanied by a copy of the
00043  *       written offer of source code that they received concurrently.
00044  *
00045  * In other words, you are welcome to use, share and improve this
00046  * source file.  You are forbidden to forbid anyone else to use, share
00047  * and improve what you give them.
00048  *
00049  * INTERNET: dburger@cs.wisc.edu
00050  * US Mail:  1210 W. Dayton Street, Madison, WI 53706
00051  *
00052  * $Id: eio.c,v 1.1.1.1 2000/05/26 15:21:52 taustin Exp $
00053  *
00054  * $Log: eio.c,v $
00055  * Revision 1.1.1.1  2000/05/26 15:21:52  taustin
00056  * SimpleScalar Tool Set
00057  *
00058  *
00059  * Revision 1.5  1999/12/31 18:34:24  taustin
00060  * event tracing (EIO) now works for traces longer than 2^32 insts
00061  *
00062  * Revision 1.4  1999/12/13 18:39:11  taustin
00063  * cross endian execution support added
00064  *
00065  * Revision 1.3  1998/09/03 22:23:24  taustin
00066  * fixed MACRO bug for Intel Reference Compiler (icc)
00067  *
00068  * Revision 1.2  1998/08/31 17:07:35  taustin
00069  * added MS VC++ headers, fixed bug in call to write()
00070  *
00071  * Revision 1.1  1998/08/27 08:20:31  taustin
00072  * Initial revision
00073  *
00074  *
00075  */
00076 
00077 #include <stdio.h>
00078 #include <stdlib.h>
00079 #ifdef _MSC_VER
00080 #include <io.h>
00081 #else /* !_MSC_VER */
00082 #include <unistd.h>
00083 #endif
00084 
00085 #include "host.h"
00086 #include "misc.h"
00087 #include "machine.h"
00088 #include "regs.h"
00089 #include "memory.h"
00090 #include "loader.h"
00091 #include "libexo/libexo.h"
00092 #include "syscall.h"
00093 #include "sim.h"
00094 #include "endian.h"
00095 #include "eio.h"
00096 
00097 #ifdef _MSC_VER
00098 #define write           _write
00099 #endif
00100 
00101 #define EIO_FILE_HEADER                                                 \
00102   "/* This is a SimpleScalar EIO file - DO NOT MOVE OR EDIT THIS LINE! */\n"
00103 /*
00104    EIO transaction format:
00105 
00106    (inst_count, pc,
00107     ... reg inputs ...
00108     [r2, r3, r4, r5, r6, r7],
00109     ... mem inputs ...
00110     ((addr, size, blob), ...)
00111     ... reg outputs ...
00112     [r2, r3, r4, r5, r6, r7],
00113     ... mem outputs ...
00114     ((addr, size, blob), ...)
00115    )
00116 */
00117 
00118 /* EIO transaction count, i.e., number of last transaction completed */
00119 static counter_t eio_trans_icnt = -1;
00120 
00121 FILE *
00122 eio_create(char *fname)
00123 {
00124   FILE *fd;
00125   struct exo_term_t *exo;
00126   int target_big_endian;
00127 
00128   target_big_endian = (endian_host_byte_order() == endian_big);
00129 
00130   fd = gzopen(fname, "w");
00131   if (!fd)
00132     fatal("unable to create EIO file `%s'", fname);
00133 
00134   /* emit EIO file header */
00135   fprintf(fd, "%s\n", EIO_FILE_HEADER);
00136   fprintf(fd, "/* file_format: %d, file_version: %d, big_endian: %d */\n", 
00137           MD_EIO_FILE_FORMAT, EIO_FILE_VERSION, ld_target_big_endian);
00138   exo = exo_new(ec_list,
00139                 exo_new(ec_integer, (exo_integer_t)MD_EIO_FILE_FORMAT),
00140                 exo_new(ec_integer, (exo_integer_t)EIO_FILE_VERSION),
00141                 exo_new(ec_integer, (exo_integer_t)target_big_endian),
00142                 NULL);
00143   exo_print(exo, fd);
00144   exo_delete(exo);
00145   fprintf(fd, "\n\n");
00146 
00147   return fd;
00148 }
00149 
00150 FILE *
00151 eio_open(char *fname)
00152 {
00153   FILE *fd;
00154   struct exo_term_t *exo;
00155   int file_format, file_version, big_endian, target_big_endian;
00156 
00157   target_big_endian = (endian_host_byte_order() == endian_big);
00158 
00159   fd = gzopen(fname, "r");
00160   if (!fd)
00161     fatal("unable to open EIO file `%s'", fname);
00162 
00163   /* read and check EIO file header */
00164   exo = exo_read(fd);
00165   if (!exo
00166       || exo->ec != ec_list
00167       || !exo->as_list.head
00168       || exo->as_list.head->ec != ec_integer
00169       || !exo->as_list.head->next
00170       || exo->as_list.head->next->ec != ec_integer
00171       || !exo->as_list.head->next->next
00172       || exo->as_list.head->next->next->ec != ec_integer
00173       || exo->as_list.head->next->next->next != NULL)
00174     fatal("could not read EIO file header");
00175 
00176   file_format = exo->as_list.head->as_integer.val;
00177   file_version = exo->as_list.head->next->as_integer.val;
00178   big_endian = exo->as_list.head->next->next->as_integer.val;
00179   exo_delete(exo);
00180 
00181   if (file_format != MD_EIO_FILE_FORMAT)
00182     fatal("EIO file `%s' has incompatible format", fname);
00183 
00184   if (file_version != EIO_FILE_VERSION)
00185     fatal("EIO file `%s' has incompatible version", fname);
00186 
00187   if (!!big_endian != !!target_big_endian)
00188     {
00189       warn("endian of `%s' does not match host", fname);
00190       warn("running with experimental cross-endian execution support");
00191       warn("****************************************");
00192       warn("**>> please check results carefully <<**");
00193       warn("****************************************");
00194     }
00195 
00196   return fd;
00197 }
00198 
00199 /* returns non-zero if file FNAME has a valid EIO header */
00200 int
00201 eio_valid(char *fname)
00202 {
00203   FILE *fd;
00204   char buf[512];
00205 
00206   /* open possible EIO file */
00207   fd = gzopen(fname, "r");
00208   if (!fd)
00209     return FALSE;
00210 
00211   /* read and check EIO file header */
00212   fgets(buf, 512, fd);
00213 
00214   /* check the header */
00215   if (strcmp(buf, EIO_FILE_HEADER))
00216     return FALSE;
00217 
00218   /* all done, close up file */
00219   gzclose(fd);
00220 
00221   /* else, has a valid header, go with it... */
00222   return TRUE;
00223 }
00224 
00225 void
00226 eio_close(FILE *fd)
00227 {
00228   gzclose(fd);
00229 }
00230 
00231 /* check point current architected state to stream FD, returns
00232    EIO transaction count (an EIO file pointer) */
00233 counter_t
00234 eio_write_chkpt(struct regs_t *regs,            /* regs to dump */
00235                 struct mem_t *mem,              /* memory to dump */
00236                 FILE *fd)                       /* stream to write to */
00237 {
00238   int i;
00239   struct exo_term_t *exo;
00240   struct mem_pte_t *pte;
00241 
00242   myfprintf(fd, "/* ** start checkpoint @ %n... */\n\n", eio_trans_icnt);
00243 
00244   myfprintf(fd, "/* EIO file pointer: %n... */\n", eio_trans_icnt);
00245   exo = exo_new(ec_integer, (exo_integer_t)eio_trans_icnt);
00246   exo_print(exo, fd);
00247   fprintf(fd, "\n\n");
00248   exo_delete(exo);
00249 
00250   /* dump misc regs: icnt, PC, NPC, etc... */
00251   fprintf(fd, "/* misc regs icnt, PC, NPC, etc... */\n");
00252   exo = MD_MISC_REGS_TO_EXO(regs);
00253   exo_print(exo, fd);
00254   fprintf(fd, "\n\n");
00255   exo_delete(exo);
00256 
00257   /* dump integer registers */
00258   fprintf(fd, "/* integer regs */\n");
00259   exo = exo_new(ec_list, NULL);
00260   for (i=0; i < MD_NUM_IREGS; i++)
00261     exo->as_list.head = exo_chain(exo->as_list.head, MD_IREG_TO_EXO(regs, i));
00262   exo_print(exo, fd);
00263   fprintf(fd, "\n\n");
00264   exo_delete(exo);
00265 
00266   /* dump FP registers */
00267   fprintf(fd, "/* FP regs (integer format) */\n");
00268   exo = exo_new(ec_list, NULL);
00269   for (i=0; i < MD_NUM_FREGS; i++)
00270     exo->as_list.head = exo_chain(exo->as_list.head, MD_FREG_TO_EXO(regs, i));
00271   exo_print(exo, fd);
00272   fprintf(fd, "\n\n");
00273   exo_delete(exo);
00274 
00275   fprintf(fd, "/* writing `%d' memory pages... */\n", (int)mem->page_count);
00276   exo = exo_new(ec_list,
00277                 exo_new(ec_integer, (exo_integer_t)mem->page_count),
00278                 exo_new(ec_address, (exo_integer_t)ld_brk_point),
00279                 exo_new(ec_address, (exo_integer_t)ld_stack_min),
00280                 NULL);
00281   exo_print(exo, fd);
00282   fprintf(fd, "\n\n");
00283   exo_delete(exo);
00284 
00285   fprintf(fd, "/* text segment specifiers (base & size) */\n");
00286   exo = exo_new(ec_list,
00287                 exo_new(ec_address, (exo_integer_t)ld_text_base),
00288                 exo_new(ec_integer, (exo_integer_t)ld_text_size),
00289                 NULL);
00290   exo_print(exo, fd);
00291   fprintf(fd, "\n\n");
00292   exo_delete(exo);
00293 
00294   fprintf(fd, "/* data segment specifiers (base & size) */\n");
00295   exo = exo_new(ec_list,
00296                 exo_new(ec_address, (exo_integer_t)ld_data_base),
00297                 exo_new(ec_integer, (exo_integer_t)ld_data_size),
00298                 NULL);
00299   exo_print(exo, fd);
00300   fprintf(fd, "\n\n");
00301   exo_delete(exo);
00302 
00303   fprintf(fd, "/* stack segment specifiers (base & size) */\n");
00304   exo = exo_new(ec_list,
00305                 exo_new(ec_address, (exo_integer_t)ld_stack_base),
00306                 exo_new(ec_integer, (exo_integer_t)ld_stack_size),
00307                 NULL);
00308   exo_print(exo, fd);
00309   fprintf(fd, "\n\n");
00310   exo_delete(exo);
00311 
00312   /* visit all active memory pages, and dump them to the checkpoint file */
00313   MEM_FORALL(mem, i, pte)
00314     {
00315       /* dump this page... */
00316       exo = exo_new(ec_list,
00317                     exo_new(ec_address, (exo_integer_t)MEM_PTE_ADDR(pte, i)),
00318                     exo_new(ec_blob, MD_PAGE_SIZE, pte->page),
00319                     NULL);
00320       exo_print(exo, fd);
00321       fprintf(fd, "\n\n");
00322       exo_delete(exo);
00323     }
00324 
00325   myfprintf(fd, "/* ** end checkpoint @ %n... */\n\n", eio_trans_icnt);
00326 
00327   return eio_trans_icnt;
00328 }
00329 
00330 /* read check point of architected state from stream FD, returns
00331    EIO transaction count (an EIO file pointer) */
00332 counter_t
00333 eio_read_chkpt(struct regs_t *regs,             /* regs to dump */
00334                 struct mem_t *mem,              /* memory to dump */
00335                 FILE *fd)                       /* stream to read */
00336 {
00337   int i, page_count;
00338   counter_t trans_icnt;
00339   struct exo_term_t *exo, *elt;
00340 
00341   /* read the EIO file pointer */
00342   exo = exo_read(fd);
00343   if (!exo
00344       || exo->ec != ec_integer)
00345     fatal("could not read EIO file pointer");
00346   trans_icnt = exo->as_integer.val;
00347   exo_delete(exo);
00348 
00349   /* read misc regs: icnt, PC, NPC, HI, LO, FCC */
00350   exo = exo_read(fd);
00351   MD_EXO_TO_MISC_REGS(exo, sim_num_insn, regs);
00352   exo_delete(exo);
00353 
00354   /* read integer registers */
00355   exo = exo_read(fd);
00356   if (!exo
00357       || exo->ec != ec_list)
00358     fatal("could not read EIO integer regs");
00359   elt = exo->as_list.head;
00360   for (i=0; i < MD_NUM_IREGS; i++)
00361     {
00362       if (!elt)
00363         fatal("could not read EIO integer regs (too few)");
00364 
00365       if (elt->ec != ec_address)
00366         fatal("could not read EIO integer regs (bad value)");
00367 
00368       MD_EXO_TO_IREG(elt, regs, i);
00369       elt = elt->next;
00370     }
00371   if (elt != NULL)
00372     fatal("could not read EIO integer regs (too many)");
00373   exo_delete(exo);
00374 
00375   /* read FP registers */
00376   exo = exo_read(fd);
00377   if (!exo
00378       || exo->ec != ec_list)
00379     fatal("could not read EIO FP regs");
00380   elt = exo->as_list.head;
00381   for (i=0; i < MD_NUM_FREGS; i++)
00382     {
00383       if (!elt)
00384         fatal("could not read EIO FP regs (too few)");
00385 
00386       if (elt->ec != ec_address)
00387         fatal("could not read EIO FP regs (bad value)");
00388 
00389       MD_EXO_TO_FREG(elt, regs, i);
00390       elt = elt->next;
00391     }
00392   if (elt != NULL)
00393     fatal("could not read EIO FP regs (too many)");
00394   exo_delete(exo);
00395 
00396   /* read the number of page defs, and memory config */
00397   exo = exo_read(fd);
00398   if (!exo
00399       || exo->ec != ec_list
00400       || !exo->as_list.head
00401       || exo->as_list.head->ec != ec_integer
00402       || !exo->as_list.head->next
00403       || exo->as_list.head->next->ec != ec_address
00404       || !exo->as_list.head->next->next
00405       || exo->as_list.head->next->next->ec != ec_address
00406       || exo->as_list.head->next->next->next != NULL)
00407     fatal("could not read EIO memory page count");
00408   page_count = exo->as_list.head->as_integer.val;
00409   ld_brk_point = (md_addr_t)exo->as_list.head->next->as_address.val;
00410   ld_stack_min = (md_addr_t)exo->as_list.head->next->next->as_address.val;
00411   exo_delete(exo);
00412 
00413   /* read text segment specifiers */
00414   exo = exo_read(fd);
00415   if (!exo
00416       || exo->ec != ec_list
00417       || !exo->as_list.head
00418       || exo->as_list.head->ec != ec_address
00419       || !exo->as_list.head->next
00420       || exo->as_list.head->next->ec != ec_integer
00421       || exo->as_list.head->next->next != NULL)
00422     fatal("count not read EIO text segment specifiers");
00423   ld_text_base = (md_addr_t)exo->as_list.head->as_address.val;
00424   ld_text_size = (unsigned int)exo->as_list.head->next->as_integer.val;
00425   exo_delete(exo);
00426 
00427   /* read data segment specifiers */
00428   exo = exo_read(fd);
00429   if (!exo
00430       || exo->ec != ec_list
00431       || !exo->as_list.head
00432       || exo->as_list.head->ec != ec_address
00433       || !exo->as_list.head->next
00434       || exo->as_list.head->next->ec != ec_integer
00435       || exo->as_list.head->next->next != NULL)
00436     fatal("count not read EIO data segment specifiers");
00437   ld_data_base = (md_addr_t)exo->as_list.head->as_address.val;
00438   ld_data_size = (unsigned int)exo->as_list.head->next->as_integer.val;
00439   exo_delete(exo);
00440 
00441   /* read stack segment specifiers */
00442   exo = exo_read(fd);
00443   if (!exo
00444       || exo->ec != ec_list
00445       || !exo->as_list.head
00446       || exo->as_list.head->ec != ec_address
00447       || !exo->as_list.head->next
00448       || exo->as_list.head->next->ec != ec_integer
00449       || exo->as_list.head->next->next != NULL)
00450     fatal("count not read EIO stack segment specifiers");
00451   ld_stack_base = (md_addr_t)exo->as_list.head->as_address.val;
00452   ld_stack_size = (unsigned int)exo->as_list.head->next->as_integer.val;
00453   exo_delete(exo);
00454 
00455   for (i=0; i < page_count; i++)
00456     {
00457       int j;
00458       md_addr_t page_addr;
00459       struct exo_term_t *blob;
00460 
00461       /* read the page */
00462       exo = exo_read(fd);
00463       if (!exo
00464           || exo->ec != ec_list
00465           || !exo->as_list.head
00466           || exo->as_list.head->ec != ec_address
00467           || !exo->as_list.head->next
00468           || exo->as_list.head->next->ec != ec_blob
00469           || exo->as_list.head->next->next != NULL)
00470         fatal("could not read EIO memory page");
00471       page_addr = (md_addr_t)exo->as_list.head->as_address.val;
00472       blob = exo->as_list.head->next;
00473 
00474       /* write data to simulator memory */
00475       for (j=0; j < blob->as_blob.size; j++)
00476         {
00477           byte_t val;
00478 
00479           val = blob->as_blob.data[j];
00480           /* unchecked access... */
00481           MEM_WRITE_BYTE(mem, page_addr, val);
00482           page_addr++;
00483         }
00484       exo_delete(exo);
00485     }
00486 
00487   return trans_icnt;
00488 }
00489 
00490 struct mem_rec_t {
00491   md_addr_t addr;
00492   unsigned size, maxsize;
00493   struct exo_term_t *exo;
00494   struct exo_term_t *blob;
00495 };
00496 
00497 /* reg recs */
00498 static struct exo_term_t *input_regs;
00499 static struct exo_term_t *output_regs;
00500 
00501 /* input memory recs */
00502 static struct exo_term_t *input_mem;
00503 static struct mem_rec_t input_mem_rec;
00504 
00505 /* output memory recs */
00506 static struct exo_term_t *output_mem;
00507 static struct mem_rec_t output_mem_rec;
00508 
00509 static int seen_write;
00510 static mem_access_fn local_mem_fn;
00511 
00512 /* size of padding that can be filled on the end of a blob tail */
00513 #define BLOB_TAIL_SIZE          256
00514 
00515 /* tracing memory access function */
00516 static enum md_fault_type
00517 my_mem_fn(struct mem_t *mem,            /* memory space to access */
00518           enum mem_cmd cmd,             /* Read (from sim mem) or Write */
00519           md_addr_t addr,               /* target address to access */
00520           void *vp,                     /* host memory address to access */
00521           int nbytes)                   /* number of bytes to access */
00522 {
00523   int i;
00524   unsigned char *p = vp;
00525   struct mem_rec_t *mem_rec = NULL;
00526   struct exo_term_t *mem_list = NULL;
00527   enum md_fault_type fault = md_fault_none;
00528 
00529   if (cmd == Read && seen_write)
00530     fatal("Read after Write in eio_syscall()");
00531 
00532   if (cmd == Write)
00533     seen_write = TRUE;
00534 
00535   /* record the memory access */
00536   if (cmd == Read)
00537     {
00538       mem_rec = &input_mem_rec;
00539       mem_list = input_mem;
00540     }
00541   else if (cmd == Write)
00542     {
00543       mem_rec = &output_mem_rec;
00544       mem_list = output_mem;
00545     }
00546   else
00547     panic("bogus memory access command");
00548 
00549   /* perform the memory access, Read's first so we can probe *p for data */
00550   if (cmd == Read /* simulator memory */)
00551     fault = (*local_mem_fn)(mem, cmd, addr, p, nbytes);
00552 
00553   /* the following freakish code simply coalesces subsequent reads and
00554      writes to memory into the same EXO blob structure, this greatly
00555      reduces the size of the EIO output files... */
00556   if (mem_rec->exo != NULL
00557       && (mem_rec->addr + mem_rec->size == addr)
00558       && (mem_rec->size + nbytes < mem_rec->maxsize))
00559     {
00560       /* add to last blob */
00561       for (i=0; i < nbytes; i++)
00562         mem_rec->blob->as_blob.data[mem_rec->size + i] = p[i];
00563       mem_rec->size += nbytes;
00564       mem_rec->blob->as_blob.size = mem_rec->size;
00565     }
00566   else
00567     {
00568       /* add to a new blob */
00569       mem_list->as_list.head =
00570         exo_chain(mem_list->as_list.head,
00571                   (mem_rec->exo =
00572                    exo_new(ec_list,
00573                            exo_new(ec_address, (exo_integer_t)addr),
00574                            (mem_rec->blob =
00575                             exo_new(ec_blob, nbytes + BLOB_TAIL_SIZE, NULL)),
00576                            NULL)));
00577       for (i=0; i < nbytes; i++)
00578         mem_rec->blob->as_blob.data[i] = p[i];
00579       mem_rec->addr = addr;
00580       mem_rec->size = nbytes;
00581       mem_rec->maxsize = nbytes + BLOB_TAIL_SIZE;
00582       mem_rec->blob->as_blob.size = mem_rec->size;
00583     }
00584 
00585   /* perform the memory access */
00586   if (cmd == Write /* simulator memory */)
00587     fault = (*local_mem_fn)(mem, cmd, addr, p, nbytes);
00588 
00589   return fault;
00590 }
00591 
00592 /* syscall proxy handler, with EIO tracing support, architect registers
00593    and memory are assumed to be precise when this function is called,
00594    register and memory are updated with the results of the sustem call */
00595 void
00596 eio_write_trace(FILE *eio_fd,                   /* EIO stream file desc */
00597                 counter_t icnt,                 /* instruction count */
00598                 struct regs_t *regs,            /* registers to update */
00599                 mem_access_fn mem_fn,           /* generic memory accessor */
00600                 struct mem_t *mem,              /* memory to update */
00601                 md_inst_t inst)                 /* system call inst */
00602 {
00603   int i;
00604   struct exo_term_t *exo;
00605 
00606   /* write syscall register inputs ($r2..$r7) */
00607   input_regs = exo_new(ec_list, NULL);
00608   for (i=MD_FIRST_IN_REG; i <= MD_LAST_IN_REG; i++)
00609     {
00610       input_regs->as_list.head =
00611         exo_chain(input_regs->as_list.head, MD_IREG_TO_EXO(regs, i));
00612     }
00613 
00614   /* initialize memory inputs */
00615   input_mem = exo_new(ec_list, NULL); input_mem_rec.exo = NULL;
00616   output_mem = exo_new(ec_list, NULL); output_mem_rec.exo = NULL;
00617 
00618   /* perform the system call, record inputs and outputs */
00619   seen_write = FALSE;
00620   local_mem_fn = mem_fn;
00621 
00622   if (sim_eio_fd != NULL)
00623     eio_read_trace(sim_eio_fd, icnt, regs, my_mem_fn, mem, inst);
00624   else
00625     {
00626       sys_syscall(regs, my_mem_fn, mem, inst, FALSE);
00627     }
00628 
00629   /* write syscall breakpoint and register outputs ($r2..$r7) */
00630   output_regs = exo_new(ec_list, NULL);
00631   output_regs->as_list.head =
00632         exo_chain(output_regs->as_list.head,
00633                   exo_new(ec_address, (exo_integer_t)ld_brk_point));
00634   for (i=MD_FIRST_OUT_REG; i <= MD_LAST_OUT_REG; i++)
00635     {
00636       output_regs->as_list.head =
00637         exo_chain(output_regs->as_list.head, MD_IREG_TO_EXO(regs, i));
00638     }
00639 
00640   /* write the whole enchalada to output stream */
00641   exo = exo_new(ec_list,
00642                 /* icnt */exo_new(ec_integer, (exo_integer_t)icnt),
00643                 /* PC */exo_new(ec_address, (exo_integer_t)regs->regs_PC),
00644                 input_regs, input_mem,
00645                 output_regs, output_mem,
00646                 NULL);
00647   exo_print(exo, eio_fd);
00648   fprintf(eio_fd, "\n\n");
00649 
00650   /* release input storage */
00651   exo_delete(exo);
00652 
00653   /* one more transaction processed */
00654   eio_trans_icnt = icnt;
00655 }
00656 
00657 /* syscall proxy handler from an EIO trace, architect registers
00658    and memory are assumed to be precise when this function is called,
00659    register and memory are updated with the results of the sustem call */
00660 void
00661 eio_read_trace(FILE *eio_fd,                    /* EIO stream file desc */
00662                counter_t icnt,                  /* instruction count */
00663                struct regs_t *regs,             /* registers to update */
00664                mem_access_fn mem_fn,            /* generic memory accessor */
00665                struct mem_t *mem,               /* memory to update */
00666                md_inst_t inst)                  /* system call inst */
00667 {
00668   int i;
00669   struct exo_term_t *exo, *exo_icnt, *exo_pc;
00670   struct exo_term_t *exo_inregs, *exo_inmem, *exo_outregs, *exo_outmem;
00671   struct exo_term_t *brkrec, *regrec, *memrec;
00672 
00673   /* exit() system calls get executed for real... */
00674   if (MD_EXIT_SYSCALL(regs))
00675     {
00676       sys_syscall(regs, mem_fn, mem, inst, FALSE);
00677       panic("returned from exit() system call");
00678     }
00679 
00680   /* else, read the external I/O (EIO) transaction */
00681   exo = exo_read(eio_fd);
00682 
00683   /* one more transaction processed */
00684   eio_trans_icnt = icnt;
00685 
00686   /* pull apart the EIO transaction (EXO format) */
00687   if (!exo
00688       || exo->ec != ec_list
00689       || !(exo_icnt = exo->as_list.head)
00690       || exo_icnt->ec != ec_integer
00691       || !(exo_pc = exo_icnt->next)
00692       || exo_pc->ec != ec_address
00693       || !(exo_inregs = exo_pc->next)
00694       || exo_inregs->ec != ec_list
00695       || !(exo_inmem = exo_inregs->next)
00696       || exo_inmem->ec != ec_list
00697       || !(exo_outregs = exo_inmem->next)
00698       || exo_outregs->ec != ec_list
00699       || !(exo_outmem = exo_outregs->next)
00700       || exo_outmem->ec != ec_list
00701       || exo_outmem->next != NULL)
00702     fatal("cannot read EIO transaction");
00703 
00704   /*
00705    * check the system call inputs
00706    */
00707 
00708   /* check ICNT input */
00709   if (icnt != (counter_t)exo_icnt->as_integer.val)
00710     fatal("EIO trace inconsistency: ICNT mismatch");
00711 
00712   /* check PC input */
00713   if (regs->regs_PC != (md_addr_t)exo_pc->as_integer.val)
00714     fatal("EIO trace inconsistency: PC mismatch");
00715 
00716   /* check integer register inputs */
00717   for (i=MD_FIRST_IN_REG, regrec=exo_inregs->as_list.head;
00718        i <= MD_LAST_IN_REG; i++, regrec=regrec->next)
00719     {
00720       if (!regrec || regrec->ec != ec_address)
00721         fatal("EIO trace inconsistency: missing input reg");
00722 
00723       if (MD_EXO_CMP_IREG(regrec, regs, i))
00724         fatal("EIO trace inconsistency: R[%d] input mismatch", i);
00725 #ifdef VERBOSE
00726       fprintf(stderr, "** R[%d] checks out...\n", i);
00727 #endif /* VERBOSE */
00728     }
00729   if (regrec != NULL)
00730     fatal("EIO trace inconsistency: too many input regs");
00731 
00732   /* check memory inputs */
00733   for (memrec=exo_inmem->as_list.head; memrec != NULL; memrec=memrec->next)
00734     {
00735       md_addr_t loc;
00736       struct exo_term_t *addr, *blob;
00737 
00738       /* check the mem transaction format */
00739       if (!memrec
00740           || memrec->ec != ec_list
00741           || !(addr = memrec->as_list.head)
00742           || addr->ec != ec_address
00743           || !(blob = addr->next)
00744           || blob->ec != ec_blob
00745           || blob->next != NULL)
00746         fatal("EIO trace inconsistency: bad memory transaction");
00747 
00748       for (loc=addr->as_integer.val, i=0; i < blob->as_blob.size; loc++,i++)
00749         {
00750           unsigned char val;
00751 
00752           /* was: val = MEM_READ_BYTE(loc); */
00753           (*mem_fn)(mem, Read, loc, &val, sizeof(unsigned char));
00754 
00755           if (val != blob->as_blob.data[i])
00756             fatal("EIO trace inconsistency: addr 0x%08p input mismatch", loc);
00757 
00758 #ifdef VERBOSE
00759           myfprintf(stderr, "** 0x%08p checks out...\n", loc);
00760 #endif /* VERBOSE */
00761         }
00762 
00763       /* simulate view'able I/O */
00764       if (MD_OUTPUT_SYSCALL(regs))
00765         {
00766           if (sim_progfd)
00767             {
00768               /* redirect program output to file */
00769               fwrite(blob->as_blob.data, 1, blob->as_blob.size, sim_progfd);
00770             }
00771           else
00772             {
00773               /* write the output to stdout/stderr */
00774               write(MD_STREAM_FILENO(regs),
00775                     blob->as_blob.data, blob->as_blob.size);
00776             }
00777         }
00778     }
00779 
00780   /*
00781    * write system call outputs
00782    */
00783 
00784   /* adjust breakpoint */
00785   brkrec = exo_outregs->as_list.head;
00786   if (!brkrec || brkrec->ec != ec_address)
00787     fatal("EIO trace inconsistency: missing memory breakpoint");
00788   ld_brk_point = (md_addr_t)brkrec->as_integer.val;
00789 
00790   /* write integer register outputs */
00791   for (i=MD_FIRST_OUT_REG, regrec=exo_outregs->as_list.head->next;
00792        i <= MD_LAST_OUT_REG; i++, regrec=regrec->next)
00793     {
00794       if (!regrec || regrec->ec != ec_address)
00795         fatal("EIO trace inconsistency: missing output reg");
00796 
00797       MD_EXO_TO_IREG(regrec, regs, i);
00798 
00799 #ifdef VERBOSE
00800       fprintf(stderr, "** R[%d] written...\n", i);
00801 #endif /* VERBOSE */
00802     }
00803   if (regrec != NULL)
00804     fatal("EIO trace inconsistency: too many output regs");
00805 
00806   /* write memory outputs */
00807   for (memrec=exo_outmem->as_list.head; memrec != NULL; memrec=memrec->next)
00808     {
00809       md_addr_t loc;
00810       struct exo_term_t *addr, *blob;
00811 
00812       /* check the mem transaction format */
00813       if (!memrec
00814           || memrec->ec != ec_list
00815           || !(addr = memrec->as_list.head)
00816           || addr->ec != ec_address
00817           || !(blob = addr->next)
00818           || blob->ec != ec_blob
00819           || blob->next != NULL)
00820         fatal("EIO trace icnonsistency: bad memory transaction");
00821 
00822       for (loc=addr->as_integer.val, i=0; i < blob->as_blob.size; loc++,i++)
00823         {
00824           /* was: MEM_WRITE_BYTE(loc, blob->as_blob.data[i]); */
00825           (*mem_fn)(mem, Write,
00826                     loc, &blob->as_blob.data[i], sizeof(unsigned char));
00827 
00828 #ifdef VERBOSE
00829           fprintf(stderr, "** 0x%08p written...\n", loc);
00830 #endif /* VERBOSE */
00831         }
00832     }
00833 
00834   /* release the EIO EXO node */
00835   exo_delete(exo);
00836 }
00837 
00838 /* fast forward EIO trace EIO_FD to the transaction just after ICNT */
00839 void
00840 eio_fast_forward(FILE *eio_fd, counter_t icnt)
00841 {
00842   struct exo_term_t *exo, *exo_icnt;
00843 
00844   do
00845     {
00846       /* read the next external I/O (EIO) transaction */
00847       exo = exo_read(eio_fd);
00848 
00849       if (!exo)
00850         fatal("could not fast forward to EIO checkpoint");
00851 
00852       /* one more transaction processed */
00853       eio_trans_icnt = icnt;
00854 
00855       /* pull apart the EIO transaction (EXO format) */
00856       if (!exo
00857           || exo->ec != ec_list
00858           || !(exo_icnt = exo->as_list.head)
00859           || exo_icnt->ec != ec_integer)
00860         fatal("cannot read EIO transaction (during fast forward)");
00861     }
00862   while ((counter_t)exo_icnt->as_integer.val != icnt);
00863 
00864   /* found it! */
00865 }


UVa CS Department of Computer Science
School of Engineering, University of Virginia
151 Engineer's Way, P.O. Box 400740
Charlottesville, Virginia 22904-4740

(434) 982-2200  Fax: (434) 982-2214