Pins: replace expected_signal_type field with a model-derived PinSpec

Introduce PinSpec (function/direction/pad/source) as the "expected" half of
pin verification, and make Pin::expected_signal_type() a derived accessor over
spec.function. pin_role() now returns a PinSpec; the connector layout (and,
later, BSDL) feed the same structure.

Pure refactor, behaviour-preserving: vpx_3u_role is still a stub, so every pin
maps to Other exactly as before. The new `pad` field will carry the BSDL
physical pin; direction/function will unlock contention/undriven/NC checks.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-03 12:01:12 +02:00
parent fdf86a2e17
commit 1b507f1752
9 changed files with 88 additions and 23 deletions

View File

@@ -40,13 +40,15 @@ bool parse_pin(const std::string &s, char &col, int &row) {
} // namespace } // namespace
SignalType pin_role(const std::string &kind, const std::string &pin_name) PinSpec pin_role(const std::string &kind, const std::string &pin_name)
{ {
if (kind.empty()) return SignalType::Other; PinSpec spec;
if (kind.empty()) return spec;
char col; int row; char col; int row;
if (!parse_pin(pin_name, col, row)) return SignalType::Other; if (!parse_pin(pin_name, col, row)) return spec;
SignalType st = SignalType::Other;
int idx = -1; int idx = -1;
bool is_vpx_3u = false; bool is_vpx_3u = false;
if (kind.rfind("vpx-3u-bkp-p", 0) == 0 if (kind.rfind("vpx-3u-bkp-p", 0) == 0
@@ -55,9 +57,11 @@ SignalType pin_role(const std::string &kind, const std::string &pin_name)
const std::string suffix = kind.substr(kind.size() - 1); const std::string suffix = kind.substr(kind.size() - 1);
try { idx = std::stoi(suffix); } catch (const std::exception &) {} try { idx = std::stoi(suffix); } catch (const std::exception &) {}
} }
if (is_vpx_3u && idx >= 0) return vpx_3u_role(col, row, idx); if (is_vpx_3u && idx >= 0) st = vpx_3u_role(col, row, idx);
return SignalType::Other; spec.function = function_from_signal_type(st);
spec.source = SpecSource::ConnectorModel;
return spec;
} }
std::vector<std::string> pin_layout(const std::string &kind) std::vector<std::string> pin_layout(const std::string &kind)

View File

@@ -1,22 +1,22 @@
#ifndef _PIN_ROLE_HPP_ #ifndef _PIN_ROLE_HPP_
#define _PIN_ROLE_HPP_ #define _PIN_ROLE_HPP_
#include "signal_type.hpp" #include "pin_spec.hpp"
#include <string> #include <string>
#include <vector> #include <vector>
class Part; class Part;
// For a given connector type and pin position, return the expected SignalType // For a given connector type and pin position, return the expected PinSpec
// (Power / GndShield / Other). Used at `set-connector-type` to populate each pin's // (function/direction/pad + source). Used at `set-connector-type` to populate
// `expected_signal_type`, then later by `verify` to flag mismatches between // each pin's `spec`, then later by `verify` to flag mismatches between the
// the connector's expectation and the actual signal's inferred/declared type. // connector's expectation and the actual signal's inferred/declared type.
// //
// Returns SignalType::Other for unknown connector types or unmatched pins — // Returns a default PinSpec (function Unknown, source None) for unknown
// caller can treat that as "no expectation, no constraint". // connector types or unmatched pins — i.e. "no expectation, no constraint".
SignalType pin_role(const std::string &connector_type, PinSpec pin_role(const std::string &connector_type,
const std::string &pin_name); const std::string &pin_name);
// Canonical full pin-name list for the connector type (e.g. for VPX 3U, // Canonical full pin-name list for the connector type (e.g. for VPX 3U,
// every (col, row) position the connector physically has). Returns an empty // every (col, row) position the connector physically has). Returns an empty

