mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-06 14:55:14 +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
@@ -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