mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-04 22:32:36 +00:00
feat: add support for GF180 and SKY130 PDKs with corresponding warnings and simulation files
- Introduced new JSON files for warnings generated by Icarus Verilog, Verilator, and Yosys for both GF180 and SKY130 PDKs. - Updated the build requirements to include necessary packages for handling JSON data. - Modified RTL filelists to use generated files for GF180 and SKY130 standard-cell models. - Enhanced the Iverilog makefile to generate filelists dynamically based on the selected PDK. - Implemented a Python script to generate Iverilog filelists, accommodating both GF180 and SKY130 technologies. - Added behavioral definitions for GF180 UDPs and a tri-state buffer for netlist simulations. - Updated Yosys synthesis scripts to handle new PDKs and ensure proper tie cell mapping. - Extended regression scripts to support PDK-specific commands for GF180 and SKY130. - Added tests to verify that PDK-specific regression commands cover firmware, RTL, and netlist simulations.
This commit is contained in:
37 files changed
+851
-123
No files matched your search
+3
-2
@@ -4,8 +4,9 @@ This directory owns repository automation metadata: pull-request templates,
|
||||
CODEOWNERS, Dependabot configuration, reusable actions, and CI/release
|
||||
workflows.
|
||||
|
||||
`workflows/quality.yml` runs the fast quality gate. `workflows/regression.yml`
|
||||
and `workflows/nightly.yml` call the reusable regression workflow;
|
||||
`workflows/quality.yml` runs the fast quality gate. `workflows/regression.yml`,
|
||||
`workflows/regression-gf180.yml`, `workflows/regression-sky130.yml`, and
|
||||
`workflows/nightly.yml` call the reusable regression workflow;
|
||||
`workflows/release.yml` packages tagged releases. `actions/locked-tools/`
|
||||
installs the locked open-source tools used by CI.
|
||||
|
||||
|
||||
@@ -7,6 +7,14 @@ on:
|
||||
description: Regression suite from scripts/regress.py
|
||||
required: true
|
||||
type: string
|
||||
pdk:
|
||||
description: PDK matrix selected by scripts/regress.py
|
||||
required: true
|
||||
type: string
|
||||
profile:
|
||||
description: Primary profile used for setup and environment checks
|
||||
required: true
|
||||
type: string
|
||||
retention_days:
|
||||
description: Report artifact retention
|
||||
required: false
|
||||
@@ -33,6 +41,8 @@ jobs:
|
||||
app/coremark/coremark-main
|
||||
app/fatfs/ff16
|
||||
pdk/IHP-Open-PDK
|
||||
pdk/gf180mcu-pdk
|
||||
pdk/skywater-pdk
|
||||
rtl/managed/clusterip/archinfo
|
||||
rtl/managed/clusterip/clint
|
||||
rtl/managed/clusterip/common
|
||||
@@ -50,8 +60,9 @@ jobs:
|
||||
rtl/managed/clusterip/wdg
|
||||
rtl/managed/third_party
|
||||
rtl/managed/mpw
|
||||
.cache/retrosoc/pdk
|
||||
.cache/retrosoc/stamps
|
||||
key: sources-${{ runner.os }}-${{ hashFiles('config/dependencies.lock.json') }}
|
||||
key: sources-${{ inputs.pdk }}-${{ runner.os }}-${{ hashFiles('config/dependencies.lock.json') }}
|
||||
|
||||
- name: Restore locked toolchains
|
||||
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
||||
@@ -79,16 +90,20 @@ jobs:
|
||||
tools: verilator sv2v iverilog yosys opensta riscv_gnu
|
||||
|
||||
- name: Set up locked source dependencies
|
||||
run: make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk setup
|
||||
run: make CONFIG=${{ inputs.profile }} setup
|
||||
|
||||
- name: Check environment
|
||||
run: |
|
||||
make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk \
|
||||
SIMU=IVERILOG SYNTH=YOSYS STA=OPENSTA doctor
|
||||
make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk SIMU=VERILATOR doctor
|
||||
make CONFIG=${{ inputs.profile }} \
|
||||
SIMU=IVERILOG SYNTH=YOSYS STA=NONE doctor
|
||||
make CONFIG=${{ inputs.profile }} SIMU=VERILATOR doctor
|
||||
|
||||
- name: Check IHP130 timing environment
|
||||
if: inputs.pdk == 'IHP130'
|
||||
run: make CONFIG=${{ inputs.profile }} STA=OPENSTA doctor
|
||||
|
||||
- name: Run ${{ inputs.suite }} regression
|
||||
run: python3 scripts/regress.py --root . --suite "${{ inputs.suite }}"
|
||||
run: python3 scripts/regress.py --root . --suite "${{ inputs.suite }}" --pdk "${{ inputs.pdk }}"
|
||||
|
||||
- name: Upload reports and structured results
|
||||
if: always()
|
||||
|
||||
@@ -17,4 +17,6 @@ jobs:
|
||||
uses: ./.github/workflows/_regression.yml
|
||||
with:
|
||||
suite: nightly
|
||||
pdk: IHP130
|
||||
profile: configs/ci/hazard3-rv32im-ihp130.mk
|
||||
retention_days: 90
|
||||
@@ -77,5 +77,7 @@ jobs:
|
||||
|
||||
- name: Validate regression definitions
|
||||
run: |
|
||||
python3 scripts/regress.py --root . --suite pr --dry-run
|
||||
python3 scripts/regress.py --root . --suite nightly --dry-run
|
||||
python3 scripts/regress.py --root . --suite pr --pdk IHP130 --dry-run
|
||||
python3 scripts/regress.py --root . --suite pr --pdk GF180 --dry-run
|
||||
python3 scripts/regress.py --root . --suite pr --pdk SKY130 --dry-run
|
||||
python3 scripts/regress.py --root . --suite nightly --pdk IHP130 --dry-run
|
||||
@@ -0,0 +1,24 @@
|
||||
name: regression-gf180
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, dev]
|
||||
pull_request:
|
||||
branches: [main, dev]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: regression-gf180-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
verified-open-source-flows:
|
||||
uses: ./.github/workflows/_regression.yml
|
||||
with:
|
||||
suite: pr
|
||||
pdk: GF180
|
||||
profile: configs/ci/hazard3-rv32im-gf180.mk
|
||||
retention_days: 30
|
||||
@@ -0,0 +1,24 @@
|
||||
name: regression-sky130
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, dev]
|
||||
pull_request:
|
||||
branches: [main, dev]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: regression-sky130-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
verified-open-source-flows:
|
||||
uses: ./.github/workflows/_regression.yml
|
||||
with:
|
||||
suite: pr
|
||||
pdk: SKY130
|
||||
profile: configs/ci/hazard3-rv32im-sky130.mk
|
||||
retention_days: 30
|
||||
@@ -19,4 +19,6 @@ jobs:
|
||||
uses: ./.github/workflows/_regression.yml
|
||||
with:
|
||||
suite: pr
|
||||
pdk: IHP130
|
||||
profile: configs/ci/hazard3-rv32im-ihp130.mk
|
||||
retention_days: 30
|
||||
@@ -117,8 +117,8 @@ $(call validate_value,APP,$(VALID_APP))
|
||||
$(call validate_value,LINK_TYPE,$(VALID_LINK_TYPE))
|
||||
|
||||
ifeq ($(SYNTH),YOSYS)
|
||||
ifeq ($(filter $(PDK),IHP130 ICS55),)
|
||||
$(error Yosys synthesis supports PDK=IHP130 or PDK=ICS55, not PDK=$(PDK))
|
||||
ifeq ($(filter $(PDK),IHP130 ICS55 GF180 SKY130),)
|
||||
$(error Yosys synthesis does not support PDK=$(PDK))
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -314,7 +314,9 @@ package: $(MPW_VARIANT_STAMP) $(FILELIST_STAMP) manifest
|
||||
--variant-root $(VARIANT_ROOT) --output-dir $(ROOT_PATH)/dist/$(VARIANT_ID)
|
||||
|
||||
regress-pr:
|
||||
python3 $(ROOT_PATH)/scripts/regress.py --root $(ROOT_PATH) --suite pr
|
||||
python3 $(ROOT_PATH)/scripts/regress.py --root $(ROOT_PATH) --suite pr --pdk IHP130
|
||||
python3 $(ROOT_PATH)/scripts/regress.py --root $(ROOT_PATH) --suite pr --pdk GF180
|
||||
python3 $(ROOT_PATH)/scripts/regress.py --root $(ROOT_PATH) --suite pr --pdk SKY130
|
||||
|
||||
regress-nightly:
|
||||
python3 $(ROOT_PATH)/scripts/regress.py --root $(ROOT_PATH) --suite nightly
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
# retroSoC
|
||||
|
||||
[](https://github.com/retroSoC/retroSoC/actions/workflows/quality.yml)
|
||||
[](https://github.com/retroSoC/retroSoC/actions/workflows/regression.yml)
|
||||
[](https://github.com/retroSoC/retroSoC/actions/workflows/regression.yml)
|
||||
[](https://github.com/retroSoC/retroSoC/actions/workflows/regression-gf180.yml)
|
||||
[](https://github.com/retroSoC/retroSoC/actions/workflows/regression-sky130.yml)
|
||||
[](https://github.com/retroSoC/retroSoC/actions/workflows/nightly.yml)
|
||||
|
||||
retroSoC is a fully open-source RISC-V SoC project. The repository brings together
|
||||
@@ -12,8 +14,8 @@ under the [Mulan Permissive Software License, Version 2](LICENSE).
|
||||
## Highlights
|
||||
|
||||
- Selectable RV32IM CPU configurations using HAZARD3, PicoRV32, or MDD cores.
|
||||
- Configurable IHP130 and ICS55 implementation targets, with open-source IHP130 flows
|
||||
available in CI and ICS55 flows intended for a configured cluster environment.
|
||||
- Configurable GF180, SKY130, IHP130, and ICS55 implementation targets. GF180, SKY130,
|
||||
and IHP130 have open-source CI coverage; ICS55 remains a configured cluster target.
|
||||
- A memory-mapped peripheral subsystem with GPIO, UART, timers, PWM, I2C, I2S, PS2,
|
||||
1-Wire, SPI/QSPI, SDIO, PSRAM/OPI-PSRAM, SDRAM, DMA, LCD, RTC, watchdog, RNG, and CRC
|
||||
support. Available interfaces depend on the selected SoC configuration.
|
||||
@@ -46,6 +48,8 @@ application, linker layout, and optional features as one reproducible configurat
|
||||
| Profile | Core / ISA | Application | Coverage |
|
||||
| --- | --- | --- | --- |
|
||||
| [`configs/ci/hazard3-rv32im-ihp130.mk`](configs/ci/hazard3-rv32im-ihp130.mk) | HAZARD3 / RV32IM | `bringup` | Pull-request open-source regression: firmware, Verilator, Icarus, Yosys, Icarus netlist simulation, and OpenSTA. |
|
||||
| [`configs/ci/hazard3-rv32im-gf180.mk`](configs/ci/hazard3-rv32im-gf180.mk) | HAZARD3 / RV32IM | `bringup` | Pull-request firmware, RTL simulation, Yosys, and Icarus netlist coverage. |
|
||||
| [`configs/ci/hazard3-rv32im-sky130.mk`](configs/ci/hazard3-rv32im-sky130.mk) | HAZARD3 / RV32IM | `bringup` | Pull-request firmware, RTL simulation, Yosys, and Icarus netlist coverage. |
|
||||
| [`configs/ci/hazard3-rv32im-ihp130-shell.mk`](configs/ci/hazard3-rv32im-ihp130-shell.mk) | HAZARD3 / RV32IM | `shell` | Pull-request firmware build with CSR support enabled. |
|
||||
| [`configs/ci/hazard3-rv32im-ihp130-ip-mdd.mk`](configs/ci/hazard3-rv32im-ihp130-ip-mdd.mk) | HAZARD3 / RV32IM + MDD IP | `bringup` | Pull-request firmware and Verilator integration coverage for the user-IP GPIO ownership path. |
|
||||
| [`configs/ci/hazard3-rv32im-ihp130-ip-mdd-shell.mk`](configs/ci/hazard3-rv32im-ihp130-ip-mdd-shell.mk) | HAZARD3 / RV32IM + MDD IP | `shell` | Pull-request firmware compilation coverage for the user-IP software command. |
|
||||
@@ -119,6 +123,8 @@ make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk SIMU=IVERILOG \
|
||||
| Yosys synthesis | `make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk SYNTH=YOSYS synth` |
|
||||
| Icarus netlist simulation after synthesis | `make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk SIMU=IVERILOG netsim` |
|
||||
| OpenSTA timing analysis after synthesis | `make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk STA=OPENSTA sta` |
|
||||
`make regress-pr` runs the supported IHP130, GF180, and SKY130 PR matrices in
|
||||
sequence. IHP130 additionally covers OpenSTA timing analysis.
|
||||
| Pull-request regression suite | `make regress-pr` |
|
||||
| Nightly regression suite | `make regress-nightly` |
|
||||
| Format C, Makefile, and RTL sources | `make format` |
|
||||
|
||||
@@ -45,6 +45,20 @@
|
||||
"recursive": true,
|
||||
"license": "NOASSERTION"
|
||||
},
|
||||
"pdk_gf180": {
|
||||
"url": "https://github.com/google/gf180mcu-pdk.git",
|
||||
"revision": "de3240d7529a6970437ac3344820aaae7839f215",
|
||||
"destination": "pdk/gf180mcu-pdk",
|
||||
"recursive": true,
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"pdk_sky130": {
|
||||
"url": "https://github.com/google/skywater-pdk.git",
|
||||
"revision": "7198cf647113f56041e02abf3eb623692820c5e1",
|
||||
"destination": "pdk/skywater-pdk",
|
||||
"recursive": true,
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"cluster_archinfo": {"url": "https://github.com/retroSoC/archinfo.git", "revision": "d65dd13c83a1176668bf5178004814a1551bf6ba", "destination": "rtl/managed/clusterip/archinfo", "license": "NOASSERTION"},
|
||||
"cluster_clint": {"url": "https://github.com/retroSoC/clint.git", "revision": "ce49f1a5501c0a9f18c0e3f358417648f3f2fb18", "destination": "rtl/managed/clusterip/clint", "license": "NOASSERTION"},
|
||||
"cluster_common": {"url": "https://github.com/retroSoC/common.git", "revision": "d9921eb05160be873aebc46bb2f820bee2c7eebc", "destination": "rtl/managed/clusterip/common", "license": "NOASSERTION"},
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
SOC := MINI
|
||||
CORE := HAZARD3
|
||||
IP := NONE
|
||||
PDK := GF180
|
||||
HAVE_PLL := NO
|
||||
HAVE_SRAM_IF := NO
|
||||
HAVE_SRAM_MACRO := NO
|
||||
HAVE_SVA := NO
|
||||
ISA := RV32IM
|
||||
HAVE_CSR := NO
|
||||
APP := bringup
|
||||
LINK_TYPE := ld2_psram
|
||||
@@ -0,0 +1,12 @@
|
||||
SOC := MINI
|
||||
CORE := HAZARD3
|
||||
IP := NONE
|
||||
PDK := SKY130
|
||||
HAVE_PLL := NO
|
||||
HAVE_SRAM_IF := NO
|
||||
HAVE_SRAM_MACRO := NO
|
||||
HAVE_SVA := NO
|
||||
ISA := RV32IM
|
||||
HAVE_CSR := NO
|
||||
APP := bringup
|
||||
LINK_TYPE := ld2_psram
|
||||
@@ -5,10 +5,16 @@
|
||||
| Tier | Profile | Automated coverage |
|
||||
| --- | --- | --- |
|
||||
| Pull request | `configs/ci/hazard3-rv32im-ihp130.mk` | firmware, Verilator, Icarus, Yosys, netlist Icarus, OpenSTA |
|
||||
| Pull request | `configs/ci/hazard3-rv32im-gf180.mk` | firmware, Verilator, Icarus, Yosys, netlist Icarus |
|
||||
| Pull request | `configs/ci/hazard3-rv32im-sky130.mk` | firmware, Verilator, Icarus, Yosys, netlist Icarus |
|
||||
| Pull request | `configs/ci/mdd-rv32im-ihp130.mk` | firmware and Verilator |
|
||||
| Nightly | `configs/nightly/picorv32-rv32im-ihp130.mk` | firmware, Verilator, and Icarus |
|
||||
| Cluster | `configs/cluster/hazard3-ics55.mk` | configuration only; run with site PDK/tool access |
|
||||
|
||||
OpenSTA timing signoff remains IHP130-only. GF180 and SKY130 use their TT standard-cell libraries
|
||||
for synthesis and functional netlist simulation, but do not publish an STA result until their
|
||||
corner, SDC, and frequency policy have been independently qualified.
|
||||
|
||||
VCS and ICS55 flows remain cluster-only because public runners do not have the licensed simulator or
|
||||
the validated site environment. They use the same variant layout, manifests, result JSON, warning
|
||||
scanner, and cleanup rules.
|
||||
|
||||
@@ -9,3 +9,14 @@ Use the dependency lock and PDK setup targets to acquire or update managed
|
||||
inputs. Do not reformat, patch, or delete vendor content as part of unrelated
|
||||
work. PDK changes require the affected synthesis, timing, physical-design, or
|
||||
FPGA validation flow and the ownership review defined by `.github/CODEOWNERS`.
|
||||
|
||||
The supported CI PDKs are IHP130, GF180, and SKY130. GF180 assembles its
|
||||
locked `gf180mcu_fd_sc_mcu7t5v0` TT 5.0 V cell fragments, and SKY130 generates
|
||||
its `sky130_fd_sc_hd` TT 1.8 V Liberty model from locked upstream JSON files.
|
||||
Both derived Liberty files are stored below `.cache/retrosoc/pdk/` and are not
|
||||
committed. OpenSTA timing remains IHP130-only.
|
||||
|
||||
The GF180 and SKY130 CI flows synth the digital core and run functional
|
||||
standard-cell netlist simulation. Physical pad-ring integration remains a
|
||||
technology-specific signoff task and is not represented by the generic SoC pad
|
||||
wrappers.
|
||||
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
sys.path.insert(0, str(ROOT))
|
||||
from scripts.setup_helpers import atomic_write # noqa: E402
|
||||
|
||||
|
||||
CORNER = "tt_025C_5v00"
|
||||
LIBRARY = "gf180mcu_fd_sc_mcu7t5v0"
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Assemble the GF180 standard-cell Liberty model from locked PDK fragments"
|
||||
)
|
||||
parser.add_argument("--source", type=Path, required=True)
|
||||
parser.add_argument("--output-dir", type=Path, required=True)
|
||||
parser.add_argument("--revision", required=True)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = parse_args()
|
||||
source = args.source.resolve()
|
||||
library_dir = source / "libraries" / LIBRARY / "latest"
|
||||
header = library_dir / "liberty" / f"{LIBRARY}__{CORNER}.lib"
|
||||
cells_dir = library_dir / "cells"
|
||||
cell_libraries = sorted(cells_dir.glob(f"*/*__{CORNER}.lib"))
|
||||
if not header.is_file() or not cell_libraries:
|
||||
raise FileNotFoundError(f"missing GF180 Liberty inputs below {library_dir}")
|
||||
|
||||
output_dir = args.output_dir.resolve()
|
||||
output = output_dir / f"{LIBRARY}__{CORNER}.lib"
|
||||
revision = output.with_suffix(output.suffix + ".revision")
|
||||
if (
|
||||
output.is_file()
|
||||
and revision.is_file()
|
||||
and revision.read_text(encoding="utf-8") == f"{args.revision}\n"
|
||||
):
|
||||
print(f"GF180 Liberty is ready: {output}")
|
||||
return 0
|
||||
|
||||
prefix, separator, _ = header.read_text(encoding="utf-8").rpartition("\n}")
|
||||
if not separator:
|
||||
raise RuntimeError(f"GF180 Liberty header is malformed: {header}")
|
||||
cells = "\n\n".join(path.read_text(encoding="utf-8") for path in cell_libraries)
|
||||
atomic_write(output, f"{prefix}\n\n{cells}\n}}\n")
|
||||
atomic_write(revision, f"{args.revision}\n")
|
||||
print(f"generated GF180 Liberty: {output}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,82 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
sys.path.insert(0, str(ROOT))
|
||||
from scripts.setup_helpers import atomic_write # noqa: E402
|
||||
|
||||
|
||||
CORNER = "tt_025C_1v80"
|
||||
LIBRARY = "sky130_fd_sc_hd"
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Generate the SKY130 HD Liberty model from locked PDK JSON sources"
|
||||
)
|
||||
parser.add_argument("--source", type=Path, required=True)
|
||||
parser.add_argument("--output-dir", type=Path, required=True)
|
||||
parser.add_argument("--revision", required=True)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = parse_args()
|
||||
source = args.source.resolve()
|
||||
library_dir = source / "libraries" / LIBRARY / "latest"
|
||||
generator_dir = source / "scripts" / "python-skywater-pdk"
|
||||
required = (
|
||||
library_dir / "timing" / f"{LIBRARY}__common.lib.json",
|
||||
library_dir / "timing" / f"{LIBRARY}__{CORNER}.lib.json",
|
||||
generator_dir / "skywater_pdk" / "liberty.py",
|
||||
)
|
||||
missing = [str(path) for path in required if not path.is_file()]
|
||||
if missing:
|
||||
raise FileNotFoundError("missing SKY130 Liberty input(s): " + ", ".join(missing))
|
||||
|
||||
output_dir = args.output_dir.resolve()
|
||||
output = output_dir / f"{LIBRARY}__{CORNER}.lib"
|
||||
revision = output.with_suffix(output.suffix + ".revision")
|
||||
if (
|
||||
output.is_file()
|
||||
and revision.is_file()
|
||||
and revision.read_text(encoding="utf-8") == f"{args.revision}\n"
|
||||
):
|
||||
print(f"SKY130 Liberty is ready: {output}")
|
||||
return 0
|
||||
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
with tempfile.TemporaryDirectory(prefix="sky130-liberty-", dir=output_dir) as temporary:
|
||||
temporary_dir = Path(temporary)
|
||||
command = (
|
||||
sys.executable,
|
||||
"-m",
|
||||
"skywater_pdk.liberty",
|
||||
str(library_dir),
|
||||
CORNER,
|
||||
"--output_directory",
|
||||
str(temporary_dir),
|
||||
)
|
||||
print("+ " + " ".join(command))
|
||||
environment = os.environ.copy()
|
||||
environment["PYTHONPATH"] = str(generator_dir)
|
||||
subprocess.run(command, check=True, env=environment)
|
||||
generated = temporary_dir / output.name
|
||||
if not generated.is_file():
|
||||
raise RuntimeError(f"SKY130 Liberty generator did not create {generated}")
|
||||
atomic_write(output, generated.read_text(encoding="utf-8"))
|
||||
atomic_write(revision, f"{args.revision}\n")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
+39
-4
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
@@ -14,19 +15,53 @@ from scripts.setup_helpers import ensure_git_repo # noqa: E402
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description="Install pinned open PDKs")
|
||||
parser.add_argument("--update", action="store_true")
|
||||
parser.add_argument("--pdk", choices=("IHP130", "ICS55"), action="append")
|
||||
parser.add_argument("--pdk", choices=("IHP130", "ICS55", "GF180", "SKY130"), action="append")
|
||||
args = parser.parse_args()
|
||||
selected = args.pdk or ("IHP130", "ICS55")
|
||||
names = {"IHP130": "pdk_ihp130", "ICS55": "pdk_ics55"}
|
||||
selected = args.pdk or ("IHP130", "ICS55", "GF180", "SKY130")
|
||||
names = {
|
||||
"IHP130": "pdk_ihp130",
|
||||
"ICS55": "pdk_ics55",
|
||||
"GF180": "pdk_gf180",
|
||||
"SKY130": "pdk_sky130",
|
||||
}
|
||||
for name in (names[pdk] for pdk in selected):
|
||||
dependency = source(name)
|
||||
destination = ROOT / dependency["destination"]
|
||||
ensure_git_repo(
|
||||
dependency["url"],
|
||||
ROOT / dependency["destination"],
|
||||
destination,
|
||||
dependency["revision"],
|
||||
recursive=dependency.get("recursive", False),
|
||||
update=args.update,
|
||||
)
|
||||
if name == "pdk_gf180":
|
||||
subprocess.run(
|
||||
(
|
||||
sys.executable,
|
||||
str(ROOT / "pdk/generate_gf180_liberty.py"),
|
||||
"--source",
|
||||
str(destination),
|
||||
"--output-dir",
|
||||
str(ROOT / ".cache/retrosoc/pdk/gf180"),
|
||||
"--revision",
|
||||
dependency["revision"],
|
||||
),
|
||||
check=True,
|
||||
)
|
||||
elif name == "pdk_sky130":
|
||||
subprocess.run(
|
||||
(
|
||||
sys.executable,
|
||||
str(ROOT / "pdk/generate_sky130_liberty.py"),
|
||||
"--source",
|
||||
str(destination),
|
||||
"--output-dir",
|
||||
str(ROOT / ".cache/retrosoc/pdk/sky130"),
|
||||
"--revision",
|
||||
dependency["revision"],
|
||||
),
|
||||
check=True,
|
||||
)
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"entries": [
|
||||
{
|
||||
"count": 2,
|
||||
"example": "warning:Found both default and explicit timescale based delays. Use",
|
||||
"signature": "aee22756a35889cc"
|
||||
}
|
||||
],
|
||||
"profile": "hazard3-rv32im-gf180",
|
||||
"schema_version": 1,
|
||||
"tool": "iverilog"
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"entries": [
|
||||
{
|
||||
"count": 1,
|
||||
"example": "UNSIGNED:$ROOT/rtl/ip/native/storage/xpi.sv:<line>: Comparison is constant due to unsigned arithmetic",
|
||||
"signature": "010491867f065cec"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"example": "UNOPTFLAT:$ROOT/rtl/ip/native/storage/xpi.sv:<line>: Signal unoptimizable: Circular combinational logic: 'retrosoc_top.u_retrosoc_asic.u_xpi_if.io_di_i'",
|
||||
"signature": "411d9ab46fef9d7d"
|
||||
},
|
||||
{
|
||||
"count": 2,
|
||||
"example": "CMPCONST:$ROOT/rtl/ip/native/storage/spisd_write.sv:<line>: Comparison is constant due to limited range",
|
||||
"signature": "813090adc9f1e8a8"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"example": "UNSIGNED:$ROOT/rtl/mini/top/bus.sv:<line>: Comparison is constant due to unsigned arithmetic",
|
||||
"signature": "9f53ff454a8648a4"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"example": "WIDTHTRUNC:$ROOT/rtl/ip/native/storage/spisd_read.sv:<line>: Operator ASSIGNDLY expects 8 bits on the Assign RHS, but Assign RHS's REPLICATE generates 9 bits.",
|
||||
"signature": "c963ef155f9a032c"
|
||||
},
|
||||
{
|
||||
"count": 3,
|
||||
"example": "WIDTHTRUNC:$ROOT/rtl/ip/native/storage/spisd_write.sv:<line>: Bit extraction of var[7:0] requires 3 bit index, not 4 bits.",
|
||||
"signature": "ef9f314dab2ac31d"
|
||||
}
|
||||
],
|
||||
"profile": "hazard3-rv32im-gf180",
|
||||
"schema_version": 1,
|
||||
"tool": "verilator"
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"entries": [
|
||||
{
|
||||
"count": 1,
|
||||
"example": "warning:Wire hazard3_csr$retrosoc_asic.u_retrosoc.u_core_wrapper.u_hazard3_cpu_1port.core.csr_u.\\debug_mode is used but has no driver.",
|
||||
"signature": "1097d6b92f19e707"
|
||||
},
|
||||
{
|
||||
"count": 9,
|
||||
"example": "warning:Detected 6 multi-output cells (for example, \"gf180mcu_fd_sc_mcu7t5v0__addf_1\").",
|
||||
"signature": "44b9341f5ba5de06"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"example": "warning:asynchronous load value missing for variable '\\update_irq_reg_arrays.i'",
|
||||
"signature": "56c5f69398be8d7b"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"example": "warning:Wire hazard3_csr$retrosoc_asic.u_retrosoc.u_core_wrapper.u_hazard3_cpu_1port.core.csr_u.\\pending_dbg_resume_prev is used but has no driver.",
|
||||
"signature": "5bbc6025e51705ec"
|
||||
},
|
||||
{
|
||||
"count": 9,
|
||||
"example": "warning:The network is combinational (run \"fraig\" or \"fraig_sweep\").",
|
||||
"signature": "62cc5ee554312205"
|
||||
},
|
||||
{
|
||||
"count": 2,
|
||||
"example": "warning:asynchronous load value missing for variable '\\update_nonconst.prev'",
|
||||
"signature": "a30df20b98d49196"
|
||||
},
|
||||
{
|
||||
"count": 2,
|
||||
"example": "warning:asynchronous load value missing for variable '\\update_nonconst.nonconst'",
|
||||
"signature": "d35463a1de40c7b2"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"example": "warning:Wire hazard3_csr$retrosoc_asic.u_retrosoc.u_core_wrapper.u_hazard3_cpu_1port.core.csr_u.\\dbg_req_resume_prev is used but has no driver.",
|
||||
"signature": "ef03dcca25b39dcb"
|
||||
}
|
||||
],
|
||||
"profile": "hazard3-rv32im-gf180",
|
||||
"schema_version": 1,
|
||||
"tool": "yosys"
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"entries": [
|
||||
{
|
||||
"count": 2,
|
||||
"example": "warning:Found both default and explicit timescale based delays. Use",
|
||||
"signature": "aee22756a35889cc"
|
||||
}
|
||||
],
|
||||
"profile": "hazard3-rv32im-sky130",
|
||||
"schema_version": 1,
|
||||
"tool": "iverilog"
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"entries": [
|
||||
{
|
||||
"count": 1,
|
||||
"example": "UNSIGNED:$ROOT/rtl/ip/native/storage/xpi.sv:<line>: Comparison is constant due to unsigned arithmetic",
|
||||
"signature": "010491867f065cec"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"example": "UNOPTFLAT:$ROOT/rtl/ip/native/storage/xpi.sv:<line>: Signal unoptimizable: Circular combinational logic: 'retrosoc_top.u_retrosoc_asic.u_xpi_if.io_di_i'",
|
||||
"signature": "411d9ab46fef9d7d"
|
||||
},
|
||||
{
|
||||
"count": 2,
|
||||
"example": "CMPCONST:$ROOT/rtl/ip/native/storage/spisd_write.sv:<line>: Comparison is constant due to limited range",
|
||||
"signature": "813090adc9f1e8a8"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"example": "UNSIGNED:$ROOT/rtl/mini/top/bus.sv:<line>: Comparison is constant due to unsigned arithmetic",
|
||||
"signature": "9f53ff454a8648a4"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"example": "WIDTHTRUNC:$ROOT/rtl/ip/native/storage/spisd_read.sv:<line>: Operator ASSIGNDLY expects 8 bits on the Assign RHS, but Assign RHS's REPLICATE generates 9 bits.",
|
||||
"signature": "c963ef155f9a032c"
|
||||
},
|
||||
{
|
||||
"count": 3,
|
||||
"example": "WIDTHTRUNC:$ROOT/rtl/ip/native/storage/spisd_write.sv:<line>: Bit extraction of var[7:0] requires 3 bit index, not 4 bits.",
|
||||
"signature": "ef9f314dab2ac31d"
|
||||
}
|
||||
],
|
||||
"profile": "hazard3-rv32im-sky130",
|
||||
"schema_version": 1,
|
||||
"tool": "verilator"
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"entries": [
|
||||
{
|
||||
"count": 9,
|
||||
"example": "warning:Detected 9 multi-output cells (for example, \"sky130_fd_sc_hd__fa_1\").",
|
||||
"signature": "09d23991154c9af8"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"example": "warning:Wire hazard3_csr$retrosoc_asic.u_retrosoc.u_core_wrapper.u_hazard3_cpu_1port.core.csr_u.\\debug_mode is used but has no driver.",
|
||||
"signature": "1097d6b92f19e707"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"example": "warning:asynchronous load value missing for variable '\\update_irq_reg_arrays.i'",
|
||||
"signature": "56c5f69398be8d7b"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"example": "warning:Wire hazard3_csr$retrosoc_asic.u_retrosoc.u_core_wrapper.u_hazard3_cpu_1port.core.csr_u.\\pending_dbg_resume_prev is used but has no driver.",
|
||||
"signature": "5bbc6025e51705ec"
|
||||
},
|
||||
{
|
||||
"count": 9,
|
||||
"example": "warning:The network is combinational (run \"fraig\" or \"fraig_sweep\").",
|
||||
"signature": "62cc5ee554312205"
|
||||
},
|
||||
{
|
||||
"count": 2,
|
||||
"example": "warning:asynchronous load value missing for variable '\\update_nonconst.prev'",
|
||||
"signature": "a30df20b98d49196"
|
||||
},
|
||||
{
|
||||
"count": 2,
|
||||
"example": "warning:asynchronous load value missing for variable '\\update_nonconst.nonconst'",
|
||||
"signature": "d35463a1de40c7b2"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"example": "warning:Wire hazard3_csr$retrosoc_asic.u_retrosoc.u_core_wrapper.u_hazard3_cpu_1port.core.csr_u.\\dbg_req_resume_prev is used but has no driver.",
|
||||
"signature": "ef03dcca25b39dcb"
|
||||
}
|
||||
],
|
||||
"profile": "hazard3-rv32im-sky130",
|
||||
"schema_version": 1,
|
||||
"tool": "yosys"
|
||||
}
|
||||
@@ -3,3 +3,9 @@
|
||||
--require-hashes
|
||||
|
||||
tomli==2.4.1 --hash=sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe
|
||||
dataclasses-json==0.6.7 --hash=sha256:0dbf33f26c8d5305befd61b39d2b3414e8a407bedc2834dea9b8d642666fb40a
|
||||
marshmallow==3.26.2 --hash=sha256:013fa8a3c4c276c24d26d84ce934dc964e2aa794345a0f8c7e5a7191482c8a73
|
||||
mypy-extensions==1.1.0 --hash=sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505
|
||||
packaging==26.2 --hash=sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e
|
||||
typing-extensions==4.16.0 --hash=sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8
|
||||
typing-inspect==0.9.0 --hash=sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f
|
||||
@@ -1,2 +1 @@
|
||||
/pdk/gf180mcu-pdk/libraries/gf180mcu_fd_io/latest/cells/bi_t/gf180mcu_fd_io__bi_t.v
|
||||
/pdk/gf180mcu-pdk/libraries/gf180mcu_fd_io/latest/cells/in_c/gf180mcu_fd_io__in_c.v
|
||||
# GF180 standard-cell models are selected by gen_iverilog_filelist.py.
|
||||
@@ -1,2 +1 @@
|
||||
/pdk/skywater-sdk/libs.ref/sg13g2_io/verilog/sg13g2_io.v
|
||||
/pdk/skywater-sdk/libs.ref/sg13g2_stdcell/verilog/sg13g2_stdcell.v
|
||||
# SKY130 standard-cell models are selected by gen_iverilog_filelist.py.
|
||||
@@ -22,6 +22,8 @@ IVERILOG_POST_SIMV := $(IVERILOG_POST_DIR)/simv
|
||||
IVERILOG_BEHV_DEPFILE := $(IVERILOG_BEHV_DIR)/simv.d
|
||||
IVERILOG_NETL_DEPFILE := $(IVERILOG_NETL_DIR)/simv.d
|
||||
IVERILOG_POST_DEPFILE := $(IVERILOG_POST_DIR)/simv.d
|
||||
IVERILOG_FILELIST_GEN := $(RTL_PATH)/script/gen_iverilog_filelist.py
|
||||
NETLIST_SIM_MODELS := $(ROOT_PATH)/rtl/tech/netlist_sim_cells.v $(ROOT_PATH)/rtl/tech/gf180_sim_cells.v
|
||||
|
||||
-include $(CONVERTED_DEPFILE) $(IVERILOG_BEHV_DEPFILE) $(IVERILOG_NETL_DEPFILE) $(IVERILOG_POST_DEPFILE)
|
||||
|
||||
@@ -36,19 +38,19 @@ $(CONVERTED_SOC): $(MPW_VARIANT_STAMP) $(FILELIST_STAMP)
|
||||
python3 $(RTL_PATH)/script/filelist_deps.py $(RTL_FLIST) --target $@ \
|
||||
--output $(CONVERTED_DEPFILE)
|
||||
|
||||
$(IVERILOG_BEHV_FLIST): $(FILELIST_STAMP) $(CONVERTED_SOC)
|
||||
$(IVERILOG_BEHV_FLIST): $(FILELIST_STAMP) $(CONVERTED_SOC) $(IVERILOG_FILELIST_GEN)
|
||||
@mkdir -p $(@D)
|
||||
python3 $(RTL_PATH)/script/gen_iverilog_filelist.py \
|
||||
--mode behv --pdk $(PDK) --generated-dir $(GENERATED_FL_DIR) \
|
||||
--pin-map-rtl-dir $(PIN_MAP_DIR)/rtl --output $@ --converted $(CONVERTED_SOC)
|
||||
|
||||
$(IVERILOG_NETL_FLIST): $(FILELIST_STAMP) $(NETLIST_PATH)
|
||||
$(IVERILOG_NETL_FLIST): $(FILELIST_STAMP) $(NETLIST_PATH) $(IVERILOG_FILELIST_GEN) $(NETLIST_SIM_MODELS)
|
||||
@mkdir -p $(@D)
|
||||
python3 $(RTL_PATH)/script/gen_iverilog_filelist.py \
|
||||
--mode netl --pdk $(PDK) --generated-dir $(GENERATED_FL_DIR) \
|
||||
--pin-map-rtl-dir $(PIN_MAP_DIR)/rtl --output $@ --netlist $(NETLIST_PATH)
|
||||
|
||||
$(IVERILOG_POST_FLIST): $(FILELIST_STAMP) $(POST_PATH) $(SDF_PATH)
|
||||
$(IVERILOG_POST_FLIST): $(FILELIST_STAMP) $(POST_PATH) $(SDF_PATH) $(IVERILOG_FILELIST_GEN) $(NETLIST_SIM_MODELS)
|
||||
@mkdir -p $(@D)
|
||||
python3 $(RTL_PATH)/script/gen_iverilog_filelist.py \
|
||||
--mode post --pdk $(PDK) --generated-dir $(GENERATED_FL_DIR) \
|
||||
|
||||
@@ -4,6 +4,7 @@ from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import gzip
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
from filelist import atomic_write, parse_filelists, write_filelist
|
||||
@@ -11,6 +12,7 @@ from filelist import atomic_write, parse_filelists, write_filelist
|
||||
|
||||
SCRIPT_DIR = Path(__file__).resolve().parent
|
||||
MINI_DIR = SCRIPT_DIR.parent
|
||||
ROOT_DIR = MINI_DIR.parents[1]
|
||||
DEFAULT_GENERATED_DIR = MINI_DIR / ".generated_fl"
|
||||
|
||||
|
||||
@@ -55,6 +57,41 @@ def _prepare_sdf(source: Path, output_dir: Path, scope: str) -> Path:
|
||||
return annotator
|
||||
|
||||
|
||||
def _standard_cell_models(pdk: str, netlist: Path | None = None) -> list[Path]:
|
||||
if pdk == "GF180":
|
||||
cells_dir = (
|
||||
ROOT_DIR
|
||||
/ "pdk/gf180mcu-pdk/libraries/gf180mcu_fd_sc_mcu7t5v0/latest/cells"
|
||||
)
|
||||
return [
|
||||
ROOT_DIR / "rtl/tech/gf180_sim_cells.v",
|
||||
*sorted(cells_dir.glob("*/*.functional.v")),
|
||||
]
|
||||
if pdk == "SKY130":
|
||||
cells_dir = ROOT_DIR / "pdk/skywater-pdk/libraries/sky130_fd_sc_hd/latest/cells"
|
||||
if netlist is None:
|
||||
raise ValueError("SKY130 standard-cell models require a netlist")
|
||||
cell_models = {
|
||||
path.stem: path
|
||||
for path in cells_dir.glob("*/*.v")
|
||||
if "." not in path.stem
|
||||
}
|
||||
cell_types = set(
|
||||
re.findall(
|
||||
r"^\s*(sky130_fd_sc_hd__[A-Za-z0-9_]+)\s+",
|
||||
netlist.read_text(encoding="utf-8", errors="replace"),
|
||||
flags=re.MULTILINE,
|
||||
)
|
||||
)
|
||||
missing = sorted(cell_types - cell_models.keys())
|
||||
if missing:
|
||||
raise FileNotFoundError(
|
||||
"missing SKY130 functional model(s): " + ", ".join(missing)
|
||||
)
|
||||
return sorted(cell_models[cell_type] for cell_type in cell_types)
|
||||
return []
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = parse_args()
|
||||
generated_dir = args.generated_dir.resolve()
|
||||
@@ -79,6 +116,15 @@ def main() -> int:
|
||||
|
||||
pdk_filelist = generated_dir / f"pdk_{args.pdk.lower()}.fl"
|
||||
base.extend(parse_filelists([pdk_filelist]))
|
||||
if args.mode != "behv":
|
||||
base.files.append(ROOT_DIR / "rtl/tech/netlist_sim_cells.v")
|
||||
cell_models = _standard_cell_models(args.pdk, args.netlist)
|
||||
if args.pdk == "SKY130":
|
||||
base.defines.append("+define+FUNCTIONAL")
|
||||
base.defines.append("+define+UNIT_DELAY=#0")
|
||||
# SKY130 wrappers include functional models from their cell directory.
|
||||
base.incdirs.extend(sorted(path.parent for path in cell_models))
|
||||
base.files.extend(cell_models)
|
||||
base.deduplicate()
|
||||
write_filelist(args.output.resolve(), base)
|
||||
print(f"generated {args.mode} filelist: {args.output.resolve()}")
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// retroSoC is licensed under Mulan PSL v2.
|
||||
// You can use this software according to the terms and conditions of Mulan PSL v2.
|
||||
// You may obtain a copy of Mulan PSL v2 at:
|
||||
// http://license.coscl.org.cn/MulanPSL2
|
||||
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
// See the Mulan PSL v2 for more details.
|
||||
|
||||
// Icarus compatibility models for UDPs referenced by the locked GF180 cells.
|
||||
// The upstream functional models instantiate these UDPs but do not provide them.
|
||||
primitive UDP_GF018hv5v_mcu_sc7_TT_1P8V_25C_verilog_nonpg_MGM_N_IQ_FF_UDP(Q, C, P, CK, D, N);
|
||||
output Q;
|
||||
reg Q;
|
||||
input C;
|
||||
input P;
|
||||
input CK;
|
||||
input D;
|
||||
input N;
|
||||
|
||||
table
|
||||
1 1 ? ? 0 : ? : x;
|
||||
1 0 ? ? 0 : ? : 0;
|
||||
0 1 ? ? 0 : ? : 1;
|
||||
0 0 r 0 0 : ? : 0;
|
||||
0 0 r 1 0 : ? : 1;
|
||||
? ? ? ? 1 : ? : x;
|
||||
endtable
|
||||
endprimitive
|
||||
|
||||
primitive UDP_GF018hv5v_mcu_sc7_TT_1P8V_25C_verilog_nonpg_MGM_HN_IQ_FF_UDP(Q, C, P, CK, D, N);
|
||||
output Q;
|
||||
reg Q;
|
||||
input C;
|
||||
input P;
|
||||
input CK;
|
||||
input D;
|
||||
input N;
|
||||
|
||||
table
|
||||
1 1 ? ? 0 : ? : x;
|
||||
1 0 ? ? 0 : ? : 0;
|
||||
0 1 ? ? 0 : ? : 1;
|
||||
0 0 r 0 0 : ? : 0;
|
||||
0 0 r 1 0 : ? : 1;
|
||||
? ? ? ? 1 : ? : x;
|
||||
endtable
|
||||
endprimitive
|
||||
|
||||
primitive UDP_GF018hv5v_mcu_sc7_TT_1P8V_25C_verilog_nonpg_MGM_N_IQ_LATCH_UDP(Q, C, P, E, D, N);
|
||||
output Q;
|
||||
reg Q;
|
||||
input C;
|
||||
input P;
|
||||
input E;
|
||||
input D;
|
||||
input N;
|
||||
|
||||
table
|
||||
1 1 ? ? 0 : ? : x;
|
||||
1 0 ? ? 0 : ? : 0;
|
||||
0 1 ? ? 0 : ? : 1;
|
||||
0 0 1 0 0 : ? : 0;
|
||||
0 0 1 1 0 : ? : 1;
|
||||
? ? ? ? 1 : ? : x;
|
||||
endtable
|
||||
endprimitive
|
||||
|
||||
primitive UDP_GF018hv5v_mcu_sc7_TT_1P8V_25C_verilog_nonpg_MGM_HN_IQ_LATCH_UDP(Q, C, P, E, D, N);
|
||||
output Q;
|
||||
reg Q;
|
||||
input C;
|
||||
input P;
|
||||
input E;
|
||||
input D;
|
||||
input N;
|
||||
|
||||
table
|
||||
1 1 ? ? 0 : ? : x;
|
||||
1 0 ? ? 0 : ? : 0;
|
||||
0 1 ? ? 0 : ? : 1;
|
||||
0 0 1 0 0 : ? : 0;
|
||||
0 0 1 1 0 : ? : 1;
|
||||
? ? ? ? 1 : ? : x;
|
||||
endtable
|
||||
endprimitive
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// retroSoC is licensed under Mulan PSL v2.
|
||||
// You can use this software according to the terms and conditions of Mulan PSL v2.
|
||||
// You may obtain a copy of Mulan PSL v2 at:
|
||||
// http://license.coscl.org.cn/MulanPSL2
|
||||
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
// See the Mulan PSL v2 for more details.
|
||||
|
||||
// Behavioral definition for the tri-state primitive retained by Yosys netlists.
|
||||
module \$_TBUF_ (
|
||||
A,
|
||||
E,
|
||||
Y
|
||||
);
|
||||
input A;
|
||||
input E;
|
||||
output Y;
|
||||
|
||||
bufif1 (Y, A, E);
|
||||
endmodule
|
||||
@@ -44,6 +44,12 @@ module tc_clk_inv (
|
||||
.A(clk_i),
|
||||
.Y(clk_o)
|
||||
);
|
||||
|
||||
`elsif PDK_GF180
|
||||
assign clk_o = ~clk_i;
|
||||
|
||||
`elsif PDK_SKY130
|
||||
assign clk_o = ~clk_i;
|
||||
`endif
|
||||
|
||||
endmodule
|
||||
@@ -76,6 +82,12 @@ module tc_clk_buf (
|
||||
.A(clk_i),
|
||||
.Y(clk_o)
|
||||
);
|
||||
|
||||
`elsif PDK_GF180
|
||||
assign clk_o = clk_i;
|
||||
|
||||
`elsif PDK_SKY130
|
||||
assign clk_o = clk_i;
|
||||
`endif
|
||||
endmodule
|
||||
|
||||
@@ -115,6 +127,12 @@ module tc_clk_mux2 (
|
||||
.B (clk1_i),
|
||||
.Y (clk_o)
|
||||
);
|
||||
|
||||
`elsif PDK_GF180
|
||||
assign clk_o = clk_sel_i ? clk1_i : clk0_i;
|
||||
|
||||
`elsif PDK_SKY130
|
||||
assign clk_o = clk_sel_i ? clk1_i : clk0_i;
|
||||
`endif
|
||||
endmodule
|
||||
|
||||
@@ -156,5 +174,11 @@ module tc_clk_xor2 (
|
||||
.B(clk1_i),
|
||||
.X(clk_o)
|
||||
);
|
||||
|
||||
`elsif PDK_GF180
|
||||
assign clk_o = clk0_i ^ clk1_i;
|
||||
|
||||
`elsif PDK_SKY130
|
||||
assign clk_o = clk0_i ^ clk1_i;
|
||||
`endif
|
||||
endmodule
|
||||
+45
-89
@@ -19,6 +19,14 @@ module tc_io_xtl_pad (
|
||||
assign clk = en ? xi_pad : 1'b0;
|
||||
assign xo_pad = xi_pad;
|
||||
|
||||
`elsif PDK_SKY130
|
||||
assign clk = en ? xi_pad : 1'b0;
|
||||
assign xo_pad = xi_pad;
|
||||
|
||||
`elsif PDK_GF180
|
||||
assign clk = en ? xi_pad : 1'b0;
|
||||
assign xo_pad = xi_pad;
|
||||
|
||||
`elsif PDK_IHP130
|
||||
wire s_xi_pad;
|
||||
assign s_xi_pad = xi_pad;
|
||||
@@ -47,22 +55,6 @@ module tc_io_xtl_pad (
|
||||
.XC (clk)
|
||||
);
|
||||
|
||||
`elsif PDK_GF180
|
||||
(* keep *) (* dont_touch = "true" *)
|
||||
wire s_xi_pad;
|
||||
assign s_xi_pad = xi_pad;
|
||||
assign xo_pad = xi_pad;
|
||||
gf180mcu_fd_io__in_c u_gf180mcu_fd_io__in_c (
|
||||
.PU (1'b0),
|
||||
.PD (1'b0),
|
||||
.PAD (s_xi_pad),
|
||||
.Y (clk),
|
||||
.DVDD(),
|
||||
.DVSS(),
|
||||
.VDD (),
|
||||
.VSS ()
|
||||
);
|
||||
|
||||
`endif
|
||||
|
||||
endmodule
|
||||
@@ -75,6 +67,12 @@ module tc_io_in_pad (
|
||||
`ifdef PDK_BEHAV
|
||||
assign p2c = pad;
|
||||
|
||||
`elsif PDK_SKY130
|
||||
assign p2c = pad;
|
||||
|
||||
`elsif PDK_GF180
|
||||
assign p2c = pad;
|
||||
|
||||
`elsif PDK_IHP130
|
||||
(* keep *) (* dont_touch = "true" *)
|
||||
sg13g2_IOPadIn u_sg13g2_IOPadIn (
|
||||
@@ -82,19 +80,6 @@ module tc_io_in_pad (
|
||||
.p2c(p2c)
|
||||
);
|
||||
|
||||
`elsif PDK_GF180
|
||||
(* keep *) (* dont_touch = "true" *)
|
||||
gf180mcu_fd_io__in_c u_gf180mcu_fd_io__in_c (
|
||||
.PU (1'b0),
|
||||
.PD (1'b0),
|
||||
.PAD (pad),
|
||||
.Y (c2p),
|
||||
.DVDD(),
|
||||
.DVSS(),
|
||||
.VDD (),
|
||||
.VSS ()
|
||||
);
|
||||
|
||||
`endif
|
||||
|
||||
endmodule
|
||||
@@ -107,12 +92,19 @@ module tc_io_out_pad (
|
||||
`ifdef PDK_BEHAV
|
||||
assign pad = c2p;
|
||||
|
||||
`elsif PDK_SKY130
|
||||
assign pad = c2p;
|
||||
|
||||
`elsif PDK_GF180
|
||||
assign pad = c2p;
|
||||
|
||||
`elsif PDK_IHP130
|
||||
(* keep *) (* dont_touch = "true" *)
|
||||
sg13g2_IOPadOut4mA u_sg13g2_IOPadOut4mA (
|
||||
.pad(pad),
|
||||
.c2p(c2p)
|
||||
);
|
||||
|
||||
`endif
|
||||
|
||||
endmodule
|
||||
@@ -128,6 +120,14 @@ module tc_io_tri_pad (
|
||||
assign pad = c2p_en ? c2p : 1'bz;
|
||||
assign p2c = pad;
|
||||
|
||||
`elsif PDK_SKY130
|
||||
assign pad = c2p_en ? c2p : 1'bz;
|
||||
assign p2c = pad;
|
||||
|
||||
`elsif PDK_GF180
|
||||
assign pad = c2p_en ? c2p : 1'bz;
|
||||
assign p2c = pad;
|
||||
|
||||
`elsif PDK_IHP130
|
||||
(* keep *) (* dont_touch = "true" *)
|
||||
sg13g2_IOPadInOut4mA u_sg13g2_IOPadInOut4mA (
|
||||
@@ -163,26 +163,6 @@ module tc_io_tri_pad (
|
||||
.DS1(1'b1) // 8mA
|
||||
);
|
||||
|
||||
`elsif PDK_GF180
|
||||
(* keep *) (* dont_touch = "true" *)
|
||||
gf180mcu_fd_io__bi_t u_gf180mcu_fd_io__bi_t (
|
||||
.CS (1'b0), // 1: SCHMI 0: CMOS
|
||||
.SL (1'b0), // 1: SLOW 0: FAST
|
||||
.IE (~c2p_en),
|
||||
.OE (c2p_en),
|
||||
.PU (1'b0),
|
||||
.PD (1'b0),
|
||||
.A (c2p),
|
||||
.PDRV0(1'b0),
|
||||
.PDRV1(1'b0), // 4mA
|
||||
.PAD (pad),
|
||||
.Y (p2c),
|
||||
.DVDD (),
|
||||
.DVSS (),
|
||||
.VDD (),
|
||||
.VSS ()
|
||||
);
|
||||
|
||||
`endif
|
||||
|
||||
endmodule
|
||||
@@ -199,6 +179,14 @@ module tc_io_tri_schmitt_pad (
|
||||
assign pad = c2p_en ? c2p : 1'bz;
|
||||
assign p2c = pad;
|
||||
|
||||
`elsif PDK_SKY130
|
||||
assign pad = c2p_en ? c2p : 1'bz;
|
||||
assign p2c = pad;
|
||||
|
||||
`elsif PDK_GF180
|
||||
assign pad = c2p_en ? c2p : 1'bz;
|
||||
assign p2c = pad;
|
||||
|
||||
`elsif PDK_IHP130
|
||||
(* keep *) (* dont_touch = "true" *)
|
||||
sg13g2_IOPadInOut4mA u_sg13g2_IOPadInOut4mA (
|
||||
@@ -234,26 +222,6 @@ module tc_io_tri_schmitt_pad (
|
||||
.DS1(1'b1) // 8mA
|
||||
);
|
||||
|
||||
`elsif PDK_GF180
|
||||
(* keep *) (* dont_touch = "true" *)
|
||||
gf180mcu_fd_io__bi_t u_gf180mcu_fd_io__bi_t (
|
||||
.CS (1'b1), // 1: SCHMI 0: CMOS
|
||||
.SL (1'b0), // 1: SLOW 0: FAST
|
||||
.IE (~c2p_en),
|
||||
.OE (c2p_en),
|
||||
.PU (1'b0),
|
||||
.PD (1'b0),
|
||||
.A (c2p),
|
||||
.PDRV0(1'b0),
|
||||
.PDRV1(1'b0), // 4mA
|
||||
.PAD (pad),
|
||||
.Y (p2c),
|
||||
.DVDD (),
|
||||
.DVSS (),
|
||||
.VDD (),
|
||||
.VSS ()
|
||||
);
|
||||
|
||||
`endif
|
||||
|
||||
endmodule
|
||||
@@ -273,6 +241,14 @@ module tc_io_tri_full_pad (
|
||||
assign pad = c2p_en ? c2p : 1'bz;
|
||||
assign p2c = pad;
|
||||
|
||||
`elsif PDK_SKY130
|
||||
assign pad = c2p_en ? c2p : 1'bz;
|
||||
assign p2c = pad;
|
||||
|
||||
`elsif PDK_GF180
|
||||
assign pad = c2p_en ? c2p : 1'bz;
|
||||
assign p2c = pad;
|
||||
|
||||
`elsif PDK_IHP130
|
||||
logic [2:0] dum;
|
||||
assign dum[0] = cs;
|
||||
@@ -312,26 +288,6 @@ module tc_io_tri_full_pad (
|
||||
.DS1(1'b1) // 8mA
|
||||
);
|
||||
|
||||
`elsif PDK_GF180
|
||||
(* keep *) (* dont_touch = "true" *)
|
||||
gf180mcu_fd_io__bi_t u_gf180mcu_fd_io__bi_t (
|
||||
.CS (1'b1), // 1: SCHMI 0: CMOS
|
||||
.SL (1'b0), // 1: SLOW 0: FAST
|
||||
.IE (~c2p_en),
|
||||
.OE (c2p_en),
|
||||
.PU (1'b0),
|
||||
.PD (1'b0),
|
||||
.A (c2p),
|
||||
.PDRV0(1'b0),
|
||||
.PDRV1(1'b0), // 4mA
|
||||
.PAD (pad),
|
||||
.Y (p2c),
|
||||
.DVDD (),
|
||||
.DVSS (),
|
||||
.VDD (),
|
||||
.VSS ()
|
||||
);
|
||||
|
||||
`endif
|
||||
|
||||
endmodule
|
||||
+6
-1
@@ -67,7 +67,12 @@ def main() -> int:
|
||||
tools.append("sta")
|
||||
|
||||
source_names = ["mpw", "cluster_common", "third_party_ip"]
|
||||
pdk_names = {"IHP130": "pdk_ihp130", "ICS55": "pdk_ics55"}
|
||||
pdk_names = {
|
||||
"IHP130": "pdk_ihp130",
|
||||
"ICS55": "pdk_ics55",
|
||||
"GF180": "pdk_gf180",
|
||||
"SKY130": "pdk_sky130",
|
||||
}
|
||||
if args.pdk in pdk_names:
|
||||
source_names.append(pdk_names[args.pdk])
|
||||
paths = {
|
||||
|
||||
+46
-3
@@ -27,7 +27,10 @@ PR_COMMANDS = (
|
||||
"configs/ci/mdd-rv32im-ihp130.mk",
|
||||
("SIMU=VERILATOR", "HAVE_SVA=YES", "firmware", "sim"),
|
||||
),
|
||||
("configs/ci/hazard3-rv32im-ihp130.mk", ("SIMU=VERILATOR", "HAVE_SVA=YES", "sim")),
|
||||
(
|
||||
"configs/ci/hazard3-rv32im-ihp130.mk",
|
||||
("SIMU=VERILATOR", "HAVE_SVA=YES", "firmware", "sim"),
|
||||
),
|
||||
(
|
||||
"configs/ci/hazard3-rv32im-ihp130.mk",
|
||||
("SIMU=IVERILOG", "RTL_SIM_TIMEOUT=5200000", "sim-asm"),
|
||||
@@ -62,6 +65,31 @@ PR_PROFILES = (
|
||||
)
|
||||
NIGHTLY_PROFILES = PR_PROFILES + ("configs/nightly/picorv32-rv32im-ihp130.mk",)
|
||||
|
||||
PDK_PR_PROFILES = {
|
||||
"GF180": "configs/ci/hazard3-rv32im-gf180.mk",
|
||||
"IHP130": "configs/ci/hazard3-rv32im-ihp130.mk",
|
||||
"SKY130": "configs/ci/hazard3-rv32im-sky130.mk",
|
||||
}
|
||||
|
||||
|
||||
def pdk_pr_commands(profile: str) -> tuple[tuple[str, tuple[str, ...]], ...]:
|
||||
return (
|
||||
(profile, ("firmware",)),
|
||||
(profile, ("SIMU=VERILATOR", "HAVE_SVA=YES", "firmware", "sim")),
|
||||
(profile, ("SIMU=IVERILOG", "RTL_SIM_TIMEOUT=5200000", "sim-asm")),
|
||||
(profile, ("SYNTH=YOSYS", "synth")),
|
||||
(
|
||||
profile,
|
||||
(
|
||||
"SIMU=IVERILOG",
|
||||
"SIM_FIRMWARE_NAME=retrosoc_asm",
|
||||
"SIM_SUCCESS_MARKER=Mem wr/rd test success",
|
||||
"RTL_SIM_TIMEOUT=5200000",
|
||||
"netsim",
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def regression_environment() -> dict[str, str]:
|
||||
environment = os.environ.copy()
|
||||
@@ -96,10 +124,25 @@ def main() -> int:
|
||||
parser = argparse.ArgumentParser(description="Run a supported retroSoC regression suite")
|
||||
parser.add_argument("--root", type=Path, required=True)
|
||||
parser.add_argument("--suite", choices=("pr", "nightly"), required=True)
|
||||
parser.add_argument("--pdk", choices=tuple(PDK_PR_PROFILES), help="run one PR PDK matrix")
|
||||
parser.add_argument("--dry-run", action="store_true")
|
||||
args = parser.parse_args()
|
||||
commands = PR_COMMANDS if args.suite == "pr" else NIGHTLY_COMMANDS
|
||||
profiles = PR_PROFILES if args.suite == "pr" else NIGHTLY_PROFILES
|
||||
if args.pdk:
|
||||
if args.suite == "nightly":
|
||||
if args.pdk != "IHP130":
|
||||
parser.error("nightly regression supports only --pdk IHP130")
|
||||
commands = NIGHTLY_COMMANDS
|
||||
profiles = NIGHTLY_PROFILES
|
||||
elif args.pdk == "IHP130":
|
||||
commands = PR_COMMANDS
|
||||
profiles = PR_PROFILES
|
||||
else:
|
||||
profile = PDK_PR_PROFILES[args.pdk]
|
||||
commands = pdk_pr_commands(profile)
|
||||
profiles = (profile,)
|
||||
else:
|
||||
commands = PR_COMMANDS if args.suite == "pr" else NIGHTLY_COMMANDS
|
||||
profiles = PR_PROFILES if args.suite == "pr" else NIGHTLY_PROFILES
|
||||
environment = regression_environment()
|
||||
for profile, values in commands:
|
||||
command = ["make", f"CONFIG={profile}", *values]
|
||||
|
||||
@@ -44,6 +44,22 @@ if {$pdk == "IHP130"} {
|
||||
# for hilomap
|
||||
set tech_cell_tiehi {TIEHIH7H Y}
|
||||
set tech_cell_tielo {TIELOH7H Y}
|
||||
} elseif {$pdk == "GF180"} {
|
||||
set pdk_cells_lib "$root_dir/.cache/retrosoc/pdk/gf180"
|
||||
set tech_cells [list "$pdk_cells_lib/gf180mcu_fd_sc_mcu7t5v0__tt_025C_5v00.lib"]
|
||||
set tech_macros [list]
|
||||
# The aggregate GF180 Liberty does not characterize the available tie cells.
|
||||
# Keep constants as logic instead of mapping them to an uncharacterized cell.
|
||||
set tech_cell_tiehi {}
|
||||
set tech_cell_tielo {}
|
||||
} elseif {$pdk == "SKY130"} {
|
||||
set pdk_cells_lib "$root_dir/.cache/retrosoc/pdk/sky130"
|
||||
set tech_cells [list "$pdk_cells_lib/sky130_fd_sc_hd__tt_025C_1v80.lib"]
|
||||
set tech_macros [list]
|
||||
set tech_cell_tiehi {sky130_fd_sc_hd__conb_1 HI}
|
||||
set tech_cell_tielo {sky130_fd_sc_hd__conb_1 LO}
|
||||
} else {
|
||||
error "unsupported PDK for Yosys: $pdk"
|
||||
}
|
||||
|
||||
# pre-formated for easier use in yosys commands
|
||||
@@ -58,4 +74,4 @@ set tech_cells_args [concat {*}$tech_cells_args_list]
|
||||
# read library files
|
||||
foreach file $lib_list {
|
||||
yosys read_liberty -lib "$file"
|
||||
}
|
||||
}
|
||||
@@ -166,7 +166,9 @@ yosys splitnets -ports -format __v
|
||||
yosys setundef -zero
|
||||
yosys clean -purge
|
||||
|
||||
yosys hilomap -singleton -hicell {*}$tech_cell_tiehi -locell {*}$tech_cell_tielo
|
||||
if {[llength $tech_cell_tiehi] > 0 && [llength $tech_cell_tielo] > 0} {
|
||||
yosys hilomap -singleton -hicell {*}$tech_cell_tiehi -locell {*}$tech_cell_tielo
|
||||
}
|
||||
|
||||
# final reports
|
||||
yosys tee -q -o "${report_dir}/${proj_name}_synth.rpt" check
|
||||
|
||||
@@ -27,7 +27,13 @@ from scripts.check_format import format_files # noqa: E402
|
||||
from scripts.dependency_lock import LockError, load_lock # noqa: E402
|
||||
from scripts.generate_mpw import migrate_user_gpio_interfaces # noqa: E402
|
||||
from scripts.install_toolchain import safe_extract # noqa: E402
|
||||
from scripts.regress import NIGHTLY_COMMANDS, PR_COMMANDS, regression_environment # noqa: E402
|
||||
from scripts.regress import ( # noqa: E402
|
||||
NIGHTLY_COMMANDS,
|
||||
PDK_PR_PROFILES,
|
||||
PR_COMMANDS,
|
||||
pdk_pr_commands,
|
||||
regression_environment,
|
||||
)
|
||||
from scripts.setup_helpers import download_file, ensure_git_repo # noqa: E402
|
||||
|
||||
|
||||
@@ -309,6 +315,18 @@ def test_verilator_simulations_use_uniform_timeout() -> None:
|
||||
assert "HAVE_SVA=YES" in values
|
||||
|
||||
|
||||
def test_pdk_pr_regressions_cover_firmware_rtl_and_netlist() -> None:
|
||||
assert set(PDK_PR_PROFILES) == {"GF180", "IHP130", "SKY130"}
|
||||
for profile in PDK_PR_PROFILES.values():
|
||||
commands = pdk_pr_commands(profile)
|
||||
command_values = [values for _, values in commands]
|
||||
assert ("firmware",) in command_values
|
||||
assert any("SIMU=VERILATOR" in values and "firmware" in values for values in command_values)
|
||||
assert any("SIMU=IVERILOG" in values and "sim-asm" in values for values in command_values)
|
||||
assert any("SYNTH=YOSYS" in values and "synth" in values for values in command_values)
|
||||
assert any("SIMU=IVERILOG" in values and "netsim" in values for values in command_values)
|
||||
|
||||
|
||||
def test_run_flow_writes_structured_result(tmp_path: Path) -> None:
|
||||
log = tmp_path / "flow.log"
|
||||
result = tmp_path / "result.json"
|
||||
|
||||
Reference in new issue
Block a user