arm: Refactor some Event subclasses to lambdas
[gem5.git] / src / dev / arm / rv_ctrl.cc
index eceba81f127ca31129781a15d735f75955e2c5d9..954be6597e0d8091c237b745f28a4f926fd1095c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 ARM Limited
+ * Copyright (c) 2010,2013,2015 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
  * Authors: Ali Saidi
  */
 
-#include "base/trace.hh"
 #include "dev/arm/rv_ctrl.hh"
+
+#include "base/trace.hh"
+#include "debug/RVCTRL.hh"
 #include "mem/packet.hh"
 #include "mem/packet_access.hh"
+#include "sim/power/thermal_model.hh"
+#include "sim/system.hh"
+#include "sim/voltage_domain.hh"
 
 RealViewCtrl::RealViewCtrl(Params *p)
-    : BasicPioDevice(p), flags(0)
+    : BasicPioDevice(p, 0xD4), flags(0), scData(0)
 {
-    pioSize = 0xD4;
 }
 
 Tick
@@ -54,7 +58,6 @@ RealViewCtrl::read(PacketPtr pkt)
     assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
     assert(pkt->getSize() == 4);
     Addr daddr = pkt->getAddr() - pioAddr;
-    pkt->allocate();
 
     switch(daddr) {
       case ProcId0:
@@ -65,12 +68,12 @@ RealViewCtrl::read(PacketPtr pkt)
         break;
       case Clock24:
         Tick clk;
-        clk = (Tick)(curTick() / (24 * SimClock::Int::us));
+        clk = SimClock::Float::MHz * curTick() * 24;
         pkt->set((uint32_t)(clk));
         break;
       case Clock100:
         Tick clk100;
-        clk100 = (Tick)(curTick() / (100 * SimClock::Int::us));
+        clk100 = SimClock::Float::MHz * curTick() * 100;
         pkt->set((uint32_t)(clk100));
         break;
       case Flash:
@@ -105,9 +108,19 @@ RealViewCtrl::read(PacketPtr pkt)
         break;
       case CfgStat:
         pkt->set<uint32_t>(1);
+        break;
+      case CfgData:
+        pkt->set<uint32_t>(scData);
+        DPRINTF(RVCTRL, "Read %#x from SCReg\n", scData);
+        break;
+      case CfgCtrl:
+        pkt->set<uint32_t>(0); // not busy
+        DPRINTF(RVCTRL, "Read 0 from CfgCtrl\n");
+        break;
       default:
         warn("Tried to read RealView I/O at offset %#x that doesn't exist\n",
              daddr);
+        pkt->set<uint32_t>(0);
         break;
     }
     pkt->makeAtomicResponse();
@@ -133,15 +146,56 @@ RealViewCtrl::write(PacketPtr pkt)
       case Lock:
         sysLock.lockVal = pkt->get<uint16_t>();
         break;
+      case ResetCtl:
+        // Ignore writes to reset control
+        warn_once("Ignoring write to reset control\n");
+        break;
       case Flags:
         flags = pkt->get<uint32_t>();
         break;
       case FlagsClr:
         flags = 0;
         break;
+      case CfgData:
+        scData = pkt->get<uint32_t>();
+        break;
+      case CfgCtrl: {
+          // A request is being submitted to read/write the system control
+          // registers.  See
+          // http://infocenter.arm.com/help/topic/com.arm.doc.dui0447h/CACDEFGH.html
+          CfgCtrlReg req = pkt->get<uint32_t>();
+          if (!req.start) {
+              DPRINTF(RVCTRL, "SCReg: write %#x to ctrl but not starting\n",
+                      req);
+              break;
+          }
+
+          auto it_dev(devices.find(req & CFG_CTRL_ADDR_MASK));
+          if (it_dev == devices.end()) {
+              warn_once("SCReg: Access to unknown device "
+                        "dcc%d:site%d:pos%d:fn%d:dev%d\n",
+                        req.dcc, req.site, req.pos, req.func, req.dev);
+              break;
+          }
+
+          // Service the request as a read or write depending on the
+          // wr bit in the control register.
+          Device &dev(*it_dev->second);
+          if (req.wr) {
+              DPRINTF(RVCTRL, "SCReg: Writing %#x (ctrlWr %#x)\n",
+                      scData, req);
+              dev.write(scData);
+
+          } else {
+              scData = dev.read();
+              DPRINTF(RVCTRL, "SCReg: Reading %#x (ctrlRd %#x)\n",
+                      scData, req);
+          }
+      } break;
+      case CfgStat:     // Weird to write this
       default:
