BSDL: ingest libbsdl into essim and populate PinSpec from a device model
Link libbsdl dynamically (add_subdirectory ../libbsdl, overridable via -DBSDL_DIR). New BsdlModel wraps the C ABI and reduces a parsed .bsd to essim's pin vocabulary; apply_bsdl() binds each port to a Pin (by name, then by physical pad) and sets its spec: direction, function (TAP role / power / ground / signal), pad, and source = Bsdl. This feeds the PinSpec fields from P1, so verify's existing power/ground placement pass now lights up for BSDL-modelled parts. Covered by test_bsdl_apply (name + pad binding, TAP roles, linkage classification). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
94
tests/test_bsdl_apply.cpp
Normal file
94
tests/test_bsdl_apply.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
#include "system/bsdl_model.hpp"
|
||||
#include "system/parts.hpp"
|
||||
#include "system/pins.hpp"
|
||||
#include "system/pin_spec.hpp"
|
||||
|
||||
// Minimal synthetic BSDL: 4 TAP pins, one bidir I/O, a power and a ground
|
||||
// linkage pin, each with a PIN_MAP ball.
|
||||
static const char DEMO_BSDL[] =
|
||||
"entity DEMO is\n"
|
||||
" generic (PHYSICAL_PIN_MAP : string := \"PKG\");\n"
|
||||
" port (\n"
|
||||
" TCK:in bit; TDI:in bit; TDO:out bit; TMS:in bit;\n"
|
||||
" IO1:inout bit;\n"
|
||||
" VDD:linkage bit; GND:linkage bit\n"
|
||||
" );\n"
|
||||
" attribute PIN_MAP of DEMO : entity is PHYSICAL_PIN_MAP;\n"
|
||||
" constant PKG : PIN_MAP_STRING :=\n"
|
||||
" \"TCK:A1,\" & \"TDI:A2,\" & \"TDO:A3,\" & \"TMS:A4,\" &\n"
|
||||
" \"IO1:B1,\" & \"VDD:C1,\" & \"GND:C2\";\n"
|
||||
" attribute TAP_SCAN_IN of TDI : signal is true;\n"
|
||||
" attribute TAP_SCAN_MODE of TMS : signal is true;\n"
|
||||
" attribute TAP_SCAN_OUT of TDO : signal is true;\n"
|
||||
" attribute TAP_SCAN_CLOCK of TCK : signal is (10.0e6, BOTH);\n"
|
||||
" attribute INSTRUCTION_LENGTH of DEMO : entity is 2;\n"
|
||||
" attribute INSTRUCTION_OPCODE of DEMO : entity is \"BYPASS (11), IDCODE (10)\";\n"
|
||||
" attribute IDCODE_REGISTER of DEMO : entity is \"00010010001101000101000000001111\";\n"
|
||||
" attribute BOUNDARY_LENGTH of DEMO : entity is 1;\n"
|
||||
" attribute BOUNDARY_REGISTER of DEMO : entity is \"0 (BC_1, IO1, bidir, X)\";\n"
|
||||
"end DEMO;\n";
|
||||
|
||||
TEST_CASE("BsdlModel parses a buffer into essim pin vocabulary") {
|
||||
BsdlModel m = BsdlModel::from_buffer(DEMO_BSDL, "demo.bsd");
|
||||
REQUIRE(m.valid());
|
||||
CHECK(m.entity() == "DEMO");
|
||||
CHECK(m.ports().size() == 7);
|
||||
}
|
||||
|
||||
TEST_CASE("apply_bsdl binds by port name and sets each pin spec") {
|
||||
BsdlModel m = BsdlModel::from_buffer(DEMO_BSDL, "demo.bsd");
|
||||
REQUIRE(m.valid());
|
||||
|
||||
Part part("U1");
|
||||
for (const char *n : {"TCK", "TDI", "TDO", "TMS", "IO1", "VDD", "GND"})
|
||||
part.add(new Pin(n));
|
||||
|
||||
BsdlApplyReport r = apply_bsdl(&part, m);
|
||||
CHECK(r.pins_total == 7);
|
||||
CHECK(r.bound == 7);
|
||||
CHECK(r.unbound == 0);
|
||||
|
||||
Pin *tck = part.get("TCK");
|
||||
CHECK(tck->spec.function == PinFunction::JtagTck);
|
||||
CHECK(tck->spec.direction == PinDirection::In);
|
||||
CHECK(tck->spec.source == SpecSource::Bsdl);
|
||||
CHECK(tck->spec.pad == "A1");
|
||||
|
||||
CHECK(part.get("TDI")->spec.function == PinFunction::JtagTdi);
|
||||
CHECK(part.get("TDO")->spec.function == PinFunction::JtagTdo);
|
||||
CHECK(part.get("TDO")->spec.direction == PinDirection::Out);
|
||||
CHECK(part.get("TMS")->spec.function == PinFunction::JtagTms);
|
||||
|
||||
Pin *io1 = part.get("IO1");
|
||||
CHECK(io1->spec.function == PinFunction::Signal);
|
||||
CHECK(io1->spec.direction == PinDirection::Bidir);
|
||||
|
||||
// Linkage pins classified, and the derived expected net type follows.
|
||||
Pin *vdd = part.get("VDD");
|
||||
CHECK(vdd->spec.function == PinFunction::Power);
|
||||
CHECK(vdd->spec.direction == PinDirection::Power);
|
||||
CHECK(vdd->expected_signal_type() == SignalType::Power);
|
||||
|
||||
Pin *gnd = part.get("GND");
|
||||
CHECK(gnd->spec.function == PinFunction::Ground);
|
||||
CHECK(gnd->expected_signal_type() == SignalType::GndShield);
|
||||
}
|
||||
|
||||
TEST_CASE("apply_bsdl falls back to the physical pad when names are balls") {
|
||||
BsdlModel m = BsdlModel::from_buffer(DEMO_BSDL, "demo.bsd");
|
||||
REQUIRE(m.valid());
|
||||
|
||||
// A part whose pins are named by package ball, not by signal.
|
||||
Part part("U2");
|
||||
for (const char *n : {"A1", "A2", "A3", "A4", "B1", "C1", "C2"})
|
||||
part.add(new Pin(n));
|
||||
|
||||
BsdlApplyReport r = apply_bsdl(&part, m);
|
||||
CHECK(r.bound == 7);
|
||||
CHECK(r.unbound == 0);
|
||||
CHECK(part.get("A1")->spec.function == PinFunction::JtagTck); // TCK:A1
|
||||
CHECK(part.get("C1")->spec.function == PinFunction::Power); // VDD:C1
|
||||
CHECK(part.get("C2")->spec.function == PinFunction::Ground); // GND:C2
|
||||
}
|
||||
Reference in New Issue
Block a user