Description file added

This commit is contained in:
2026-06-01 11:34:00 +08:00
parent 20f773cec6
commit d0b6ac018a
15 changed files with 1618 additions and 2 deletions
+226
View File
@@ -0,0 +1,226 @@
import os
import sys
import unittest
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
class EdaRouterPinsContractTest(unittest.TestCase):
def test_loader_uses_top_level_pins_and_ignores_legacy_ports(self):
from mxpic_router.eda_loader import parse_cell_dict
spec = parse_cell_dict({
"name": "cell",
"pins": [
{"name": "input_io1", "x": 1, "y": 2, "angle": 90, "width": 0.6},
],
"ports": [
{"name": "legacy_port", "x": 9, "y": 9, "angle": 0},
],
})
self.assertIn("input_io1", spec.pins)
self.assertNotIn("legacy_port", spec.pins)
self.assertEqual(spec.pins["input_io1"].angle, 90.0)
def test_loader_accepts_pin_links_with_route_metadata(self):
from mxpic_router.eda_loader import parse_cell_dict
spec = parse_cell_dict({
"name": "cell_a",
"instances": {
"inst_a": {"component": "mmi", "x": 0, "y": 0},
"inst_b": {"component": "mmi", "x": 100, "y": 0},
},
"bundles": {
"output_bus": {
"links": [{
"from": "inst_a:out",
"to": "inst_b:in",
"xsection": "metal_1",
"family": "electrical",
"width": 5,
"radius": 20,
"routing_type": "standard_bend",
"points": [{"x": 0, "y": 0}, {"x": 50, "y": 0}],
}]
}
}
})
link = spec.bundles["output_bus"].links[0]
self.assertEqual(link.src_inst, "inst_a")
self.assertEqual(link.src_pin, "out")
self.assertEqual(link.dst_inst, "inst_b")
self.assertEqual(link.dst_pin, "in")
self.assertEqual(link.xsection, "metal_1")
self.assertEqual(link.width, 5)
self.assertEqual(link.points[1], {"x": 50.0, "y": 0.0})
def test_port_element_creates_named_io_pins_and_inside_route_pins(self):
from mxpic_router.builder import _register_element_pins
from mxpic_router.eda_loader import parse_cell_dict
class FakePlacedPin:
def __init__(self, name, x, y, a):
self.name = name
self.x = x
self.y = y
self.a = a
def move(self, dx, dy, da):
return FakePlacedPin(f"{self.name}_in", self.x + dx, self.y + dy, self.a + da)
class FakePin:
created_names = []
current_cell = None
def __init__(self, name, width=None, xs=None):
self.name = name
self.width = width
self.xs = xs
self.created_names.append(name)
def put(self, x, y, a):
placed = FakePlacedPin(self.name, x, y, a)
if FakePin.current_cell is not None:
FakePin.current_cell.pin[self.name] = placed
return placed
class FakeCell:
put_calls = []
def __init__(self, name=None, instantiate=True):
self.name = name
self.pin = {}
def __enter__(self):
FakePin.current_cell = self
return self
def __exit__(self, exc_type, exc, tb):
FakePin.current_cell = None
return False
def put(self, x, y, a):
self.put_calls.append((self.name, x, y, a))
placed = FakeCell(name=f"{self.name}_placed")
placed.pin = {
name: FakePlacedPin(name, pin.x + x, pin.y + y, pin.a + a)
for name, pin in self.pin.items()
}
return placed
class FakeNazca:
Pin = FakePin
Cell = FakeCell
spec = parse_cell_dict({
"name": "cell",
"elements": {
"input": {
"type": "port",
"x": 5,
"y": 10,
"angle": 90,
"width": 0.5,
"port_number": 2,
"pitch": 12,
"pins": [
{"name": "input_io1", "role": "io1"},
{"name": "input_io2", "role": "io2"},
],
},
},
})
pin_map = {}
_register_element_pins(pin_map, "input", spec.elements["input"], FakeNazca)
self.assertEqual(FakePin.created_names, ["input_io1", "input_io1_in", "input_io2", "input_io2_in"])
self.assertEqual(FakeCell.put_calls, [("element_input", 5.0, 10.0, 90.0)])
self.assertEqual(pin_map[("input", "input_io1")].a, 450.0)
self.assertEqual(pin_map[("input", "input_io2")].a, 450.0)
self.assertEqual((pin_map[("input", "input_io1")].x, pin_map[("input", "input_io1")].y), (5.0, 16.0))
self.assertEqual((pin_map[("input", "input_io2")].x, pin_map[("input", "input_io2")].y), (5.0, 4.0))
def test_anchor_element_defaults_to_named_a_b_pins(self):
from mxpic_router.builder import _register_element_pins
from mxpic_router.eda_loader import parse_cell_dict
class FakePlacedPin:
def __init__(self, name, x, y, a):
self.name = name
self.x = x
self.y = y
self.a = a
class FakePin:
current_cell = None
def __init__(self, name, width=None, xs=None):
self.name = name
def put(self, x, y, a):
placed = FakePlacedPin(self.name, x, y, a)
if FakePin.current_cell is not None:
FakePin.current_cell.pin[self.name] = placed
return placed
class FakeCell:
def __init__(self, name=None, instantiate=True):
self.name = name
self.pin = {}
def __enter__(self):
FakePin.current_cell = self
return self
def __exit__(self, exc_type, exc, tb):
FakePin.current_cell = None
return False
def put(self, x, y, a):
placed = FakeCell(name=f"{self.name}_placed")
placed.pin = {
name: FakePlacedPin(name, pin.x + x, pin.y + y, pin.a + a)
for name, pin in self.pin.items()
}
return placed
class FakeNazca:
Pin = FakePin
Cell = FakeCell
spec = parse_cell_dict({
"name": "cell",
"elements": {
"anchor_1": {"type": "anchor", "x": 10, "y": 20, "angle": 0, "port_number": 2, "pitch": 12},
},
})
pin_map = {}
_register_element_pins(pin_map, "anchor_1", spec.elements["anchor_1"], FakeNazca)
self.assertIn(("anchor_1", "anchor_1_a1"), pin_map)
self.assertIn(("anchor_1", "anchor_1_b1"), pin_map)
self.assertIn(("anchor_1", "anchor_1_a2"), pin_map)
self.assertIn(("anchor_1", "anchor_1_b2"), pin_map)
self.assertEqual(pin_map[("anchor_1", "anchor_1_a1")].a, 180.0)
self.assertEqual(pin_map[("anchor_1", "anchor_1_b1")].a, 0.0)
def test_pdk_metadata_ports_are_registered_as_pins_for_allowed_pdk_roots(self):
from mxpic_router.builder import _metadata_pins
metadata = {"ports": {"a1": {"x": 0, "y": 0, "a": 180}}}
self.assertEqual(
_metadata_pins(metadata, r"D:\mxpic\opt_pdk_public\foundries"),
metadata["ports"],
)
self.assertEqual(_metadata_pins(metadata, r"D:\mxpic\some_project_layout"), {})
if __name__ == "__main__":
unittest.main()