@@ -350,7 +350,8 @@ def init(project_root):
350350
351351@main .command ('gpio-config' )
352352@click .option ('--project-root' , required = False , type = click .Path (exists = True , file_okay = False ), help = 'Path to the project directory (defaults to current directory).' )
353- def gpio_config (project_root ):
353+ @click .option ('--view' , is_flag = True , help = 'Display current GPIO configuration summary without editing.' )
354+ def gpio_config (project_root , view ):
354355 """Configure GPIO settings interactively and save to project config and user_defines.v."""
355356 if not project_root :
356357 project_root = os .getcwd ()
@@ -547,6 +548,17 @@ def display_summary(gpio_configs, user_to_real_map):
547548 # Initialize gpio_configs
548549 gpio_configs = existing_configs .copy () if existing_configs else {}
549550
551+ # If --view flag is set, just display the summary and return
552+ if view :
553+ if not gpio_configs :
554+ console .print ("[yellow]No GPIO configuration found.[/yellow]" )
555+ console .print ("[dim]Run 'cf gpio-config' to configure GPIOs.[/dim]" )
556+ return
557+ console .print (f"\n [bold cyan]GPIO Configuration ({ gpio_label } )[/bold cyan]" )
558+ display_summary (gpio_configs , user_to_real_map )
559+ console .print ()
560+ return
561+
550562 # ========================
551563 # HEADER
552564 # ========================
@@ -576,7 +588,7 @@ def get_mode_color(mode_key):
576588 if not mode_key :
577589 return "red"
578590 elif "output" in mode_key :
579- return "ansi_bright_blue "
591+ return "ansi_bright_green "
580592 elif "input" in mode_key :
581593 return "cyan"
582594 elif "bidirectional" in mode_key :
@@ -1198,118 +1210,6 @@ def action_quit(self) -> None:
11981210 console .print (f"[red]Error updating user_defines.v: { e } [/red]" )
11991211
12001212
1201- @main .command ('gpio-status' )
1202- @click .option ('--project-root' , required = False , type = click .Path (exists = True , file_okay = False ), help = 'Path to the project directory (defaults to current directory).' )
1203- def gpio_status (project_root ):
1204- """Display current GPIO configuration summary."""
1205- if not project_root :
1206- project_root = os .getcwd ()
1207-
1208- project_root = Path (project_root )
1209-
1210- # Load project config
1211- project_json_path = project_root / '.cf' / 'project.json'
1212- if not project_json_path .exists ():
1213- console .print ("[red]Error: No project configuration found.[/red]" )
1214- console .print ("[dim]Run 'cf gpio-config' first to configure GPIOs.[/dim]" )
1215- return
1216-
1217- with open (project_json_path , 'r' ) as f :
1218- project_config = json .load (f )
1219-
1220- # GPIO config is stored under project.gpio_config
1221- project_data = project_config .get ('project' , {})
1222- gpio_configs = project_data .get ('gpio_config' , {})
1223- if not gpio_configs :
1224- console .print ("[yellow]No GPIO configuration found in project.json[/yellow]" )
1225- console .print ("[dim]Run 'cf gpio-config' to configure GPIOs.[/dim]" )
1226- return
1227-
1228- # Detect project type
1229- project_type = project_data .get ('type' )
1230- if not project_type :
1231- project_type = detect_project_type (project_root )
1232-
1233- # Determine GPIO range based on project type
1234- if project_type == 'caravan' :
1235- user_gpio_range = list (range (0 , 32 ))
1236- gpio_label = "Caravan"
1237- else :
1238- user_gpio_range = list (range (5 , 38 ))
1239- gpio_label = "Caravel"
1240-
1241- user_to_real_map = {g : g for g in user_gpio_range }
1242-
1243- # Convert string keys back to int if needed
1244- gpio_configs_int = {}
1245- for k , v in gpio_configs .items ():
1246- try :
1247- gpio_configs_int [int (k )] = v
1248- except (ValueError , TypeError ):
1249- gpio_configs_int [k ] = v
1250-
1251- def find_mode_key (mode_value ):
1252- """Find the mode key for a given mode value (handles hex values)."""
1253- if not mode_value :
1254- return None
1255- # First, try to convert hex to mode constant name
1256- mode_name = GPIO_HEX_TO_MODE .get (mode_value , mode_value )
1257- # Then find the short key for that mode constant
1258- for key , name in GPIO_MODES .items ():
1259- if name == mode_name and key != "invalid" :
1260- return key
1261- return None
1262-
1263- def format_gpio_ranges (gpio_list ):
1264- """Convert [5,6,7,10,11,15] to '5-7, 10-11, 15'."""
1265- if not gpio_list :
1266- return "-"
1267- gpio_list = sorted (gpio_list )
1268- ranges = []
1269- start = gpio_list [0 ]
1270- end = start
1271- for g in gpio_list [1 :]:
1272- if g == end + 1 :
1273- end = g
1274- else :
1275- ranges .append (f"{ start } -{ end } " if start != end else str (start ))
1276- start = end = g
1277- ranges .append (f"{ start } -{ end } " if start != end else str (start ))
1278- return ", " .join (ranges )
1279-
1280- # Group by mode
1281- mode_groups = {}
1282- for user_gpio , real_gpio in user_to_real_map .items ():
1283- mode_value = gpio_configs_int .get (real_gpio )
1284- mode_key = find_mode_key (mode_value ) if mode_value else None
1285- if mode_key not in mode_groups :
1286- mode_groups [mode_key ] = []
1287- mode_groups [mode_key ].append (user_gpio )
1288-
1289- console .print (f"\n [bold cyan]GPIO Configuration ({ gpio_label } )[/bold cyan]\n " )
1290-
1291- table = Table (show_header = True , header_style = "bold" , box = None , padding = (0 , 2 ))
1292- table .add_column ("Mode" , style = "cyan" , width = 24 )
1293- table .add_column ("Count" , justify = "right" , width = 6 )
1294- table .add_column ("GPIOs" )
1295-
1296- # Sort by count (most common first)
1297- for mode_key in sorted (mode_groups .keys (), key = lambda k : - len (mode_groups [k ])):
1298- gpios = mode_groups [mode_key ]
1299- display_name = mode_key if mode_key else "[red]unconfigured[/red]"
1300- style = ""
1301- if mode_key :
1302- if "output" in mode_key : style = "[green]"
1303- elif "input" in mode_key : style = "[cyan]"
1304- elif "bidirectional" in mode_key : style = "[yellow]"
1305- elif "analog" in mode_key : style = "[magenta]"
1306- display_name = f"{ style } { mode_key } [/]"
1307- table .add_row (display_name , str (len (gpios )), format_gpio_ranges (gpios ))
1308-
1309- console .print (table )
1310- console .print ()
1311-
1312-
13131213@main .command ('push' )
13141214@click .option ('--project-root' , required = False , type = click .Path (exists = True , file_okay = False ), help = 'Path to the local ChipFoundry project directory (defaults to current directory if .cf/project.json exists).' )
13151215@click .option ('--sftp-host' , default = DEFAULT_SFTP_HOST , show_default = True , help = 'SFTP server hostname.' )
@@ -2608,12 +2508,10 @@ def maybe_abort_no_space(err, step_label):
26082508def harden (macro , project_root , list_designs , tag , pdk , use_nix , use_docker , dry_run ):
26092509 """Harden a macro using LibreLane (OpenLane 2).
26102510
2611- If no macro is specified, lists all available macros.
2612-
26132511 Examples:
2614- cf harden # List available macros
26152512 cf harden user_proj_example # Harden a specific macro
26162513 cf harden user_project_wrapper
2514+ cf harden --list # List available macros
26172515 """
26182516 from datetime import datetime
26192517
@@ -2641,13 +2539,17 @@ def harden(macro, project_root, list_designs, tag, pdk, use_nix, use_docker, dry
26412539 console .print ("[yellow]Run 'cf setup' first to install OpenLane[/yellow]" )
26422540 return
26432541
2644- # If no macro specified, default to listing available macros
2542+ # If no macro specified, show prompt with available macros
2543+ no_macro_specified = not macro and not list_designs
26452544 if not macro :
26462545 list_designs = True
26472546
26482547 # List designs if requested (or if no macro specified)
26492548 if list_designs :
2650- console .print ("[bold cyan]Available macros:[/bold cyan]" )
2549+ if no_macro_specified :
2550+ console .print ("[yellow]Please specify a macro from this list:[/yellow]" )
2551+ else :
2552+ console .print ("[bold cyan]Available macros:[/bold cyan]" )
26512553 designs = [d .name for d in openlane_dir .iterdir () if d .is_dir () and ((d / 'config.json' ).exists () or (d / 'config.yaml' ).exists () or (d / 'config.tcl' ).exists ())]
26522554 if designs :
26532555 for design in sorted (designs ):
0 commit comments