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:
maksyuki committed 2026-07-24 09:17:08 +08:00
1 parent 7d90d2ffb4
commit 7c923687ff
37 files changed
+851 -123

No files matched your search

+3 -2
View File
@@ -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.
+21 -6
View File
@@ -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()
+2
View File
@@ -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
+4 -2
View File
@@ -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
+24
View File
@@ -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
+24
View File
@@ -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
+2
View File
@@ -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
+5 -3
View File
@@ -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
+9 -3
View File
@@ -1,7 +1,9 @@
# retroSoC
[![quality](https://github.com/retroSoC/retroSoC/actions/workflows/quality.yml/badge.svg)](https://github.com/retroSoC/retroSoC/actions/workflows/quality.yml)
[![regression](https://github.com/retroSoC/retroSoC/actions/workflows/regression.yml/badge.svg)](https://github.com/retroSoC/retroSoC/actions/workflows/regression.yml)
[![IHP130 regression](https://github.com/retroSoC/retroSoC/actions/workflows/regression.yml/badge.svg)](https://github.com/retroSoC/retroSoC/actions/workflows/regression.yml)
[![GF180 regression](https://github.com/retroSoC/retroSoC/actions/workflows/regression-gf180.yml/badge.svg)](https://github.com/retroSoC/retroSoC/actions/workflows/regression-gf180.yml)
[![SKY130 regression](https://github.com/retroSoC/retroSoC/actions/workflows/regression-sky130.yml/badge.svg)](https://github.com/retroSoC/retroSoC/actions/workflows/regression-sky130.yml)
[![nightly](https://github.com/retroSoC/retroSoC/actions/workflows/nightly.yml/badge.svg)](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` |
+14
View File
@@ -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"},
+12
View File
@@ -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
+12
View File
@@ -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
+6
View File
@@ -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.
+11
View File
@@ -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.
+61
View File
@@ -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())
+82
View File
@@ -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
View File
@@ -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"
}
+6
View File
@@ -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
View File
@@ -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
View File
@@ -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.
+5 -3
View File
@@ -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) \
+46
View File
@@ -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()}")
+87
View File
@@ -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
+22
View File
@@ -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
+24
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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]
+17 -1
View File
@@ -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"
}
}
+3 -1
View 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
+19 -1
View File
@@ -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"