Add support in the isolator to perform write operations on a signature
Signed-off-by: Caleb Palmer <cnpalmer@us.ibm.com>
Change-Id: Ia1f189a8ce7d1d71efc0ae81942151c31d63a4f5
diff --git a/src/isolator/hei_isolation_node.cpp b/src/isolator/hei_isolation_node.cpp
index d156015..099a955 100644
--- a/src/isolator/hei_isolation_node.cpp
+++ b/src/isolator/hei_isolation_node.cpp
@@ -156,6 +156,21 @@
//------------------------------------------------------------------------------
+std::pair<OpRuleType_t, RegisterId_t>
+ IsolationNode::getOpRule(OpRuleName_t i_name) const
+{
+ return iv_op_rules.at(i_name);
+}
+
+//------------------------------------------------------------------------------
+
+bool IsolationNode::doesOpExist(OpRuleName_t i_name) const
+{
+ return (0 != iv_op_rules.count(i_name));
+}
+
+//------------------------------------------------------------------------------
+
std::vector<const IsolationNode*> IsolationNode::cv_isolationStack{};
//------------------------------------------------------------------------------
diff --git a/src/isolator/hei_isolation_node.hpp b/src/isolator/hei_isolation_node.hpp
index 9043f1d..5c5f8ed 100644
--- a/src/isolator/hei_isolation_node.hpp
+++ b/src/isolator/hei_isolation_node.hpp
@@ -187,6 +187,23 @@
void addOpRule(OpRuleName_t i_opName, OpRuleType_t i_opType,
RegisterId_t i_regId);
+ /**
+ * @brief Returns a write operation for the isolation node based on the
+ * input operation name.
+ *
+ * @param i_name The name of the operation.
+ * @return The operation type and reg ID of the operation rule in a pair.
+ */
+ std::pair<OpRuleType_t, RegisterId_t> getOpRule(OpRuleName_t i_name) const;
+
+ /**
+ * @brief Returns whether the write operation rule exists for the node
+ *
+ * @param i_name The name of the operation.
+ * @return True if the operation exists, else false.
+ */
+ bool doesOpExist(OpRuleName_t i_name) const;
+
/** @return The node ID. */
NodeId_t getId() const
{
diff --git a/src/isolator/hei_isolator.cpp b/src/isolator/hei_isolator.cpp
index f431cb3..85995a6 100644
--- a/src/isolator/hei_isolator.cpp
+++ b/src/isolator/hei_isolator.cpp
@@ -73,4 +73,148 @@
}
}
+//------------------------------------------------------------------------------
+
+#ifdef __HEI_ENABLE_HW_WRITE
+
+bool __atomicOr(Signature i_sig, HardwareRegister::ConstPtr i_hwReg)
+{
+ // Input register is for an atomic OR register used for setting a bit. Get
+ // the bit in the input signature and write that bit to the register.
+ i_hwReg->clearAllBits(i_sig.getChip());
+ i_hwReg->setBit(i_sig.getChip(), i_sig.getBit());
+
+ return i_hwReg->write(i_sig.getChip());
+}
+
+bool __atomicAnd(Signature i_sig, HardwareRegister::ConstPtr i_hwReg)
+{
+ // Input register is for an atomic AND register used for clearing a bit. Get
+ // the bit in the input signature and write that bit to the register.
+ i_hwReg->setAllBits(i_sig.getChip());
+ i_hwReg->clearBit(i_sig.getChip(), i_sig.getBit());
+
+ return i_hwReg->write(i_sig.getChip());
+}
+
+bool __readSetWrite(Signature i_sig, HardwareRegister::ConstPtr i_hwReg)
+{
+ // Perform a read, modify, write to set a bit. Get the bit from the input
+ // signature.
+ if (i_hwReg->read(i_sig.getChip(), true))
+ {
+ HEI_ERR("Failed to read reg ID 0x%04x", i_hwReg->getId());
+ return true;
+ }
+ i_hwReg->setBit(i_sig.getChip(), i_sig.getBit());
+
+ return i_hwReg->write(i_sig.getChip());
+}
+
+bool __readClearWrite(Signature i_sig, HardwareRegister::ConstPtr i_hwReg)
+{
+ // Perform a read, modify, write to clear a bit. Get the bit from the input
+ // signature.
+ if (i_hwReg->read(i_sig.getChip(), true))
+ {
+ HEI_ERR("Failed to read reg ID 0x%04x", i_hwReg->getId());
+ return true;
+ }
+ i_hwReg->clearBit(i_sig.getChip(), i_sig.getBit());
+
+ return i_hwReg->write(i_sig.getChip());
+}
+
+bool Isolator::performWriteOp(OpRuleName_t i_op, Signature i_sig)
+{
+ // Return true on a failure.
+ bool writefail = false;
+
+ // Use the signature to determine the relevant isolation node.
+ IsolationNode::Key nodeKey = {i_sig.getId(), i_sig.getInstance()};
+ IsolationChip::ConstPtr isoChip = iv_isoChips.at(i_sig.getChip().getType());
+ IsolationNode::ConstPtr node = isoChip->getIsolationNode(nodeKey);
+
+ // If the operation name does not exist for the node, print an error
+ // message and return.
+ if (!node->doesOpExist(i_op))
+ {
+ HEI_ERR("Operation rule %d does not exist for node 0x%04x", i_op,
+ node->getId());
+ writeFail = true;
+ return writeFail;
+ }
+
+ // Get the write operation defined in the node.
+ std::pair<OpRuleType_t, RegisterId_t> op = node->getOpRule(i_op);
+
+ // Get the relevant hardware register from the isolation chip. The instance
+ // of the register should match the instance of the signature.
+ HardwareRegister::Key regKey = {op.second, i_sig.getInstance()};
+ HardwareRegister::ConstPtr hwReg = isoChip->getHardwareRegister(regKey);
+
+ // Perform write operation dependent on the operation type.
+ switch (op.first)
+ {
+ case ATOMIC_OR:
+ {
+ if (__atomicOr(i_sig, hwReg))
+ {
+ HEI_ERR("Failed performing ATOMIC_OR write operation %d on "
+ "node 0x%04x",
+ i_op, node->getId());
+ writeFail = true;
+ }
+ break;
+ }
+ case ATOMIC_AND:
+ {
+ if (__atomicAnd(i_sig, hwReg))
+ {
+ HEI_ERR("Failed performing ATOMIC_AND write operation %d on "
+ "node 0x%04x",
+ i_op, node->getId());
+ writeFail = true;
+ }
+ break;
+ }
+ case READ_SET_WRITE:
+ {
+ if (__readSetWrite(i_sig, hwReg))
+ {
+ HEI_ERR("Failed performing READ_SET_WRITE write operation %d "
+ "on node 0x%04x",
+ i_op, node->getId());
+ writeFail = true;
+ }
+ break;
+ }
+ case READ_CLEAR_WRITE:
+ {
+ if (__readClearWrite(i_sig, hwReg))
+ {
+ HEI_ERR("Failed performing READ_CLEAR_WRITE write operation %d "
+ "on node 0x%04x",
+ i_op, node->getId());
+ writeFail = true;
+ }
+ break;
+ }
+ default:
+ {
+ HEI_ERR("Invalid operation type %d for op %d on node 0x%04x",
+ op.first, i_op, node->getId());
+ writeFail = true;
+ }
+ }
+
+ // Flush the affected register from the cache so it is re-read from hardware
+ // next time it is read.
+ hwReg->flush(i_sig.getChip());
+
+ return writeFail;
+}
+
+#endif
+
} // end namespace libhei
diff --git a/src/isolator/hei_isolator.hpp b/src/isolator/hei_isolator.hpp
index 79a7993..4e9419b 100644
--- a/src/isolator/hei_isolator.hpp
+++ b/src/isolator/hei_isolator.hpp
@@ -76,6 +76,19 @@
void isolate(const std::vector<Chip>& i_chipList,
IsolationData& o_isoData) const;
+#ifdef __HEI_ENABLE_HW_WRITE
+ /**
+ * @brief Performs the given write operation on the input signature. The
+ * node and bit in the input signature will determine which register
+ * and bit are to be written by the operation.
+ * @param i_op The given write operation rule. See the OpRuleName_t enum
+ * for supported values.
+ * @param i_sig The signature to determine what's to be written.
+ * @return True if write operation failed, false if successful.
+ */
+ bool performWriteOp(OpRuleName_t i_op, Signature i_sig);
+#endif
+
}; // end class Isolator
} // end namespace libhei
diff --git a/src/register/hei_hardware_register.cpp b/src/register/hei_hardware_register.cpp
index 0aa2342..b990fc9 100644
--- a/src/register/hei_hardware_register.cpp
+++ b/src/register/hei_hardware_register.cpp
@@ -101,6 +101,42 @@
//------------------------------------------------------------------------------
+void HardwareRegister::setBit(const Chip& i_chip, uint64_t i_pos) const
+{
+ // Get the buffer from the register cache.
+ BitString& bs = accessCache(i_chip);
+ bs.setBit(i_pos);
+}
+
+//------------------------------------------------------------------------------
+
+void HardwareRegister::setAllBits(const Chip& i_chip) const
+{
+ // Get the buffer from the register cache.
+ BitString& bs = accessCache(i_chip);
+ bs.setAll();
+}
+
+//------------------------------------------------------------------------------
+
+void HardwareRegister::clearBit(const Chip& i_chip, uint64_t i_pos) const
+{
+ // Get the buffer from the register cache.
+ BitString& bs = accessCache(i_chip);
+ bs.clearBit(i_pos);
+}
+
+//------------------------------------------------------------------------------
+
+void HardwareRegister::clearAllBits(const Chip& i_chip) const
+{
+ // Get the buffer from the register cache.
+ BitString& bs = accessCache(i_chip);
+ bs.clearAll();
+}
+
+//------------------------------------------------------------------------------
+
HardwareRegister::Cache HardwareRegister::cv_cache{};
//------------------------------------------------------------------------------
diff --git a/src/register/hei_hardware_register.hpp b/src/register/hei_hardware_register.hpp
index 85d87ff..d75960c 100644
--- a/src/register/hei_hardware_register.hpp
+++ b/src/register/hei_hardware_register.hpp
@@ -188,6 +188,32 @@
#endif // __HEI_ENABLE_HW_WRITE
+ /**
+ * @brief Sets the target position to 1 in the cached bit string.
+ * @param i_chip The target chip in which this register belongs.
+ * @param i_pos The target position.
+ */
+ void setBit(const Chip& i_chip, uint64_t i_pos) const;
+
+ /**
+ * @brief Sets the entire cached bit string to 1s.
+ * @param i_chip The target chip in which this register belongs.
+ */
+ void setAllBits(const Chip& i_chip) const;
+
+ /**
+ * @brief Sets the target position to 0 in the cached bit string.
+ * @param i_chip The target chip in which this register belongs.
+ * @param i_pos The target position.
+ */
+ void clearBit(const Chip& i_chip, uint64_t i_pos) const;
+
+ /**
+ * @brief Sets the entire cached bit string to 0s.
+ * @param i_chip The target chip in which this register belongs.
+ */
+ void clearAllBits(const Chip& i_chip) const;
+
protected:
/**
* @brief Provides access to this register's BitString.
diff --git a/test/simulator/simulator.cpp b/test/simulator/simulator.cpp
index 408d14a..b68ec80 100644
--- a/test/simulator/simulator.cpp
+++ b/test/simulator/simulator.cpp
@@ -15,6 +15,7 @@
{SAMPLE, "../test/simulator/sample_data/sample.cdb"},
{EXPLORER_11, "chip_data/chip_data_explorer_11.cdb"},
{EXPLORER_20, "chip_data/chip_data_explorer_20.cdb"},
+ {ODYSSEY_10, "chip_data/chip_data_odyssey_10.cdb"},
{P10_10, "chip_data/chip_data_p10_10.cdb"},
{P10_20, "chip_data/chip_data_p10_20.cdb"},
};
diff --git a/test/simulator/simulator.hpp b/test/simulator/simulator.hpp
index 4f81508..58b279a 100644
--- a/test/simulator/simulator.hpp
+++ b/test/simulator/simulator.hpp
@@ -46,6 +46,7 @@
SAMPLE = 0xdeadbeef,
EXPLORER_11 = 0x60d20011,
EXPLORER_20 = 0x60d20020,
+ ODYSSEY_10 = 0x60c00010,
P10_10 = 0x20da0010,
P10_20 = 0x20da0020,
};
diff --git a/test/simulator/testcases/meson.build b/test/simulator/testcases/meson.build
index 5d9e306..0e894cd 100644
--- a/test/simulator/testcases/meson.build
+++ b/test/simulator/testcases/meson.build
@@ -6,5 +6,6 @@
'exp20_tlx_err_rpt_1.cpp',
'omi_dl_fatal.cpp',
'tod_fault.cpp',
+ 'ody_mcbist2.cpp',
)
diff --git a/test/simulator/testcases/ody_mcbist2.cpp b/test/simulator/testcases/ody_mcbist2.cpp
new file mode 100644
index 0000000..7e0776f
--- /dev/null
+++ b/test/simulator/testcases/ody_mcbist2.cpp
@@ -0,0 +1,18 @@
+#include "simulator.hpp"
+
+START_TEST_CASE(ody_mcbist2)
+
+CHIP(ocmb0, ODYSSEY_10)
+
+START_ITERATION
+
+REG_SCOM(ocmb0, 0x570F001C, 0x0080000000000000) // GFIR_CS
+REG_SCOM(ocmb0, 0x08040000, 0x0200000000000000) // CFIR_MEM_CHIP_CS
+REG_SCOM(ocmb0, 0x08011400, 0x2000000000000000) // MCBIST_FIR
+REG_SCOM(ocmb0, 0x08011404, 0x2000000000000000) // MCBIST_FIR_CFG_CHIP_CS
+
+EXP_SIG(ocmb0, 0x8d4d, 0, 2, CHIP_CS)
+
+END_ITERATION
+
+END_TEST_CASE