Skip to content

Commit fb2999d

Browse files
committed
Add comprehensive tests for SiliconStep and SiliconTop
- Created new test_steps_silicon.py with tests for SiliconStep and SiliconTop classes - Added 'amaranth: UnusedElaboratable=no' directive to suppress warnings - Fixed sortpins test in test_utils_additional.py - Achieved 96% test coverage for silicon.py
1 parent 18320b3 commit fb2999d

File tree

5 files changed

+824
-360
lines changed

5 files changed

+824
-360
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ __pycache__/
1818
.doit.db
1919

2020
docs/_build
21+
/tmp

tests/test_pin_lock_complete.py

Lines changed: 0 additions & 356 deletions
Original file line numberDiff line numberDiff line change
@@ -35,362 +35,6 @@ def allocate(self, available, width):
3535
return allocated
3636

3737

38-
@mock.patch('chipflow_lib.pin_lock._parse_config')
39-
class TestLockPins(unittest.TestCase):
40-
def setUp(self):
41-
"""Set up test environment with temporary directory"""
42-
self.temp_dir = tempfile.TemporaryDirectory()
43-
self.original_cwd = os.getcwd()
44-
os.chdir(self.temp_dir.name)
45-
46-
# Set up mock environment variables
47-
self.env_patcher = mock.patch.dict(os.environ, {
48-
"CHIPFLOW_ROOT": self.temp_dir.name
49-
})
50-
self.env_patcher.start()
51-
52-
# Create test configuration
53-
self.test_config = {
54-
"chipflow": {
55-
"silicon": {
56-
"package": "test_package",
57-
"pads": {
58-
"clk": {"type": "clock", "loc": "1"},
59-
"rst": {"type": "reset", "loc": "2"},
60-
"led": {"type": "io", "loc": "3"}
61-
},
62-
"power": {
63-
"vdd": {"type": "power", "loc": "4"},
64-
"vss": {"type": "ground", "loc": "5"}
65-
}
66-
},
67-
"clocks": {
68-
"default": "clk"
69-
},
70-
"resets": {
71-
"default": "rst"
72-
},
73-
"top": {
74-
"soc": "module:SoC"
75-
}
76-
}
77-
}
78-
79-
# Create mock interfaces
80-
self.mock_interfaces = {
81-
"soc": {
82-
"interface": {
83-
"members": {
84-
"uart": {
85-
"type": "interface",
86-
"members": {
87-
"tx": {"type": "port", "width": 1, "dir": "o"},
88-
"rx": {"type": "port", "width": 1, "dir": "i"}
89-
}
90-
},
91-
"gpio": {
92-
"type": "interface",
93-
"members": {
94-
"pins": {"type": "port", "width": 4, "dir": "io"}
95-
}
96-
}
97-
}
98-
}
99-
}
100-
}
101-
102-
def tearDown(self):
103-
"""Clean up after tests"""
104-
self.env_patcher.stop()
105-
os.chdir(self.original_cwd)
106-
self.temp_dir.cleanup()
107-
108-
@mock.patch('chipflow_lib.pin_lock.PACKAGE_DEFINITIONS')
109-
@mock.patch('chipflow_lib.pin_lock.top_interfaces')
110-
@mock.patch('builtins.print')
111-
def test_lock_pins_new_lockfile(self, mock_print, mock_top_interfaces, mock_package_defs, mock_parse_config):
112-
"""Test lock_pins when no lockfile exists"""
113-
# Setup mocks
114-
mock_parse_config.return_value = self.test_config
115-
mock_top_interfaces.return_value = ({}, self.mock_interfaces)
116-
117-
# Create mock package type
118-
mock_package_type = MockPackageType()
119-
mock_package_defs.__getitem__.return_value = mock_package_type
120-
mock_package_defs.__contains__.return_value = True
121-
122-
# Execute lock_pins
123-
with mock.patch('chipflow_lib.pin_lock.logger') as mock_logger:
124-
lock_pins()
125-
126-
# Verify print and logger calls
127-
mock_print.assert_called_once_with("Locking pins: ")
128-
mock_logger.debug.assert_any_call(f"Checking [chipflow.silicon.pads]:")
129-
mock_logger.debug.assert_any_call(f"Checking [chipflow.silicon.power]:")
130-
131-
# Verify lockfile was created
132-
lockfile_path = Path('pins.lock')
133-
self.assertTrue(lockfile_path.exists())
134-
135-
# Check content of lockfile
136-
with open(lockfile_path, 'r') as f:
137-
lock_data = json.load(f)
138-
139-
# Check that pins were allocated for interfaces
140-
self.assertIn("port_map", lock_data)
141-
self.assertIn("soc", lock_data["port_map"])
142-
self.assertIn("uart", lock_data["port_map"]["soc"])
143-
self.assertIn("gpio", lock_data["port_map"]["soc"])
144-
145-
# Check that pin allocations make sense
146-
self.assertEqual(len(lock_data["port_map"]["soc"]["uart"]["tx"]["pins"]), 1)
147-
self.assertEqual(len(lock_data["port_map"]["soc"]["uart"]["rx"]["pins"]), 1)
148-
self.assertEqual(len(lock_data["port_map"]["soc"]["gpio"]["pins"]["pins"]), 4)
149-
150-
@mock.patch('chipflow_lib.pin_lock.PACKAGE_DEFINITIONS')
151-
@mock.patch('chipflow_lib.pin_lock.top_interfaces')
152-
@mock.patch('builtins.print')
153-
def test_lock_pins_existing_lockfile(self, mock_print, mock_top_interfaces, mock_package_defs, mock_parse_config):
154-
"""Test lock_pins when lockfile exists"""
155-
# Setup mocks
156-
mock_parse_config.return_value = self.test_config
157-
mock_top_interfaces.return_value = ({}, self.mock_interfaces)
158-
159-
# Create mock package type
160-
mock_package_type = MockPackageType()
161-
mock_package_defs.__getitem__.return_value = mock_package_type
162-
mock_package_defs.__contains__.return_value = True
163-
164-
# Create existing lockfile with predefined pin allocations
165-
existing_lock = {
166-
"package": {
167-
"package_type": {
168-
"type": "_QuadPackageDef",
169-
"name": "test_package",
170-
"width": 36,
171-
"height": 36
172-
},
173-
"power": {
174-
"vdd": {"type": "power", "pins": ["4"], "port_name": "vdd"},
175-
"vss": {"type": "ground", "pins": ["5"], "port_name": "vss"}
176-
},
177-
"clocks": {
178-
"clk": {"type": "clock", "pins": ["1"], "direction": "i", "port_name": "clk"}
179-
},
180-
"resets": {
181-
"rst": {"type": "reset", "pins": ["2"], "direction": "i", "port_name": "rst"}
182-
}
183-
},
184-
"port_map": {
185-
"soc": {
186-
"uart": {
187-
"tx": {"type": "output", "pins": ["10"], "port_name": "soc_uart_tx", "direction": "o"},
188-
"rx": {"type": "input", "pins": ["11"], "port_name": "soc_uart_rx", "direction": "i"}
189-
},
190-
"gpio": {
191-
"pins": {"type": "bidir", "pins": ["12", "13", "14", "15"], "port_name": "soc_gpio_pins", "direction": "io"}
192-
}
193-
}
194-
},
195-
"metadata": self.mock_interfaces
196-
}
197-
198-
with open('pins.lock', 'w') as f:
199-
json.dump(existing_lock, f)
200-
201-
# Execute lock_pins
202-
with mock.patch('chipflow_lib.pin_lock.logger') as mock_logger:
203-
lock_pins()
204-
205-
# Verify print and logger calls
206-
mock_print.assert_called_once_with("Locking pins: using pins.lock")
207-
208-
# Verify lockfile was updated
209-
lockfile_path = Path('pins.lock')
210-
self.assertTrue(lockfile_path.exists())
211-
212-
# Check content of lockfile
213-
with open(lockfile_path, 'r') as f:
214-
lock_data = json.load(f)
215-
216-
# Check that pins were preserved from existing lock
217-
self.assertEqual(lock_data["port_map"]["soc"]["uart"]["tx"]["pins"], ["10"])
218-
self.assertEqual(lock_data["port_map"]["soc"]["uart"]["rx"]["pins"], ["11"])
219-
self.assertEqual(lock_data["port_map"]["soc"]["gpio"]["pins"]["pins"], ["12", "13", "14", "15"])
220-
221-
@mock.patch('chipflow_lib.pin_lock.PACKAGE_DEFINITIONS')
222-
@mock.patch('chipflow_lib.pin_lock.top_interfaces')
223-
def test_lock_pins_out_of_pins(self, mock_top_interfaces, mock_package_defs, mock_parse_config):
224-
"""Test lock_pins when we run out of pins"""
225-
# Setup mocks
226-
mock_parse_config.return_value = self.test_config
227-
mock_top_interfaces.return_value = ({}, self.mock_interfaces)
228-
229-
# Create mock package type with limited pins
230-
limited_package = MockPackageType()
231-
limited_package.pins = set(["1", "2", "3", "4", "5"]) # Only enough for the fixed pins
232-
mock_package_defs.__getitem__.return_value = limited_package
233-
mock_package_defs.__contains__.return_value = True
234-
235-
# Execute lock_pins - should raise an error
236-
with self.assertRaises(ChipFlowError) as cm:
237-
lock_pins()
238-
239-
self.assertIn("No pins were allocated", str(cm.exception))
240-
241-
@mock.patch('chipflow_lib.pin_lock.PACKAGE_DEFINITIONS')
242-
@mock.patch('chipflow_lib.pin_lock.top_interfaces')
243-
def test_lock_pins_pin_conflict(self, mock_top_interfaces, mock_package_defs, mock_parse_config):
244-
"""Test lock_pins when there's a pin conflict with existing lock"""
245-
# Setup mocks
246-
# Change the loc of a pin in the config
247-
conflicting_config = self.test_config.copy()
248-
conflicting_config["chipflow"]["silicon"]["pads"]["clk"]["loc"] = "99"
249-
250-
mock_parse_config.return_value = conflicting_config
251-
mock_top_interfaces.return_value = ({}, self.mock_interfaces)
252-
253-
# Create mock package type
254-
mock_package_type = MockPackageType()
255-
mock_package_defs.__getitem__.return_value = mock_package_type
256-
mock_package_defs.__contains__.return_value = True
257-
258-
# Create existing lockfile with clk on pin 1
259-
existing_lock = {
260-
"package": {
261-
"package_type": {
262-
"type": "_QuadPackageDef",
263-
"name": "test_package",
264-
"width": 36,
265-
"height": 36
266-
},
267-
"power": {
268-
"vdd": {"type": "power", "pins": ["4"], "port_name": "vdd"},
269-
"vss": {"type": "ground", "pins": ["5"], "port_name": "vss"}
270-
},
271-
"clocks": {
272-
"clk": {"type": "clock", "pins": ["1"], "direction": "i", "port_name": "clk"}
273-
},
274-
"resets": {
275-
"rst": {"type": "reset", "pins": ["2"], "direction": "i", "port_name": "rst"}
276-
}
277-
},
278-
"port_map": {},
279-
"metadata": {}
280-
}
281-
282-
with open('pins.lock', 'w') as f:
283-
json.dump(existing_lock, f)
284-
285-
# Execute lock_pins - should raise an error
286-
with self.assertRaises(ChipFlowError) as cm:
287-
lock_pins()
288-
289-
self.assertIn("conflicts with pins.lock", str(cm.exception))
290-
291-
@mock.patch('chipflow_lib.pin_lock.PACKAGE_DEFINITIONS')
292-
@mock.patch('chipflow_lib.pin_lock.top_interfaces')
293-
def test_lock_pins_interface_size_change(self, mock_top_interfaces, mock_package_defs, mock_parse_config):
294-
"""Test lock_pins when an interface changes size"""
295-
# Setup mocks
296-
mock_parse_config.return_value = self.test_config
297-
298-
# Create interfaces with larger gpio width
299-
modified_interfaces = {
300-
"soc": {
301-
"interface": {
302-
"members": {
303-
"uart": {
304-
"type": "interface",
305-
"members": {
306-
"tx": {"type": "port", "width": 1, "dir": "o"},
307-
"rx": {"type": "port", "width": 1, "dir": "i"}
308-
}
309-
},
310-
"gpio": {
311-
"type": "interface",
312-
"members": {
313-
"pins": {"type": "port", "width": 8, "dir": "io"} # Changed from 4 to 8
314-
}
315-
}
316-
}
317-
}
318-
}
319-
}
320-
321-
mock_top_interfaces.return_value = ({}, modified_interfaces)
322-
323-
# Create mock package type
324-
mock_package_type = MockPackageType()
325-
mock_package_defs.__getitem__.return_value = mock_package_type
326-
mock_package_defs.__contains__.return_value = True
327-
328-
# Create existing lockfile with gpio width 4
329-
existing_lock = {
330-
"package": {
331-
"package_type": {
332-
"type": "_QuadPackageDef",
333-
"name": "test_package",
334-
"width": 36,
335-
"height": 36
336-
},
337-
"power": {
338-
"vdd": {"type": "power", "pins": ["4"], "port_name": "vdd"},
339-
"vss": {"type": "ground", "pins": ["5"], "port_name": "vss"}
340-
},
341-
"clocks": {
342-
"clk": {"type": "clock", "pins": ["1"], "direction": "i", "port_name": "clk"}
343-
},
344-
"resets": {
345-
"rst": {"type": "reset", "pins": ["2"], "direction": "i", "port_name": "rst"}
346-
}
347-
},
348-
"port_map": {
349-
"soc": {
350-
"uart": {
351-
"tx": {"type": "output", "pins": ["10"], "port_name": "soc_uart_tx", "direction": "o"},
352-
"rx": {"type": "input", "pins": ["11"], "port_name": "soc_uart_rx", "direction": "i"}
353-
},
354-
"gpio": {
355-
"pins": {"type": "bidir", "pins": ["12", "13", "14", "15"], "port_name": "soc_gpio_pins", "direction": "io"}
356-
}
357-
}
358-
},
359-
"metadata": {}
360-
}
361-
362-
with open('pins.lock', 'w') as f:
363-
json.dump(existing_lock, f)
364-
365-
# Execute lock_pins - should raise an error
366-
with self.assertRaises(ChipFlowError) as cm:
367-
lock_pins()
368-
369-
self.assertIn("has changed size", str(cm.exception))
370-
371-
@mock.patch('chipflow_lib.pin_lock.PACKAGE_DEFINITIONS')
372-
@mock.patch('chipflow_lib.pin_lock.top_interfaces')
373-
@mock.patch('builtins.print')
374-
def test_lock_pins_unknown_package(self, mock_print, mock_top_interfaces, mock_package_defs, mock_parse_config):
375-
"""Test lock_pins with an unknown package"""
376-
# Setup config with unknown package
377-
unknown_config = self.test_config.copy()
378-
unknown_config["chipflow"]["silicon"]["package"] = "unknown_package"
379-
mock_parse_config.return_value = unknown_config
380-
381-
# Create mock interfaces
382-
mock_top_interfaces.return_value = ({}, {})
383-
384-
# Set up package defs
385-
mock_package_defs.__contains__.return_value = False
386-
387-
# Execute lock_pins
388-
with mock.patch('chipflow_lib.pin_lock.logger') as mock_logger:
389-
with self.assertRaises(KeyError) as cm:
390-
lock_pins()
391-
392-
# Verify logger warning
393-
mock_logger.debug.assert_any_call("Package 'unknown_package is unknown")
39438

39539

39640
class TestPinLockUtilities(unittest.TestCase):

0 commit comments

Comments
 (0)