chipfoundry-cli 1.2.9__tar.gz → 1.2.11__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {chipfoundry_cli-1.2.9 → chipfoundry_cli-1.2.11}/PKG-INFO +1 -1
- {chipfoundry_cli-1.2.9 → chipfoundry_cli-1.2.11}/chipfoundry_cli/main.py +44 -31
- {chipfoundry_cli-1.2.9 → chipfoundry_cli-1.2.11}/pyproject.toml +2 -2
- {chipfoundry_cli-1.2.9 → chipfoundry_cli-1.2.11}/LICENSE +0 -0
- {chipfoundry_cli-1.2.9 → chipfoundry_cli-1.2.11}/README.md +0 -0
- {chipfoundry_cli-1.2.9 → chipfoundry_cli-1.2.11}/chipfoundry_cli/__init__.py +0 -0
- {chipfoundry_cli-1.2.9 → chipfoundry_cli-1.2.11}/chipfoundry_cli/utils.py +0 -0
|
@@ -7,7 +7,7 @@ from chipfoundry_cli.utils import (
|
|
|
7
7
|
open_html_in_browser, download_with_progress, update_repo_files,
|
|
8
8
|
fetch_versions_from_upstream, parse_user_defines_v, update_user_defines_v,
|
|
9
9
|
get_gpio_config_from_project_json, save_gpio_config_to_project_json,
|
|
10
|
-
GPIO_MODES, GPIO_MODE_DESCRIPTIONS
|
|
10
|
+
GPIO_MODES, GPIO_MODE_DESCRIPTIONS, GPIO_HEX_TO_MODE
|
|
11
11
|
)
|
|
12
12
|
import os
|
|
13
13
|
from pathlib import Path
|
|
@@ -350,7 +350,8 @@ def init(project_root):
|
|
|
350
350
|
|
|
351
351
|
@main.command('gpio-config')
|
|
352
352
|
@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
|
-
|
|
353
|
+
@click.option('--view', is_flag=True, help='Display current GPIO configuration summary without editing.')
|
|
354
|
+
def gpio_config(project_root, view):
|
|
354
355
|
"""Configure GPIO settings interactively and save to project config and user_defines.v."""
|
|
355
356
|
if not project_root:
|
|
356
357
|
project_root = os.getcwd()
|
|
@@ -527,7 +528,7 @@ def gpio_config(project_root):
|
|
|
527
528
|
table = Table(show_header=True, header_style="bold", box=None, padding=(0, 2))
|
|
528
529
|
table.add_column("Mode", style="cyan", width=24)
|
|
529
530
|
table.add_column("Count", justify="right", width=6)
|
|
530
|
-
table.add_column("GPIOs"
|
|
531
|
+
table.add_column("GPIOs")
|
|
531
532
|
|
|
532
533
|
# Sort by count (most common first)
|
|
533
534
|
for mode_key in sorted(mode_groups.keys(), key=lambda k: -len(mode_groups[k])):
|
|
@@ -547,6 +548,17 @@ def gpio_config(project_root):
|
|
|
547
548
|
# Initialize gpio_configs
|
|
548
549
|
gpio_configs = existing_configs.copy() if existing_configs else {}
|
|
549
550
|
|
|
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
|
+
|
|
550
562
|
# ========================
|
|
551
563
|
# HEADER
|
|
552
564
|
# ========================
|
|
@@ -576,7 +588,7 @@ def gpio_config(project_root):
|
|
|
576
588
|
if not mode_key:
|
|
577
589
|
return "red"
|
|
578
590
|
elif "output" in mode_key:
|
|
579
|
-
return "
|
|
591
|
+
return "ansi_bright_green"
|
|
580
592
|
elif "input" in mode_key:
|
|
581
593
|
return "cyan"
|
|
582
594
|
elif "bidirectional" in mode_key:
|
|
@@ -838,7 +850,7 @@ def gpio_config(project_root):
|
|
|
838
850
|
class GPIOGridApp(App):
|
|
839
851
|
"""Textual app for GPIO grid configuration."""
|
|
840
852
|
|
|
841
|
-
GRID_COLS =
|
|
853
|
+
GRID_COLS = 6 # Number of columns in the grid
|
|
842
854
|
|
|
843
855
|
CSS = """
|
|
844
856
|
Screen {
|
|
@@ -864,21 +876,21 @@ def gpio_config(project_root):
|
|
|
864
876
|
}
|
|
865
877
|
|
|
866
878
|
#gpio-grid {
|
|
867
|
-
grid-size:
|
|
868
|
-
grid-gutter:
|
|
869
|
-
padding:
|
|
879
|
+
grid-size: 6;
|
|
880
|
+
grid-gutter: 0;
|
|
881
|
+
padding: 0;
|
|
870
882
|
height: auto;
|
|
871
883
|
width: 100%;
|
|
872
884
|
}
|
|
873
885
|
|
|
874
886
|
GPIOButton {
|
|
875
887
|
width: 1fr;
|
|
876
|
-
min-width:
|
|
888
|
+
min-width: 20;
|
|
877
889
|
height: 4;
|
|
878
890
|
text-align: center;
|
|
879
|
-
border: solid
|
|
891
|
+
border: solid grey;
|
|
880
892
|
content-align: center middle;
|
|
881
|
-
padding: 0
|
|
893
|
+
padding: 0;
|
|
882
894
|
}
|
|
883
895
|
|
|
884
896
|
GPIOButton.current {
|
|
@@ -1089,10 +1101,9 @@ def gpio_config(project_root):
|
|
|
1089
1101
|
"""Open mode selection for selected GPIOs."""
|
|
1090
1102
|
selected = self._get_selected_gpios()
|
|
1091
1103
|
if not selected:
|
|
1092
|
-
# If nothing selected, use the
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
selected = [focused.gpio_num]
|
|
1104
|
+
# If nothing selected, use the current one (where cursor is)
|
|
1105
|
+
if 0 <= self.current_index < len(self.gpio_list):
|
|
1106
|
+
selected = [self.gpio_list[self.current_index]]
|
|
1096
1107
|
|
|
1097
1108
|
if selected:
|
|
1098
1109
|
self.push_screen(ModeSelectScreen(selected), self._apply_mode)
|
|
@@ -1102,9 +1113,9 @@ def gpio_config(project_root):
|
|
|
1102
1113
|
if mode_key:
|
|
1103
1114
|
selected = self._get_selected_gpios()
|
|
1104
1115
|
if not selected:
|
|
1105
|
-
|
|
1106
|
-
if
|
|
1107
|
-
selected = [
|
|
1116
|
+
# Use current one if nothing selected
|
|
1117
|
+
if 0 <= self.current_index < len(self.gpio_list):
|
|
1118
|
+
selected = [self.gpio_list[self.current_index]]
|
|
1108
1119
|
|
|
1109
1120
|
for gpio_num in selected:
|
|
1110
1121
|
real_gpio = self.user_to_real_map[gpio_num]
|
|
@@ -1198,6 +1209,7 @@ def gpio_config(project_root):
|
|
|
1198
1209
|
except Exception as e:
|
|
1199
1210
|
console.print(f"[red]Error updating user_defines.v: {e}[/red]")
|
|
1200
1211
|
|
|
1212
|
+
|
|
1201
1213
|
@main.command('push')
|
|
1202
1214
|
@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).')
|
|
1203
1215
|
@click.option('--sftp-host', default=DEFAULT_SFTP_HOST, show_default=True, help='SFTP server hostname.')
|
|
@@ -2497,9 +2509,9 @@ def harden(macro, project_root, list_designs, tag, pdk, use_nix, use_docker, dry
|
|
|
2497
2509
|
"""Harden a macro using LibreLane (OpenLane 2).
|
|
2498
2510
|
|
|
2499
2511
|
Examples:
|
|
2500
|
-
cf harden user_proj_example
|
|
2512
|
+
cf harden user_proj_example # Harden a specific macro
|
|
2501
2513
|
cf harden user_project_wrapper
|
|
2502
|
-
cf harden --list
|
|
2514
|
+
cf harden --list # List available macros
|
|
2503
2515
|
"""
|
|
2504
2516
|
from datetime import datetime
|
|
2505
2517
|
|
|
@@ -2512,8 +2524,8 @@ def harden(macro, project_root, list_designs, tag, pdk, use_nix, use_docker, dry
|
|
|
2512
2524
|
|
|
2513
2525
|
project_root_path = Path(project_root)
|
|
2514
2526
|
|
|
2515
|
-
# Check if project is initialized (skip check for --list, allow graceful return)
|
|
2516
|
-
if not list_designs:
|
|
2527
|
+
# Check if project is initialized (skip check for --list or when no macro specified, allow graceful return)
|
|
2528
|
+
if not list_designs and macro:
|
|
2517
2529
|
if not check_project_initialized(project_root_path, 'harden', dry_run=dry_run, allow_graceful=True):
|
|
2518
2530
|
console.print(f"[red]✗[/red] Project not initialized. Please run 'cf init' first.")
|
|
2519
2531
|
console.print("[yellow]Run 'cf setup' first to install OpenLane[/yellow]")
|
|
@@ -2527,9 +2539,17 @@ def harden(macro, project_root, list_designs, tag, pdk, use_nix, use_docker, dry
|
|
|
2527
2539
|
console.print("[yellow]Run 'cf setup' first to install OpenLane[/yellow]")
|
|
2528
2540
|
return
|
|
2529
2541
|
|
|
2530
|
-
#
|
|
2542
|
+
# If no macro specified, show prompt with available macros
|
|
2543
|
+
no_macro_specified = not macro and not list_designs
|
|
2544
|
+
if not macro:
|
|
2545
|
+
list_designs = True
|
|
2546
|
+
|
|
2547
|
+
# List designs if requested (or if no macro specified)
|
|
2531
2548
|
if list_designs:
|
|
2532
|
-
|
|
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]")
|
|
2533
2553
|
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())]
|
|
2534
2554
|
if designs:
|
|
2535
2555
|
for design in sorted(designs):
|
|
@@ -2544,13 +2564,6 @@ def harden(macro, project_root, list_designs, tag, pdk, use_nix, use_docker, dry
|
|
|
2544
2564
|
console.print("[yellow]No macros found in openlane/[/yellow]")
|
|
2545
2565
|
return
|
|
2546
2566
|
|
|
2547
|
-
# Macro is required if not listing
|
|
2548
|
-
if not macro:
|
|
2549
|
-
console.print("[red]✗[/red] Error: MACRO argument is required")
|
|
2550
|
-
console.print("[yellow]Usage:[/yellow] cf harden <macro>")
|
|
2551
|
-
console.print("[yellow] [/yellow] cf harden --list")
|
|
2552
|
-
return
|
|
2553
|
-
|
|
2554
2567
|
# Check if macro exists
|
|
2555
2568
|
macro_dir = openlane_dir / macro
|
|
2556
2569
|
if not macro_dir.exists():
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "chipfoundry-cli"
|
|
3
|
-
version = "1.2.
|
|
3
|
+
version = "1.2.11"
|
|
4
4
|
description = "CLI tool to automate ChipFoundry project submission to SFTP server"
|
|
5
5
|
authors = ["ChipFoundry <marwan.abbas@chipfoundry.io>"]
|
|
6
6
|
readme = "README.md"
|
|
@@ -18,7 +18,7 @@ toml = ">=0.10,<1.0"
|
|
|
18
18
|
httpx = ">=0.24.0,<1.0"
|
|
19
19
|
textual = ">=0.40.0,<1"
|
|
20
20
|
|
|
21
|
-
[tool.poetry.dev
|
|
21
|
+
[tool.poetry.group.dev.dependencies]
|
|
22
22
|
wheel = "*"
|
|
23
23
|
black = ">=24.4.0,<25"
|
|
24
24
|
flake8 = ">=4"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|