cxxrtl: use CXXRTL_ASSERT for RTL contract violations instead of assert.
authorwhitequark <whitequark@whitequark.org>
Wed, 2 Dec 2020 19:41:00 +0000 (19:41 +0000)
committerwhitequark <whitequark@whitequark.org>
Wed, 2 Dec 2020 19:41:00 +0000 (19:41 +0000)
RTL contract violations and C++ contract violations are different:
the former depend on the netlist and will never violate memory safety
whereas the latter may. When loading a CXXRTL simulation into another
process, RTL contract violations should generally not crash it, while
C++ contract violations should.

backends/cxxrtl/cxxrtl.h
backends/cxxrtl/cxxrtl_backend.cc

index 41089a153d5fb32d50a5fa3683b1e8dd508a221f..7d3a8485c56f4d4f81227dd8fcaf8c2090d62aff 100644 (file)
 #define CXXRTL_ALWAYS_INLINE inline
 #endif
 
+// CXXRTL uses assert() to check for C++ contract violations (which may result in e.g. undefined behavior
+// of the simulation code itself), and CXXRTL_ASSERT to check for RTL contract violations (which may at
+// most result in undefined simulation results).
+//
+// Though by default, CXXRTL_ASSERT() expands to assert(), it may be overridden e.g. when integrating
+// the simulation into another process that should survive violating RTL contracts.
+#ifndef CXXRTL_ASSERT
+#ifndef CXXRTL_NDEBUG
+#define CXXRTL_ASSERT(x) assert(x)
+#else
+#define CXXRTL_ASSERT(x)
+#endif
+#endif
+
 namespace cxxrtl {
 
 // All arbitrary-width values in CXXRTL are backed by arrays of unsigned integers called chunks. The chunk size
index a48ea5b23a8115d682b4c33d0f830d33fa47c3c7..23ea57b5ab560e147b2a99de7c45edd9349d71c0 100644 (file)
@@ -1154,7 +1154,7 @@ struct CxxrtlWorker {
                                // larger program) will never crash the code that calls into it.
                                //
                                // If assertions are disabled, out of bounds reads are defined to return zero.
-                               f << indent << "assert(" << valid_index_temp << ".valid && \"out of bounds read\");\n";
+                               f << indent << "CXXRTL_ASSERT(" << valid_index_temp << ".valid && \"out of bounds read\");\n";
                                f << indent << "if(" << valid_index_temp << ".valid) {\n";
                                inc_indent();
                                        if (writable_memories[memory]) {
@@ -1211,7 +1211,7 @@ struct CxxrtlWorker {
                                // See above for rationale of having both the assert and the condition.
                                //
                                // If assertions are disabled, out of bounds writes are defined to do nothing.
-                               f << indent << "assert(" << valid_index_temp << ".valid && \"out of bounds write\");\n";
+                               f << indent << "CXXRTL_ASSERT(" << valid_index_temp << ".valid && \"out of bounds write\");\n";
                                f << indent << "if (" << valid_index_temp << ".valid) {\n";
                                inc_indent();
                                        f << indent << mangle(memory) << ".update(" << valid_index_temp << ".index, ";