/* SPIM S20 MIPS simulator. Macros for accessing memory. 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. A note on directions: "Bottom" of memory is the direction of decreasing addresses. "Top" is the direction of increasing addresses. Memio hooks added by Scott Kempf (scottk@cs.wisc.edu). $Header: /home/aa/projects/spim/public_html/cvsroot/spimsal/mem.h,v 1.2 1999/08/21 19:57:55 brg Exp $ */ /* Type of contents of a memory word. */ typedef long mem_word; /* The text segment and boundaries. */ instruction **text_seg; int text_modified; /* Non-zero means text segment was written */ #define TEXT_BOT ((mem_addr) 0x400000) mem_addr text_top; /* Amount to grow text segment when we run out of space for instructions. */ #define TEXT_CHUNK_SIZE 4096 /* The data segment and boundaries. */ mem_word *data_seg; int data_modified; /* Non-zero means a data segment was written */ short *data_seg_h; /* Points to same vector as DATA_SEG */ #ifdef ibm032 #define BYTE_TYPE signed char #else #define BYTE_TYPE char #endif BYTE_TYPE *data_seg_b; /* Ditto */ #define DATA_BOT ((mem_addr) 0x10000000) mem_addr data_top; mem_addr gp_midpoint; /* Middle of $gp area */ /* The stack segment and boundaries. */ mem_word *stack_seg; short *stack_seg_h; /* Points to same vector as STACK_SEG */ BYTE_TYPE *stack_seg_b; /* Ditto */ mem_addr stack_bot; /* Exclusive, but include 4K at top of stack. */ #define STACK_TOP ((mem_addr) 0x80000000) /* The kernel text segment and boundaries. */ instruction **k_text_seg; #define K_TEXT_BOT ((mem_addr) 0x80000000) mem_addr k_text_top; /* Kernel data segment and boundaries. */ mem_word *k_data_seg; short *k_data_seg_h; BYTE_TYPE *k_data_seg_b; #define K_DATA_BOT ((mem_addr) 0x90000000) mem_addr k_data_top; /* The non-cached memory mapped i/o area */ #define IO_BOT ((mem_addr) 0xffff0000) #define IO_TOP ((mem_addr) 0xffff0024) instruction *funny_text_read (); void funny_text_write (); mem_word bad_mem_read (); void bad_mem_write (); /* Include definitions for handle_IO_read and handle_IO_write */ #include "memio.h" /* You would think that a compiler could perform CSE on the arguments to these macros. However, complex expressions break some compilers, so do the CSE ourselves. */ /* Translate from SPIM memory address to physical address */ /* MEM_ADDRESS is _currently_ only used for reading and writing strings */ #define MEM_ADDRESS(ADDR) \ (((mem_addr) (ADDR) >= TEXT_BOT && (mem_addr) (ADDR) < text_top) \ ? (mem_addr) (ADDR) - TEXT_BOT + (mem_addr) text_seg \ : (((mem_addr) (ADDR) >= DATA_BOT && (mem_addr) (ADDR) < data_top) \ ? (mem_addr) (ADDR) - DATA_BOT + (mem_addr) data_seg \ : (((mem_addr) (ADDR) >= stack_bot && (mem_addr) (ADDR) < STACK_TOP) \ ? (mem_addr) (ADDR) - stack_bot + (mem_addr) stack_seg \ : ((mem_addr) (ADDR) >= K_TEXT_BOT && (mem_addr) (ADDR) < k_text_top)\ ? (mem_addr) (ADDR) - K_TEXT_BOT + (mem_addr) k_text_seg \ : (((mem_addr) (ADDR) >= K_DATA_BOT && (mem_addr) (ADDR) < k_data_top)\ ? (mem_addr) (ADDR) - K_DATA_BOT + (mem_addr) k_data_seg \ : run_error ("Memory address out of bounds\n"))))) #define READ_MEM_INST(LOC, ADDR) \ {register mem_addr _addr_ = (mem_addr) (ADDR); \ if (_addr_ >= TEXT_BOT && _addr_ < text_top && !(_addr_ & 0x3)) \ LOC = text_seg [(_addr_ - TEXT_BOT) >> 2]; \ else if (_addr_ >= K_TEXT_BOT && _addr_ < k_text_top && !(_addr_ & 0x3))\ LOC = k_text_seg [(_addr_ - K_TEXT_BOT) >> 2]; \ else LOC = funny_text_read (_addr_);} #define READ_MEM_BYTE(LOC, ADDR) \ {register mem_addr _addr_ = (mem_addr) (ADDR); \ if (_addr_ >= DATA_BOT && _addr_ < data_top) \ LOC = data_seg_b [_addr_ - DATA_BOT]; \ else if (_addr_ >= stack_bot && _addr_ < STACK_TOP) \ LOC = stack_seg_b [_addr_ - stack_bot]; \ else if (_addr_ >= K_DATA_BOT && _addr_ < k_data_top) \ LOC = k_data_seg_b [_addr_ - K_DATA_BOT]; \ else if ((_addr_ >= IO_BOT && _addr_ < IO_TOP) && memio) \ handle_IO_read(_addr_, &LOC, 1); \ else \ LOC = bad_mem_read (_addr_, 0, &LOC);} #define READ_MEM_HALF(LOC, ADDR) \ {register mem_addr _addr_ = (mem_addr) (ADDR); \ if (_addr_ >= DATA_BOT && _addr_ < data_top && !(_addr_ & 0x1)) \ LOC = data_seg_h [(_addr_ - DATA_BOT) >> 1]; \ else if (_addr_ >= stack_bot && _addr_ < STACK_TOP && !(_addr_ & 0x1)) \ LOC = stack_seg_h [(_addr_ - stack_bot) >> 1]; \ else if (_addr_ >= K_DATA_BOT && _addr_ < k_data_top && !(_addr_ & 0x1))\ LOC = k_data_seg_h [(_addr_ - K_DATA_BOT) >> 1]; \ else if (_addr_ >= IO_BOT && _addr_ < IO_TOP && !(_addr_ & 0x1) && memio)\ handle_IO_read(_addr_, &LOC, 2); \ else \ LOC = bad_mem_read (_addr_, 0x1, &LOC);} #define READ_MEM_WORD(LOC, ADDR) \ {register mem_addr _addr_ = (mem_addr) (ADDR); \ if (_addr_ >= DATA_BOT && _addr_ < data_top && !(_addr_ & 0x3)) \ LOC = data_seg [(_addr_ - DATA_BOT) >> 2]; \ else if (_addr_ >= stack_bot && _addr_ < STACK_TOP && !(_addr_ & 0x3)) \ LOC = stack_seg [(_addr_ - stack_bot) >> 2]; \ else if (_addr_ >= K_DATA_BOT && _addr_ < k_data_top && !(_addr_ & 0x3))\ LOC = k_data_seg [(_addr_ - K_DATA_BOT) >> 2]; \ else if (_addr_ >= IO_BOT && _addr_ < IO_TOP && !(_addr_ & 0x3) && memio)\ handle_IO_read(_addr_, &LOC, 4); \ else \ LOC = bad_mem_read (_addr_, 0x3, &LOC);} #define SET_MEM_INST(ADDR, INST) \ {register mem_addr _addr_ = (mem_addr) (ADDR); \ text_modified = 1; \ if (_addr_ >= TEXT_BOT && _addr_ < text_top && !(_addr_ & 0x3)) \ text_seg [(_addr_ - TEXT_BOT) >> 2] = INST; \ else if (_addr_ >= K_TEXT_BOT && _addr_ < k_text_top && !(_addr_ & 0x3))\ k_text_seg [(_addr_ - K_TEXT_BOT) >> 2] = INST; \ else funny_text_write (_addr_, INST);} #define SET_MEM_BYTE(ADDR, VALUE) \ {register mem_addr _addr_ = (mem_addr) (ADDR); \ data_modified = 1; \ if (_addr_ >= DATA_BOT && _addr_ < data_top) \ data_seg_b [_addr_ - DATA_BOT] = (unsigned char) (VALUE); \ else if (_addr_ >= stack_bot && _addr_ < STACK_TOP) \ stack_seg_b [_addr_ - stack_bot] = (unsigned char) (VALUE); \ else if (_addr_ >= K_DATA_BOT && _addr_ < k_data_top) \ k_data_seg_b [_addr_ - K_DATA_BOT] = (unsigned char) (VALUE); \ else if (_addr_ >= IO_BOT && _addr_ < IO_TOP && memio) \ handle_IO_write(_addr_, VALUE, 2); \ else bad_mem_write (_addr_, VALUE, 0);} #define SET_MEM_HALF(ADDR, VALUE) \ {register mem_addr _addr_ = (mem_addr) (ADDR); \ data_modified = 1; \ if (_addr_ >= DATA_BOT && _addr_ < data_top && !(_addr_ & 0x1)) \ data_seg_h [(_addr_ - DATA_BOT) >> 1] = (unsigned short) (VALUE); \ else if (_addr_ >= stack_bot && _addr_ < STACK_TOP && !(_addr_ & 0x1)) \ stack_seg_h [(_addr_ - stack_bot) >> 1] = (unsigned short) (VALUE); \ else if (_addr_ >= K_DATA_BOT && _addr_ < k_data_top && !(_addr_ & 0x1))\ k_data_seg_h [(_addr_ - K_DATA_BOT) >> 1] = (unsigned short) (VALUE); \ else if (_addr_ >= IO_BOT && _addr_ < IO_TOP && !(_addr_ & 0x1) && memio)\ handle_IO_write(_addr_, VALUE, 1); \ else bad_mem_write (_addr_, VALUE, 0x1);} #define SET_MEM_WORD(ADDR, VALUE) \ {register mem_addr _addr_ = (mem_addr) (ADDR); \ data_modified = 1; \ if (_addr_ >= DATA_BOT && _addr_ < data_top && !(_addr_ & 0x3)) \ data_seg [(_addr_ - DATA_BOT) >> 2] = (mem_word) (VALUE); \ else if (_addr_ >= stack_bot && _addr_ < STACK_TOP && !(_addr_ & 0x3)) \ stack_seg [(_addr_ - stack_bot) >> 2] = (mem_word) (VALUE); \ else if (_addr_ >= K_DATA_BOT && _addr_ < k_data_top && !(_addr_ & 0x3))\ k_data_seg [(_addr_ - K_DATA_BOT) >> 2] = (mem_word) (VALUE); \ else if (_addr_ >= IO_BOT && _addr_ < IO_TOP && !(_addr_ & 0x3) && memio)\ handle_IO_write(_addr_, VALUE, 4); \ else bad_mem_write (_addr_, VALUE, 0x3);} extern void make_memory(long text_size,long data_size,long data_limit, long stack_size,long stack_limit,long k_text_size,long k_data_size, long k_data_limit); extern void expand_data(long addl_bytes); extern void expand_stack(long addl_bytes); extern void expand_k_data(long addl_bytes); extern instruction *funny_text_read(mem_addr addr); extern void funny_text_write(mem_addr addr, instruction *inst); extern mem_word bad_mem_read(mem_addr addr,int mask,mem_word *dest); extern void bad_mem_write(mem_addr addr,mem_word value,int mask); extern void print_mem(mem_addr addr);