home *** CD-ROM | disk | FTP | other *** search
/ Mac Mania 2 / MacMania 2.toast / Demo's / Tools&Utilities / Programming / SPIM Folder / Sources / data.c next >
Encoding:
C/C++ Source or Header  |  1993-01-18  |  6.6 KB  |  295 lines  |  [TEXT/ttxt]

  1. /* SPIM S20 MIPS simulator.
  2.    Code to manipulate data segment directives.
  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/data.c,v 1.3 1992/10/12 11:33:35 cs354 Exp $
  23. */
  24.  
  25.  
  26. #include <stdio.h>
  27. #include "spim.h"
  28. #include "inst.h"
  29. #include "mem.h"
  30. #include "reg.h"
  31. #include "sym_tbl.h"
  32. #include "data.h"
  33.  
  34. /* Imported functions: */
  35.  
  36. void fix_current_label_address (mem_addr);
  37.  
  38.  
  39. /* The first 64K of the data segment are dedicated to small data
  40.    segment, which is pointed to by $gp. This register points to the
  41.    middle of the segment, so we can use the full offset field in an
  42.    instruction. */
  43.  
  44. static mem_addr next_data_pc;    /* Location for next datum in user process */
  45.  
  46. static mem_addr next_k_data_pc;    /* Location for next datum in kernel */
  47.  
  48. static int in_kernel = 0;    /* Non-zero => data goes to kdata, not data */
  49.  
  50. #define DATA_PC (in_kernel ? next_k_data_pc : next_data_pc)
  51.  
  52. #define BUMP_DATA_PC(DELTA) {if (in_kernel) \
  53.                 next_k_data_pc += DELTA; \
  54.                 else {next_data_pc += DELTA; \
  55.                       program_break = next_data_pc;}}
  56.  
  57. static int next_gp_offset;    /* Offset off $gp of next data item */
  58.  
  59. static int auto_alignment = 1;    /* Non-zero => align literal to natural bound*/
  60.  
  61.  
  62. /* Imported variables: */
  63.  
  64. extern int program_break;
  65.  
  66.  
  67.  
  68. /* If TO_KERNEL is non-zero, subsequent data will be placed in the
  69.    kernel data segment.  If it is zero, data will go to the user's data
  70.    segment.*/
  71.  
  72. void user_kernel_data_segment (int to_kernel)
  73. {
  74.     in_kernel = to_kernel;
  75. }
  76.  
  77.  
  78. /* Set the point at which the first datum is stored to be ADDRESS +
  79.    64K.     The 64K increment allocates an area pointed to by register
  80.    $gp, which is initialized. */
  81.  
  82. void data_begins_at_point (mem_addr addr)
  83. {
  84.   if (bare_machine)
  85.     next_data_pc = addr;
  86.   else
  87.     {
  88.       next_gp_offset = addr;
  89.       gp_midpoint = addr + 32*K;
  90.       R[REG_GP] = gp_midpoint;
  91.       next_data_pc = addr + 64 * K;
  92.     }
  93. }
  94.  
  95.  
  96. /* Set the point at which the first datum is stored in the kernel's
  97.    data segment. */
  98.  
  99. void k_data_begins_at_point (mem_addr addr)
  100. {
  101.     next_k_data_pc = addr;
  102. }
  103.  
  104.  
  105. /* Arrange that the next datum is stored on a memory boundary with its
  106.    low ALIGNMENT bits equal to 0.  If argument is 0, disable automatic
  107.    alignment.*/
  108.  
  109. void align_data (int alignment)
  110. {
  111.   if (alignment == 0)
  112.     auto_alignment = 0;
  113.   else if (in_kernel)
  114.     {
  115.       next_k_data_pc =
  116.     (next_k_data_pc + (1 << alignment) - 1) & (-1 << alignment);
  117.       fix_current_label_address (next_k_data_pc);
  118.     }
  119.   else
  120.     {
  121.       next_data_pc = (next_data_pc + (1 << alignment) - 1) & (-1 << alignment);
  122.       fix_current_label_address (next_data_pc);
  123.     }
  124. }
  125.  
  126.  
  127. void enable_data_alignment (void)
  128. {
  129.   auto_alignment = 1;
  130. }
  131.  
  132.  
  133. /* Return the address at which the next datum will be stored.  */
  134.  
  135. mem_addr current_data_pc (void)
  136. {
  137.   return (DATA_PC);
  138. }
  139.  
  140.  
  141. /* Bump the address at which the next data will be stored by VALUE
  142.    bytes. */
  143.  
  144. void increment_data_pc (int value)
  145. {
  146.   BUMP_DATA_PC (value);
  147. }
  148.  
  149.  
  150. /* Process a .extern NAME SIZE directive. */
  151.  
  152. void extern_directive (char *name, int size)
  153. {
  154.   label *sym = make_label_global (name);
  155.  
  156.   if (!bare_machine
  157.       && size > 0 && size <= SMALL_DATA_SEG_MAX_SIZE
  158.       && next_gp_offset + size < gp_midpoint + 32*K)
  159.     {
  160.       sym->gp_flag = 1;
  161.       sym->addr = next_gp_offset;
  162.       next_gp_offset += size;
  163.     }
  164. }
  165.  
  166.  
  167. /* Process a .lcomm NAME SIZE directive. */
  168.  
  169. void lcomm_directive (char *name, int size)
  170. {
  171.   label *sym = lookup_label (name);
  172.  
  173.   if (!bare_machine
  174.       && size > 0 && size <= SMALL_DATA_SEG_MAX_SIZE
  175.       && next_gp_offset + size < gp_midpoint + 32*K)
  176.     {
  177.       sym->gp_flag = 1;
  178.       sym->addr = next_gp_offset;
  179.       next_gp_offset += size;
  180.     }
  181.   /* Don't need to initialize since memory starts with 0's */
  182. }
  183.  
  184.  
  185. /* Process a .ascii STRING or .asciiz STRING directive. */
  186.  
  187. void store_string (char *string, int length, int null_terminate)
  188. {
  189.   for ( ; length > 0; string ++, length --) {
  190.     SET_MEM_BYTE (DATA_PC, *string);
  191.     BUMP_DATA_PC(1);
  192.   }
  193.   if (null_terminate)
  194.     {
  195.       SET_MEM_BYTE (DATA_PC, 0);
  196.       BUMP_DATA_PC(1);
  197.     }
  198. }
  199.  
  200.  
  201. /* Process a .byte EXPR directive. */
  202.  
  203. void store_byte (int value)
  204. {
  205.   SET_MEM_BYTE (DATA_PC, value);
  206.   BUMP_DATA_PC (1);
  207. }
  208.  
  209.  
  210. /* Process a .half EXPR directive. */
  211.  
  212. void store_half (int value)
  213. {
  214.   if (auto_alignment) align_data (1);
  215.   if (DATA_PC & 0x1)
  216.     {
  217. #ifdef BIGENDIAN
  218.       store_byte ((value >> 8) & 0xff);
  219.       store_byte (value & 0xff);
  220. #else
  221.       store_byte (value & 0xff);
  222.       store_byte ((value >> 8) & 0xff);
  223. #endif
  224.     }
  225.   else
  226.     {
  227.       SET_MEM_HALF (DATA_PC, value);
  228.       BUMP_DATA_PC (BYTES_PER_WORD / 2);
  229.     }
  230. }
  231.  
  232.  
  233. /* Process a .word EXPR directive. */
  234.  
  235. void store_word (int value)
  236. {
  237.   if (auto_alignment) align_data (2);
  238.   if (DATA_PC & 0x3)
  239.     {
  240. #ifdef BIGENDIAN
  241.       store_half ((value >> 16) & 0xffff);
  242.       store_half (value & 0xffff);
  243. #else
  244.       store_half ((short) (value & 0xffff));
  245.       store_half ((short) ((value >> 16) & 0xffff));
  246. #endif
  247.     }
  248.   else
  249.     {
  250.       SET_MEM_WORD (DATA_PC, value);
  251.       BUMP_DATA_PC (BYTES_PER_WORD);
  252.     }
  253. }
  254.  
  255.  
  256. /* Process a .double EXPR directive. */
  257.  
  258. void store_double (double *value)
  259. {
  260.   if (auto_alignment) align_data (3);
  261.   if (DATA_PC & 0x7)
  262.     {
  263.       store_word (* ((long *) value));
  264.       store_word (* (((long *) value) + 1));
  265.     }
  266.   else
  267.     {
  268.       SET_MEM_WORD (DATA_PC, * ((long *) value));
  269.       BUMP_DATA_PC (BYTES_PER_WORD);
  270.       SET_MEM_WORD (DATA_PC, * (((long *) value) + 1));
  271.       BUMP_DATA_PC (BYTES_PER_WORD);
  272.     }
  273. }
  274.  
  275.  
  276. /* Process a .float EXPR directive. */
  277.  
  278. void store_float (double *value)
  279. {
  280.   float val = *value;
  281.   float *vp = &val;
  282.  
  283.   if (auto_alignment) align_data (2);
  284.   if (DATA_PC & 0x3)
  285.     {
  286.       store_half ((*(long *) vp & 0xffff));
  287.       store_half (((*(long *) vp >> 16) & 0xffff));
  288.     }
  289.   else
  290.     {
  291.       SET_MEM_WORD (DATA_PC, *((long *) vp));
  292.       BUMP_DATA_PC (BYTES_PER_WORD);
  293.     }
  294. }
  295.