mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-04 22:32:36 +00:00
feat: add support for ICS55 PDK in various components and tools
- Introduced Verilator and Yosys warning configurations for ICS55. - Updated RTL filelists to include functional models for ICS55. - Modified memory modules to use wire instead of logic for clock and reset signals. - Enhanced Makefile and Iverilog configurations to support ICS55. - Implemented new simulation cells for ICS55 in the tech library. - Updated regression scripts and tests to include ICS55 support. - Added functionality to prepare ICS55 liberty and simulation models. - Enhanced testbench to validate ICS55 specific components and behaviors.
This commit is contained in:
35 files changed
+5336
-43
No files matched your search
+2
-1
@@ -6,7 +6,8 @@ workflows.
|
||||
|
||||
`workflows/quality.yml` runs the fast quality gate. `workflows/regression-smoke.yml`,
|
||||
`workflows/regression-ihp130.yml`, `workflows/regression-gf180.yml`,
|
||||
`workflows/regression-sky130.yml`, and `workflows/nightly.yml` call the reusable regression workflow;
|
||||
`workflows/regression-ics55.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.
|
||||
|
||||
|
||||
@@ -62,6 +62,7 @@ jobs:
|
||||
app/fatfs/ff16
|
||||
pdk/IHP-Open-PDK
|
||||
pdk/gf180mcu-pdk
|
||||
pdk/icsprout55-pdk
|
||||
pdk/skywater-pdk
|
||||
rtl/managed/clusterip/archinfo
|
||||
rtl/managed/clusterip/clint
|
||||
|
||||
@@ -79,6 +79,7 @@ jobs:
|
||||
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 ICS55 --dry-run
|
||||
python3 scripts/regress.py --root . --suite pr --pdk SKY130 --dry-run
|
||||
python3 scripts/regress.py --root . --suite nightly --pdk IHP130 --dry-run
|
||||
python3 scripts/regress.py --root . --suite smoke --pdk IHP130 --dry-run
|
||||
@@ -0,0 +1,24 @@
|
||||
name: regression-ics55
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, dev]
|
||||
pull_request:
|
||||
branches: [main, dev]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: regression-ics55-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
verified-open-source-flows:
|
||||
uses: ./.github/workflows/_regression.yml
|
||||
with:
|
||||
suite: pr
|
||||
pdk: ICS55
|
||||
profile: configs/ci/ics55.mk
|
||||
retention_days: 30
|
||||
@@ -341,6 +341,7 @@ regress-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
|
||||
python3 $(ROOT_PATH)/scripts/regress.py --root $(ROOT_PATH) --suite pr --pdk ICS55
|
||||
|
||||
regress-nightly:
|
||||
python3 $(ROOT_PATH)/scripts/regress.py --root $(ROOT_PATH) --suite nightly
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
[](https://github.com/retroSoC/retroSoC/actions/workflows/quality.yml)
|
||||
[](https://github.com/retroSoC/retroSoC/actions/workflows/regression-ihp130.yml)
|
||||
[](https://github.com/retroSoC/retroSoC/actions/workflows/regression-gf180.yml)
|
||||
[](https://github.com/retroSoC/retroSoC/actions/workflows/regression-ics55.yml)
|
||||
[](https://github.com/retroSoC/retroSoC/actions/workflows/regression-sky130.yml)
|
||||
[](https://github.com/retroSoC/retroSoC/actions/workflows/nightly.yml)
|
||||
|
||||
@@ -16,8 +17,8 @@ under the [Mulan Permissive Software License, Version 2](LICENSE).
|
||||
- A fixed architecture with a Hazard3 management core by default (PicoRV32 is
|
||||
an explicit build option) and software-selected
|
||||
user-core and user-IP extension slots.
|
||||
- Configurable GF180, SKY130, IHP130, and ICS55 implementation targets. GF180, SKY130,
|
||||
and IHP130 have open-source CI coverage; ICS55 remains a configured cluster target.
|
||||
- Configurable GF180, SKY130, IHP130, and ICS55 implementation targets with
|
||||
open-source CI coverage.
|
||||
- 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.
|
||||
@@ -53,9 +54,10 @@ core and defaults to `HAZARD3`.
|
||||
| --- | --- | --- | --- |
|
||||
| [`configs/ci/ihp130.mk`](configs/ci/ihp130.mk) | RV32IM | `bringup` | Pull-request open-source regression: firmware, Verilator, Icarus, Yosys, Icarus netlist simulation, and OpenSTA. |
|
||||
| [`configs/ci/gf180.mk`](configs/ci/gf180.mk) | RV32IM | `bringup` | Pull-request firmware, RTL simulation, Yosys, and Icarus netlist coverage. |
|
||||
| [`configs/ci/ics55.mk`](configs/ci/ics55.mk) | RV32IM | `bringup` | Pull-request firmware, RTL simulation, Yosys, Icarus netlist simulation, and OpenSTA core timing coverage. |
|
||||
| [`configs/ci/sky130.mk`](configs/ci/sky130.mk) | RV32IM | `bringup` | Pull-request firmware, RTL simulation, Yosys, and Icarus netlist coverage. |
|
||||
| [`configs/ci/ihp130-shell.mk`](configs/ci/ihp130-shell.mk) | RV32IM | `shell` | Pull-request firmware build with CSR support enabled. |
|
||||
| [`configs/cluster/ics55.mk`](configs/cluster/ics55.mk) | RV32IM | `bringup` | Cluster-only configuration; requires the site PDK and licensed-tool environment. |
|
||||
| [`configs/cluster/ics55.mk`](configs/cluster/ics55.mk) | RV32IM | `bringup` | Compatibility profile for site-specific ICS55 runs. |
|
||||
|
||||
## Prerequisites
|
||||
|
||||
@@ -145,7 +147,7 @@ make CONFIG=configs/ci/ihp130.mk SIMU=IVERILOG \
|
||||
configuration, and runs the Icarus assembly self-test. It runs strict RTL lint
|
||||
before those flows and omits synthesis,
|
||||
timing, and netlist simulation for fast feedback. `make regress-pr` runs the
|
||||
supported IHP130, GF180, and SKY130 PR matrices in sequence, including
|
||||
supported IHP130, GF180, ICS55, and SKY130 PR matrices in sequence, including
|
||||
slow-corner OpenSTA core timing analysis for each PDK.
|
||||
|
||||
Build outputs are isolated below `build/<profile>-<YYYY-MM-DD-HH-MM>-<config-hash>/`. Each variant keeps its
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
"revision": "e696e093129ca2212487aa169af74d06ebd86eb6",
|
||||
"destination": "pdk/icsprout55-pdk",
|
||||
"recursive": true,
|
||||
"license": "NOASSERTION"
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"pdk_gf180": {
|
||||
"url": "https://github.com/google/gf180mcu-pdk.git",
|
||||
@@ -83,6 +83,12 @@
|
||||
"destination": "app/fatfs/ff16/ff16.zip",
|
||||
"license": "LicenseRef-FatFs"
|
||||
},
|
||||
"pdk_ics55_h7cr_liberty": {
|
||||
"url": "https://github.com/openecos-projects/icsprout55-pdk/releases/download/v1.10.100/ics55_LLSC_H7CR_liberty.tar.bz2",
|
||||
"sha256": "faa3fc2f3ef8560c2d7cafc7800ecee39b69b8d177b14d098ed94062ba3f6e5c",
|
||||
"destination": ".cache/retrosoc/downloads/pdk/ics55/ics55_LLSC_H7CR_liberty.tar.bz2",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"serv": {
|
||||
"url": "https://github.com/olofk/serv/archive/refs/tags/1.4.0.tar.gz",
|
||||
"sha256": "f81c37b9f9d548c658e23bb7eb90fbed8b54e2e9e51fa42b8cd2f34cecc472ab",
|
||||
@@ -121,10 +127,10 @@
|
||||
"path": "bin"
|
||||
},
|
||||
"yosys": {
|
||||
"version": "0.58",
|
||||
"url": "https://github.com/retroSoC/artifact/releases/download/yosys-v0.58/yosys-v0.58-ubuntu-22.04-gcc.tar.gz",
|
||||
"sha256": "54468eb1fe474b11b8014fcabb068bf1398eaa072fa724b26e09dd2df58c3386",
|
||||
"archive": "yosys-v0.58-ubuntu-22.04-gcc.tar.gz",
|
||||
"version": "0.67",
|
||||
"url": "https://github.com/retroSoC/artifact/releases/download/yosys-v0.67/yosys-v0.67-ubuntu-22.04-gcc.tar.gz",
|
||||
"sha256": "272b5060e5c5d8c8830e2d4efd8d88f388fe39e152136bd99c293e718a91c1a7",
|
||||
"archive": "yosys-v0.67-ubuntu-22.04-gcc.tar.gz",
|
||||
"path": "bin"
|
||||
},
|
||||
"sby": {
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
SOC := MINI
|
||||
PDK := ICS55
|
||||
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
|
||||
+8
-6
@@ -7,21 +7,23 @@
|
||||
| Smoke | `configs/ci/ihp130.mk` | strict Verilator RTL lint, firmware, Verilator SVA compilation, Icarus assembly self-test |
|
||||
| Pull request | `configs/ci/ihp130.mk` | strict Verilator RTL lint, firmware, Verilator, Icarus, Yosys, netlist Icarus, OpenSTA |
|
||||
| Pull request | `configs/ci/gf180.mk` | strict Verilator RTL lint, firmware, Verilator, Icarus, Yosys, netlist Icarus, OpenSTA |
|
||||
| Pull request | `configs/ci/ics55.mk` | strict Verilator RTL lint, firmware, Verilator, Icarus, Yosys, netlist Icarus, OpenSTA |
|
||||
| Pull request | `configs/ci/sky130.mk` | strict Verilator RTL lint, firmware, Verilator, Icarus, Yosys, netlist Icarus, OpenSTA |
|
||||
| Nightly | `configs/ci/ihp130.mk` | repeated full IHP130 regression |
|
||||
| Cluster | `configs/cluster/ics55.mk` | configuration only; run with site PDK/tool access |
|
||||
| Cluster | `configs/cluster/ics55.mk` | compatibility profile for site-specific ICS55 runs |
|
||||
|
||||
OpenSTA runs a reproducible core-STA baseline for every CI PDK: IHP130 uses
|
||||
`slow_1p08V_125C`, GF180 uses `ss_125C_4v50`, and SKY130 uses `ss_100C_1v40`.
|
||||
`slow_1p08V_125C`, GF180 uses `ss_125C_4v50`, ICS55 uses the H7CR
|
||||
`ss_1p08_125C` view, and SKY130 uses `ss_100C_1v40`.
|
||||
The SDC is generated from `rtl/mini/integration/clock_reset_domains.json`, applies
|
||||
the external, audio, and DVP clocks at their technology-buffer observation pins,
|
||||
and groups unrelated clocks asynchronously. It intentionally excludes package,
|
||||
board, pad-ring, extraction, and PLL timing, so it is a regression-quality core
|
||||
analysis rather than physical signoff.
|
||||
|
||||
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.
|
||||
VCS flows remain cluster-only because public runners do not have the licensed
|
||||
simulator. ICS55 uses the same variant layout, manifests, result JSON, warning
|
||||
scanner, and cleanup rules as the other open-source CI PDKs.
|
||||
|
||||
## Reproducible Inputs
|
||||
|
||||
@@ -177,7 +179,7 @@ for diagnosis but is initially non-blocking.
|
||||
|
||||
`quality.yml` validates C, Makefile, and self-owned RTL formatting as well as Python, YAML, GitHub
|
||||
Actions, the dependency lock, and script tests. `regression-smoke.yml` provides fast IHP130 feedback;
|
||||
the three full PDK regression workflows remain required PR coverage and do not repeat the format checks.
|
||||
the four full PDK regression workflows remain required PR coverage and do not repeat the format checks.
|
||||
`nightly.yml` repeats the fixed IHP130 architecture. Source dependencies, locked tool archives, and Verilator `ccache` use
|
||||
separate cache keys.
|
||||
|
||||
|
||||
+13
-4
@@ -10,7 +10,13 @@ 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
|
||||
The supported CI PDKs are IHP130, GF180, ICS55, and SKY130. ICS55 obtains its
|
||||
locked H7CR standard-cell Liberty archive through
|
||||
`config/dependencies.lock.json` and materializes normalized TT and SS views
|
||||
below `.cache/retrosoc/pdk/ics55/`; its IO Liberty is part of the locked
|
||||
source checkout. PDK setup also generates a cached copy of the H7CR
|
||||
functional standard-cell model that corrects the seven upstream `MUXI2`
|
||||
self-feedback models without modifying the vendor checkout. GF180 assembles its
|
||||
locked `gf180mcu_fd_sc_mcu7t5v0` Liberty fragments and the two SoC-used IO
|
||||
cells (`in_c` and `bi_t`) at both its TT and core-STA slow corners. SKY130
|
||||
generates its `sky130_fd_sc_hd` Liberty model from locked upstream JSON files
|
||||
@@ -19,12 +25,12 @@ at TT and slow corners. Derived Liberty files are stored below
|
||||
the locked HD library submodule; the remaining upstream libraries are outside
|
||||
the SoC integration boundary.
|
||||
|
||||
All three PDK profiles run slow-corner OpenSTA core timing in CI. The analysis
|
||||
All four PDK profiles run slow-corner OpenSTA core timing in CI. The analysis
|
||||
uses the PDK standard-cell Liberty plus the linked IO-cell model required to
|
||||
read the synthesized top-level wrapper. It excludes board, pad-ring,
|
||||
extraction, and PLL timing and is therefore not a physical signoff result.
|
||||
|
||||
The GF180 and SKY130 CI flows synth the digital core and run functional
|
||||
The GF180, ICS55, and SKY130 CI flows synth the digital core and run functional
|
||||
standard-cell netlist simulation. Their generic SoC wrappers explicitly use
|
||||
the locked PDK GPIO and clock cells for RTL and netlist simulation: GF180 uses
|
||||
`gf180mcu_fd_io__in_c`/`gf180mcu_fd_io__bi_t` and MCU7T5V0 clock cells, while
|
||||
@@ -34,7 +40,10 @@ collateral; physical pad-ring integration remains a technology-specific
|
||||
signoff task. GF180/SKY130 PLL configurations are rejected because no
|
||||
qualified crystal-pad implementation is selected. SKY130 maps the generic
|
||||
Schmitt-control input to its threshold-select control and therefore does not
|
||||
provide hysteresis. Verilator uses a pin-compatible local functional model
|
||||
provide hysteresis. ICS55 uses its cached corrected standard-cell functional
|
||||
model with timing blocks disabled and a pin-compatible local PBMUX/PWE model
|
||||
only for Verilator, because the upstream IO model uses unsupported gate
|
||||
strengths and transmission primitives. Verilator uses a pin-compatible local functional model
|
||||
for the GF180 IO cells because the upstream model contains unsupported `rnmos`
|
||||
primitives. SKY130 uses the same approach because its upstream IO model uses
|
||||
unsupported switch primitives and drive strengths. Synthesis still preserves
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Prepare the locked ICS55 H7CR Liberty timing views."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from typing import Iterable
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
sys.path.insert(0, str(ROOT))
|
||||
from scripts.install_toolchain import safe_extract # noqa: E402
|
||||
from scripts.setup_helpers import atomic_write, sha256 # noqa: E402
|
||||
|
||||
|
||||
TT_OUTPUT = "ics55_h7cr_tt.lib"
|
||||
SS_OUTPUT = "ics55_h7cr_ss.lib"
|
||||
MARKER = ".complete"
|
||||
|
||||
|
||||
def find_corner(root: Path, tokens: Iterable[str]) -> Path:
|
||||
normalized_tokens = tuple(token.lower() for token in tokens)
|
||||
matches = [
|
||||
path
|
||||
for path in sorted(root.rglob("*.lib"))
|
||||
if all(token in path.name.lower() for token in normalized_tokens)
|
||||
]
|
||||
if len(matches) != 1:
|
||||
description = ", ".join(normalized_tokens)
|
||||
raise FileNotFoundError(
|
||||
f"expected one ICS55 Liberty corner matching {description}, found {len(matches)}"
|
||||
)
|
||||
return matches[0]
|
||||
|
||||
|
||||
def prepare(archive: Path, output_dir: Path, revision: str) -> None:
|
||||
archive = archive.resolve()
|
||||
if not archive.is_file():
|
||||
raise FileNotFoundError(f"ICS55 Liberty archive not found: {archive}")
|
||||
|
||||
output_dir = output_dir.resolve()
|
||||
marker_content = f"{revision}\n{sha256(archive)}\n"
|
||||
marker = output_dir / MARKER
|
||||
if (
|
||||
marker.is_file()
|
||||
and marker.read_text(encoding="utf-8") == marker_content
|
||||
and (output_dir / TT_OUTPUT).is_file()
|
||||
and (output_dir / SS_OUTPUT).is_file()
|
||||
):
|
||||
print(f"ICS55 Liberty is ready: {output_dir}")
|
||||
return
|
||||
|
||||
output_dir.parent.mkdir(parents=True, exist_ok=True)
|
||||
with tempfile.TemporaryDirectory(prefix=f".{output_dir.name}.", dir=output_dir.parent) as temp:
|
||||
candidate = Path(temp) / "content"
|
||||
extracted = Path(temp) / "extracted"
|
||||
candidate.mkdir()
|
||||
extracted.mkdir()
|
||||
safe_extract(archive, extracted)
|
||||
shutil.copy2(find_corner(extracted, ("tt", "1p2", "25")), candidate / TT_OUTPUT)
|
||||
shutil.copy2(find_corner(extracted, ("ss", "1p08", "125")), candidate / SS_OUTPUT)
|
||||
atomic_write(candidate / MARKER, marker_content)
|
||||
if output_dir.exists():
|
||||
shutil.rmtree(output_dir)
|
||||
os.replace(candidate, output_dir)
|
||||
print(f"prepared ICS55 Liberty: {output_dir}")
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Extract locked ICS55 H7CR Liberty timing views into the cache"
|
||||
)
|
||||
parser.add_argument("--archive", type=Path, required=True)
|
||||
parser.add_argument("--output-dir", type=Path, required=True)
|
||||
parser.add_argument("--revision", required=True)
|
||||
args = parser.parse_args()
|
||||
prepare(args.archive, args.output_dir, args.revision)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,99 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Prepare the ICS55 H7CR functional standard-cell model for simulation."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import re
|
||||
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, sha256 # noqa: E402
|
||||
|
||||
|
||||
EXPECTED_MUXI2_CELLS = {
|
||||
"MUXI2X0P5H7R",
|
||||
"MUXI2X0P7H7R",
|
||||
"MUXI2X1H7R",
|
||||
"MUXI2X1P4H7R",
|
||||
"MUXI2X2H7R",
|
||||
"MUXI2X3H7R",
|
||||
"MUXI2X4H7R",
|
||||
}
|
||||
BROKEN_IMPLEMENTATION = " udp_mux2 u0(Y, A, B, S0);\n not u1(Y, Y);"
|
||||
FIXED_IMPLEMENTATION = (
|
||||
" wire muxi2_y;\n\n"
|
||||
" udp_mux2 u0(muxi2_y, A, B, S0);\n"
|
||||
" not u1(Y, muxi2_y);"
|
||||
)
|
||||
MUXI2_MODULE = re.compile(
|
||||
r"(?P<header>\bmodule\s+(?P<name>MUXI2X[A-Za-z0-9]+H7R)"
|
||||
r"\s*\(Y,\s*A,\s*B,\s*S0\);)"
|
||||
r"(?P<body>.*?)"
|
||||
r"(?P<footer>\bendmodule\s*//\s*(?P=name))",
|
||||
re.DOTALL,
|
||||
)
|
||||
|
||||
|
||||
def patch_muxi2_models(content: str) -> tuple[str, tuple[str, ...]]:
|
||||
"""Replace the self-referential MUXI2 model with an intermediate-net form."""
|
||||
|
||||
cells: list[str] = []
|
||||
|
||||
def patch(match: re.Match[str]) -> str:
|
||||
name = match["name"]
|
||||
body = match["body"]
|
||||
broken_count = body.count(BROKEN_IMPLEMENTATION)
|
||||
fixed_count = body.count(FIXED_IMPLEMENTATION)
|
||||
if broken_count == 1 and fixed_count == 0:
|
||||
body = body.replace(BROKEN_IMPLEMENTATION, FIXED_IMPLEMENTATION)
|
||||
elif broken_count != 0 or fixed_count != 1:
|
||||
raise ValueError(f"unexpected {name} functional implementation")
|
||||
cells.append(name)
|
||||
return f"{match['header']}{body}{match['footer']}"
|
||||
|
||||
patched = MUXI2_MODULE.sub(patch, content)
|
||||
found = set(cells)
|
||||
if found != EXPECTED_MUXI2_CELLS:
|
||||
missing = ", ".join(sorted(EXPECTED_MUXI2_CELLS - found))
|
||||
unexpected = ", ".join(sorted(found - EXPECTED_MUXI2_CELLS))
|
||||
details = []
|
||||
if missing:
|
||||
details.append(f"missing {missing}")
|
||||
if unexpected:
|
||||
details.append(f"unexpected {unexpected}")
|
||||
raise ValueError("unexpected ICS55 H7CR MUXI2 cell set: " + "; ".join(details))
|
||||
return patched, tuple(sorted(cells))
|
||||
|
||||
|
||||
def prepare(source: Path, output: Path, revision: str) -> None:
|
||||
source = source.resolve()
|
||||
if not source.is_file():
|
||||
raise FileNotFoundError(f"ICS55 H7CR Verilog model not found: {source}")
|
||||
|
||||
patched, cells = patch_muxi2_models(source.read_text(encoding="utf-8"))
|
||||
output = output.resolve()
|
||||
metadata = f"{revision}\n{sha256(source)}\n{','.join(cells)}\n"
|
||||
changed = atomic_write(output, patched)
|
||||
atomic_write(output.with_suffix(output.suffix + ".revision"), metadata)
|
||||
state = "prepared" if changed else "ready"
|
||||
print(f"ICS55 H7CR functional model {state}: {output}")
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Patch the locked ICS55 H7CR MUXI2 functional models in the cache"
|
||||
)
|
||||
parser.add_argument("--source", type=Path, required=True)
|
||||
parser.add_argument("--output", type=Path, required=True)
|
||||
parser.add_argument("--revision", required=True)
|
||||
args = parser.parse_args()
|
||||
prepare(args.source, args.output, args.revision)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
+42
-2
@@ -8,8 +8,8 @@ from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
sys.path.insert(0, str(ROOT))
|
||||
from scripts.dependency_lock import source # noqa: E402
|
||||
from scripts.setup_helpers import ensure_git_repo # noqa: E402
|
||||
from scripts.dependency_lock import archive, source # noqa: E402
|
||||
from scripts.setup_helpers import download_file, ensure_git_repo # noqa: E402
|
||||
|
||||
|
||||
def main() -> int:
|
||||
@@ -116,6 +116,46 @@ def main() -> int:
|
||||
),
|
||||
check=True,
|
||||
)
|
||||
elif name == "pdk_ics55":
|
||||
liberty = archive("pdk_ics55_h7cr_liberty")
|
||||
archive_path = ROOT / liberty["destination"]
|
||||
download_file(
|
||||
liberty["url"],
|
||||
archive_path,
|
||||
liberty["sha256"],
|
||||
update=args.update,
|
||||
timeout=120,
|
||||
)
|
||||
subprocess.run(
|
||||
(
|
||||
sys.executable,
|
||||
str(ROOT / "pdk/prepare_ics55_liberty.py"),
|
||||
"--archive",
|
||||
str(archive_path),
|
||||
"--output-dir",
|
||||
str(ROOT / ".cache/retrosoc/pdk/ics55"),
|
||||
"--revision",
|
||||
dependency["revision"],
|
||||
),
|
||||
check=True,
|
||||
)
|
||||
subprocess.run(
|
||||
(
|
||||
sys.executable,
|
||||
str(ROOT / "pdk/prepare_ics55_sim_model.py"),
|
||||
"--source",
|
||||
str(
|
||||
destination
|
||||
/ "IP/STD_cell/ics55_LLSC_H7C_V1p10C100"
|
||||
/ "ics55_LLSC_H7CR/verilog/ics55_LLSC_H7CR.v"
|
||||
),
|
||||
"--output",
|
||||
str(ROOT / ".cache/retrosoc/pdk/ics55/ics55_h7cr_functional.v"),
|
||||
"--revision",
|
||||
dependency["revision"],
|
||||
),
|
||||
check=True,
|
||||
)
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"entries": [
|
||||
{
|
||||
"count": 1,
|
||||
"example": "warning:Found both default and explicit timescale based delays. Use",
|
||||
"signature": "aee22756a35889cc"
|
||||
}
|
||||
],
|
||||
"profile": "ics55",
|
||||
"schema_version": 1,
|
||||
"tool": "iverilog"
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"entries": [],
|
||||
"profile": "ics55",
|
||||
"schema_version": 1,
|
||||
"tool": "opensta"
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,77 @@
|
||||
{
|
||||
"entries": [
|
||||
{
|
||||
"count": 1,
|
||||
"example": "UNOPTFLAT:$ROOT/rtl/managed/mpw/core/username1/kianV/kianv_harris_mc_edition.v:<line>: Signal unoptimizable: Circular combinational logic: 'retrosoc_top.u_retrosoc_asic.u_retrosoc.u_user_core_top.u_user_core_design_username1.u_kianv_harris_mc_edition.alu_valid'",
|
||||
"signature": "1558b81c8599cb8f"
|
||||
},
|
||||
{
|
||||
"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": 1,
|
||||
"example": "UNOPTFLAT:$ROOT/rtl/managed/mpw/core/username1/kianV/kianv_harris_mc_edition.v:<line>: Signal unoptimizable: Circular combinational logic: 'retrosoc_top.u_retrosoc_asic.u_retrosoc.u_user_core_top.u_user_core_design_username1.u_kianv_harris_mc_edition.ALUSrcA'",
|
||||
"signature": "5b2c034f9f3213b7"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"example": "PINMISSING:$ROOT/rtl/managed/mpw/core/username4/serv/serv_synth_wrapper.v:<line>: Instance has missing pin: 'o_ren'",
|
||||
"signature": "704b76c39b529025"
|
||||
},
|
||||
{
|
||||
"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": "UNOPTFLAT:$ROOT/rtl/managed/mpw/core/username1/kianV/kianv_harris_mc_edition.v:<line>: Signal unoptimizable: Circular combinational logic: 'retrosoc_top.u_retrosoc_asic.u_retrosoc.u_user_core_top.u_user_core_design_username1.u_kianv_harris_mc_edition.ALUSrcB'",
|
||||
"signature": "8c87143c9aa63807"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"example": "UNOPTFLAT:$ROOT/rtl/managed/mpw/core/username1/kianV/alu_decoder.v:<line>: Signal unoptimizable: Circular combinational logic: 'retrosoc_top.u_retrosoc_asic.u_retrosoc.u_user_core_top.u_user_core_design_username1.u_kianv_harris_mc_edition.control_unit_I.alu_decoder_I.ALUControl'",
|
||||
"signature": "a7cc0b675cb3537c"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"example": "UNOPTFLAT:$ROOT/rtl/managed/mpw/core/username1/kianV/alu.v:<line>: Signal unoptimizable: Circular combinational logic: 'retrosoc_top.u_retrosoc_asic.u_retrosoc.u_user_core_top.u_user_core_design_username1.u_kianv_harris_mc_edition.datapath_unit_I.alu_I.is_sub'",
|
||||
"signature": "b808f41166ecb8fb"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"example": "WIDTHEXPAND:$ROOT/rtl/managed/mpw/core/username6/darkriscv/darkriscv.v:<line>: Operator COND expects 32 bits on the Conditional True, but Conditional True's LT generates 1 bits.",
|
||||
"signature": "c1b20cb9d552ca20"
|
||||
},
|
||||
{
|
||||
"count": 14,
|
||||
"example": "WIDTHTRUNC:$ROOT/rtl/managed/mpw/core/username6/darkriscv/darkriscv.v:<line>: Logical operator COND expects 1 bit on the Conditional Test, but Conditional Test's VARREF 'FLUSH' generates 2 bits.",
|
||||
"signature": "c7ca04782912d519"
|
||||
},
|
||||
{
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"example": "WIDTHEXPAND:$ROOT/rtl/managed/mpw/core/username6/darkriscv/darkriscv.v:<line>: Operator COND expects 32 bits on the Conditional True, but Conditional True's LTS generates 1 bits.",
|
||||
"signature": "f505968343b665e3"
|
||||
},
|
||||
{
|
||||
"count": 35,
|
||||
"example": "SPECIFYIGN:$ROOT/pdk/icsprout55-pdk/IP/STD_cell/ics55_LLSC_H7C_V1p10C100/ics55_LLSC_H7CR/verilog/ics55_LLSC_H7CR.v:<line>: Ignoring unsupported: specify block construct",
|
||||
"signature": "fda0ac7e720e6088"
|
||||
}
|
||||
],
|
||||
"profile": "ics55",
|
||||
"schema_version": 1,
|
||||
"tool": "verilator"
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
{
|
||||
"entries": [
|
||||
{
|
||||
"count": 1,
|
||||
"example": "warning:Wire hazard3_csr_username3$retrosoc_asic.u_retrosoc.u_user_core_top.u_user_core_design_username3.u_hazard3_cpu_1port.core.csr_u.\\dbg_req_resume_prev is used but has no driver.",
|
||||
"signature": "0a782ef45c9a2826"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"example": "warning:Wire hazard3_csr_username3$retrosoc_asic.u_retrosoc.u_user_core_top.u_user_core_design_username3.u_hazard3_cpu_1port.core.csr_u.\\debug_mode is used but has no driver.",
|
||||
"signature": "0b15e8e8ff1ec2e6"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"example": "warning:Wire hazard3_csr_username3$retrosoc_asic.u_retrosoc.u_user_core_top.u_user_core_design_username3.u_hazard3_cpu_1port.core.csr_u.\\pending_dbg_resume_prev is used but has no driver.",
|
||||
"signature": "1b869cf19bdd0fc1"
|
||||
},
|
||||
{
|
||||
"count": 2,
|
||||
"example": "warning:asynchronous load value missing for variable '\\update_irq_reg_arrays.i'",
|
||||
"signature": "56c5f69398be8d7b"
|
||||
},
|
||||
{
|
||||
"count": 10,
|
||||
"example": "warning:The network is combinational (run \"fraig\" or \"fraig_sweep\").",
|
||||
"signature": "62cc5ee554312205"
|
||||
},
|
||||
{
|
||||
"count": 4,
|
||||
"example": "warning:asynchronous load value missing for variable '\\update_nonconst.prev'",
|
||||
"signature": "a30df20b98d49196"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"example": "warning:Wire hazard3_csr$retrosoc_asic.u_retrosoc.u_core_wrapper.u_mgmt_core_wrapper.u_hazard3_cpu_1port.core.csr_u.\\debug_mode is used but has no driver.",
|
||||
"signature": "abc4bf82285e7e27"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"example": "warning:Wire hazard3_csr$retrosoc_asic.u_retrosoc.u_core_wrapper.u_mgmt_core_wrapper.u_hazard3_cpu_1port.core.csr_u.\\dbg_req_resume_prev is used but has no driver.",
|
||||
"signature": "b53fced7cd12c426"
|
||||
},
|
||||
{
|
||||
"count": 4,
|
||||
"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_mgmt_core_wrapper.u_hazard3_cpu_1port.core.csr_u.\\pending_dbg_resume_prev is used but has no driver.",
|
||||
"signature": "dcbf3e1cbb359ba9"
|
||||
},
|
||||
{
|
||||
"count": 10,
|
||||
"example": "warning:Detected 6 multi-output cells (for example, \"ADDFX1H7R\").",
|
||||
"signature": "efa45c73f40f4fe6"
|
||||
}
|
||||
],
|
||||
"profile": "ics55",
|
||||
"schema_version": 1,
|
||||
"tool": "yosys"
|
||||
}
|
||||
@@ -1,2 +1,3 @@
|
||||
/pdk/icsprout55-pdk/IP/STD_cell/ics55_LLSC_H7C_V1p10C100/ics55_LLSC_H7CR/verilog/ics55_LLSC_H7CR.v
|
||||
+define+functional
|
||||
/cache/retrosoc/pdk/ics55/ics55_h7cr_functional.v
|
||||
/pdk/icsprout55-pdk/IP/IO/ICsprout_55LLULP1233_IO_251013/verilog/icsIOA_N55_3P3.v
|
||||
@@ -41,8 +41,8 @@ module nmi_opipsram (
|
||||
// verilog_format: on
|
||||
);
|
||||
|
||||
logic dummy0 = clk_i;
|
||||
logic dummy1 = rst_n_i;
|
||||
wire dummy0 = clk_i;
|
||||
wire dummy1 = rst_n_i;
|
||||
|
||||
// nmi
|
||||
assign nmi.rdata = '0;
|
||||
|
||||
@@ -40,8 +40,8 @@ module nmi_sdio (
|
||||
// verilog_format: on
|
||||
);
|
||||
|
||||
logic dummy0 = clk_i;
|
||||
logic dummy1 = rst_n_i;
|
||||
wire dummy0 = clk_i;
|
||||
wire dummy1 = rst_n_i;
|
||||
// nmi
|
||||
assign nmi.rdata = '0;
|
||||
assign nmi.ready = '0;
|
||||
|
||||
@@ -112,7 +112,13 @@ ifeq ($(PDK), IHP130)
|
||||
else ifeq ($(PDK), SKY130)
|
||||
PDK_FILELIST := $(GENERATED_FL_DIR)/pdk_sky130.fl
|
||||
else ifeq ($(PDK), ICS55)
|
||||
ifeq ($(SYNTH), YOSYS)
|
||||
PDK_FILELIST := $(GENERATED_FL_DIR)/pdk_ics55_yosys.fl
|
||||
else ifeq ($(SIMU), VERILATOR)
|
||||
PDK_FILELIST := $(GENERATED_FL_DIR)/pdk_ics55_verilator.fl
|
||||
else
|
||||
PDK_FILELIST := $(GENERATED_FL_DIR)/pdk_ics55.fl
|
||||
endif
|
||||
else ifeq ($(PDK), GF180)
|
||||
PDK_FILELIST := $(GENERATED_FL_DIR)/pdk_gf180.fl
|
||||
endif
|
||||
|
||||
@@ -65,8 +65,8 @@ gen_iverilog_filelist: $(IVERILOG_BEHV_FLIST)
|
||||
tech-cell-test: $(FILELIST_STAMP) $(TECH_CELL_TEST) $(ROOT_PATH)/rtl/tech/tc_io.sv \
|
||||
$(ROOT_PATH)/rtl/tech/tc_clk.sv
|
||||
@case "$(PDK)" in \
|
||||
GF180|SKY130) ;; \
|
||||
*) echo "tech-cell-test supports PDK=GF180 or PDK=SKY130" >&2; exit 2 ;; \
|
||||
GF180|SKY130|ICS55) ;; \
|
||||
*) echo "tech-cell-test supports PDK=GF180, SKY130, or ICS55" >&2; exit 2 ;; \
|
||||
esac
|
||||
@mkdir -p $(TECH_CELL_TEST_DIR)
|
||||
python3 $(ROOT_PATH)/scripts/run_flow.py --tool iverilog-tech-cells \
|
||||
|
||||
@@ -16,6 +16,7 @@ ROOT_DIR = RTL_DIR.parent
|
||||
DEFAULT_OUTPUT_DIR = MINI_DIR / ".generated_fl"
|
||||
|
||||
PATH_PREFIXES = {
|
||||
"cache": ROOT_DIR / ".cache",
|
||||
"pdk": ROOT_DIR / "pdk",
|
||||
"clusterip": RTL_DIR / "managed" / "clusterip",
|
||||
"ip": RTL_DIR / "ip",
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
// Functional ICS55 IO models for Verilator only.
|
||||
//
|
||||
// The native model uses transistor primitives, transmission gates, and drive
|
||||
// strengths that Verilator does not support. These models retain the logical
|
||||
// behavior used by the SoC wrappers without replacing native-cell instances in
|
||||
// other flows.
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
// The native PDK module names and analog drive controls are fixed interfaces.
|
||||
// They do not affect the digital behavior represented by these models.
|
||||
/* verilator lint_off DECLFILENAME */
|
||||
/* verilator lint_off UNUSED */
|
||||
module P65_1233_PWE (
|
||||
input logic E,
|
||||
input logic XIN,
|
||||
output logic XOUT,
|
||||
output logic XC
|
||||
);
|
||||
|
||||
assign XOUT = ~(E & XIN);
|
||||
assign XC = E & XIN;
|
||||
|
||||
endmodule
|
||||
|
||||
module P65_1233_PBMUX (
|
||||
output logic C,
|
||||
inout wire A,
|
||||
inout wire PAD,
|
||||
input logic IE,
|
||||
input logic CS,
|
||||
input logic I,
|
||||
input logic OE,
|
||||
input logic OD,
|
||||
input logic PU,
|
||||
input logic PD,
|
||||
input logic DS0,
|
||||
input logic DS1
|
||||
);
|
||||
|
||||
assign PAD = OE ? (OD ? (I ? 1'bz : 1'b0) : I) : 1'bz;
|
||||
assign PAD = PU ? 1'b1 : 1'bz;
|
||||
assign PAD = PD ? 1'b0 : 1'bz;
|
||||
assign A = PAD;
|
||||
assign C = IE ? PAD : 1'b0;
|
||||
|
||||
endmodule
|
||||
/* verilator lint_on UNUSED */
|
||||
/* verilator lint_on DECLFILENAME */
|
||||
@@ -203,6 +203,14 @@ module tc_clk_xor2 (
|
||||
.X(clk_o)
|
||||
);
|
||||
|
||||
`elsif PDK_ICS55
|
||||
(* keep *) (* dont_touch = "true" *)
|
||||
XOR2X0P5H7R u_XOR2X0P5H7R (
|
||||
.A(clk0_i),
|
||||
.B(clk1_i),
|
||||
.Y(clk_o)
|
||||
);
|
||||
|
||||
`elsif PDK_GF180
|
||||
(* keep *) (* dont_touch = "true" *)
|
||||
gf180mcu_fd_sc_mcu7t5v0__xor2_1 u_gf180mcu_fd_sc_mcu7t5v0__xor2_1 (
|
||||
|
||||
@@ -188,6 +188,23 @@ module tc_io_in_pad (
|
||||
.p2c(p2c)
|
||||
);
|
||||
|
||||
`elsif PDK_ICS55
|
||||
(* keep *) (* dont_touch = "true" *)
|
||||
P65_1233_PBMUX u_P65_1233_PBMUX (
|
||||
.C (p2c),
|
||||
.A (),
|
||||
.PAD(pad),
|
||||
.IE (1'b1),
|
||||
.CS (1'b1), // 1: CMOS 0: SCHMI
|
||||
.I (1'b0),
|
||||
.OE (1'b0),
|
||||
.OD (1'b0),
|
||||
.PU (1'b0),
|
||||
.PD (1'b0),
|
||||
.DS0(1'b0),
|
||||
.DS1(1'b1) // 8mA
|
||||
);
|
||||
|
||||
`endif
|
||||
|
||||
endmodule
|
||||
@@ -229,6 +246,23 @@ module tc_io_out_pad (
|
||||
.c2p(c2p)
|
||||
);
|
||||
|
||||
`elsif PDK_ICS55
|
||||
(* keep *) (* dont_touch = "true" *)
|
||||
P65_1233_PBMUX u_P65_1233_PBMUX (
|
||||
.C (),
|
||||
.A (),
|
||||
.PAD(pad),
|
||||
.IE (1'b0),
|
||||
.CS (1'b1), // 1: CMOS 0: SCHMI
|
||||
.I (c2p),
|
||||
.OE (1'b1),
|
||||
.OD (1'b0),
|
||||
.PU (1'b0),
|
||||
.PD (1'b0),
|
||||
.DS0(1'b0),
|
||||
.DS1(1'b1) // 8mA
|
||||
);
|
||||
|
||||
`endif
|
||||
|
||||
endmodule
|
||||
|
||||
@@ -58,6 +58,7 @@ NIGHTLY_PROFILES = PR_PROFILES
|
||||
PDK_PR_PROFILES = {
|
||||
"GF180": "configs/ci/gf180.mk",
|
||||
"IHP130": "configs/ci/ihp130.mk",
|
||||
"ICS55": "configs/ci/ics55.mk",
|
||||
"SKY130": "configs/ci/sky130.mk",
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,8 @@ make CONFIG=configs/ci/ihp130.mk SYNTH=YOSYS synth
|
||||
make CONFIG=configs/ci/ihp130.mk STA=OPENSTA sta
|
||||
make CONFIG=configs/ci/gf180.mk SYNTH=YOSYS synth
|
||||
make CONFIG=configs/ci/gf180.mk STA=OPENSTA sta
|
||||
make CONFIG=configs/ci/ics55.mk SYNTH=YOSYS synth
|
||||
make CONFIG=configs/ci/ics55.mk STA=OPENSTA sta
|
||||
make CONFIG=configs/ci/sky130.mk SYNTH=YOSYS synth
|
||||
make CONFIG=configs/ci/sky130.mk STA=OPENSTA sta
|
||||
```
|
||||
|
||||
@@ -12,6 +12,9 @@ OPENSTA_LINK_LIBS := $(ROOT_PATH)/.cache/retrosoc/pdk/gf180/gf180mcu_fd_io_retro
|
||||
else ifeq ($(PDK),SKY130)
|
||||
OPENSTA_LIBERTY := $(ROOT_PATH)/.cache/retrosoc/pdk/sky130/sky130_fd_sc_hd__ss_100C_1v40.lib
|
||||
OPENSTA_LINK_LIBS := $(ROOT_PATH)/sta/opensta/sky130_io_blackbox.liberty
|
||||
else ifeq ($(PDK),ICS55)
|
||||
OPENSTA_LIBERTY := $(ROOT_PATH)/.cache/retrosoc/pdk/ics55/ics55_h7cr_ss.lib
|
||||
OPENSTA_LINK_LIBS := $(ROOT_PATH)/pdk/icsprout55-pdk/IP/IO/ICsprout_55LLULP1233_IO_251013/liberty/ICSIOA_N55_3P3_ss_1p08_2p97_125c.lib
|
||||
else
|
||||
$(error OpenSTA core-STA does not support PDK=$(PDK))
|
||||
endif
|
||||
|
||||
@@ -34,16 +34,14 @@ if {$pdk == "IHP130"} {
|
||||
set tech_cell_tiehi {sg13g2_tiehi L_HI}
|
||||
set tech_cell_tielo {sg13g2_tielo L_LO}
|
||||
} elseif {$pdk == "ICS55"} {
|
||||
set pdk_dir "/nfs/share/home/zhuangchunan/proj/Flow_CX55/lib_data"
|
||||
set pdk_cells_lib /nfs/share/home/qiming/yosys-flow
|
||||
set pdk_sram_lib ${pdk_dir}/mem
|
||||
set pdk_io_lib ${pdk_dir}/ccslib
|
||||
set tech_cells [list "$pdk_cells_lib/ETSCA_N55_H7BL_DSS_PRCMAX_V1P0_T125.lib"]
|
||||
set tech_macros [list "$pdk_sram_lib/S55NLLG1PH_X256Y4D32_BW_ss_1.08_125.lib"]
|
||||
lappend tech_macros "$pdk_io_lib/ETIOA_N55_3P3_ss1p08v2p97v125c.lib"
|
||||
set pdk_dir "$root_dir/pdk/icsprout55-pdk"
|
||||
set pdk_cells_lib "$root_dir/.cache/retrosoc/pdk/ics55"
|
||||
set pdk_io_lib "${pdk_dir}/IP/IO/ICsprout_55LLULP1233_IO_251013/liberty"
|
||||
set tech_cells [list "$pdk_cells_lib/ics55_h7cr_tt.lib"]
|
||||
set tech_macros [list "$pdk_io_lib/ICSIOA_N55_3P3_tt_1p2_3p3_25c.lib"]
|
||||
# for hilomap
|
||||
set tech_cell_tiehi {TIEHIH7H Y}
|
||||
set tech_cell_tielo {TIELOH7H Y}
|
||||
set tech_cell_tiehi {TIEHIH7R Z}
|
||||
set tech_cell_tielo {TIELOH7R Z}
|
||||
} 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"]
|
||||
|
||||
@@ -33,12 +33,9 @@ set abc_comb_script [processAbcScript $abc_combinational_script]
|
||||
# read liberty files and prepare some variables
|
||||
source $script_dir/init_tech.tcl
|
||||
|
||||
yosys plugin -i slang
|
||||
|
||||
# # read design
|
||||
yosys read_slang --top $top_design -F $sv_flist \
|
||||
--compat-mode --keep-hierarchy \
|
||||
--allow-use-before-declare --ignore-timing --ignore-unknown-modules
|
||||
--keep-hierarchy --allow-use-before-declare --ignore-initial --ignore-timing
|
||||
|
||||
# # blackbox requested modules
|
||||
# if { [info exists ::env(YOSYS_BLACKBOX_MODULES)] } {
|
||||
|
||||
@@ -73,6 +73,39 @@ module tc_pdk_cells_tb;
|
||||
);
|
||||
`endif
|
||||
|
||||
`ifdef PDK_ICS55
|
||||
logic ics55_od_i;
|
||||
logic ics55_od_oe;
|
||||
logic ics55_od_mode;
|
||||
logic ics55_pu;
|
||||
logic ics55_pd;
|
||||
tri ics55_pad;
|
||||
logic [2:0] ics55_mux_inputs;
|
||||
logic ics55_mux_y;
|
||||
|
||||
P65_1233_PBMUX u_ics55_open_drain_pad (
|
||||
.C (),
|
||||
.A (),
|
||||
.PAD(ics55_pad),
|
||||
.IE (1'b0),
|
||||
.CS (1'b1),
|
||||
.I (ics55_od_i),
|
||||
.OE (ics55_od_oe),
|
||||
.OD (ics55_od_mode),
|
||||
.PU (ics55_pu),
|
||||
.PD (ics55_pd),
|
||||
.DS0(1'b0),
|
||||
.DS1(1'b1)
|
||||
);
|
||||
|
||||
MUXI2X0P5H7R u_ics55_muxi2 (
|
||||
.A (ics55_mux_inputs[0]),
|
||||
.B (ics55_mux_inputs[1]),
|
||||
.S0(ics55_mux_inputs[2]),
|
||||
.Y (ics55_mux_y)
|
||||
);
|
||||
`endif
|
||||
|
||||
assign in_pad = in_drive_en ? in_drive : 1'bz;
|
||||
assign tri_pad = tri_drive_en ? tri_drive : 1'bz;
|
||||
assign schmitt_pad = schmitt_drive_en ? schmitt_drive : 1'bz;
|
||||
@@ -168,6 +201,14 @@ module tc_pdk_cells_tb;
|
||||
gf180_seq_d = 1'b0;
|
||||
gf180_seq_reset_n = 1'b0;
|
||||
`endif
|
||||
`ifdef PDK_ICS55
|
||||
ics55_od_i = 1'b1;
|
||||
ics55_od_oe = 1'b0;
|
||||
ics55_od_mode = 1'b1;
|
||||
ics55_pu = 1'b0;
|
||||
ics55_pd = 1'b0;
|
||||
ics55_mux_inputs = 3'b000;
|
||||
`endif
|
||||
|
||||
#5;
|
||||
in_drive_en = 1'b1;
|
||||
@@ -191,7 +232,11 @@ module tc_pdk_cells_tb;
|
||||
tri_c2p_en = 1'b1;
|
||||
#5;
|
||||
expect_bit(tri_pad, 1'b1, "tri-state pad output");
|
||||
`ifdef PDK_ICS55
|
||||
expect_bit(tri_p2c, 1'b0, "ICS55 tri-state output disables input receiver");
|
||||
`else
|
||||
expect_bit(tri_p2c, 1'b1, "tri-state output readback");
|
||||
`endif
|
||||
tri_c2p_en = 1'b0;
|
||||
#5;
|
||||
if (tri_pad !== 1'bz) begin
|
||||
@@ -244,6 +289,33 @@ module tc_pdk_cells_tb;
|
||||
expect_bit(gf180_dffrnq_q, 1'b1, "GF180 reset-low DFF clock capture");
|
||||
expect_bit(gf180_dffsnq_q, 1'b1, "GF180 reset-high DFF clock capture");
|
||||
`endif
|
||||
`ifdef PDK_ICS55
|
||||
ics55_od_oe = 1'b1;
|
||||
#5;
|
||||
if (ics55_pad !== 1'bz) begin
|
||||
$fatal(1, "ICS55 open-drain pad did not release high data");
|
||||
end
|
||||
ics55_od_i = 1'b0;
|
||||
#5;
|
||||
expect_bit(ics55_pad, 1'b0, "ICS55 open-drain low drive");
|
||||
ics55_od_oe = 1'b0;
|
||||
ics55_pu = 1'b1;
|
||||
#5;
|
||||
expect_bit(ics55_pad, 1'b1, "ICS55 pull-up");
|
||||
ics55_pu = 1'b0;
|
||||
ics55_pd = 1'b1;
|
||||
#5;
|
||||
expect_bit(ics55_pad, 1'b0, "ICS55 pull-down");
|
||||
for (int mux_vector = 0; mux_vector < 8; mux_vector++) begin
|
||||
ics55_mux_inputs = mux_vector[2:0];
|
||||
#1;
|
||||
expect_bit(
|
||||
ics55_mux_y,
|
||||
~(ics55_mux_inputs[2] ? ics55_mux_inputs[1] : ics55_mux_inputs[0]),
|
||||
$sformatf("ICS55 MUXI2 vector %0d", mux_vector)
|
||||
);
|
||||
end
|
||||
`endif
|
||||
|
||||
$display("technology IO and clock cell test passed");
|
||||
$finish;
|
||||
|
||||
@@ -664,7 +664,7 @@ def test_smoke_regression_uses_ihp130_behavioral_coverage_only() -> None:
|
||||
|
||||
|
||||
def test_pdk_pr_regressions_cover_firmware_rtl_and_netlist() -> None:
|
||||
assert set(PDK_PR_PROFILES) == {"GF180", "IHP130", "SKY130"}
|
||||
assert set(PDK_PR_PROFILES) == {"GF180", "IHP130", "ICS55", "SKY130"}
|
||||
for profile in PDK_PR_PROFILES.values():
|
||||
commands = pdk_pr_commands(profile)
|
||||
command_values = [values for _, values in commands]
|
||||
|
||||
@@ -2,9 +2,12 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import io
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
import tarfile
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
@@ -13,6 +16,8 @@ DOMAINS = ROOT / "rtl/mini/integration/clock_reset_domains.json"
|
||||
PIN_MAP = ROOT / "rtl/mini/pin_map/pin_map.json"
|
||||
GENERATOR = ROOT / "sta/opensta/generate_sdc.py"
|
||||
GF180_GENERATOR = ROOT / "pdk/generate_gf180_liberty.py"
|
||||
ICS55_PREPARER = ROOT / "pdk/prepare_ics55_liberty.py"
|
||||
ICS55_SIM_MODEL_PREPARER = ROOT / "pdk/prepare_ics55_sim_model.py"
|
||||
|
||||
|
||||
def generate(domains: Path, output: Path) -> subprocess.CompletedProcess[str]:
|
||||
@@ -113,3 +118,102 @@ def test_gf180_liberty_generator_assembles_requested_io_cells(tmp_path: Path) ->
|
||||
assert (output.with_suffix(".lib.revision")).read_text(encoding="utf-8") == (
|
||||
"locked-revision\ngf180mcu_fd_io\nbi_t,in_c\n"
|
||||
)
|
||||
|
||||
|
||||
def test_ics55_liberty_preparer_selects_stable_tt_and_ss_views(tmp_path: Path) -> None:
|
||||
archive = tmp_path / "ics55_LLSC_H7CR_liberty.tar.bz2"
|
||||
members = {
|
||||
"liberty/ics55_LLSC_H7CR_tt_1p2_25c.lib": "library (ics55_tt) {}\n",
|
||||
"liberty/ics55_LLSC_H7CR_ss_1p08_125c.lib": "library (ics55_ss) {}\n",
|
||||
}
|
||||
with tarfile.open(archive, "w:bz2") as bundle:
|
||||
for name, content in members.items():
|
||||
payload = content.encode("utf-8")
|
||||
member = tarfile.TarInfo(name)
|
||||
member.size = len(payload)
|
||||
bundle.addfile(member, io.BytesIO(payload))
|
||||
|
||||
output = tmp_path / "output"
|
||||
command = [
|
||||
sys.executable,
|
||||
str(ICS55_PREPARER),
|
||||
"--archive",
|
||||
str(archive),
|
||||
"--output-dir",
|
||||
str(output),
|
||||
"--revision",
|
||||
"locked-revision",
|
||||
]
|
||||
first = subprocess.run(command, text=True, capture_output=True)
|
||||
|
||||
assert first.returncode == 0, first.stderr
|
||||
assert (output / "ics55_h7cr_tt.lib").read_text(encoding="utf-8") == members[
|
||||
"liberty/ics55_LLSC_H7CR_tt_1p2_25c.lib"
|
||||
]
|
||||
assert (output / "ics55_h7cr_ss.lib").read_text(encoding="utf-8") == members[
|
||||
"liberty/ics55_LLSC_H7CR_ss_1p08_125c.lib"
|
||||
]
|
||||
assert (output / ".complete").read_text(encoding="utf-8") == (
|
||||
"locked-revision\n" + hashlib.sha256(archive.read_bytes()).hexdigest() + "\n"
|
||||
)
|
||||
|
||||
first_mtime = (output / "ics55_h7cr_tt.lib").stat().st_mtime_ns
|
||||
second = subprocess.run(command, text=True, capture_output=True)
|
||||
assert second.returncode == 0, second.stderr
|
||||
assert (output / "ics55_h7cr_tt.lib").stat().st_mtime_ns == first_mtime
|
||||
|
||||
|
||||
def test_ics55_sim_model_preparer_patches_every_h7cr_muxi2_variant(tmp_path: Path) -> None:
|
||||
cells = (
|
||||
"MUXI2X0P5H7R",
|
||||
"MUXI2X0P7H7R",
|
||||
"MUXI2X1H7R",
|
||||
"MUXI2X1P4H7R",
|
||||
"MUXI2X2H7R",
|
||||
"MUXI2X3H7R",
|
||||
"MUXI2X4H7R",
|
||||
)
|
||||
source = tmp_path / "ics55_LLSC_H7CR.v"
|
||||
source.write_text(
|
||||
"".join(
|
||||
f"module {cell} (Y, A, B, S0);\n"
|
||||
"output Y;\n"
|
||||
"input A, B, S0;\n\n"
|
||||
" udp_mux2 u0(Y, A, B, S0);\n"
|
||||
" not u1(Y, Y);\n"
|
||||
f"endmodule //{cell}\n"
|
||||
for cell in cells
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
output = tmp_path / "ics55_h7cr_functional.v"
|
||||
command = [
|
||||
sys.executable,
|
||||
str(ICS55_SIM_MODEL_PREPARER),
|
||||
"--source",
|
||||
str(source),
|
||||
"--output",
|
||||
str(output),
|
||||
"--revision",
|
||||
"locked-revision",
|
||||
]
|
||||
|
||||
first = subprocess.run(command, text=True, capture_output=True)
|
||||
|
||||
assert first.returncode == 0, first.stderr
|
||||
prepared = output.read_text(encoding="utf-8")
|
||||
assert prepared.count("wire muxi2_y;") == len(cells)
|
||||
assert prepared.count("udp_mux2 u0(muxi2_y, A, B, S0);") == len(cells)
|
||||
assert "not u1(Y, Y);" not in prepared
|
||||
assert (output.with_suffix(".v.revision")).read_text(encoding="utf-8") == (
|
||||
"locked-revision\n"
|
||||
+ hashlib.sha256(source.read_bytes()).hexdigest()
|
||||
+ "\n"
|
||||
+ ",".join(cells)
|
||||
+ "\n"
|
||||
)
|
||||
|
||||
first_mtime = output.stat().st_mtime_ns
|
||||
second = subprocess.run(command, text=True, capture_output=True)
|
||||
assert second.returncode == 0, second.stderr
|
||||
assert output.stat().st_mtime_ns == first_mtime
|
||||
Reference in new issue
Block a user