Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SvgPcb layout template backend + netlister refactor #337

Merged
merged 41 commits into from
Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
5c35d7f
wip skeleton
ducky64 Apr 8, 2024
31b05a9
wip
ducky64 Apr 8, 2024
6c63e25
plumbing
ducky64 Apr 8, 2024
add7442
Update SvgPcbBackend.py
ducky64 Apr 9, 2024
161d74a
plumbed!
ducky64 Apr 9, 2024
a3b1307
working w/o plumbing
ducky64 Apr 9, 2024
6d8e49c
create keyboard netlist
ducky64 Apr 9, 2024
f4e3956
Update SvgPcbBackend.py
ducky64 Apr 9, 2024
4edf8c5
Update SvgPcbBackend.py
ducky64 Apr 9, 2024
8308578
Update SvgPcbTemplateBlock.py
ducky64 Apr 9, 2024
2f1fbc0
rename -> NetBlock,NetPin
ducky64 Apr 9, 2024
834976e
cleaning naming
ducky64 Apr 9, 2024
b931eef
cleaning?
ducky64 Apr 9, 2024
8869ed0
fix tests
ducky64 Apr 9, 2024
f9b00e8
refdes generator - broken
ducky64 Apr 10, 2024
76bb7b0
wip, poorly?
ducky64 Apr 10, 2024
a7089cd
wip
ducky64 Apr 10, 2024
28fcb86
wip
ducky64 Apr 10, 2024
3a17d74
working
ducky64 Apr 10, 2024
6948464
nets
ducky64 Apr 10, 2024
ecf790b
clean up goodness
ducky64 Apr 10, 2024
772c00a
netlist update
ducky64 Apr 10, 2024
c829510
Update SvgPcbBackend.py
ducky64 Apr 10, 2024
f5a7557
Update SvgPcbBackend.py
ducky64 Apr 10, 2024
62c32b2
Update SvgPcbBackend.py
ducky64 Apr 10, 2024
87519c5
Update SwitchMatrix.py
ducky64 Apr 10, 2024
88b936e
Update SwitchMatrix.py
ducky64 Apr 10, 2024
e9711e5
refactor wip
ducky64 Apr 10, 2024
59c285b
wip
ducky64 Apr 10, 2024
1aa5e16
wip switch matrix dynamic pins
ducky64 Apr 17, 2024
d614b61
Path.startswith
ducky64 Apr 17, 2024
78e9957
Update SvgPcbTemplateBlock.py
ducky64 Apr 17, 2024
607a454
cleaning
ducky64 Apr 17, 2024
294c1b0
Update SvgPcbTemplateBlock.py
ducky64 Apr 17, 2024
6e000ad
Update SwitchMatrix.py
ducky64 Apr 17, 2024
4052c44
Update SwitchMatrix.py
ducky64 Apr 17, 2024
82bf10d
cleaning
ducky64 Apr 17, 2024
04cd66a
clean test cases
ducky64 Apr 17, 2024
746c722
Update SvgPcbTemplateBlock.py
ducky64 Apr 19, 2024
fe92591
merge
ducky64 Apr 22, 2024
c671288
update netlists
ducky64 Apr 22, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions edg/BoardCompiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,15 @@ def compile_board(design: Type[Block], target_dir_name: Optional[Tuple[str, str]

design_filename = os.path.join(target_dir, f'{target_name}.edg')
netlist_filename = os.path.join(target_dir, f'{target_name}.net')
netlist_refdes_filename = os.path.join(target_dir, f'{target_name}.ref.net')
bom_filename = os.path.join(target_dir, f'{target_name}.csv')

with suppress(FileNotFoundError):
os.remove(design_filename)
with suppress(FileNotFoundError):
os.remove(netlist_filename)
with suppress(FileNotFoundError):
os.remove(netlist_refdes_filename)
with suppress(FileNotFoundError):
os.remove(bom_filename)

Expand All @@ -39,13 +42,17 @@ def compile_board(design: Type[Block], target_dir_name: Optional[Tuple[str, str]
raise edg_core.ScalaCompilerInterface.CompilerCheckError(f"error during compilation: \n{compiled.error}")

netlist_all = NetlistBackend().run(compiled)
netlist_refdes = NetlistBackend().run(compiled, {'RefdesMode': 'refdes'})
bom_all = GenerateBom().run(compiled)
assert len(netlist_all) == 1

if target_dir_name is not None:
with open(netlist_filename, 'w', encoding='utf-8') as net_file:
net_file.write(netlist_all[0][1])

with open(netlist_refdes_filename, 'w', encoding='utf-8') as net_file:
net_file.write(netlist_refdes[0][1])

with open(bom_filename, 'w', encoding='utf-8') as bom_file:
bom_file.write(bom_all[0][1])

Expand Down
10 changes: 7 additions & 3 deletions edg_core/ScalaCompilerInterface.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,13 @@ def __init__(self, design: edgir.Design, values: Dict[bytes, edgir.LitTypes], er

# Reserved.V is a string because it doesn't load properly at runtime
# Serialized strings are used since proto objects are mutable and unhashable
def get_value(self, path: Iterable[Union[str, 'edgir.Reserved.V']]) -> Optional[edgir.LitTypes]:
path_key = edgir.LocalPathList(path).SerializeToString()
return self._values.get(path_key, None)
def get_value(self, path: Union[edgir.LocalPath, Iterable[Union[str, 'edgir.Reserved.V']]]) ->\
Optional[edgir.LitTypes]:
if isinstance(path, edgir.LocalPath):
localpath = path
else:
localpath = edgir.LocalPathList(path)
return self._values.get(localpath.SerializeToString(), None)

def append_values(self, values: List[Tuple[edgir.LocalPath, edgir.ValueLit]]):
"""Append solved values to this design, such as from a refinement pass"""
Expand Down
44 changes: 33 additions & 11 deletions edg_core/TransformUtil.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,39 @@ def __repr__(self) -> str:
def empty(cls) -> Path:
return Path((), (), (), ())

def append_block(self, name: str) -> Path:
assert not self.links and not self.ports and not self.params, f"tried to append block {name} to {self}"
return Path(self.blocks + (name, ), self.links, self.ports, self.params)

def append_link(self, name: str) -> Path:
assert not self.ports and not self.params, f"tried to append link {name} to {self}"
return Path(self.blocks, self.links + (name, ), self.ports, self.params)

def append_port(self, name: str) -> Path:
assert not self.params, f"tried to append port {name} to {self}"
return Path(self.blocks, self.links, self.ports + (name, ), self.params)
def startswith(self, prefix: Path) -> bool:
if self.blocks == prefix.blocks: # exact match, check subpaths
if self.links == prefix.links:
if self.ports == prefix.ports:
return len(self.params) >= len(prefix.params) and self.params[:len(prefix.params)] == prefix.params
elif len(self.ports) >= len(prefix.ports) and self.ports[:len(prefix.ports)] == prefix.ports:
return (not self.params) and (not prefix.params)
else:
return False

elif len(self.links) >= len(prefix.links) and self.links[:len(prefix.links)] == prefix.links:
return (not self.ports) and (not prefix.ports) and (not self.params) and (not prefix.params)
else:
return False

elif len(self.blocks) >= len(prefix.blocks) and self.blocks[:len(prefix.blocks)] == prefix.blocks:
# partial match, check subpaths don't exist
return (not self.links) and (not prefix.links) and (not self.ports) and (not prefix.ports) and \
(not self.params) and (not prefix.params)
else: # no match
return False

def append_block(self, *names: str) -> Path:
assert not self.links and not self.ports and not self.params, f"tried to append block {names} to {self}"
return Path(self.blocks + tuple(names), self.links, self.ports, self.params)

def append_link(self, *names: str) -> Path:
assert not self.ports and not self.params, f"tried to append link {names} to {self}"
return Path(self.blocks, self.links + tuple(names), self.ports, self.params)

def append_port(self, *names: str) -> Path:
assert not self.params, f"tried to append port {names} to {self}"
return Path(self.blocks, self.links, self.ports + tuple(names), self.params)

def append_param(self, name: str) -> Path:
return Path(self.blocks, self.links, self.ports, self.params + (name, ))
Expand Down
21 changes: 21 additions & 0 deletions edg_core/test_path.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import unittest

from .TransformUtil import Path


class PathTestCase(unittest.TestCase):
def test_startswith(self) -> None:
path = Path.empty()
self.assertTrue(path.append_block('a', 'b').startswith(path.append_block('a')))
self.assertFalse(path.append_block('a').startswith(path.append_block('a', 'b')))
self.assertTrue(path.append_block('a').startswith(path.append_block('a')))
self.assertTrue(path.append_block('a', 'b').startswith(path.append_block('a', 'b')))

self.assertFalse(path.append_block('a').startswith(path.append_link('a')))

self.assertTrue(path.append_block('a').append_link('b').startswith(path.append_block('a')))
self.assertTrue(path.append_block('a').append_link('b').startswith(path.append_block('a').append_link('b')))
self.assertTrue(path.append_block('a').append_link('b', 'c').startswith(path.append_block('a').append_link('b')))
self.assertTrue(path.append_block('a').append_link('b', 'c').startswith(path.append_block('a').append_link('b', 'c')))
self.assertFalse(path.append_block('a').append_link('b').startswith(path.append_link('b')))
self.assertFalse(path.append_block('a').append_link('b').startswith(path.append_block('a', 'b')))
75 changes: 46 additions & 29 deletions electronics_abstract_parts/test_kicad_import_netlist.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
# this class lives in electronics_abstract_parts since it requires the Resistor
import unittest

from edg_core import Block, Range, Refinements, InOut
from edg_core import Block, Range, Refinements, InOut, TransformUtil
from electronics_model import FootprintBlock, Passive
from electronics_abstract_parts import Resistor
from electronics_model.test_netlist import NetlistTestCase
from electronics_model.test_netlist import NetlistTestCase, Net, NetPin, NetBlock
from electronics_model.test_kicad_import_blackbox import KiCadBlackboxBlock
from electronics_model.footprint import Pin, Block as FBlock # TODO cleanup naming


class PassiveDummy(Block):
Expand Down Expand Up @@ -41,29 +40,47 @@ def test_netlist(self):
]
))
# note, dut pruned out from paths since it's the only block in the top-level
self.assertEqual(net.nets['pwr'], [
Pin('U1', '1')
])
self.assertEqual(net.nets['gnd'], [
Pin('U1', '3')
])
self.assertEqual(net.nets['node.0'], [
Pin('U1', '2'),
Pin('res', '1')
])
self.assertEqual(net.nets['out'], [
Pin('res', '2')
])
self.assertEqual(net.blocks['U1'], FBlock('Package_TO_SOT_SMD:SOT-23', 'U1',
# expected value is wonky because netlisting combines part and value
'Sensor_Temperature:MCP9700AT-ETT', 'MCP9700AT-ETT',
['dut', 'U1'], ['U1'],
['electronics_model.KiCadSchematicBlock.KiCadBlackbox']))
self.assertEqual(net.blocks['SYM1'], FBlock('Symbol:Symbol_ESD-Logo_CopperTop', 'SYM1',
# expected value is wonky because netlisting combines part and value
'Graphic:SYM_ESD_Small', 'SYM_ESD_Small',
['dut', 'SYM1'], ['SYM1'],
['electronics_model.KiCadSchematicBlock.KiCadBlackbox']))
self.assertEqual(net.blocks['res'], FBlock('Resistor_SMD:R_0603_1608Metric', 'R1', '', '',
['dut', 'res'], ['res'],
['electronics_abstract_parts.test_kicad_import_netlist.DummyResistor']))
self.assertIn(Net('dut.pwr', [
NetPin(['dut', 'U1'], '1')
], [
TransformUtil.Path.empty().append_block('dut').append_port('pwr'),
TransformUtil.Path.empty().append_block('dut', 'U1').append_port('ports', '1'),
TransformUtil.Path.empty().append_block('dummypwr').append_port('port'),
]), net.nets)
self.assertIn(Net('dut.gnd', [
NetPin(['dut', 'U1'], '3')
], [
TransformUtil.Path.empty().append_block('dut').append_port('gnd'),
TransformUtil.Path.empty().append_block('dut', 'U1').append_port('ports', '3'),
TransformUtil.Path.empty().append_block('dummygnd').append_port('port'),
]), net.nets)
self.assertIn(Net('dut.node', [
NetPin(['dut', 'U1'], '2'),
NetPin(['dut', 'res'], '1')
], [
TransformUtil.Path.empty().append_block('dut', 'U1').append_port('ports', '2'),
TransformUtil.Path.empty().append_block('dut', 'res').append_port('a'),
]), net.nets)
self.assertIn(Net('dut.out', [
NetPin(['dut', 'res'], '2')
], [
TransformUtil.Path.empty().append_block('dut').append_port('out'),
TransformUtil.Path.empty().append_block('dut', 'res').append_port('b'),
TransformUtil.Path.empty().append_block('dummyout').append_port('port'),
]), net.nets)
self.assertIn(NetBlock('Package_TO_SOT_SMD:SOT-23', 'U1',
# expected value is wonky because netlisting combines part and value
'Sensor_Temperature:MCP9700AT-ETT', 'MCP9700AT-ETT',
['dut', 'U1'], ['U1'],
['electronics_model.KiCadSchematicBlock.KiCadBlackbox']),
net.blocks)
self.assertIn(NetBlock('Symbol:Symbol_ESD-Logo_CopperTop', 'SYM1',
# expected value is wonky because netlisting combines part and value
'Graphic:SYM_ESD_Small', 'SYM_ESD_Small',
['dut', 'SYM1'], ['SYM1'],
['electronics_model.KiCadSchematicBlock.KiCadBlackbox']),
net.blocks)
self.assertIn(NetBlock('Resistor_SMD:R_0603_1608Metric', 'R1', '', '',
['dut', 'res'], ['res'],
['electronics_abstract_parts.test_kicad_import_netlist.DummyResistor']),
net.blocks)
80 changes: 39 additions & 41 deletions electronics_lib/Microcontroller_Esp32c3.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def _io_pinmap(self) -> PinMapUtil:
PeripheralAnyResource('SPI2', spi_model),
PeripheralAnyResource('SPI2_P', spi_peripheral_model), # TODO shared resource w/ SPI controller
PeripheralAnyResource('I2S', I2sController.empty()),
])
]).remap_pins(self.RESOURCE_PIN_REMAP)


