Skip to content

Multi-board netlist generation#487

Merged
ducky64 merged 11 commits into
masterfrom
multiboard
May 17, 2026
Merged

Multi-board netlist generation#487
ducky64 merged 11 commits into
masterfrom
multiboard

Conversation

@ducky64
Copy link
Copy Markdown
Collaborator

@ducky64 ducky64 commented May 17, 2026

Add netlister functionality to generate multiple netlists for sub-boards. The netlister can now return multiple netlists per design.

Changes netlisting where in subboard blocks, connections happen in both the enclosing and sub-board scope. This is needed to handle connections across the external facing boundary ports, external-scope blocks, and internal-scope blocks.

Changes refdesing to have a single consistent numbering across all sub-boards, instead of restarting every board at 1.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds multi-board netlist generation by having the netlister produce one netlist per board scope (top-level + sub-boards), and updates refdes assignment to be globally consistent across scopes.

Changes:

  • Update NetlistTransform to return Dict[Path, Netlist] (one per board scope) and adjust net-connection handling for sub-board scoping.
  • Change refdes numbering to be global per prefix (no longer restarting per board scope).
  • Update/add tests and backend consumers to handle multi-netlist output.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
edg/electronics_model/NetlistGenerator.py Return multiple netlists (per scope) and connect sub-board constraints into both parent + sub-board scopes.
edg/electronics_model/BoardScopedTransform.py Refactor scoping bookkeeping to track parent scope separately from internal scope.
edg/electronics_model/NetlistBackend.py Emit one KiCad netlist per board scope.
edg/electronics_model/SvgPcbBackend.py Adapt to multi-netlist output (but currently selects “first” netlist).
edg/electronics_model/RefdesRefinementPass.py Make refdes numbering global per prefix across all scopes.
edg/BoardCompiler.py Write multiple .net outputs and delete prior netlists (currently has filename/cleanup logic issues).
edg/electronics_model/test_netlist.py Update helpers/tests for single-netlist designs under new multi-netlist API.
edg/electronics_model/test_netlist_subboard.py New coverage asserting both top-level and sub-board netlists are generated.
edg/electronics_model/test_netlist_subboard_wrapper.py Split wrapper-specific subboard tests into a dedicated file.
edg/electronics_model/test_netlist_subboard_array.py Update to new generate_single_net helper.
edg/electronics_model/test_multipack_netlist.py Update to new generate_single_net helper.
edg/electronics_model/test_bundle_netlist.py Update to new generate_single_net helper.
edg/abstract_parts/test_kicad_import_netlist.py Update to new generate_single_net helper.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread edg/BoardCompiler.py Outdated
with suppress(FileNotFoundError):
os.remove(netlist_filename)
for filename in os.listdir(target_dir):
if filename.startswith(netlist_filename_prefix) and filename.endswith(".net"):
Comment thread edg/BoardCompiler.py Outdated
Comment on lines +62 to +64
net_filename = netlist_filename_prefix + ".net"
else:
net_filename = netlist_filename_prefix + "_".join(path_str) + ".net"
Comment on lines 192 to 194
def run(self, design: CompiledDesign, args: Dict[str, str] = {}) -> List[Tuple[edgir.LocalPath, str]]:
netlist = NetlistTransform(design).run()
netlist = list(NetlistTransform(design).run().values())[0] # only generate for top-level board
result = self._generate(design, netlist)
Comment thread edg/electronics_model/SvgPcbBackend.py Outdated

# handle footprints
netlist = NetlistTransform(design).run()
netlist = list(NetlistTransform(design).run().values())[0] # only generate for top-level board
Comment on lines 83 to 87
super().__init__(design)

self.all_scopes = [BoardScope.empty(TransformUtil.Path.empty())] # list of unique scopes
self.scopes: Scopes = {TransformUtil.Path.empty(): self.all_scopes[0]}
self.scopes: Scopes = {TransformUtil.Path.empty(): BoardScope.empty(TransformUtil.Path.empty())}
self.class_paths: ClassPaths = {TransformUtil.Path.empty(): []} # seed root
self.path_traverse_order: List[TransformUtil.Path] = []
@ducky64 ducky64 merged commit e5ad241 into master May 17, 2026
12 checks passed
@ducky64 ducky64 deleted the multiboard branch May 17, 2026 08:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants