mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-04 22:32:36 +00:00
feat: enhance PDK support and add test coverage
- Updated gen_iverilog_filelist.py to exclude sequential models from the file list for GF180 PDK. - Introduced black box definitions for GF180 and SKY130 IO cells in their respective .sv files. - Added simulation models for GF180 IO cells and sequential cells in gf180_seq_sim_cells.v. - Modified tc_clk.sv to utilize specific clock cells for GF180 and SKY130 PDKs. - Implemented bi-directional and tri-state pad modules for GF180 and SKY130 PDKs in tc_io.sv. - Enhanced dependency lock validation to include submodule checks in dependency_lock.py. - Updated setup_helpers.py to support selective submodule initialization. - Created a comprehensive testbench for PDK cells in tc_pdk_cells_tb.sv. - Added tests for dependency helper functions and tech cell configurations to ensure proper error handling.
This commit is contained in:
24 files changed
+956
-41
No files matched your search
@@ -100,7 +100,7 @@ jobs:
|
||||
|
||||
- name: Check IHP130 timing environment
|
||||
if: inputs.pdk == 'IHP130'
|
||||
run: make CONFIG=${{ inputs.profile }} STA=OPENSTA doctor
|
||||
run: make CONFIG=${{ inputs.profile }} SIMU=IVERILOG STA=OPENSTA doctor
|
||||
|
||||
- name: Run ${{ inputs.suite }} regression
|
||||
run: python3 scripts/regress.py --root . --suite "${{ inputs.suite }}" --pdk "${{ inputs.pdk }}"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
name: regression
|
||||
name: regression-ihp130
|
||||
|
||||
on:
|
||||
push:
|
||||
|
||||
@@ -134,6 +134,9 @@ DEF_LIST += +define+IP_$(IP)
|
||||
DEF_LIST += +define+SIMU_$(SIMU)
|
||||
|
||||
ifeq ($(HAVE_PLL), YES)
|
||||
ifneq ($(filter $(PDK),GF180 SKY130),)
|
||||
$(error HAVE_PLL=YES requires a qualified crystal pad and is unsupported for PDK=$(PDK))
|
||||
endif
|
||||
DEF_LIST += +define+HAVE_PLL
|
||||
endif
|
||||
|
||||
@@ -168,7 +171,7 @@ endif
|
||||
regress-pr regress-nightly sim-asm format format-check sw-format sw-format-check mk-format \
|
||||
mk-format-check rtl-format rtl-format-check sw-policy-check sw-host-test \
|
||||
pin-map check-pin-map soc-topology check-soc-topology user-extensions check-user-extensions \
|
||||
check-clock-reset-domains
|
||||
check-clock-reset-domains tech-cell-test
|
||||
.NOTPARALLEL: setup
|
||||
|
||||
help:
|
||||
@@ -192,6 +195,7 @@ help:
|
||||
' user-extensions generate the selected scalar user-extension bindings' \
|
||||
' check-user-extensions validate the canonical user-extension map' \
|
||||
' check-clock-reset-domains validate the root clock/reset and CDC inventory' \
|
||||
' tech-cell-test test GF180/SKY130 technology IO and clock wrappers' \
|
||||
' check-warnings | metrics analyze flow logs and reports' \
|
||||
' check-metrics apply the committed metrics policy' \
|
||||
' format format self-owned C, Makefile, and RTL sources' \
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
"revision": "7198cf647113f56041e02abf3eb623692820c5e1",
|
||||
"destination": "pdk/skywater-pdk",
|
||||
"recursive": true,
|
||||
"submodules": ["libraries/sky130_fd_sc_hd/latest"],
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"cluster_archinfo": {"url": "https://github.com/retroSoC/archinfo.git", "revision": "d65dd13c83a1176668bf5178004814a1551bf6ba", "destination": "rtl/managed/clusterip/archinfo", "license": "NOASSERTION"},
|
||||
|
||||
+19
-4
@@ -14,9 +14,24 @@ 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.
|
||||
committed. SKY130 setup initializes only the locked HD library submodule;
|
||||
the remaining upstream libraries are outside the SoC integration boundary.
|
||||
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.
|
||||
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
|
||||
SKY130 uses `sky130_fd_io__top_gpiov2` and HD clock cells. This integration
|
||||
does not add supply, corner, filler, placement, or physical verification
|
||||
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
|
||||
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
|
||||
the original PDK cell instances. GF180 netlist simulation also substitutes
|
||||
pin-compatible sequential-cell models because the upstream functional models
|
||||
propagate an unconnected synthesized notifier as an unknown value.
|
||||
@@ -32,6 +32,7 @@ def main() -> int:
|
||||
destination,
|
||||
dependency["revision"],
|
||||
recursive=dependency.get("recursive", False),
|
||||
submodules=tuple(dependency.get("submodules", ())),
|
||||
update=args.update,
|
||||
)
|
||||
if name == "pdk_gf180":
|
||||
|
||||
@@ -1 +1,8 @@
|
||||
# GF180 standard-cell models are selected by gen_iverilog_filelist.py.
|
||||
# Technology wrappers instantiate these models directly in RTL simulation.
|
||||
/tech/gf180_io_sim_cells.v
|
||||
/tech/gf180_seq_sim_cells.v
|
||||
/pdk/gf180mcu-pdk/libraries/gf180mcu_fd_sc_mcu7t5v0/latest/cells/clkbuf/gf180mcu_fd_sc_mcu7t5v0__clkbuf_1.functional.v
|
||||
/pdk/gf180mcu-pdk/libraries/gf180mcu_fd_sc_mcu7t5v0/latest/cells/clkinv/gf180mcu_fd_sc_mcu7t5v0__clkinv_1.functional.v
|
||||
/pdk/gf180mcu-pdk/libraries/gf180mcu_fd_sc_mcu7t5v0/latest/cells/mux2/gf180mcu_fd_sc_mcu7t5v0__mux2_1.functional.v
|
||||
/pdk/gf180mcu-pdk/libraries/gf180mcu_fd_sc_mcu7t5v0/latest/cells/xor2/gf180mcu_fd_sc_mcu7t5v0__xor2_1.functional.v
|
||||
@@ -1 +1,12 @@
|
||||
# SKY130 standard-cell models are selected by gen_iverilog_filelist.py.
|
||||
# Technology wrappers instantiate these functional models directly in RTL simulation.
|
||||
+define+FUNCTIONAL
|
||||
+incdir+/pdk/skywater-pdk/libraries/sky130_fd_sc_hd/latest/cells/clkbuf
|
||||
+incdir+/pdk/skywater-pdk/libraries/sky130_fd_sc_hd/latest/cells/clkinv
|
||||
+incdir+/pdk/skywater-pdk/libraries/sky130_fd_sc_hd/latest/cells/mux2
|
||||
+incdir+/pdk/skywater-pdk/libraries/sky130_fd_sc_hd/latest/cells/xor2
|
||||
/tech/sky130_io_sim_cells.v
|
||||
/pdk/skywater-pdk/libraries/sky130_fd_sc_hd/latest/cells/clkbuf/sky130_fd_sc_hd__clkbuf_1.v
|
||||
/pdk/skywater-pdk/libraries/sky130_fd_sc_hd/latest/cells/clkinv/sky130_fd_sc_hd__clkinv_1.v
|
||||
/pdk/skywater-pdk/libraries/sky130_fd_sc_hd/latest/cells/mux2/sky130_fd_sc_hd__mux2_1.v
|
||||
/pdk/skywater-pdk/libraries/sky130_fd_sc_hd/latest/cells/xor2/sky130_fd_sc_hd__xor2_1.v
|
||||
+5
-4
@@ -110,15 +110,16 @@ include $(RTL_PATH)/mk/software.mk
|
||||
|
||||
#====================== filelist ======================
|
||||
ifeq ($(PDK), IHP130)
|
||||
NET_FLIST := -f $(GENERATED_FL_DIR)/pdk_ihp130.fl
|
||||
PDK_FILELIST := $(GENERATED_FL_DIR)/pdk_ihp130.fl
|
||||
else ifeq ($(PDK), SKY130)
|
||||
NET_FLIST := -f $(GENERATED_FL_DIR)/pdk_sky130.fl
|
||||
PDK_FILELIST := $(GENERATED_FL_DIR)/pdk_sky130.fl
|
||||
else ifeq ($(PDK), ICS55)
|
||||
NET_FLIST := -f $(GENERATED_FL_DIR)/pdk_ics55.fl
|
||||
PDK_FILELIST := $(GENERATED_FL_DIR)/pdk_ics55.fl
|
||||
else ifeq ($(PDK), GF180)
|
||||
NET_FLIST := -f $(GENERATED_FL_DIR)/pdk_gf180.fl
|
||||
PDK_FILELIST := $(GENERATED_FL_DIR)/pdk_gf180.fl
|
||||
endif
|
||||
|
||||
NET_FLIST := -f $(PDK_FILELIST)
|
||||
NET_FLIST += -f $(GENERATED_FL_DIR)/def.fl
|
||||
NET_FLIST += -f $(GENERATED_FL_DIR)/sys_def.fl
|
||||
NET_FLIST += -f $(GENERATED_FL_DIR)/commonip.fl
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/tech/tc_io.sv
|
||||
/tech/gf180_io_cells_blackbox.sv
|
||||
/tech/sky130_io_cells_blackbox.sv
|
||||
/tech/tc_clk.sv
|
||||
/tech/tc_pll.sv
|
||||
/tech/tc_sram.sv
|
||||
+19
-1
@@ -24,6 +24,8 @@ 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
|
||||
TECH_CELL_TEST := $(ROOT_PATH)/tests/rtl/tc_pdk_cells_tb.sv
|
||||
TECH_CELL_TEST_DIR := $(IVERILOG_ROOT)/tech-cells
|
||||
|
||||
-include $(CONVERTED_DEPFILE) $(IVERILOG_BEHV_DEPFILE) $(IVERILOG_NETL_DEPFILE) $(IVERILOG_POST_DEPFILE)
|
||||
|
||||
@@ -60,6 +62,22 @@ $(IVERILOG_POST_FLIST): $(FILELIST_STAMP) $(POST_PATH) $(SDF_PATH) $(IVERILOG_FI
|
||||
convt_sv2v: $(CONVERTED_SOC)
|
||||
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 ;; \
|
||||
esac
|
||||
@mkdir -p $(TECH_CELL_TEST_DIR)
|
||||
python3 $(ROOT_PATH)/scripts/run_flow.py --tool iverilog-tech-cells \
|
||||
--log $(TECH_CELL_TEST_DIR)/compile.log --result $(TECH_CELL_TEST_DIR)/result-compile.json \
|
||||
--cwd $(TECH_CELL_TEST_DIR) -- $(IVERILOG) $(IVERILOG_COMMON_OPTS) $(IVERILOG_TIME_OPTS) \
|
||||
-f $(GENERATED_FL_DIR)/def.fl -f $(PDK_FILELIST) $(ROOT_PATH)/rtl/tech/tc_io.sv \
|
||||
$(ROOT_PATH)/rtl/tech/tc_clk.sv $(TECH_CELL_TEST) -o simv -s tc_pdk_cells_tb
|
||||
python3 $(ROOT_PATH)/scripts/run_flow.py --tool iverilog-tech-cells-sim \
|
||||
--log $(TECH_CELL_TEST_DIR)/sim.log --result $(TECH_CELL_TEST_DIR)/result-sim.json \
|
||||
--cwd $(TECH_CELL_TEST_DIR) -- $(VVP) simv
|
||||
|
||||
$(IVERILOG_BEHV_SIMV): $(IVERILOG_BEHV_FLIST)
|
||||
@mkdir -p $(IVERILOG_BEHV_DIR)
|
||||
python3 $(ROOT_PATH)/scripts/run_flow.py --tool iverilog \
|
||||
@@ -130,4 +148,4 @@ postwave:
|
||||
clean:
|
||||
python3 $(ROOT_PATH)/scripts/clean.py --root $(ROOT_PATH) --path $(IVERILOG_ROOT)
|
||||
|
||||
.PHONY: convt_sv2v gen_iverilog_filelist comp netcomp postcomp sim netsim postsim wave netwave postwave clean
|
||||
.PHONY: convt_sv2v gen_iverilog_filelist tech-cell-test comp netcomp postcomp sim netsim postsim wave netwave postwave clean
|
||||
@@ -63,9 +63,18 @@ def _standard_cell_models(pdk: str, netlist: Path | None = None) -> list[Path]:
|
||||
ROOT_DIR
|
||||
/ "pdk/gf180mcu-pdk/libraries/gf180mcu_fd_sc_mcu7t5v0/latest/cells"
|
||||
)
|
||||
sequential_models = {
|
||||
"gf180mcu_fd_sc_mcu7t5v0__dffq_1",
|
||||
"gf180mcu_fd_sc_mcu7t5v0__dffrnq_1",
|
||||
"gf180mcu_fd_sc_mcu7t5v0__dffsnq_1",
|
||||
}
|
||||
return [
|
||||
ROOT_DIR / "rtl/tech/gf180_sim_cells.v",
|
||||
*sorted(cells_dir.glob("*/*.functional.v")),
|
||||
*sorted(
|
||||
path
|
||||
for path in cells_dir.glob("*/*.functional.v")
|
||||
if path.name.removesuffix(".functional.v") not in sequential_models
|
||||
),
|
||||
]
|
||||
if pdk == "SKY130":
|
||||
cells_dir = ROOT_DIR / "pdk/skywater-pdk/libraries/sky130_fd_sc_hd/latest/cells"
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// retroSoC is licensed under Mulan PSL v2.
|
||||
// You may use this software according to the terms and conditions of the 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 OF ANY KIND,
|
||||
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
// See the Mulan PSL v2 for more details.
|
||||
|
||||
// Yosys needs the macro interfaces even though PDK simulation models are excluded
|
||||
// from the synthesis file list. The technology cells remain black boxes.
|
||||
`ifdef SYNTHESIS
|
||||
`ifdef PDK_GF180
|
||||
(* blackbox *)
|
||||
module gf180mcu_fd_io__in_c (
|
||||
input wire PU,
|
||||
input wire PD,
|
||||
inout wire PAD,
|
||||
output wire Y,
|
||||
input wire DVDD,
|
||||
input wire DVSS,
|
||||
input wire VDD,
|
||||
input wire VSS
|
||||
);
|
||||
endmodule
|
||||
|
||||
(* blackbox *)
|
||||
module gf180mcu_fd_io__bi_t (
|
||||
input wire CS,
|
||||
input wire SL,
|
||||
input wire IE,
|
||||
input wire OE,
|
||||
input wire PU,
|
||||
input wire PD,
|
||||
input wire A,
|
||||
input wire PDRV0,
|
||||
input wire PDRV1,
|
||||
inout wire PAD,
|
||||
output wire Y,
|
||||
input wire DVDD,
|
||||
input wire DVSS,
|
||||
input wire VDD,
|
||||
input wire VSS
|
||||
);
|
||||
endmodule
|
||||
`endif
|
||||
`endif
|
||||
@@ -0,0 +1,72 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// retroSoC is licensed under Mulan PSL v2.
|
||||
// You may use this software according to the terms and conditions of the 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 OF ANY KIND,
|
||||
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
// See the Mulan PSL v2 for more details.
|
||||
|
||||
// The upstream GF180 IO Verilog models use rnmos primitives unsupported by the
|
||||
// active simulator. These pin-compatible functional models are simulation-only;
|
||||
// synthesis preserves the corresponding GF180 PDK cell instances.
|
||||
module gf180mcu_fd_io__in_c (
|
||||
PU,
|
||||
PD,
|
||||
PAD,
|
||||
Y,
|
||||
DVDD,
|
||||
DVSS,
|
||||
VDD,
|
||||
VSS
|
||||
);
|
||||
input PU;
|
||||
input PD;
|
||||
inout PAD;
|
||||
output Y;
|
||||
input DVDD;
|
||||
input DVSS;
|
||||
input VDD;
|
||||
input VSS;
|
||||
|
||||
assign PAD = (!PU && PD) ? 1'b0 : ((PU && !PD) ? 1'b1 : 1'bz);
|
||||
assign Y = PAD;
|
||||
endmodule
|
||||
|
||||
module gf180mcu_fd_io__bi_t (
|
||||
CS,
|
||||
SL,
|
||||
IE,
|
||||
OE,
|
||||
PU,
|
||||
PD,
|
||||
A,
|
||||
PDRV0,
|
||||
PDRV1,
|
||||
PAD,
|
||||
Y,
|
||||
DVDD,
|
||||
DVSS,
|
||||
VDD,
|
||||
VSS
|
||||
);
|
||||
input CS;
|
||||
input SL;
|
||||
input IE;
|
||||
input OE;
|
||||
input PU;
|
||||
input PD;
|
||||
input A;
|
||||
input PDRV0;
|
||||
input PDRV1;
|
||||
inout PAD;
|
||||
output Y;
|
||||
input DVDD;
|
||||
input DVSS;
|
||||
input VDD;
|
||||
input VSS;
|
||||
|
||||
assign PAD = OE ? A : ((!PU && PD) ? 1'b0 : ((PU && !PD) ? 1'b1 : 1'bz));
|
||||
assign Y = IE ? PAD : 1'b0;
|
||||
endmodule
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// retroSoC is licensed under Mulan PSL v2.
|
||||
// You may use this software according to the terms and conditions of the 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 OF ANY KIND,
|
||||
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
// See the Mulan PSL v2 for more details.
|
||||
|
||||
// Icarus functional models for the sequential GF180 cells selected by Yosys.
|
||||
// The upstream models expose a timing notifier that the synthesized netlist
|
||||
// leaves unconnected; these models retain the PDK cell interfaces without
|
||||
// propagating that high-impedance notifier into functional simulation.
|
||||
module gf180mcu_fd_sc_mcu7t5v0__dffq_1 (
|
||||
input wire CLK,
|
||||
input wire D,
|
||||
output reg Q,
|
||||
input wire notifier
|
||||
);
|
||||
always @(posedge CLK) Q <= D;
|
||||
endmodule
|
||||
|
||||
module gf180mcu_fd_sc_mcu7t5v0__dffrnq_1 (
|
||||
input wire CLK,
|
||||
input wire D,
|
||||
input wire RN,
|
||||
output reg Q,
|
||||
input wire notifier
|
||||
);
|
||||
always @(posedge CLK or negedge RN) begin
|
||||
if (!RN) Q <= 1'b0;
|
||||
else Q <= D;
|
||||
end
|
||||
endmodule
|
||||
|
||||
module gf180mcu_fd_sc_mcu7t5v0__dffsnq_1 (
|
||||
input wire CLK,
|
||||
input wire D,
|
||||
input wire SETN,
|
||||
output reg Q,
|
||||
input wire notifier
|
||||
);
|
||||
always @(posedge CLK or negedge SETN) begin
|
||||
if (!SETN) Q <= 1'b1;
|
||||
else Q <= D;
|
||||
end
|
||||
endmodule
|
||||
@@ -0,0 +1,47 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// retroSoC is licensed under Mulan PSL v2.
|
||||
// You may use this software according to the terms and conditions of the 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 OF ANY KIND,
|
||||
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
// See the Mulan PSL v2 for more details.
|
||||
|
||||
// Yosys needs the macro interface even though PDK simulation models are excluded
|
||||
// from the synthesis file list. The technology cell remains a black box.
|
||||
`ifdef SYNTHESIS
|
||||
`ifdef PDK_SKY130
|
||||
(* blackbox *)
|
||||
module sky130_fd_io__top_gpiov2 (
|
||||
input wire OUT,
|
||||
input wire OE_N,
|
||||
input wire HLD_H_N,
|
||||
input wire ENABLE_H,
|
||||
input wire ENABLE_INP_H,
|
||||
input wire ENABLE_VDDA_H,
|
||||
input wire ENABLE_VSWITCH_H,
|
||||
input wire ENABLE_VDDIO,
|
||||
input wire INP_DIS,
|
||||
input wire IB_MODE_SEL,
|
||||
input wire VTRIP_SEL,
|
||||
input wire SLOW,
|
||||
input wire HLD_OVR,
|
||||
input wire ANALOG_EN,
|
||||
input wire ANALOG_SEL,
|
||||
input wire ANALOG_POL,
|
||||
input wire [2:0] DM,
|
||||
inout wire PAD,
|
||||
inout wire PAD_A_NOESD_H,
|
||||
inout wire PAD_A_ESD_0_H,
|
||||
inout wire PAD_A_ESD_1_H,
|
||||
inout wire AMUXBUS_A,
|
||||
inout wire AMUXBUS_B,
|
||||
output wire IN,
|
||||
output wire IN_H,
|
||||
output wire TIE_HI_ESD,
|
||||
output wire TIE_LO_ESD
|
||||
);
|
||||
endmodule
|
||||
`endif
|
||||
`endif
|
||||
@@ -0,0 +1,79 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// retroSoC is licensed under Mulan PSL v2.
|
||||
// You may use this software according to the terms and conditions of the 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 OF ANY KIND,
|
||||
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
// See the Mulan PSL v2 for more details.
|
||||
|
||||
// The upstream Sky130 IO Verilog model uses switch primitives and drive strengths
|
||||
// unsupported by the active simulator. This pin-compatible functional model is
|
||||
// simulation-only; synthesis preserves the corresponding Sky130 PDK cell instance.
|
||||
module sky130_fd_io__top_gpiov2 (
|
||||
IN_H,
|
||||
PAD_A_NOESD_H,
|
||||
PAD_A_ESD_0_H,
|
||||
PAD_A_ESD_1_H,
|
||||
PAD,
|
||||
DM,
|
||||
HLD_H_N,
|
||||
IN,
|
||||
INP_DIS,
|
||||
IB_MODE_SEL,
|
||||
ENABLE_H,
|
||||
ENABLE_VDDA_H,
|
||||
ENABLE_INP_H,
|
||||
OE_N,
|
||||
TIE_HI_ESD,
|
||||
TIE_LO_ESD,
|
||||
SLOW,
|
||||
VTRIP_SEL,
|
||||
HLD_OVR,
|
||||
ANALOG_EN,
|
||||
ANALOG_SEL,
|
||||
ENABLE_VDDIO,
|
||||
ENABLE_VSWITCH_H,
|
||||
ANALOG_POL,
|
||||
OUT,
|
||||
AMUXBUS_A,
|
||||
AMUXBUS_B
|
||||
);
|
||||
input OUT;
|
||||
input OE_N;
|
||||
input HLD_H_N;
|
||||
input ENABLE_H;
|
||||
input ENABLE_INP_H;
|
||||
input ENABLE_VDDA_H;
|
||||
input ENABLE_VSWITCH_H;
|
||||
input ENABLE_VDDIO;
|
||||
input INP_DIS;
|
||||
input IB_MODE_SEL;
|
||||
input VTRIP_SEL;
|
||||
input SLOW;
|
||||
input HLD_OVR;
|
||||
input ANALOG_EN;
|
||||
input ANALOG_SEL;
|
||||
input ANALOG_POL;
|
||||
input [2:0] DM;
|
||||
inout PAD;
|
||||
inout PAD_A_NOESD_H;
|
||||
inout PAD_A_ESD_0_H;
|
||||
inout PAD_A_ESD_1_H;
|
||||
inout AMUXBUS_A;
|
||||
inout AMUXBUS_B;
|
||||
output IN;
|
||||
output IN_H;
|
||||
output TIE_HI_ESD;
|
||||
output TIE_LO_ESD;
|
||||
|
||||
wire s_output_enable;
|
||||
|
||||
assign s_output_enable = !OE_N && (DM != 3'b000) && (DM != 3'b001);
|
||||
assign PAD = s_output_enable ? OUT : 1'bz;
|
||||
assign IN = INP_DIS ? 1'b0 : PAD;
|
||||
assign IN_H = IN;
|
||||
assign TIE_HI_ESD = 1'b1;
|
||||
assign TIE_LO_ESD = 1'b0;
|
||||
endmodule
|
||||
+46
-8
@@ -46,10 +46,18 @@ module tc_clk_inv (
|
||||
);
|
||||
|
||||
`elsif PDK_GF180
|
||||
assign clk_o = ~clk_i;
|
||||
(* keep *) (* dont_touch = "true" *)
|
||||
gf180mcu_fd_sc_mcu7t5v0__clkinv_1 u_gf180mcu_fd_sc_mcu7t5v0__clkinv_1 (
|
||||
.I (clk_i),
|
||||
.ZN(clk_o)
|
||||
);
|
||||
|
||||
`elsif PDK_SKY130
|
||||
assign clk_o = ~clk_i;
|
||||
(* keep *) (* dont_touch = "true" *)
|
||||
sky130_fd_sc_hd__clkinv_1 u_sky130_fd_sc_hd__clkinv_1 (
|
||||
.A(clk_i),
|
||||
.Y(clk_o)
|
||||
);
|
||||
`endif
|
||||
|
||||
endmodule
|
||||
@@ -84,10 +92,18 @@ module tc_clk_buf (
|
||||
);
|
||||
|
||||
`elsif PDK_GF180
|
||||
assign clk_o = clk_i;
|
||||
(* keep *) (* dont_touch = "true" *)
|
||||
gf180mcu_fd_sc_mcu7t5v0__clkbuf_1 u_gf180mcu_fd_sc_mcu7t5v0__clkbuf_1 (
|
||||
.I(clk_i),
|
||||
.Z(clk_o)
|
||||
);
|
||||
|
||||
`elsif PDK_SKY130
|
||||
assign clk_o = clk_i;
|
||||
(* keep *) (* dont_touch = "true" *)
|
||||
sky130_fd_sc_hd__clkbuf_1 u_sky130_fd_sc_hd__clkbuf_1 (
|
||||
.A(clk_i),
|
||||
.X(clk_o)
|
||||
);
|
||||
`endif
|
||||
endmodule
|
||||
|
||||
@@ -129,10 +145,22 @@ module tc_clk_mux2 (
|
||||
);
|
||||
|
||||
`elsif PDK_GF180
|
||||
assign clk_o = clk_sel_i ? clk1_i : clk0_i;
|
||||
(* keep *) (* dont_touch = "true" *)
|
||||
gf180mcu_fd_sc_mcu7t5v0__mux2_1 u_gf180mcu_fd_sc_mcu7t5v0__mux2_1 (
|
||||
.I0(clk0_i),
|
||||
.I1(clk1_i),
|
||||
.S (clk_sel_i),
|
||||
.Z (clk_o)
|
||||
);
|
||||
|
||||
`elsif PDK_SKY130
|
||||
assign clk_o = clk_sel_i ? clk1_i : clk0_i;
|
||||
(* keep *) (* dont_touch = "true" *)
|
||||
sky130_fd_sc_hd__mux2_1 u_sky130_fd_sc_hd__mux2_1 (
|
||||
.A0(clk0_i),
|
||||
.A1(clk1_i),
|
||||
.S (clk_sel_i),
|
||||
.X (clk_o)
|
||||
);
|
||||
`endif
|
||||
endmodule
|
||||
|
||||
@@ -176,9 +204,19 @@ module tc_clk_xor2 (
|
||||
);
|
||||
|
||||
`elsif PDK_GF180
|
||||
assign clk_o = clk0_i ^ clk1_i;
|
||||
(* keep *) (* dont_touch = "true" *)
|
||||
gf180mcu_fd_sc_mcu7t5v0__xor2_1 u_gf180mcu_fd_sc_mcu7t5v0__xor2_1 (
|
||||
.A1(clk0_i),
|
||||
.A2(clk1_i),
|
||||
.Z (clk_o)
|
||||
);
|
||||
|
||||
`elsif PDK_SKY130
|
||||
assign clk_o = clk0_i ^ clk1_i;
|
||||
(* keep *) (* dont_touch = "true" *)
|
||||
sky130_fd_sc_hd__xor2_1 u_sky130_fd_sc_hd__xor2_1 (
|
||||
.A(clk0_i),
|
||||
.B(clk1_i),
|
||||
.X(clk_o)
|
||||
);
|
||||
`endif
|
||||
endmodule
|
||||
+178
-16
@@ -9,6 +9,92 @@
|
||||
// See the Mulan PSL v2 for more details.
|
||||
|
||||
|
||||
`ifdef PDK_GF180
|
||||
module tc_io_gf180_bi_pad (
|
||||
inout wire pad,
|
||||
input logic c2p,
|
||||
input logic c2p_en,
|
||||
output logic p2c,
|
||||
input logic cs,
|
||||
input logic pu,
|
||||
input logic pd
|
||||
);
|
||||
logic s_p2c;
|
||||
wire s_dvdd = 1'b1;
|
||||
wire s_dvss = 1'b0;
|
||||
wire s_vdd = 1'b1;
|
||||
wire s_vss = 1'b0;
|
||||
|
||||
(* keep *) (* dont_touch = "true" *)
|
||||
gf180mcu_fd_io__bi_t u_gf180mcu_fd_io__bi_t (
|
||||
.CS (cs),
|
||||
.SL (1'b0),
|
||||
.IE (~c2p_en),
|
||||
.OE (c2p_en),
|
||||
.PU (pu),
|
||||
.PD (pd),
|
||||
.A (c2p),
|
||||
.PDRV0(1'b0),
|
||||
.PDRV1(1'b0),
|
||||
.PAD (pad),
|
||||
.Y (s_p2c),
|
||||
.DVDD (s_dvdd),
|
||||
.DVSS (s_dvss),
|
||||
.VDD (s_vdd),
|
||||
.VSS (s_vss)
|
||||
);
|
||||
|
||||
// gf180mcu_fd_io__bi_t forbids simultaneous input and output enable.
|
||||
assign p2c = c2p_en ? c2p : s_p2c;
|
||||
endmodule
|
||||
`endif
|
||||
|
||||
`ifdef PDK_SKY130
|
||||
module tc_io_sky130_pad (
|
||||
inout wire pad,
|
||||
input logic c2p,
|
||||
input logic c2p_en,
|
||||
output logic p2c,
|
||||
input logic cs
|
||||
);
|
||||
logic s_p2c;
|
||||
|
||||
(* keep *) (* dont_touch = "true" *)
|
||||
sky130_fd_io__top_gpiov2 u_sky130_fd_io__top_gpiov2 (
|
||||
.OUT (c2p),
|
||||
.OE_N (~c2p_en),
|
||||
.HLD_H_N (1'b1),
|
||||
.INP_DIS (1'b0),
|
||||
.IB_MODE_SEL (1'b0),
|
||||
.ENABLE_H (1'b1),
|
||||
.ENABLE_VDDA_H (1'b0),
|
||||
.ENABLE_INP_H (1'b0),
|
||||
.ENABLE_VDDIO (1'b1),
|
||||
.ENABLE_VSWITCH_H(1'b0),
|
||||
.TIE_HI_ESD (),
|
||||
.TIE_LO_ESD (),
|
||||
.SLOW (1'b0),
|
||||
.VTRIP_SEL (cs),
|
||||
.HLD_OVR (1'b0),
|
||||
.ANALOG_EN (1'b0),
|
||||
.ANALOG_SEL (1'b0),
|
||||
.ANALOG_POL (1'b0),
|
||||
.DM (3'b110),
|
||||
.PAD (pad),
|
||||
.PAD_A_NOESD_H (),
|
||||
.PAD_A_ESD_0_H (),
|
||||
.PAD_A_ESD_1_H (),
|
||||
.IN (s_p2c),
|
||||
.IN_H (),
|
||||
.AMUXBUS_A (),
|
||||
.AMUXBUS_B ()
|
||||
);
|
||||
|
||||
assign p2c = s_p2c;
|
||||
endmodule
|
||||
`endif
|
||||
|
||||
|
||||
module tc_io_xtl_pad (
|
||||
input logic xi_pad,
|
||||
output logic xo_pad,
|
||||
@@ -20,10 +106,12 @@ module tc_io_xtl_pad (
|
||||
assign xo_pad = xi_pad;
|
||||
|
||||
`elsif PDK_SKY130
|
||||
// No qualified SKY130 crystal pad is selected. The Makefile rejects HAVE_PLL=YES.
|
||||
assign clk = en ? xi_pad : 1'b0;
|
||||
assign xo_pad = xi_pad;
|
||||
|
||||
`elsif PDK_GF180
|
||||
// No qualified GF180 crystal pad is selected. The Makefile rejects HAVE_PLL=YES.
|
||||
assign clk = en ? xi_pad : 1'b0;
|
||||
assign xo_pad = xi_pad;
|
||||
|
||||
@@ -68,10 +156,30 @@ module tc_io_in_pad (
|
||||
assign p2c = pad;
|
||||
|
||||
`elsif PDK_SKY130
|
||||
assign p2c = pad;
|
||||
tc_io_sky130_pad u_tc_io_sky130_pad (
|
||||
.pad (pad),
|
||||
.c2p (1'b0),
|
||||
.c2p_en(1'b0),
|
||||
.p2c (p2c),
|
||||
.cs (1'b0)
|
||||
);
|
||||
|
||||
`elsif PDK_GF180
|
||||
assign p2c = pad;
|
||||
wire s_dvdd = 1'b1;
|
||||
wire s_dvss = 1'b0;
|
||||
wire s_vdd = 1'b1;
|
||||
wire s_vss = 1'b0;
|
||||
(* keep *) (* dont_touch = "true" *)
|
||||
gf180mcu_fd_io__in_c u_gf180mcu_fd_io__in_c (
|
||||
.PU (1'b0),
|
||||
.PD (1'b0),
|
||||
.PAD (pad),
|
||||
.Y (p2c),
|
||||
.DVDD(s_dvdd),
|
||||
.DVSS(s_dvss),
|
||||
.VDD (s_vdd),
|
||||
.VSS (s_vss)
|
||||
);
|
||||
|
||||
`elsif PDK_IHP130
|
||||
(* keep *) (* dont_touch = "true" *)
|
||||
@@ -93,10 +201,26 @@ module tc_io_out_pad (
|
||||
assign pad = c2p;
|
||||
|
||||
`elsif PDK_SKY130
|
||||
assign pad = c2p;
|
||||
logic unused_p2c;
|
||||
tc_io_sky130_pad u_tc_io_sky130_pad (
|
||||
.pad (pad),
|
||||
.c2p (c2p),
|
||||
.c2p_en(1'b1),
|
||||
.p2c (unused_p2c),
|
||||
.cs (1'b0)
|
||||
);
|
||||
|
||||
`elsif PDK_GF180
|
||||
assign pad = c2p;
|
||||
logic unused_p2c;
|
||||
tc_io_gf180_bi_pad u_tc_io_gf180_bi_pad (
|
||||
.pad (pad),
|
||||
.c2p (c2p),
|
||||
.c2p_en(1'b1),
|
||||
.p2c (unused_p2c),
|
||||
.cs (1'b0),
|
||||
.pu (1'b0),
|
||||
.pd (1'b0)
|
||||
);
|
||||
|
||||
`elsif PDK_IHP130
|
||||
(* keep *) (* dont_touch = "true" *)
|
||||
@@ -121,12 +245,24 @@ module tc_io_tri_pad (
|
||||
assign p2c = pad;
|
||||
|
||||
`elsif PDK_SKY130
|
||||
assign pad = c2p_en ? c2p : 1'bz;
|
||||
assign p2c = pad;
|
||||
tc_io_sky130_pad u_tc_io_sky130_pad (
|
||||
.pad (pad),
|
||||
.c2p (c2p),
|
||||
.c2p_en(c2p_en),
|
||||
.p2c (p2c),
|
||||
.cs (1'b0)
|
||||
);
|
||||
|
||||
`elsif PDK_GF180
|
||||
assign pad = c2p_en ? c2p : 1'bz;
|
||||
assign p2c = pad;
|
||||
tc_io_gf180_bi_pad u_tc_io_gf180_bi_pad (
|
||||
.pad (pad),
|
||||
.c2p (c2p),
|
||||
.c2p_en(c2p_en),
|
||||
.p2c (p2c),
|
||||
.cs (1'b0),
|
||||
.pu (1'b0),
|
||||
.pd (1'b0)
|
||||
);
|
||||
|
||||
`elsif PDK_IHP130
|
||||
(* keep *) (* dont_touch = "true" *)
|
||||
@@ -180,12 +316,24 @@ module tc_io_tri_schmitt_pad (
|
||||
assign p2c = pad;
|
||||
|
||||
`elsif PDK_SKY130
|
||||
assign pad = c2p_en ? c2p : 1'bz;
|
||||
assign p2c = pad;
|
||||
tc_io_sky130_pad u_tc_io_sky130_pad (
|
||||
.pad (pad),
|
||||
.c2p (c2p),
|
||||
.c2p_en(c2p_en),
|
||||
.p2c (p2c),
|
||||
.cs (1'b1)
|
||||
);
|
||||
|
||||
`elsif PDK_GF180
|
||||
assign pad = c2p_en ? c2p : 1'bz;
|
||||
assign p2c = pad;
|
||||
tc_io_gf180_bi_pad u_tc_io_gf180_bi_pad (
|
||||
.pad (pad),
|
||||
.c2p (c2p),
|
||||
.c2p_en(c2p_en),
|
||||
.p2c (p2c),
|
||||
.cs (1'b1),
|
||||
.pu (1'b0),
|
||||
.pd (1'b0)
|
||||
);
|
||||
|
||||
`elsif PDK_IHP130
|
||||
(* keep *) (* dont_touch = "true" *)
|
||||
@@ -242,12 +390,26 @@ module tc_io_tri_full_pad (
|
||||
assign p2c = pad;
|
||||
|
||||
`elsif PDK_SKY130
|
||||
assign pad = c2p_en ? c2p : 1'bz;
|
||||
assign p2c = pad;
|
||||
logic [1:0] unused_pull;
|
||||
assign unused_pull = {pu, pd};
|
||||
tc_io_sky130_pad u_tc_io_sky130_pad (
|
||||
.pad (pad),
|
||||
.c2p (c2p),
|
||||
.c2p_en(c2p_en),
|
||||
.p2c (p2c),
|
||||
.cs (cs)
|
||||
);
|
||||
|
||||
`elsif PDK_GF180
|
||||
assign pad = c2p_en ? c2p : 1'bz;
|
||||
assign p2c = pad;
|
||||
tc_io_gf180_bi_pad u_tc_io_gf180_bi_pad (
|
||||
.pad (pad),
|
||||
.c2p (c2p),
|
||||
.c2p_en(c2p_en),
|
||||
.p2c (p2c),
|
||||
.cs (cs),
|
||||
.pu (pu),
|
||||
.pd (pd)
|
||||
);
|
||||
|
||||
`elsif PDK_IHP130
|
||||
logic [2:0] dum;
|
||||
|
||||
@@ -40,6 +40,7 @@ def validate_lock(data: dict[str, Any]) -> None:
|
||||
raise LockError(f"source {name} revision must be a full 40-character commit")
|
||||
_validate_url(f"source {name}", source["url"])
|
||||
_validate_relative_path(f"source {name} destination", source["destination"])
|
||||
_validate_source_submodules(name, source)
|
||||
for name, archive in data["archives"].items():
|
||||
_validate_archive("archive", name, archive)
|
||||
for platform, tools in data["toolchains"].items():
|
||||
@@ -60,6 +61,20 @@ def _validate_archive(kind: str, name: str, value: dict[str, Any]) -> None:
|
||||
_validate_relative_path(f"{kind} {name} destination", value["destination"])
|
||||
|
||||
|
||||
def _validate_source_submodules(name: str, value: dict[str, Any]) -> None:
|
||||
submodules = value.get("submodules")
|
||||
if submodules is None:
|
||||
return
|
||||
if value.get("recursive") is not True:
|
||||
raise LockError(f"source {name} submodules require recursive=true")
|
||||
if not isinstance(submodules, list) or not submodules:
|
||||
raise LockError(f"source {name} submodules must be a non-empty list")
|
||||
for submodule in submodules:
|
||||
if not isinstance(submodule, str):
|
||||
raise LockError(f"source {name} submodules must contain paths")
|
||||
_validate_relative_path(f"source {name} submodule", submodule)
|
||||
|
||||
|
||||
def _require_fields(kind: str, name: str, value: Any, fields: tuple[str, ...]) -> None:
|
||||
if not isinstance(value, dict):
|
||||
raise LockError(f"{kind} {name} must be an object")
|
||||
|
||||
@@ -34,6 +34,7 @@ def ensure_git_repo(
|
||||
revision: str,
|
||||
*,
|
||||
recursive: bool = False,
|
||||
submodules: tuple[str, ...] = (),
|
||||
update: bool = False,
|
||||
allow_dirty: bool = False,
|
||||
) -> None:
|
||||
@@ -67,10 +68,12 @@ def ensure_git_repo(
|
||||
raise RuntimeError(f"pinned dependency has local changes: {destination}")
|
||||
|
||||
if recursive:
|
||||
run(
|
||||
("git", "submodule", "update", "--init", "--recursive", "--depth", "1"),
|
||||
cwd=destination,
|
||||
)
|
||||
command: tuple[str, ...] = ("git", "submodule", "update", "--init", "--depth", "1")
|
||||
if submodules:
|
||||
command += ("--", *submodules)
|
||||
else:
|
||||
command += ("--recursive",)
|
||||
run(command, cwd=destination)
|
||||
print(f"[dependency] {destination.name}: {revision}")
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,251 @@
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
module tc_pdk_cells_tb;
|
||||
logic in_drive;
|
||||
logic in_drive_en;
|
||||
tri in_pad;
|
||||
logic in_p2c;
|
||||
|
||||
logic out_c2p;
|
||||
tri out_pad;
|
||||
|
||||
logic tri_c2p;
|
||||
logic tri_c2p_en;
|
||||
logic tri_drive;
|
||||
logic tri_drive_en;
|
||||
tri tri_pad;
|
||||
logic tri_p2c;
|
||||
|
||||
logic schmitt_c2p;
|
||||
logic schmitt_c2p_en;
|
||||
logic schmitt_drive;
|
||||
logic schmitt_drive_en;
|
||||
tri schmitt_pad;
|
||||
logic schmitt_p2c;
|
||||
|
||||
logic full_c2p;
|
||||
logic full_c2p_en;
|
||||
logic full_drive;
|
||||
logic full_drive_en;
|
||||
logic full_cs;
|
||||
logic full_pu;
|
||||
logic full_pd;
|
||||
tri full_pad;
|
||||
logic full_p2c;
|
||||
|
||||
logic clk0_i;
|
||||
logic clk1_i;
|
||||
logic clk_sel_i;
|
||||
logic clk_inv_o;
|
||||
logic clk_buf_o;
|
||||
logic clk_mux_o;
|
||||
logic clk_xor_o;
|
||||
|
||||
`ifdef PDK_GF180
|
||||
logic gf180_seq_clk;
|
||||
logic gf180_seq_d;
|
||||
logic gf180_seq_reset_n;
|
||||
logic gf180_dffq_q;
|
||||
logic gf180_dffrnq_q;
|
||||
logic gf180_dffsnq_q;
|
||||
|
||||
gf180mcu_fd_sc_mcu7t5v0__dffq_1 u_gf180_dffq (
|
||||
.CLK (gf180_seq_clk),
|
||||
.D (gf180_seq_d),
|
||||
.Q (gf180_dffq_q),
|
||||
.notifier()
|
||||
);
|
||||
|
||||
gf180mcu_fd_sc_mcu7t5v0__dffrnq_1 u_gf180_dffrnq (
|
||||
.CLK (gf180_seq_clk),
|
||||
.D (gf180_seq_d),
|
||||
.RN (gf180_seq_reset_n),
|
||||
.Q (gf180_dffrnq_q),
|
||||
.notifier()
|
||||
);
|
||||
|
||||
gf180mcu_fd_sc_mcu7t5v0__dffsnq_1 u_gf180_dffsnq (
|
||||
.CLK (gf180_seq_clk),
|
||||
.D (gf180_seq_d),
|
||||
.SETN (gf180_seq_reset_n),
|
||||
.Q (gf180_dffsnq_q),
|
||||
.notifier()
|
||||
);
|
||||
`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;
|
||||
assign full_pad = full_drive_en ? full_drive : 1'bz;
|
||||
|
||||
tc_io_in_pad u_tc_io_in_pad (
|
||||
.pad(in_pad),
|
||||
.p2c(in_p2c)
|
||||
);
|
||||
|
||||
tc_io_out_pad u_tc_io_out_pad (
|
||||
.pad(out_pad),
|
||||
.c2p(out_c2p)
|
||||
);
|
||||
|
||||
tc_io_tri_pad u_tc_io_tri_pad (
|
||||
.pad (tri_pad),
|
||||
.c2p (tri_c2p),
|
||||
.c2p_en(tri_c2p_en),
|
||||
.p2c (tri_p2c)
|
||||
);
|
||||
|
||||
tc_io_tri_schmitt_pad u_tc_io_tri_schmitt_pad (
|
||||
.pad (schmitt_pad),
|
||||
.c2p (schmitt_c2p),
|
||||
.c2p_en(schmitt_c2p_en),
|
||||
.p2c (schmitt_p2c)
|
||||
);
|
||||
|
||||
tc_io_tri_full_pad u_tc_io_tri_full_pad (
|
||||
.pad (full_pad),
|
||||
.c2p (full_c2p),
|
||||
.c2p_en(full_c2p_en),
|
||||
.p2c (full_p2c),
|
||||
.cs (full_cs),
|
||||
.pu (full_pu),
|
||||
.pd (full_pd)
|
||||
);
|
||||
|
||||
tc_clk_inv u_tc_clk_inv (
|
||||
.clk_i(clk0_i),
|
||||
.clk_o(clk_inv_o)
|
||||
);
|
||||
|
||||
tc_clk_buf u_tc_clk_buf (
|
||||
.clk_i(clk0_i),
|
||||
.clk_o(clk_buf_o)
|
||||
);
|
||||
|
||||
tc_clk_mux2 u_tc_clk_mux2 (
|
||||
.clk0_i (clk0_i),
|
||||
.clk1_i (clk1_i),
|
||||
.clk_sel_i(clk_sel_i),
|
||||
.clk_o (clk_mux_o)
|
||||
);
|
||||
|
||||
tc_clk_xor2 u_tc_clk_xor2 (
|
||||
.clk0_i(clk0_i),
|
||||
.clk1_i(clk1_i),
|
||||
.clk_o (clk_xor_o)
|
||||
);
|
||||
|
||||
task automatic expect_bit(input logic actual, input logic expected, input string message);
|
||||
if (actual !== expected) begin
|
||||
$fatal(1, "%s: expected %b, got %b", message, expected, actual);
|
||||
end
|
||||
endtask
|
||||
|
||||
initial begin
|
||||
in_drive = 1'b0;
|
||||
in_drive_en = 1'b0;
|
||||
out_c2p = 1'b0;
|
||||
tri_c2p = 1'b0;
|
||||
tri_c2p_en = 1'b0;
|
||||
tri_drive = 1'b0;
|
||||
tri_drive_en = 1'b0;
|
||||
schmitt_c2p = 1'b0;
|
||||
schmitt_c2p_en = 1'b0;
|
||||
schmitt_drive = 1'b0;
|
||||
schmitt_drive_en = 1'b0;
|
||||
full_c2p = 1'b0;
|
||||
full_c2p_en = 1'b0;
|
||||
full_drive = 1'b0;
|
||||
full_drive_en = 1'b0;
|
||||
full_cs = 1'b0;
|
||||
full_pu = 1'b0;
|
||||
full_pd = 1'b0;
|
||||
clk0_i = 1'b0;
|
||||
clk1_i = 1'b1;
|
||||
clk_sel_i = 1'b0;
|
||||
`ifdef PDK_GF180
|
||||
gf180_seq_clk = 1'b0;
|
||||
gf180_seq_d = 1'b0;
|
||||
gf180_seq_reset_n = 1'b0;
|
||||
`endif
|
||||
|
||||
#5;
|
||||
in_drive_en = 1'b1;
|
||||
in_drive = 1'b1;
|
||||
#5;
|
||||
expect_bit(in_p2c, 1'b1, "input pad propagation");
|
||||
|
||||
out_c2p = 1'b1;
|
||||
#5;
|
||||
expect_bit(out_pad, 1'b1, "output pad high drive");
|
||||
out_c2p = 1'b0;
|
||||
#5;
|
||||
expect_bit(out_pad, 1'b0, "output pad low drive");
|
||||
|
||||
tri_drive_en = 1'b1;
|
||||
tri_drive = 1'b1;
|
||||
#5;
|
||||
expect_bit(tri_p2c, 1'b1, "tri-state pad input");
|
||||
tri_drive_en = 1'b0;
|
||||
tri_c2p = 1'b1;
|
||||
tri_c2p_en = 1'b1;
|
||||
#5;
|
||||
expect_bit(tri_pad, 1'b1, "tri-state pad output");
|
||||
expect_bit(tri_p2c, 1'b1, "tri-state output readback");
|
||||
tri_c2p_en = 1'b0;
|
||||
#5;
|
||||
if (tri_pad !== 1'bz) begin
|
||||
$fatal(1, "tri-state pad did not release the line");
|
||||
end
|
||||
|
||||
schmitt_drive_en = 1'b1;
|
||||
schmitt_drive = 1'b1;
|
||||
#5;
|
||||
expect_bit(schmitt_p2c, 1'b1, "Schmitt pad input");
|
||||
schmitt_drive_en = 1'b0;
|
||||
schmitt_c2p = 1'b1;
|
||||
schmitt_c2p_en = 1'b1;
|
||||
#5;
|
||||
expect_bit(schmitt_pad, 1'b1, "Schmitt pad output");
|
||||
|
||||
full_drive_en = 1'b1;
|
||||
full_drive = 1'b1;
|
||||
full_cs = 1'b1;
|
||||
#5;
|
||||
expect_bit(full_p2c, 1'b1, "full pad input");
|
||||
full_drive_en = 1'b0;
|
||||
full_c2p = 1'b1;
|
||||
full_c2p_en = 1'b1;
|
||||
#5;
|
||||
expect_bit(full_pad, 1'b1, "full pad output");
|
||||
|
||||
#5;
|
||||
expect_bit(clk_inv_o, 1'b1, "clock inverter");
|
||||
expect_bit(clk_buf_o, 1'b0, "clock buffer");
|
||||
expect_bit(clk_mux_o, 1'b0, "clock mux select zero");
|
||||
expect_bit(clk_xor_o, 1'b1, "clock xor");
|
||||
clk_sel_i = 1'b1;
|
||||
clk0_i = 1'b1;
|
||||
clk1_i = 1'b0;
|
||||
#5;
|
||||
expect_bit(clk_inv_o, 1'b0, "clock inverter toggle");
|
||||
expect_bit(clk_buf_o, 1'b1, "clock buffer toggle");
|
||||
expect_bit(clk_mux_o, 1'b0, "clock mux select one");
|
||||
expect_bit(clk_xor_o, 1'b1, "clock xor toggle");
|
||||
|
||||
`ifdef PDK_GF180
|
||||
expect_bit(gf180_dffrnq_q, 1'b0, "GF180 reset-low DFF");
|
||||
expect_bit(gf180_dffsnq_q, 1'b1, "GF180 reset-high DFF");
|
||||
gf180_seq_reset_n = 1'b1;
|
||||
gf180_seq_d = 1'b1;
|
||||
gf180_seq_clk = 1'b1;
|
||||
#5;
|
||||
expect_bit(gf180_dffq_q, 1'b1, "GF180 DFF clock capture");
|
||||
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
|
||||
|
||||
$display("technology IO and clock cell test passed");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
@@ -34,6 +34,7 @@ from scripts.regress import ( # noqa: E402
|
||||
pdk_pr_commands,
|
||||
regression_environment,
|
||||
)
|
||||
from scripts import setup_helpers # noqa: E402
|
||||
from scripts.setup_helpers import download_file, ensure_git_repo # noqa: E402
|
||||
|
||||
|
||||
@@ -192,6 +193,44 @@ def test_dependency_helpers_are_idempotent(tmp_path: Path) -> None:
|
||||
assert downloaded.stat().st_mtime_ns == first_mtime
|
||||
|
||||
|
||||
def test_dependency_helper_limits_recursive_submodules(monkeypatch, tmp_path: Path) -> None:
|
||||
commands: list[tuple[str, ...]] = []
|
||||
revision = "a" * 40
|
||||
|
||||
def record(command, *, cwd=None) -> None:
|
||||
del cwd
|
||||
commands.append(tuple(command))
|
||||
|
||||
def git_output_stub(repo: Path, *args: str) -> str:
|
||||
del repo
|
||||
if args == ("rev-parse", "HEAD"):
|
||||
return revision
|
||||
if args == ("status", "--porcelain"):
|
||||
return ""
|
||||
raise AssertionError(f"unexpected git command: {args}")
|
||||
|
||||
monkeypatch.setattr(setup_helpers, "run", record)
|
||||
monkeypatch.setattr(setup_helpers, "git_output", git_output_stub)
|
||||
ensure_git_repo(
|
||||
"https://example.com/pdk.git",
|
||||
tmp_path / "pdk",
|
||||
revision,
|
||||
recursive=True,
|
||||
submodules=("libraries/sky130_fd_sc_hd/latest",),
|
||||
)
|
||||
|
||||
assert commands[-1] == (
|
||||
"git",
|
||||
"submodule",
|
||||
"update",
|
||||
"--init",
|
||||
"--depth",
|
||||
"1",
|
||||
"--",
|
||||
"libraries/sky130_fd_sc_hd/latest",
|
||||
)
|
||||
|
||||
|
||||
def test_make_dry_run_and_validation_do_not_write_filelists() -> None:
|
||||
def build_state() -> dict[str, tuple[int, int]]:
|
||||
build = ROOT / "build"
|
||||
@@ -255,6 +294,9 @@ def test_dependency_lock_and_config_key_include_a_fixed_timestamp(tmp_path: Path
|
||||
lock = load_lock(ROOT / "config/dependencies.lock.json")
|
||||
assert lock["schema_version"] == 1
|
||||
assert len(lock["sources"]["mpw"]["revision"]) == 40
|
||||
assert lock["sources"]["pdk_sky130"]["submodules"] == [
|
||||
"libraries/sky130_fd_sc_hd/latest"
|
||||
]
|
||||
|
||||
command = (
|
||||
sys.executable,
|
||||
@@ -292,6 +334,16 @@ def test_dependency_lock_and_config_key_include_a_fixed_timestamp(tmp_path: Path
|
||||
else:
|
||||
raise AssertionError("invalid dependency lock was accepted")
|
||||
|
||||
invalid_submodules = json.loads(json.dumps(lock))
|
||||
invalid_submodules["sources"]["pdk_sky130"]["submodules"] = ["../outside"]
|
||||
broken.write_text(json.dumps(invalid_submodules), encoding="utf-8")
|
||||
try:
|
||||
load_lock(broken)
|
||||
except LockError as error:
|
||||
assert "submodule" in str(error)
|
||||
else:
|
||||
raise AssertionError("invalid submodule path was accepted")
|
||||
|
||||
|
||||
def test_regression_runner_uses_one_build_timestamp(monkeypatch) -> None:
|
||||
monkeypatch.setenv("BUILD_TIMESTAMP", "2026-07-21-10-39")
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("profile", "pdk"),
|
||||
(
|
||||
("configs/ci/hazard3-rv32im-gf180.mk", "GF180"),
|
||||
("configs/ci/hazard3-rv32im-sky130.mk", "SKY130"),
|
||||
),
|
||||
)
|
||||
def test_unqualified_pll_profiles_are_rejected(profile: str, pdk: str) -> None:
|
||||
result = subprocess.run(
|
||||
("make", f"CONFIG={profile}", "HAVE_PLL=YES", "config"),
|
||||
cwd=ROOT,
|
||||
check=False,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
|
||||
assert result.returncode != 0
|
||||
assert f"HAVE_PLL=YES requires a qualified crystal pad and is unsupported for PDK={pdk}" in (
|
||||
result.stdout + result.stderr
|
||||
)
|
||||
Reference in new issue
Block a user