Add coverage report output for covergroup

Signed-off-by: Matthew Ballance <matt.ballance@gmail.com>
This commit is contained in:
Matthew Ballance 2026-03-25 14:29:19 +00:00
parent 73332329be
commit 47d5f536bc
12 changed files with 315 additions and 133 deletions

View File

@ -1599,12 +1599,15 @@ class FunctionalCoverageVisitor final : public VNVisitor {
+ "\", "
"\"column\", \""
+ std::to_string(fl->firstColumn()) + "\", ");
const std::string crossSuffix = crossp ? ", \"cross\", \"1\"" : "";
if (binp->binsType() == VCoverBinsType::BINS_IGNORE) {
cstmtp->add("\"bin\", \"" + binName + "\", \"bin_type\", \"ignore\");");
cstmtp->add("\"bin\", \"" + binName + "\", \"bin_type\", \"ignore\""
+ crossSuffix + ");");
} else if (binp->binsType() == VCoverBinsType::BINS_ILLEGAL) {
cstmtp->add("\"bin\", \"" + binName + "\", \"bin_type\", \"illegal\");");
cstmtp->add("\"bin\", \"" + binName + "\", \"bin_type\", \"illegal\""
+ crossSuffix + ");");
} else {
cstmtp->add("\"bin\", \"" + binName + "\");");
cstmtp->add("\"bin\", \"" + binName + "\"" + crossSuffix + ");");
}
// Add to constructor

View File

@ -66,6 +66,7 @@ void VlcOptions::parseOptsList(int argc, char** argv) {
DECL_OPTION("-annotate-all", OnOff, &m_annotateAll);
DECL_OPTION("-annotate-min", Set, &m_annotateMin);
DECL_OPTION("-annotate-points", OnOff, &m_annotatePoints);
DECL_OPTION("-covergroup", OnOff, &m_covergroup);
DECL_OPTION("-debug", CbCall, []() { V3Error::debugDefault(3); });
DECL_OPTION("-debugi", CbVal, [](int v) { V3Error::debugDefault(v); });
DECL_OPTION("-filter-type", Set, &m_filterType);
@ -143,6 +144,8 @@ int main(int argc, char** argv) {
V3Error::abortIfWarnings();
if (!top.opt.annotateOut().empty()) top.annotate(top.opt.annotateOut());
if (top.opt.covergroup()) top.covergroup();
if (top.opt.rank()) {
top.rank();
top.tests().dump(false);

View File

@ -39,6 +39,7 @@ class VlcOptions final {
bool m_annotateAll = false; // main switch: --annotate-all
int m_annotateMin = 10; // main switch: --annotate-min I<count>
bool m_annotatePoints = false; // main switch: --annotate-points
bool m_covergroup = false; // main switch: --covergroup
string m_filterType = "*"; // main switch: --filter-type
VlStringSet m_readFiles; // main switch: --read
bool m_rank = false; // main switch: --rank
@ -67,6 +68,7 @@ public:
int annotateMin() const { return m_annotateMin; }
bool countOk(uint64_t count) const { return count >= static_cast<uint64_t>(m_annotateMin); }
bool annotatePoints() const { return m_annotatePoints; }
bool covergroup() const { return m_covergroup; }
bool rank() const { return m_rank; }
bool unlink() const { return m_unlink; }
string writeFile() const { return m_writeFile; }

View File

@ -65,6 +65,11 @@ public:
string comment() const { return keyExtract(VL_CIK_COMMENT, m_name.c_str()); }
string hier() const { return keyExtract(VL_CIK_HIER, m_name.c_str()); }
string type() const { return typeExtract(m_name.c_str()); }
// Covergroup-specific key accessors (long keys, no short-key alias)
string page() const { return keyExtract("page", m_name.c_str()); }
string bin() const { return keyExtract("bin", m_name.c_str()); }
string binType() const { return keyExtract("bin_type", m_name.c_str()); }
bool isCross() const { return !keyExtract("cross", m_name.c_str()).empty(); }
string thresh() const {
// string as maybe ""
return keyExtract(VL_CIK_THRESH, m_name.c_str());

View File

@ -25,6 +25,9 @@
#include <algorithm>
#include <fstream>
#include <iomanip>
#include <map>
#include <sstream>
#include <string>
#include <vector>
@ -205,6 +208,165 @@ void VlcTop::rank() {
}
}
void VlcTop::covergroup() {
UINFO(2, "covergroup...");
// Structs for accumulating report data
struct BinEntry {
std::string name;
std::string binType; // "ignore", "illegal", or "" (normal)
bool covered = false;
uint64_t count = 0;
};
struct CpEntry {
std::string name;
bool isCross = false;
std::vector<BinEntry> bins;
uint64_t normalTotal = 0;
uint64_t normalCovered = 0;
};
struct CgEntry {
std::string typeName;
std::string filename;
int lineno = 0;
std::vector<CpEntry> coverpoints;
std::map<std::string, size_t> cpIndex;
};
std::map<std::string, CgEntry> cgMap;
// Collect covergroup points from all loaded coverage data
for (const auto& nameNum : m_points) {
const VlcPoint& pt = m_points.pointNumber(nameNum.second);
if (pt.type() != "covergroup") continue;
const std::string page = pt.page();
// Page format: "v_covergroup/<cgTypeName>"
const std::string pagePrefix = "v_covergroup/";
if (page.size() <= pagePrefix.size()) continue;
const std::string cgTypeName = page.substr(pagePrefix.size());
// Parse hier: "<cg_type>.<cp_name>.<bin_name>"
const std::string hier = pt.hier();
const size_t dot1 = hier.find('.');
if (dot1 == std::string::npos) continue;
const size_t dot2 = hier.find('.', dot1 + 1);
if (dot2 == std::string::npos) continue;
const std::string cpName = hier.substr(dot1 + 1, dot2 - dot1 - 1);
const std::string binName = hier.substr(dot2 + 1);
auto& cg = cgMap[cgTypeName];
if (cg.typeName.empty()) {
cg.typeName = cgTypeName;
cg.filename = pt.filename();
cg.lineno = pt.lineno();
}
auto it = cg.cpIndex.find(cpName);
size_t cpIdx;
if (it == cg.cpIndex.end()) {
cpIdx = cg.coverpoints.size();
cg.cpIndex[cpName] = cpIdx;
CpEntry cp;
cp.name = cpName;
cp.isCross = pt.isCross();
cg.coverpoints.push_back(cp);
} else {
cpIdx = it->second;
}
BinEntry bin;
bin.name = binName;
bin.binType = pt.binType();
// Threshold: use per-bin thresh key (option.at_least) if present, else 1 (SV default)
const std::string threshStr = pt.thresh();
const uint64_t binThresh = threshStr.empty() ? 1 : std::stoull(threshStr);
bin.count = pt.count();
bin.covered = (bin.count >= binThresh);
cg.coverpoints[cpIdx].bins.push_back(bin);
if (bin.binType.empty()) {
++cg.coverpoints[cpIdx].normalTotal;
if (bin.covered) ++cg.coverpoints[cpIdx].normalCovered;
}
}
// Compute grand totals
uint64_t grandTotal = 0, grandCovered = 0, grandIgnored = 0, grandIllegal = 0;
for (const auto& cgPair : cgMap) {
for (const auto& cp : cgPair.second.coverpoints) {
grandTotal += cp.normalTotal;
grandCovered += cp.normalCovered;
for (const auto& bin : cp.bins) {
if (bin.binType == "ignore") ++grandIgnored;
else if (bin.binType == "illegal") ++grandIllegal;
}
}
}
// Format a percentage string "xx.xx"
const auto pctStr = [](uint64_t covered, uint64_t total) -> std::string {
std::ostringstream oss;
const double pct = (total == 0) ? 100.0 : (100.0 * covered / total);
oss << std::fixed << std::setprecision(2) << pct;
return oss.str();
};
const std::string divider(78, '-');
// Header and grand total
std::cout << "COVERGROUP COVERAGE REPORT\n";
std::cout << "==========================\n";
std::cout << "\n";
std::cout << "TOTAL: " << grandCovered << "/" << grandTotal
<< " bins covered (" << pctStr(grandCovered, grandTotal) << "%)\n";
if (grandIgnored || grandIllegal)
std::cout << " (" << grandIgnored << " ignored, " << grandIllegal << " illegal)\n";
// One section per covergroup type (map is sorted alphabetically)
for (const auto& cgPair : cgMap) {
const CgEntry& cg = cgPair.second;
uint64_t cgTotal = 0, cgCovered = 0;
for (const auto& cp : cg.coverpoints) {
cgTotal += cp.normalTotal;
cgCovered += cp.normalCovered;
}
std::cout << "\n" << divider << "\n";
std::cout << "Covergroup Type: " << cg.typeName
<< " [" << cg.filename << ":" << cg.lineno << "]\n";
std::cout << " Type Coverage: " << cgCovered << "/" << cgTotal
<< " bins (" << pctStr(cgCovered, cgTotal) << "%)\n";
for (const auto& cp : cg.coverpoints) {
std::cout << "\n";
std::cout << " " << (cp.isCross ? "Cross" : "Coverpoint") << ": " << cp.name << "\n";
std::cout << " Coverage: " << cp.normalCovered << "/" << cp.normalTotal
<< " bins (" << pctStr(cp.normalCovered, cp.normalTotal) << "%)\n";
std::cout << " Bins:\n";
// Align bin name column to max name length in this coverpoint
size_t maxNameLen = 0;
for (const auto& bin : cp.bins)
if (bin.name.size() > maxNameLen) maxNameLen = bin.name.size();
for (const auto& bin : cp.bins) {
const char* status;
if (bin.binType == "ignore") status = "IGNORE ";
else if (bin.binType == "illegal") status = "ILLEGAL";
else if (bin.covered) status = "COVERED";
else status = "ZERO ";
std::cout << " " << status << " "
<< std::left << std::setw(static_cast<int>(maxNameLen)) << bin.name
<< std::right << " " << bin.count << " hits\n";
}
}
}
std::cout << "\n" << divider << "\n";
}
//######################################################################
void VlcTop::annotateCalc() {

View File

@ -55,6 +55,7 @@ public:
// METHODS
void annotate(const string& dirname);
void covergroup();
void readCoverage(const string& filename, bool nonfatal = false);
void writeCoverage(const string& filename);
void writeInfo(const string& filename);

View File

@ -2823,7 +2823,13 @@ class VlTest:
continue
hier = h_m.group(1)
bt_m = re.search(r'\x01bin_type\x02([^\x01]+)', entry)
label = f"{hier} [{bt_m.group(1)}]" if bt_m else hier
cross_m = re.search(r'\x01cross\x021', entry)
annotations = []
if bt_m:
annotations.append(bt_m.group(1))
if cross_m:
annotations.append("cross")
label = f"{hier} [{','.join(annotations)}]" if annotations else hier
entries.append((hier, label, int(count)))
entries.sort()
with open(outfile, 'w', encoding='utf-8') as fh:

View File

@ -1,15 +1,15 @@
cg.addr_cmd_mode.addr0_x_read_x_debug: 0
cg.addr_cmd_mode.addr0_x_read_x_normal: 1
cg.addr_cmd_mode.addr0_x_write_x_debug: 1
cg.addr_cmd_mode.addr0_x_write_x_normal: 0
cg.addr_cmd_mode.addr1_x_read_x_debug: 0
cg.addr_cmd_mode.addr1_x_read_x_normal: 0
cg.addr_cmd_mode.addr1_x_write_x_debug: 0
cg.addr_cmd_mode.addr1_x_write_x_normal: 1
cg.addr_cmd_mode.addr2_x_read_x_debug: 1
cg.addr_cmd_mode.addr2_x_read_x_normal: 0
cg.addr_cmd_mode.addr2_x_write_x_debug: 0
cg.addr_cmd_mode.addr2_x_write_x_normal: 0
cg.addr_cmd_mode.addr0_x_read_x_debug [cross]: 0
cg.addr_cmd_mode.addr0_x_read_x_normal [cross]: 1
cg.addr_cmd_mode.addr0_x_write_x_debug [cross]: 1
cg.addr_cmd_mode.addr0_x_write_x_normal [cross]: 0
cg.addr_cmd_mode.addr1_x_read_x_debug [cross]: 0
cg.addr_cmd_mode.addr1_x_read_x_normal [cross]: 0
cg.addr_cmd_mode.addr1_x_write_x_debug [cross]: 0
cg.addr_cmd_mode.addr1_x_write_x_normal [cross]: 1
cg.addr_cmd_mode.addr2_x_read_x_debug [cross]: 1
cg.addr_cmd_mode.addr2_x_read_x_normal [cross]: 0
cg.addr_cmd_mode.addr2_x_write_x_debug [cross]: 0
cg.addr_cmd_mode.addr2_x_write_x_normal [cross]: 0
cg.cp_addr.addr0: 2
cg.cp_addr.addr1: 1
cg.cp_addr.addr2: 1

View File

@ -1,19 +1,19 @@
cg.addr_cmd_mode_parity.addr0_x_read_x_debug_x_even: 0
cg.addr_cmd_mode_parity.addr0_x_read_x_debug_x_odd: 0
cg.addr_cmd_mode_parity.addr0_x_read_x_normal_x_even: 1
cg.addr_cmd_mode_parity.addr0_x_read_x_normal_x_odd: 0
cg.addr_cmd_mode_parity.addr0_x_write_x_debug_x_even: 1
cg.addr_cmd_mode_parity.addr0_x_write_x_debug_x_odd: 0
cg.addr_cmd_mode_parity.addr0_x_write_x_normal_x_even: 0
cg.addr_cmd_mode_parity.addr0_x_write_x_normal_x_odd: 0
cg.addr_cmd_mode_parity.addr1_x_read_x_debug_x_even: 0
cg.addr_cmd_mode_parity.addr1_x_read_x_debug_x_odd: 1
cg.addr_cmd_mode_parity.addr1_x_read_x_normal_x_even: 0
cg.addr_cmd_mode_parity.addr1_x_read_x_normal_x_odd: 0
cg.addr_cmd_mode_parity.addr1_x_write_x_debug_x_even: 0
cg.addr_cmd_mode_parity.addr1_x_write_x_debug_x_odd: 0
cg.addr_cmd_mode_parity.addr1_x_write_x_normal_x_even: 0
cg.addr_cmd_mode_parity.addr1_x_write_x_normal_x_odd: 1
cg.addr_cmd_mode_parity.addr0_x_read_x_debug_x_even [cross]: 0
cg.addr_cmd_mode_parity.addr0_x_read_x_debug_x_odd [cross]: 0
cg.addr_cmd_mode_parity.addr0_x_read_x_normal_x_even [cross]: 1
cg.addr_cmd_mode_parity.addr0_x_read_x_normal_x_odd [cross]: 0
cg.addr_cmd_mode_parity.addr0_x_write_x_debug_x_even [cross]: 1
cg.addr_cmd_mode_parity.addr0_x_write_x_debug_x_odd [cross]: 0
cg.addr_cmd_mode_parity.addr0_x_write_x_normal_x_even [cross]: 0
cg.addr_cmd_mode_parity.addr0_x_write_x_normal_x_odd [cross]: 0
cg.addr_cmd_mode_parity.addr1_x_read_x_debug_x_even [cross]: 0
cg.addr_cmd_mode_parity.addr1_x_read_x_debug_x_odd [cross]: 1
cg.addr_cmd_mode_parity.addr1_x_read_x_normal_x_even [cross]: 0
cg.addr_cmd_mode_parity.addr1_x_read_x_normal_x_odd [cross]: 0
cg.addr_cmd_mode_parity.addr1_x_write_x_debug_x_even [cross]: 0
cg.addr_cmd_mode_parity.addr1_x_write_x_debug_x_odd [cross]: 0
cg.addr_cmd_mode_parity.addr1_x_write_x_normal_x_even [cross]: 0
cg.addr_cmd_mode_parity.addr1_x_write_x_normal_x_odd [cross]: 1
cg.cp_addr.addr0: 2
cg.cp_addr.addr1: 2
cg.cp_cmd.read: 2

View File

@ -6,19 +6,19 @@ cg.cp_b.b0: 21
cg.cp_b.b1: 0
cg.cp_b.b2: 0
cg.cp_b.b3: 0
cg.cross_ab.a0_x_b0: 9
cg.cross_ab.a0_x_b1: 0
cg.cross_ab.a0_x_b2: 0
cg.cross_ab.a0_x_b3: 0
cg.cross_ab.a1_x_b0: 4
cg.cross_ab.a1_x_b1: 0
cg.cross_ab.a1_x_b2: 0
cg.cross_ab.a1_x_b3: 0
cg.cross_ab.a2_x_b0: 4
cg.cross_ab.a2_x_b1: 0
cg.cross_ab.a2_x_b2: 0
cg.cross_ab.a2_x_b3: 0
cg.cross_ab.a3_x_b0: 4
cg.cross_ab.a3_x_b1: 0
cg.cross_ab.a3_x_b2: 0
cg.cross_ab.a3_x_b3: 0
cg.cross_ab.a0_x_b0 [cross]: 9
cg.cross_ab.a0_x_b1 [cross]: 0
cg.cross_ab.a0_x_b2 [cross]: 0
cg.cross_ab.a0_x_b3 [cross]: 0
cg.cross_ab.a1_x_b0 [cross]: 4
cg.cross_ab.a1_x_b1 [cross]: 0
cg.cross_ab.a1_x_b2 [cross]: 0
cg.cross_ab.a1_x_b3 [cross]: 0
cg.cross_ab.a2_x_b0 [cross]: 4
cg.cross_ab.a2_x_b1 [cross]: 0
cg.cross_ab.a2_x_b2 [cross]: 0
cg.cross_ab.a2_x_b3 [cross]: 0
cg.cross_ab.a3_x_b0 [cross]: 4
cg.cross_ab.a3_x_b1 [cross]: 0
cg.cross_ab.a3_x_b2 [cross]: 0
cg.cross_ab.a3_x_b3 [cross]: 0

View File

@ -1,7 +1,7 @@
cg.addr_cmd.addr0_x_read: 1
cg.addr_cmd.addr0_x_write: 1
cg.addr_cmd.addr1_x_read: 1
cg.addr_cmd.addr1_x_write: 1
cg.addr_cmd.addr0_x_read [cross]: 1
cg.addr_cmd.addr0_x_write [cross]: 1
cg.addr_cmd.addr1_x_read [cross]: 1
cg.addr_cmd.addr1_x_write [cross]: 1
cg.cp_addr.addr0: 2
cg.cp_addr.addr1: 2
cg.cp_cmd.read: 2

View File

@ -10,84 +10,84 @@ cg.cp_c.c2: 6
cg.cp_d.d0: 21
cg.cp_d.d1: 0
cg.cp_d.d2: 0
cg.cross_abcd.a0_x_b0_x_c0_x_d0: 10
cg.cross_abcd.a0_x_b0_x_c0_x_d1: 0
cg.cross_abcd.a0_x_b0_x_c0_x_d2: 0
cg.cross_abcd.a0_x_b0_x_c1_x_d0: 0
cg.cross_abcd.a0_x_b0_x_c1_x_d1: 0
cg.cross_abcd.a0_x_b0_x_c1_x_d2: 0
cg.cross_abcd.a0_x_b0_x_c2_x_d0: 0
cg.cross_abcd.a0_x_b0_x_c2_x_d1: 0
cg.cross_abcd.a0_x_b0_x_c2_x_d2: 0
cg.cross_abcd.a0_x_b1_x_c0_x_d0: 0
cg.cross_abcd.a0_x_b1_x_c0_x_d1: 0
cg.cross_abcd.a0_x_b1_x_c0_x_d2: 0
cg.cross_abcd.a0_x_b1_x_c1_x_d0: 0
cg.cross_abcd.a0_x_b1_x_c1_x_d1: 0
cg.cross_abcd.a0_x_b1_x_c1_x_d2: 0
cg.cross_abcd.a0_x_b1_x_c2_x_d0: 0
cg.cross_abcd.a0_x_b1_x_c2_x_d1: 0
cg.cross_abcd.a0_x_b1_x_c2_x_d2: 0
cg.cross_abcd.a0_x_b2_x_c0_x_d0: 0
cg.cross_abcd.a0_x_b2_x_c0_x_d1: 0
cg.cross_abcd.a0_x_b2_x_c0_x_d2: 0
cg.cross_abcd.a0_x_b2_x_c1_x_d0: 0
cg.cross_abcd.a0_x_b2_x_c1_x_d1: 0
cg.cross_abcd.a0_x_b2_x_c1_x_d2: 0
cg.cross_abcd.a0_x_b2_x_c2_x_d0: 0
cg.cross_abcd.a0_x_b2_x_c2_x_d1: 0
cg.cross_abcd.a0_x_b2_x_c2_x_d2: 0
cg.cross_abcd.a1_x_b0_x_c0_x_d0: 0
cg.cross_abcd.a1_x_b0_x_c0_x_d1: 0
cg.cross_abcd.a1_x_b0_x_c0_x_d2: 0
cg.cross_abcd.a1_x_b0_x_c1_x_d0: 5
cg.cross_abcd.a1_x_b0_x_c1_x_d1: 0
cg.cross_abcd.a1_x_b0_x_c1_x_d2: 0
cg.cross_abcd.a1_x_b0_x_c2_x_d0: 0
cg.cross_abcd.a1_x_b0_x_c2_x_d1: 0
cg.cross_abcd.a1_x_b0_x_c2_x_d2: 0
cg.cross_abcd.a1_x_b1_x_c0_x_d0: 0
cg.cross_abcd.a1_x_b1_x_c0_x_d1: 0
cg.cross_abcd.a1_x_b1_x_c0_x_d2: 0
cg.cross_abcd.a1_x_b1_x_c1_x_d0: 0
cg.cross_abcd.a1_x_b1_x_c1_x_d1: 0
cg.cross_abcd.a1_x_b1_x_c1_x_d2: 0
cg.cross_abcd.a1_x_b1_x_c2_x_d0: 0
cg.cross_abcd.a1_x_b1_x_c2_x_d1: 0
cg.cross_abcd.a1_x_b1_x_c2_x_d2: 0
cg.cross_abcd.a1_x_b2_x_c0_x_d0: 0
cg.cross_abcd.a1_x_b2_x_c0_x_d1: 0
cg.cross_abcd.a1_x_b2_x_c0_x_d2: 0
cg.cross_abcd.a1_x_b2_x_c1_x_d0: 0
cg.cross_abcd.a1_x_b2_x_c1_x_d1: 0
cg.cross_abcd.a1_x_b2_x_c1_x_d2: 0
cg.cross_abcd.a1_x_b2_x_c2_x_d0: 0
cg.cross_abcd.a1_x_b2_x_c2_x_d1: 0
cg.cross_abcd.a1_x_b2_x_c2_x_d2: 0
cg.cross_abcd.a2_x_b0_x_c0_x_d0: 0
cg.cross_abcd.a2_x_b0_x_c0_x_d1: 0
cg.cross_abcd.a2_x_b0_x_c0_x_d2: 0
cg.cross_abcd.a2_x_b0_x_c1_x_d0: 0
cg.cross_abcd.a2_x_b0_x_c1_x_d1: 0
cg.cross_abcd.a2_x_b0_x_c1_x_d2: 0
cg.cross_abcd.a2_x_b0_x_c2_x_d0: 6
cg.cross_abcd.a2_x_b0_x_c2_x_d1: 0
cg.cross_abcd.a2_x_b0_x_c2_x_d2: 0
cg.cross_abcd.a2_x_b1_x_c0_x_d0: 0
cg.cross_abcd.a2_x_b1_x_c0_x_d1: 0
cg.cross_abcd.a2_x_b1_x_c0_x_d2: 0
cg.cross_abcd.a2_x_b1_x_c1_x_d0: 0
cg.cross_abcd.a2_x_b1_x_c1_x_d1: 0
cg.cross_abcd.a2_x_b1_x_c1_x_d2: 0
cg.cross_abcd.a2_x_b1_x_c2_x_d0: 0
cg.cross_abcd.a2_x_b1_x_c2_x_d1: 0
cg.cross_abcd.a2_x_b1_x_c2_x_d2: 0
cg.cross_abcd.a2_x_b2_x_c0_x_d0: 0
cg.cross_abcd.a2_x_b2_x_c0_x_d1: 0
cg.cross_abcd.a2_x_b2_x_c0_x_d2: 0
cg.cross_abcd.a2_x_b2_x_c1_x_d0: 0
cg.cross_abcd.a2_x_b2_x_c1_x_d1: 0
cg.cross_abcd.a2_x_b2_x_c1_x_d2: 0
cg.cross_abcd.a2_x_b2_x_c2_x_d0: 0
cg.cross_abcd.a2_x_b2_x_c2_x_d1: 0
cg.cross_abcd.a2_x_b2_x_c2_x_d2: 0
cg.cross_abcd.a0_x_b0_x_c0_x_d0 [cross]: 10
cg.cross_abcd.a0_x_b0_x_c0_x_d1 [cross]: 0
cg.cross_abcd.a0_x_b0_x_c0_x_d2 [cross]: 0
cg.cross_abcd.a0_x_b0_x_c1_x_d0 [cross]: 0
cg.cross_abcd.a0_x_b0_x_c1_x_d1 [cross]: 0
cg.cross_abcd.a0_x_b0_x_c1_x_d2 [cross]: 0
cg.cross_abcd.a0_x_b0_x_c2_x_d0 [cross]: 0
cg.cross_abcd.a0_x_b0_x_c2_x_d1 [cross]: 0
cg.cross_abcd.a0_x_b0_x_c2_x_d2 [cross]: 0
cg.cross_abcd.a0_x_b1_x_c0_x_d0 [cross]: 0
cg.cross_abcd.a0_x_b1_x_c0_x_d1 [cross]: 0
cg.cross_abcd.a0_x_b1_x_c0_x_d2 [cross]: 0
cg.cross_abcd.a0_x_b1_x_c1_x_d0 [cross]: 0
cg.cross_abcd.a0_x_b1_x_c1_x_d1 [cross]: 0
cg.cross_abcd.a0_x_b1_x_c1_x_d2 [cross]: 0
cg.cross_abcd.a0_x_b1_x_c2_x_d0 [cross]: 0
cg.cross_abcd.a0_x_b1_x_c2_x_d1 [cross]: 0
cg.cross_abcd.a0_x_b1_x_c2_x_d2 [cross]: 0
cg.cross_abcd.a0_x_b2_x_c0_x_d0 [cross]: 0
cg.cross_abcd.a0_x_b2_x_c0_x_d1 [cross]: 0
cg.cross_abcd.a0_x_b2_x_c0_x_d2 [cross]: 0
cg.cross_abcd.a0_x_b2_x_c1_x_d0 [cross]: 0
cg.cross_abcd.a0_x_b2_x_c1_x_d1 [cross]: 0
cg.cross_abcd.a0_x_b2_x_c1_x_d2 [cross]: 0
cg.cross_abcd.a0_x_b2_x_c2_x_d0 [cross]: 0
cg.cross_abcd.a0_x_b2_x_c2_x_d1 [cross]: 0
cg.cross_abcd.a0_x_b2_x_c2_x_d2 [cross]: 0
cg.cross_abcd.a1_x_b0_x_c0_x_d0 [cross]: 0
cg.cross_abcd.a1_x_b0_x_c0_x_d1 [cross]: 0
cg.cross_abcd.a1_x_b0_x_c0_x_d2 [cross]: 0
cg.cross_abcd.a1_x_b0_x_c1_x_d0 [cross]: 5
cg.cross_abcd.a1_x_b0_x_c1_x_d1 [cross]: 0
cg.cross_abcd.a1_x_b0_x_c1_x_d2 [cross]: 0
cg.cross_abcd.a1_x_b0_x_c2_x_d0 [cross]: 0
cg.cross_abcd.a1_x_b0_x_c2_x_d1 [cross]: 0
cg.cross_abcd.a1_x_b0_x_c2_x_d2 [cross]: 0
cg.cross_abcd.a1_x_b1_x_c0_x_d0 [cross]: 0
cg.cross_abcd.a1_x_b1_x_c0_x_d1 [cross]: 0
cg.cross_abcd.a1_x_b1_x_c0_x_d2 [cross]: 0
cg.cross_abcd.a1_x_b1_x_c1_x_d0 [cross]: 0
cg.cross_abcd.a1_x_b1_x_c1_x_d1 [cross]: 0
cg.cross_abcd.a1_x_b1_x_c1_x_d2 [cross]: 0
cg.cross_abcd.a1_x_b1_x_c2_x_d0 [cross]: 0
cg.cross_abcd.a1_x_b1_x_c2_x_d1 [cross]: 0
cg.cross_abcd.a1_x_b1_x_c2_x_d2 [cross]: 0
cg.cross_abcd.a1_x_b2_x_c0_x_d0 [cross]: 0
cg.cross_abcd.a1_x_b2_x_c0_x_d1 [cross]: 0
cg.cross_abcd.a1_x_b2_x_c0_x_d2 [cross]: 0
cg.cross_abcd.a1_x_b2_x_c1_x_d0 [cross]: 0
cg.cross_abcd.a1_x_b2_x_c1_x_d1 [cross]: 0
cg.cross_abcd.a1_x_b2_x_c1_x_d2 [cross]: 0
cg.cross_abcd.a1_x_b2_x_c2_x_d0 [cross]: 0
cg.cross_abcd.a1_x_b2_x_c2_x_d1 [cross]: 0
cg.cross_abcd.a1_x_b2_x_c2_x_d2 [cross]: 0
cg.cross_abcd.a2_x_b0_x_c0_x_d0 [cross]: 0
cg.cross_abcd.a2_x_b0_x_c0_x_d1 [cross]: 0
cg.cross_abcd.a2_x_b0_x_c0_x_d2 [cross]: 0
cg.cross_abcd.a2_x_b0_x_c1_x_d0 [cross]: 0
cg.cross_abcd.a2_x_b0_x_c1_x_d1 [cross]: 0
cg.cross_abcd.a2_x_b0_x_c1_x_d2 [cross]: 0
cg.cross_abcd.a2_x_b0_x_c2_x_d0 [cross]: 6
cg.cross_abcd.a2_x_b0_x_c2_x_d1 [cross]: 0
cg.cross_abcd.a2_x_b0_x_c2_x_d2 [cross]: 0
cg.cross_abcd.a2_x_b1_x_c0_x_d0 [cross]: 0
cg.cross_abcd.a2_x_b1_x_c0_x_d1 [cross]: 0
cg.cross_abcd.a2_x_b1_x_c0_x_d2 [cross]: 0
cg.cross_abcd.a2_x_b1_x_c1_x_d0 [cross]: 0
cg.cross_abcd.a2_x_b1_x_c1_x_d1 [cross]: 0
cg.cross_abcd.a2_x_b1_x_c1_x_d2 [cross]: 0
cg.cross_abcd.a2_x_b1_x_c2_x_d0 [cross]: 0
cg.cross_abcd.a2_x_b1_x_c2_x_d1 [cross]: 0
cg.cross_abcd.a2_x_b1_x_c2_x_d2 [cross]: 0
cg.cross_abcd.a2_x_b2_x_c0_x_d0 [cross]: 0
cg.cross_abcd.a2_x_b2_x_c0_x_d1 [cross]: 0
cg.cross_abcd.a2_x_b2_x_c0_x_d2 [cross]: 0
cg.cross_abcd.a2_x_b2_x_c1_x_d0 [cross]: 0
cg.cross_abcd.a2_x_b2_x_c1_x_d1 [cross]: 0
cg.cross_abcd.a2_x_b2_x_c1_x_d2 [cross]: 0
cg.cross_abcd.a2_x_b2_x_c2_x_d0 [cross]: 0
cg.cross_abcd.a2_x_b2_x_c2_x_d1 [cross]: 0
cg.cross_abcd.a2_x_b2_x_c2_x_d2 [cross]: 0