Skip to content
This repository has been archived by the owner on Dec 10, 2024. It is now read-only.

Commit

Permalink
multiple path limits; fix rp2040; fix minimal_led_order
Browse files Browse the repository at this point in the history
  • Loading branch information
iopapamanoglou committed Nov 12, 2024
1 parent 07096ba commit bae262e
Show file tree
Hide file tree
Showing 12 changed files with 164 additions and 21 deletions.
3 changes: 2 additions & 1 deletion examples/minimal_led_orderable.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from faebryk.exporters.pcb.layout.typehierarchy import LayoutTypeHierarchy
from faebryk.libs.app.checks import run_checks
from faebryk.libs.app.manufacturing import export_pcba_artifacts
from faebryk.libs.app.parameters import replace_tbd_with_any
from faebryk.libs.app.parameters import replace_tbd_with_any, resolve_dynamic_parameters
from faebryk.libs.brightness import TypicalLuminousIntensity
from faebryk.libs.examples.buildutil import BUILD_DIR, PCB_FILE, apply_design_to_pcb
from faebryk.libs.examples.pickers import add_example_pickers
Expand Down Expand Up @@ -130,6 +130,7 @@ def main():
logger.info("Building app")
app = App()
G = app.get_graph()
resolve_dynamic_parameters(G)

