verify: model-driven pin checks (contention / undriven / NC-wired)
New bsdl_check.{hpp,cpp}: check_pin_specs(System*) walks the nets and uses
each pin's PinSpec direction/function to flag DriveContention (>=2 push-pull
output drivers), UndrivenNet (a multi-pin net with input(s) but no driver),
and NcWired (a no-connect pin wired onto a multi-pin net). Added as a pass in
`verify`; AnomalyKind extended accordingly. Nets with no direction data are
skipped, so un-modelled parts produce no noise. Covered by test_bsdl_check.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
92
tests/test_bsdl_check.cpp
Normal file
92
tests/test_bsdl_check.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
#include "system/analysis.hpp"
|
||||
#include "system/bsdl_check.hpp"
|
||||
#include "system/modules.hpp"
|
||||
#include "system/parts.hpp"
|
||||
#include "system/pin_spec.hpp"
|
||||
#include "system/pins.hpp"
|
||||
#include "system/signals.hpp"
|
||||
#include "system/system.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
Pin *mkpin(Part *part, const char *name, PinDirection d, PinFunction f)
|
||||
{
|
||||
Pin *p = new Pin(name);
|
||||
p->spec.direction = d;
|
||||
p->spec.function = f;
|
||||
p->spec.source = SpecSource::Bsdl;
|
||||
part->add(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
void wire(Module *m, const char *signame, std::vector<Pin *> pins)
|
||||
{
|
||||
Signal *s = m->signals->merge(signame);
|
||||
for (Pin *p : pins) {
|
||||
s->add(p);
|
||||
p->connect(s);
|
||||
}
|
||||
}
|
||||
|
||||
int count_kind(const std::vector<Anomaly> &v, AnomalyKind k)
|
||||
{
|
||||
return (int)std::count_if(v.begin(), v.end(),
|
||||
[&](const Anomaly &a) { return a.kind == k; });
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("check_pin_specs flags contention, undriven nets and NC-wired pins") {
|
||||
System sys;
|
||||
Module *m = sys.modules()->merge("M");
|
||||
Part *u1 = new Part("U1");
|
||||
Part *u2 = new Part("U2");
|
||||
m->add(u1);
|
||||
m->add(u2);
|
||||
|
||||
// Two push-pull outputs on one net → contention.
|
||||
wire(m, "NET_CONT", {mkpin(u1, "O1", PinDirection::Out, PinFunction::Signal),
|
||||
mkpin(u2, "O2", PinDirection::Out, PinFunction::Signal)});
|
||||
|
||||
// Two inputs, no driver → undriven.
|
||||
wire(m, "NET_UNDR", {mkpin(u1, "I1", PinDirection::In, PinFunction::Signal),
|
||||
mkpin(u2, "I2", PinDirection::In, PinFunction::Signal)});
|
||||
|
||||
// A no-connect pin wired to a driver → nc-wired (and not undriven: the
|
||||
// NC pin is Power-direction here, so the net has a driver).
|
||||
wire(m, "NET_NC", {mkpin(u1, "NC1", PinDirection::Power, PinFunction::NoConnect),
|
||||
mkpin(u2, "D1", PinDirection::Out, PinFunction::Signal)});
|
||||
|
||||
// Healthy: one driver + one input → no anomaly.
|
||||
wire(m, "NET_OK", {mkpin(u1, "OD", PinDirection::Out, PinFunction::Signal),
|
||||
mkpin(u2, "ID", PinDirection::In, PinFunction::Signal)});
|
||||
|
||||
auto anoms = check_pin_specs(&sys);
|
||||
CHECK(count_kind(anoms, AnomalyKind::DriveContention) == 1);
|
||||
CHECK(count_kind(anoms, AnomalyKind::UndrivenNet) == 1);
|
||||
CHECK(count_kind(anoms, AnomalyKind::NcWired) == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("check_pin_specs stays silent on un-modelled nets") {
|
||||
System sys;
|
||||
Module *m = sys.modules()->merge("M");
|
||||
Part *u1 = new Part("U1");
|
||||
Part *u2 = new Part("U2");
|
||||
m->add(u1);
|
||||
m->add(u2);
|
||||
|
||||
// No specs set (direction Unknown / function Unknown) → no findings.
|
||||
Pin *a = new Pin("A");
|
||||
Pin *b = new Pin("B");
|
||||
u1->add(a);
|
||||
u2->add(b);
|
||||
wire(m, "NET", {a, b});
|
||||
|
||||
auto anoms = check_pin_specs(&sys);
|
||||
CHECK(anoms.empty());
|
||||
}
|
||||
Reference in New Issue
Block a user