54
src/system/pin_spec.hpp Normal file
View File

@@ -0,0 +1,54 @@
#ifndef _PIN_SPEC_HPP_
#define _PIN_SPEC_HPP_
#include "signal_type.hpp"
#include <string>
#pragma once
// Direction of a pin as seen from the component (port/BSDL semantics).
enum class PinDirection { Unknown, In, Out, Bidir, Passive, Power };
// Functional role of a pin. Richer than SignalType (which classifies *nets*):
// this classifies the *pin* itself and carries the TAP roles JTAG checks need.
enum class PinFunction {
Unknown, Power, Ground, Signal, Clock, NoConnect,
JtagTdi, JtagTdo, JtagTms, JtagTck, JtagTrst
};
// Where a pin's expected attributes came from. Lets verify report conflicts and
// lets a user override win over a model-derived value.
enum class SpecSource { None, Imported, ConnectorModel, Bsdl, Inferred, UserOverride };
// Expected, model-derived attributes of a pin (from a connector layout, a BSDL
// model, …). The "expected" half of the expected-vs-observed verify duality;
// the "observed" half stays Pin::signal() + the net + inference.
struct PinSpec {
PinFunction function = PinFunction::Unknown;
PinDirection direction = PinDirection::Unknown;
std::string pad; ///< Physical terminal (package ball/pin); "" if unknown.
SpecSource source = SpecSource::None;
};
// PinFunction -> the net SignalType a pin of that function expects to sit on.
inline SignalType to_signal_type(PinFunction f)
{
switch (f) {
case PinFunction::Power: return SignalType::Power;
case PinFunction::Ground: return SignalType::GndShield;
default: return SignalType::Other;
}
}
// Coarse SignalType -> PinFunction, used when a model only yields a SignalType.
inline PinFunction function_from_signal_type(SignalType t)
{
switch (t) {
case SignalType::Power: return PinFunction::Power;
case SignalType::GndShield: return PinFunction::Ground;
default: return PinFunction::Unknown;
}
}
#endif // _PIN_SPEC_HPP_

View File