# picking ----------------------------------------------------------------
replace_tbd_with_any(app, recursive=True)
Expand Down
2 changes: 1 addition & 1 deletion src/faebryk/core/cpp/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -200,4 +200,4 @@ def find_paths(src: Node, dst: Sequence[Node]) -> tuple[list[Path], list[Counter
def print_obj(obj: object) -> None: ...
def set_indiv_measure(value: bool) -> None: ...
def set_leak_warnings(value: bool) -> None: ...
def set_max_paths(value: int) -> None: ...
def set_max_paths(arg0: int, arg1: int, arg2: int, /) -> None: ...
14 changes: 11 additions & 3 deletions src/faebryk/core/cpp/include/pathfinder/pathfinder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,18 @@
#include <memory>
#include <sstream>

inline uint32_t MAX_PATHS = 1 << 31;
struct PathLimits {
uint32_t absolute = 1 << 31;
uint32_t no_new_weak = 1 << 31;
uint32_t no_weak = 1 << 31;
};

inline PathLimits PATH_LIMITS;

inline void set_max_paths(uint32_t v) {
MAX_PATHS = v;
inline void set_max_paths(uint32_t absolute, uint32_t no_new_weak, uint32_t no_weak) {
PATH_LIMITS.absolute = absolute;
PATH_LIMITS.no_new_weak = no_new_weak;
PATH_LIMITS.no_weak = no_weak;
}

class PathFinder;
Expand Down
2 changes: 1 addition & 1 deletion src/faebryk/core/cpp/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ PYMOD(m) {
// TODO why this rv_pol needed
m.def("find_paths", &find_paths, "src"_a, "dst"_a, nb::rv_policy::reference);
m.def("set_indiv_measure", &set_indiv_measure, "value"_a);
m.def("set_max_paths", &set_max_paths, "value"_a);

m.def("set_max_paths", &set_max_paths);
// Graph
using GI = GraphInterface;

Expand Down
13 changes: 11 additions & 2 deletions src/faebryk/core/cpp/src/pathfinder/pathfinder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ PathFinder::PathFinder()
},
Filter{
.filter = &PathFinder::_build_path_stack,
.discovery = false,
.discovery = true,
.counter =
Counter{
.name = "build stack",
Expand Down Expand Up @@ -177,7 +177,7 @@ bool PathFinder::_count(BFSPath &p) {
if (path_cnt % 50000 == 0) {
printf("path_cnt: %lld\n", path_cnt);
}
if (path_cnt > MAX_PATHS) {
if (path_cnt > PATH_LIMITS.absolute) {
p.stop = true;
}
return true;
Expand Down Expand Up @@ -251,11 +251,20 @@ bool PathFinder::_build_path_stack(BFSPath &p) {
auto &split_stack = splits.split_stack;

size_t split_cnt = split_stack.size();
if (split_cnt > 0 && path_cnt > PATH_LIMITS.no_weak) {
return false;
}

_extend_fold_stack(elem.value(), unresolved_stack, split_stack);

int split_growth = split_stack.size() - split_cnt;
p.confidence *= std::pow(0.5, split_growth);

// heuristic, stop making weaker paths after limit
if (split_growth > 0 && path_cnt > PATH_LIMITS.no_new_weak) {
return false;
}

return true;
}

Expand Down
4 changes: 4 additions & 0 deletions src/faebryk/core/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ def connect_all_interfaces_by_name(
for k, (src_m, dst_m) in src_.zip_children_by_name_with(
dst_, ModuleInterface
).items():
# TODO: careful this also connects runtime children
# for now skip stuff prefixed with _
if k.startswith("_"):
continue
if src_m is None or dst_m is None:
if not allow_partial:
raise Exception(f"Node with name {k} not present in both")
Expand Down
2 changes: 1 addition & 1 deletion src/faebryk/core/moduleinterface.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
logger = logging.getLogger(__name__)


IMPLIED_PATHS = ConfigFlag("IMPLIED_PATHS", default=True, descr="Use implied paths")
IMPLIED_PATHS = ConfigFlag("IMPLIED_PATHS", default=False, descr="Use implied paths")


class ModuleInterface(Node):
Expand Down
12 changes: 10 additions & 2 deletions src/faebryk/core/pathfinder.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,17 @@
INDIV_MEASURE = ConfigFlag(
"INDIV_MEASURE", default=True, descr="Measure individual paths"
)
MAX_PATHS = ConfigFlagInt("MAX_PATHS", default=int(1e5), descr="Max paths to search")
set_indiv_measure(bool(INDIV_MEASURE))
set_max_paths(int(MAX_PATHS))


MAX_PATHS = ConfigFlagInt("MAX_PATHS", default=int(1e6), descr="Max paths to search")
MAX_PATHS_NO_NEW_WEAK = ConfigFlagInt(
"MAX_PATHS_NO_NEW_WEAK", default=int(1e3), descr="Max paths with no new weak"
)
MAX_PATHS_NO_WEAK = ConfigFlagInt(
"MAX_PATHS_NO_WEAK", default=int(1e4), descr="Max paths with no weak"
)
set_max_paths(int(MAX_PATHS), int(MAX_PATHS_NO_NEW_WEAK), int(MAX_PATHS_NO_WEAK))


def find_paths(src: Node, dst: Sequence[Node]) -> Sequence[Path]:
Expand Down
8 changes: 5 additions & 3 deletions src/faebryk/library/RP2040_ReferenceDesign.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,10 @@ def __preinit__(self):
)

# USB
terminated_usb = self.usb.usb_if.d.terminated()
terminated_usb.impedance.merge(F.Range.from_center_rel(27.4 * P.ohm, 0.05))
terminated_usb_data = self.add(
self.usb.usb_if.d.terminated(), "_terminated_usb_data"
)
terminated_usb_data.impedance.merge(F.Range.from_center_rel(27.4 * P.ohm, 0.05))

# Flash
self.flash.memory_size.merge(16 * P.Mbit)
Expand Down Expand Up @@ -157,7 +159,7 @@ def __preinit__(self):
self.flash.qspi.connect(self.rp2040.qspi)
self.flash.qspi.chip_select.connect(self.boot_selector.logic_out)

terminated_usb.connect(self.rp2040.usb)
terminated_usb_data.connect(self.rp2040.usb)

self.rp2040.xtal_if.connect(self.clock_source.xtal_if)

Expand Down
6 changes: 4 additions & 2 deletions src/faebryk/library/USB2_0_IF.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,17 @@

class USB2_0_IF(ModuleInterface):
class Data(F.DifferentialPair):
# FIXME: this should be in diffpair right?
@L.rt_field
def single_electric_reference(self):
return F.has_single_electric_reference_defined(
F.ElectricLogic.connect_all_module_references(self)
)

def __preinit__(self):
self.p.reference.voltage.merge(F.Range(0 * P.V, 3.6 * P.V))
self.n.reference.voltage.merge(F.Range(0 * P.V, 3.6 * P.V))
self.single_electric_reference.get_reference().voltage.merge(
F.Range(0 * P.V, 3.6 * P.V)
)

d: Data
buspower: F.ElectricPower
6 changes: 2 additions & 4 deletions src/faebryk/libs/app/parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,13 @@ def _resolve_dynamic_parameters_connection(
set()
)

debug_stuff = {}

while params_grouped_by_mif:
bus_representative_mif, bus_representative_params = (
params_grouped_by_mif.popitem()
)
# expensive call
connections = set(bus_representative_mif.get_connected(include_self=True))
debug_stuff[bus_representative_mif] = connections
paths = bus_representative_mif.get_connected(include_self=True)
connections = set(paths.keys())

busses.append(connections)
if len(set(map(type, connections))) > 1:
Expand Down
113 changes: 112 additions & 1 deletion test/core/test_hierarchy_connect.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,17 @@

import faebryk.library._F as F
from faebryk.core.link import (
LinkDirect,
LinkDirectConditional,
LinkDirectConditionalFilterResult,
LinkDirectDerived,
)
from faebryk.core.module import Module
from faebryk.core.moduleinterface import IMPLIED_PATHS, ModuleInterface
from faebryk.libs.app.erc import ERCPowerSourcesShortedError, simple_erc
from faebryk.libs.app.parameters import resolve_dynamic_parameters
from faebryk.libs.library import L
from faebryk.libs.util import times
from faebryk.libs.util import cast_assert, times

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -451,3 +453,112 @@ def test_shallow_implied_paths():
assert powers[3] in powers[0].get_connected()

assert not powers[0].hv.is_connected_to(powers[3].hv)


def test_direct_shallow_instance():
class MIFType(ModuleInterface):
pass

mif1 = MIFType()
mif2 = MIFType()
mif3 = MIFType()

mif1.connect_shallow(mif2, mif3)
assert isinstance(
mif1.connected.is_connected_to(mif2.connected), MIFType.LinkDirectShallow()
)
assert isinstance(
mif1.connected.is_connected_to(mif3.connected), MIFType.LinkDirectShallow()
)


def test_regression_rp2040_usb_diffpair_minimal():
usb = F.USB2_0_IF.Data()
terminated_usb = usb.terminated()

other_usb = F.USB2_0_IF.Data()
terminated_usb.connect(other_usb)

n_ref = usb.n.reference
p_ref = usb.p.reference
t_n_ref = terminated_usb.n.reference
t_p_ref = terminated_usb.p.reference
o_n_ref = other_usb.n.reference
o_p_ref = other_usb.p.reference
refs = {n_ref, p_ref, t_n_ref, t_p_ref, o_n_ref, o_p_ref}

assert isinstance(
usb.connected.is_connected_to(terminated_usb.connected),
F.USB2_0_IF.Data.LinkDirectShallow(),
)
assert isinstance(
other_usb.connected.is_connected_to(terminated_usb.connected), LinkDirect
)
assert usb.connected.is_connected_to(other_usb.connected) is None

connected_per_mif = {ref: ref.get_connected(include_self=True) for ref in refs}

assert not {n_ref, p_ref} & connected_per_mif[t_n_ref].keys()
assert not {n_ref, p_ref} & connected_per_mif[t_p_ref].keys()
assert not {t_n_ref, t_p_ref} & connected_per_mif[n_ref].keys()
assert not {t_n_ref, t_p_ref} & connected_per_mif[p_ref].keys()

assert set(connected_per_mif[n_ref].keys()) == {n_ref, p_ref}
assert set(connected_per_mif[p_ref].keys()) == {n_ref, p_ref}
assert set(connected_per_mif[t_n_ref].keys()) == {
t_n_ref,
t_p_ref,
o_n_ref,
o_p_ref,
}
assert set(connected_per_mif[t_p_ref].keys()) == {
t_n_ref,
t_p_ref,
o_n_ref,
o_p_ref,
}

# close references
p_ref.connect(other_usb.p.reference)

connected_per_mif_post = {ref: ref.get_connected(include_self=True) for ref in refs}
for _, connected in connected_per_mif_post.items():
assert set(connected.keys()).issuperset(refs)


def test_regression_rp2040_usb_diffpair():
app = F.RP2040_ReferenceDesign()

terminated_usb = cast_assert(F.USB2_0_IF.Data, app.runtime["_terminated_usb_data"])
rp_usb = app.rp2040.usb

t_p_ref = terminated_usb.p.reference
t_n_ref = terminated_usb.n.reference
r_p_ref = rp_usb.p.reference
r_n_ref = rp_usb.n.reference
refs = [
r_p_ref,
r_n_ref,
t_p_ref,
t_n_ref,
]

connected_per_mif = {ref: ref.get_connected(include_self=True) for ref in refs}
for connected in connected_per_mif.values():
assert set(connected.keys()) == set(refs)


def test_regression_rp2040_usb_diffpair_full():
app = F.RP2040_ReferenceDesign()
rp2040_2 = F.RP2040()
rp2040_3 = F.RP2040()

# make graph bigger
app.rp2040.i2c[0].connect(rp2040_2.i2c[0])
app.rp2040.i2c[0].connect(rp2040_3.i2c[0])

resolve_dynamic_parameters(app.get_graph())


if __name__ == "__main__":
test_regression_rp2040_usb_diffpair()

0 comments on commit bae262e

Please sign in to comment.