home *** CD-ROM | disk | FTP | other *** search
/ Mac Mania 2 / MacMania 2.toast / Demo's / Tools&Utilities / Programming / SPIM Folder / Sources / mem.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-02-09  |  11.4 KB  |  392 lines  |  [TEXT/ttxt]

  1. /* SPIM S20 MIPS simulator.
  2.    Code to create, maintain and access memory.
  3.    Copyright (C) 1990 by James Larus (larus@cs.wisc.edu).
  4.  
  5.    SPIM is free software; you can redistribute it and/or modify it
  6.    under the terms of the GNU General Public License as published by the
  7.    Free Software Foundation; either version 1, or (at your option) any
  8.    later version.
  9.  
  10.    SPIM is distributed in the hope that it will be useful, but WITHOUT
  11.    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12.    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13.    for more details.
  14.  
  15.    You should have received a copy of the GNU General Public License
  16.    along with GNU CC; see the file COPYING.  If not, write to James R.
  17.    Larus, Computer Sciences Department, University of Wisconsin--Madison,
  18.    1210 West Dayton Street, Madison, WI 53706, USA or to the Free
  19.    Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  20.  
  21.  
  22. /* $Header: /var/home/cs354/.spim/RCS/mem.c,v 1.4 1992/10/12 11:34:05 cs354 Exp $
  23. */
  24.  
  25.  
  26. #include <stdio.h>
  27. #include "spim.h"
  28. #include "inst.h"
  29. #define MEM_MAIN
  30. #include "mem.h"
  31. #define REG_MAIN
  32. #include "reg.h"
  33.  
  34.  
  35. /* Local functions: */
  36.  
  37. static    void free_instructions(instruction **inst ,int n);
  38.  
  39.  
  40. /* Local variables: */
  41.  
  42. static long data_size_limit, stack_size_limit, k_data_size_limit;
  43.  
  44.  
  45.  
  46. /* Memory is allocated in five chunks:
  47.     text, data, stack, kernel text, and kernel data.
  48.  
  49.    The arrays are independent and have different semantics.
  50.  
  51.    text is allocated from 0x400000 up and only contains INSTRUCTIONs.
  52.    It does not expand.
  53.  
  54.    data is allocated from 0x10000000 up.  It can be extended by the
  55.    SBRK system call.  Programs can only read and write this segment.
  56.  
  57.    stack grows from 0x7fffefff down.  It is automatically extended.
  58.    Programs can only read and write this segment.
  59.  
  60.    k_text is like text, except its is allocated from 0x80000000 up.
  61.  
  62.    k_data is like data, but is allocated from 0x90000000 up.
  63.  
  64.    Both kernel text and kernel data can only be accessed in kernel mode.
  65. */
  66.  
  67. #ifdef MACINTOSH
  68.  
  69. /* Here are the memory and register access functions that are macros in the non-Mac
  70.    versions of SPIM.
  71. */
  72.  
  73. mem_addr MEM_ADDRESS(mem_addr addr)
  74. {
  75.   if ( (addr >= TEXT_BOT) && (addr < text_top) )
  76.     return addr - TEXT_BOT + (mem_addr) text_seg;
  77.   if ( (addr >= DATA_BOT) && (addr < data_top) )
  78.     return addr - DATA_BOT + (mem_addr) data_seg;
  79.   if ( (addr >= stack_bot) && (addr < STACK_TOP) )
  80.     return addr - stack_bot + (mem_addr) stack_seg;
  81.   if ( (addr >= K_TEXT_BOT) && (addr < k_text_top) )
  82.     return addr - K_TEXT_BOT + (mem_addr) k_text_seg;
  83.   if ( (addr >= K_DATA_BOT) && (addr < k_data_top) )
  84.     return addr - K_DATA_BOT + (mem_addr) k_data_seg;
  85.   run_error("Memory address out of bounds\n");
  86. } /* MEM_ADDRESS */
  87.  
  88. #endif
  89.  
  90.  
  91. void make_memory (long text_size, long data_size, long data_limit,
  92.     long stack_size, long stack_limit, long k_text_size, long k_data_size, 
  93.     long k_data_limit)
  94. {
  95.   if (data_size <= 65536)
  96.     fatal_error ("Data segment must be larger than 64K\n");
  97.   if (text_seg == NULL)
  98.     text_seg = (instruction **)
  99.       malloc (sizeof (instruction *) * text_size / BYTES_PER_WORD);
  100.   else
  101.     free_instructions (text_seg, (text_top - TEXT_BOT) / BYTES_PER_WORD);
  102.   if (text_seg == NULL)
  103.     fatal_error ("malloc failed in make_memory\n");
  104.   bzero (text_seg, sizeof (instruction *) * text_size / BYTES_PER_WORD);
  105.   text_top = TEXT_BOT + text_size;
  106.  
  107.   if (data_seg == NULL)
  108.     data_seg =
  109.       (mem_word *) malloc (sizeof (mem_word) * data_size / BYTES_PER_WORD);
  110.   if (data_seg == NULL)
  111.     fatal_error ("malloc failed in make_memory\n");
  112.   bzero (data_seg, sizeof (instruction *) * data_size / BYTES_PER_WORD);
  113.   data_seg_b = (BYTE_TYPE *) data_seg;
  114.   data_seg_h = (short *) data_seg;
  115.   data_top = DATA_BOT + data_size;
  116.   data_size_limit = data_limit;
  117.  
  118.   if (stack_seg == NULL)
  119.     stack_seg =
  120.       (mem_word *) malloc (sizeof (mem_word) * stack_size / BYTES_PER_WORD);
  121.   if (stack_seg == NULL)
  122.     fatal_error ("malloc failed in make_memory\n");
  123.   bzero (stack_seg, sizeof (instruction *) * stack_size / BYTES_PER_WORD);
  124.   stack_seg_b = (BYTE_TYPE *) stack_seg;
  125.   stack_seg_h = (short *) stack_seg;
  126.   stack_bot = STACK_TOP - stack_size;
  127.   stack_size_limit = stack_limit;
  128.  
  129.   if (k_text_seg == NULL)
  130.     k_text_seg = (instruction **)
  131.       malloc (sizeof (instruction *) * k_text_size / BYTES_PER_WORD);
  132.   else
  133.     free_instructions (k_text_seg, (k_text_top - K_TEXT_BOT) / BYTES_PER_WORD);
  134.   if (k_text_seg == NULL)
  135.     fatal_error ("malloc failed in make_memory\n");
  136.   bzero (k_text_seg, sizeof (instruction *) * k_text_size / BYTES_PER_WORD);
  137.   k_text_top = K_TEXT_BOT + k_text_size;
  138.  
  139.   if (k_data_seg == NULL)
  140.     k_data_seg =
  141.       (mem_word *) malloc (sizeof (mem_word) * k_data_size / BYTES_PER_WORD);
  142.   if (k_data_seg == NULL)
  143.     fatal_error ("malloc failed in make_memory\n");
  144.   bzero (k_data_seg, sizeof (instruction *) * k_data_size / BYTES_PER_WORD);
  145.   k_data_seg_b = (BYTE_TYPE *) k_data_seg;
  146.   k_data_seg_h = (short *) k_data_seg;
  147.   k_data_top = K_DATA_BOT + k_data_size;
  148.   k_data_size_limit = k_data_limit;
  149.  
  150.   text_modified = 0;
  151.   data_modified = 0;
  152. }
  153.  
  154.  
  155. /* Free the storage used by the old instructions in memory. */
  156.  
  157. static void free_instructions (register instruction **inst, int n)
  158. {
  159.   for ( ; n > 0; n --, inst ++)
  160.     if (*inst)
  161.       {
  162.     if (EXPR (*inst))
  163.       free (EXPR (*inst));
  164.     free (*inst);
  165.       }
  166. }
  167.  
  168.  
  169. /* Expand the data segment by adding N bytes. */
  170.  
  171. void expand_data (long addl_bytes)
  172. {
  173.   long old_size = data_top - DATA_BOT;
  174.   long new_size = old_size + addl_bytes;
  175.   register mem_word *p;
  176.  
  177. #ifdef MACINTOSH
  178.   error("You're not allowed to expand_data() on the Macintosh.\n");
  179. #endif
  180.  
  181.   if (addl_bytes < 0 || (source_file && new_size > data_size_limit))
  182.     {
  183.       sprintf(mess_buff,
  184.         "Can't expand data segment by %d bytes to %d bytes\n",
  185.         addl_bytes, new_size);
  186.       error (mess_buff);
  187.       sprintf(mess_buff, "Use -ldata # with # > %d\n", new_size);
  188.       run_error (mess_buff);
  189.     }
  190.   data_seg = (mem_word *) realloc (data_seg, new_size);
  191.   if (data_seg == NULL)
  192.     fatal_error ("realloc failed in expand_data\n");
  193.   data_seg_b = (BYTE_TYPE *) data_seg;
  194.   data_seg_h = (short *) data_seg;
  195.   for (p = data_seg + old_size / BYTES_PER_WORD;
  196.        p < data_seg + new_size / BYTES_PER_WORD; )
  197.     *p ++ = 0;
  198.   data_top += addl_bytes;
  199. }
  200.  
  201.  
  202. /* Expand the stack segment by adding N bytes.  Can't use REALLOC
  203.    since it copies from bottom of memory blocks and stack grows down from
  204.    top of its block. */
  205.  
  206. void expand_stack (long addl_bytes)
  207. {
  208.   long old_size = STACK_TOP - stack_bot;
  209.   long new_size = old_size + addl_bytes;
  210.   mem_word *new_seg;
  211.   register mem_word *po, *pn;
  212.  
  213. #ifdef MACINTOSH
  214.   error("You're not allowed to expand_stack() on the Macintosh.\n");
  215. #endif
  216.  
  217.   if (addl_bytes < 0 || (source_file && new_size > stack_size_limit))
  218.     {
  219.       sprintf(mess_buff,
  220.         "Can't expand stack segment by %d bytes to %d bytes\n",
  221.         addl_bytes, new_size);
  222.       error (mess_buff);
  223.       sprintf(mess_buff, "Use -lstack # with # > %d\n", new_size);
  224.       run_error (mess_buff);
  225.     }
  226.  
  227.   new_seg = (mem_word *) malloc (new_size);
  228.   if (new_seg == NULL)
  229.     fatal_error ("malloc failed in expand_stack\n");
  230.   po = stack_seg + old_size / BYTES_PER_WORD;
  231.   pn = new_seg + new_size / BYTES_PER_WORD;
  232.  
  233.   for ( ; po >= stack_seg ; ) *pn -- = *po --;
  234.   for ( ; pn >= new_seg ; ) *pn -- = 0;
  235.  
  236.   stack_seg = new_seg;
  237.   stack_seg_b = (BYTE_TYPE *) stack_seg;
  238.   stack_seg_h = (short *) stack_seg;
  239.   stack_bot -= addl_bytes;
  240. }
  241.  
  242.  
  243. /* Expand the kernel data segment by adding N bytes. */
  244.  
  245. void expand_k_data (long addl_bytes)
  246. {
  247.   long old_size = k_data_top - K_DATA_BOT;
  248.   long new_size = old_size + addl_bytes;
  249.   register mem_word *p;
  250.  
  251. #ifdef MACINTOSH
  252.   error("You're not allowed to expand_k_data() on the Macintosh.\n");
  253. #endif
  254.  
  255.   if (addl_bytes < 0 || (source_file && new_size > k_data_size_limit))
  256.     {
  257.       sprintf(mess_buff,
  258.         "Can't expand kernel data segment by %d bytes to %d bytes\n",
  259.         addl_bytes, new_size);
  260.       error (mess_buff);
  261.       sprintf(mess_buff, "Use -lkdata # with # > %d\n", new_size);
  262.       run_error (mess_buff);
  263.     }
  264.   k_data_seg = (mem_word *) realloc (k_data_seg, new_size);
  265.   if (k_data_seg == NULL)
  266.     fatal_error ("realloc failed in expand_k_data\n");
  267.   k_data_seg_b = (BYTE_TYPE *) k_data_seg;
  268.   k_data_seg_h = (short *) k_data_seg;
  269.   for (p = k_data_seg + old_size / BYTES_PER_WORD;
  270.        p < k_data_seg + new_size / BYTES_PER_WORD; )
  271.     *p ++ = 0;
  272.   k_data_top += addl_bytes;
  273. }
  274.  
  275.  
  276. instruction * funny_text_read (mem_addr addr)
  277. {
  278.   mem_word bits;
  279.  
  280.   READ_MEM_WORD (bits, addr);
  281.   return (inst_decode (bits));
  282. }
  283.  
  284.  
  285. void funny_text_write (mem_addr addr, instruction *inst)
  286. {
  287.   mem_word bits = inst_encode (inst);
  288.  
  289.   SET_MEM_WORD (addr, bits);
  290. }
  291.  
  292.  
  293. mem_word bad_mem_read (mem_addr addr, int mask, mem_word *dest)
  294. {
  295.   if (addr & mask)
  296.     RAISE_EXCEPTION (ADDRL_EXCPT, BadVAddr = addr)
  297.   else if (addr >= TEXT_BOT && addr < text_top)
  298.     {
  299.       if (mask != 0x3)
  300.     run_error ("SPIM restriction: Can only read text segment by words\n");
  301.       else
  302.     return (inst_encode (text_seg [(addr - TEXT_BOT) >> 2]));
  303.     }
  304.   else if (addr > data_top
  305.        && addr < stack_bot
  306.        /* If more than 16 MB below stack, probably is bad data ref */
  307.        && addr > stack_bot - 16*1000*K)
  308.     {
  309.       /* Grow stack segment */
  310.       expand_stack (stack_bot - addr + 4);
  311.       *dest = 0;                 /* Newly allocated memory */
  312.     }
  313.   else
  314.     /* Address out of range */
  315.     RAISE_EXCEPTION (DBUS_EXCPT, BadVAddr = addr)
  316.   return (0);
  317. }
  318.  
  319.  
  320. void bad_mem_write (mem_addr addr, mem_word value, int mask)
  321. {
  322.   if (addr & mask)
  323.     /* Unaligned address fault */
  324.     RAISE_EXCEPTION (ADDRS_EXCPT, BadVAddr = addr)
  325.   else if (addr >= TEXT_BOT && addr < text_top)
  326.     {
  327.       if (mask != 0x3)
  328.     run_error ("SPIM restriction: Can only write text segment by words\n");
  329.       else
  330.     text_seg [(addr - TEXT_BOT) >> 2] = inst_decode (value);
  331.     }
  332.   else if (addr > data_top
  333.        && addr < stack_bot
  334.        /* If more than 16 MB below stack, probably is bad data ref */
  335.        && addr > stack_bot - 16*1000*K)
  336.     {
  337.       /* Grow stack segment */
  338.       expand_stack (stack_bot - addr + 4);
  339.       if (addr >= stack_bot)
  340.     {
  341.       if (mask == 0)
  342.         stack_seg_b [addr - stack_bot] = value;
  343.       else if (mask == 1)
  344.         stack_seg_h [addr - stack_bot] = value;
  345.       else
  346.         stack_seg [addr - stack_bot] = value;
  347.     }
  348.       else
  349.     RAISE_EXCEPTION (DBUS_EXCPT, BadVAddr = addr)
  350.     }
  351.   else
  352.     /* Address out of range */
  353.     RAISE_EXCEPTION (DBUS_EXCPT, BadVAddr = addr)
  354. }
  355.  
  356.  
  357. void print_mem (mem_addr addr)
  358. {
  359.   long value;
  360.  
  361.   if (TEXT_BOT <= addr && addr < text_top)
  362.     print_inst (addr);
  363.   else if (DATA_BOT <= addr && addr < data_top)
  364.     {
  365.       READ_MEM_WORD (value, addr);
  366.       sprintf(mess_buff, "Data seg @ 0x%08x (%d) = 0x%08x (%d)\n",
  367.         addr, addr, value, value);
  368.       write_output (message_out, mess_buff);
  369.     }
  370.   else if (stack_bot <= addr && addr < STACK_TOP)
  371.     {
  372.       READ_MEM_WORD (value, addr);
  373.       sprintf(mess_buff, "Stack seg @ 0x%08x (%d) = 0x%08x (%d)\n",
  374.         addr, addr, value, value);
  375.       write_output (message_out, mess_buff);
  376.     }
  377.   else if (K_TEXT_BOT <= addr && addr < k_text_top)
  378.     print_inst (addr);
  379.   else if (K_DATA_BOT <= addr && addr < k_data_top)
  380.     {
  381.       READ_MEM_WORD (value, addr);
  382.       sprintf(mess_buff, "Kernel Data seg @ 0x%08x (%d) = 0x%08x (%d)\n",
  383.             addr, addr, value, value);
  384.       write_output (message_out, mess_buff);
  385.     }
  386.   else {
  387.     sprintf(mess_buff,
  388.     "Address 0x%08x (%d) to print_mem is out of bounds\n", addr, addr);
  389.     error (mess_buff);
  390.   }
  391. }
  392.