CPU: Add readBytes and writeBytes functions to the exec contexts.
[gem5.git] / src / cpu / base_dyn_inst.hh
index f58bf7cf855ed832f39e8b227bef43d4c5e8e685..3ecec0f0cf2dd5e778de5b069fa04403c9e2c7e4 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004-2006 The Regents of The University of Michigan
+ * Copyright (c) 2009 The University of Edinburgh
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,6 +27,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * Authors: Kevin Lim
+ *          Timothy M. Jones
  */
 
 #ifndef __CPU_BASE_DYN_INST_HH__
 #include "base/fast_alloc.hh"
 #include "base/trace.hh"
 #include "config/full_system.hh"
+#include "config/the_isa.hh"
 #include "cpu/o3/comm.hh"
 #include "cpu/exetrace.hh"
 #include "cpu/inst_seq.hh"
 #include "cpu/op_class.hh"
 #include "cpu/static_inst.hh"
+#include "cpu/translation.hh"
 #include "mem/packet.hh"
 #include "sim/system.hh"
+#include "sim/tlb.hh"
 
 /**
  * @file
@@ -115,6 +120,8 @@ class BaseDynInst : public FastAlloc, public RefCounted
     template <class T>
     Fault read(Addr addr, T &data, unsigned flags);
 
+    Fault readBytes(Addr addr, uint8_t *data, unsigned size, unsigned flags);
+
     /**
      * Does a write to a given address.
      * @param data The data to be written.
@@ -124,8 +131,22 @@ class BaseDynInst : public FastAlloc, public RefCounted
      * @return Returns any fault due to the write.
      */
     template <class T>
-    Fault write(T data, Addr addr, unsigned flags,
-                        uint64_t *res);
+    Fault write(T data, Addr addr, unsigned flags, uint64_t *res);
+
+    Fault writeBytes(uint8_t *data, unsigned size,
+                     Addr addr, unsigned flags, uint64_t *res);
+
+    /** Splits a request in two if it crosses a dcache block. */
+    void splitRequest(RequestPtr req, RequestPtr &sreqLow,
+                      RequestPtr &sreqHigh);
+
+    /** Initiate a DTB address translation. */
+    void initiateTranslation(RequestPtr req, RequestPtr sreqLow,
+                             RequestPtr sreqHigh, uint64_t *res,
+                             BaseTLB::Mode mode);
+
+    /** Finish a DTB address translation. */
+    void finishTranslation(WholeTranslationState *state);
 
     void prefetch(Addr addr, unsigned flags);
     void writeHint(Addr addr, int size, unsigned flags);
@@ -167,7 +188,7 @@ class BaseDynInst : public FastAlloc, public RefCounted
     std::bitset<NumStatus> status;
 
     /** The thread this instruction is from. */
-    short threadNumber;
+    ThreadID threadNumber;
 
     /** data address space ID, for loads & stores. */
     short asid;
@@ -777,7 +798,7 @@ class BaseDynInst : public FastAlloc, public RefCounted
     void setASID(short addr_space_id) { asid = addr_space_id; }
 
     /** Sets the thread id. */
-    void setTid(unsigned tid) { threadNumber = tid; }
+    void setTid(ThreadID tid) { threadNumber = tid; }
 
     /** Sets the pointer to the thread state. */
     void setThreadState(ImplState *state) { thread = state; }
@@ -851,51 +872,35 @@ class BaseDynInst : public FastAlloc, public RefCounted
 };
 
 template<class Impl>
