@@ -316,6 +316,131 @@ def test_submit_dry_run(self, mock_version, mock_check_output):
316316 # Verify no requests were made
317317 self .assertFalse (hasattr (step , "_request_made" ))
318318
319+ @mock .patch ("chipflow_lib.steps.silicon.subprocess.check_output" )
320+ @mock .patch ("chipflow_lib.steps.silicon.importlib.metadata.version" )
321+ @mock .patch ("json.dumps" )
322+ def test_config_json_content (self , mock_json_dumps , mock_version , mock_check_output ):
323+ """Test the content of the config.json generated by submit"""
324+ # Setup mocks for git commands - need enough values for two calls to submit
325+ mock_check_output .side_effect = [
326+ "abcdef\n " , # git rev-parse for first submit
327+ "" , # git status for first submit
328+ "abcdef\n " , # git rev-parse for second submit
329+ "" # git status for second submit
330+ ]
331+
332+ # Setup version mocks
333+ mock_version .return_value = "1.0.0"
334+
335+ # Create a custom platform mock with specific ports
336+ platform_mock = mock .MagicMock ()
337+ platform_mock ._ports = {
338+ "uart_tx" : mock .MagicMock (
339+ pins = ["A1" ],
340+ direction = mock .MagicMock (value = "o" )
341+ ),
342+ "uart_rx" : mock .MagicMock (
343+ pins = ["B1" ],
344+ direction = mock .MagicMock (value = "i" )
345+ ),
346+ "gpio" : mock .MagicMock (
347+ pins = ["C1" , "C2" , "C3" ],
348+ direction = mock .MagicMock (value = "io" )
349+ )
350+ }
351+
352+ # Create SiliconStep with mocked platform
353+ step = SiliconStep (self .config )
354+ step .platform = platform_mock
355+
356+ # Mock the json.dumps to capture the config content
357+ def capture_json_args (* args , ** kwargs ):
358+ if len (args ) > 0 and isinstance (args [0 ], dict ) and "silicon" in args [0 ]:
359+ # Store the captured config for later assertion
360+ capture_json_args .captured_config = args [0 ]
361+ return "mocked_json_string"
362+
363+ capture_json_args .captured_config = None
364+ mock_json_dumps .side_effect = capture_json_args
365+
366+ # Call submit with dry run to avoid actual HTTP requests
367+ with mock .patch ("builtins.print" ):
368+ step .submit ("/path/to/rtlil" , dry_run = True )
369+
370+ # Verify the config content
371+ config = capture_json_args .captured_config
372+ self .assertIsNotNone (config , "Config should have been captured" )
373+
374+ # Check dependency versions
375+ self .assertIn ("dependency_versions" , config )
376+ dep_versions = config ["dependency_versions" ]
377+ self .assertEqual (dep_versions ["chipflow-lib" ], "1.0.0" )
378+ self .assertEqual (dep_versions ["amaranth" ], "1.0.0" )
379+
380+ # Check silicon section
381+ self .assertIn ("silicon" , config )
382+ silicon = config ["silicon" ]
383+
384+ # Check process and package
385+ self .assertEqual (silicon ["process" ], "ihp_sg13g2" )
386+ self .assertEqual (silicon ["pad_ring" ], "cf20" )
387+
388+ # Check pads configuration
389+ self .assertIn ("pads" , silicon )
390+ pads = silicon ["pads" ]
391+
392+ # Check specific pads
393+ self .assertIn ("uart_tx" , pads )
394+ self .assertEqual (pads ["uart_tx" ]["loc" ], "A1" )
395+ self .assertEqual (pads ["uart_tx" ]["type" ], "o" )
396+
397+ self .assertIn ("uart_rx" , pads )
398+ self .assertEqual (pads ["uart_rx" ]["loc" ], "B1" )
399+ self .assertEqual (pads ["uart_rx" ]["type" ], "i" )
400+
401+ # Check multi-bit ports are correctly expanded
402+ self .assertIn ("gpio0" , pads )
403+ self .assertEqual (pads ["gpio0" ]["loc" ], "C1" )
404+ self .assertEqual (pads ["gpio0" ]["type" ], "io" )
405+
406+ self .assertIn ("gpio1" , pads )
407+ self .assertEqual (pads ["gpio1" ]["loc" ], "C2" )
408+
409+ self .assertIn ("gpio2" , pads )
410+ self .assertEqual (pads ["gpio2" ]["loc" ], "C3" )
411+
412+ # Check power section exists and matches config
413+ self .assertIn ("power" , silicon )
414+
415+ # Add a power entry to the config to test power section in the generated config
416+ self .config ["chipflow" ]["silicon" ]["power" ] = {
417+ "vdd" : {"type" : "power" , "loc" : "N1" },
418+ "gnd" : {"type" : "ground" , "loc" : "S2" }
419+ }
420+
421+ # Recreate SiliconStep with updated config
422+ step_with_power = SiliconStep (self .config )
423+ step_with_power .platform = platform_mock
424+
425+ # Reset captured config and call submit again
426+ capture_json_args .captured_config = None
427+ with mock .patch ("builtins.print" ):
428+ step_with_power .submit ("/path/to/rtlil" , dry_run = True )
429+
430+ # Get new config with power entries
431+ config_with_power = capture_json_args .captured_config
432+ self .assertIsNotNone (config_with_power , "Config with power should have been captured" )
433+
434+ # Check power entries
435+ power = config_with_power ["silicon" ]["power" ]
436+ self .assertIn ("vdd" , power )
437+ self .assertEqual (power ["vdd" ]["type" ], "power" )
438+ self .assertEqual (power ["vdd" ]["loc" ], "N1" )
439+
440+ self .assertIn ("gnd" , power )
441+ self .assertEqual (power ["gnd" ]["type" ], "ground" )
442+ self .assertEqual (power ["gnd" ]["loc" ], "S2" )
443+
319444 @mock .patch ("chipflow_lib.steps.silicon.SiliconPlatform" )
320445 @mock .patch ("chipflow_lib.steps.silicon.importlib.metadata.version" )
321446 @mock .patch ("chipflow_lib.steps.silicon.subprocess.check_output" )
0 commit comments