Add capture regs from Chip Data File to IsolationNode
Change-Id: Ia91821f2b14e12ed917c97b622789710ffb8bdb4
Signed-off-by: Zane Shelley <zshelle@us.ibm.com>
diff --git a/src/chip_data/hei_chip_data.cpp b/src/chip_data/hei_chip_data.cpp
index 87044db..752014b 100644
--- a/src/chip_data/hei_chip_data.cpp
+++ b/src/chip_data/hei_chip_data.cpp
@@ -75,7 +75,8 @@
//------------------------------------------------------------------------------
-void __readExpr(ChipDataStream& io_stream, RegisterType_t i_regType)
+void __readExpr(ChipDataStream& io_stream, const IsolationChip::Ptr& i_isoChip,
+ IsolationNode::Ptr& io_isoNode)
{
uint8_t exprType;
io_stream >> exprType;
@@ -86,11 +87,23 @@
RegisterId_t regId;
Instance_t regInst;
io_stream >> regId >> regInst;
+
+ // Find the hardware register that is stored in this isolation chip
+ // and add it to the list of capture registers. This ensures all
+ // registers referenced in the rules are are captured by default.
+ // Note that this will assert that the target register must exist in
+ // the isolation chip.
+ auto hwReg = i_isoChip->getHardwareRegister({regId, regInst});
+
+ // Add the register to the isolation node.
+ io_isoNode->addCaptureRegister(hwReg);
+
break;
}
case 0x02: // integer constant
{
- if (REG_TYPE_SCOM == i_regType || REG_TYPE_ID_SCOM == i_regType)
+ if (REG_TYPE_SCOM == io_isoNode->getRegisterType() ||
+ REG_TYPE_ID_SCOM == io_isoNode->getRegisterType())
{
uint64_t constant; // 8-byte value
io_stream >> constant;
@@ -107,7 +120,7 @@
io_stream >> numSubExpr;
for (uint8_t i = 0; i < numSubExpr; i++)
{
- __readExpr(io_stream, i_regType);
+ __readExpr(io_stream, i_isoChip, io_isoNode);
}
break;
}
@@ -117,27 +130,27 @@
io_stream >> numSubExpr;
for (uint8_t i = 0; i < numSubExpr; i++)
{
- __readExpr(io_stream, i_regType);
+ __readExpr(io_stream, i_isoChip, io_isoNode);
}
break;
}
case 0x12: // NOT operation
{
- __readExpr(io_stream, i_regType);
+ __readExpr(io_stream, i_isoChip, io_isoNode);
break;
}
case 0x13: // left shift operation
{
uint8_t shiftValue;
io_stream >> shiftValue;
- __readExpr(io_stream, i_regType);
+ __readExpr(io_stream, i_isoChip, io_isoNode);
break;
}
case 0x14: // right shift operation
{
uint8_t shiftValue;
io_stream >> shiftValue;
- __readExpr(io_stream, i_regType);
+ __readExpr(io_stream, i_isoChip, io_isoNode);
break;
}
default:
@@ -162,30 +175,51 @@
uint8_t numCapRegs, numIsoRules, numChildNodes;
io_stream >> nodeInst >> numCapRegs >> numIsoRules >> numChildNodes;
+ // There must be at least one isolation rule defined.
+ HEI_ASSERT(0 != numIsoRules);
+
+ // Allocate memory for this isolation node.
+ auto isoNode =
+ std::make_shared<IsolationNode>(nodeId, nodeInst, regType);
+
// Add capture registers.
for (unsigned int j = 0; j < numCapRegs; j++)
{
+ // Read the capture register metadata.
RegisterId_t regId;
Instance_t regInst;
io_stream >> regId >> regInst;
+
+ // Find the hardware register that is stored in this isolation chip
+ // and add it to the list of capture registers. Note that this will
+ // assert that the target register must exist in the isolation chip.
+ auto hwReg = io_isoChip->getHardwareRegister({regId, regInst});
+
+ // Add the register to the isolation node.
+ isoNode->addCaptureRegister(hwReg);
}
// Add isolation rules.
for (unsigned int j = 0; j < numIsoRules; j++)
{
+ // Read the rule metadata.
AttentionType_t attnType;
io_stream >> attnType;
- __readExpr(io_stream, regType);
+ __readExpr(io_stream, io_isoChip, isoNode);
}
// Add child nodes.
for (unsigned int j = 0; j < numChildNodes; j++)
{
+ // Read the child node metadata.
BitPosition_t bit;
NodeId_t childId;
Instance_t childInst;
io_stream >> bit >> childId >> childInst;
}
+
+ // Add this node to the isolation chip.
+ io_isoChip->addIsolationNode(isoNode);
}
}
diff --git a/src/isolator/hei_isolation_node.hpp b/src/isolator/hei_isolation_node.hpp
index 2546a93..33df441 100644
--- a/src/isolator/hei_isolation_node.hpp
+++ b/src/isolator/hei_isolation_node.hpp
@@ -51,8 +51,10 @@
* @param i_id Unique ID for all instances of this node.
* @param i_instance Instance of this node.
*/
- IsolationNode(NodeId_t i_id, Instance_t i_instance) :
- iv_id(i_id), iv_instance(i_instance)
+ IsolationNode(NodeId_t i_id, Instance_t i_instance,
+ RegisterType_t i_regType) :
+ iv_id(i_id),
+ iv_instance(i_instance), iv_regType(i_regType)
{}
/** @brief Destructor. */
@@ -75,6 +77,14 @@
const Instance_t iv_instance;
/**
+ * A registers referenced by this node's rules must be of this type. No
+ * mixing of register types is allowed because comparing different sized
+ * registers is undefined behavior. Note that it is possible to have capture
+ * registers of mixed types.
+ */
+ const RegisterType_t iv_regType;
+
+ /**
* The list of register to capture and add to the log for additional
* debugging.
*/
@@ -85,7 +95,8 @@
* register 'rule' (value) to find any active attentions for each attention
* type (key). A 'rule', like "register & ~mask", is a combination of
* HardwareRegister objects and virtual operator registers (all children
- * of the Register class).
+ * of the Register class). Note that all registers referenced by these rules
+ * must be the same type as iv_regType.
*/
std::map<AttentionType_t, const Register::ConstPtr> iv_rules;
@@ -166,6 +177,12 @@
return {iv_id, iv_instance};
}
+ /** @return This node's register type.. */
+ RegisterType_t getRegisterType() const
+ {
+ return iv_regType;
+ }
+
private: // Isolation stack and supporting functions.
/** When analyze() is called at the tree root, all recursive calls to
* analyze() will target the same chip and attention type. So we only need
diff --git a/src/register/hei_operator_register.hpp b/src/register/hei_operator_register.hpp
index 6bfaca9..5c225b1 100644
--- a/src/register/hei_operator_register.hpp
+++ b/src/register/hei_operator_register.hpp
@@ -72,18 +72,18 @@
* @brief Constructor from components.
* @param i_arg Target register for operation.
*/
- explicit NotRegister(Register& i_arg) :
- OperatorRegister(i_arg.getSize()), iv_child(&i_arg)
+ explicit NotRegister(Register::ConstPtr i_arg) :
+ OperatorRegister(i_arg->getSize()), iv_child(i_arg)
{}
- /** @brief Default destructor. */
+ /** @brief Destructor. */
~NotRegister() = default;
- /** @brief Default copy constructor. */
- NotRegister(const NotRegister&) = default;
+ /** @brief Copy constructor. */
+ NotRegister(const NotRegister&) = delete;
- /** @brief Default assignment operator. */
- NotRegister& operator=(const NotRegister& r) = default;
+ /** @brief Assignment operator. */
+ NotRegister& operator=(const NotRegister& r) = delete;
/** @brief Overloaded from parent class. */
const BitString* getBitString(const Chip& i_chip) const override
@@ -108,7 +108,7 @@
}
private:
- Register* iv_child;
+ const Register::ConstPtr iv_child;
};
/**
@@ -126,18 +126,18 @@
* @param i_arg Target register for operation.
* @param i_amount The shift value.
*/
- LeftShiftRegister(Register& i_arg, uint16_t i_amount) :
- OperatorRegister(i_arg.getSize()), iv_child(&i_arg), iv_amount(i_amount)
+ LeftShiftRegister(Register::ConstPtr i_arg, size_t i_amount) :
+ OperatorRegister(i_arg->getSize()), iv_child(i_arg), iv_amount(i_amount)
{}
- /** @brief Default destructor. */
+ /** @brief Destructor. */
~LeftShiftRegister() = default;
- /** @brief Default copy constructor. */
- LeftShiftRegister(const LeftShiftRegister&) = default;
+ /** @brief Copy constructor. */
+ LeftShiftRegister(const LeftShiftRegister&) = delete;
- /** @brief Default assignment operator. */
- LeftShiftRegister& operator=(const LeftShiftRegister& r) = default;
+ /** @brief Assignment operator. */
+ LeftShiftRegister& operator=(const LeftShiftRegister& r) = delete;
/** @brief Overloaded from parent class. */
const BitString* getBitString(const Chip& i_chip) const override
@@ -164,8 +164,8 @@
}
private:
- Register* iv_child;
- uint16_t iv_amount;
+ const Register::ConstPtr iv_child;
+ const size_t iv_amount;
};
/**
@@ -183,18 +183,18 @@
* @param i_arg Target register for operation.
* @param i_amount The shift value.
*/
- RightShiftRegister(Register& i_arg, uint16_t i_amount) :
- OperatorRegister(i_arg.getSize()), iv_child(&i_arg), iv_amount(i_amount)
+ RightShiftRegister(Register::ConstPtr i_arg, size_t i_amount) :
+ OperatorRegister(i_arg->getSize()), iv_child(i_arg), iv_amount(i_amount)
{}
- /** @brief Default destructor. */
+ /** @brief Destructor. */
~RightShiftRegister() = default;
- /** @brief Default copy constructor. */
- RightShiftRegister(const RightShiftRegister&) = default;
+ /** @brief Copy constructor. */
+ RightShiftRegister(const RightShiftRegister&) = delete;
- /** @brief Default assignment operator. */
- RightShiftRegister& operator=(const RightShiftRegister& r) = default;
+ /** @brief Assignment operator. */
+ RightShiftRegister& operator=(const RightShiftRegister& r) = delete;
/** @brief Overloaded from parent class. */
const BitString* getBitString(const Chip& i_chip) const override
@@ -221,8 +221,8 @@
}
private:
- Register* iv_child;
- uint16_t iv_amount;
+ const Register::ConstPtr iv_child;
+ const size_t iv_amount;
};
/**
@@ -241,19 +241,22 @@
* @param i_left Target register for operation.
* @param i_right Target register for operation.
*/
- AndRegister(Register& i_left, Register& i_right) :
- OperatorRegister(std::min(i_left.getSize(), i_right.getSize())),
- iv_left(&i_left), iv_right(&i_right)
- {}
+ AndRegister(Register::ConstPtr i_left, Register::ConstPtr i_right) :
+ OperatorRegister(i_left->getSize()), iv_left(i_left), iv_right(i_right)
+ {
+ // The two registers must be the same sizes or it makes for some weird
+ // results.
+ HEI_ASSERT(iv_left->getSize() == iv_right->getSize());
+ }
- /** @brief Default destructor. */
+ /** @brief Destructor. */
~AndRegister() = default;
- /** @brief Default copy constructor. */
- AndRegister(const AndRegister&) = default;
+ /** @brief Copy constructor. */
+ AndRegister(const AndRegister&) = delete;
- /** @brief Default assignment operator. */
- AndRegister& operator=(const AndRegister& r) = default;
+ /** @brief Assignment operator. */
+ AndRegister& operator=(const AndRegister& r) = delete;
/** @brief Overloaded from parent class. */
const BitString* getBitString(const Chip& i_chip) const override
@@ -281,8 +284,8 @@
}
private:
- Register* iv_left;
- Register* iv_right;
+ const Register::ConstPtr iv_left;
+ const Register::ConstPtr iv_right;
};
/**
@@ -301,19 +304,22 @@
* @param i_left Target register for operation.
* @param i_right Target register for operation.
*/
- OrRegister(Register& i_left, Register& i_right) :
- OperatorRegister(std::min(i_left.getSize(), i_right.getSize())),
- iv_left(&i_left), iv_right(&i_right)
- {}
+ OrRegister(Register::ConstPtr i_left, Register::ConstPtr i_right) :
+ OperatorRegister(i_left->getSize()), iv_left(i_left), iv_right(i_right)
+ {
+ // The two registers must be the same sizes or it makes for some weird
+ // results.
+ HEI_ASSERT(iv_left->getSize() == iv_right->getSize());
+ }
- /** @brief Default destructor. */
+ /** @brief Destructor. */
~OrRegister() = default;
- /** @brief Default copy constructor. */
- OrRegister(const OrRegister&) = default;
+ /** @brief Copy constructor. */
+ OrRegister(const OrRegister&) = delete;
- /** @brief Default assignment operator. */
- OrRegister& operator=(const OrRegister& r) = default;
+ /** @brief Assignment operator. */
+ OrRegister& operator=(const OrRegister& r) = delete;
/** @brief Overloaded from parent class. */
const BitString* getBitString(const Chip& i_chip) const override
@@ -341,36 +347,38 @@
}
private:
- Register* iv_left;
- Register* iv_right;
+ const Register::ConstPtr iv_left;
+ const Register::ConstPtr iv_right;
};
/**
* @brief Contains a constant value that can be used within any of the other
* register operators. The value can be retrieved using the
* getBitString() function.
- **/
+ */
class ConstantRegister : public OperatorRegister
{
public:
/**
* @brief Constructor from components.
- * @param i_arg A BitStringBuffer containing the constant value.
+ * @param i_val An unsigned integer value. iv_result will be initialized to
+ * the size of type T and this value will be copied into that
+ * buffer.
*/
- explicit ConstantRegister(const BitStringBuffer& i_arg) :
- OperatorRegister(BitString::getMinBytes(i_arg.getBitLen()))
+ template <class T>
+ explicit ConstantRegister(T i_val) : OperatorRegister(sizeof(i_val))
{
- iv_result = i_arg;
+ iv_result.setFieldRight(0, iv_result.getBitLen(), i_val);
}
- /** @brief Default destructor. */
+ /** @brief Destructor. */
~ConstantRegister() = default;
- /** @brief Default copy constructor. */
- ConstantRegister(const ConstantRegister&) = default;
+ /** @brief Copy constructor. */
+ ConstantRegister(const ConstantRegister&) = delete;
- /** @brief Default assignment operator. */
- ConstantRegister& operator=(const ConstantRegister& r) = default;
+ /** @brief Assignment operator. */
+ ConstantRegister& operator=(const ConstantRegister& r) = delete;
/** @brief Overloaded from parent class. */
const BitString* getBitString(const Chip& i_chip) const override
diff --git a/src/util/hei_bit_string.cpp b/src/util/hei_bit_string.cpp
index 9cc2613..a04fb43 100644
--- a/src/util/hei_bit_string.cpp
+++ b/src/util/hei_bit_string.cpp
@@ -286,25 +286,29 @@
bool BitString::operator<(const BitString& i_str) const
{
- // The two bit strings must be the same length. Otherwise, the comparison
- // undefined (i.e. compare from the left vs. right).
- HEI_ASSERT(getBitLen() == i_str.getBitLen());
-
- for (uint64_t pos = 0; pos < getBitLen(); pos += UINT64_BIT_LEN)
+ if (getBitLen() < i_str.getBitLen())
{
- uint64_t len = std::min(getBitLen() - pos, UINT64_BIT_LEN);
-
- auto l_str = getFieldRight(pos, len);
- auto r_str = i_str.getFieldRight(pos, len);
-
- if (l_str < r_str)
+ return true;
+ }
+ else if (getBitLen() == i_str.getBitLen())
+ {
+ // Can only compare the bit strings if the length is the same.
+ for (uint64_t pos = 0; pos < getBitLen(); pos += UINT64_BIT_LEN)
{
- return true;
- }
- // The loop can only continue if the values are equal.
- else if (l_str > r_str)
- {
- return false;
+ uint64_t len = std::min(getBitLen() - pos, UINT64_BIT_LEN);
+
+ auto l_str = getFieldRight(pos, len);
+ auto r_str = i_str.getFieldRight(pos, len);
+
+ if (l_str < r_str)
+ {
+ return true;
+ }
+ // The loop can only continue if the values are equal.
+ else if (l_str > r_str)
+ {
+ return false;
+ }
}
}
diff --git a/src/util/hei_bit_string.hpp b/src/util/hei_bit_string.hpp
index 669e755..59369b7 100644
--- a/src/util/hei_bit_string.hpp
+++ b/src/util/hei_bit_string.hpp
@@ -333,7 +333,15 @@
return isEqual(i_str);
}
- /** @brief Less-than operator */
+ /**
+ * @brief Less-than operator.
+ *
+ * IMPORTANT:
+ * The purpose of this function is primarily for sorting these objects in
+ * data structures like map and vector. It does not guarantee a less than
+ * comparison of the bit strings because bit strings can vary in length and
+ * it is difficult to define that kind of comparison.
+ */
bool operator<(const BitString& i_str) const;
/** @brief Bitwise NOT operator. */
diff --git a/test/hei_operator_register_testcase.cpp b/test/hei_operator_register_testcase.cpp
deleted file mode 100644
index 47cb53e..0000000
--- a/test/hei_operator_register_testcase.cpp
+++ /dev/null
@@ -1,387 +0,0 @@
-#include <hei_chip.hpp>
-#include <hei_includes.hpp>
-#include <register/hei_hardware_register.hpp>
-#include <register/hei_operator_register.hpp>
-#include <register/hei_register.hpp>
-
-#include <iomanip>
-#include <iostream>
-
-#define BITSTRING_BIT_WIDTH 16
-#define CONSTANT1 0x1458 // 1458
-#define CONSTANT2 0x5368 // 5468
-
-using namespace std;
-using namespace libhei;
-
-int main()
-{
-
- Chip my_chip{nullptr, 0};
- size_t constant1 = CONSTANT1;
- size_t constant2 = CONSTANT2;
-
- // Initializing two registers
-
- cout << "\n\n\nInitializing two constant registers ";
- cout << "(leftside & rightside):\n\n";
-
- cout << "\nCreating BitString \"bsa\".\n";
- BitStringBuffer bsa{BITSTRING_BIT_WIDTH};
- cout << "Setting BitString \"bsa\" to: ";
- cout << "0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4) << hex
- << uppercase << constant1 << "\n";
- bsa.setFieldRight(0, BITSTRING_BIT_WIDTH, constant1);
-
- cout << "\nCreating BitString \"bsb\".\n";
- BitStringBuffer bsb{BITSTRING_BIT_WIDTH};
- cout << "Setting BitString \"bsb\" to: ";
- cout << "0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4) << hex
- << uppercase << constant2 << "\n\n";
- bsb.setFieldRight(0, BITSTRING_BIT_WIDTH, constant2);
-
- cout << "Creating \"leftside\" register from bsa.\n";
- ConstantRegister leftside(bsa);
- cout << "Creating \"rightside\" register from bsb.\n";
- ConstantRegister rightside(bsb);
-
- cout << "Leftside: ";
- cout << "0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4) << hex
- << leftside.getBitString(my_chip)->getFieldRight(0,
- BITSTRING_BIT_WIDTH);
-
- cout << " Rightside: ";
- cout << "0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4) << hex
- << rightside.getBitString(my_chip)->getFieldRight(0,
- BITSTRING_BIT_WIDTH);
- cout << "\n\n";
-
- // Basic functional tests:
- // AND
- cout << "Instantiating my_and_register passing in two registers:\n";
- cout << "AndRegister my_and_register(leftside, rightside);\n";
- AndRegister my_and_register(leftside, rightside);
- cout << "AND result: ";
- cout << "0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4) << hex
- << my_and_register.getBitString(my_chip)->getFieldRight(
- 0, BITSTRING_BIT_WIDTH)
- << "\n\n";
-
- // NOT
- cout << "Instantiating my_not_register passing in my_and_register "
- << "from above:\n";
- cout << "NotRegister my_not_register(my_and_register);\n";
- NotRegister my_not_register(my_and_register);
- cout << "NOT result: ";
- cout << "0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4) << hex
- << my_not_register.getBitString(my_chip)->getFieldRight(
- 0, BITSTRING_BIT_WIDTH)
- << "\n\n";
-
- // Left Shift
- cout << "Instantiating my_leftshift_register passing "
- << "in my_not_register from above and a 4 directing i"
- << "a left shift of 4 bits:\n";
- cout << "LeftShiftRegister my_leftshift_register(my_not_register, 4);\n";
- LeftShiftRegister my_leftshift_register(my_not_register, 4);
- cout << "LeftShift result: ";
- cout << "0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4) << hex
- << my_leftshift_register.getBitString(my_chip)->getFieldRight(
- 0, BITSTRING_BIT_WIDTH)
- << "\n\n";
-
- // Right Shift
- cout << "Instantiating my_rightshift_register passing in "
- << "my_leftshift_register from above and a 4 directing "
- << "a right shift of 4 bits:\n";
- cout << "RightShiftRegister my_rightshift_register("
- << "my_leftshift_register, 4);\n";
- RightShiftRegister my_rightshift_register(my_leftshift_register, 4);
- cout << "Right Shift result: ";
- cout << "0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4) << hex
- << my_rightshift_register.getBitString(my_chip)->getFieldRight(
- 0, BITSTRING_BIT_WIDTH)
- << "\n\n";
-
- // OR
- cout << "Instantiating my_or_register passing in my_leftshift_register"
- << " and my_rightshift_register from above:\n";
- cout << "OrRegister my_or_register(my_leftshift_register,"
- << "my_rightshift_register);\n";
- OrRegister my_or_register(my_leftshift_register, my_rightshift_register);
- cout << "OR result: ";
- cout << "0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4) << hex
- << my_or_register.getBitString(my_chip)->getFieldRight(
- 0, BITSTRING_BIT_WIDTH)
- << "\n\n";
-
- // = operator
-
- // ConstantRegister
- cout << "\nExercising operator \"=\" (assignment):\n\n";
-
- cout << "Assigning leftside register to constreg1 register. (";
- ConstantRegister constreg1 = leftside;
- cout << "0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4) << hex
- << constreg1.getBitString(my_chip)->getFieldRight(0,
- BITSTRING_BIT_WIDTH)
- << ")\n";
- cout << "ConstantRegister constreg1 = leftside;\n";
-
- cout << "Assigning rightside register to constreg2 register. (";
- ConstantRegister constreg2 = rightside;
- cout << "0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4) << hex
- << constreg2.getBitString(my_chip)->getFieldRight(0,
- BITSTRING_BIT_WIDTH)
- << ")\n";
- cout << "ConstantRegister constreg2 = rightside;\n";
-
- // AndRegister
- cout << "\nCreating and_register1 with leftside & rightside registers.\n";
- cout << "AndRegister and_register1(leftside,rightside);\n";
- AndRegister and_register1(leftside, rightside);
- cout << "Creating and_register2 with the assignment operator (=).\n";
- cout << "AndRegister and_register2 = and_register1;\n";
- AndRegister and_register2 = and_register1;
- cout << "and_register2 = ";
- cout << "0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4) << hex
- << and_register2.getBitString(my_chip)->getFieldRight(
- 0, BITSTRING_BIT_WIDTH)
- << "\n";
-
- // NotRegister
- cout << "\nCreating not_register1 with leftside register.\n";
- cout << "NotRegister not_register1(leftside);\n";
- NotRegister not_register1(leftside);
- cout << "Creating not_register2 with the assignment operator (=).\n";
- cout << "NotRegister not_register2 = not_register1;\n";
- NotRegister not_register2 = not_register1;
- cout << "not_register2 = ";
- cout << "0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4) << hex
- << not_register2.getBitString(my_chip)->getFieldRight(
- 0, BITSTRING_BIT_WIDTH)
- << "\n";
-
- // LeftShiftRegister
- cout << "\nCreating leftshift_register1 with leftside register.\n";
- cout << "LeftShiftRegister leftshift_register1(leftside,4);\n";
- LeftShiftRegister leftshift_register1(leftside, 4);
- cout << "Creating leftshift_register2 with the assignment operator (=).\n";
- cout << "LeftShiftRegister leftshift_register2 = leftshift_register1;\n";
- LeftShiftRegister leftshift_register2 = leftshift_register1;
- cout << "leftshift_register2 = ";
- cout << "0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4) << hex
- << leftshift_register2.getBitString(my_chip)->getFieldRight(
- 0, BITSTRING_BIT_WIDTH)
- << "\n";
-
- // RightShiftRegister
- cout << "\nCreating rightshift_register1 with leftside register.\n";
- cout << "RightShiftRegister rightshift_register1(leftside,4);\n";
- RightShiftRegister rightshift_register1(leftside, 4);
- cout << "Creating rightshift_register2 with the assignment operator (=).\n";
- cout << "RightShiftRegister rightshift_register2 = rightshift_register1;\n";
- RightShiftRegister rightshift_register2 = rightshift_register1;
- cout << "rightshift_register2 = ";
- cout << "0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4) << hex
- << rightshift_register2.getBitString(my_chip)->getFieldRight(
- 0, BITSTRING_BIT_WIDTH)
- << "\n";
-
- // OrRegister
- cout << "\nCreating or_register1 with leftside & rightside registers.\n";
- cout << "OrRegister or_register1(leftside,rightside);\n";
- OrRegister or_register1(leftside, rightside);
- cout << "or_register1 = ";
- cout << "0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4) << hex
- << or_register1.getBitString(my_chip)->getFieldRight(
- 0, BITSTRING_BIT_WIDTH)
- << "\n";
- cout << "Creating or_register2 with the assignment operator (=).\n";
- cout << "OrRegister or_register2 = or_register1;\n";
- OrRegister or_register2 = or_register1;
- cout << "or_register2 = ";
- cout << "0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4) << hex
- << or_register2.getBitString(my_chip)->getFieldRight(
- 0, BITSTRING_BIT_WIDTH)
- << "\n";
-
- //***** == operator *****
- cout << "\nOperator \"==\" (equality)\n\n";
- cout << "Operation Register1 = Register2 Equality\n";
-
- // Constant Register
- ConstantRegister cr1(leftside);
- ConstantRegister cr2(rightside);
- cout << " Constant 0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4)
- << hex
- << cr1.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH);
- cout << " 0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4) << hex
- << cr2.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH);
- if (cr1 == cr2)
- cout << " Equal\n";
- else
- cout << " Not Equal\n";
-
- // And Register
- AndRegister and1(leftside, rightside);
- AndRegister and2(leftside, rightside);
-
- cout << " And 0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4)
- << hex
- << and1.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH);
- cout << " 0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4) << hex
- << and2.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH);
- if (and1 == and2)
- cout << " Equal\n";
- else
- cout << " Not Equal\n";
-
- // Not Register
- NotRegister nr1(leftside);
- NotRegister nr2(rightside);
- cout << " Not 0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4)
- << hex
- << nr1.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH);
- cout << " 0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4) << hex
- << nr2.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH);
- if (nr1 == nr2)
- cout << " Equal\n";
- else
- cout << " Not Equal\n";
-
- // Left Shift Register
- LeftShiftRegister lsr1(leftside, 4);
- LeftShiftRegister lsr2(rightside, 4);
- cout << " Left Shift 0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4)
- << hex
- << lsr1.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH);
- cout << " 0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4) << hex
- << lsr2.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH);
- if (lsr1 == lsr2)
- cout << " Equal\n";
- else
- cout << " Not Equal\n";
-
- // Right Shift Register
- RightShiftRegister rsr1(leftside, 6);
- RightShiftRegister rsr2(rightside, 6);
- cout << " Right Shift 0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4)
- << hex
- << rsr1.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH);
- cout << " 0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4) << hex
- << rsr2.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH);
- if (rsr1 == rsr2)
- cout << " Equal\n";
- else
- cout << " Not Equal\n";
-
- // Or Register
- OrRegister or1(leftside, rightside);
- OrRegister or2(leftside, rightside);
- cout << " OR 0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4)
- << hex
- << or1.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH);
- cout << " 0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4) << hex
- << or2.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH);
- if (or1 == or2)
- cout << " Equal\n";
- else
- cout << " Not Equal\n";
-
- //***** < operator *****
- cout << "\nOperator \"<\" (equality)\n\n";
- cout << "Operation Register1 < Register2 Equal/Less Than\n";
-
- // Constant Register
- ConstantRegister cr1a(leftside);
- ConstantRegister cr2a(rightside);
- cout << " Constant 0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4)
- << hex
- << cr1a.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH);
- cout << " 0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4) << hex
- << cr2a.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH);
- // if (cr1a < cr2a)
- if (cr1a.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH) <
- cr2a.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH))
- cout << " Less Than\n";
- else
- cout << " Not Less Than\n";
-
- // And Register
- AndRegister and1a(leftside, rightside);
- AndRegister and2a(leftside, rightside);
- cout << " And 0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4)
- << hex
- << and1a.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH);
- cout << " 0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4) << hex
- << and2a.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH);
- // if (and2a < and1a)
- if (and1a.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH) <
- and2a.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH))
- cout << " Less Than\n";
- else
- cout << " Not Less Than\n";
-
- // Not Register
- NotRegister nr1a(leftside);
- NotRegister nr2a(rightside);
- cout << " Not 0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4)
- << hex
- << nr1a.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH);
- cout << " 0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4) << hex
- << nr2a.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH);
- // if (nr1a < nr2a) Paul
- if (nr1a.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH) <
- nr2a.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH))
- cout << " Less Than\n";
- else
- cout << " Not Less Than\n";
-
- // Left Shift Register
- LeftShiftRegister lsr1a(leftside, 4);
- LeftShiftRegister lsr2a(leftside, 4);
- cout << " Left Shift 0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4)
- << hex
- << lsr1a.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH);
- cout << " 0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4) << hex
- << lsr2a.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH);
- // if (lsr1a < lsr2a)
- if (lsr1a.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH) <
- lsr2a.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH))
- cout << " Less Than\n";
- else
- cout << " Not Less Than\n";
-
- // Right Shift Register
- RightShiftRegister rsr1a(leftside, 4);
- RightShiftRegister rsr2a(leftside, 4);
- cout << " Right Shift 0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4)
- << hex
- << rsr1a.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH);
- cout << " 0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4) << hex
- << rsr2a.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH);
- // if (rsr1a < rsr2a)
- if (rsr1a.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH) <
- rsr2a.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH))
- cout << " Less Than\n";
- else
- cout << " Not Less Than\n";
-
- // Or Register
- OrRegister or1a(leftside, rightside);
- OrRegister or2a(leftside, rightside);
- cout << " Or 0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4)
- << hex
- << or1a.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH);
- cout << " 0x" << setfill('0') << setw(BITSTRING_BIT_WIDTH / 4) << hex
- << or2a.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH);
- // if (or1a < or2a)
- if (or1a.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH) <
- or2a.getBitString(my_chip)->getFieldRight(0, BITSTRING_BIT_WIDTH))
- cout << " Less Than\n";
- else
- cout << " Not Less Than\n";
-
- return (0);
-}
diff --git a/test/meson.build b/test/meson.build
index 642b827..e780a2e 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -8,7 +8,8 @@
# build g-test framework unit tests
gtests = [
'bit_string_test',
- 'flyweight_test'
+ 'flyweight_test',
+ 'operator_register_test',
]
gtest = dependency('gtest', main : true, required : false, method : 'system')
@@ -21,10 +22,3 @@
endforeach
endif
-# build unit-test framework
-tests = ['hei_operator_register_testcase']
-
-foreach t : tests
- test(t, executable(t.underscorify(), t + '.cpp', test_src, \
- include_directories : incdir))
-endforeach
diff --git a/test/operator_register_test.cpp b/test/operator_register_test.cpp
new file mode 100644
index 0000000..227a566
--- /dev/null
+++ b/test/operator_register_test.cpp
@@ -0,0 +1,152 @@
+#include <hei_chip.hpp>
+#include <register/hei_operator_register.hpp>
+#include <util/hei_flyweight.hpp>
+
+#include "gtest/gtest.h"
+
+using namespace libhei;
+
+constexpr uint16_t CONST1 = 0x1458;
+constexpr uint16_t CONST2 = 0x5368;
+
+#define MATH(x) static_cast<uint16_t>(x)
+
+uint64_t __getVal(Register::ConstPtr i_reg)
+{
+ Chip CHIP{nullptr, 0};
+ auto bs = i_reg->getBitString(CHIP);
+ return bs->getFieldRight(0, bs->getBitLen());
+}
+
+size_t __getBW(Register::ConstPtr i_reg)
+{
+ Chip CHIP{nullptr, 0};
+ return i_reg->getBitString(CHIP)->getBitLen();
+}
+
+TEST(OperatorRegisterTest, BasicOperations)
+{
+ auto const1 = std::make_shared<const ConstantRegister>(CONST1);
+ ASSERT_EQ(MATH(CONST1), __getVal(const1));
+
+ auto const2 = std::make_shared<const ConstantRegister>(CONST2);
+ ASSERT_EQ(MATH(CONST2), __getVal(const2));
+
+ auto and1 = std::make_shared<const AndRegister>(const1, const2);
+ ASSERT_EQ(MATH(CONST1 & CONST2), __getVal(and1));
+
+ auto or1 = std::make_shared<const OrRegister>(const1, const2);
+ ASSERT_EQ(MATH(CONST1 | CONST2), __getVal(or1));
+
+ auto not1 = std::make_shared<const NotRegister>(const1);
+ ASSERT_EQ(MATH(~CONST1), __getVal(not1));
+
+ auto not2 = std::make_shared<const NotRegister>(const2);
+ ASSERT_EQ(MATH(~CONST2), __getVal(not2));
+}
+
+TEST(OperatorRegisterTest, BasicOperationsWithFlyweights)
+{
+ auto& const_factory = Flyweight<const ConstantRegister>::getSingleton();
+ auto& and_factory = Flyweight<const AndRegister>::getSingleton();
+ auto& or_factory = Flyweight<const OrRegister>::getSingleton();
+ auto& not_factory = Flyweight<const NotRegister>::getSingleton();
+
+ auto const1 = const_factory.get(CONST1);
+ auto const2 = const_factory.get(CONST2);
+
+ ASSERT_EQ(MATH(CONST1), __getVal(const1));
+ ASSERT_EQ(MATH(CONST2), __getVal(const2));
+ ASSERT_EQ(MATH(CONST1 & CONST2), __getVal(and_factory.get(const1, const2)));
+ ASSERT_EQ(MATH(CONST1 | CONST2), __getVal(or_factory.get(const1, const2)));
+ ASSERT_EQ(MATH(~CONST1), __getVal(not_factory.get(const1)));
+ ASSERT_EQ(MATH(~CONST2), __getVal(not_factory.get(const2)));
+
+ const_factory.clear();
+ and_factory.clear();
+ or_factory.clear();
+ not_factory.clear();
+}
+
+TEST(OperatorRegisterTest, ShiftOperations)
+{
+ auto& const_factory = Flyweight<const ConstantRegister>::getSingleton();
+ auto& lshift_factory = Flyweight<const LeftShiftRegister>::getSingleton();
+ auto& rshift_factory = Flyweight<const RightShiftRegister>::getSingleton();
+
+ auto const1 = const_factory.get(CONST1);
+
+ for (size_t i = 0; i < __getBW(const1); i++)
+ {
+ ASSERT_EQ(MATH(CONST1 << i), __getVal(lshift_factory.get(const1, i)));
+ }
+
+ for (size_t i = 0; i < __getBW(const1); i++)
+ {
+ ASSERT_EQ(MATH(CONST1 >> i), __getVal(rshift_factory.get(const1, i)));
+ }
+
+ const_factory.clear();
+ lshift_factory.clear();
+ rshift_factory.clear();
+}
+
+TEST(OperatorRegisterTest, ComplexOperation)
+{
+ // Something seemingly complex:
+ // ~(((CONST1 & CONST2) << 12) | ((CONST1 | CONST2) >> 4)))
+
+ auto& const_factory = Flyweight<const ConstantRegister>::getSingleton();
+ auto& and_factory = Flyweight<const AndRegister>::getSingleton();
+ auto& or_factory = Flyweight<const OrRegister>::getSingleton();
+ auto& not_factory = Flyweight<const NotRegister>::getSingleton();
+ auto& lshift_factory = Flyweight<const LeftShiftRegister>::getSingleton();
+ auto& rshift_factory = Flyweight<const RightShiftRegister>::getSingleton();
+
+ auto const1 = const_factory.get(CONST1);
+ auto const2 = const_factory.get(CONST2);
+
+ auto lshift = lshift_factory.get(and_factory.get(const1, const2), 12);
+ auto rshift = rshift_factory.get(or_factory.get(const1, const2), 4);
+
+ auto expr = not_factory.get(or_factory.get(lshift, rshift));
+
+ ASSERT_EQ(MATH(~(((CONST1 & CONST2) << 12) | ((CONST1 | CONST2) >> 4))),
+ __getVal(expr));
+
+ const_factory.clear();
+ and_factory.clear();
+ or_factory.clear();
+ not_factory.clear();
+ lshift_factory.clear();
+ rshift_factory.clear();
+}
+
+TEST(OperatorRegisterTest, ConstRegConstructor)
+{
+ auto& const_factory = Flyweight<const ConstantRegister>::getSingleton();
+ auto& and_factory = Flyweight<const AndRegister>::getSingleton();
+
+ // The ConstRegister constructor is a template that requires some integer
+ // type.
+
+ auto const1 = const_factory.get(CONST1); // CONST1 is uint16_t, GOOD
+
+ auto const2 = const_factory.get(uint16_t{0x1458}); // This also works
+
+ ASSERT_EQ(const1, const2); // Should point to the same thing.
+
+ // If you pass in a constant with no type the compiler assumes it is the
+ // implicit int type. This value is the same as const2, but the size will be
+ // different.
+ auto const3 = const_factory.get(0x1458);
+
+ // The values are the same, but the bit strings are are different sizes.
+ ASSERT_NE(const2, const3);
+
+ // AND and OR operators will not like different sizes either.
+ ASSERT_DEATH(and_factory.get(const2, const3), "");
+
+ const_factory.clear();
+ and_factory.clear();
+}