diff options
53 files changed, 2876 insertions, 489 deletions
diff --git a/SConscript b/SConscript index 8afac510b..3a141a7d2 100644 --- a/SConscript +++ b/SConscript @@ -81,67 +81,18 @@ base_sources = Split(''' base/stats/text.cc cpu/base.cc - cpu/base_dyn_inst.cc cpu/cpu_exec_context.cc cpu/exetrace.cc + cpu/op_class.cc cpu/pc_event.cc cpu/static_inst.cc cpu/sampler/sampler.cc - cpu/trace/reader/mem_trace_reader.cc - cpu/trace/reader/ibm_reader.cc - cpu/trace/reader/itx_reader.cc - cpu/trace/reader/m5_reader.cc - cpu/trace/opt_cpu.cc - cpu/trace/trace_cpu.cc - encumbered/mem/functional/main.cc - - mem/base_hier.cc - mem/base_mem.cc - mem/hier_params.cc - mem/mem_cmd.cc - mem/mem_debug.cc - mem/mem_req.cc - mem/memory_interface.cc - mem/bus/base_interface.cc - mem/bus/bus.cc - mem/bus/bus_bridge.cc - mem/bus/bus_bridge_master.cc - mem/bus/bus_bridge_slave.cc - mem/bus/bus_interface.cc - mem/bus/dma_bus_interface.cc - mem/bus/dma_interface.cc - mem/bus/master_interface.cc - mem/bus/slave_interface.cc - mem/cache/base_cache.cc - mem/cache/cache.cc - mem/cache/cache_builder.cc - mem/cache/coherence/coherence_protocol.cc - mem/cache/coherence/uni_coherence.cc - mem/cache/miss/blocking_buffer.cc - mem/cache/miss/miss_queue.cc - mem/cache/miss/mshr.cc - mem/cache/miss/mshr_queue.cc - mem/cache/prefetch/base_prefetcher.cc - mem/cache/prefetch/prefetcher.cc - mem/cache/prefetch/tagged_prefetcher.cc - mem/cache/tags/base_tags.cc - mem/cache/tags/cache_tags.cc - mem/cache/tags/fa_lru.cc - mem/cache/tags/iic.cc - mem/cache/tags/lru.cc - mem/cache/tags/repl/gen.cc - mem/cache/tags/repl/repl.cc - mem/cache/tags/split.cc - mem/cache/tags/split_lru.cc - mem/cache/tags/split_lifo.cc - mem/functional/functional.cc - mem/timing/base_memory.cc - mem/timing/memory_builder.cc - mem/timing/simple_mem_bank.cc - mem/trace/itx_writer.cc - mem/trace/mem_trace_writer.cc - mem/trace/m5_writer.cc + mem/memory.cc + mem/page_table.cc + mem/physical.cc + mem/port.cc + mem/translating_port.cc python/pyconfig.cc python/embedded_py.cc @@ -162,6 +113,7 @@ base_sources = Split(''' sim/startup.cc sim/stat_context.cc sim/stat_control.cc + sim/system.cc sim/trace_context.cc ''') @@ -204,6 +156,17 @@ full_cpu_sources = Split(''' encumbered/cpu/full/iq/standard/iq_standard.cc ''') +trace_reader_sources = Split(''' + cpu/trace/reader/mem_trace_reader.cc + cpu/trace/reader/ibm_reader.cc + cpu/trace/reader/itx_reader.cc + cpu/trace/reader/m5_reader.cc + cpu/trace/opt_cpu.cc + cpu/trace/trace_cpu.cc + ''') + + + # MySql sources mysql_sources = Split(''' base/mysql.cc @@ -260,9 +223,6 @@ full_system_sources = Split(''' kern/tru64/tru64_syscalls.cc mem/functional/memory_control.cc - mem/functional/physical.cc - - sim/system.cc sim/pseudo_inst.cc ''') @@ -288,8 +248,7 @@ turbolaser_sources = Split(''' # Syscall emulation (non-full-system) sources syscall_emulation_sources = Split(''' - cpu/memtest/memtest.cc - encumbered/eio/eio.cc + encumbered/eio/exolex.cc encumbered/eio/libexo.cc kern/linux/linux.cc @@ -298,6 +257,14 @@ syscall_emulation_sources = Split(''' sim/syscall_emul.cc ''') +eio_sources = Split(''' + encumbered/eio/eio.cc + ''') + +memtest_sources = Split(''' + cpu/memtest/memtest.cc + ''') + # Add a flag defining what THE_ISA should be for all compilation env.Append(CPPDEFINES=[('THE_ISA','%s_ISA' % env['TARGET_ISA'].upper())]) diff --git a/arch/alpha/isa/main.isa b/arch/alpha/isa/main.isa index 17c9989ab..d4c744fbc 100644 --- a/arch/alpha/isa/main.isa +++ b/arch/alpha/isa/main.isa @@ -34,7 +34,7 @@ output header {{ #include "config/ss_compatible_fp.hh" #include "cpu/static_inst.hh" #include "arch/alpha/faults.hh" -#include "mem/mem_req.hh" // some constructors use MemReq flags +#include "mem/request.hh" // some constructors use MemReq flags }}; output decoder {{ diff --git a/arch/alpha/linux/process.hh b/arch/alpha/linux/process.hh index 7de1b1ac1..2cabc3f76 100644 --- a/arch/alpha/linux/process.hh +++ b/arch/alpha/linux/process.hh @@ -39,6 +39,7 @@ class AlphaLinuxProcess : public LiveProcess /// Constructor. AlphaLinuxProcess(const std::string &name, ObjectFile *objFile, + System *system, int stdin_fd, int stdout_fd, int stderr_fd, std::vector<std::string> &argv, std::vector<std::string> &envp); diff --git a/arch/alpha/tru64/process.hh b/arch/alpha/tru64/process.hh index 051760702..84abd54bf 100644 --- a/arch/alpha/tru64/process.hh +++ b/arch/alpha/tru64/process.hh @@ -38,6 +38,7 @@ class AlphaTru64Process : public LiveProcess /// Constructor. AlphaTru64Process(const std::string &name, ObjectFile *objFile, + System *system, int stdin_fd, int stdout_fd, int stderr_fd, std::vector<std::string> &argv, std::vector<std::string> &envp); diff --git a/base/chunk_generator.hh b/base/chunk_generator.hh new file mode 100644 index 000000000..a584679d0 --- /dev/null +++ b/base/chunk_generator.hh @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __BASE__CHUNK_GENERATOR_HH__ +#define __BASE__CHUNK_GENERATOR_HH__ + +/** + * @file + * Declaration and inline definition of ChunkGenerator object. + */ + +#include <algorithm> +#include "base/intmath.hh" +#include "targetarch/isa_traits.hh" // for Addr + +/** + * This class takes an arbitrary memory region (address/length pair) + * and generates a series of appropriately (e.g. block- or page-) + * aligned chunks covering the same region. + * + * Example usage: + +\code + for (ChunkGenerator gen(addr, size, chunkSize); !gen.done(); gen.next()) { + doSomethingChunky(gen.addr(), gen.size()); + } +\endcode + */ +class ChunkGenerator +{ + private: + /** The starting address of the current chunk. */ + Addr curAddr; + /** The starting address of the next chunk (after the current one). */ + Addr nextAddr; + /** The size of the current chunk (in bytes). */ + int curSize; + /** The number of bytes remaining in the region after the current chunk. */ + int sizeLeft; + /** The maximum chunk size, e.g., the cache block size or page size. */ + const int chunkSize; + + public: + /** + * Constructor. + * @param startAddr The starting address of the region. + * @param totalSize The total size of the region. + * @param _chunkSize The size/alignment of chunks into which + * the region should be decomposed. + */ + ChunkGenerator(Addr startAddr, int totalSize, int _chunkSize) + : chunkSize(_chunkSize) + { + // chunkSize must be a power of two + assert(chunkSize == 0 || isPowerOf2(chunkSize)); + + // set up initial chunk. + curAddr = startAddr; + + if (chunkSize == 0) //Special Case, if we see 0, assume no chuncking + { + nextAddr = startAddr + totalSize; + } + else + { + // nextAddr should be *next* chunk start + nextAddr = roundUp(startAddr, chunkSize); + if (curAddr == nextAddr) { + // ... even if startAddr is already chunk-aligned + nextAddr += chunkSize; + } + } + + // how many bytes are left between curAddr and the end of this chunk? + int left_in_chunk = nextAddr - curAddr; + curSize = std::min(totalSize, left_in_chunk); + sizeLeft = totalSize - curSize; + } + + /** Return starting address of current chunk. */ + Addr addr() { return curAddr; } + /** Return size in bytes of current chunk. */ + int size() { return curSize; } + + /** + * Are we done? That is, did the last call to next() advance + * past the end of the region? + * @return True if yes, false if more to go. + */ + bool done() { return (curSize == 0); } + + /** + * Advance generator to next chunk. + * @return True if successful, false if unsuccessful + * (because we were at the last chunk). + */ + bool next() + { + if (sizeLeft == 0) { + curSize = 0; + return false; + } + + curAddr = nextAddr; + curSize = std::min(sizeLeft, chunkSize); + sizeLeft -= curSize; + nextAddr += curSize; + return true; + } +}; + +#endif // __BASE__CHUNK_GENERATOR_HH__ diff --git a/base/intmath.hh b/base/intmath.hh index df0687c62..51baddb91 100644 --- a/base/intmath.hh +++ b/base/intmath.hh @@ -186,9 +186,9 @@ roundUp(T val, int align) template <class T> inline T -roundDown(T val, T align) +roundDown(T val, int align) { - T mask = align - 1; + T mask = (T)align - 1; return val & ~mask; } diff --git a/base/loader/aout_object.cc b/base/loader/aout_object.cc index c81f7123f..564898ca3 100644 --- a/base/loader/aout_object.cc +++ b/base/loader/aout_object.cc @@ -30,7 +30,6 @@ #include "base/loader/aout_object.hh" -#include "mem/functional/functional.hh" #include "base/loader/symtab.hh" #include "base/trace.hh" // for DPRINTF @@ -64,12 +63,15 @@ AoutObject::AoutObject(const string &_filename, int _fd, text.baseAddr = N_TXTADDR(*execHdr); text.size = execHdr->tsize; + text.fileImage = fileData + N_TXTOFF(*execHdr); data.baseAddr = N_DATADDR(*execHdr); data.size = execHdr->dsize; + data.fileImage = fileData + N_DATOFF(*execHdr); bss.baseAddr = N_BSSADDR(*execHdr); bss.size = execHdr->bsize; + bss.fileImage = NULL; DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n", text.baseAddr, text.size, data.baseAddr, data.size, @@ -78,28 +80,6 @@ AoutObject::AoutObject(const string &_filename, int _fd, bool -AoutObject::loadSections(FunctionalMemory *mem, bool loadPhys) -{ - Addr textAddr = text.baseAddr; - Addr dataAddr = data.baseAddr; - - if (loadPhys) { - textAddr &= (ULL(1) << 40) - 1; - dataAddr &= (ULL(1) << 40) - 1; - } - - // Since we don't really have an MMU and all memory is - // zero-filled, there's no need to set up the BSS segment. - if (text.size != 0) - mem->prot_write(textAddr, fileData + N_TXTOFF(*execHdr), text.size); - if (data.size != 0) - mem->prot_write(dataAddr, fileData + N_DATOFF(*execHdr), data.size); - - return true; -} - - -bool AoutObject::loadGlobalSymbols(SymbolTable *symtab) { // a.out symbols not supported yet diff --git a/base/loader/aout_object.hh b/base/loader/aout_object.hh index 1868192b2..aeb710427 100644 --- a/base/loader/aout_object.hh +++ b/base/loader/aout_object.hh @@ -46,8 +46,6 @@ class AoutObject : public ObjectFile public: virtual ~AoutObject() {} - virtual bool loadSections(FunctionalMemory *mem, - bool loadPhys = false); virtual bool loadGlobalSymbols(SymbolTable *symtab); virtual bool loadLocalSymbols(SymbolTable *symtab); diff --git a/base/loader/ecoff_object.cc b/base/loader/ecoff_object.cc index 353a5f333..cd37abaa7 100644 --- a/base/loader/ecoff_object.cc +++ b/base/loader/ecoff_object.cc @@ -29,8 +29,6 @@ #include <string> #include "base/loader/ecoff_object.hh" - -#include "mem/functional/functional.hh" #include "base/loader/symtab.hh" #include "base/trace.hh" // for DPRINTF @@ -68,12 +66,15 @@ EcoffObject::EcoffObject(const string &_filename, int _fd, text.baseAddr = aoutHdr->text_start; text.size = aoutHdr->tsize; + text.fileImage = fileData + ECOFF_TXTOFF(execHdr); data.baseAddr = aoutHdr->data_start; data.size = aoutHdr->dsize; + data.fileImage = fileData + ECOFF_DATOFF(execHdr); bss.baseAddr = aoutHdr->bss_start; bss.size = aoutHdr->bsize; + bss.fileImage = NULL; DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n", text.baseAddr, text.size, data.baseAddr, data.size, @@ -82,26 +83,6 @@ EcoffObject::EcoffObject(const string &_filename, int _fd, bool -EcoffObject::loadSections(FunctionalMemory *mem, bool loadPhys) -{ - Addr textAddr = text.baseAddr; - Addr dataAddr = data.baseAddr; - - if (loadPhys) { - textAddr &= (ULL(1) << 40) - 1; - dataAddr &= (ULL(1) << 40) - 1; - } - - // Since we don't really have an MMU and all memory is - // zero-filled, there's no need to set up the BSS segment. - mem->prot_write(textAddr, fileData + ECOFF_TXTOFF(execHdr), text.size); - mem->prot_write(dataAddr, fileData + ECOFF_DATOFF(execHdr), data.size); - - return true; -} - - -bool EcoffObject::loadGlobalSymbols(SymbolTable *symtab) { if (!symtab) diff --git a/base/loader/ecoff_object.hh b/base/loader/ecoff_object.hh index 78aa7f3f7..603c70bec 100644 --- a/base/loader/ecoff_object.hh +++ b/base/loader/ecoff_object.hh @@ -50,8 +50,6 @@ class EcoffObject : public ObjectFile public: virtual ~EcoffObject() {} - virtual bool loadSections(FunctionalMemory *mem, - bool loadPhys = false); virtual bool loadGlobalSymbols(SymbolTable *symtab); virtual bool loadLocalSymbols(SymbolTable *symtab); diff --git a/base/loader/elf_object.cc b/base/loader/elf_object.cc index 791c6f6de..1136686f0 100644 --- a/base/loader/elf_object.cc +++ b/base/loader/elf_object.cc @@ -43,7 +43,6 @@ #include "base/loader/elf_object.hh" -#include "mem/functional/functional.hh" #include "base/loader/symtab.hh" #include "base/trace.hh" // for DPRINTF @@ -203,20 +202,19 @@ ElfObject::ElfObject(const string &_filename, int _fd, if (text.size == 0) { // haven't seen text segment yet text.baseAddr = phdr.p_vaddr; text.size = phdr.p_filesz; - // remember where the data is for loadSections() - fileTextBits = fileData + phdr.p_offset; + text.fileImage = fileData + phdr.p_offset; // if there's any padding at the end that's not in the // file, call it the bss. This happens in the "text" // segment if there's only one loadable segment (as for // kernel images). bss.size = phdr.p_memsz - phdr.p_filesz; bss.baseAddr = phdr.p_vaddr + phdr.p_filesz; + bss.fileImage = NULL; } else if (data.size == 0) { // have text, this must be data data.baseAddr = phdr.p_vaddr; data.size = phdr.p_filesz; - // remember where the data is for loadSections() - fileDataBits = fileData + phdr.p_offset; + data.fileImage = fileData + phdr.p_offset; // if there's any padding at the end that's not in the // file, call it the bss. Warn if this happens for both // the text & data segments (should only have one bss). @@ -225,6 +223,7 @@ ElfObject::ElfObject(const string &_filename, int _fd, } bss.size = phdr.p_memsz - phdr.p_filesz; bss.baseAddr = phdr.p_vaddr + phdr.p_filesz; + bss.fileImage = NULL; } } @@ -242,28 +241,6 @@ ElfObject::ElfObject(const string &_filename, int _fd, bool -ElfObject::loadSections(FunctionalMemory *mem, bool loadPhys) -{ - Addr textAddr = text.baseAddr; - Addr dataAddr = data.baseAddr; - - if (loadPhys) { - textAddr &= (ULL(1) << 40) - 1; - dataAddr &= (ULL(1) << 40) - 1; - } - - // Since we don't really have an MMU and all memory is - // zero-filled, there's no need to set up the BSS segment. - if (text.size != 0) - mem->prot_write(textAddr, fileTextBits, text.size); - if (data.size != 0) - mem->prot_write(dataAddr, fileDataBits, data.size); - - return true; -} - - -bool ElfObject::loadSomeSymbols(SymbolTable *symtab, int binding) { Elf *elf; diff --git a/base/loader/elf_object.hh b/base/loader/elf_object.hh index 66d8b3e63..72c265edd 100644 --- a/base/loader/elf_object.hh +++ b/base/loader/elf_object.hh @@ -35,9 +35,6 @@ class ElfObject : public ObjectFile { protected: - uint8_t *fileTextBits; //!< Pointer to file's text segment image - uint8_t *fileDataBits; //!< Pointer to file's data segment image - /// Helper functions for loadGlobalSymbols() and loadLocalSymbols(). bool loadSomeSymbols(SymbolTable *symtab, int binding); @@ -48,8 +45,6 @@ class ElfObject : public ObjectFile public: virtual ~ElfObject() {} - virtual bool loadSections(FunctionalMemory *mem, - bool loadPhys = false); virtual bool loadGlobalSymbols(SymbolTable *symtab); virtual bool loadLocalSymbols(SymbolTable *symtab); diff --git a/base/loader/object_file.cc b/base/loader/object_file.cc index 1410d05b8..f33957269 100644 --- a/base/loader/object_file.cc +++ b/base/loader/object_file.cc @@ -43,6 +43,8 @@ #include "base/loader/aout_object.hh" #include "base/loader/elf_object.hh" +#include "mem/translating_port.hh" + using namespace std; ObjectFile::ObjectFile(const string &_filename, int _fd, @@ -60,6 +62,38 @@ ObjectFile::~ObjectFile() } +bool +ObjectFile::loadSection(Section *sec, TranslatingPort *memPort, bool loadPhys) +{ + if (sec->size != 0) { + Addr addr = sec->baseAddr; + if (loadPhys) { + // this is Alpha-specific... going to have to fix this + // for other architectures + addr &= (ULL(1) << 40) - 1; + } + + if (sec->fileImage) { + memPort->writeBlobFunctional(addr, sec->fileImage, sec->size, true); + } + else { + // no image: must be bss + memPort->memsetBlobFunctional(addr, 0, sec->size, true); + } + } + return true; +} + + +bool +ObjectFile::loadSections(TranslatingPort *memPort, bool loadPhys) +{ + return (loadSection(&text, memPort, loadPhys) + && loadSection(&data, memPort, loadPhys) + && loadSection(&bss, memPort, loadPhys)); +} + + void ObjectFile::close() { diff --git a/base/loader/object_file.hh b/base/loader/object_file.hh index 1b44ae14f..08a51863e 100644 --- a/base/loader/object_file.hh +++ b/base/loader/object_file.hh @@ -33,7 +33,7 @@ #include "sim/host.hh" // for Addr -class FunctionalMemory; +class TranslatingPort; class SymbolTable; class ObjectFile @@ -72,8 +72,7 @@ class ObjectFile void close(); - virtual bool loadSections(FunctionalMemory *mem, - bool loadPhys = false) = 0; + virtual bool loadSections(TranslatingPort *memPort, bool loadPhys = false); virtual bool loadGlobalSymbols(SymbolTable *symtab) = 0; virtual bool loadLocalSymbols(SymbolTable *symtab) = 0; @@ -83,8 +82,9 @@ class ObjectFile protected: struct Section { - Addr baseAddr; - size_t size; + Addr baseAddr; + uint8_t *fileImage; + size_t size; }; Addr entry; @@ -94,6 +94,8 @@ class ObjectFile Section data; Section bss; + bool loadSection(Section *sec, TranslatingPort *memPort, bool loadPhys); + public: Addr entryPoint() const { return entry; } Addr globalPointer() const { return globalPtr; } diff --git a/configs/test.py b/configs/test.py new file mode 100644 index 000000000..ea0e63a61 --- /dev/null +++ b/configs/test.py @@ -0,0 +1,8 @@ +from m5 import * +AddToPath('/z/stever/bk/m5-test') +import Benchmarks + +mem = PhysicalMemory() +cpu = SimpleCPU(workload=Benchmarks.HelloWorld(), mem=mem) +system = System(physmem=mem, cpu=cpu) +root = Root(system=system) diff --git a/cpu/base.cc b/cpu/base.cc index 2eb5f7fd3..9ce458c64 100644 --- a/cpu/base.cc +++ b/cpu/base.cc @@ -65,7 +65,7 @@ BaseCPU::BaseCPU(Params *p) #else BaseCPU::BaseCPU(Params *p) : SimObject(p->name), clock(p->clock), params(p), - number_of_threads(p->numberOfThreads) + number_of_threads(p->numberOfThreads), system(p->system) #endif { DPRINTF(FullCPU, "BaseCPU: Creating object, mem address %#x.\n", this); @@ -229,6 +229,7 @@ BaseCPU::registerExecContexts() { for (int i = 0; i < execContexts.size(); ++i) { ExecContext *xc = execContexts[i]; + #if FULL_SYSTEM int id = params->cpu_id; if (id != -1) diff --git a/cpu/base.hh b/cpu/base.hh index d9d5d2b88..0866b49a7 100644 --- a/cpu/base.hh +++ b/cpu/base.hh @@ -38,13 +38,11 @@ #include "sim/sim_object.hh" #include "arch/isa_traits.hh" -#if FULL_SYSTEM class System; namespace Kernel { class Statistics; } -#endif - class BranchPred; class ExecContext; +class Port; class BaseCPU : public SimObject { @@ -123,8 +121,8 @@ class BaseCPU : public SimObject Tick clock; bool functionTrace; Tick functionTraceStart; -#if FULL_SYSTEM System *system; +#if FULL_SYSTEM int cpu_id; Tick profile; #endif @@ -173,9 +171,9 @@ class BaseCPU : public SimObject */ EventQueue **comLoadEventQueue; -#if FULL_SYSTEM System *system; +#if FULL_SYSTEM /** * Serialize this object to the given output stream. * @param os The stream to serialize to. diff --git a/cpu/cpu_exec_context.cc b/cpu/cpu_exec_context.cc index b7238e73a..6ef42762d 100644 --- a/cpu/cpu_exec_context.cc +++ b/cpu/cpu_exec_context.cc @@ -45,6 +45,7 @@ #include "arch/stacktrace.hh" #else #include "sim/process.hh" +#include "mem/translating_port.hh" #endif using namespace std; @@ -53,7 +54,7 @@ using namespace std; #if FULL_SYSTEM CPUExecContext::CPUExecContext(BaseCPU *_cpu, int _thread_num, System *_sys, AlphaITB *_itb, AlphaDTB *_dtb, - FunctionalMemory *_mem) + Memory *_mem) : _status(ExecContext::Unallocated), cpu(_cpu), thread_num(_thread_num), cpu_id(-1), lastActivate(0), lastSuspend(0), mem(_mem), itb(_itb), dtb(_dtb), system(_sys), memctrl(_sys->memctrl), physmem(_sys->physmem), @@ -79,21 +80,13 @@ CPUExecContext::CPUExecContext(BaseCPU *_cpu, int _thread_num, System *_sys, } #else CPUExecContext::CPUExecContext(BaseCPU *_cpu, int _thread_num, - Process *_process, int _asid) + Process *_process, int _asid, Port *mem_port) : _status(ExecContext::Unallocated), cpu(_cpu), thread_num(_thread_num), cpu_id(-1), lastActivate(0), - lastSuspend(0), process(_process), mem(process->getMemory()), asid(_asid), - func_exe_inst(0), storeCondFailures(0) -{ - memset(®s, 0, sizeof(RegFile)); - proxy = new ProxyExecContext<CPUExecContext>(this); -} - -CPUExecContext::CPUExecContext(BaseCPU *_cpu, int _thread_num, - FunctionalMemory *_mem, int _asid) - : cpu(_cpu), thread_num(_thread_num), process(0), mem(_mem), asid(_asid), + lastSuspend(0), process(_process), asid(_asid), func_exe_inst(0), storeCondFailures(0) { + port = new TranslatingPort(mem_port, process->pTable); memset(®s, 0, sizeof(RegFile)); proxy = new ProxyExecContext<CPUExecContext>(this); } @@ -158,7 +151,6 @@ void CPUExecContext::takeOverFrom(ExecContext *oldContext) { // some things should already be set up - assert(mem == oldContext->getMemPtr()); #if FULL_SYSTEM assert(system == oldContext->getSystemPtr()); #else diff --git a/cpu/cpu_exec_context.hh b/cpu/cpu_exec_context.hh index beaf67352..e17cfbb94 100644 --- a/cpu/cpu_exec_context.hh +++ b/cpu/cpu_exec_context.hh @@ -32,16 +32,13 @@ #include "arch/isa_traits.hh" #include "config/full_system.hh" #include "cpu/exec_context.hh" -#include "mem/functional/functional.hh" -#include "mem/mem_req.hh" +#include "mem/physical.hh" +#include "mem/request.hh" #include "sim/byteswap.hh" #include "sim/eventq.hh" #include "sim/host.hh" #include "sim/serialize.hh" -// forward declaration: see functional_memory.hh -class FunctionalMemory; -class PhysicalMemory; class BaseCPU; #if FULL_SYSTEM @@ -56,6 +53,7 @@ class MemoryController; #else // !FULL_SYSTEM #include "sim/process.hh" +class TranslatingPort; #endif // FULL_SYSTEM @@ -118,17 +116,21 @@ class CPUExecContext Tick lastActivate; Tick lastSuspend; + System *system; + + /// Port that syscalls can use to access memory (provides translation step). + TranslatingPort *port; +// Memory *mem; + #if FULL_SYSTEM - FunctionalMemory *mem; AlphaITB *itb; AlphaDTB *dtb; - System *system; // the following two fields are redundant, since we can always // look them up through the system pointer, but we'll leave them // here for now for convenience MemoryController *memctrl; - PhysicalMemory *physmem; +// PhysicalMemory *physmem; FunctionProfile *profile; ProfileNode *profileNode; @@ -164,8 +166,6 @@ class CPUExecContext #else Process *process; - FunctionalMemory *mem; // functional storage for process address space - // Address space ID. Note that this is used for TIMING cache // simulation only; all functional memory accesses should use // one of the FunctionalMemory pointers above. @@ -202,9 +202,7 @@ class CPUExecContext CPUExecContext(BaseCPU *_cpu, int _thread_num, System *_system, AlphaITB *_itb, AlphaDTB *_dtb, FunctionalMemory *_dem); #else - CPUExecContext(BaseCPU *_cpu, int _thread_num, Process *_process, int _asid); - CPUExecContext(BaseCPU *_cpu, int _thread_num, FunctionalMemory *_mem, - int _asid); + CPUExecContext(BaseCPU *_cpu, int _thread_num, Process *_process, int _asid, Port *mem_port); // Constructor to use XC to pass reg file around. Not used for anything // else. CPUExecContext(RegFile *regFile); @@ -238,17 +236,17 @@ class CPUExecContext int getInstAsid() { return regs.instAsid(); } int getDataAsid() { return regs.dataAsid(); } - Fault translateInstReq(MemReqPtr &req) + Fault translateInstReq(CpuRequestPtr &req) { return itb->translate(req); } - Fault translateDataReadReq(MemReqPtr &req) + Fault translateDataReadReq(CpuRequestPtr &req) { return dtb->translate(req, false); } - Fault translateDataWriteReq(MemReqPtr &req) + Fault translateDataWriteReq(CpuRequestPtr &req) { return dtb->translate(req, true); } @@ -265,34 +263,26 @@ class CPUExecContext int getInstAsid() { return asid; } int getDataAsid() { return asid; } - Fault dummyTranslation(MemReqPtr &req) + Fault translateInstReq(CpuRequestPtr &req) { -#if 0 - assert((req->vaddr >> 48 & 0xffff) == 0); -#endif - - // put the asid in the upper 16 bits of the paddr - req->paddr = req->vaddr & ~((Addr)0xffff << sizeof(Addr) * 8 - 16); - req->paddr = req->paddr | (Addr)req->asid << sizeof(Addr) * 8 - 16; - return NoFault; + return process->pTable->translate(req); } - Fault translateInstReq(MemReqPtr &req) - { - return dummyTranslation(req); - } - Fault translateDataReadReq(MemReqPtr &req) + + Fault translateDataReadReq(CpuRequestPtr &req) { - return dummyTranslation(req); + return process->pTable->translate(req); } - Fault translateDataWriteReq(MemReqPtr &req) + + Fault translateDataWriteReq(CpuRequestPtr &req) { - return dummyTranslation(req); + return process->pTable->translate(req); } #endif +/* template <class T> - Fault read(MemReqPtr &req, T &data) + Fault read(CpuRequestPtr &req, T &data) { #if FULL_SYSTEM && defined(TARGET_ALPHA) if (req->flags & LOCKED) { @@ -302,13 +292,13 @@ class CPUExecContext #endif Fault error; - error = mem->read(req, data); + error = mem->prot_read(req->paddr, data, req->size); data = LittleEndianGuest::gtoh(data); return error; } template <class T> - Fault write(MemReqPtr &req, T &data) + Fault write(CpuRequestPtr &req, T &data) { #if FULL_SYSTEM && defined(TARGET_ALPHA) ExecContext *xc; @@ -356,9 +346,9 @@ class CPUExecContext } #endif - return mem->write(req, (T)LittleEndianGuest::htog(data)); + return mem->prot_write(req->paddr, (T)htog(data), req->size); } - +*/ virtual bool misspeculating(); @@ -369,9 +359,11 @@ class CPUExecContext inst = new_inst; } - Fault instRead(MemReqPtr &req) + Fault instRead(CpuRequestPtr &req) { - return mem->read(req, inst); + panic("instRead not implemented"); + // return funcPhysMem->read(req, inst); + return No_Fault; } void setCpuId(int id) { cpu_id = id; } diff --git a/cpu/exetrace.cc b/cpu/exetrace.cc index 84b5eacf7..ebb719b2c 100644 --- a/cpu/exetrace.cc +++ b/cpu/exetrace.cc @@ -30,9 +30,6 @@ #include <iomanip> #include "sim/param.hh" -#include "encumbered/cpu/full/dyn_inst.hh" -#include "encumbered/cpu/full/spec_state.hh" -#include "encumbered/cpu/full/issue.hh" #include "cpu/exetrace.hh" #include "base/loader/symtab.hh" #include "cpu/base.hh" diff --git a/cpu/op_class.cc b/cpu/op_class.cc new file mode 100644 index 000000000..00136ded5 --- /dev/null +++ b/cpu/op_class.cc @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cpu/op_class.hh" + +/** OpClass enum -> description string */ +const char * +opClassStrings[Num_OpClasses] = +{ + "(null)", + "IntAlu", + "IntMult", + "IntDiv", + "FloatAdd", + "FloatCmp", + "FloatCvt", + "FloatMult", + "FloatDiv", + "FloatSqrt", + "MemRead", + "MemWrite", + "IprAccess", + "InstPrefetch" +}; + diff --git a/encumbered/cpu/full/op_class.hh b/cpu/op_class.hh index ff53b58d2..cdb40a0fb 100644 --- a/encumbered/cpu/full/op_class.hh +++ b/cpu/op_class.hh @@ -26,8 +26,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef __ENCUMBERED_CPU_FULL_OP_CLASS_HH__ -#define __ENCUMBERED_CPU_FULL_OP_CLASS_HH__ +#ifndef __CPU__OP_CLASS_HH__ +#define __CPU__OP_CLASS_HH__ /** * @file @@ -39,26 +39,26 @@ * assigning instructions to functional units. */ enum OpClass { - No_OpClass = 0, /* inst does not use a functional unit */ - IntAluOp, /* integer ALU */ - IntMultOp, /* integer multiplier */ - IntDivOp, /* integer divider */ - FloatAddOp, /* floating point adder/subtractor */ - FloatCmpOp, /* floating point comparator */ - FloatCvtOp, /* floating point<->integer converter */ - FloatMultOp, /* floating point multiplier */ - FloatDivOp, /* floating point divider */ - FloatSqrtOp, /* floating point square root */ - MemReadOp, /* memory read port */ - MemWriteOp, /* memory write port */ - IprAccessOp, /* Internal Processor Register read/write port */ - InstPrefetchOp, /* instruction prefetch port (on I-cache) */ - Num_OpClasses /* total functional unit classes */ + No_OpClass = 0, ///< Instruction does not use a functional unit + IntAluOp, ///< Integer ALU operaton (add/sub/logical) + IntMultOp, ///< Integer multiply + IntDivOp, ///< Integer divide + FloatAddOp, ///< Floating point add/subtract + FloatCmpOp, ///< Floating point comparison + FloatCvtOp, ///< Floating point<->integer conversion + FloatMultOp, ///< Floating point multiply + FloatDivOp, ///< Floating point divide + FloatSqrtOp, ///< Floating point square root + MemReadOp, ///< Memory read port + MemWriteOp, ///< Memory write port + IprAccessOp, ///< Internal Processor Register read/write port + InstPrefetchOp, ///< Instruction prefetch port (on I-cache) + Num_OpClasses ///< Total number of operation classes }; /** - * Array mapping OpClass enum values to strings. Defined in fu_pool.cc. + * Array mapping OpClass enum values to strings. Defined in op_class.cc. */ extern const char *opClassStrings[]; -#endif // __ENCUMBERED_CPU_FULL_OP_CLASS_HH__ +#endif // __CPU__OP_CLASS_HH__ diff --git a/cpu/pc_event.hh b/cpu/pc_event.hh index 7fa3902cc..585aba0f1 100644 --- a/cpu/pc_event.hh +++ b/cpu/pc_event.hh @@ -31,17 +31,12 @@ #include <vector> -#include "mem/mem_req.hh" - class ExecContext; class PCEventQueue; class PCEvent { protected: - static const Addr badpc = MemReq::inval_addr; - - protected: std::string description; PCEventQueue *queue; Addr evpc; diff --git a/cpu/simple/cpu.cc b/cpu/simple/cpu.cc index 8db72b77e..fc70df662 100644 --- a/cpu/simple/cpu.cc +++ b/cpu/simple/cpu.cc @@ -53,8 +53,6 @@ #include "cpu/smt.hh" #include "cpu/static_inst.hh" #include "kern/kernel_stats.hh" -#include "mem/base_mem.hh" -#include "mem/mem_interface.hh" #include "sim/byteswap.hh" #include "sim/builder.hh" #include "sim/debug.hh" @@ -72,7 +70,7 @@ #include "arch/stacktrace.hh" #include "arch/vtophys.hh" #else // !FULL_SYSTEM -#include "mem/functional/functional.hh" +#include "mem/memory.hh" #endif // FULL_SYSTEM using namespace std; @@ -116,43 +114,85 @@ SimpleCPU::TickEvent::description() } -SimpleCPU::CacheCompletionEvent::CacheCompletionEvent(SimpleCPU *_cpu) - : Event(&mainEventQueue), cpu(_cpu) +bool +SimpleCPU::CpuPort::recvTiming(Packet &pkt) { + cpu->processResponse(pkt); + return true; } -void SimpleCPU::CacheCompletionEvent::process() +Tick +SimpleCPU::CpuPort::recvAtomic(Packet &pkt) { - cpu->processCacheCompletion(); + panic("CPU doesn't expect callback!"); + return curTick; } -const char * -SimpleCPU::CacheCompletionEvent::description() +void +SimpleCPU::CpuPort::recvFunctional(Packet &pkt) +{ + panic("CPU doesn't expect callback!"); +} + +void +SimpleCPU::CpuPort::recvStatusChange(Status status) { - return "SimpleCPU cache completion event"; + cpu->recvStatusChange(status); +} + +Packet * +SimpleCPU::CpuPort::recvRetry() +{ + return cpu->processRetry(); } SimpleCPU::SimpleCPU(Params *p) - : BaseCPU(p), tickEvent(this, p->width), cpuXC(NULL), - cacheCompletionEvent(this) + : BaseCPU(p), icachePort(this), + dcachePort(this), tickEvent(this, p->width), cpuXC(NULL) { _status = Idle; + + //Create Memory Ports (conect them up) + p->mem->addPort("DCACHE"); + dcachePort.setPeer(p->mem->getPort("DCACHE")); + (p->mem->getPort("DCACHE"))->setPeer(&dcachePort); + + p->mem->addPort("ICACHE"); + icachePort.setPeer(p->mem->getPort("ICACHE")); + (p->mem->getPort("ICACHE"))->setPeer(&icachePort); + #if FULL_SYSTEM cpuXC = new CPUExecContext(this, 0, p->system, p->itb, p->dtb, p->mem); - #else - cpuXC = new CPUExecContext(this, /* thread_num */ 0, p->process, - /* asid */ 0); + cpuXC = new CPUExecContext(this, /* thread_num */ 0, p->process, /* asid */ 0, + &dcachePort); #endif // !FULL_SYSTEM - xcProxy = cpuXC->getProxy(); - icacheInterface = p->icache_interface; - dcacheInterface = p->dcache_interface; + xcProxy = cpuXC->getProxy(); - memReq = new MemReq(); - memReq->xc = xcProxy; - memReq->asid = 0; - memReq->data = new uint8_t[64]; +#if SIMPLE_CPU_MEM_ATOMIC || SIMPLE_CPU_MEM_IMMEDIATE + ifetch_req = new CpuRequest; + ifetch_req->asid = 0; + ifetch_req->size = sizeof(MachInst); + ifetch_pkt = new Packet; + ifetch_pkt->cmd = Read; + ifetch_pkt->data = (uint8_t *)&inst; + ifetch_pkt->req = ifetch_req; + ifetch_pkt->size = sizeof(MachInst); + + data_read_req = new CpuRequest; + data_read_req->asid = 0; + data_read_pkt = new Packet; + data_read_pkt->cmd = Read; + data_read_pkt->data = new uint8_t[8]; + data_read_pkt->req = data_read_req; + + data_write_req = new CpuRequest; + data_write_req->asid = 0; + data_write_pkt = new Packet; + data_write_pkt->cmd = Write; + data_write_pkt->req = data_write_req; +#endif numInst = 0; startNumInst = 0; @@ -172,9 +212,9 @@ void SimpleCPU::switchOut(Sampler *s) { sampler = s; - if (status() == DcacheMissStall) { + if (status() == DcacheWaitResponse) { DPRINTF(Sampler,"Outstanding dcache access, waiting for completion\n"); - _status = DcacheMissSwitch; + _status = DcacheWaitSwitch; } else { _status = SwitchedOut; @@ -287,6 +327,18 @@ SimpleCPU::regStats() .prereq(dcacheStallCycles) ; + icacheRetryCycles + .name(name() + ".icache_retry_cycles") + .desc("ICache total retry cycles") + .prereq(icacheRetryCycles) + ; + + dcacheRetryCycles + .name(name() + ".dcache_retry_cycles") + .desc("DCache total retry cycles") + .prereq(dcacheRetryCycles) + ; + idleFraction = constant(1.0) - notIdleFraction; } @@ -308,7 +360,6 @@ SimpleCPU::serialize(ostream &os) nameOut(os, csprintf("%s.tickEvent", name())); tickEvent.serialize(os); nameOut(os, csprintf("%s.cacheCompletionEvent", name())); - cacheCompletionEvent.serialize(os); } void @@ -319,8 +370,6 @@ SimpleCPU::unserialize(Checkpoint *cp, const string §ion) UNSERIALIZE_SCALAR(inst); cpuXC->unserialize(cp, csprintf("%s.xc", section)); tickEvent.unserialize(cp, csprintf("%s.tickEvent", section)); - cacheCompletionEvent - .unserialize(cp, csprintf("%s.cacheCompletionEvent", section)); } void @@ -331,6 +380,7 @@ change_thread_state(int thread_number, int activate, int priority) Fault SimpleCPU::copySrcTranslate(Addr src) { +#if 0 static bool no_warn = true; int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; // Only support block sizes of 64 atm. @@ -347,8 +397,7 @@ SimpleCPU::copySrcTranslate(Addr src) memReq->reset(src & ~(blk_size - 1), blk_size); - // translate to physical address - Fault fault = cpuXC->translateDataReadReq(memReq); + // translate to physical address Fault fault = cpuXC->translateDataReadReq(req); if (fault == NoFault) { cpuXC->copySrcAddr = src; @@ -360,11 +409,15 @@ SimpleCPU::copySrcTranslate(Addr src) cpuXC->copySrcPhysAddr = 0; } return fault; +#else + return No_Fault; +#endif } Fault SimpleCPU::copy(Addr dest) { +#if 0 static bool no_warn = true; int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; // Only support block sizes of 64 atm. @@ -383,7 +436,7 @@ SimpleCPU::copy(Addr dest) memReq->reset(dest & ~(blk_size -1), blk_size); // translate to physical address - Fault fault = cpuXC->translateDataWriteReq(memReq); + Fault fault = cpuXC->translateDataWriteReq(req); if (fault == NoFault) { Addr dest_addr = memReq->paddr + offset; @@ -407,6 +460,10 @@ SimpleCPU::copy(Addr dest) assert(!fault->isAlignmentFault()); return fault; +#else + panic("copy not implemented"); + return No_Fault; +#endif } // precise architected memory state accessor macros @@ -414,22 +471,64 @@ template <class T> Fault SimpleCPU::read(Addr addr, T &data, unsigned flags) { - if (status() == DcacheMissStall || status() == DcacheMissSwitch) { - Fault fault = cpuXC->read(memReq,data); + if (status() == DcacheWaitResponse || status() == DcacheWaitSwitch) { +// Fault fault = xc->read(memReq,data); + // Not sure what to check for no fault... + if (data_read_pkt->result == Success) { + memcpy(&data, data_read_pkt->data, sizeof(T)); + } if (traceData) { traceData->setAddr(addr); } - return fault; + + // @todo: Figure out a way to create a Fault from the packet result. + return No_Fault; } - memReq->reset(addr, sizeof(T), flags); +// memReq->reset(addr, sizeof(T), flags); + +#if SIMPLE_CPU_MEM_TIMING + CpuRequest *data_read_req = new CpuRequest; +#endif + + data_read_req->vaddr = addr; + data_read_req->size = sizeof(T); + data_read_req->flags = flags; + data_read_req->time = curTick; // translate to physical address - Fault fault = cpuXC->translateDataReadReq(memReq); + Fault fault = cpuXC->translateDataReadReq(data_read_req); + + // Now do the access. + if (fault == No_Fault) { +#if SIMPLE_CPU_MEM_TIMING + data_read_pkt = new Packet; + data_read_pkt->cmd = Read; + data_read_pkt->req = data_read_req; + data_read_pkt->data = new uint8_t[8]; +#endif + data_read_pkt->addr = data_read_req->paddr; + data_read_pkt->size = sizeof(T); - // if we have a cache, do cache access too - if (fault == NoFault && dcacheInterface) { + sendDcacheRequest(data_read_pkt); + +#if SIMPLE_CPU_MEM_IMMEDIATE + // Need to find a way to not duplicate code above. + + if (data_read_pkt->result == Success) { + memcpy(&data, data_read_pkt->data, sizeof(T)); + } + + if (traceData) { + traceData->setAddr(addr); + } + + // @todo: Figure out a way to create a Fault from the packet result. + return No_Fault; +#endif + } +/* memReq->cmd = Read; memReq->completionEvent = NULL; memReq->time = curTick; @@ -454,8 +553,9 @@ SimpleCPU::read(Addr addr, T &data, unsigned flags) fault = cpuXC->read(memReq, data); } - - if (!dcacheInterface && (memReq->flags & UNCACHEABLE)) +*/ + // This will need a new way to tell if it has a dcache attached. + if (data_read_req->flags & UNCACHEABLE) recordEvent("Uncached Read"); return fault; @@ -508,11 +608,31 @@ template <class T> Fault SimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) { - memReq->reset(addr, sizeof(T), flags); + data_write_req->vaddr = addr; + data_write_req->time = curTick; + data_write_req->size = sizeof(T); + data_write_req->flags = flags; // translate to physical address - Fault fault = cpuXC->translateDataWriteReq(memReq); + Fault fault = cpuXC->translateDataWriteReq(data_write_req); + // Now do the access. + if (fault == No_Fault) { +#if SIMPLE_CPU_MEM_TIMING + data_write_pkt = new Packet; + data_write_pkt->cmd = Write; + data_write_pkt->req = data_write_req; + data_write_pkt->data = new uint8_t[64]; + memcpy(data_write_pkt->data, &data, sizeof(T)); +#else + data_write_pkt->data = (uint8_t *)&data; +#endif + data_write_pkt->addr = data_write_req->paddr; + data_write_pkt->size = sizeof(T); + + sendDcacheRequest(data_write_pkt); + } +/* // do functional access if (fault == NoFault) fault = cpuXC->write(memReq, data); @@ -535,13 +655,16 @@ SimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) _status = DcacheMissStall; } } - +*/ if (res && (fault == NoFault)) - *res = memReq->result; + *res = data_write_pkt->result; - if (!dcacheInterface && (memReq->flags & UNCACHEABLE)) + // This will need a new way to tell if it's hooked up to a cache or not. + if (data_write_req->flags & UNCACHEABLE) recordEvent("Uncached Write"); + // If the write needs to have a fault on the access, consider calling + // changeStatus() and changing it to "bad addr write" or something. return fault; } @@ -597,36 +720,130 @@ SimpleCPU::dbg_vtophys(Addr addr) #endif // FULL_SYSTEM void -SimpleCPU::processCacheCompletion() +SimpleCPU::sendIcacheRequest(Packet *pkt) { + assert(!tickEvent.scheduled()); +#if SIMPLE_CPU_MEM_TIMING + retry_pkt = pkt; + bool success = icachePort.sendTiming(*pkt); + + unscheduleTickEvent(); + + lastIcacheStall = curTick; + + if (!success) { + // Need to wait for retry + _status = IcacheRetry; + } else { + // Need to wait for cache to respond + _status = IcacheWaitResponse; + } +#elif SIMPLE_CPU_MEM_ATOMIC + Tick latency = icachePort.sendAtomic(*pkt); + + unscheduleTickEvent(); + scheduleTickEvent(latency); + + // Note that Icache miss cycles will be incorrect. Unless + // we check the status of the packet sent (is this valid?), + // we won't know if the latency is a hit or a miss. + icacheStallCycles += latency; + + _status = IcacheAccessComplete; +#elif SIMPLE_CPU_MEM_IMMEDIATE + icachePort.sendAtomic(*pkt); +#else +#error "SimpleCPU has no mem model set" +#endif +} + +void +SimpleCPU::sendDcacheRequest(Packet *pkt) +{ + assert(!tickEvent.scheduled()); +#if SIMPLE_CPU_MEM_TIMING + unscheduleTickEvent(); + + retry_pkt = pkt; + bool success = dcachePort.sendTiming(*pkt); + + lastDcacheStall = curTick; + + if (!success) { + _status = DcacheRetry; + } else { + _status = DcacheWaitResponse; + } +#elif SIMPLE_CPU_MEM_ATOMIC + unscheduleTickEvent(); + + Tick latency = dcachePort.sendAtomic(*pkt); + + scheduleTickEvent(latency); + + // Note that Dcache miss cycles will be incorrect. Unless + // we check the status of the packet sent (is this valid?), + // we won't know if the latency is a hit or a miss. + dcacheStallCycles += latency; +#elif SIMPLE_CPU_MEM_IMMEDIATE + dcachePort.sendAtomic(*pkt); +#else +#error "SimpleCPU has no mem model set" +#endif +} + +void +SimpleCPU::processResponse(Packet &response) +{ + assert(SIMPLE_CPU_MEM_TIMING); + + // For what things is the CPU the consumer of the packet it sent + // out? This may create a memory leak if that's the case and it's + // expected of the SimpleCPU to delete its own packet. + Packet *pkt = &response; + switch (status()) { - case IcacheMissStall: + case IcacheWaitResponse: icacheStallCycles += curTick - lastIcacheStall; - _status = IcacheMissComplete; + + _status = IcacheAccessComplete; scheduleTickEvent(1); + + // Copy the icache data into the instruction itself. + memcpy(&inst, pkt->data, sizeof(inst)); + + delete pkt; break; - case DcacheMissStall: - if (memReq->cmd.isRead()) { + case DcacheWaitResponse: + if (pkt->cmd == Read) { curStaticInst->execute(this,traceData); if (traceData) traceData->finalize(); } + + delete pkt; + dcacheStallCycles += curTick - lastDcacheStall; _status = Running; scheduleTickEvent(1); break; - case DcacheMissSwitch: - if (memReq->cmd.isRead()) { + case DcacheWaitSwitch: + if (pkt->cmd == Read) { curStaticInst->execute(this,traceData); if (traceData) traceData->finalize(); } + + delete pkt; + _status = SwitchedOut; sampler->signalSwitched(); case SwitchedOut: // If this CPU has been switched out due to sampling/warm-up, // ignore any further status changes (e.g., due to cache // misses outstanding at the time of the switch). + delete pkt; + return; default: panic("SimpleCPU::processCacheCompletion: bad state"); @@ -634,6 +851,28 @@ SimpleCPU::processCacheCompletion() } } +Packet * +SimpleCPU::processRetry() +{ +#if SIMPLE_CPU_MEM_TIMING + switch(status()) { + case IcacheRetry: + icacheRetryCycles += curTick - lastIcacheStall; + return retry_pkt; + break; + case DcacheRetry: + dcacheRetryCycles += curTick - lastDcacheStall; + return retry_pkt; + break; + default: + panic("SimpleCPU::processRetry: bad state"); + break; + } +#else + panic("shouldn't be here"); +#endif +} + #if FULL_SYSTEM void SimpleCPU::post_interrupt(int int_num, int index) @@ -706,15 +945,14 @@ SimpleCPU::tick() cpuXC->setFloatRegDouble(ZeroReg, 0.0); #endif // TARGET_ALPHA - if (status() == IcacheMissComplete) { + if (status() == IcacheAccessComplete) { // We've already fetched an instruction and were stalled on an // I-cache miss. No need to fetch it again. // Set status to running; tick event will get rescheduled if // necessary at end of tick() function. _status = Running; - } - else { + } else { // Try to fetch an instruction // set up memory request for instruction fetch @@ -724,15 +962,35 @@ SimpleCPU::tick() #define IFETCH_FLAGS(pc) 0 #endif - memReq->cmd = Read; - memReq->reset(cpuXC->readPC() & ~3, sizeof(uint32_t), - IFETCH_FLAGS(cpuXC->readPC())); +#if SIMPLE_CPU_MEM_TIMING + CpuRequest *ifetch_req = new CpuRequest(); + ifetch_req->size = sizeof(MachInst); +#endif - fault = cpuXC->translateInstReq(memReq); + ifetch_req->vaddr = cpuXC->readPC() & ~3; + ifetch_req->time = curTick; - if (fault == NoFault) - fault = cpuXC->mem->read(memReq, inst); +/* memReq->reset(xc->regs.pc & ~3, sizeof(uint32_t), + IFETCH_FLAGS(xc->regs.pc)); +*/ + + fault = xc->translateInstReq(ifetch_req); + + if (fault == NoFault) { +#if SIMPLE_CPU_MEM_TIMING + Packet *ifetch_pkt = new Packet; + ifetch_pkt->cmd = Read; + ifetch_pkt->data = (uint8_t *)&inst; + ifetch_pkt->req = ifetch_req; + ifetch_pkt->size = sizeof(MachInst); +#endif + ifetch_pkt->addr = ifetch_req->paddr; + sendIcacheRequest(ifetch_pkt); +#if SIMPLE_CPU_MEM_TIMING || SIMPLE_CPU_MEM_ATOMIC + return; +#endif +/* if (icacheInterface && fault == NoFault) { memReq->completionEvent = NULL; @@ -743,7 +1001,7 @@ SimpleCPU::tick() // Ugly hack to get an event scheduled *only* if the access is // a miss. We really should add first-class support for this // at some point. - if (result != MA_HIT && icacheInterface->doEvents()) { + if (result != MA_HIT && icacheInterface->doEvents()) { memReq->completionEvent = &cacheCompletionEvent; lastIcacheStall = curTick; unscheduleTickEvent(); @@ -751,6 +1009,8 @@ SimpleCPU::tick() return; } } +*/ + } } // If we've got a valid instruction (i.e., no fault on instruction @@ -806,8 +1066,7 @@ SimpleCPU::tick() // If we have a dcache miss, then we can't finialize the instruction // trace yet because we want to populate it with the data later - if (traceData && - !(status() == DcacheMissStall && memReq->cmd.isRead())) { + if (traceData && (status() != DcacheWaitResponse)) { traceData->finalize(); } @@ -846,7 +1105,7 @@ SimpleCPU::tick() assert(status() == Running || status() == Idle || - status() == DcacheMissStall); + status() == DcacheWaitResponse); if (status() == Running && !tickEvent.scheduled()) tickEvent.schedule(curTick + cycles(1)); @@ -866,17 +1125,15 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) #if FULL_SYSTEM SimObjectParam<AlphaITB *> itb; SimObjectParam<AlphaDTB *> dtb; - SimObjectParam<FunctionalMemory *> mem; SimObjectParam<System *> system; Param<int> cpu_id; Param<Tick> profile; #else + SimObjectParam<Memory *> mem; SimObjectParam<Process *> workload; #endif // FULL_SYSTEM Param<int> clock; - SimObjectParam<BaseMem *> icache; - SimObjectParam<BaseMem *> dcache; Param<bool> defer_registration; Param<int> width; @@ -899,17 +1156,15 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU) #if FULL_SYSTEM INIT_PARAM(itb, "Instruction TLB"), INIT_PARAM(dtb, "Data TLB"), - INIT_PARAM(mem, "memory"), INIT_PARAM(system, "system object"), INIT_PARAM(cpu_id, "processor ID"), INIT_PARAM(profile, ""), #else + INIT_PARAM(mem, "memory"), INIT_PARAM(workload, "processes to run"), #endif // FULL_SYSTEM INIT_PARAM(clock, "clock speed"), - INIT_PARAM(icache, "L1 instruction cache object"), - INIT_PARAM(dcache, "L1 data cache object"), INIT_PARAM(defer_registration, "defer system registration (for sampling)"), INIT_PARAM(width, "cpu width"), INIT_PARAM(function_trace, "Enable function trace"), @@ -931,18 +1186,16 @@ CREATE_SIM_OBJECT(SimpleCPU) params->clock = clock; params->functionTrace = function_trace; params->functionTraceStart = function_trace_start; - params->icache_interface = (icache) ? icache->getInterface() : NULL; - params->dcache_interface = (dcache) ? dcache->getInterface() : NULL; params->width = width; #if FULL_SYSTEM params->itb = itb; params->dtb = dtb; - params->mem = mem; params->system = system; params->cpu_id = cpu_id; params->profile = profile; #else + params->mem = mem; params->process = workload; #endif diff --git a/cpu/simple/cpu.hh b/cpu/simple/cpu.hh index 4ab9a1c3e..fbfae950f 100644 --- a/cpu/simple/cpu.hh +++ b/cpu/simple/cpu.hh @@ -36,6 +36,9 @@ #include "cpu/pc_event.hh" #include "cpu/sampler/sampler.hh" #include "cpu/static_inst.hh" +#include "mem/packet.hh" +#include "mem/port.hh" +#include "mem/request.hh" #include "sim/eventq.hh" // forward declarations @@ -43,7 +46,7 @@ class Processor; class AlphaITB; class AlphaDTB; -class PhysicalMemory; +class Memory; class RemoteGDB; class GDBListener; @@ -62,11 +65,48 @@ namespace Trace { class InstRecord; } + +// Set exactly one of these symbols to 1 to set the memory access +// model. Probably should make these template parameters, or even +// just fork the CPU models. +// +#define SIMPLE_CPU_MEM_TIMING 0 +#define SIMPLE_CPU_MEM_ATOMIC 0 +#define SIMPLE_CPU_MEM_IMMEDIATE 1 + + class SimpleCPU : public BaseCPU { protected: typedef TheISA::MachInst MachInst; typedef TheISA::MiscReg MiscReg; + class CpuPort : public Port + { + + SimpleCPU *cpu; + + public: + + CpuPort(SimpleCPU *_cpu) + : cpu(_cpu) + { } + + protected: + + virtual bool recvTiming(Packet &pkt); + + virtual Tick recvAtomic(Packet &pkt); + + virtual void recvFunctional(Packet &pkt); + + virtual void recvStatusChange(Status status); + + virtual Packet *recvRetry(); + }; + + CpuPort icachePort; + CpuPort dcachePort; + public: // main simulation loop (one cycle) void tick(); @@ -109,10 +149,12 @@ class SimpleCPU : public BaseCPU enum Status { Running, Idle, - IcacheMissStall, - IcacheMissComplete, - DcacheMissStall, - DcacheMissSwitch, + IcacheRetry, + IcacheWaitResponse, + IcacheAccessComplete, + DcacheRetry, + DcacheWaitResponse, + DcacheWaitSwitch, SwitchedOut }; @@ -133,14 +175,12 @@ class SimpleCPU : public BaseCPU public: struct Params : public BaseCPU::Params { - MemInterface *icache_interface; - MemInterface *dcache_interface; int width; #if FULL_SYSTEM AlphaITB *itb; AlphaDTB *dtb; - FunctionalMemory *mem; #else + Memory *mem; Process *process; #endif }; @@ -162,17 +202,19 @@ class SimpleCPU : public BaseCPU bool interval_stats; #endif - // L1 instruction cache - MemInterface *icacheInterface; - - // L1 data cache - MemInterface *dcacheInterface; - // current instruction MachInst inst; - // Refcounted pointer to the one memory request. - MemReqPtr memReq; +#if SIMPLE_CPU_MEM_TIMING + Packet *retry_pkt; +#elif SIMPLE_CPU_MEM_ATOMIC || SIMPLE_CPU_MEM_IMMEDIATE + CpuRequest *ifetch_req; + Packet *ifetch_pkt; + CpuRequest *data_read_req; + Packet *data_read_pkt; + CpuRequest *data_write_req; + Packet *data_write_pkt; +#endif // Pointer to the sampler that is telling us to switchover. // Used to signal the completion of the pipe drain and schedule @@ -181,20 +223,6 @@ class SimpleCPU : public BaseCPU StaticInstPtr curStaticInst; - class CacheCompletionEvent : public Event - { - private: - SimpleCPU *cpu; - - public: - CacheCompletionEvent(SimpleCPU *_cpu); - - virtual void process(); - virtual const char *description(); - }; - - CacheCompletionEvent cacheCompletionEvent; - Status status() const { return _status; } virtual void activateContext(int thread_num, int delay); @@ -227,15 +255,28 @@ class SimpleCPU : public BaseCPU Stats::Average<> notIdleFraction; Stats::Formula idleFraction; - // number of cycles stalled for I-cache misses + // number of cycles stalled for I-cache responses Stats::Scalar<> icacheStallCycles; Counter lastIcacheStall; - // number of cycles stalled for D-cache misses + // number of cycles stalled for I-cache retries + Stats::Scalar<> icacheRetryCycles; + Counter lastIcacheRetry; + + // number of cycles stalled for D-cache responses Stats::Scalar<> dcacheStallCycles; Counter lastDcacheStall; - void processCacheCompletion(); + // number of cycles stalled for D-cache retries + Stats::Scalar<> dcacheRetryCycles; + Counter lastDcacheRetry; + + void sendIcacheRequest(Packet *pkt); + void sendDcacheRequest(Packet *pkt); + void processResponse(Packet &response); + + Packet * processRetry(); + void recvStatusChange(Port::Status status) {} virtual void serialize(std::ostream &os); virtual void unserialize(Checkpoint *cp, const std::string §ion); diff --git a/cpu/static_inst.hh b/cpu/static_inst.hh index 20116554e..2ed2fe61c 100644 --- a/cpu/static_inst.hh +++ b/cpu/static_inst.hh @@ -34,7 +34,7 @@ #include "base/hashmap.hh" #include "base/refcnt.hh" -#include "encumbered/cpu/full/op_class.hh" +#include "cpu/op_class.hh" #include "sim/host.hh" #include "arch/isa_traits.hh" diff --git a/dev/io_device.cc b/dev/io_device.cc index 6ab876ab8..b580c2805 100644 --- a/dev/io_device.cc +++ b/dev/io_device.cc @@ -27,25 +27,119 @@ */ #include "dev/io_device.hh" -#include "mem/bus/base_interface.hh" -#include "mem/bus/dma_interface.hh" #include "sim/builder.hh" +void +PioPort::SendEvent::process() +{ + if (port->sendTiming(packet) == Success) + return; + + port->transmitList.push_back(&packet); +} + PioDevice::PioDevice(const std::string &name, Platform *p) - : FunctionalMemory(name), platform(p), pioInterface(NULL), pioLatency(0) -{} + : SimObject(name), platform(p) +{ + pioPort = new PioPort(this); +} + + +bool +PioDevice::recvTiming(Packet &pkt) +{ + device->recvAtomic(pkt); + sendTiming(pkt, pkt.responseTime-pkt.requestTime); + return Success; +} PioDevice::~PioDevice() { - if (pioInterface) + if (pioPort) delete pioInterface; } -DEFINE_SIM_OBJECT_CLASS_NAME("PioDevice", PioDevice) +void +DmaPort::sendDma(Packet &pkt) +{ + device->platform->system->memoryMode() + { + case MemAtomic: + } +} DmaDevice::DmaDevice(const std::string &name, Platform *p) - : PioDevice(name, p), dmaInterface(NULL) -{} + : PioDevice(name, p) +{ + dmaPort = new dmaPort(this); +} + +void +DmaPort::dmaAction(Memory::Command cmd, DmaPort port, Addr addr, int size, + Event *event, uint8_t *data = NULL) +{ + + assert(event); + + int prevSize = 0; + Packet basePkt; + Request baseReq; + + basePkt.flags = 0; + basePkt.coherence = NULL; + basePkt.senderState = NULL; + basePkt.src = 0; + basePkt.dest = 0; + basePkt.cmd = cmd; + basePkt.result = Unknown; + basePkt.request = NULL; + baseReq.nicReq = true; + baseReq.time = curTick; + + completionEvent = event; + + for (ChunkGenerator gen(addr, size, peerBlockSize()); + !gen.done(); gen.next()) { + Packet *pkt = new Packet(basePkt); + Request *req = new Request(baseReq); + pkt->addr = gen.addr(); + pkt->size = gen.size(); + pkt->req = req; + pkt->req->paddr = pkt->addr; + pkt->req->size = pkt->size; + // Increment the data pointer on a write + pkt->data = data ? data + prevSize : NULL ; + prevSize = pkt->size; + + sendDma(*pkt); + } +} + + +void +DmaPort::sendDma(Packet &pkt) +{ + // some kind of selction between access methods + // more work is going to have to be done to make + // switching actually work + MemState state = device->platform->system->memState; + + if (state == Timing) { + if (sendTiming(pkt) == Failure) + transmitList.push_back(&packet); + } else if (state == Atomic) { + sendAtomic(pkt); + completionEvent->schedule(pkt.responseTime - pkt.requestTime); + completionEvent == NULL; + } else if (state == Functional) { + sendFunctional(pkt); + // Is this correct??? + completionEvent->schedule(pkt.responseTime - pkt.requestTime); + completionEvent == NULL; + } else + panic("Unknown memory command state."); + +} DmaDevice::~DmaDevice() { @@ -53,5 +147,4 @@ DmaDevice::~DmaDevice() delete dmaInterface; } -DEFINE_SIM_OBJECT_CLASS_NAME("DmaDevice", DmaDevice) diff --git a/dev/io_device.hh b/dev/io_device.hh index bcfd062b9..a79c3f20a 100644 --- a/dev/io_device.hh +++ b/dev/io_device.hh @@ -29,34 +29,165 @@ #ifndef __DEV_IO_DEVICE_HH__ #define __DEV_IO_DEVICE_HH__ -#include "mem/functional/functional.hh" +#include "base/chunk_generator.hh" +#include "mem/port.hh" +#include "sim/eventq.hh" -class BaseInterface; class Bus; -class HierParams; class Platform; -template <class BusType> class DMAInterface; +class PioDevice; -class PioDevice : public FunctionalMemory +class PioPort : public Port { protected: + PioDevice *device; + + virtual bool recvTiming(Packet &pkt); + + virtual Tick recvAtomic(Packet &pkt) + { return device->recvAtomic(pkt) }; + + virtual void recvFunctional(Packet &pkt) + { device->recvAtomic(pkt) }; + + virtual void getDeviceAddressRanges(AddrRangeList &range_list, bool &owner) + { device->addressRanges(range_list, owner); } + + void sendTiming(Packet &pkt, Tick time) + { new SendEvent(this, pkt, time); } + + class SendEvent : public Event + { + PioPort *port; + Packet packet; + + SendEvent(PioPort *p, Packet &pkt, Tick t) + : Event(&mainEventQueue), packet(pkt) + { schedule(curTick + t); } + + virtual void process(); + + virtual const char *description() + { return "Future scheduled sendTiming event"; } + + friend class PioPort; + } + + public: + PioPort(PioDevice *dev) + : device(dev) + { } + +}; + +class DmaPort : public Port +{ + protected: + PioDevice *device; + std::list<Packet*> transmitList; + + + virtual bool recvTiming(Packet &pkt) + { completionEvent->schedule(curTick+1); completionEvent = NULL; } + virtual Tick recvAtomic(Packet &pkt) + { panic("dma port shouldn't be used for pio access."); } + virtual void recvFunctional(Packet &pkt) + { panic("dma port shouldn't be used for pio access."); } + + virtual void recvStatusChange(Status status) + { ; } + + virtual Packet *recvRetry() + { return transmitList.pop_front(); } + + virtual void getDeviceAddressRanges(AddrRangeList &range_list, bool &owner) + { range_list.clear(); owner = true; } + + void dmaAction(Memory::Command cmd, DmaPort port, Addr addr, int size, + Event *event, uint8_t *data = NULL); + + void sendDma(Packet &pkt); + + virtual Packet *recvRetry() + { return transmitList.pop_front(); } + + class SendEvent : public Event + { + PioPort *port; + Packet packet; + + SendEvent(PioPort *p, Packet &pkt, Tick t) + : Event(&mainEventQueue), packet(pkt) + { schedule(curTick + t); } + + virtual void process(); + + virtual const char *description() + { return "Future scheduled sendTiming event"; } + + friend class PioPort; + } + public: + DmaPort(DmaDevice *dev) + : device(dev) + { } + + +}; + + +class PioDevice : public SimObject +{ + protected: + Platform *platform; - BaseInterface *pioInterface; - Tick pioLatency; + + PioPort *pioPort; + + virtual void addressRanges(AddrRangeList &range_list, bool &owner) = 0; + + virtual read(Packet &pkt) = 0; + + virtual write(Packet &pkt) = 0; + + Tick recvAtomic(Packet &pkt) + { return pkt->cmd == Read ? this->read(pkt) : this->write(pkt); } public: PioDevice(const std::string &name, Platform *p); + virtual ~PioDevice(); + + virtual Port *getPort(std::string if_name) + { + if (if_name == "pio") + return pioPort; + else + return NULL; + } }; class DmaDevice : public PioDevice { protected: - DMAInterface<Bus> *dmaInterface; + DmaPort *dmaPort; public: DmaDevice(const std::string &name, Platform *p); virtual ~DmaDevice(); + + virtual Port *getPort(std::string if_name) + { + if (if_name == "pio") + return pioPort; + else if (if_name = "dma") + return dmaPort; + else + return NULL; + } }; + + + #endif // __DEV_IO_DEVICE_HH__ diff --git a/dev/platform.hh b/dev/platform.hh index 1ee645454..2c37048d4 100644 --- a/dev/platform.hh +++ b/dev/platform.hh @@ -41,6 +41,7 @@ class PciConfigAll; class IntrControl; class SimConsole; class Uart; +class System; class Platform : public SimObject { @@ -54,6 +55,9 @@ class Platform : public SimObject /** Pointer to the UART, set by the uart */ Uart *uart; + /** Pointer to the system for info about the memory system. */ + System *system; + public: Platform(const std::string &name, IntrControl *intctrl, PciConfigAll *pci); virtual ~Platform(); diff --git a/mem/bus.hh b/mem/bus.hh new file mode 100644 index 000000000..e26065295 --- /dev/null +++ b/mem/bus.hh @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file Decleration of a bus object. + */ + +#ifndef __MEM_BUS_HH__ +#define __MEM_BUS_HH__ + +#include <string> +#include <list> +#include <inttypes.h> + +#include "base/range.hh" +#include "mem/mem_object.hh" +#include "mem/packet.hh" +#include "mem/port.hh" +#include "mem/request.hh" + +class Bus : public MemObject +{ + /** Function called by the port when the bus is recieving a Timing + transaction.*/ + bool recvTiming(Packet &pkt, int id); + + /** Function called by the port when the bus is recieving a Atomic + transaction.*/ + Tick recvAtomic(Packet &pkt, int id); + + /** Function called by the port when the bus is recieving a Functional + transaction.*/ + void recvFunctional(Packet &pkt, int id); + + /** Function called by the port when the bus is recieving a status change.*/ + void recvStatusChange(Port::Status status, int id); + + /** Decleration of the buses port type, one will be instantiated for each + of the interfaces connecting to the bus. */ + class BusPort : public Port + { + /** A pointer to the bus to which this port belongs. */ + Bus *bus; + + /** A id to keep track of the intercafe ID this port is connected to. */ + int id; + + public: + + /** Constructor for the BusPort.*/ + BusPort(Bus *_bus, int _id) + : bus(_bus), id(_id) + { } + + protected: + + /** When reciving a timing request from the peer port (at id), + pass it to the bus. */ + virtual bool recvTiming(Packet &pkt) + { return bus->recvTiming(pkt, id); } + + /** When reciving a Atomic requestfrom the peer port (at id), + pass it to the bus. */ + virtual Tick recvAtomic(Packet &pkt) + { return bus->recvAtomic(pkt, id); } + + /** When reciving a Functional requestfrom the peer port (at id), + pass it to the bus. */ + virtual void recvFunctional(Packet &pkt) + { bus->recvFunctional(pkt, id); } + + /** When reciving a status changefrom the peer port (at id), + pass it to the bus. */ + virtual void recvStatusChange(Status status) + { bus->recvStatusChange(status, id); } + + // This should return all the 'owned' addresses that are + // downstream from this bus, yes? That is, the union of all + // the 'owned' address ranges of all the other interfaces on + // this bus... + virtual void addressRanges(AddrRangeList &range_list, bool &owner); + }; + + /** A count of the number of interfaces connected to this bus. */ + int num_interfaces; + + /** An array of pointers to the peer port interfaces + connected to this bus.*/ + Port *interfaces[]; + + public: + + /** A function used to return the port associated with this bus object. */ + virtual Port *getPort(const char *if_name) + { + // if_name ignored? forced to be empty? + int id = num_interfaces++; + interfaces[id] = new BusPort(this, id); + return interfaces[id]; + } +}; + +#endif //__MEM_BUS_HH__ diff --git a/mem/mem_object.hh b/mem/mem_object.hh new file mode 100644 index 000000000..634fb164a --- /dev/null +++ b/mem/mem_object.hh @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * Base Memory Object decleration. + */ + +#ifndef __MEM_MEM_OBJECT_HH__ +#define __MEM_MEM_OBJECT_HH__ + +#include "sim/sim_object.hh" +#include "mem/port.hh" + +/** + * The base MemoryObject class, allows for an accesor function to a + * simobj that returns the Port. + */ +class MemObject : public SimObject +{ + public: + MemObject(const std::string &name) + : SimObject(name) + {}; + + public: + /** Additional function to return the Port of a memory object. */ + virtual Port *getPort(const char *if_name) = 0; +}; + +#endif //__MEM_MEM_OBJECT_HH__ diff --git a/mem/packet.hh b/mem/packet.hh new file mode 100644 index 000000000..ef4eb85d9 --- /dev/null +++ b/mem/packet.hh @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * Declaration of the Packet Class, a packet is a transaction occuring + * between a single level of the memory heirarchy (ie L1->L2). + */ + +#ifndef __MEM_PACKET_HH__ +#define __MEM_PACKET_HH__ + +#include "mem/request.hh" +#include "targetarch/isa_traits.hh" +#include "sim/root.hh" + +struct Packet; +typedef Packet* PacketPtr; +typedef uint8_t* PacketDataPtr; + +/** List of all commands associated with a packet. */ +enum Command +{ + Read, + Write +}; + +/** The result of a particular pakets request. */ +enum PacketResult +{ + Success, + BadAddress +}; + +class SenderState{}; +class Coherence{}; + +/** + * A Packet is the structure to handle requests between two levels + * of the memory system. The Request is a global object that trancends + * all of the memory heirarchy, but at each levels interface a packet + * is created to transfer data/requests. For example, a request would + * be used to initiate a request to go to memory/IOdevices, as the request + * passes through the memory system several packets will be created. One + * will be created to go between the L1 and L2 caches and another to go to + * the next level and so forth. + * + * Packets are assumed to be returned in the case of a single response. If + * the transaction has no response, then the consumer will delete the packet. + */ +struct Packet +{ + /** The address of the request, could be virtual or physical (depending on + cache configurations). */ + Addr addr; + + /** Flag structure to hold flags for this particular packet */ + uint64_t flags; + + /** A pointer to the overall request. */ + RequestPtr req; + + /** A virtual base opaque structure used to hold + coherence status messages. */ + Coherence *coherence; // virtual base opaque, + // assert(dynamic_cast<Foo>) etc. + + /** A virtual base opaque structure used to hold the senders state. */ + SenderState *senderState; // virtual base opaque, + // assert(dynamic_cast<Foo>) etc. + + /** A pointer to the data being transfered. It can be differnt sizes + at each level of the heirarchy so it belongs in the packet, + not request*/ + PacketDataPtr data; + + /** Indicates the size of the request. */ + int size; + + /** A index of the source of the transaction. */ + short src; + + /** A index to the destination of the transaction. */ + short dest; + + /** The command of the transaction. */ + Command cmd; + + /** The result of the packet transaction. */ + PacketResult result; + + /** Accessor function that returns the source index of the packet. */ + short getSrc() const { return src; } + + /** Accessor function that returns the destination index of + the packet. */ + short getDest() const { return dest; } +}; + +#endif //__MEM_PACKET_HH diff --git a/mem/page_table.cc b/mem/page_table.cc new file mode 100644 index 000000000..63b60de24 --- /dev/null +++ b/mem/page_table.cc @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * Definitions of page table. + */ +#include <string> +#include <map> +#include <fstream> + +#include "base/bitfield.hh" +#include "base/intmath.hh" +#include "base/trace.hh" +#include "mem/page_table.hh" +#include "sim/builder.hh" +#include "sim/sim_object.hh" +#include "sim/system.hh" + +using namespace std; + +PageTable::PageTable(System *_system, Addr _pageSize) + : pageSize(_pageSize), offsetMask(mask(floorLog2(_pageSize))), + system(_system) +{ + assert(isPowerOf2(pageSize)); +} + +PageTable::~PageTable() +{ +} + +Fault +PageTable::page_check(Addr addr, int size) const +{ + if (size < sizeof(uint64_t)) { + if (!isPowerOf2(size)) { + panic("Invalid request size!\n"); + return Machine_Check_Fault; + } + + if ((size - 1) & addr) + return Alignment_Fault; + } + else { + if ((addr & (VMPageSize - 1)) + size > VMPageSize) { + panic("Invalid request size!\n"); + return Machine_Check_Fault; + } + + if ((sizeof(uint64_t) - 1) & addr) + return Alignment_Fault; + } + + return No_Fault; +} + + + + +void +PageTable::allocate(Addr vaddr, int size) +{ + // starting address must be page aligned + assert(pageOffset(vaddr) == 0); + + for (; size > 0; size -= pageSize, vaddr += pageSize) { + std::map<Addr,Addr>::iterator iter = pTable.find(vaddr); + + if (iter != pTable.end()) { + // already mapped + fatal("PageTable::allocate: address 0x%x already mapped", vaddr); + } + + pTable[vaddr] = system->new_page(); + } +} + + + +bool +PageTable::translate(Addr vaddr, Addr &paddr) +{ + Addr page_addr = pageAlign(vaddr); + std::map<Addr,Addr>::iterator iter = pTable.find(page_addr); + + if (iter == pTable.end()) { + return false; + } + + paddr = iter->second + pageOffset(vaddr); + return true; +} + + +Fault +PageTable::translate(CpuRequestPtr &req) +{ + assert(pageAlign(req->vaddr + req->size - 1) == pageAlign(req->vaddr)); + if (!translate(req->vaddr, req->paddr)) { + return Machine_Check_Fault; + } + return page_check(req->paddr, req->size); +} diff --git a/mem/page_table.hh b/mem/page_table.hh new file mode 100644 index 000000000..d318783be --- /dev/null +++ b/mem/page_table.hh @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * Declaration of a non-full system Page Table. + */ + +#ifndef __PAGE_TABLE__ +#define __PAGE_TABLE__ + +#include <string> +#include <map> + +#include "base/trace.hh" +#include "mem/request.hh" +#include "mem/packet.hh" +#include "sim/sim_object.hh" + +class System; + +/** + * Page Table Decleration. + */ +class PageTable +{ + protected: + std::map<Addr,Addr> pTable; + + const Addr pageSize; + const Addr offsetMask; + + System *system; + + public: + + PageTable(System *_system, Addr _pageSize = VMPageSize); + + ~PageTable(); + + Addr pageAlign(Addr a) { return (a & ~offsetMask); } + Addr pageOffset(Addr a) { return (a & offsetMask); } + + Fault page_check(Addr addr, int size) const; + + void allocate(Addr vaddr, int size); + + /** + * Translate function + * @param vaddr The virtual address. + * @return Physical address from translation. + */ + bool translate(Addr vaddr, Addr &paddr); + + /** + * Perform a translation on the memory request, fills in paddr + * field of mem_req. + * @param req The memory request. + */ + Fault translate(CpuRequestPtr &req); + +}; + +#endif diff --git a/mem/physical.cc b/mem/physical.cc new file mode 100644 index 000000000..69544c8fe --- /dev/null +++ b/mem/physical.cc @@ -0,0 +1,378 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/mman.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <zlib.h> + +#include <cstdio> +#include <iostream> +#include <string> + + +#include "base/misc.hh" +#include "config/full_system.hh" +#include "mem/physical.hh" +#include "sim/host.hh" +#include "sim/builder.hh" +#include "sim/eventq.hh" +#include "targetarch/isa_traits.hh" + + +using namespace std; + +PhysicalMemory::MemResponseEvent::MemResponseEvent(Packet &pkt, MemoryPort* _m) + : Event(&mainEventQueue, CPU_Tick_Pri), pkt(pkt), memoryPort(_m) +{ + + this->setFlags(AutoDelete); +} + +void +PhysicalMemory::MemResponseEvent::process() +{ + memoryPort->sendTiming(pkt); +} + +const char * +PhysicalMemory::MemResponseEvent::description() +{ + return "Physical Memory Timing Access respnse event"; +} + +PhysicalMemory::PhysicalMemory(const string &n) + : Memory(n), base_addr(0), pmem_addr(NULL) +{ + // Hardcoded to 128 MB for now. + pmem_size = 1 << 27; + + if (pmem_size % TheISA::PageBytes != 0) + panic("Memory Size not divisible by page size\n"); + + int map_flags = MAP_ANON | MAP_PRIVATE; + pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE, + map_flags, -1, 0); + + if (pmem_addr == (void *)MAP_FAILED) { + perror("mmap"); + fatal("Could not mmap!\n"); + } + + page_ptr = 0; +} + +PhysicalMemory::~PhysicalMemory() +{ + if (pmem_addr) + munmap(pmem_addr, pmem_size); + //Remove memPorts? +} + +Addr +PhysicalMemory::new_page() +{ + Addr return_addr = page_ptr << LogVMPageSize; + return_addr += base_addr; + + ++page_ptr; + return return_addr; +} + +Port * +PhysicalMemory::addPort(std::string portName) +{ + memoryPortList[portName] = new MemoryPort(this); + return memoryPortList[portName]; +} + +// +// little helper for better prot_* error messages +// +void +PhysicalMemory::prot_access_error(Addr addr, int size, Command func) +{ + panic("invalid physical memory access!\n" + "%s: %i(addr=%#x, size=%d) out of range (max=%#x)\n", + name(), func, addr, size, pmem_size - 1); +} + +void +PhysicalMemory::prot_memset(Addr addr, uint8_t val, int size) +{ + if (addr + size >= pmem_size) + prot_access_error(addr, size, Write); + + memset(pmem_addr + addr - base_addr, val, size); +} + +int +PhysicalMemory::deviceBlockSize() +{ + //Can accept anysize request + return 0; +} + +bool +PhysicalMemory::doTimingAccess (Packet &pkt, MemoryPort* memoryPort) +{ + doFunctionalAccess(pkt); + + MemResponseEvent* response = new MemResponseEvent(pkt, memoryPort); + response->schedule(curTick + lat); + + return true; +} + +Tick +PhysicalMemory::doAtomicAccess(Packet &pkt) +{ + doFunctionalAccess(pkt); + return curTick + lat; +} + +void +PhysicalMemory::doFunctionalAccess(Packet &pkt) +{ + if (pkt.addr + pkt.size >= pmem_size) + prot_access_error(pkt.addr, pkt.size, pkt.cmd); + + switch (pkt.cmd) { + case Read: + memcpy(pkt.data, pmem_addr + pkt.addr - base_addr, pkt.size); + break; + case Write: + memcpy(pmem_addr + pkt.addr - base_addr, pkt.data, pkt.size); + break; + default: + panic("unimplemented"); + } + + pkt.result = Success; +} + +Port * +PhysicalMemory::getPort(const char *if_name) +{ + if (memoryPortList.find(if_name) != memoryPortList.end()) + return memoryPortList[if_name]; + else + panic("Looking for a port that didn't exist\n"); +} + +void +PhysicalMemory::recvStatusChange(Port::Status status) +{ + panic("??"); +} + +PhysicalMemory::MemoryPort::MemoryPort(PhysicalMemory *_memory) + : memory(_memory) +{ } + +void +PhysicalMemory::MemoryPort::recvStatusChange(Port::Status status) +{ + memory->recvStatusChange(status); +} + +void +PhysicalMemory::MemoryPort::getDeviceAddressRanges(AddrRangeList &range_list, + bool &owner) +{ + panic("??"); +} + +int +PhysicalMemory::MemoryPort::deviceBlockSize() +{ + return memory->deviceBlockSize(); +} + +bool +PhysicalMemory::MemoryPort::recvTiming(Packet &pkt) +{ + return memory->doTimingAccess(pkt, this); +} + +Tick +PhysicalMemory::MemoryPort::recvAtomic(Packet &pkt) +{ + return memory->doAtomicAccess(pkt); +} + +void +PhysicalMemory::MemoryPort::recvFunctional(Packet &pkt) +{ + memory->doFunctionalAccess(pkt); +} + + + +void +PhysicalMemory::serialize(ostream &os) +{ + gzFile compressedMem; + string filename = name() + ".physmem"; + + SERIALIZE_SCALAR(pmem_size); + SERIALIZE_SCALAR(filename); + + // write memory file + string thefile = Checkpoint::dir() + "/" + filename.c_str(); + int fd = creat(thefile.c_str(), 0664); + if (fd < 0) { + perror("creat"); + fatal("Can't open physical memory checkpoint file '%s'\n", filename); + } + + compressedMem = gzdopen(fd, "wb"); + if (compressedMem == NULL) + fatal("Insufficient memory to allocate compression state for %s\n", + filename); + + if (gzwrite(compressedMem, pmem_addr, pmem_size) != pmem_size) { + fatal("Write failed on physical memory checkpoint file '%s'\n", + filename); + } + + if (gzclose(compressedMem)) + fatal("Close failed on physical memory checkpoint file '%s'\n", + filename); +} + +void +PhysicalMemory::unserialize(Checkpoint *cp, const string §ion) +{ + gzFile compressedMem; + long *tempPage; + long *pmem_current; + uint64_t curSize; + uint32_t bytesRead; + const int chunkSize = 16384; + + + // unmap file that was mmaped in the constructor + munmap(pmem_addr, pmem_size); + + string filename; + + UNSERIALIZE_SCALAR(pmem_size); + UNSERIALIZE_SCALAR(filename); + + filename = cp->cptDir + "/" + filename; + + // mmap memoryfile + int fd = open(filename.c_str(), O_RDONLY); + if (fd < 0) { + perror("open"); + fatal("Can't open physical memory checkpoint file '%s'", filename); + } + + compressedMem = gzdopen(fd, "rb"); + if (compressedMem == NULL) + fatal("Insufficient memory to allocate compression state for %s\n", + filename); + + + pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE, -1, 0); + + if (pmem_addr == (void *)MAP_FAILED) { + perror("mmap"); + fatal("Could not mmap physical memory!\n"); + } + + curSize = 0; + tempPage = (long*)malloc(chunkSize); + if (tempPage == NULL) + fatal("Unable to malloc memory to read file %s\n", filename); + + /* Only copy bytes that are non-zero, so we don't give the VM system hell */ + while (curSize < pmem_size) { + bytesRead = gzread(compressedMem, tempPage, chunkSize); + if (bytesRead != chunkSize && bytesRead != pmem_size - curSize) + fatal("Read failed on physical memory checkpoint file '%s'" + " got %d bytes, expected %d or %d bytes\n", + filename, bytesRead, chunkSize, pmem_size-curSize); + + assert(bytesRead % sizeof(long) == 0); + + for (int x = 0; x < bytesRead/sizeof(long); x++) + { + if (*(tempPage+x) != 0) { + pmem_current = (long*)(pmem_addr + curSize + x * sizeof(long)); + *pmem_current = *(tempPage+x); + } + } + curSize += bytesRead; + } + + free(tempPage); + + if (gzclose(compressedMem)) + fatal("Close failed on physical memory checkpoint file '%s'\n", + filename); + +} + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory) + + Param<string> file; +#if FULL_SYSTEM + SimObjectParam<MemoryController *> mmu; +#endif + Param<Range<Addr> > range; + +END_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory) + +BEGIN_INIT_SIM_OBJECT_PARAMS(PhysicalMemory) + + INIT_PARAM_DFLT(file, "memory mapped file", ""), +#if FULL_SYSTEM + INIT_PARAM(mmu, "Memory Controller"), +#endif + INIT_PARAM(range, "Device Address Range") + +END_INIT_SIM_OBJECT_PARAMS(PhysicalMemory) + +CREATE_SIM_OBJECT(PhysicalMemory) +{ +#if FULL_SYSTEM + if (mmu) { + return new PhysicalMemory(getInstanceName(), range, mmu, file); + } +#endif + + return new PhysicalMemory(getInstanceName()); +} + +REGISTER_SIM_OBJECT("PhysicalMemory", PhysicalMemory) diff --git a/mem/physical.hh b/mem/physical.hh new file mode 100644 index 000000000..854886a27 --- /dev/null +++ b/mem/physical.hh @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* @file + */ + +#ifndef __PHYSICAL_MEMORY_HH__ +#define __PHYSICAL_MEMORY_HH__ + +#include "base/range.hh" +#include "mem/memory.hh" +#include "mem/packet.hh" +#include "mem/port.hh" +#include "sim/eventq.hh" +#include <map> +#include <string> +// +// Functional model for a contiguous block of physical memory. (i.e. RAM) +// +class PhysicalMemory : public Memory +{ + class MemoryPort : public Port + { + PhysicalMemory *memory; + + public: + + MemoryPort(PhysicalMemory *_memory); + + protected: + + virtual bool recvTiming(Packet &pkt); + + virtual Tick recvAtomic(Packet &pkt); + + virtual void recvFunctional(Packet &pkt); + + virtual void recvStatusChange(Status status); + + virtual void getDeviceAddressRanges(AddrRangeList &range_list, + bool &owner); + + virtual int deviceBlockSize(); + }; + + std::map<std::string, MemoryPort*> memoryPortList; + + virtual Port * getPort(const char *if_name); + + virtual Port * addPort(std::string portName); + + int numPorts; + + int lat; + + struct MemResponseEvent : public Event + { + Packet &pkt; + MemoryPort *memoryPort; + + MemResponseEvent(Packet &pkt, MemoryPort *memoryPort); + void process(); + const char *description(); + }; + + private: + // prevent copying of a MainMemory object + PhysicalMemory(const PhysicalMemory &specmem); + const PhysicalMemory &operator=(const PhysicalMemory &specmem); + + protected: + Addr base_addr; + Addr pmem_size; + uint8_t *pmem_addr; + int page_ptr; + + public: + Addr new_page(); + uint64_t size() { return pmem_size; } + + public: + PhysicalMemory(const std::string &n); + virtual ~PhysicalMemory(); + + protected: + // error handling for prot_* functions + void prot_access_error(Addr addr, int size, Command func); + + public: + int deviceBlockSize(); + + void prot_memset(Addr addr, uint8_t val, int size); + + // fast back-door memory access for vtophys(), remote gdb, etc. + // uint64_t phys_read_qword(Addr addr) const; + private: + bool doTimingAccess(Packet &pkt, MemoryPort *memoryPort); + Tick doAtomicAccess(Packet &pkt); + void doFunctionalAccess(Packet &pkt); + + void recvStatusChange(Port::Status status); + + public: + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); +}; + +/*uint64_t +PhysicalMemory::phys_read_qword(Addr addr) const +{ + if (addr + sizeof(uint64_t) > pmem_size) + return 0; + + return *(uint64_t *)(pmem_addr + addr); +}*/ + + +#endif //__PHYSICAL_MEMORY_HH__ diff --git a/mem/port.cc b/mem/port.cc new file mode 100644 index 000000000..75362b472 --- /dev/null +++ b/mem/port.cc @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file Port object definitions. + */ + +#include "base/chunk_generator.hh" +#include "mem/port.hh" + +void +Port::blobHelper(Addr addr, uint8_t *p, int size, Command cmd) +{ + Request req; + Packet pkt; + pkt.req = &req; + pkt.cmd = cmd; + + for (ChunkGenerator gen(addr, size, peerBlockSize()); + !gen.done(); gen.next()) { + pkt.addr = req.paddr = gen.addr(); + pkt.size = req.size = gen.size(); + pkt.data = p; + sendFunctional(pkt); + p += gen.size(); + } +} + +void +Port::writeBlobFunctional(Addr addr, uint8_t *p, int size) +{ + blobHelper(addr, p, size, Write); +} + +void +Port::readBlobFunctional(Addr addr, uint8_t *p, int size) +{ + blobHelper(addr, p, size, Read); +} + +void +Port::memsetBlobFunctional(Addr addr, uint8_t val, int size) +{ + // quick and dirty... + uint8_t *buf = new uint8_t[size]; + + memset(buf, val, size); + blobHelper(addr, buf, size, Write); + + delete buf; +} diff --git a/mem/port.hh b/mem/port.hh new file mode 100644 index 000000000..9d0bd7968 --- /dev/null +++ b/mem/port.hh @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * Port Object Decleration. Ports are used to interface memory objects to + * each other. They will always come in pairs, and we refer to the other + * port object as the peer. These are used to make the design more + * modular so that a specific interface between every type of objcet doesn't + * have to be created. + */ + +#ifndef __MEM_PORT_HH__ +#define __MEM_PORT_HH__ + +#include <string> +#include <list> +#include <inttypes.h> + +#include "base/range.hh" +#include "mem/packet.hh" +#include "mem/request.hh" + +/** This typedef is used to clean up the parameter list of + * getDeviceAddressRanges() and getPeerAddressRanges(). It's declared + * outside the Port object since it's also used by some mem objects. + * Eventually we should move this typedef to wherever Addr is + * defined. + */ + +typedef std::list<Range<Addr> > AddrRangeList; + +/** + * Ports are used to interface memory objects to + * each other. They will always come in pairs, and we refer to the other + * port object as the peer. These are used to make the design more + * modular so that a specific interface between every type of objcet doesn't + * have to be created. + * + * Recv accesor functions are being called from the peer interface. + * Send accessor functions are being called from the device the port is + * associated with, and it will call the peer recv. accessor function. + */ +class Port +{ + public: + + // mey be better to use subclasses & RTTI? + /** Holds the ports status. Keeps track if it is blocked, or has + calculated a range change. */ + enum Status { + Blocked, + Unblocked, + RangeChange + }; + + private: + + /** A pointer to the peer port. Ports always come in pairs, that way they + can use a standardized interface to communicate between different + memory objects. */ + Port *peer; + + public: + + /** Function to set the pointer for the peer port. + @todo should be called by the configuration stuff (python). + */ + void setPeer(Port *port) { peer = port; } + + /** Function to set the pointer for the peer port. + @todo should be called by the configuration stuff (python). + */ + Port *getPeer() { return peer; } + + protected: + + /** These functions are protected because they should only be + * called by a peer port, never directly by any outside object. */ + + /** Called to recive a timing call from the peer port. */ + virtual bool recvTiming(Packet &pkt) = 0; + + /** Called to recive a atomic call from the peer port. */ + virtual Tick recvAtomic(Packet &pkt) = 0; + + /** Called to recive a functional call from the peer port. */ + virtual void recvFunctional(Packet &pkt) = 0; + + /** Called to recieve a status change from the peer port. */ + virtual void recvStatusChange(Status status) = 0; + + /** Called by a peer port if the send was unsuccesful, and had to + wait. This shouldn't be valid for response paths (IO Devices). + so it is set to panic if it isn't already defined. + */ + virtual Packet *recvRetry() { panic("??"); } + + /** Called by a peer port in order to determine the block size of the + device connected to this port. It sometimes doesn't make sense for + this function to be called, a DMA interface doesn't really have a + block size, so it is defaulted to a panic. + */ + virtual int deviceBlockSize() { panic("??"); } + + /** The peer port is requesting us to reply with a list of the ranges we + are responsible for. + @param owner is an output param that, if set, indicates that the + port is the owner of the specified ranges (i.e., slave, default + responder, etc.). If 'owner' is false, the interface is + interested in the specified ranges for snooping purposes. If + an object wants to own some ranges and snoop on others, it will + need to use two different ports. + */ + virtual void getDeviceAddressRanges(AddrRangeList &range_list, + bool &owner) + { panic("??"); } + + public: + + /** Function called by associated memory device (cache, memory, iodevice) + in order to send a timing request to the port. Simply calls the peer + port receive function. + @return This function returns if the send was succesful in it's + recieve. If it was a failure, then the port will wait for a recvRetry + at which point it can issue a successful sendTiming. This is used in + case a cache has a higher priority request come in while waiting for + the bus to arbitrate. + */ + bool sendTiming(Packet &pkt) { return peer->recvTiming(pkt); } + + /** Function called by the associated device to send an atomic access, + an access in which the data is moved and the state is updated in one + cycle, without interleaving with other memory accesses. + */ + Tick sendAtomic(Packet &pkt) + { return peer->recvAtomic(pkt); } + + /** Function called by the associated device to send a functional access, + an access in which the data is instantly updated everywhere in the + memory system, without affecting the current state of any block + or moving the block. + */ + void sendFunctional(Packet &pkt) + { return peer->recvFunctional(pkt); } + + /** Called by the associated device to send a status change to the device + connected to the peer interface. + */ + void sendStatusChange(Status status) {peer->recvStatusChange(status); } + + /** When a timing access doesn't return a success, some time later the + Retry will be sent. + */ + Packet *sendRetry() { return peer->recvRetry(); } + + /** Called by the associated device if it wishes to find out the blocksize + of the device on attached to the peer port. + */ + int peerBlockSize() { return peer->deviceBlockSize(); } + + /** Called by the associated device if it wishes to find out the address + ranges connected to the peer ports devices. + */ + void getPeerAddressRanges(AddrRangeList &range_list, bool &owner) + { peer->getDeviceAddressRanges(range_list, owner); } + + // Do we need similar wrappers for sendAtomic()? If not, should + // we drop the "Functional" from the names? + + /** This function is a wrapper around sendFunctional() + that breaks a larger, arbitrarily aligned access into + appropriate chunks. The default implementation can use + getBlockSize() to determine the block size and go from there. + */ + void readBlobFunctional(Addr addr, uint8_t *p, int size); + + /** This function is a wrapper around sendFunctional() + that breaks a larger, arbitrarily aligned access into + appropriate chunks. The default implementation can use + getBlockSize() to determine the block size and go from there. + */ + void writeBlobFunctional(Addr addr, uint8_t *p, int size); + + /** Fill size bytes starting at addr with byte value val. This + should not need to be virtual, since it can be implemented in + terms of writeBlobFunctional(). However, it shouldn't be + performance-critical either, so it could be if we wanted to. + Not even sure if this is actually needed anywhere (there's a + prot_memset on the old functional memory that's never used), + but Nate claims it is. + */ + void memsetBlobFunctional(Addr addr, uint8_t val, int size); + + private: + + /** Internal helper function for read/writeBlob(). + */ + void blobHelper(Addr addr, uint8_t *p, int size, Command cmd); +}; + +#endif //__MEM_PORT_HH__ diff --git a/mem/request.hh b/mem/request.hh new file mode 100644 index 000000000..c3c1d0fd4 --- /dev/null +++ b/mem/request.hh @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file Decleration of a request, the overall memory request consisting of + the parts of the request that are persistent throughout the transaction. + */ + +#ifndef __MEM_REQUEST_HH__ +#define __MEM_REQUEST_HH__ + +#include "targetarch/isa_traits.hh" + +class Request; +class CpuRequest; + +typedef Request* RequestPtr; +typedef CpuRequest* CpuRequestPtr; + +/** The request is a Load locked/store conditional. */ +const unsigned LOCKED = 0x001; +/** The virtual address is also the physical address. */ +const unsigned PHYSICAL = 0x002; +/** The request is an ALPHA VPTE pal access (hw_ld). */ +const unsigned VPTE = 0x004; +/** Use the alternate mode bits in ALPHA. */ +const unsigned ALTMODE = 0x008; +/** The request is to an uncacheable address. */ +const unsigned UNCACHEABLE = 0x010; +/** The request should not cause a page fault. */ +const unsigned NO_FAULT = 0x020; +/** The request should be prefetched into the exclusive state. */ +const unsigned PF_EXCLUSIVE = 0x100; +/** The request should be marked as LRU. */ +const unsigned EVICT_NEXT = 0x200; + +class Request +{ + //@todo Make Accesor functions, make these private. + public: + /** The physical address of the request. */ + Addr paddr; + + /** whether this req came from the CPU or not **DO we need this??***/ + bool nicReq; + + /** The size of the request. */ + int size; + + /** The time this request was started. Used to calculate latencies. */ + Tick time; + + /** Destination address if this is a block copy. */ + Addr copyDest; + + uint32_t flags; +}; + +class CpuRequest : public Request +{ + //@todo Make Accesor functions, make these private. + public: + /** The virtual address of the request. */ + Addr vaddr; + + /** The address space ID. */ + int asid; + + /** The return value of store conditional. */ + uint64_t scResult; + + /** The cpu number for statistics. */ + int cpuNum; + + /** The requesting thread id. */ + int threadNum; + + /** program counter of initiating access; for tracing/debugging */ + Addr pc; +}; + +#endif // __MEM_REQUEST_HH__ diff --git a/mem/translating_port.cc b/mem/translating_port.cc new file mode 100644 index 000000000..f4f2ca737 --- /dev/null +++ b/mem/translating_port.cc @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string> +#include "base/chunk_generator.hh" +#include "mem/port.hh" +#include "mem/translating_port.hh" +#include "mem/page_table.hh" + +TranslatingPort::TranslatingPort(Port *_port, PageTable *p_table) + : port(_port), pTable(p_table) +{ } + +TranslatingPort::~TranslatingPort() +{ } + +Fault +TranslatingPort::readBlobFunctional(Addr addr, uint8_t *p, int size) +{ + Addr paddr; + int prevSize = 0; + + for (ChunkGenerator gen(addr, size, VMPageSize); !gen.done(); gen.next()) { + + if (!pTable->translate(gen.addr(),paddr)) + return Machine_Check_Fault; + + port->readBlobFunctional(paddr, p + prevSize, gen.size()); + prevSize += gen.size(); + } + + return No_Fault; +} + +Fault +TranslatingPort::writeBlobFunctional(Addr addr, uint8_t *p, int size, + bool alloc) +{ + Addr paddr; + int prevSize = 0; + + for (ChunkGenerator gen(addr, size, VMPageSize); !gen.done(); gen.next()) { + + if (!pTable->translate(gen.addr(), paddr)) { + if (alloc) { + pTable->allocate(roundDown(gen.addr(), VMPageSize), + VMPageSize); + pTable->translate(gen.addr(), paddr); + } else { + return Machine_Check_Fault; + } + } + + port->writeBlobFunctional(paddr, p + prevSize, gen.size()); + prevSize += gen.size(); + } + + return No_Fault; +} + + +Fault +TranslatingPort::memsetBlobFunctional(Addr addr, uint8_t val, int size, + bool alloc) +{ + Addr paddr; + + for (ChunkGenerator gen(addr, size, VMPageSize); !gen.done(); gen.next()) { + + if (!pTable->translate(gen.addr(), paddr)) { + if (alloc) { + pTable->allocate(roundDown(gen.addr(), VMPageSize), + VMPageSize); + pTable->translate(gen.addr(), paddr); + } else { + return Machine_Check_Fault; + } + } + + port->memsetBlobFunctional(paddr, val, gen.size()); + } + + return No_Fault; +} + + +Fault +TranslatingPort::writeStringFunctional(Addr addr, const char *str) +{ + Addr paddr,vaddr; + uint8_t c; + + vaddr = addr; + + do { + c = *str++; + if (!pTable->translate(vaddr++,paddr)) + return Machine_Check_Fault; + + port->writeBlobFunctional(paddr, &c, 1); + } while (c); + + return No_Fault; +} + +Fault +TranslatingPort::readStringFunctional(std::string &str, Addr addr) +{ + Addr paddr,vaddr; + uint8_t c; + + vaddr = addr; + + do { + if (!pTable->translate(vaddr++,paddr)) + return Machine_Check_Fault; + + port->readBlobFunctional(paddr, &c, 1); + str += c; + } while (c); + + return No_Fault; +} + diff --git a/mem/translating_port.hh b/mem/translating_port.hh new file mode 100644 index 000000000..1a334c103 --- /dev/null +++ b/mem/translating_port.hh @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MEM_TRANSLATING_PROT_HH__ +#define __MEM_TRANSLATING_PROT_HH__ + +#include "mem/memory.hh" + +class Port; +class PageTable; + +class TranslatingPort +{ + private: + Port *port; + PageTable *pTable; + + TranslatingPort(const TranslatingPort &specmem); + const TranslatingPort &operator=(const TranslatingPort &specmem); + + public: + TranslatingPort(Port *_port, PageTable *p_table); + virtual ~TranslatingPort(); + + public: + Fault readBlobFunctional(Addr addr, uint8_t *p, int size); + Fault writeBlobFunctional(Addr addr, uint8_t *p, int size, + bool alloc = false); + Fault memsetBlobFunctional(Addr addr, uint8_t val, int size, + bool alloc = false); + Fault writeStringFunctional(Addr addr, const char *str); + Fault readStringFunctional(std::string &str, Addr addr); + +}; + +#endif diff --git a/python/m5/objects/BaseCPU.py b/python/m5/objects/BaseCPU.py index a90203729..07cb850f1 100644 --- a/python/m5/objects/BaseCPU.py +++ b/python/m5/objects/BaseCPU.py @@ -2,16 +2,14 @@ from m5 import * class BaseCPU(SimObject): type = 'BaseCPU' abstract = True - icache = Param.BaseMem(NULL, "L1 instruction cache object") - dcache = Param.BaseMem(NULL, "L1 data cache object") if build_env['FULL_SYSTEM']: dtb = Param.AlphaDTB("Data TLB") itb = Param.AlphaITB("Instruction TLB") - mem = Param.FunctionalMemory("memory") system = Param.System(Parent.any, "system object") cpu_id = Param.Int(-1, "CPU identifier") else: + mem = Param.Memory(Parent.any, "memory") workload = VectorParam.Process("processes to run") max_insts_all_threads = Param.Counter(0, diff --git a/python/m5/objects/Ethernet.py b/python/m5/objects/Ethernet.py index 6113e656f..22714e15c 100644 --- a/python/m5/objects/Ethernet.py +++ b/python/m5/objects/Ethernet.py @@ -69,7 +69,6 @@ class EtherDevBase(PciDevice): physmem = Param.PhysicalMemory(Parent.any, "Physical Memory") - hier = Param.HierParams(Parent.any, "Hierarchy global variables") payload_bus = Param.Bus(NULL, "The IO Bus to attach to for payload") dma_read_delay = Param.Latency('0us', "fixed delay for dma reads") dma_read_factor = Param.Latency('0us', "multiplier for dma reads") diff --git a/python/m5/objects/MemObject.py b/python/m5/objects/MemObject.py new file mode 100644 index 000000000..4d68243e6 --- /dev/null +++ b/python/m5/objects/MemObject.py @@ -0,0 +1,5 @@ +from m5 import * + +class MemObject(SimObject): + type = 'MemObject' + abstract = True diff --git a/python/m5/objects/PhysicalMemory.py b/python/m5/objects/PhysicalMemory.py index f50937ee6..b0aba1a7d 100644 --- a/python/m5/objects/PhysicalMemory.py +++ b/python/m5/objects/PhysicalMemory.py @@ -1,8 +1,9 @@ from m5 import * -from FunctionalMemory import FunctionalMemory +from Memory import Memory -class PhysicalMemory(FunctionalMemory): +class PhysicalMemory(Memory): type = 'PhysicalMemory' range = Param.AddrRange("Device Address") file = Param.String('', "memory mapped file") - mmu = Param.MemoryController(Parent.any, "Memory Controller") + if build_env['FULL_SYSTEM']: + mmu = Param.MemoryController(Parent.any, "Memory Controller") diff --git a/python/m5/objects/Process.py b/python/m5/objects/Process.py index b4ccc1bec..def70dbaa 100644 --- a/python/m5/objects/Process.py +++ b/python/m5/objects/Process.py @@ -3,6 +3,7 @@ class Process(SimObject): type = 'Process' abstract = True output = Param.String('cout', 'filename for stdout/stderr') + system = Param.System(Parent.any, "system process will run on") class LiveProcess(Process): type = 'LiveProcess' diff --git a/python/m5/objects/Root.py b/python/m5/objects/Root.py index 23b13fc67..f51516098 100644 --- a/python/m5/objects/Root.py +++ b/python/m5/objects/Root.py @@ -1,5 +1,4 @@ from m5 import * -from HierParams import HierParams from Serialize import Serialize from Statistics import Statistics from Trace import Trace @@ -13,12 +12,9 @@ class Root(SimObject): "print a progress message every n ticks (0 = never)") output_file = Param.String('cout', "file to dump simulator output to") checkpoint = Param.String('', "checkpoint file to load") -# hier = Param.HierParams(HierParams(do_data = False, do_events = True), -# "shared memory hierarchy parameters") # stats = Param.Statistics(Statistics(), "statistics object") # trace = Param.Trace(Trace(), "trace object") # serialize = Param.Serialize(Serialize(), "checkpoint generation options") - hier = HierParams(do_data = False, do_events = True) stats = Statistics() trace = Trace() exetrace = ExecutionTrace() diff --git a/sim/process.cc b/sim/process.cc index f02ca8bfd..70a92a604 100644 --- a/sim/process.cc +++ b/sim/process.cc @@ -42,12 +42,15 @@ #include "cpu/smt.hh" #include "encumbered/cpu/full/thread.hh" #include "encumbered/eio/eio.hh" -#include "encumbered/mem/functional/main.hh" +#include "mem/page_table.hh" +#include "mem/memory.hh" +#include "mem/translating_port.hh" #include "sim/builder.hh" #include "sim/fake_syscall.hh" #include "sim/process.hh" #include "sim/stats.hh" #include "sim/syscall_emul.hh" +#include "sim/system.hh" #include "arch/process.hh" @@ -67,20 +70,12 @@ using namespace TheISA; int num_processes = 0; Process::Process(const string &nm, + System *_system, int stdin_fd, // initial I/O descriptors int stdout_fd, int stderr_fd) - : SimObject(nm) + : SimObject(nm), system(_system) { - // allocate memory space - memory = new MainMemory(nm + ".MainMem"); - - // allocate initial register file - init_regs = new RegFile; - memset(init_regs, 0, sizeof(RegFile)); - - cpuXC = new CPUExecContext(init_regs); - // initialize first 3 fds (stdin, stdout, stderr) fd_map[STDIN_FILENO] = stdin_fd; fd_map[STDOUT_FILENO] = stdout_fd; @@ -93,9 +88,11 @@ Process::Process(const string &nm, mmap_start = mmap_end = 0; nxm_start = nxm_end = 0; + pTable = new PageTable(system); // other parameters will be initialized when the program is loaded } + void Process::regStats() { @@ -147,12 +144,7 @@ Process::registerExecContext(ExecContext *xc) int myIndex = execContexts.size(); execContexts.push_back(xc); - if (myIndex == 0) { - // copy process's initial regs struct - xc->copyArchRegs(cpuXC->getProxy()); - } - - // return CPU number to caller and increment available CPU count + // return CPU number to caller return myIndex; } @@ -160,7 +152,9 @@ void Process::startup() { if (execContexts.empty()) - return; + fatal("Process %s is not associated with any CPUs!\n", name()); + + initVirtMem = new TranslatingPort((system->physmem->getPort("DCACHE"))->getPeer(), pTable); // first exec context for this process... initialize & enable ExecContext *xc = execContexts[0]; @@ -251,25 +245,28 @@ DEFINE_SIM_OBJECT_CLASS_NAME("Process", Process) static void copyStringArray(vector<string> &strings, Addr array_ptr, Addr data_ptr, - FunctionalMemory *memory) + TranslatingPort* memPort) { Addr data_ptr_swap; for (int i = 0; i < strings.size(); ++i) { data_ptr_swap = htog(data_ptr); - memory->access(Write, array_ptr, &data_ptr_swap, sizeof(Addr)); - memory->writeString(data_ptr, strings[i].c_str()); + memPort->writeBlobFunctional(array_ptr, (uint8_t*)&data_ptr_swap, sizeof(Addr)); + memPort->writeStringFunctional(data_ptr, strings[i].c_str()); array_ptr += sizeof(Addr); data_ptr += strings[i].size() + 1; } // add NULL terminator data_ptr = 0; - memory->access(Write, array_ptr, &data_ptr, sizeof(Addr)); + + memPort->writeBlobFunctional(array_ptr, (uint8_t*)&data_ptr, sizeof(Addr)); } -LiveProcess::LiveProcess(const string &nm, ObjectFile *objFile, +LiveProcess::LiveProcess(const string &nm, ObjectFile *_objFile, + System *_system, int stdin_fd, int stdout_fd, int stderr_fd, - vector<string> &argv, vector<string> &envp) - : Process(nm, stdin_fd, stdout_fd, stderr_fd) + vector<string> &_argv, vector<string> &_envp) + : Process(nm, _system, stdin_fd, stdout_fd, stderr_fd), + objFile(_objFile), argv(_argv), envp(_envp) { prog_fname = argv[0]; @@ -280,8 +277,16 @@ LiveProcess::LiveProcess(const string &nm, ObjectFile *objFile, data_size = objFile->dataSize() + objFile->bssSize(); brk_point = roundUp(data_base + data_size, VMPageSize); - // load object file into target memory - objFile->loadSections(memory); + // Set up stack. On Alpha, stack goes below text section. This + // code should get moved to some architecture-specific spot. + stack_base = text_base - (409600+4096); + + // Set up region for mmaps. Tru64 seems to start just above 0 and + // grow up from there. + mmap_start = mmap_end = 0x10000; + + // Set pointer for next thread stack. Reserve 8M for main stack. + next_thread_stack_base = stack_base - (8 * 1024 * 1024); // load up symbols, if any... these may be used for debugging or // profiling. @@ -294,17 +299,15 @@ LiveProcess::LiveProcess(const string &nm, ObjectFile *objFile, debugSymbolTable = NULL; } } +} - // Set up stack. On Alpha, stack goes below text section. This - // code should get moved to some architecture-specific spot. - stack_base = text_base - (409600+4096); - - // Set up region for mmaps. Tru64 seems to start just above 0 and - // grow up from there. - mmap_start = mmap_end = 0x10000; +void +LiveProcess::startup() +{ + Process::startup(); - // Set pointer for next thread stack. Reserve 8M for main stack. - next_thread_stack_base = stack_base - (8 * 1024 * 1024); + // load object file into target memory + objFile->loadSections(initVirtMem); // Calculate how much space we need for arg & env arrays. int argv_array_size = sizeof(Addr) * (argv.size() + 1); @@ -329,6 +332,9 @@ LiveProcess::LiveProcess(const string &nm, ObjectFile *objFile, // align it stack_min &= ~7; stack_size = stack_base - stack_min; + // map memory + pTable->allocate(roundDown(stack_min, VMPageSize), + roundUp(stack_size, VMPageSize)); // map out initial stack contents Addr argv_array_base = stack_min + sizeof(uint64_t); // room for argc @@ -339,17 +345,19 @@ LiveProcess::LiveProcess(const string &nm, ObjectFile *objFile, // write contents to stack uint64_t argc = argv.size(); argc = htog(argc); - memory->access(Write, stack_min, &argc, sizeof(uint64_t)); + initVirtMem->writeBlobFunctional(stack_min, (uint8_t*)&argc, sizeof(uint64_t)); - copyStringArray(argv, argv_array_base, arg_data_base, memory); - copyStringArray(envp, envp_array_base, env_data_base, memory); + copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem); + copyStringArray(envp, envp_array_base, env_data_base, initVirtMem); - init_regs->intRegFile[ArgumentReg0] = argc; - init_regs->intRegFile[ArgumentReg1] = argv_array_base; - init_regs->intRegFile[StackPointerReg] = stack_min; - init_regs->intRegFile[GlobalPointerReg] = objFile->globalPointer(); - init_regs->pc = prog_entry; - init_regs->npc = prog_entry + sizeof(MachInst); + execContexts[0]->setIntReg(ArgumentReg0, argc); + execContexts[0]->setIntReg(ArgumentReg1, argv_array_base); + execContexts[0]->setIntReg(StackPointerReg, stack_min); + execContexts[0]->setIntReg(GlobalPointerReg, objFile->globalPointer()); + execContexts[0]->setPC(prog_entry); + execContexts[0]->setNextPC(prog_entry + sizeof(MachInst)); + + num_processes++; } void @@ -367,7 +375,7 @@ LiveProcess::syscall(ExecContext *xc) } LiveProcess * -LiveProcess::create(const string &nm, +LiveProcess::create(const string &nm, System *system, int stdin_fd, int stdout_fd, int stderr_fd, string executable, vector<string> &argv, vector<string> &envp) @@ -379,12 +387,10 @@ LiveProcess::create(const string &nm, } // set up syscall emulation pointer for the current ISA - process = createProcess(nm, objFile, + process = createProcess(nm, objFile, system, stdin_fd, stdout_fd, stderr_fd, argv, envp); - delete objFile; - if (process == NULL) fatal("Unknown error creating process object."); @@ -400,6 +406,7 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(LiveProcess) Param<string> input; Param<string> output; VectorParam<string> env; + SimObjectParam<System *> system; END_DECLARE_SIM_OBJECT_PARAMS(LiveProcess) @@ -410,7 +417,8 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(LiveProcess) INIT_PARAM(executable, "executable (overrides cmd[0] if set)"), INIT_PARAM(input, "filename for stdin (dflt: use sim stdin)"), INIT_PARAM(output, "filename for stdout/stderr (dflt: use sim stdout)"), - INIT_PARAM(env, "environment settings") + INIT_PARAM(env, "environment settings"), + INIT_PARAM(system, "system") END_INIT_SIM_OBJECT_PARAMS(LiveProcess) @@ -437,7 +445,7 @@ CREATE_SIM_OBJECT(LiveProcess) stderr_fd = (stdout_fd != STDOUT_FILENO) ? stdout_fd : STDERR_FILENO; - return LiveProcess::create(getInstanceName(), + return LiveProcess::create(getInstanceName(), system, stdin_fd, stdout_fd, stderr_fd, (string)executable == "" ? cmd[0] : executable, cmd, env); diff --git a/sim/process.hh b/sim/process.hh index 3a48f128c..fc600fb06 100644 --- a/sim/process.hh +++ b/sim/process.hh @@ -41,15 +41,21 @@ #include <vector> #include "arch/isa_traits.hh" -#include "sim/sim_object.hh" -#include "sim/stats.hh" #include "base/statistics.hh" #include "base/trace.hh" +#include "mem/memory.hh" +//#include "mem/mem_interface.hh" +#include "mem/page_table.hh" +#include "sim/sim_object.hh" +#include "sim/stats.hh" +#include "targetarch/isa_traits.hh" class CPUExecContext; class ExecContext; -class FunctionalMemory; class SyscallDesc; +class TranslatingPort; +class System; + class Process : public SimObject { protected: @@ -57,6 +63,10 @@ class Process : public SimObject typedef TheISA::MachInst MachInst; public: + /// Pointer to object representing the system this process is + /// running on. + System *system; + // have we initialized an execution context from this process? If // yes, subsequent contexts are assumed to be for dynamically // created threads and are not initialized. @@ -76,16 +86,12 @@ class Process : public SimObject WaitRec(Addr chan, ExecContext *ctx) : waitChan(chan), waitingContext(ctx) - { - } + { } }; // list of all blocked contexts std::list<WaitRec> waitList; - RegFile *init_regs; // initial register contents - CPUExecContext *cpuXC; // XC to hold the init_regs - Addr text_base; // text (code) segment base unsigned text_size; // text (code) size in bytes @@ -118,6 +124,7 @@ class Process : public SimObject protected: // constructor Process(const std::string &nm, + System *_system, int stdin_fd, // initial I/O descriptors int stdout_fd, int stderr_fd); @@ -126,7 +133,11 @@ class Process : public SimObject virtual void startup(); protected: - FunctionalMemory *memory; + /// Memory object for initialization (image loading) + TranslatingPort *initVirtMem; + + public: + PageTable *pTable; private: // file descriptor remapping support @@ -181,8 +192,6 @@ class Process : public SimObject } virtual void syscall(ExecContext *xc) = 0; - - virtual FunctionalMemory *getMemory() { return memory; } }; // @@ -192,16 +201,23 @@ class ObjectFile; class LiveProcess : public Process { protected: + ObjectFile *objFile; + std::vector<std::string> argv; + std::vector<std::string> envp; + LiveProcess(const std::string &nm, ObjectFile *objFile, - int stdin_fd, int stdout_fd, int stderr_fd, + System *_system, int stdin_fd, int stdout_fd, int stderr_fd, std::vector<std::string> &argv, std::vector<std::string> &envp); + void startup(); + public: // this function is used to create the LiveProcess object, since // we can't tell which subclass of LiveProcess to use until we // open and look at the object file. static LiveProcess *create(const std::string &nm, + System *_system, int stdin_fd, int stdout_fd, int stderr_fd, std::string executable, std::vector<std::string> &argv, diff --git a/sim/syscall_emul.cc b/sim/syscall_emul.cc index 00168b025..1d0b3a375 100644 --- a/sim/syscall_emul.cc +++ b/sim/syscall_emul.cc @@ -130,7 +130,7 @@ readFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) int bytes_read = read(fd, bufArg.bufferPtr(), nbytes); if (bytes_read != -1) - bufArg.copyOut(xc->getMemPtr()); + bufArg.copyOut(xc->port); return bytes_read; } @@ -142,7 +142,7 @@ writeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) int nbytes = xc->getSyscallArg(2); BufferArg bufArg(xc->getSyscallArg(1), nbytes); - bufArg.copyIn(xc->getMemPtr()); + bufArg.copyIn(xc->port); int bytes_written = write(fd, bufArg.bufferPtr(), nbytes); @@ -183,7 +183,7 @@ gethostnameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) strncpy((char *)name.bufferPtr(), hostname, name_len); - name.copyOut(xc->getMemPtr()); + name.copyOut(xc->port); return 0; } @@ -193,7 +193,7 @@ unlinkFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) { string path; - if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault) + if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != NoFault) return (TheISA::IntReg)-EFAULT; int result = unlink(path.c_str()); @@ -205,12 +205,12 @@ renameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) { string old_name; - if (xc->getMemPtr()->readString(old_name, xc->getSyscallArg(0)) != NoFault) + if (xc->port->readStringFunctional(old_name, xc->getSyscallArg(0)) != NoFault) return -EFAULT; string new_name; - if (xc->getMemPtr()->readString(new_name, xc->getSyscallArg(1)) != NoFault) + if (xc->port->readStringFunctional(new_name, xc->getSyscallArg(1)) != NoFault) return -EFAULT; int64_t result = rename(old_name.c_str(), new_name.c_str()); @@ -222,7 +222,7 @@ truncateFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) { string path; - if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault) + if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != NoFault) return -EFAULT; off_t length = xc->getSyscallArg(1); @@ -250,7 +250,7 @@ chownFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) { string path; - if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault) + if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != NoFault) return -EFAULT; /* XXX endianess */ diff --git a/sim/syscall_emul.hh b/sim/syscall_emul.hh index 35129bcb4..25f8c6cb8 100644 --- a/sim/syscall_emul.hh +++ b/sim/syscall_emul.hh @@ -46,11 +46,12 @@ #include <sys/uio.h> #include "base/intmath.hh" // for RoundUp -#include "mem/functional/functional.hh" +#include "mem/translating_port.hh" #include "arch/isa_traits.hh" // for Addr #include "base/trace.hh" #include "cpu/exec_context.hh" +#include "cpu/base.hh" #include "sim/process.hh" /// @@ -106,18 +107,18 @@ class BaseBufferArg { // // copy data into simulator space (read from target memory) // - virtual bool copyIn(FunctionalMemory *mem) + virtual bool copyIn(TranslatingPort *memport) { - mem->access(Read, addr, bufPtr, size); + memport->readBlobFunctional(addr, bufPtr, size); return true; // no EFAULT detection for now } // // copy data out of simulator space (write to target memory) // - virtual bool copyOut(FunctionalMemory *mem) + virtual bool copyOut(TranslatingPort *memport) { - mem->access(Write, addr, bufPtr, size); + memport->writeBlobFunctional(addr, bufPtr, size); return true; // no EFAULT detection for now } @@ -369,7 +370,7 @@ openFunc(SyscallDesc *desc, int callnum, Process *process, { std::string path; - if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault) + if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != NoFault) return -EFAULT; if (path == "/dev/sysdev0") { @@ -416,7 +417,7 @@ chmodFunc(SyscallDesc *desc, int callnum, Process *process, { std::string path; - if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault) + if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != NoFault) return -EFAULT; uint32_t mode = xc->getSyscallArg(1); @@ -469,8 +470,8 @@ statFunc(SyscallDesc *desc, int callnum, Process *process, { std::string path; - if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault) - return -EFAULT; + if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != NoFault) + return -EFAULT; struct stat hostBuf; int result = stat(path.c_str(), &hostBuf); @@ -478,7 +479,7 @@ statFunc(SyscallDesc *desc, int callnum, Process *process, if (result < 0) return -errno; - OS::copyOutStatBuf(xc->getMemPtr(), xc->getSyscallArg(1), &hostBuf); + OS::copyOutStatBuf(xc->port, xc->getSyscallArg(1), &hostBuf); return 0; } @@ -507,7 +508,7 @@ fstat64Func(SyscallDesc *desc, int callnum, Process *process, if (result < 0) return -errno; - OS::copyOutStat64Buf(xc->getMemPtr(), fd, xc->getSyscallArg(1), &hostBuf); + OS::copyOutStat64Buf(xc->port, fd, xc->getSyscallArg(1), &hostBuf); return 0; } @@ -521,8 +522,8 @@ lstatFunc(SyscallDesc *desc, int callnum, Process *process, { std::string path; - if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault) - return -EFAULT; + if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != NoFault) + return -EFAULT; struct stat hostBuf; int result = lstat(path.c_str(), &hostBuf); @@ -530,7 +531,7 @@ lstatFunc(SyscallDesc *desc, int callnum, Process *process, if (result < 0) return -errno; - OS::copyOutStatBuf(xc->getMemPtr(), xc->getSyscallArg(1), &hostBuf); + OS::copyOutStatBuf(xc->port, xc->getSyscallArg(1), &hostBuf); return 0; } @@ -543,8 +544,8 @@ lstat64Func(SyscallDesc *desc, int callnum, Process *process, { std::string path; - if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault) - return -EFAULT; + if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != NoFault) + return -EFAULT; #if BSD_HOST struct stat hostBuf; @@ -557,7 +558,7 @@ lstat64Func(SyscallDesc *desc, int callnum, Process *process, if (result < 0) return -errno; - OS::copyOutStat64Buf(xc->getMemPtr(), -1, xc->getSyscallArg(1), &hostBuf); + OS::copyOutStat64Buf(xc->port, -1, xc->getSyscallArg(1), &hostBuf); return 0; } @@ -581,7 +582,8 @@ fstatFunc(SyscallDesc *desc, int callnum, Process *process, if (result < 0) return -errno; - OS::copyOutStatBuf(xc->getMemPtr(), xc->getSyscallArg(1), &hostBuf); + OS::copyOutStatBuf(xc->port, xc->getSyscallArg(1), &hostBuf); + return 0; } @@ -594,8 +596,8 @@ statfsFunc(SyscallDesc *desc, int callnum, Process *process, { std::string path; - if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault) - return -EFAULT; + if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != NoFault) + return -EFAULT; struct statfs hostBuf; int result = statfs(path.c_str(), &hostBuf); @@ -603,7 +605,7 @@ statfsFunc(SyscallDesc *desc, int callnum, Process *process, if (result < 0) return -errno; - OS::copyOutStatfsBuf(xc->getMemPtr(), xc->getSyscallArg(1), &hostBuf); + OS::copyOutStatfsBuf(xc->port, xc->getSyscallArg(1), &hostBuf); return 0; } @@ -626,7 +628,7 @@ fstatfsFunc(SyscallDesc *desc, int callnum, Process *process, if (result < 0) return -errno; - OS::copyOutStatfsBuf(xc->getMemPtr(), xc->getSyscallArg(1), &hostBuf); + OS::copyOutStatfsBuf(xc->port, xc->getSyscallArg(1), &hostBuf); return 0; } @@ -650,12 +652,12 @@ writevFunc(SyscallDesc *desc, int callnum, Process *process, for (int i = 0; i < count; ++i) { typename OS::tgt_iovec tiov; - xc->getMemPtr()->access(Read, tiov_base + i*sizeof(typename OS::tgt_iovec), + xc->port->readBlobFunctional(tiov_base + i*sizeof(typename OS::tgt_iovec),(uint8_t*) &tiov, sizeof(typename OS::tgt_iovec)); hiov[i].iov_len = gtoh(tiov.iov_len); hiov[i].iov_base = new char [hiov[i].iov_len]; - xc->getMemPtr()->access(Read, gtoh(tiov.iov_base), - hiov[i].iov_base, hiov[i].iov_len); + xc->port->readBlobFunctional(gtoh(tiov.iov_base), + (uint8_t *)hiov[i].iov_base, hiov[i].iov_len); } int result = writev(process->sim_fd(fd), hiov, count); @@ -737,7 +739,7 @@ getrlimitFunc(SyscallDesc *desc, int callnum, Process *process, break; } - rlp.copyOut(xc->getMemPtr()); + rlp.copyOut(xc->port); return 0; } @@ -754,7 +756,7 @@ gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process, tp->tv_sec = htog(tp->tv_sec); tp->tv_usec = htog(tp->tv_usec); - tp.copyOut(xc->getMemPtr()); + tp.copyOut(xc->port); return 0; } @@ -768,11 +770,11 @@ utimesFunc(SyscallDesc *desc, int callnum, Process *process, { std::string path; - if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault) - return -EFAULT; + if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != NoFault) + return -EFAULT; TypedBufferArg<typename OS::timeval [2]> tp(xc->getSyscallArg(1)); - tp.copyIn(xc->getMemPtr()); + tp.copyIn(xc->port); struct timeval hostTimeval[2]; for (int i = 0; i < 2; ++i) @@ -824,7 +826,7 @@ getrusageFunc(SyscallDesc *desc, int callnum, Process *process, rup->ru_nvcsw = 0; rup->ru_nivcsw = 0; - rup.copyOut(xc->getMemPtr()); + rup.copyOut(xc->port); return 0; } diff --git a/sim/system.cc b/sim/system.cc index 8820922c1..3ed7ed590 100644 --- a/sim/system.cc +++ b/sim/system.cc @@ -1,16 +1,19 @@ #include "base/loader/object_file.hh" #include "base/loader/symtab.hh" -#include "base/remote_gdb.hh" #include "cpu/exec_context.hh" -#include "kern/kernel_stats.hh" -#include "mem/functional/memory_control.hh" -#include "mem/functional/physical.hh" #include "arch/vtophys.hh" +#include "mem/memory.hh" #include "sim/builder.hh" #include "arch/isa_traits.hh" #include "sim/byteswap.hh" #include "sim/system.hh" #include "base/trace.hh" +#if FULL_SYSTEM +#include "base/remote_gdb.hh" +#include "kern/kernel_stats.hh" +#include "mem/functional/memory_control.hh" +#include "targetarch/vtophys.hh" +#endif using namespace std; using namespace TheISA; @@ -20,12 +23,18 @@ vector<System *> System::systemList; int System::numSystemsRunning = 0; System::System(Params *p) - : SimObject(p->name), memctrl(p->memctrl), physmem(p->physmem), - init_param(p->init_param), numcpus(0), _params(p) + : SimObject(p->name), physmem(p->physmem), numcpus(0), +#if FULL_SYSTEM + memctrl(p->memctrl), init_param(p->init_param), +#else + page_ptr(0), +#endif + _params(p) { // add self to global system list systemList.push_back(this); +#if FULL_SYSTEM kernelSymtab = new SymbolTable; debugSymbolTable = new SymbolTable; @@ -63,25 +72,34 @@ System::System(Params *p) DPRINTF(Loader, "Kernel entry = %#x\n", kernelEntry); DPRINTF(Loader, "Kernel loaded...\n"); +#if FULL_SYSTEM + kernelBinning = new Kernel::Binning(this); +#endif // FULL_SYSTEM + // increment the number of running systms numSystemsRunning++; - - kernelBinning = new Kernel::Binning(this); } System::~System() { +#if FULL_SYSTEM delete kernelSymtab; delete kernel; delete kernelBinning; +#else + panic("System::fixFuncEventAddr needs to be rewritten " + "to work with syscall emulation"); +#endif // FULL_SYSTEM} } - +#if FULL_SYSTEM int rgdb_wait = -1; +#endif // FULL_SYSTEM + int System::registerExecContext(ExecContext *xc, int id) { @@ -101,6 +119,7 @@ System::registerExecContext(ExecContext *xc, int id) execContexts[id] = xc; numcpus++; +#if FULL_SYSTEM RemoteGDB *rgdb = new RemoteGDB(this, xc); GDBListener *gdbl = new GDBListener(rgdb, 7000 + id); gdbl->listen(); @@ -116,6 +135,7 @@ System::registerExecContext(ExecContext *xc, int id) } remoteGDB[id] = rgdb; +#endif // FULL_SYSTEM return id; } @@ -137,30 +157,48 @@ System::replaceExecContext(ExecContext *xc, int id) } execContexts[id] = xc; +#if FULL_SYSTEM remoteGDB[id]->replaceExecContext(xc); +#endif // FULL_SYSTEM +} + +#if !FULL_SYSTEM +Addr +System::new_page() +{ + Addr return_addr = page_ptr << LogVMPageSize; + ++page_ptr; + return return_addr; } +#endif void System::regStats() { +#if FULL_SYSTEM kernelBinning->regStats(name() + ".kern"); +#endif // FULL_SYSTEM } void System::serialize(ostream &os) { +#if FULL_SYSTEM kernelBinning->serialize(os); kernelSymtab->serialize("kernel_symtab", os); +#endif // FULL_SYSTEM } void System::unserialize(Checkpoint *cp, const string §ion) { +#if FULL_SYSTEM kernelBinning->unserialize(cp, section); kernelSymtab->unserialize("kernel_symtab", cp, section); +#endif // FULL_SYSTEM } void diff --git a/sim/system.hh b/sim/system.hh index ea482a102..cbe876c42 100644 --- a/sim/system.hh +++ b/sim/system.hh @@ -35,27 +35,29 @@ #include "base/statistics.hh" #include "base/loader/symtab.hh" #include "cpu/pc_event.hh" -#include "kern/system_events.hh" #include "sim/sim_object.hh" +#if FULL_SYSTEM +#include "kern/system_events.hh" +#endif class BaseCPU; class ExecContext; -class GDBListener; class MemoryController; class ObjectFile; -class PhysicalMemory; +class Memory; + +#if FULL_SYSTEM class Platform; +class GDBListener; class RemoteGDB; namespace Kernel { class Binning; } +#endif class System : public SimObject { public: - MemoryController *memctrl; - PhysicalMemory *physmem; - Platform *platform; + Memory *physmem; PCEventQueue pcEventQueue; - uint64_t init_param; std::vector<ExecContext *> execContexts; int numcpus; @@ -68,6 +70,11 @@ class System : public SimObject return numcpus; } +#if FULL_SYSTEM + MemoryController *memctrl; + Platform *platform; + uint64_t init_param; + /** kernel symbol table */ SymbolTable *kernelSymtab; @@ -85,6 +92,13 @@ class System : public SimObject Kernel::Binning *kernelBinning; +#else + + int page_ptr; + + +#endif // FULL_SYSTEM + protected: /** @@ -111,6 +125,7 @@ class System : public SimObject return NULL; } +#if FULL_SYSTEM /** Add a function-based event to kernel code. */ template <class T> T *System::addKernelFuncEvent(const char *lbl) @@ -118,18 +133,23 @@ class System : public SimObject return addFuncEvent<T>(kernelSymtab, lbl); } +#endif public: +#if FULL_SYSTEM std::vector<RemoteGDB *> remoteGDB; std::vector<GDBListener *> gdbListen; virtual bool breakpoint() = 0; +#endif // FULL_SYSTEM public: struct Params { std::string name; + Memory *physmem; + +#if FULL_SYSTEM Tick boot_cpu_frequency; MemoryController *memctrl; - PhysicalMemory *physmem; uint64_t init_param; bool bin; std::vector<std::string> binned_fns; @@ -137,6 +157,7 @@ class System : public SimObject std::string kernel_path; std::string readfile; +#endif }; protected: @@ -151,6 +172,8 @@ class System : public SimObject const Params *params() const { return (const Params *)_params; } public: + +#if FULL_SYSTEM /** * Returns the addess the kernel starts at. * @return address the kernel starts at @@ -169,6 +192,12 @@ class System : public SimObject */ Addr getKernelEntry() const { return kernelEntry; } +#else + + Addr new_page(); + +#endif // FULL_SYSTEM + int registerExecContext(ExecContext *xc, int xcIndex); void replaceExecContext(ExecContext *xc, int xcIndex); |