@@ -3,8 +3,12 @@
#include "signals.hpp" #include "signals.hpp"
Pin::Pin(std::string name) Pin::Pin(std::string name)
: SystemElement(name), sig(nullptr), prnt(nullptr), : SystemElement(name), sig(nullptr), prnt(nullptr) {};
expected_signal_type(SignalType::Other) {};
SignalType Pin::expected_signal_type() const
{
return to_signal_type(spec.function);
}
const char *nc_origin_tag(NcOrigin o) { const char *nc_origin_tag(NcOrigin o) {
switch (o) { switch (o) {

View File

@@ -2,6 +2,7 @@
#define _PINS_HPP_ #define _PINS_HPP_
#include "signal_type.hpp" #include "signal_type.hpp"
#include "pin_spec.hpp"
#include "syselmts.hpp" #include "syselmts.hpp"
#pragma once #pragma once
@@ -29,11 +30,13 @@ class Pin : public SystemElement
public: public:
Pin(std::string name); Pin(std::string name);
Part *prnt; ///< Pointer to the parent part. Part *prnt; ///< Pointer to the parent part.
SignalType expected_signal_type; ///< Set from connector_type at set-connector-type. PinSpec spec; ///< Expected, model-derived attributes (connector layout / BSDL). Not persisted; re-applied from the model.
NcOrigin nc_origin = NcOrigin::None; NcOrigin nc_origin = NcOrigin::None;
bool connected(); bool connected();
Signal *signal() const { return sig; } Signal *signal() const { return sig; }
void connect(Signal *signal); void connect(Signal *signal);
// Net type this pin expects, derived from spec.function (Power/GndShield/Other).
SignalType expected_signal_type() const;
}; };
class Pins : public SystemElementContainer<Pin> class Pins : public SystemElementContainer<Pin>

View File

@@ -235,7 +235,7 @@ void Tui::RegisterCommands() {
for (auto &nkv : *prt) { for (auto &nkv : *prt) {
Pin *pin = nkv.second; Pin *pin = nkv.second;
++checked; ++checked;
SignalType expected = pin->expected_signal_type; SignalType expected = pin->expected_signal_type();
if (expected == SignalType::Other) continue; if (expected == SignalType::Other) continue;
Signal *s = pin->signal(); Signal *s = pin->signal();
SignalType actual = s ? s->type : SignalType::Other; SignalType actual = s ? s->type : SignalType::Other;
@@ -440,7 +440,7 @@ void Tui::RegisterCommands() {
prt->connector_type = args[2]; prt->connector_type = args[2];
int filled = FillPartFromLayout(prt, args[2]); int filled = FillPartFromLayout(prt, args[2]);
for (auto &kv : *prt) for (auto &kv : *prt)
kv.second->expected_signal_type = pin_role(args[2], kv.first); kv.second->spec = pin_role(args[2], kv.first);
Print(mod->name + "/" + prt->name + ": connector_type = " Print(mod->name + "/" + prt->name + ": connector_type = "
+ (args[2].empty() ? "(none)" : args[2])); + (args[2].empty() ? "(none)" : args[2]));
if (filled > 0) if (filled > 0)
@@ -648,7 +648,7 @@ void Tui::RegisterCommands() {
for (auto &nkv : *sp) { for (auto &nkv : *sp) {
Pin *sn = nkv.second; Pin *sn = nkv.second;
Pin *dn = new Pin(sn->name); Pin *dn = new Pin(sn->name);
dn->expected_signal_type = sn->expected_signal_type; dn->spec = sn->spec;
dn->nc_origin = sn->nc_origin; dn->nc_origin = sn->nc_origin;
dp->add(dn); dp->add(dn);
if (sn->signal()) { if (sn->signal()) {

View File

@@ -64,7 +64,7 @@ Component Tui::BuildAnalyzeScreen() {
for (auto &nkv : *prt) { for (auto &nkv : *prt) {
Pin *pin = nkv.second; Pin *pin = nkv.second;
++n_typed_pins; ++n_typed_pins;
SignalType expected = pin->expected_signal_type; SignalType expected = pin->expected_signal_type();
if (expected == SignalType::Other) continue; if (expected == SignalType::Other) continue;
Signal *s = pin->signal(); Signal *s = pin->signal();
SignalType actual = s ? s->type : SignalType::Other; SignalType actual = s ? s->type : SignalType::Other;

View File

@@ -83,7 +83,7 @@ Component Tui::BuildDashboardScreen() {
for (auto &nkv : *prt) { for (auto &nkv : *prt) {
Pin *pin = nkv.second; Pin *pin = nkv.second;
++n_typed_pins; ++n_typed_pins;
SignalType expected = pin->expected_signal_type; SignalType expected = pin->expected_signal_type();
if (expected == SignalType::Other) continue; if (expected == SignalType::Other) continue;
Signal *s = pin->signal(); Signal *s = pin->signal();
SignalType actual = s ? s->type : SignalType::Other; SignalType actual = s ? s->type : SignalType::Other;

View File

@@ -69,7 +69,7 @@ Component Tui::BuildSettypeScreen() {
} }
prt->connector_type = settype_type; prt->connector_type = settype_type;
for (auto &kv : *prt) for (auto &kv : *prt)
kv.second->expected_signal_type = pin_role(settype_type, kv.first); kv.second->spec = pin_role(settype_type, kv.first);
std::string msg = mod->name + "/" + prt->name + " = " std::string msg = mod->name + "/" + prt->name + " = "
+ (settype_type.empty() ? "(none)" : settype_type); + (settype_type.empty() ? "(none)" : settype_type);
settype_status = "applied: " + msg; settype_status = "applied: " + msg;