@abstract_block
Expand Down Expand Up @@ -132,6 +132,19 @@ class Esp32c3_Wroom02_Device(Esp32c3_Base, FootprintBlock, JlcPart):

Module datasheet: https://www.espressif.com/sites/default/files/documentation/esp32-c3-wroom-02_datasheet_en.pdf
"""
RESOURCE_PIN_REMAP = {
'MTMS': '3', # GPIO4
'MTDI': '4', # GPIO5
'MTCK': '5', # GPIO6
'MTDO': '6', # GPIO7
'GPIO10': '10',
'GPIO18': '13',
'GPIO19': '14',
'GPIO3': '15',
'GPIO1': '17',
'GPIO0': '18',
}

def _system_pinmap(self) -> Dict[str, CircuitPort]:
return VariantPinRemapper(super()._system_pinmap()).remap({
'Vdd': '1',
Expand All @@ -144,20 +157,6 @@ def _system_pinmap(self) -> Dict[str, CircuitPort]:
'TXD': '12', # TXD, GPIO21
})

def _io_pinmap(self) -> PinMapUtil:
return super()._io_pinmap().remap_pins({
'MTMS': '3', # GPIO4
'MTDI': '4', # GPIO5
'MTCK': '5', # GPIO6
'MTDO': '6', # GPIO7
'GPIO10': '10',
'GPIO18': '13',
'GPIO19': '14',
'GPIO3': '15',
'GPIO1': '17',
'GPIO0': '18',
})

def generate(self) -> None:
super().generate()

Expand Down Expand Up @@ -216,6 +215,31 @@ class Esp32c3_Device(Esp32c3_Base, FootprintBlock, JlcPart):
"""ESP32C3 with 4MB integrated flash
TODO: support other part numbers, including without integrated flash
"""
RESOURCE_PIN_REMAP = {
'GPIO0': '4',
'GPIO1': '5',
'GPIO3': '8',
'MTMS': '9', # GPIO4
'MTDI': '10', # GPIO5
'MTCK': '12', # GPIO6
'MTDO': '13', # GPIO7
'GPIO10': '16',
'GPIO18': '25',
'GPIO19': '26',
}

def _system_pinmap(self) -> Dict[str, CircuitPort]:
return VariantPinRemapper(super()._system_pinmap()).remap({
'Vdd': ['31', '32'], # VDDA
'Vss': ['33'], # 33 is EP
'GPIO2': '6',
'EN': '7',
'GPIO8': '14',
'GPIO9': '15',
'RXD': '27', # U0RXD, GPIO20
'TXD': '28', # U0TXD, GPIO21
})

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.lna_in = self.Port(Passive())
Expand All @@ -238,32 +262,6 @@ def __init__(self, *args, **kwargs):
self.xtal = self.Port(CrystalDriver(frequency_limits=40*MHertz(tol=10e-6),
voltage_out=self.pwr.link().voltage))

def _system_pinmap(self) -> Dict[str, CircuitPort]:
return VariantPinRemapper(super()._system_pinmap()).remap({
'Vdd': ['31', '32'], # VDDA
'Vss': ['33'], # 33 is EP
'GPIO2': '6',
'EN': '7',
'GPIO8': '14',
'GPIO9': '15',
'RXD': '27', # U0RXD, GPIO20
'TXD': '28', # U0TXD, GPIO21
})

def _io_pinmap(self) -> PinMapUtil:
return super()._io_pinmap().remap_pins({
'GPIO0': '4',
'GPIO1': '5',
'GPIO3': '8',
'MTMS': '9', # GPIO4
'MTDI': '10', # GPIO5
'MTCK': '12', # GPIO6
'MTDO': '13', # GPIO7
'GPIO10': '16',
'GPIO18': '25',
'GPIO19': '26',
})

def generate(self) -> None:
super().generate()

Expand Down
Loading
Loading