"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  

memory.c

Go to the documentation of this file.
00001 /*
00002  * memory.c - flat memory space routines
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) 1994, 1995, 1996, 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: memory.c,v 1.1.1.1 2000/05/26 15:18:58 taustin Exp $
00053  *
00054  * $Log: memory.c,v $
00055  * Revision 1.1.1.1  2000/05/26 15:18:58  taustin
00056  * SimpleScalar Tool Set
00057  *
00058  *
00059  * Revision 1.8  1999/12/31 18:38:19  taustin
00060  * cross-endian execution support added
00061  * quad_t naming conflicts removed
00062  *
00063  * Revision 1.7  1999/12/13 18:40:18  taustin
00064  * block copies now byte length (more portable across targets)
00065  *
00066  * Revision 1.6  1998/08/27 15:38:28  taustin
00067  * implemented host interface description in host.h
00068  * added target interface support
00069  * memory module updated to support 64/32 bit address spaces on 64/32
00070  *       bit machines, now implemented with a dynamically optimized hashed
00071  *       page table
00072  * added support for qword's
00073  * added fault support
00074  *
00075  * Revision 1.5  1997/03/11  01:15:25  taustin
00076  * updated copyright
00077  * mem_valid() added, indicates if an address is bogus, used by DLite!
00078  * long/int tweaks made for ALPHA target support
00079  *
00080  * Revision 1.4  1997/01/06  16:00:51  taustin
00081  * stat_reg calls now do not initialize stat variable values
00082  *
00083  * Revision 1.3  1996/12/27  15:52:46  taustin
00084  * updated comments
00085  * integrated support for options and stats packages
00086  *
00087  * Revision 1.1  1996/12/05  18:52:32  taustin
00088  * Initial revision
00089  *
00090  *
00091  */
00092 
00093 #include <stdio.h>
00094 #include <stdlib.h>
00095 
00096 #include "host.h"
00097 #include "misc.h"
00098 #include "machine.h"
00099 #include "options.h"
00100 #include "stats.h"
00101 #include "memory.h"
00102 
00103 
00104 /* create a flat memory space */
00105 struct mem_t *
00106 mem_create(char *name)                  /* name of the memory space */
00107 {
00108   struct mem_t *mem;
00109 
00110   mem = calloc(1, sizeof(struct mem_t));
00111   if (!mem)
00112     fatal("out of virtual memory");
00113 
00114   mem->name = mystrdup(name);
00115   return mem;
00116 }
00117 
00118 /* translate address ADDR in memory space MEM, returns pointer to host page */
00119 byte_t *
00120 mem_translate(struct mem_t *mem,        /* memory space to access */
00121               md_addr_t addr)           /* virtual address to translate */
00122 {
00123   struct mem_pte_t *pte, *prev;
00124 
00125   /* got here via a first level miss in the page tables */
00126   mem->ptab_misses++; mem->ptab_accesses++;
00127 
00128   /* locate accessed PTE */
00129   for (prev=NULL, pte=mem->ptab[MEM_PTAB_SET(addr)];
00130        pte != NULL;
00131        prev=pte, pte=pte->next)
00132     {
00133       if (pte->tag == MEM_PTAB_TAG(addr))
00134         {
00135           /* move this PTE to head of the bucket list */
00136           if (prev)
00137             {
00138               prev->next = pte->next;
00139               pte->next = mem->ptab[MEM_PTAB_SET(addr)];
00140               mem->ptab[MEM_PTAB_SET(addr)] = pte;
00141             }
00142           return pte->page;
00143         }
00144     }
00145 
00146   /* no translation found, return NULL */
00147   return NULL;
00148 }
00149 
00150 /* allocate a memory page */
00151 void
00152 mem_newpage(struct mem_t *mem,          /* memory space to allocate in */
00153             md_addr_t addr)             /* virtual address to allocate */
00154 {
00155   byte_t *page;
00156   struct mem_pte_t *pte;
00157 
00158   /* see misc.c for details on the getcore() function */
00159   page = getcore(MD_PAGE_SIZE);
00160   if (!page)
00161     fatal("out of virtual memory");
00162 
00163   /* generate a new PTE */
00164   pte = calloc(1, sizeof(struct mem_pte_t));
00165   if (!pte)
00166     fatal("out of virtual memory");
00167   pte->tag = MEM_PTAB_TAG(addr);
00168   pte->page = page;
00169 
00170   /* insert PTE into inverted hash table */
00171   pte->next = mem->ptab[MEM_PTAB_SET(addr)];
00172   mem->ptab[MEM_PTAB_SET(addr)] = pte;
00173 
00174   /* one more page allocated */
00175   mem->page_count++;
00176 }
00177 
00178 /* generic memory access function, it's safe because alignments and permissions
00179    are checked, handles any natural transfer sizes; note, faults out if nbytes
00180    is not a power-of-two or larger then MD_PAGE_SIZE */
00181 enum md_fault_type
00182 mem_access(struct mem_t *mem,           /* memory space to access */
00183            enum mem_cmd cmd,            /* Read (from sim mem) or Write */
00184            md_addr_t addr,              /* target address to access */
00185            void *vp,                    /* host memory address to access */
00186            int nbytes)                  /* number of bytes to access */
00187 {
00188   byte_t *p = vp;
00189 
00190   /* check alignments */
00191   if (/* check size */(nbytes & (nbytes-1)) != 0
00192       || /* check max size */nbytes > MD_PAGE_SIZE)
00193     return md_fault_access;
00194 
00195   if (/* check natural alignment */(addr & (nbytes-1)) != 0)
00196     return md_fault_alignment;
00197 
00198   /* perform the copy */
00199   {
00200     if (cmd == Read)
00201       {
00202         while (nbytes-- > 0)
00203           {
00204             *((byte_t *)p) = MEM_READ_BYTE(mem, addr);
00205             p += sizeof(byte_t);
00206             addr += sizeof(byte_t);
00207           }
00208       }
00209     else
00210       {
00211         while (nbytes-- > 0)
00212           {
00213             MEM_WRITE_BYTE(mem, addr, *((byte_t *)p));
00214             p += sizeof(byte_t);
00215             addr += sizeof(byte_t);
00216           }
00217       }
00218   }
00219 
00220 #if 0
00221   switch (nbytes)
00222     {
00223     case 1:
00224       if (cmd == Read)
00225         *((byte_t *)p) = MEM_READ_BYTE(mem, addr);
00226       else
00227         MEM_WRITE_BYTE(mem, addr, *((byte_t *)p));
00228       break;
00229 
00230     case 2:
00231       if (cmd == Read)
00232         *((half_t *)p) = MEM_READ_HALF(mem, addr);
00233       else
00234         MEM_WRITE_HALF(mem, addr, *((half_t *)p));
00235       break;
00236 
00237     case 4:
00238       if (cmd == Read)
00239         *((word_t *)p) = MEM_READ_WORD(mem, addr);
00240       else
00241         MEM_WRITE_WORD(mem, addr, *((word_t *)p));
00242       break;
00243 
00244 #ifdef HOST_HAS_QWORD
00245     case 8:
00246       if (cmd == Read)
00247         *((qword_t *)p) = MEM_READ_QWORD(mem, addr);
00248       else
00249         MEM_WRITE_QWORD(mem, addr, *((qword_t *)p));
00250       break;
00251 #endif /* HOST_HAS_QWORD */
00252 
00253     default:
00254       break;
00255     }
00256 #endif
00257 
00258   /* no fault... */
00259   return md_fault_none;
00260 }
00261 
00262 /* register memory system-specific statistics */
00263 void
00264 mem_reg_stats(struct mem_t *mem,        /* memory space to declare */
00265               struct stat_sdb_t *sdb)   /* stats data base */
00266 {
00267   char buf[512], buf1[512];
00268 
00269   sprintf(buf, "%s.page_count", mem->name);
00270   stat_reg_counter(sdb, buf, "total number of pages allocated",
00271                    &mem->page_count, mem->page_count, NULL);
00272 
00273   sprintf(buf, "%s.page_mem", mem->name);
00274   sprintf(buf1, "%s.page_count * %d / 1024", mem->name, MD_PAGE_SIZE);
00275   stat_reg_formula(sdb, buf, "total size of memory pages allocated",
00276                    buf1, "%11.0fk");
00277 
00278   sprintf(buf, "%s.ptab_misses", mem->name);
00279   stat_reg_counter(sdb, buf, "total first level page table misses",
00280                    &mem->ptab_misses, mem->ptab_misses, NULL);
00281 
00282   sprintf(buf, "%s.ptab_accesses", mem->name);
00283   stat_reg_counter(sdb, buf, "total page table accesses",
00284                    &mem->ptab_accesses, mem->ptab_accesses, NULL);
00285 
00286   sprintf(buf, "%s.ptab_miss_rate", mem->name);
00287   sprintf(buf1, "%s.ptab_misses / %s.ptab_accesses", mem->name, mem->name);
00288   stat_reg_formula(sdb, buf, "first level page table miss rate", buf1, NULL);
00289 }
00290 
00291 /* initialize memory system, call before loader.c */
00292 void
00293 mem_init(struct mem_t *mem)     /* memory space to initialize */
00294 {
00295   int i;
00296 
00297   /* initialize the first level page table to all empty */
00298   for (i=0; i < MEM_PTAB_SIZE; i++)
00299     mem->ptab[i] = NULL;
00300 
00301   mem->page_count = 0;
00302   mem->ptab_misses = 0;
00303   mem->ptab_accesses = 0;
00304 }
00305 
00306 /* dump a block of memory, returns any faults encountered */
00307 enum md_fault_type
00308 mem_dump(struct mem_t *mem,             /* memory space to display */
00309          md_addr_t addr,                /* target address to dump */
00310          int len,                       /* number bytes to dump */
00311          FILE *stream)                  /* output stream */
00312 {
00313   int data;
00314   enum md_fault_type fault;
00315 
00316   if (!stream)
00317     stream = stderr;
00318 
00319   addr &= ~sizeof(word_t);
00320   len = (len + (sizeof(word_t) - 1)) & ~sizeof(word_t);
00321   while (len-- > 0)
00322     {
00323       fault = mem_access(mem, Read, addr, &data, sizeof(word_t));
00324       if (fault != md_fault_none)
00325         return fault;
00326 
00327       myfprintf(stream, "0x%08p: %08x\n", addr, data);
00328       addr += sizeof(word_t);
00329     }
00330 
00331   /* no faults... */
00332   return md_fault_none;
00333 }
00334 
00335 /* copy a '\0' terminated string to/from simulated memory space, returns
00336    the number of bytes copied, returns any fault encountered */
00337 enum md_fault_type
00338 mem_strcpy(mem_access_fn mem_fn,        /* user-specified memory accessor */
00339            struct mem_t *mem,           /* memory space to access */
00340            enum mem_cmd cmd,            /* Read (from sim mem) or Write */
00341            md_addr_t addr,              /* target address to access */
00342            char *s)
00343 {
00344   int n = 0;
00345   char c;
00346   enum md_fault_type fault;
00347 
00348   switch (cmd)
00349     {
00350     case Read:
00351       /* copy until string terminator ('\0') is encountered */
00352       do {
00353         fault = mem_fn(mem, Read, addr++, &c, 1);
00354         if (fault != md_fault_none)
00355           return fault;
00356         *s++ = c;
00357         n++;
00358       } while (c);
00359       break;
00360 
00361     case Write:
00362       /* copy until string terminator ('\0') is encountered */
00363       do {
00364         c = *s++;
00365         fault = mem_fn(mem, Write, addr++, &c, 1);
00366         if (fault != md_fault_none)
00367           return fault;
00368         n++;
00369       } while (c);
00370       break;
00371 
00372     default:
00373       return md_fault_internal;
00374   }
00375 
00376   /* no faults... */
00377   return md_fault_none;
00378 }
00379 
00380 /* copy NBYTES to/from simulated memory space, returns any faults */
00381 enum md_fault_type
00382 mem_bcopy(mem_access_fn mem_fn,         /* user-specified memory accessor */
00383           struct mem_t *mem,            /* memory space to access */
00384           enum mem_cmd cmd,             /* Read (from sim mem) or Write */
00385           md_addr_t addr,               /* target address to access */
00386           void *vp,                     /* host memory address to access */
00387           int nbytes)
00388 {
00389   byte_t *p = vp;
00390   enum md_fault_type fault;
00391 
00392   /* copy NBYTES bytes to/from simulator memory */
00393   while (nbytes-- > 0)
00394     {
00395       fault = mem_fn(mem, cmd, addr++, p++, 1);
00396       if (fault != md_fault_none)
00397         return fault;
00398     }
00399 
00400   /* no faults... */
00401   return md_fault_none;
00402 }
00403 
00404 /* copy NBYTES to/from simulated memory space, NBYTES must be a multiple
00405    of 4 bytes, this function is faster than mem_bcopy(), returns any
00406    faults encountered */
00407 enum md_fault_type
00408 mem_bcopy4(mem_access_fn mem_fn,        /* user-specified memory accessor */
00409            struct mem_t *mem,           /* memory space to access */
00410            enum mem_cmd cmd,            /* Read (from sim mem) or Write */
00411            md_addr_t addr,              /* target address to access */
00412            void *vp,                    /* host memory address to access */
00413            int nbytes)
00414 {
00415   byte_t *p = vp;
00416   int words = nbytes >> 2;              /* note: nbytes % 2 == 0 is assumed */
00417   enum md_fault_type fault;
00418 
00419   while (words-- > 0)
00420     {
00421       fault = mem_fn(mem, cmd, addr, p, sizeof(word_t));
00422       if (fault != md_fault_none)
00423         return fault;
00424 
00425       addr += sizeof(word_t);
00426       p += sizeof(word_t);
00427     }
00428 
00429   /* no faults... */
00430   return md_fault_none;
00431 }
00432 
00433 /* zero out NBYTES of simulated memory, returns any faults encountered */
00434 enum md_fault_type
00435 mem_bzero(mem_access_fn mem_fn,         /* user-specified memory accessor */
00436           struct mem_t *mem,            /* memory space to access */
00437           md_addr_t addr,               /* target address to access */
00438           int nbytes)
00439 {
00440   byte_t c = 0;
00441   enum md_fault_type fault;
00442 
00443   /* zero out NBYTES of simulator memory */
00444   while (nbytes-- > 0)
00445     {
00446       fault = mem_fn(mem, Write, addr++, &c, 1);
00447       if (fault != md_fault_none)
00448         return fault;
00449     }
00450 
00451   /* no faults... */
00452   return md_fault_none;
00453 }
00454 
00455 
00456 
00457 
00458 
00459 
00460 
00461 
00462 
00463 #if 0
00464 
00465 /*
00466  * The SimpleScalar virtual memory address space is 2^31 bytes mapped from
00467  * 0x00000000 to 0x7fffffff.  The upper 2^31 bytes are currently reserved for
00468  * future developments.  The address space from 0x00000000 to 0x00400000 is
00469  * currently unused.  The address space from 0x00400000 to 0x10000000 is used
00470  * to map the program text (code), although accessing any memory outside of
00471  * the defined program space causes an error to be declared.  The address
00472  * space from 0x10000000 to "mem_brk_point" is used for the program data
00473  * segment.  This section of the address space is initially set to contain the
00474  * initialized data segment and then the uninitialized data segment.
00475  * "mem_brk_point" then grows to higher memory when sbrk() is called to
00476  * service heap growth.  The data segment can continue to expand until it
00477  * collides with the stack segment.  The stack segment starts at 0x7fffc000
00478  * and grows to lower memory as more stack space is allocated.  Initially,
00479  * the stack contains program arguments and environment variables (see
00480  * loader.c for details on initial stack layout).  The stack may continue to
00481  * expand to lower memory until it collides with the data segment.
00482  *
00483  * The SimpleScalar virtual memory address space is implemented with a
00484  * one level page table, where the first level table contains MEM_TABLE_SIZE
00485  * pointers to MEM_BLOCK_SIZE byte pages in the second level table.  Pages
00486  * are allocated in MEM_BLOCK_SIZE size chunks when first accessed, the initial
00487  * value of page memory is all zero.
00488  *
00489  * Graphically, it all looks like this:
00490  *
00491  *                 Virtual        Level 1    Host Memory Pages
00492  *                 Address        Page       (allocated as needed)
00493  *                 Space          Table
00494  * 0x00000000    +----------+      +-+      +-------------------+
00495  *               | unused   |      | |----->| memory page (64k) |
00496  * 0x00400000    +----------+      +-+      +-------------------+
00497  *               |          |      | |
00498  *               | text     |      +-+
00499  *               |          |      | |
00500  * 0x10000000    +----------+      +-+
00501  *               |          |      | |
00502  *               | data seg |      +-+      +-------------------+
00503  *               |          |      | |----->| memory page (64k) |
00504  * mem_brk_point +----------+      +-+      +-------------------+
00505  *               |          |      | |
00506  *               |          |      +-+
00507  *               |          |      | |
00508  * regs_R[29]    +----------+      +-+
00509  * (stack ptr)   |          |      | |
00510  *               | stack    |      +-+
00511  *               |          |      | |
00512  * 0x7fffc000    +----------+      +-+      +-------------------+
00513  *               | unsed    |      | |----->| memory page (64k) |
00514  * 0x7fffffff    +----------+      +-+      +-------------------+
00515 
00516  */
00517 
00518 /* top of the data segment, sbrk() moves this to higher memory */
00519 extern SS_ADDR_TYPE mem_brk_point;
00520 
00521 /* lowest address accessed on the stack */
00522 extern SS_ADDR_TYPE mem_stack_min;
00523 
00524 /*
00525  * memory page table defs
00526  */
00527 
00528 /* memory indirect table size (upper mem is not used) */
00529 #define MEM_TABLE_SIZE          0x8000 /* was: 0x7fff */
00530 
00531 #ifndef HIDE_MEM_TABLE_DEF      /* used by sim-fast.c */
00532 /* the level 1 page table map */
00533 extern char *mem_table[MEM_TABLE_SIZE];
00534 #endif /* HIDE_MEM_TABLE_DEF */
00535 
00536 /* memory block size, in bytes */
00537 #define MEM_BLOCK_SIZE          0x10000
00538 
00539   /* check permissions, no probes allowed into undefined segment regions */
00540   if (!(/* text access and a read */
00541         (addr >= ld_text_base && addr < (ld_text_base+ld_text_size)
00542          && cmd == Read)
00543         /* data access within bounds */
00544         || (addr >= ld_data_base && addr < ld_stack_base)))
00545     fatal("access error: segmentation violation, addr 0x%08p", addr);
00546 
00547   /* track the minimum SP for memory access stats */
00548   if (addr > mem_brk_point && addr < mem_stack_min)
00549     mem_stack_min = addr;
00550 
00551 /* determines if the memory access is valid, returns error str or NULL */
00552 char *                                  /* error string, or NULL */
00553 mem_valid(struct mem_t *mem,            /* memory space to probe */
00554           enum mem_cmd cmd,             /* Read (from sim'ed mem) or Write */
00555           md_addr_t addr,               /* target address to access */
00556           int nbytes,                   /* number of bytes to access */
00557           int declare);                 /* declare any detected error? */
00558 
00559 /* determines if the memory access is valid, returns error str or NULL */
00560 char *                                  /* error string, or NULL */
00561 mem_valid(enum mem_cmd cmd,             /* Read (from sim mem) or Write */
00562           SS_ADDR_TYPE addr,            /* target address to access */
00563           int nbytes,                   /* number of bytes to access */
00564           int declare)                  /* declare the error if detected? */
00565 {
00566   char *err_str = NULL;
00567 
00568   /* check alignments */
00569   if ((nbytes & (nbytes-1)) != 0 || (addr & (nbytes-1)) != 0)
00570     {
00571       err_str = "bad size or alignment";
00572     }
00573   /* check permissions, no probes allowed into undefined segment regions */
00574   else if (!(/* text access and a read */
00575            (addr >= ld_text_base && addr < (ld_text_base+ld_text_size)
00576             && cmd == Read)
00577            /* data access within bounds */
00578            || (addr >= ld_data_base && addr < ld_stack_base)))
00579     {
00580       err_str = "segmentation violation";
00581     }
00582 
00583   /* track the minimum SP for memory access stats */
00584   if (addr > mem_brk_point && addr < mem_stack_min)
00585     mem_stack_min = addr;
00586 
00587   if (!declare)
00588     return err_str;
00589   else if (err_str != NULL)
00590     fatal(err_str);
00591   else /* no error */
00592     return NULL;
00593 }
00594 
00595 /* initialize memory system, call after loader.c */
00596 void
00597 mem_init1(void)
00598 {
00599 
00600   /* initialize the bottom of heap to top of data segment */
00601   mem_brk_point = ROUND_UP(ld_data_base + ld_data_size, SS_PAGE_SIZE);
00602 
00603   /* set initial minimum stack pointer value to initial stack value */
00604   mem_stack_min = regs_R[SS_STACK_REGNO];
00605 }
00606 
00607 #endif


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