/* 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: /home/aa/projects/spim/public_html/cvsroot/spimsal/data.c,v 1.1.1.1 1999/08/21 19:31:25 brg Exp $ */ #include #include "endian.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*/ /* Local variables: */ 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) { if (IS_BIG_ENDIAN) { store_byte ((value >> 8) & 0xff); store_byte (value & 0xff); } else { store_byte (value & 0xff); store_byte ((value >> 8) & 0xff); } } 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) { if (IS_BIG_ENDIAN) { store_half ((value >> 16) & 0xffff); store_half (value & 0xffff); } else { store_half ((short) (value & 0xffff)); store_half ((short) ((value >> 16) & 0xffff)); } } 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 ((short) (*(long *) vp & 0xffff)); store_half ((short) ((*(long *) vp >> 16) & 0xffff)); } else { SET_MEM_WORD (DATA_PC, *((long *) vp)); BUMP_DATA_PC (BYTES_PER_WORD); } }