mem-ruby: HTM mem implementation
[gem5.git] / src / mem / ruby / slicc_interface / RubySlicc_Util.hh
index f55b6eae414c9a7a3883d561358db8c4cfdf0b41..8ff8884aae06c1aa140b50b508a533985e627f98 100644 (file)
@@ -1,5 +1,18 @@
 /*
+ * Copyright (c) 2020 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
  * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
+ * Copyright (c) 2013 Advanced Micro Devices, Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * These are the functions that exported to slicc from ruby.
  */
 
-#ifndef __MEM_RUBY_SLICC_INTERFACE_RUBYSLICCUTIL_HH__
-#define __MEM_RUBY_SLICC_INTERFACE_RUBYSLICCUTIL_HH__
+#ifndef __MEM_RUBY_SLICC_INTERFACE_RUBYSLICC_UTIL_HH__
+#define __MEM_RUBY_SLICC_INTERFACE_RUBYSLICC_UTIL_HH__
 
 #include <cassert>
 
 #include "debug/RubySlicc.hh"
+#include "mem/packet.hh"
 #include "mem/ruby/common/Address.hh"
-#include "mem/ruby/common/Global.hh"
-#include "mem/ruby/slicc_interface/RubySlicc_ComponentMapping.hh"
-#include "mem/ruby/system/System.hh"
+#include "mem/ruby/common/BoolVec.hh"
+#include "mem/ruby/common/DataBlock.hh"
+#include "mem/ruby/common/TypeDefines.hh"
+#include "mem/ruby/common/WriteMask.hh"
 
-inline int
-random(int n)
-{
-  return random() % n;
-}
-
-inline Time
-zero_time()
-{
-    return 0;
-}
+inline Cycles zero_time() { return Cycles(0); }
 
 inline NodeID
 intToID(int nodenum)
@@ -67,66 +72,98 @@ IDToInt(NodeID id)
     return nodenum;
 }
 
-inline Time
-getTimeModInt(Time time, int modulus)
+inline int
+addressToInt(Addr addr)
 {
-    return time % modulus;
+    assert(!(addr & 0xffffffff00000000));
+    return addr;
 }
 
-inline Time
-getTimePlusInt(Time addend1, int addend2)
+inline Addr
+intToAddress(int addr)
 {
-    return (Time) addend1 + addend2;
+    assert(!(addr & 0xffffffff00000000));
+    return addr;
 }
 
-inline Time
-getTimeMinusTime(Time t1, Time t2)
+inline int
+mod(int val, int mod)
 {
-    assert(t1 >= t2);
-    return t1 - t2;
+    return val % mod;
 }
 
-// Return type for time_to_int is "Time" and not "int" so we get a
-// 64-bit integer
-inline Time
-time_to_int(Time time)
+inline int max_tokens()
 {
-    return time;
+  return 1024;
 }
 
-// Appends an offset to an address
-inline Address
-setOffset(Address addr, int offset)
+inline bool
+isWriteRequest(RubyRequestType type)
 {
-    Address result = addr;
-    result.setOffset(offset);
-    return result;
+    if ((type == RubyRequestType_ST) ||
+        (type == RubyRequestType_ATOMIC) ||
+        (type == RubyRequestType_RMW_Read) ||
+        (type == RubyRequestType_RMW_Write) ||
+        (type == RubyRequestType_Store_Conditional) ||
+        (type == RubyRequestType_Locked_RMW_Read) ||
+        (type == RubyRequestType_Locked_RMW_Write) ||
+        (type == RubyRequestType_FLUSH)) {
+            return true;
+    } else {
+            return false;
+    }
 }
 
-// Makes an address into a line address
-inline Address
-makeLineAddress(Address addr)
+inline bool
+isDataReadRequest(RubyRequestType type)
 {
-    Address result = addr;
-    result.makeLineAddress();
-    return result;
+    if ((type == RubyRequestType_LD) ||
+        (type == RubyRequestType_Load_Linked)) {
+            return true;
+    } else {
+            return false;
+    }
 }
 
-inline int
-addressOffset(Address addr)
+inline bool
+isReadRequest(RubyRequestType type)
 {
-    return addr.getOffset();
+    if (isDataReadRequest(type) ||
+        (type == RubyRequestType_IFETCH)) {
+            return true;
+    } else {
+            return false;
+    }
 }
 
-inline int
-mod(int val, int mod)
+inline bool
+isHtmCmdRequest(RubyRequestType type)
 {
-    return val % mod;
+    if ((type == RubyRequestType_HTM_Start)  ||
+        (type == RubyRequestType_HTM_Commit) ||
+        (type == RubyRequestType_HTM_Cancel) ||
+        (type == RubyRequestType_HTM_Abort)) {
+            return true;
+    } else {
+            return false;
+    }
 }
 
-inline int max_tokens()
+inline RubyRequestType
+htmCmdToRubyRequestType(const Packet *pkt)
 {
-  return 1024;
+    if (pkt->req->isHTMStart()) {
+        return RubyRequestType_HTM_Start;
+    } else if (pkt->req->isHTMCommit()) {
+        return RubyRequestType_HTM_Commit;
+    } else if (pkt->req->isHTMCancel()) {
+        return RubyRequestType_HTM_Cancel;
+    } else if (pkt->req->isHTMAbort()) {
+        return RubyRequestType_HTM_Abort;
+    }
+    else {
+        panic("invalid ruby packet type\n");
+    }
 }
 
 /**
@@ -134,20 +171,23 @@ inline int max_tokens()
  * range for the data block contains the address which the packet needs to
  * read, then the data from the data block is written to the packet. True is
  * returned if the data block was read, otherwise false is returned.
+ *
+ * This is used during a functional access "search the world" operation. The
+ * functional access looks in every place that might hold a valid data block
+ * and, if it finds one, checks to see if it is holding the address the access
+ * is searching for. During the access check, the WriteMask could be in any
+ * state, including empty.
  */
 inline bool
-testAndRead(Address addr, DataBlock& blk, Packet *pkt)
+testAndRead(Addr addr, DataBlock& blk, Packet *pkt)
 {
-    Address pktLineAddr(pkt->getAddr());
-    pktLineAddr.makeLineAddress();
-
-    Address lineAddr = addr;
-    lineAddr.makeLineAddress();
+    Addr pktLineAddr = makeLineAddress(pkt->getAddr());
+    Addr lineAddr = makeLineAddress(addr);
 
     if (pktLineAddr == lineAddr) {
-        uint8_t *data = pkt->getPtr<uint8_t>(true);
+        uint8_t *data = pkt->getPtr<uint8_t>();
         unsigned int size_in_bytes = pkt->getSize();
-        unsigned startByte = pkt->getAddr() - lineAddr.getAddress();
+        unsigned startByte = pkt->getAddr() - lineAddr;
 
         for (unsigned i = 0; i < size_in_bytes; ++i) {
             data[i] = blk.getByte(i + startByte);
@@ -157,6 +197,36 @@ testAndRead(Address addr, DataBlock& blk, Packet *pkt)
     return false;
 }
 
+/**
+ * This function accepts an address, a data block, a write mask and a packet.
+ * If the valid address range for the data block contains the address which
+ * the packet needs to read, then the data from the data block is written to
+ * the packet. True is returned if any part of the data block was read,
+ * otherwise false is returned.
+ */
+inline bool
+testAndReadMask(Addr addr, DataBlock& blk, WriteMask& mask, Packet *pkt)
+{
+    Addr pktLineAddr = makeLineAddress(pkt->getAddr());
+    Addr lineAddr = makeLineAddress(addr);
+
+    if (pktLineAddr == lineAddr) {
+        uint8_t *data = pkt->getPtr<uint8_t>();
+        unsigned int size_in_bytes = pkt->getSize();
+        unsigned startByte = pkt->getAddr() - lineAddr;
+        bool was_read = false;
+
+        for (unsigned i = 0; i < size_in_bytes; ++i) {
+            if (mask.test(i + startByte)) {
+                was_read = true;
+                data[i] = blk.getByte(i + startByte);
+            }
+        }
+        return was_read;
+    }
+    return false;
+}
+
 /**
  * This function accepts an address, a data block and a packet. If the address
  * range for the data block contains the address which the packet needs to
@@ -164,18 +234,15 @@ testAndRead(Address addr, DataBlock& blk, Packet *pkt)
  * returned if the data block was written, otherwise false is returned.
  */
 inline bool
-testAndWrite(Address addr, DataBlock& blk, Packet *pkt)
+testAndWrite(Addr addr, DataBlock& blk, Packet *pkt)
 {
-    Address pktLineAddr(pkt->getAddr());
-    pktLineAddr.makeLineAddress();
-
-    Address lineAddr = addr;
-    lineAddr.makeLineAddress();
+    Addr pktLineAddr = makeLineAddress(pkt->getAddr());
+    Addr lineAddr = makeLineAddress(addr);
 
     if (pktLineAddr == lineAddr) {
-        uint8_t *data = pkt->getPtr<uint8_t>(true);
+        const uint8_t *data = pkt->getConstPtr<uint8_t>();
         unsigned int size_in_bytes = pkt->getSize();
-        unsigned startByte = pkt->getAddr() - lineAddr.getAddress();
+        unsigned startByte = pkt->getAddr() - lineAddr;
 
         for (unsigned i = 0; i < size_in_bytes; ++i) {
             blk.setByte(i + startByte, data[i]);
@@ -185,4 +252,16 @@ testAndWrite(Address addr, DataBlock& blk, Packet *pkt)
     return false;
 }
 
-#endif // __MEM_RUBY_SLICC_INTERFACE_RUBYSLICCUTIL_HH__
+inline int
+countBoolVec(BoolVec bVec)
+{
+    int count = 0;
+    for (const auto &it: bVec) {
+        if (it) {
+            count++;
+        }
+    }
+    return count;
+}
+
+#endif //__MEM_RUBY_SLICC_INTERFACE_RUBYSLICC_UTIL_HH__