-        warn("Tried to write RVIO at offset %#x that doesn't exist\n",
-             daddr);
+        warn("Tried to write RVIO at offset %#x (data %#x) that doesn't exist\n",
+             daddr, pkt->get<uint32_t>());
         break;
     }
     pkt->makeAtomicResponse();
@@ -149,19 +203,133 @@ RealViewCtrl::write(PacketPtr pkt)
 }
 
 void
-RealViewCtrl::serialize(std::ostream &os)
+RealViewCtrl::serialize(CheckpointOut &cp) const
 {
     SERIALIZE_SCALAR(flags);
 }
 
 void
-RealViewCtrl::unserialize(Checkpoint *cp, const std::string &section)
+RealViewCtrl::unserialize(CheckpointIn &cp)
 {
     UNSERIALIZE_SCALAR(flags);
 }
 
+void
+RealViewCtrl::registerDevice(DeviceFunc func, uint8_t site, uint8_t pos,
+                             uint8_t dcc, uint16_t dev,
+                             Device *handler)
+{
+    CfgCtrlReg addr = 0;
+    addr.func = func;
+    addr.site = site;
+    addr.pos = pos;
+    addr.dcc = dcc;
+    addr.dev = dev;
+
+    if (devices.find(addr) != devices.end()) {
+        fatal("Platform device dcc%d:site%d:pos%d:fn%d:dev%d "
+              "already registered.",
+              addr.dcc, addr.site, addr.pos, addr.func, addr.dev);
+    }
+
+    devices[addr] = handler;
+}
+
+
+RealViewOsc::RealViewOsc(RealViewOscParams *p)
+    : ClockDomain(p, p->voltage_domain),
+      RealViewCtrl::Device(*p->parent, RealViewCtrl::FUNC_OSC,
+                           p->site, p->position, p->dcc, p->device)
+{
+    if (SimClock::Float::s  / p->freq > UINT32_MAX) {
+        fatal("Oscillator frequency out of range: %f\n",
+            SimClock::Float::s  / p->freq / 1E6);
+    }
+
+    _clockPeriod = p->freq;
+}
+
+void
+RealViewOsc::startup()
+{
+    // Tell dependent object to set their clock frequency
+    for (auto m : members)
+        m->updateClockPeriod();
+}
+
+void
+RealViewOsc::serialize(CheckpointOut &cp) const
+{
+    SERIALIZE_SCALAR(_clockPeriod);
+}
+
+void
+RealViewOsc::unserialize(CheckpointIn &cp)
+{
+    UNSERIALIZE_SCALAR(_clockPeriod);
+}
+
+void
+RealViewOsc::clockPeriod(Tick clock_period)
+{
+    panic_if(clock_period == 0, "%s has a clock period of zero\n", name());
+
+    // Align all members to the current tick
+    for (auto m : members)
+        m->updateClockPeriod();
+
+    _clockPeriod = clock_period;
+
+    // inform any derived clocks they need to updated their period
+    for (auto m : children)
+        m->updateClockPeriod();
+}
+
+uint32_t
+RealViewOsc::read() const
+{
+    const uint32_t freq(SimClock::Float::s / _clockPeriod);
+    DPRINTF(RVCTRL, "Reading OSC frequency: %f MHz\n", freq / 1E6);
+    return freq;
+}
+
+void
+RealViewOsc::write(uint32_t freq)
+{
+    DPRINTF(RVCTRL, "Setting new OSC frequency: %f MHz\n", freq / 1E6);
+    clockPeriod(SimClock::Float::s / freq);
+}
+
+uint32_t
+RealViewTemperatureSensor::read() const
+{
+    // Temperature reported in uC
+    ThermalModel * tm = system->getThermalModel();
+    if (tm) {
+        double t = tm->getTemp();
+        if (t < 0)
+            warn("Temperature below zero!\n");
+        return fmax(0, t) * 1000000;
+    }
+
+    // Report a dummy 25 degrees temperature
+    return 25000000;
+}
+
 RealViewCtrl *
 RealViewCtrlParams::create()
 {
     return new RealViewCtrl(this);
 }
+
+RealViewOsc *
+RealViewOscParams::create()
+{
+    return new RealViewOsc(this);
+}
+
+RealViewTemperatureSensor *
+RealViewTemperatureSensorParams::create()
+{
+    return new RealViewTemperatureSensor(this);
+}