home *** CD-ROM | disk | FTP | other *** search
- /* SPIM S20 MIPS simulator.
- Code to manipulate data segment directives.
- Copyright (C) 1990 by James Larus (larus@cs.wisc.edu).
-
- SPIM is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 1, or (at your option) any
- later version.
-
- SPIM is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNU CC; see the file COPYING. If not, write to James R.
- Larus, Computer Sciences Department, University of Wisconsin--Madison,
- 1210 West Dayton Street, Madison, WI 53706, USA or to the Free
- Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-
- /* $Header: /var/home/cs354/.spim/RCS/data.c,v 1.3 1992/10/12 11:33:35 cs354 Exp $
- */
-
-
- #include <stdio.h>
- #include "spim.h"
- #include "inst.h"
- #include "mem.h"
- #include "reg.h"
- #include "sym_tbl.h"
- #include "data.h"
-
- /* Imported functions: */
-
- void fix_current_label_address (mem_addr);
-
-
- /* The first 64K of the data segment are dedicated to small data
- segment, which is pointed to by $gp. This register points to the
- middle of the segment, so we can use the full offset field in an
- instruction. */
-
- static mem_addr next_data_pc; /* Location for next datum in user process */
-
- static mem_addr next_k_data_pc; /* Location for next datum in kernel */
-
- static int in_kernel = 0; /* Non-zero => data goes to kdata, not data */
-
- #define DATA_PC (in_kernel ? next_k_data_pc : next_data_pc)
-
- #define BUMP_DATA_PC(DELTA) {if (in_kernel) \
- next_k_data_pc += DELTA; \
- else {next_data_pc += DELTA; \
- program_break = next_data_pc;}}
-
- static int next_gp_offset; /* Offset off $gp of next data item */
-
- static int auto_alignment = 1; /* Non-zero => align literal to natural bound*/
-
-
- /* Imported variables: */
-
- extern int program_break;
-
-
-
- /* If TO_KERNEL is non-zero, subsequent data will be placed in the
- kernel data segment. If it is zero, data will go to the user's data
- segment.*/
-
- void user_kernel_data_segment (int to_kernel)
- {
- in_kernel = to_kernel;
- }
-
-
- /* Set the point at which the first datum is stored to be ADDRESS +
- 64K. The 64K increment allocates an area pointed to by register
- $gp, which is initialized. */
-
- void data_begins_at_point (mem_addr addr)
- {
- if (bare_machine)
- next_data_pc = addr;
- else
- {
- next_gp_offset = addr;
- gp_midpoint = addr + 32*K;
- R[REG_GP] = gp_midpoint;
- next_data_pc = addr + 64 * K;
- }
- }
-
-
- /* Set the point at which the first datum is stored in the kernel's
- data segment. */
-
- void k_data_begins_at_point (mem_addr addr)
- {
- next_k_data_pc = addr;
- }
-
-
- /* Arrange that the next datum is stored on a memory boundary with its
- low ALIGNMENT bits equal to 0. If argument is 0, disable automatic
- alignment.*/
-
- void align_data (int alignment)
- {
- if (alignment == 0)
- auto_alignment = 0;
- else if (in_kernel)
- {
- next_k_data_pc =
- (next_k_data_pc + (1 << alignment) - 1) & (-1 << alignment);
- fix_current_label_address (next_k_data_pc);
- }
- else
- {
- next_data_pc = (next_data_pc + (1 << alignment) - 1) & (-1 << alignment);
- fix_current_label_address (next_data_pc);
- }
- }
-
-
- void enable_data_alignment (void)
- {
- auto_alignment = 1;
- }
-
-
- /* Return the address at which the next datum will be stored. */
-
- mem_addr current_data_pc (void)
- {
- return (DATA_PC);
- }
-
-
- /* Bump the address at which the next data will be stored by VALUE
- bytes. */
-
- void increment_data_pc (int value)
- {
- BUMP_DATA_PC (value);
- }
-
-
- /* Process a .extern NAME SIZE directive. */
-
- void extern_directive (char *name, int size)
- {
- label *sym = make_label_global (name);
-
- if (!bare_machine
- && size > 0 && size <= SMALL_DATA_SEG_MAX_SIZE
- && next_gp_offset + size < gp_midpoint + 32*K)
- {
- sym->gp_flag = 1;
- sym->addr = next_gp_offset;
- next_gp_offset += size;
- }
- }
-
-
- /* Process a .lcomm NAME SIZE directive. */
-
- void lcomm_directive (char *name, int size)
- {
- label *sym = lookup_label (name);
-
- if (!bare_machine
- && size > 0 && size <= SMALL_DATA_SEG_MAX_SIZE
- && next_gp_offset + size < gp_midpoint + 32*K)
- {
- sym->gp_flag = 1;
- sym->addr = next_gp_offset;
- next_gp_offset += size;
- }
- /* Don't need to initialize since memory starts with 0's */
- }
-
-
- /* Process a .ascii STRING or .asciiz STRING directive. */
-
- void store_string (char *string, int length, int null_terminate)
- {
- for ( ; length > 0; string ++, length --) {
- SET_MEM_BYTE (DATA_PC, *string);
- BUMP_DATA_PC(1);
- }
- if (null_terminate)
- {
- SET_MEM_BYTE (DATA_PC, 0);
- BUMP_DATA_PC(1);
- }
- }
-
-
- /* Process a .byte EXPR directive. */
-
- void store_byte (int value)
- {
- SET_MEM_BYTE (DATA_PC, value);
- BUMP_DATA_PC (1);
- }
-
-
- /* Process a .half EXPR directive. */
-
- void store_half (int value)
- {
- if (auto_alignment) align_data (1);
- if (DATA_PC & 0x1)
- {
- #ifdef BIGENDIAN
- store_byte ((value >> 8) & 0xff);
- store_byte (value & 0xff);
- #else
- store_byte (value & 0xff);
- store_byte ((value >> 8) & 0xff);
- #endif
- }
- else
- {
- SET_MEM_HALF (DATA_PC, value);
- BUMP_DATA_PC (BYTES_PER_WORD / 2);
- }
- }
-
-
- /* Process a .word EXPR directive. */
-
- void store_word (int value)
- {
- if (auto_alignment) align_data (2);
- if (DATA_PC & 0x3)
- {
- #ifdef BIGENDIAN
- store_half ((value >> 16) & 0xffff);
- store_half (value & 0xffff);
- #else
- store_half ((short) (value & 0xffff));
- store_half ((short) ((value >> 16) & 0xffff));
- #endif
- }
- else
- {
- SET_MEM_WORD (DATA_PC, value);
- BUMP_DATA_PC (BYTES_PER_WORD);
- }
- }
-
-
- /* Process a .double EXPR directive. */
-
- void store_double (double *value)
- {
- if (auto_alignment) align_data (3);
- if (DATA_PC & 0x7)
- {
- store_word (* ((long *) value));
- store_word (* (((long *) value) + 1));
- }
- else
- {
- SET_MEM_WORD (DATA_PC, * ((long *) value));
- BUMP_DATA_PC (BYTES_PER_WORD);
- SET_MEM_WORD (DATA_PC, * (((long *) value) + 1));
- BUMP_DATA_PC (BYTES_PER_WORD);
- }
- }
-
-
- /* Process a .float EXPR directive. */
-
- void store_float (double *value)
- {
- float val = *value;
- float *vp = &val;
-
- if (auto_alignment) align_data (2);
- if (DATA_PC & 0x3)
- {
- store_half ((*(long *) vp & 0xffff));
- store_half (((*(long *) vp >> 16) & 0xffff));
- }
- else
- {
- SET_MEM_WORD (DATA_PC, *((long *) vp));
- BUMP_DATA_PC (BYTES_PER_WORD);
- }
- }
-