-template<class T>
-inline Fault
-BaseDynInst<Impl>::read(Addr addr, T &data, unsigned flags)
+Fault
+BaseDynInst<Impl>::readBytes(Addr addr, uint8_t *data,
+                             unsigned size, unsigned flags)
 {
     reqMade = true;
-    Request *req = new Request();
-    req->setVirt(asid, addr, sizeof(T), flags, this->PC);
-    req->setThreadContext(thread->contextId(), threadNumber);
+    Request *req = new Request(asid, addr, size, flags, this->PC,
+                               thread->contextId(), threadNumber);
 
-    fault = cpu->dtb->translate(req, thread->getTC(), false);
+    Request *sreqLow = NULL;
+    Request *sreqHigh = NULL;
 
-    if (req->isUncacheable())
-        isUncacheable = true;
+    // Only split the request if the ISA supports unaligned accesses.
+    if (TheISA::HasUnalignedMemAcc) {
+        splitRequest(req, sreqLow, sreqHigh);
+    }
+    initiateTranslation(req, sreqLow, sreqHigh, NULL, BaseTLB::Read);
 
     if (fault == NoFault) {
         effAddr = req->getVaddr();
         effAddrValid = true;
-        physEffAddr = req->getPaddr();
-        memReqFlags = req->getFlags();
-
-#if 0
-        if (cpu->system->memctrl->badaddr(physEffAddr)) {
-            fault = TheISA::genMachineCheckFault();
-            data = (T)-1;
-            this->setExecuted();
-        } else {
-            fault = cpu->read(req, data, lqIdx);
-        }
-#else
-        fault = cpu->read(req, data, lqIdx);
-#endif
+        fault = cpu->read(req, sreqLow, sreqHigh, data, lqIdx);
     } else {
-        // Return a fixed value to keep simulation deterministic even
-        // along misspeculated paths.
-        data = (T)-1;
-
         // Commit will have to clean up whatever happened.  Set this
         // instruction as executed.
         this->setExecuted();
-        delete req;
     }
 
     if (traceData) {
         traceData->setAddr(addr);
-        traceData->setData(data);
     }
 
     return fault;
@@ -904,47 +909,135 @@ BaseDynInst<Impl>::read(Addr addr, T &data, unsigned flags)
 template<class Impl>
 template<class T>
 inline Fault
-BaseDynInst<Impl>::write(T data, Addr addr, unsigned flags, uint64_t *res)
+BaseDynInst<Impl>::read(Addr addr, T &data, unsigned flags)
 {
+    Fault fault = readBytes(addr, (uint8_t *)&data, sizeof(T), flags);
+
+    if (fault != NoFault) {
+        // Return a fixed value to keep simulation deterministic even
+        // along misspeculated paths.
+        data = (T)-1;
+    }
+    data = TheISA::gtoh(data);
+
     if (traceData) {
-        traceData->setAddr(addr);
         traceData->setData(data);
     }
 
+    return fault;
+}
+
+template<class Impl>
+Fault
+BaseDynInst<Impl>::writeBytes(uint8_t *data, unsigned size,
+                              Addr addr, unsigned flags, uint64_t *res)
+{
+    if (traceData) {
+        traceData->setAddr(addr);
+    }
+
     reqMade = true;
-    Request *req = new Request();
-    req->setVirt(asid, addr, sizeof(T), flags, this->PC);
-    req->setThreadContext(thread->contextId(), threadNumber);
+    Request *req = new Request(asid, addr, size, flags, this->PC,
+                               thread->contextId(), threadNumber);
 
-    fault = cpu->dtb->translate(req, thread->getTC(), true);
+    Request *sreqLow = NULL;
+    Request *sreqHigh = NULL;
 
-    if (req->isUncacheable())
-        isUncacheable = true;
+    // Only split the request if the ISA supports unaligned accesses.
+    if (TheISA::HasUnalignedMemAcc) {
+        splitRequest(req, sreqLow, sreqHigh);
+    }
+    initiateTranslation(req, sreqLow, sreqHigh, res, BaseTLB::Write);
 
     if (fault == NoFault) {
         effAddr = req->getVaddr();
         effAddrValid = true;
-        physEffAddr = req->getPaddr();
-        memReqFlags = req->getFlags();
+        fault = cpu->write(req, sreqLow, sreqHigh, data, sqIdx);
+    }
 
-        if (req->isCondSwap()) {
-            assert(res);
-            req->setExtraData(*res);
-        }
-#if 0
-        if (cpu->system->memctrl->badaddr(physEffAddr)) {
-            fault = TheISA::genMachineCheckFault();
-        } else {
-            fault = cpu->write(req, data, sqIdx);
-        }
-#else
-        fault = cpu->write(req, data, sqIdx);
-#endif
+    return fault;
+}
+
+template<class Impl>
+template<class T>
+inline Fault
+BaseDynInst<Impl>::write(T data, Addr addr, unsigned flags, uint64_t *res)
+{
+    if (traceData) {
+        traceData->setData(data);
+    }
+    data = TheISA::htog(data);
+    return writeBytes((uint8_t *)&data, sizeof(T), addr, flags, res);
+}
+
+template<class Impl>
+inline void
+BaseDynInst<Impl>::splitRequest(RequestPtr req, RequestPtr &sreqLow,
+                                RequestPtr &sreqHigh)
+{
+    // Check to see if the request crosses the next level block boundary.
+    unsigned block_size = cpu->getDcachePort()->peerBlockSize();
+    Addr addr = req->getVaddr();
+    Addr split_addr = roundDown(addr + req->getSize() - 1, block_size);
+    assert(split_addr <= addr || split_addr - addr < block_size);
+
+    // Spans two blocks.
+    if (split_addr > addr) {
+        req->splitOnVaddr(split_addr, sreqLow, sreqHigh);
+    }
+}
+
+template<class Impl>
+inline void
+BaseDynInst<Impl>::initiateTranslation(RequestPtr req, RequestPtr sreqLow,
+                                       RequestPtr sreqHigh, uint64_t *res,
+                                       BaseTLB::Mode mode)
+{
+    if (!TheISA::HasUnalignedMemAcc || sreqLow == NULL) {
+        WholeTranslationState *state =
+            new WholeTranslationState(req, NULL, res, mode);
+
+        // One translation if the request isn't split.
+        DataTranslation<BaseDynInst<Impl> > *trans =
+            new DataTranslation<BaseDynInst<Impl> >(this, state);
+        cpu->dtb->translateTiming(req, thread->getTC(), trans, mode);
     } else {
-        delete req;
+        WholeTranslationState *state =
+            new WholeTranslationState(req, sreqLow, sreqHigh, NULL, res, mode);
+
+        // Two translations when the request is split.
+        DataTranslation<BaseDynInst<Impl> > *stransLow =
+            new DataTranslation<BaseDynInst<Impl> >(this, state, 0);
+        DataTranslation<BaseDynInst<Impl> > *stransHigh =
+            new DataTranslation<BaseDynInst<Impl> >(this, state, 1);
+
+        cpu->dtb->translateTiming(sreqLow, thread->getTC(), stransLow, mode);
+        cpu->dtb->translateTiming(sreqHigh, thread->getTC(), stransHigh, mode);
     }
+}
 
-    return fault;
+template<class Impl>
+inline void
+BaseDynInst<Impl>::finishTranslation(WholeTranslationState *state)
+{
+    fault = state->getFault();
+
+    if (state->isUncacheable())
+        isUncacheable = true;
+
+    if (fault == NoFault) {
+        physEffAddr = state->getPaddr();
+        memReqFlags = state->getFlags();
+
+        if (state->mainReq->isCondSwap()) {
+            assert(state->res);
+            state->mainReq->setExtraData(*state->res);
+        }
+
+    } else {
+        state->deleteReqs();
+    }
+    delete state;
 }
 
 #endif // __CPU_BASE_DYN_INST_HH__