Optimize assertion control queries (#8547)

This commit is contained in:
Artur Bieniek
2026-09-30 11:32:56 -04:00
committed by GitHub
parent 055b870e11
commit d4e4b1d795
6 changed files with 56 additions and 204 deletions
+3 -19
View File
@@ -3128,32 +3128,16 @@ VerilatedContext::Serialized::Serialized() {
bool VerilatedContext::assertOn() const VL_MT_SAFE { return m_s.m_assertOn; }
void VerilatedContext::assertOn(bool flag) VL_MT_SAFE {
if (assertCtlsLocked()) return;
if (m_ns.m_assertCtlsLocked) return;
// Set all assert and directive types when true, clear otherwise.
m_s.m_assertOn = VL_MASK_I(ASSERT_ON_WIDTH) * flag;
}
bool VerilatedContext::assertOnGet(VerilatedAssertType_t type,
VerilatedAssertDirectiveType_t directive) const VL_MT_SAFE {
return assertCtlGet(VerilatedAssertCtlQuery::ASSERT_CTL_ON, type, directive);
}
void VerilatedContext::assertOnSet(VerilatedAssertType_t types,
VerilatedAssertDirectiveType_t directives) VL_MT_SAFE {
if (assertCtlsLocked()) return;
m_s.m_assertOn |= assertOnMask(types, directives);
}
void VerilatedContext::assertOnClear(VerilatedAssertType_t types,
VerilatedAssertDirectiveType_t directives) VL_MT_SAFE {
if (assertCtlsLocked()) return;
m_s.m_assertOn &= ~assertOnMask(types, directives);
}
bool VerilatedContext::assertCtlsLocked() const VL_MT_SAFE { return m_ns.m_assertCtlsLocked; }
void VerilatedContext::assertCtlsLocked(bool flag) VL_MT_SAFE { m_ns.m_assertCtlsLocked = flag; }
void VerilatedContext::assertCtl(uint32_t controlType, VerilatedAssertType_t types,
VerilatedAssertDirectiveType_t directives) VL_MT_SAFE {
// IEEE 1800-2023 Table 20-5 control_type. Lock freezes the On/Off state of the
// selected bits until Unlock; On/Off/Kill leave locked bits unchanged.
// +verilator+assert+lock freezes everything, including Lock/Unlock itself.
if (assertCtlsLocked()) return;
if (m_ns.m_assertCtlsLocked) return;
const uint32_t mask = assertOnMask(types, directives);
const uint32_t lockedMask = mask & ~m_s.m_assertLock;
switch (controlType) {
@@ -3598,7 +3582,7 @@ void VerilatedContextImp::commandArgVl(const std::string& arg) {
std::string str;
uint64_t u64;
if (arg == "+verilator+assert+lock") {
assertCtlsLocked(true);
m_ns.m_assertCtlsLocked = true;
} else if (commandArgVlString(arg, "+verilator+coverage+file+", str)) {
coverageFilename(str);
} else if (arg == "+verilator+debug") {
+21 -32
View File
@@ -510,8 +510,8 @@ private:
= ASSERT_DIRECTIVE_TYPE_MASK_WIDTH * std::numeric_limits<VerilatedAssertType_t>::digits
+ 1;
// Build the assertion-control bit mask for the given assertion x directive types.
static inline uint32_t assertOnMask(VerilatedAssertType_t types,
VerilatedAssertDirectiveType_t directives) VL_PURE;
static constexpr uint32_t assertOnMask(VerilatedAssertType_t types,
VerilatedAssertDirectiveType_t directives) VL_PURE;
static constexpr size_t ASSERT_CONTROL_SLOT_COUNT = ASSERT_ON_WIDTH - 1;
// No termination request has stamped m_finishPendingTime yet
static constexpr uint64_t TIME_UNSET = ~0ULL;
@@ -651,28 +651,9 @@ public:
bool assertOn() const VL_MT_SAFE;
/// Enable all assertion types
void assertOn(bool flag) VL_MT_SAFE;
/// Get enabled status for given assertion types
bool assertOnGet(VerilatedAssertType_t type,
VerilatedAssertDirectiveType_t directive) const VL_MT_SAFE;
/// Set enabled status for given assertion types
void assertOnSet(VerilatedAssertType_t types,
VerilatedAssertDirectiveType_t directives) VL_MT_SAFE;
/// Clear enabled status for given assertion types
void assertOnClear(VerilatedAssertType_t types,
VerilatedAssertDirectiveType_t directives) VL_MT_SAFE;
/// Return if assertion-control updates are locked. When locked, RTL assert
// control statements ($asserton/$assertoff/$assertcontrol) are ignored, as
// are updates from the C++ API.
bool assertCtlsLocked() const VL_MT_SAFE;
/// Lock/unlock assertion-control updates.
void assertCtlsLocked(bool flag) VL_MT_SAFE;
/// Apply assertion control for given control, assertion, and directive types
void assertCtl(uint32_t controlType, VerilatedAssertType_t types,
VerilatedAssertDirectiveType_t directives) VL_MT_SAFE;
/// Get assertion-control runtime state. Boolean queries return 0/1, Kill returns
/// the generation count.
inline uint32_t assertCtlGet(VerilatedAssertCtlQuery query, VerilatedAssertType_t type,
VerilatedAssertDirectiveType_t directive) const VL_MT_SAFE;
/// Return if calculating of unused signals (for traces)
bool calcUnusedSigs() const VL_MT_SAFE { return m_s.m_calcUnusedSigs; }
/// Enable calculation of unused signals (for traces)
@@ -848,6 +829,10 @@ public:
bool stopRequestReserve(bool maybe) VL_MT_SAFE;
void stopRequestRelease() VL_MT_SAFE;
// Internal: assertCtlGet() for generated code, with constant type and directive
template <VerilatedAssertType_t T_Type, VerilatedAssertDirectiveType_t T_Directive>
VL_ATTR_ALWINLINE uint32_t assertCtlGet(VerilatedAssertCtlQuery query) const VL_MT_SAFE;
// Internal: access to implementation class
VerilatedContextImp* impp() VL_MT_SAFE { return reinterpret_cast<VerilatedContextImp*>(this); }
const VerilatedContextImp* impp() const VL_MT_SAFE {
@@ -1356,8 +1341,9 @@ void VerilatedContext::timeprecision(int value) VL_MT_SAFE {
}
// Defined here, not in-class: VL_CLOG2_I / VL_FATAL_MT (verilated_funcs.h) are not yet in scope
uint32_t VerilatedContext::assertOnMask(VerilatedAssertType_t types,
VerilatedAssertDirectiveType_t directives) VL_PURE {
constexpr uint32_t
VerilatedContext::assertOnMask(VerilatedAssertType_t types,
VerilatedAssertDirectiveType_t directives) VL_PURE {
// Place the directive bits at each selected assertion type's 3-bit group.
uint32_t mask = 0;
for (int i = 0; i < std::numeric_limits<VerilatedAssertType_t>::digits; ++i) {
@@ -1365,21 +1351,24 @@ uint32_t VerilatedContext::assertOnMask(VerilatedAssertType_t types,
}
return mask;
}
uint32_t
VerilatedContext::assertCtlGet(VerilatedAssertCtlQuery query, VerilatedAssertType_t type,
VerilatedAssertDirectiveType_t directive) const VL_MT_SAFE {
const uint32_t mask = assertOnMask(type, directive);
template <VerilatedAssertType_t T_Type, VerilatedAssertDirectiveType_t T_Directive>
uint32_t VerilatedContext::assertCtlGet(VerilatedAssertCtlQuery query) const VL_MT_SAFE {
// A constexpr local forces compile-time evaluation of the mask, which a plain
// assertOnMask() call does not get from GCC at -Os
constexpr uint32_t mask = assertOnMask(T_Type, T_Directive);
if (!mask) return 0;
// Explicit load(): G++ -Os inlines it but not the implicit conversion.
switch (query) { // LCOV_EXCL_BR_LINE
case VerilatedAssertCtlQuery::ASSERT_CTL_ON: return (m_s.m_assertOn & mask) != 0;
case VerilatedAssertCtlQuery::ASSERT_CTL_ON: return (m_s.m_assertOn.load() & mask) != 0;
case VerilatedAssertCtlQuery::ASSERT_CTL_KILL:
assert(mask && (mask & (mask - 1)) == 0);
return m_s.m_assertKill[VL_CLOG2_I(mask)];
return m_s.m_assertKill[VL_CLOG2_I(mask)].load();
case VerilatedAssertCtlQuery::ASSERT_CTL_PASS_ON_VACUOUS:
return (m_s.m_assertPassOnVacuous & mask) != 0;
return (m_s.m_assertPassOnVacuous.load() & mask) != 0;
case VerilatedAssertCtlQuery::ASSERT_CTL_PASS_ON_NONVACUOUS:
return (m_s.m_assertPassOnNonvacuous & mask) != 0;
case VerilatedAssertCtlQuery::ASSERT_CTL_FAIL_ON: return (m_s.m_assertFailOn & mask) != 0;
return (m_s.m_assertPassOnNonvacuous.load() & mask) != 0;
case VerilatedAssertCtlQuery::ASSERT_CTL_FAIL_ON:
return (m_s.m_assertFailOn.load() & mask) != 0;
default: // LCOV_EXCL_START
VL_FATAL_MT("", 0, "", "Internal: Bad assertCtlGet query");
VL_UNREACHABLE;
+16 -11
View File
@@ -154,6 +154,13 @@ void V3AssertCommon::lowerSequenceEvents(AstNetlist* nodep) {
V3Global::dumpCheckGlobalTree("assertseqevent", 0, dumpTreeEitherLevel() >= 3);
}
string V3AssertCommon::assertCtlGetCall(const char* query, VAssertType type,
VAssertDirectiveType directiveType) {
// Template arguments let the runtime build the type/directive mask at C++ compile time
return "vlSymsp->_vm_contextp__->assertCtlGet<"s + std::to_string(type) + ", "s
+ std::to_string(directiveType) + ">(VerilatedAssertCtlQuery::"s + query + ")"s;
}
//######################################################################
// AssertDeFutureVisitor
// If any AstFuture, then move all non-future varrefs to be one cycle behind,
@@ -335,11 +342,6 @@ class AssertVisitor final : public VNVisitor {
std::unordered_map<const AstAlways*, AstVar*> m_delayedAlways2TickTimep;
// METHODS
static string assertCtlGetCall(const char* query, VAssertType type,
VAssertDirectiveType directiveType) {
return "vlSymsp->_vm_contextp__->assertCtlGet(VerilatedAssertCtlQuery::"s + query + ", "s
+ std::to_string(type) + ", "s + std::to_string(directiveType) + ")"s;
}
static const char* assertPassOnQuery(bool vacuous) {
static constexpr const char* queries[2]
= {"ASSERT_CTL_PASS_ON_NONVACUOUS", "ASSERT_CTL_PASS_ON_VACUOUS"};
@@ -363,8 +365,9 @@ class AssertVisitor final : public VNVisitor {
case VAssertDirectiveType::COVER:
case VAssertDirectiveType::ASSUME: {
if (v3Global.opt.assertOn()) {
return new AstCExpr{fl, AstCExpr::Pure{},
assertCtlGetCall("ASSERT_CTL_ON", type, directiveType), 1};
return new AstCExpr{
fl, AstCExpr::Pure{},
V3AssertCommon::assertCtlGetCall("ASSERT_CTL_ON", type, directiveType), 1};
}
return new AstConst{fl, AstConst::BitFalse{}};
}
@@ -391,15 +394,17 @@ class AssertVisitor final : public VNVisitor {
VAssertDirectiveType directiveType, bool vacuous) {
if (!isControlled(directiveType)) return new AstConst{fl, AstConst::BitTrue{}};
if (!v3Global.opt.assertOn()) return new AstConst{fl, AstConst::BitFalse{}};
return new AstCExpr{fl, AstCExpr::Pure{},
assertCtlGetCall(assertPassOnQuery(vacuous), type, directiveType), 1};
return new AstCExpr{
fl, AstCExpr::Pure{},
V3AssertCommon::assertCtlGetCall(assertPassOnQuery(vacuous), type, directiveType), 1};
}
static AstNodeExpr* assertFailOnCond(FileLine* fl, VAssertType type,
VAssertDirectiveType directiveType) {
if (!isControlled(directiveType)) return new AstConst{fl, AstConst::BitTrue{}};
if (!v3Global.opt.assertOn()) return new AstConst{fl, AstConst::BitFalse{}};
return new AstCExpr{fl, AstCExpr::Pure{},
assertCtlGetCall("ASSERT_CTL_FAIL_ON", type, directiveType), 1};
return new AstCExpr{
fl, AstCExpr::Pure{},
V3AssertCommon::assertCtlGetCall("ASSERT_CTL_FAIL_ON", type, directiveType), 1};
}
string assertDisplayMessage(const AstNode* nodep, const string& prefix, const string& message,
VDisplayType severity) {
+2
View File
@@ -28,6 +28,8 @@ class V3AssertCommon final {
public:
static void collectDefaultDisable(AstNetlist* nodep) VL_MT_DISABLED;
static void lowerSequenceEvents(AstNetlist* nodep) VL_MT_DISABLED;
static string assertCtlGetCall(const char* query, VAssertType type,
VAssertDirectiveType directiveType) VL_MT_DISABLED;
};
class V3Assert final {
+14 -17
View File
@@ -243,12 +243,6 @@ static AstNodeExpr* sampled(AstNodeExpr* exprp) {
return new AstSampled{exprp->fileline(), exprp, exprp->dtypep(), true};
}
static string assertCtlGetCall(const char* query, VAssertType type,
VAssertDirectiveType directiveType) {
return "vlSymsp->_vm_contextp__->assertCtlGet(VerilatedAssertCtlQuery::"s + query + ", "s
+ std::to_string(type) + ", "s + std::to_string(directiveType) + ")"s;
}
static const char* assertPassOnQuery(bool vacuous) {
static constexpr const char* queries[2]
= {"ASSERT_CTL_PASS_ON_NONVACUOUS", "ASSERT_CTL_PASS_ON_VACUOUS"};
@@ -259,13 +253,14 @@ static AstNodeExpr* assertOnCond(FileLine* flp, VAssertType type,
VAssertDirectiveType directiveType) {
if (!v3Global.opt.assertOn()) { return new AstConst{flp, AstConst::BitFalse{}}; }
return new AstCExpr{flp, AstCExpr::Pure{},
assertCtlGetCall("ASSERT_CTL_ON", type, directiveType), 1};
V3AssertCommon::assertCtlGetCall("ASSERT_CTL_ON", type, directiveType), 1};
}
static AstNodeExpr* assertKillGet(FileLine* flp, VAssertType type,
VAssertDirectiveType directiveType) {
return new AstCExpr{flp, AstCExpr::Pure{},
assertCtlGetCall("ASSERT_CTL_KILL", type, directiveType), 32};
V3AssertCommon::assertCtlGetCall("ASSERT_CTL_KILL", type, directiveType),
32};
}
static string assertActionControlPrefix(VAssertDirectiveType directiveType) {
@@ -280,19 +275,21 @@ static string assertActionControlPrefix(VAssertDirectiveType directiveType) {
static AstNodeExpr* assertPassOnCond(FileLine* flp, VAssertType type,
VAssertDirectiveType directiveType, bool vacuous) {
return new AstCExpr{flp, AstCExpr::Pure{},
assertActionControlPrefix(directiveType)
+ assertCtlGetCall(assertPassOnQuery(vacuous), type, directiveType)
+ "))"s,
1};
return new AstCExpr{
flp, AstCExpr::Pure{},
assertActionControlPrefix(directiveType)
+ V3AssertCommon::assertCtlGetCall(assertPassOnQuery(vacuous), type, directiveType)
+ "))"s,
1};
}
static AstNodeExpr* assertFailOnCond(FileLine* flp, VAssertType type,
VAssertDirectiveType directiveType) {
return new AstCExpr{flp, AstCExpr::Pure{},
assertActionControlPrefix(directiveType)
+ assertCtlGetCall("ASSERT_CTL_FAIL_ON", type, directiveType) + "))"s,
1};
return new AstCExpr{
flp, AstCExpr::Pure{},
assertActionControlPrefix(directiveType)
+ V3AssertCommon::assertCtlGetCall("ASSERT_CTL_FAIL_ON", type, directiveType) + "))"s,
1};
}
static AstIf* newPassOnIf(FileLine* flp, AstNodeExpr* firep, AstNode* bodyp, VAssertType type,
-125
View File
@@ -27,140 +27,15 @@ void verilatedTest() {
TEST_CHECK_NZ(contextp->assertOn());
contextp->assertOn(false);
TEST_CHECK_Z(contextp->assertOn());
TEST_CHECK_Z(contextp->assertOnGet(1, 1));
// Setting one type
contextp->assertOnSet(1, 1);
TEST_CHECK_NZ(contextp->assertOnGet(1, 1));
TEST_CHECK_NZ(contextp->assertOn());
TEST_CHECK_Z(contextp->assertOnGet(2, 2));
// Setting types
contextp->assertOn(false);
contextp->assertOnSet(1, 3);
TEST_CHECK_NZ(contextp->assertOnGet(1, 3));
TEST_CHECK_NZ(contextp->assertOnGet(1, 2));
TEST_CHECK_NZ(contextp->assertOnGet(1, 1));
TEST_CHECK_Z(contextp->assertOnGet(1, 0));
TEST_CHECK_Z(contextp->assertOnGet(2, 0));
TEST_CHECK_Z(contextp->assertOnGet(0, 0));
// Setting multiple types separately
contextp->assertOn(false);
contextp->assertOnSet(0, 1);
contextp->assertOnSet(1, 2);
contextp->assertOnSet(2, 3);
TEST_CHECK_NZ(contextp->assertOn());
TEST_CHECK_Z(contextp->assertOnGet(0, 1));
TEST_CHECK_Z(contextp->assertOnGet(1, 1));
TEST_CHECK_NZ(contextp->assertOnGet(1, 2));
TEST_CHECK_NZ(contextp->assertOnGet(2, 1));
TEST_CHECK_NZ(contextp->assertOnGet(2, 2));
TEST_CHECK_NZ(contextp->assertOnGet(2, 3));
TEST_CHECK_Z(contextp->assertOnGet(0, 2));
TEST_CHECK_Z(contextp->assertOnGet(4, 1));
TEST_CHECK_Z(contextp->assertOnGet(8, 7));
// Clearing selected types
contextp->assertOn(true);
contextp->assertOnClear(1, 3);
contextp->assertOnClear(1, 4);
TEST_CHECK_Z(contextp->assertOnGet(1, 1));
TEST_CHECK_Z(contextp->assertOnGet(1, 2));
TEST_CHECK_Z(contextp->assertOnGet(1, 4));
contextp->assertOnClear(4, 4);
TEST_CHECK_Z(contextp->assertOnGet(4, 4));
TEST_CHECK_NZ(contextp->assertOnGet(4, 1));
TEST_CHECK_NZ(contextp->assertOnGet(4, 2));
TEST_CHECK_NZ(contextp->assertOn());
// Clearing all assert types
contextp->assertOn(true);
contextp->assertOnClear(255, 7);
// Everything is disabled except internal asserts
TEST_CHECK_NZ(contextp->assertOn());
contextp->assertOn(false);
// Now everything is disabled
TEST_CHECK_Z(contextp->assertOn());
// Unified runtime query getter
using Query = VerilatedAssertCtlQuery;
constexpr uint32_t LOCK = 1;
constexpr uint32_t UNLOCK = 2;
constexpr uint32_t ON = 3;
constexpr uint32_t OFF = 4;
constexpr uint32_t KILL = 5;
constexpr uint32_t PASS_ON = 6;
constexpr uint32_t PASS_OFF = 7;
constexpr uint32_t FAIL_ON = 8;
constexpr uint32_t FAIL_OFF = 9;
constexpr uint32_t NONVACUOUS_ON = 10;
constexpr uint32_t VACUOUS_OFF = 11;
constexpr uint32_t TYPE = 1;
constexpr uint32_t DIRECTIVE = 1;
TEST_CHECK_Z(contextp->assertCtlGet(Query::ASSERT_CTL_ON, TYPE, DIRECTIVE));
TEST_CHECK_Z(contextp->assertCtlGet(Query::ASSERT_CTL_ON, 0, DIRECTIVE));
contextp->assertCtl(LOCK, TYPE, DIRECTIVE);
contextp->assertCtl(ON, TYPE, DIRECTIVE);
TEST_CHECK_Z(contextp->assertCtlGet(Query::ASSERT_CTL_ON, TYPE, DIRECTIVE));
contextp->assertCtl(UNLOCK, TYPE, DIRECTIVE);
contextp->assertCtl(ON, TYPE, DIRECTIVE);
TEST_CHECK_NZ(contextp->assertCtlGet(Query::ASSERT_CTL_ON, TYPE, DIRECTIVE));
contextp->assertCtl(OFF, TYPE, DIRECTIVE);
TEST_CHECK_Z(contextp->assertCtlGet(Query::ASSERT_CTL_ON, TYPE, DIRECTIVE));
const uint32_t killBefore = contextp->assertCtlGet(Query::ASSERT_CTL_KILL, TYPE, DIRECTIVE);
contextp->assertCtl(KILL, TYPE, DIRECTIVE);
TEST_CHECK_EQ(contextp->assertCtlGet(Query::ASSERT_CTL_KILL, TYPE, DIRECTIVE), killBefore + 1);
TEST_CHECK_Z(contextp->assertCtlGet(Query::ASSERT_CTL_ON, TYPE, DIRECTIVE));
TEST_CHECK_NZ(contextp->assertCtlGet(Query::ASSERT_CTL_PASS_ON_NONVACUOUS, TYPE, DIRECTIVE));
TEST_CHECK_NZ(contextp->assertCtlGet(Query::ASSERT_CTL_PASS_ON_VACUOUS, TYPE, DIRECTIVE));
contextp->assertCtl(PASS_OFF, TYPE, DIRECTIVE);
TEST_CHECK_Z(contextp->assertCtlGet(Query::ASSERT_CTL_PASS_ON_NONVACUOUS, TYPE, DIRECTIVE));
TEST_CHECK_Z(contextp->assertCtlGet(Query::ASSERT_CTL_PASS_ON_VACUOUS, TYPE, DIRECTIVE));
contextp->assertCtl(NONVACUOUS_ON, TYPE, DIRECTIVE);
TEST_CHECK_NZ(contextp->assertCtlGet(Query::ASSERT_CTL_PASS_ON_NONVACUOUS, TYPE, DIRECTIVE));
TEST_CHECK_Z(contextp->assertCtlGet(Query::ASSERT_CTL_PASS_ON_VACUOUS, TYPE, DIRECTIVE));
contextp->assertCtl(PASS_ON, TYPE, DIRECTIVE);
TEST_CHECK_NZ(contextp->assertCtlGet(Query::ASSERT_CTL_PASS_ON_NONVACUOUS, TYPE, DIRECTIVE));
TEST_CHECK_NZ(contextp->assertCtlGet(Query::ASSERT_CTL_PASS_ON_VACUOUS, TYPE, DIRECTIVE));
contextp->assertCtl(VACUOUS_OFF, TYPE, DIRECTIVE);
TEST_CHECK_NZ(contextp->assertCtlGet(Query::ASSERT_CTL_PASS_ON_NONVACUOUS, TYPE, DIRECTIVE));
TEST_CHECK_Z(contextp->assertCtlGet(Query::ASSERT_CTL_PASS_ON_VACUOUS, TYPE, DIRECTIVE));
TEST_CHECK_NZ(contextp->assertCtlGet(Query::ASSERT_CTL_FAIL_ON, TYPE, DIRECTIVE));
contextp->assertCtl(FAIL_OFF, TYPE, DIRECTIVE);
TEST_CHECK_Z(contextp->assertCtlGet(Query::ASSERT_CTL_FAIL_ON, TYPE, DIRECTIVE));
contextp->assertCtl(FAIL_ON, TYPE, DIRECTIVE);
TEST_CHECK_NZ(contextp->assertCtlGet(Query::ASSERT_CTL_FAIL_ON, TYPE, DIRECTIVE));
}
void verilatedLockedTest() {
// With +verilator+assert+lock, every assertion-control update is a no-op
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
// Clear some bits to test assertOnSet
contextp->assertOnClear(2, 3);
const char* argsp[] = {"+verilator+assert+lock"};
contextp->commandArgsAdd(1, argsp);
TEST_CHECK_EQ(contextp->assertCtlsLocked(), true);
// Validate each assert control API call is a no-op
contextp->assertOn(false);
TEST_CHECK_NZ(contextp->assertOn());
contextp->assertOnSet(2, 3);
TEST_CHECK_Z(contextp->assertOnGet(2, 3));
contextp->assertOnClear(1, 1);
TEST_CHECK_NZ(contextp->assertOnGet(1, 1));
contextp->assertCtl(4, 4, 1);
TEST_CHECK_NZ(contextp->assertOnGet(4, 1));
}
int main(int argc, char** argv) {