Commit Graph
5 Commits
Author SHA1 Message Date
rsp2k 49c258e81d Add crossing fixture and multi-layer/via routing tests
Adds crossing_2net.dsn: NET_A is a full-width horizontal wall and NET_B's
pins sit above and below it, so single-layer routing cannot connect NET_B
but two-layer routing succeeds by dipping to the other layer through vias.

Tests assert the multi-layer invariants: single-layer routing leaves a net
unrouted with no vias; multi-layer connects both nets with >= 1 via; the
SES contains a via scope; every via sits at a real layer transition of its
net's path; trace/via endpoints still land on the pads; traces stay on
valid layers and within the outline; and no two different nets cross on the
same layer. Oracle-gated parity tests cover the simple and crossing boards.
2026-07-12 13:21:00 -06:00
rsp2k 89c0481ccc Add MVP grid maze router and DSN->SES routing pipeline
Implements a working autorouter and the Java-free replacement for the
freerouting.jar step: dsn_text -> parse_dsn -> build_board -> route ->
write_ses.

GridRouter is a single-layer A* maze search over a uniform occupancy
grid: a cell is blocked by another net's pad (inflated by clearance +
half trace width) or a keepout; each net's ratsnest is connected pin to
pin; a routed trace then blocks other nets. The cell path becomes a
trace polyline whose endpoints are the exact pin locations. Board-unit
paths are converted back to DSN units for the SES (wire (path ...))
scopes.

This is an MVP, not a port of FreeRouting's expansion-room maze:
free-space rooms, rip-up-and-retry, multi-layer via search, and shove
are deferred (they raise quality/coverage, not the connectivity
milestone). It reaches connectivity on boards whose nets route on one
layer without crossing.

Adds tests/dsn/fixtures/simple_2net.dsn (a guaranteed-routable 2-net
board). Invariant tests: both nets route, the emitted SES parses, every
trace stays on a valid layer and within the board outline, and every
routed net's trace endpoints sit exactly on its two pads. An oracle-gated
test asserts connectivity parity with the reference FreeRouting JAR on
the simple board.
2026-07-12 11:25:03 -06:00
rsp2k 18f3afc8a5 Add FreeRouting JAR oracle harness for behaviour-level validation
FreeRouting ships no unit tests for its geometry/router, so there is no
value-level oracle to port against. This adds a dev/test-only harness that runs
the reference JAR to route a DSN, letting freeroute's output be diffed against
the reference implementation — the router phase will assert connectivity parity
(same nets routed) via routed_net_set().

- tests/oracle.py: locate Java 21+ and a freerouting JAR (env overrides:
  FREEROUTE_ORACLE_JAVA, FREEROUTING_JAR), route a DSN, and extract routed
  connectivity from the SES. requires_oracle skips when no JVM/JAR is present,
  so the suite stays Java-free.
- tests/test_oracle.py: routes a routable board end-to-end and checks the
  connectivity extraction.
- tests/dsn/fixtures/kicad_routable.dsn: a real KiCad pcbnew-exported DSN
  (Arduino_Mega template, path sanitized) that actually routes — the smd_demo
  fixture leaves its nets unrouted.
- pyproject: pythonpath=["tests"] so the harness imports as `oracle`.
2026-07-12 08:12:03 -06:00
rsp2k c905032a39 Fix DSN tokenizer to accept KiCad net names like /*52
Specctra's SpecCharASCII includes / and *, and an Identifier may start with /,
so KiCad emits hierarchical net names such as /*52 and /53. The tokenizer
treated any /* as a block-comment start and raised 'unterminated comment' when
no */ followed — rejecting real KiCad DSN. Match FreeRouting's JFlex rule-order
resolution: /* is a comment only when a closing */ exists; otherwise it is an
ordinary name run. Validated against a KiCad 10.0.4 pcbnew-exported DSN (78 nets
incl. /*52, /53).
2026-07-11 18:46:29 -06:00
rsp2k 3bf4f6bed2 Implement Specctra DSN parser with typed board model
Ports the read path of FreeRouting's io/specctra/parser package to a
Java-free Python implementation:

- tokenizer: S-expression lexer mirroring SpecctraFileDescription.flex
  (comments, quoted strings, the string_quote IGNORE_QUOTE directive,
  case-insensitive keywords, and hash-prefixed names)
- sexp: nested S-expression tree builder
- shapes: rect/circle/polygon/path plus area-with-holes scopes
- model: typed dataclasses for layers, padstacks, images, placements,
  nets, net classes, rules, keepouts
- reader: recursive-descent scope readers producing a DsnBoard, one
  _read_* function per FreeRouting read_scope method

46 pytest cases cover the tokenizer, tree, shapes, and end-to-end
parsing against hand-crafted fixtures modeled on FreeRouting's own
test DSN files. Parses 90 of 91 upstream fixtures (the one failure is
a binary OLE file, not text DSN).
2026-07-11 15:21:18 -06:00