fastmodel: Implement PC based events.
authorGabe Black <gabeblack@google.com>
Wed, 23 Oct 2019 04:42:51 +0000 (21:42 -0700)
committerGabe Black <gabeblack@google.com>
Mon, 23 Dec 2019 20:57:59 +0000 (20:57 +0000)
These use the IRIS breakpoint API to stop the models at the appropriate
points. There seems to be a slightly wonky interaction between
breakpoints and stepping, where if you stop at a breakpoint and then
step, you might end up moving forward more than the number of requested
instructions.

Change-Id: I31f13a120cfc1ad2ec3669ee8befd6d21b328bb2
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/22122
Reviewed-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Maintainer: Giacomo Travaglini <giacomo.travaglini@arm.com>
Tested-by: kokoro <noreply+kokoro@google.com>
src/arch/arm/fastmodel/iris/thread_context.cc
src/arch/arm/fastmodel/iris/thread_context.hh

index 00c41ba9c90ccd723cbce01fd77837998cd14f3a..8721366159501331b066e0eede52dae2b606bb48 100644 (file)
@@ -29,6 +29,8 @@
 
 #include "arch/arm/fastmodel/iris/thread_context.hh"
 
+#include <utility>
+
 #include "iris/detail/IrisCppAdapter.h"
 #include "iris/detail/IrisObjects.h"
 #include "mem/fs_translating_port_proxy.hh"
@@ -48,6 +50,19 @@ ThreadContext::initFromIrisInstance(const ResourceMap &resources)
 
     call().memory_getMemorySpaces(_instId, memorySpaces);
     call().memory_getUsefulAddressTranslations(_instId, translations);
+
+    typedef ThreadContext Self;
+    iris::EventSourceInfo evSrcInfo;
+
+    client.registerEventCallback<Self, &Self::breakpointHit>(
+            this, "ec_IRIS_BREAKPOINT_HIT",
+            "Handle hitting a breakpoint", "Iris::ThreadContext");
+    call().event_getEventSource(_instId, evSrcInfo, "IRIS_BREAKPOINT_HIT");
+    call().eventStream_create(_instId, breakpointEventStreamId,
+            evSrcInfo.evSrcId, client.getInstId());
+
+    for (auto it = bps.begin(); it != bps.end(); it++)
+        installBp(it);
 }
 
 iris::ResourceId
@@ -102,6 +117,47 @@ ThreadContext::maintainStepping()
     }
 }
 
+ThreadContext::BpInfoIt
+ThreadContext::getOrAllocBp(Addr pc)
+{
+    auto pc_it = bps.find(pc);
+
+    if (pc_it != bps.end())
+        return pc_it;
+
+    auto res = bps.emplace(std::make_pair(pc, new BpInfo(pc)));
+    panic_if(!res.second, "Inserting breakpoint failed.");
+    return res.first;
+}
+
+void
+ThreadContext::installBp(BpInfoIt it)
+{
+    BpId id;
+    // Hard code address space 5 for now.
+    call().breakpoint_set_code(_instId, id, it->second->pc, 5, 0, true);
+    it->second->id = id;
+}
+
+void
+ThreadContext::uninstallBp(BpInfoIt it)
+{
+    call().breakpoint_delete(_instId, it->second->id);
+    it->second->clearId();
+}
+
+void
+ThreadContext::delBp(BpInfoIt it)
+{
+    panic_if(!it->second->empty(),
+             "BP info still had events associated with it.");
+
+    if (it->second->validId())
+        uninstallBp(it);
+
+    bps.erase(it);
+}
+
 iris::IrisErrorCode
 ThreadContext::instanceRegistryChanged(
         uint64_t esId, const iris::IrisValueMap &fields, uint64_t time,
@@ -163,6 +219,26 @@ ThreadContext::simulationTimeEvent(
     return iris::E_ok;
 }
 
+iris::IrisErrorCode
+ThreadContext::breakpointHit(
+        uint64_t esId, const iris::IrisValueMap &fields, uint64_t time,
+        uint64_t sInstId, bool syncEc, std::string &error_message_out)
+{
+    Addr pc = fields.at("PC").getU64();
+
+    auto it = getOrAllocBp(pc);
+
+    auto e_it = it->second->events.begin();
+    while (e_it != it->second->events.end()) {
+        PCEvent *e = *e_it;
+        // Advance e_it here since e might remove itself from the list.
+        e_it++;
+        e->process(this);
+    }
+
+    return iris::E_ok;
+}
+
 ThreadContext::ThreadContext(
         BaseCPU *cpu, int id, System *system, ::BaseTLB *dtb, ::BaseTLB *itb,
         iris::IrisConnectionInterface *iris_if, const std::string &iris_path) :
@@ -216,6 +292,8 @@ ThreadContext::ThreadContext(
     call().eventStream_create(
             iris::IrisInstIdSimulationEngine, timeEventStreamId,
             evSrcInfo.evSrcId, client.getInstId());
+
+    breakpointEventStreamId = iris::IRIS_UINT64_MAX;
 }
 
 ThreadContext::~ThreadContext()
@@ -236,6 +314,30 @@ ThreadContext::~ThreadContext()
     client.unregisterEventCallback("ec_IRIS_SIMULATION_TIME_EVENT");
 }
 
+bool
+ThreadContext::schedule(PCEvent *e)
+{
+    auto it = getOrAllocBp(e->pc());
+    it->second->events.push_back(e);
+
+    if (_instId != iris::IRIS_UINT64_MAX && !it->second->validId())
+        installBp(it);
+
+    return true;
+}
+
+bool
+ThreadContext::remove(PCEvent *e)
+{
+    auto it = getOrAllocBp(e->pc());
+    it->second->events.remove(e);
+
+    if (it->second->empty())
+        delBp(it);
+
+    return true;
+}
+
 bool
 ThreadContext::translateAddress(Addr &paddr, iris::MemorySpaceId p_space,
                                 Addr vaddr, iris::MemorySpaceId v_space)
index 8d2070a023b6a08a31503bff92399b91a9c8546b..4175e93633a1271789b0f0b41044053095a83ca8 100644 (file)
@@ -30,6 +30,8 @@
 #ifndef __ARCH_ARM_FASTMODEL_IRIS_THREAD_CONTEXT_HH__
 #define __ARCH_ARM_FASTMODEL_IRIS_THREAD_CONTEXT_HH__
 
+#include <list>
+#include <map>
 #include <memory>
 
 #include "cpu/base.hh"
@@ -91,6 +93,33 @@ class ThreadContext : public ::ThreadContext
     void maintainStepping();
 
 
+    using BpId = uint64_t;
+    struct BpInfo
+    {
+        Addr pc;
+        BpId id;
+        std::list<PCEvent *> events;
+
+        BpInfo(Addr _pc) : pc(_pc), id(iris::IRIS_UINT64_MAX) {}
+
+        bool empty() const { return events.empty(); }
+        bool validId() const { return id != iris::IRIS_UINT64_MAX; }
+        void clearId() { id = iris::IRIS_UINT64_MAX; }
+    };
+
+    using BpInfoPtr = std::unique_ptr<BpInfo>;
+    using BpInfoMap = std::map<Addr, BpInfoPtr>;
+    using BpInfoIt = BpInfoMap::iterator;
+
+    BpInfoMap bps;
+
+    BpInfoIt getOrAllocBp(Addr pc);
+
+    void installBp(BpInfoIt it);
+    void uninstallBp(BpInfoIt it);
+    void delBp(BpInfoIt it);
+
+
     iris::IrisErrorCode instanceRegistryChanged(
             uint64_t esId, const iris::IrisValueMap &fields, uint64_t time,
             uint64_t sInstId, bool syncEc, std::string &error_message_out);
@@ -100,10 +129,14 @@ class ThreadContext : public ::ThreadContext
     iris::IrisErrorCode simulationTimeEvent(
             uint64_t esId, const iris::IrisValueMap &fields, uint64_t time,
             uint64_t sInstId, bool syncEc, std::string &error_message_out);
+    iris::IrisErrorCode breakpointHit(
+            uint64_t esId, const iris::IrisValueMap &fields, uint64_t time,
+            uint64_t sInstId, bool syncEc, std::string &error_message_out);
 
     iris::EventStreamId regEventStreamId;
     iris::EventStreamId initEventStreamId;
     iris::EventStreamId timeEventStreamId;
+    iris::EventStreamId breakpointEventStreamId;
 
     mutable iris::IrisInstance client;
     iris::IrisCppAdapter &call() const { return client.irisCall(); }
@@ -121,8 +154,8 @@ class ThreadContext : public ::ThreadContext
 
     virtual bool translateAddress(Addr &paddr, Addr vaddr) = 0;
 
-    bool schedule(PCEvent *e) override { return false; }
-    bool remove(PCEvent *e) override { return false; }
+    bool schedule(PCEvent *e) override;
+    bool remove(PCEvent *e) override;
 
     void scheduleInstCountEvent(Event *event, Tick count) override;
     void descheduleInstCountEvent(Event *event) override;