mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-04 22:32:36 +00:00
feat: Add support for SKY130 OpenRAM SRAM integration
- Introduced to handle the preparation of the SKY130 OpenRAM SRAM views. - Updated to download and prepare the SRAM archive during PDK setup. - Enhanced OpenSTA and Yosys configurations to accommodate SRAM macro integration. - Added Verilog simulation models for GF180 and SKY130 SRAM macros. - Implemented tests for SRAM setup and validation, ensuring correct integration and functionality. - Updated various Makefiles and scripts to support SRAM size and macro configurations.
This commit is contained in:
40 files changed
+749
-61
No files matched your search
@@ -57,4 +57,10 @@ Reserved" notice; its inclusion does not relicense it under Mulan PSL v2.
|
||||
|
||||
## 6. Notes on redistribution
|
||||
|
||||
The optional checksum-locked SKY130 SRAM artifact is generated with OpenRAM at
|
||||
the revision recorded in its manifest. OpenRAM is distributed under the BSD
|
||||
3-Clause License; the SkyWater-provided SRAM build-space used by the generator
|
||||
is distributed under Apache License 2.0. The artifact retains both exact
|
||||
license texts and is materialized only below the ignored `.cache/` tree.
|
||||
|
||||
The preserved third-party notices are included to maintain attribution for code that was adapted or reused in this repository. They do not replace the repository's main license declaration. The retroSoC project itself is distributed under the Mulan PSL v2 license.
|
||||
@@ -37,9 +37,9 @@ STA ?= NONE
|
||||
# HW
|
||||
PDK ?= IHP130
|
||||
HAVE_PLL ?= NO
|
||||
HAVE_SRAM_IF ?= NO
|
||||
HAVE_SRAM_MACRO ?= NO
|
||||
SRAM_SIZE_KIB ?= 128
|
||||
HAVE_SRAM_IF ?= $(if $(filter ICS55,$(PDK)),NO,YES)
|
||||
HAVE_SRAM_MACRO ?= $(if $(filter ICS55,$(PDK)),NO,YES)
|
||||
SRAM_SIZE_KIB ?= $(if $(filter ICS55,$(PDK)),128,32)
|
||||
PDK_BEHAV ?= NO
|
||||
HAVE_SVA ?= NO
|
||||
BUILD_RELEASE ?= NO
|
||||
@@ -161,6 +161,12 @@ $(call validate_value,APP,$(VALID_APP))
|
||||
$(call validate_value,LINK_TYPE,$(VALID_LINK_TYPE))
|
||||
$(call validate_value,COREMARK_MODE,$(VALID_COREMARK_MODE))
|
||||
|
||||
ifeq ($(HAVE_SRAM_MACRO),YES)
|
||||
ifneq ($(HAVE_SRAM_IF),YES)
|
||||
$(error HAVE_SRAM_MACRO=YES requires HAVE_SRAM_IF=YES)
|
||||
endif
|
||||
endif
|
||||
|
||||
JTAG_IDCODE_VALID := $(shell printf '%s' '$(JTAG_IDCODE)' | grep -E '^[[:xdigit:]]{8}$$')
|
||||
ifneq ($(JTAG_IDCODE_VALID),$(JTAG_IDCODE))
|
||||
$(error JTAG_IDCODE='$(JTAG_IDCODE)' must be exactly eight hexadecimal digits)
|
||||
@@ -364,7 +370,8 @@ config:
|
||||
doctor:
|
||||
@python3 $(ROOT_PATH)/scripts/doctor.py \
|
||||
--root $(ROOT_PATH) --simu $(SIMU) --synth $(SYNTH) --sta $(STA) \
|
||||
--pdk $(PDK) --formal $(FORMAL) --lock $(LOCK_FILE)
|
||||
--pdk $(PDK) --have-sram-macro $(HAVE_SRAM_MACRO) \
|
||||
--formal $(FORMAL) --lock $(LOCK_FILE)
|
||||
|
||||
benchmark-report: firmware
|
||||
|
||||
|
||||
@@ -12,5 +12,8 @@ The following third-party projects or authors are referenced in the RTL source h
|
||||
- Device simulation models: the models under rtl/model/ preserve their upstream
|
||||
notices, including the Winbond Electronics Corporation notice in the
|
||||
W25Q128JVxIM model.
|
||||
- SKY130 OpenRAM SRAM artifact: generated using OpenRAM under BSD-3-Clause and
|
||||
the SkyWater SRAM build-space under Apache-2.0. Both license texts and the
|
||||
exact source revisions are retained in the downloaded artifact manifest.
|
||||
|
||||
These notices are included solely to preserve attribution for the retained third-party source material. They do not alter the licensing terms of the retroSoC repository itself, which is distributed under the Mulan PSL v2 license.
|
||||
@@ -70,21 +70,24 @@ PDK, application, linker layout, and optional features as one reproducible
|
||||
configuration. The management core is fixed to Hazard3. The user-extension
|
||||
fabric exposes C0-C3 user-core slots and software selects one active user core.
|
||||
`SRAM_SIZE_KIB` selects a generated 4/16/32/64/128 KiB native-AXI4 on-chip
|
||||
SRAM window; committed profiles explicitly retain the 128 KiB default.
|
||||
SRAM window. The IHP130, GF180, and SKY130 CI profiles enable a 32 KiB macro-backed
|
||||
window; ICS55 keeps it absent. IHP130 benchmark/CoreMark profiles retain 128 KiB
|
||||
because their fixed data placement and SRAM-resident image require the larger capacity.
|
||||
|
||||
| Profile | ISA | Application | Coverage |
|
||||
| --- | --- | --- | --- |
|
||||
| [`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/ihp130.mk`](configs/ci/ihp130.mk) | RV32IM | `bringup` | Pull-request open-source regression with a 32 KiB IHP SRAM: 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, Icarus netlist, and OpenSTA coverage with a 32 KiB SRAM assembled from GF180 macros. |
|
||||
| [`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/sky130.mk`](configs/ci/sky130.mk) | RV32IM | `bringup` | Pull-request firmware, RTL simulation, Yosys, Icarus netlist, and OpenSTA coverage with a 32 KiB OpenRAM SRAM. |
|
||||
| [`configs/ci/ihp130-shell.mk`](configs/ci/ihp130-shell.mk) | RV32IM | `shell` | Pull-request firmware build with CSR support enabled. |
|
||||
| [`configs/ci/ihp130-debug.mk`](configs/ci/ihp130-debug.mk) | RV32IM | `debug` | Verilator remote-bitbang acceptance of the Hazard3 JTAG DTM, Debug Module, OpenOCD, and GDB. |
|
||||
| [`configs/benchmark/ihp130-hazard3-coremark.mk`](configs/benchmark/ihp130-hazard3-coremark.mk) | RV32IM | `coremark` | Fixed four-iteration SRAM CoreMark quick measurement, recorded by nightly IHP130 regression. |
|
||||
| [`configs/cluster/ics55.mk`](configs/cluster/ics55.mk) | RV32IM | `bringup` | Compatibility profile for site-specific ICS55 runs. |
|
||||
|
||||
CI Verilator firmware simulations explicitly select the `ci_smoke`
|
||||
application, which checks UART, archinfo APB readback, RNG fail-closed behavior, and test-status
|
||||
application, which checks UART, archinfo APB readback, macro-backed on-chip SRAM,
|
||||
RNG fail-closed behavior, and test-status
|
||||
completion without the verbose startup report. ARCHINFO checks include its
|
||||
ABI and the build/configuration identifiers generated for that variant. The profiles retain `bringup`
|
||||
as their default for manual diagnostics. To run the full report in Verilator,
|
||||
|
||||
@@ -39,6 +39,33 @@ static bool rs_ci_smoke_onchip_sram(void) {
|
||||
return (info.memory_bytes == 0U) && (info.bank_count == 0U);
|
||||
}
|
||||
|
||||
static bool rs_ci_smoke_onchip_sram_access(void) {
|
||||
#if RS_SOC_HAS_SRAM
|
||||
volatile uint8_t *const bytes = (volatile uint8_t *)(uintptr_t)RS_SOC_SRAM_BASE;
|
||||
volatile uint16_t *const halfs = (volatile uint16_t *)(uintptr_t)RS_SOC_SRAM_BASE;
|
||||
volatile uint32_t *const words = (volatile uint32_t *)(uintptr_t)RS_SOC_SRAM_BASE;
|
||||
volatile uint32_t *const last =
|
||||
(volatile uint32_t *)(uintptr_t)(RS_SOC_SRAM_BASE + RS_SOC_SRAM_SIZE - 4U);
|
||||
|
||||
words[0] = UINT32_C(0x11223344);
|
||||
if (words[0] != UINT32_C(0x11223344)) {
|
||||
return false;
|
||||
}
|
||||
bytes[1] = UINT8_C(0xA5);
|
||||
if (words[0] != UINT32_C(0x1122A544)) {
|
||||
return false;
|
||||
}
|
||||
halfs[1] = UINT16_C(0xBEEF);
|
||||
if (words[0] != UINT32_C(0xBEEFA544)) {
|
||||
return false;
|
||||
}
|
||||
*last = UINT32_C(0xCAFEF00D);
|
||||
return *last == UINT32_C(0xCAFEF00D);
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool rs_ci_smoke_user_ip(void) {
|
||||
rs_status_t status;
|
||||
uint32_t identifier = 0U;
|
||||
@@ -306,7 +333,7 @@ int main(void) {
|
||||
rs_test_finish(RS_TEST_FAILED, 1U);
|
||||
}
|
||||
printf("ci_smoke: archinfo passed\n");
|
||||
if (!rs_ci_smoke_onchip_sram()) {
|
||||
if (!rs_ci_smoke_onchip_sram() || !rs_ci_smoke_onchip_sram_access()) {
|
||||
rs_test_finish(RS_TEST_FAILED, 12U);
|
||||
}
|
||||
printf("ci_smoke: on-chip SRAM passed\n");
|
||||
|
||||
+9
-3
@@ -18,9 +18,15 @@ Start builds from a committed profile rather than setting an unreviewed mix of
|
||||
variables on the command line.
|
||||
|
||||
`SRAM_SIZE_KIB` selects 4, 16, 32, 64, or 128 KiB of on-chip SRAM and is part
|
||||
of the build variant key. Every committed profile sets 128 explicitly;
|
||||
profiles with `HAVE_SRAM_IF=NO` keep a reproducible capacity selection while
|
||||
the hardware capability reports the memory absent.
|
||||
of the build variant key. IHP130, GF180, and SKY130 CI profiles select eight
|
||||
4 KiB banks for 32 KiB total and enable both the interface and technology
|
||||
macro. ICS55 profiles keep the memory absent. IHP130 benchmark and CoreMark
|
||||
profiles explicitly retain 128 KiB for their fixed workload placement and
|
||||
SRAM-resident image.
|
||||
|
||||
`HAVE_SRAM_MACRO=YES` requires `HAVE_SRAM_IF=YES`. The generic manual defaults
|
||||
enable 32 KiB for IHP130, GF180, and SKY130 and keep ICS55 disabled; committed
|
||||
profiles remain the supported reproducible entry points.
|
||||
|
||||
`PDK_BEHAV=YES` selects technology-wrapper functional models for behavioral
|
||||
simulation. It is a simulation-only setting, participates in the build variant
|
||||
|
||||
+3
-3
@@ -1,9 +1,9 @@
|
||||
SOC := MINI
|
||||
PDK := GF180
|
||||
HAVE_PLL := NO
|
||||
HAVE_SRAM_IF := NO
|
||||
HAVE_SRAM_MACRO := NO
|
||||
SRAM_SIZE_KIB := 128
|
||||
HAVE_SRAM_IF := YES
|
||||
HAVE_SRAM_MACRO := YES
|
||||
SRAM_SIZE_KIB := 32
|
||||
HAVE_SVA := NO
|
||||
EXT_CLK_HZ := 72000000
|
||||
AUD_CLK_HZ := 18432000
|
||||
|
||||
@@ -3,7 +3,7 @@ PDK := IHP130
|
||||
HAVE_PLL := NO
|
||||
HAVE_SRAM_IF := YES
|
||||
HAVE_SRAM_MACRO := YES
|
||||
SRAM_SIZE_KIB := 128
|
||||
SRAM_SIZE_KIB := 32
|
||||
PDK_BEHAV := YES
|
||||
HAVE_SVA := NO
|
||||
EXT_CLK_HZ := 72000000
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
SOC := MINI
|
||||
PDK := IHP130
|
||||
HAVE_PLL := NO
|
||||
HAVE_SRAM_IF := NO
|
||||
HAVE_SRAM_MACRO := NO
|
||||
SRAM_SIZE_KIB := 128
|
||||
HAVE_SRAM_IF := YES
|
||||
HAVE_SRAM_MACRO := YES
|
||||
SRAM_SIZE_KIB := 32
|
||||
HAVE_SVA := NO
|
||||
EXT_CLK_HZ := 72000000
|
||||
AUD_CLK_HZ := 18432000
|
||||
|
||||
@@ -3,7 +3,7 @@ PDK := IHP130
|
||||
HAVE_PLL := NO
|
||||
HAVE_SRAM_IF := YES
|
||||
HAVE_SRAM_MACRO := YES
|
||||
SRAM_SIZE_KIB := 128
|
||||
SRAM_SIZE_KIB := 32
|
||||
PDK_BEHAV := YES
|
||||
HAVE_SVA := NO
|
||||
EXT_CLK_HZ := 72000000
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
SOC := MINI
|
||||
PDK := IHP130
|
||||
HAVE_PLL := NO
|
||||
HAVE_SRAM_IF := NO
|
||||
HAVE_SRAM_MACRO := NO
|
||||
SRAM_SIZE_KIB := 128
|
||||
HAVE_SRAM_IF := YES
|
||||
HAVE_SRAM_MACRO := YES
|
||||
SRAM_SIZE_KIB := 32
|
||||
HAVE_SVA := NO
|
||||
EXT_CLK_HZ := 72000000
|
||||
AUD_CLK_HZ := 18432000
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
SOC := MINI
|
||||
PDK := SKY130
|
||||
HAVE_PLL := NO
|
||||
HAVE_SRAM_IF := NO
|
||||
HAVE_SRAM_MACRO := NO
|
||||
SRAM_SIZE_KIB := 128
|
||||
HAVE_SRAM_IF := YES
|
||||
HAVE_SRAM_MACRO := YES
|
||||
SRAM_SIZE_KIB := 32
|
||||
HAVE_SVA := NO
|
||||
EXT_CLK_HZ := 72000000
|
||||
AUD_CLK_HZ := 18432000
|
||||
|
||||
Vendored
+6
@@ -14,3 +14,9 @@ python3 scripts/dependency_lock.py --lock dependencies/dependencies.lock.json
|
||||
|
||||
Then run the affected setup, doctor, test, and regression flow described in
|
||||
[Engineering Workflow](../docs/engineering.md).
|
||||
|
||||
The locked SKY130 OpenRAM SRAM archive is generated and published by the
|
||||
`retroSoC/artifact` workflow. `physical/pdk/setup.py` verifies its SHA-256,
|
||||
manifest, geometry, source revisions, generated-file hashes, and TT/SS views
|
||||
before materializing it below `.cache/retrosoc/pdk/sky130/openram/`. Generated
|
||||
Verilog, Liberty, LEF, GDS, and SPICE views are never committed here.
|
||||
Vendored
+6
@@ -82,6 +82,12 @@
|
||||
"destination": ".cache/retrosoc/downloads/pdk/ics55/ics55_LLSC_H7CR_liberty.tar.bz2",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"sky130_openram_sram_4kbyte_1rw_32x1024_8": {
|
||||
"url": "https://github.com/retroSoC/artifact/releases/download/openram-sky130_sram_4kbyte_1rw_32x1024_8-b2b069ce119d-24dfd2f0371c/sky130_sram_4kbyte_1rw_32x1024_8-openram-b2b069ce119d.tar.gz",
|
||||
"sha256": "75d987556561c7f3e9bc29e59b854849c2938c509c1b2e37906eb2af6aae211e",
|
||||
"destination": ".cache/retrosoc/downloads/pdk/sky130/sky130_sram_4kbyte_1rw_32x1024_8-openram-b2b069ce119d.tar.gz",
|
||||
"license": "LicenseRef-OpenRAM-SKY130-Mixed"
|
||||
},
|
||||
"serv": {
|
||||
"url": "https://github.com/olofk/serv/archive/refs/tags/1.4.0.tar.gz",
|
||||
"sha256": "f81c37b9f9d548c658e23bb7eb90fbed8b54e2e9e51fa42b8cd2f34cecc472ab",
|
||||
|
||||
+5
-2
@@ -15,7 +15,8 @@
|
||||
|
||||
Regression Verilator firmware simulations override the profiles' manual
|
||||
`bringup` default with `APP=ci_smoke`. This application verifies UART output,
|
||||
archinfo APB readback, RNG integration, SDRAM 8/16/32-bit mapped-window access,
|
||||
archinfo APB readback, on-chip SRAM first/last-word and 8/16/32-bit access,
|
||||
RNG integration, SDRAM 8/16/32-bit mapped-window access,
|
||||
and test-status completion within the CI time budget;
|
||||
`bringup` retains the full automatic application-information report for
|
||||
manual runs.
|
||||
@@ -41,7 +42,9 @@ completing the source-specific characterization and NIST SP 800-90B evidence.
|
||||
|
||||
OpenSTA runs a reproducible core-STA baseline for every CI PDK: IHP130 uses
|
||||
`slow_1p08V_125C`, GF180 uses `ss_125C_4v50`, ICS55 uses the H7CR
|
||||
`ss_1p08_125C` view, and SKY130 uses `ss_100C_1v40`.
|
||||
`ss_1p08_125C` view, and SKY130 uses `ss_100C_1v40`. Enabled SRAM macros use
|
||||
matching slow-corner Liberty views; the SKY130 SRAM view is analytically
|
||||
generated by the locked OpenRAM artifact.
|
||||
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,
|
||||
|
||||
+20
-9
@@ -37,10 +37,10 @@ cost-effective in the current one-owner-per-target fabric.
|
||||
## Configuration and address contract
|
||||
|
||||
`SRAM_SIZE_KIB` is part of the reproducible configuration digest and accepts
|
||||
only `4`, `16`, `32`, `64`, or `128`. Every committed profile sets `128`
|
||||
explicitly to preserve the prior address map. The address-map generator uses
|
||||
the selected value for RTL decode macros, SDK base/size/end constants, and the
|
||||
linker `LENGTH(SRAM)`.
|
||||
only `4`, `16`, `32`, `64`, or `128`. IHP130, GF180, and SKY130 CI profiles
|
||||
select `32`; ICS55 keeps the SRAM absent. IHP130 benchmark/CoreMark profiles
|
||||
retain `128`. The address-map generator uses the selected value for RTL decode
|
||||
macros, SDK base/size/end constants, and the linker `LENGTH(SRAM)`.
|
||||
|
||||
`HAVE_SRAM_IF=YES` marks the memory present and elaborates the bank array. When
|
||||
it is `NO`, the AXI target returns `DECERR`; the APB window remains readable
|
||||
@@ -111,10 +111,18 @@ the register parity test prevents drift without adding a generator.
|
||||
## Technology mapping
|
||||
|
||||
`tc_sram_1024x32` is the stable technology boundary. Behavioral simulation
|
||||
uses an inferred 1024-by-32 array. IHP130 maps to
|
||||
`RM_IHPSG13_1P_1024x32_c2_bm_bist`; the former 1024-by-64 mapping and discarded
|
||||
upper half are removed. ICS55 continues to map to its 1024-by-32 wrapper. Bank
|
||||
count, rather than technology depth or width, implements every product size.
|
||||
uses the Common byte-mask RAM model. IHP130 maps to
|
||||
`RM_IHPSG13_1P_1024x32_c2_bm_bist`. GF180 composes four byte lanes across two
|
||||
`gf180mcu_fd_ip_sram__sram512x8m8wm1` depth halves and registers the address
|
||||
high bit for synchronous read selection. SKY130 maps to the OpenRAM-generated
|
||||
`sky130_sram_4kbyte_1rw_32x1024_8`. Its Liberty-compatible logical boundary
|
||||
exports 32 data bits and hides OpenRAM's required physical spare column; a
|
||||
future physical adapter must tie the spare enable and spare input low. The
|
||||
required spare row expands the macro address port to 11 bits, so the wrapper
|
||||
ties its high bit low and exposes exactly logical addresses 0 through 1023.
|
||||
ICS55 retains its existing mapping but its supported profiles keep the macro
|
||||
disabled. Bank count, rather than technology depth or width, implements every
|
||||
product size.
|
||||
|
||||
The wrapper preserves byte masks and one-cycle synchronous reads. PDK timing,
|
||||
LEF/GDS placement, power hookup, BIST pins, and foundry signoff remain
|
||||
@@ -125,7 +133,10 @@ physical-flow responsibilities.
|
||||
`tests/test_onchip_ram.py` elaborates all five capacities and covers bank
|
||||
boundaries, first/last words, byte/half/word masks, `FIXED`, `INCR`, `WRAP`,
|
||||
16-beat continuous traffic, backpressure, AR/AW priority, absent-memory and
|
||||
malformed accesses, counters, and IHP130/ICS55 x32 wrapper polarity and masks.
|
||||
malformed accesses, counters, all four PDK wrapper polarities and masks, and
|
||||
the GF180 511/512 depth boundary. The setup tests independently validate the
|
||||
SKY130 artifact manifest and generated-file hashes. Full Verilator regression
|
||||
firmware exercises the first and last locations through the SoC interconnect.
|
||||
|
||||
`make CONFIG=configs/ci/ihp130.mk formal-onchip-ram` runs a 20-cycle bounded
|
||||
proof and cover set for AXI stability, channel exclusion, response bounds,
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2019, Regents of the University of California and The Board of
|
||||
Regents for the Oklahoma Agricultural and Mechanical College (acting for and
|
||||
on behalf of Oklahoma State University)
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -7,3 +7,8 @@ and `ATTRIBUTIONS.md`.
|
||||
Do not replace, remove, or rewrite a third-party notice when updating a
|
||||
dependency. Add the applicable license and attribution material in the same
|
||||
review as a new bundled component, and preserve upstream license text exactly.
|
||||
|
||||
The SKY130 OpenRAM SRAM dependency uses
|
||||
[`OpenRAM-BSD-3-Clause`](OpenRAM-BSD-3-Clause) and
|
||||
[`SKY130-OpenRAM-Mixed-NOTICE`](SKY130-OpenRAM-Mixed-NOTICE). Its downloaded
|
||||
artifact also contains the exact Apache-2.0 SkyWater build-space license.
|
||||
@@ -0,0 +1,18 @@
|
||||
SKY130 OpenRAM SRAM Artifact Notice
|
||||
|
||||
The checksum-locked SKY130 SRAM archive referenced by
|
||||
dependencies/dependencies.lock.json is generated by OpenRAM using the
|
||||
SkyWater-provided SKY130 SRAM build-space.
|
||||
|
||||
OpenRAM source:
|
||||
https://github.com/VLSIDA/OpenRAM
|
||||
BSD-3-Clause; the exact license text is retained in this directory and in the
|
||||
artifact as LICENSE.OpenRAM-BSD-3-Clause.
|
||||
|
||||
SkyWater SRAM build-space source:
|
||||
https://github.com/VLSIDA/sky130_fd_bd_sram
|
||||
Apache-2.0; the exact upstream license text is retained in the artifact as
|
||||
LICENSE.SkyWater-Apache-2.0.
|
||||
|
||||
The artifact manifest records the exact source revisions, logical geometry,
|
||||
characterization corners, generation policy, and generated-file checksums.
|
||||
@@ -158,4 +158,4 @@ librelane-package:
|
||||
+$(MAKE) LIBRELANE_TARGET=chip librelane-package-run
|
||||
|
||||
librelane-core-package:
|
||||
+$(MAKE) LIBRELANE_TARGET=core librelane-package-run
|
||||
+$(MAKE) LIBRELANE_TARGET=core librelane-package-run
|
||||
+21
-3
@@ -21,10 +21,13 @@ 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
|
||||
at TT and slow corners. Derived Liberty files are stored below
|
||||
at TT and slow corners. It also downloads the checksum-locked OpenRAM
|
||||
`sky130_sram_4kbyte_1rw_32x1024_8` artifact and validates its source manifest,
|
||||
logical geometry, generated-file hashes, TT 1.8 V/25 C Liberty, and SS
|
||||
1.4 V/100 C Liberty. Derived and generated views are stored below
|
||||
`.cache/retrosoc/pdk/` and are not committed. SKY130 setup initializes only
|
||||
the locked HD library submodule; the remaining upstream libraries are outside
|
||||
the SoC integration boundary.
|
||||
the locked HD library submodule; OpenRAM's build-space and Ciel inputs are
|
||||
recorded in the macro artifact rather than added to the SoC PDK checkout.
|
||||
|
||||
The IHP130 dependency is also the technology source for the independent
|
||||
`physical/librelane/` core-hardening and full-chip pad-ring flows. The locked
|
||||
@@ -58,3 +61,18 @@ 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.
|
||||
|
||||
GF180 implements each logical `1024 x 32` SRAM bank with eight public
|
||||
`512 x 8` macros: four byte lanes across two address-depth halves. SKY130 uses
|
||||
one OpenRAM logical `1024 x 32` macro per bank. The Liberty-compatible wrapper
|
||||
hides its required physical spare column, and its spare row remains outside the
|
||||
logical address space. A future physical adapter must tie the spare enable and
|
||||
spare input low. The wrapper also fixes the generated 11-bit address port's
|
||||
high bit low to expose words 0 through 1023. Fast logical models are used for
|
||||
RTL and functional netlist simulation, while Yosys and OpenSTA consume the
|
||||
real macro Liberty views.
|
||||
|
||||
The SKY130 artifact uses analytical characterization and does not gate release
|
||||
on OpenRAM DRC/LVS. Its LEF/GDS/SPICE files are development collateral, not
|
||||
foundry-qualified or production-signoff evidence. GF180/SKY130 still lack
|
||||
project-owned full-chip placement, extraction, DRC, and LVS adapters.
|
||||
@@ -0,0 +1,136 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
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
|
||||
|
||||
|
||||
MACRO = "sky130_sram_4kbyte_1rw_32x1024_8"
|
||||
OPENRAM_COMMIT = "b2b069ce119d1488cbe6883b2240bceb5c7ce29a"
|
||||
INPUT_CONFIG_SHA256 = "24dfd2f0371c6007015ccd825d13f5227a5cc7ffb158bc0ce35d4a62aa2fc646"
|
||||
SKY130_CIEL_REVISION = "e8294524e5f67c533c5d0c3afa0bcc5b2a5fa066"
|
||||
SKY130_BUILDSPACE_REVISION = "dd64256961317205343a3fd446908b42bafba388"
|
||||
EXPECTED_GEOMETRY = {
|
||||
"words": 1024,
|
||||
"data_bits": 32,
|
||||
"write_granularity_bits": 8,
|
||||
"read_write_ports": 1,
|
||||
"spare_rows": 1,
|
||||
"spare_columns": 1,
|
||||
}
|
||||
EXPECTED_CORNERS = ["TT_1p8V_25C", "SS_1p4V_100C"]
|
||||
REQUIRED_FILES = (
|
||||
f"{MACRO}.v",
|
||||
f"{MACRO}.lef",
|
||||
f"{MACRO}.gds",
|
||||
f"{MACRO}.sp",
|
||||
f"{MACRO}.lvs.sp",
|
||||
f"{MACRO}.html",
|
||||
f"{MACRO}.py",
|
||||
f"{MACRO}_TT_1p8V_25C.lib",
|
||||
f"{MACRO}_SS_1p4V_100C.lib",
|
||||
"INPUT_CONFIG.py",
|
||||
"LICENSE.OpenRAM-BSD-3-Clause",
|
||||
"LICENSE.SkyWater-Apache-2.0",
|
||||
"SHA256SUMS",
|
||||
"manifest.json",
|
||||
)
|
||||
|
||||
|
||||
def load_manifest(source: Path) -> dict[str, Any]:
|
||||
manifest_path = source / "manifest.json"
|
||||
try:
|
||||
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
|
||||
except (OSError, json.JSONDecodeError) as error:
|
||||
raise RuntimeError(f"cannot read SKY130 SRAM manifest: {error}") from error
|
||||
if not isinstance(manifest, dict):
|
||||
raise RuntimeError("SKY130 SRAM manifest must be an object")
|
||||
return manifest
|
||||
|
||||
|
||||
def validate_generated_sram(source: Path) -> None:
|
||||
missing = [name for name in REQUIRED_FILES if not (source / name).is_file()]
|
||||
if missing:
|
||||
raise RuntimeError("SKY130 SRAM archive is missing: " + ", ".join(missing))
|
||||
|
||||
manifest = load_manifest(source)
|
||||
expected = {
|
||||
"schema_version": 1,
|
||||
"macro": MACRO,
|
||||
"geometry": EXPECTED_GEOMETRY,
|
||||
"corners": EXPECTED_CORNERS,
|
||||
"openram_commit": OPENRAM_COMMIT,
|
||||
"input_config_sha256": INPUT_CONFIG_SHA256,
|
||||
"sky130_ciel_revision": SKY130_CIEL_REVISION,
|
||||
"sky130_buildspace_revision": SKY130_BUILDSPACE_REVISION,
|
||||
"analytical_characterization": True,
|
||||
"drc_lvs_checked": False,
|
||||
}
|
||||
for key, value in expected.items():
|
||||
if manifest.get(key) != value:
|
||||
raise RuntimeError(
|
||||
f"SKY130 SRAM manifest {key}={manifest.get(key)!r}, expected {value!r}"
|
||||
)
|
||||
|
||||
file_hashes = manifest.get("files")
|
||||
if not isinstance(file_hashes, dict) or not file_hashes:
|
||||
raise RuntimeError("SKY130 SRAM manifest has no generated-file hashes")
|
||||
for name, expected_hash in file_hashes.items():
|
||||
path = source / name
|
||||
if not isinstance(name, str) or not isinstance(expected_hash, str) or not path.is_file():
|
||||
raise RuntimeError(f"invalid SKY130 SRAM manifest file entry: {name!r}")
|
||||
actual_hash = sha256(path)
|
||||
if actual_hash != expected_hash:
|
||||
raise RuntimeError(
|
||||
f"SKY130 SRAM generated-file checksum mismatch for {name}: "
|
||||
f"{actual_hash}, expected {expected_hash}"
|
||||
)
|
||||
|
||||
|
||||
def prepare(archive: Path, output_dir: Path, archive_sha256: str) -> None:
|
||||
complete = output_dir / ".complete"
|
||||
if complete.is_file() and complete.read_text(encoding="utf-8").strip() == archive_sha256:
|
||||
validate_generated_sram(output_dir)
|
||||
print(f"SKY130 OpenRAM SRAM is ready: {output_dir}")
|
||||
return
|
||||
|
||||
output_dir.parent.mkdir(parents=True, exist_ok=True)
|
||||
with tempfile.TemporaryDirectory(prefix="sky130-openram-", dir=output_dir.parent) as temp:
|
||||
extracted = Path(temp) / "extracted"
|
||||
extracted.mkdir()
|
||||
safe_extract(archive, extracted)
|
||||
validate_generated_sram(extracted)
|
||||
atomic_write(extracted / ".complete", archive_sha256 + "\n")
|
||||
candidate = Path(temp) / "candidate"
|
||||
os.replace(extracted, candidate)
|
||||
if output_dir.exists():
|
||||
shutil.rmtree(output_dir)
|
||||
os.replace(candidate, output_dir)
|
||||
print(f"SKY130 OpenRAM SRAM is ready: {output_dir}")
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description="Prepare the locked SKY130 OpenRAM SRAM views")
|
||||
parser.add_argument("--archive", type=Path, required=True)
|
||||
parser.add_argument("--output-dir", type=Path, required=True)
|
||||
parser.add_argument("--archive-sha256", required=True)
|
||||
args = parser.parse_args()
|
||||
prepare(args.archive.resolve(), args.output_dir.resolve(), args.archive_sha256)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -102,6 +102,28 @@ def main() -> int:
|
||||
),
|
||||
check=True,
|
||||
)
|
||||
sram = archive("sky130_openram_sram_4kbyte_1rw_32x1024_8")
|
||||
sram_archive = ROOT / sram["destination"]
|
||||
download_file(
|
||||
sram["url"],
|
||||
sram_archive,
|
||||
sram["sha256"],
|
||||
update=args.update,
|
||||
timeout=120,
|
||||
)
|
||||
subprocess.run(
|
||||
(
|
||||
sys.executable,
|
||||
str(PDK_DIR / "prepare_sky130_sram.py"),
|
||||
"--archive",
|
||||
str(sram_archive),
|
||||
"--output-dir",
|
||||
str(ROOT / ".cache/retrosoc/pdk/sky130/openram"),
|
||||
"--archive-sha256",
|
||||
sram["sha256"],
|
||||
),
|
||||
check=True,
|
||||
)
|
||||
subprocess.run(
|
||||
(
|
||||
sys.executable,
|
||||
|
||||
@@ -26,6 +26,14 @@ sta: $(OPENSTA_SDC) | manifest
|
||||
echo "OpenSTA netlist configuration does not match PDK=$(PDK); rerun synthesis" >&2; \
|
||||
exit 1; \
|
||||
}
|
||||
@grep -qx 'HAVE_SRAM_MACRO=$(HAVE_SRAM_MACRO)' $(OPENSTA_CONFIG) || { \
|
||||
echo "OpenSTA netlist SRAM macro configuration mismatch; rerun synthesis" >&2; \
|
||||
exit 1; \
|
||||
}
|
||||
@grep -qx 'SRAM_SIZE_KIB=$(SRAM_SIZE_KIB)' $(OPENSTA_CONFIG) || { \
|
||||
echo "OpenSTA netlist SRAM capacity mismatch; rerun synthesis" >&2; \
|
||||
exit 1; \
|
||||
}
|
||||
python3 $(ROOT_PATH)/scripts/run_flow.py --tool opensta --log $(OPENSTA_LOG) \
|
||||
--result $(STA_BUILD_ROOT)/result-sta.json \
|
||||
--env OPENSTA_NETLIST=$(OPENSTA_NETLIST) --env OPENSTA_LIBERTY=$(OPENSTA_LIBERTY) \
|
||||
|
||||
@@ -14,9 +14,15 @@ endif
|
||||
else ifeq ($(PDK),GF180)
|
||||
OPENSTA_LIBERTY := $(ROOT_PATH)/.cache/retrosoc/pdk/gf180/gf180mcu_fd_sc_mcu7t5v0__ss_125C_4v50.lib
|
||||
OPENSTA_LINK_LIBS := $(ROOT_PATH)/.cache/retrosoc/pdk/gf180/gf180mcu_fd_io_retrosoc__ss_125C_4v50.lib
|
||||
ifeq ($(HAVE_SRAM_MACRO),YES)
|
||||
OPENSTA_SRAM_LIBS := $(ROOT_PATH)/physical/pdk/gf180mcu-pdk/macros/gf180mcu_fd_ip_sram/latest/cells/gf180mcu_fd_ip_sram__sram512x8m8wm1/gf180mcu_fd_ip_sram__sram512x8m8wm1__ss_125C_4v50.lib
|
||||
endif
|
||||
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)/physical/smoke/sta/opensta/sky130_io_blackbox.liberty
|
||||
ifeq ($(HAVE_SRAM_MACRO),YES)
|
||||
OPENSTA_SRAM_LIBS := $(ROOT_PATH)/.cache/retrosoc/pdk/sky130/openram/sky130_sram_4kbyte_1rw_32x1024_8_SS_1p4V_100C.lib
|
||||
endif
|
||||
else ifeq ($(PDK),ICS55)
|
||||
OPENSTA_LIBERTY := $(ROOT_PATH)/.cache/retrosoc/pdk/ics55/ics55_h7cr_ss.lib
|
||||
OPENSTA_LINK_LIBS := $(ROOT_PATH)/physical/pdk/icsprout55-pdk/IP/IO/ICsprout_55LLULP1233_IO_251013/liberty/ICSIOA_N55_3P3_ss_1p08_2p97_125c.lib
|
||||
|
||||
@@ -22,13 +22,20 @@ set root_dir [file normalize [file join [file dirname [info script]] ../../../..
|
||||
|
||||
puts "0. Executing init_tech: load technology from Github PDK"
|
||||
|
||||
set have_sram_macro [expr {
|
||||
[info exists ::env(HAVE_SRAM_MACRO)] && $::env(HAVE_SRAM_MACRO) eq "YES"
|
||||
}]
|
||||
|
||||
if {$pdk == "IHP130"} {
|
||||
set pdk_dir "$root_dir/physical/pdk/IHP-Open-PDK"
|
||||
set pdk_cells_lib ${pdk_dir}/ihp-sg13g2/libs.ref/sg13g2_stdcell/lib
|
||||
set pdk_sram_lib ${pdk_dir}/ihp-sg13g2/libs.ref/sg13g2_sram/lib
|
||||
set pdk_io_lib ${pdk_dir}/ihp-sg13g2/libs.ref/sg13g2_io/lib
|
||||
set tech_cells [list "$pdk_cells_lib/sg13g2_stdcell_typ_1p20V_25C.lib"]
|
||||
set tech_macros [glob -nocomplain -directory $pdk_sram_lib *_typ_1p20V_25C.lib]
|
||||
set tech_macros [list]
|
||||
if {$have_sram_macro} {
|
||||
set tech_macros [glob -nocomplain -directory $pdk_sram_lib *_typ_1p20V_25C.lib]
|
||||
}
|
||||
lappend tech_macros "$pdk_io_lib/sg13g2_io_typ_1p2V_3p3V_25C.lib"
|
||||
# for hilomap
|
||||
set tech_cell_tiehi {sg13g2_tiehi L_HI}
|
||||
@@ -47,9 +54,13 @@ if {$pdk == "IHP130"} {
|
||||
set abc_driver BUFX4H7R
|
||||
set abc_load 6.0
|
||||
} elseif {$pdk == "GF180"} {
|
||||
set pdk_sram_lib "$root_dir/physical/pdk/gf180mcu-pdk/macros/gf180mcu_fd_ip_sram/latest/cells/gf180mcu_fd_ip_sram__sram512x8m8wm1"
|
||||
set pdk_cells_lib "$root_dir/.cache/retrosoc/pdk/gf180"
|
||||
set tech_cells [list "$pdk_cells_lib/gf180mcu_fd_sc_mcu7t5v0__tt_025C_5v00.lib"]
|
||||
set tech_macros [list]
|
||||
if {$have_sram_macro} {
|
||||
lappend tech_macros "$pdk_sram_lib/gf180mcu_fd_ip_sram__sram512x8m8wm1__tt_025C_5v00.lib"
|
||||
}
|
||||
# The aggregate GF180 Liberty does not characterize the available tie cells.
|
||||
# Keep constants as logic instead of mapping them to an uncharacterized cell.
|
||||
set tech_cell_tiehi {}
|
||||
@@ -58,8 +69,12 @@ if {$pdk == "IHP130"} {
|
||||
set abc_load 13.43
|
||||
} elseif {$pdk == "SKY130"} {
|
||||
set pdk_cells_lib "$root_dir/.cache/retrosoc/pdk/sky130"
|
||||
set pdk_sram_lib "$pdk_cells_lib/openram"
|
||||
set tech_cells [list "$pdk_cells_lib/sky130_fd_sc_hd__tt_025C_1v80.lib"]
|
||||
set tech_macros [list]
|
||||
if {$have_sram_macro} {
|
||||
lappend tech_macros "$pdk_sram_lib/sky130_sram_4kbyte_1rw_32x1024_8_TT_1p8V_25C.lib"
|
||||
}
|
||||
set tech_cell_tiehi {sky130_fd_sc_hd__conb_1 HI}
|
||||
set tech_cell_tielo {sky130_fd_sc_hd__conb_1 LO}
|
||||
set abc_driver sky130_fd_sc_hd__buf_1
|
||||
|
||||
@@ -170,5 +170,7 @@ puts $config_file "SOC=$soc"
|
||||
puts $config_file "TOP_DESIGN=$top_design"
|
||||
puts $config_file "SYNTH_RECIPE=$synth_recipe"
|
||||
puts $config_file "PERIOD_PS=$period_ps"
|
||||
puts $config_file "HAVE_SRAM_MACRO=$::env(HAVE_SRAM_MACRO)"
|
||||
puts $config_file "SRAM_SIZE_KIB=$::env(SRAM_SIZE_KIB)"
|
||||
close $config_file
|
||||
file rename -force $config_tmp $config
|
||||
@@ -64,6 +64,7 @@ $(NETLIST): $(SV_FLIST) $(YOSYS_SCRIPTS)
|
||||
python3 $(ROOT_PATH)/scripts/run_flow.py --tool yosys \
|
||||
--log $(YOSYS_BUILD)/$(RTL_NAME).log --result $(YOSYS_BUILD)/result-synth.json \
|
||||
--env PDK=$(PDK) --env SOC=$(SOC) --env SYNTH_RECIPE=$(SYNTH_RECIPE) \
|
||||
--env HAVE_SRAM_MACRO=$(HAVE_SRAM_MACRO) --env SRAM_SIZE_KIB=$(SRAM_SIZE_KIB) \
|
||||
--env YOSYS_TARGET_PERIOD_PS=$(YOSYS_TARGET_PERIOD_PS) \
|
||||
--env SV_FLIST=$(SV_FLIST) --env TOP_DESIGN=$(TOP_DESIGN) --env CONFIG=$(NETLIST_CONFIG) \
|
||||
--env PROJ_NAME=$(RTL_NAME) --env WORK=$(YOSYS_TMP) --env BUILD=$(YOSYS_OUT) \
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# Technology wrappers instantiate these models directly in RTL simulation.
|
||||
/tech/gf180_io_sim_cells.v
|
||||
/tech/gf180_seq_sim_cells.v
|
||||
/tech/gf180_sram_sim_cells.sv
|
||||
/physical/pdk/gf180mcu-pdk/libraries/gf180mcu_fd_sc_mcu7t5v0/latest/cells/clkbuf/gf180mcu_fd_sc_mcu7t5v0__clkbuf_1.functional.v
|
||||
/physical/pdk/gf180mcu-pdk/libraries/gf180mcu_fd_sc_mcu7t5v0/latest/cells/clkinv/gf180mcu_fd_sc_mcu7t5v0__clkinv_1.functional.v
|
||||
/physical/pdk/gf180mcu-pdk/libraries/gf180mcu_fd_sc_mcu7t5v0/latest/cells/mux2/gf180mcu_fd_sc_mcu7t5v0__mux2_1.functional.v
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
+incdir+/physical/pdk/skywater-pdk/libraries/sky130_fd_sc_hd/latest/cells/mux2
|
||||
+incdir+/physical/pdk/skywater-pdk/libraries/sky130_fd_sc_hd/latest/cells/xor2
|
||||
/tech/sky130_io_sim_cells.v
|
||||
/clusterip/common/rtl/tech/ram.sv
|
||||
/tech/sky130_sram_sim_cells.sv
|
||||
/physical/pdk/skywater-pdk/libraries/sky130_fd_sc_hd/latest/cells/clkbuf/sky130_fd_sc_hd__clkbuf_1.v
|
||||
/physical/pdk/skywater-pdk/libraries/sky130_fd_sc_hd/latest/cells/clkinv/sky130_fd_sc_hd__clkinv_1.v
|
||||
/physical/pdk/skywater-pdk/libraries/sky130_fd_sc_hd/latest/cells/mux2/sky130_fd_sc_hd__mux2_1.v
|
||||
|
||||
@@ -111,7 +111,8 @@ sim: comp
|
||||
debug-sim: comp firmware
|
||||
@test "$(SIMU)" = VERILATOR || { echo "debug-sim requires SIMU=VERILATOR" >&2; exit 2; }
|
||||
$(FLOW_PYTHON) $(ROOT_PATH)/scripts/doctor.py --root $(ROOT_PATH) --simu $(SIMU) \
|
||||
--synth $(SYNTH) --sta $(STA) --pdk $(PDK) --formal $(FORMAL) \
|
||||
--synth $(SYNTH) --sta $(STA) --pdk $(PDK) --have-sram-macro $(HAVE_SRAM_MACRO) \
|
||||
--formal $(FORMAL) \
|
||||
--require-debug-tools --lock $(LOCK_FILE)
|
||||
python3 $(DEBUG_SIM_SESSION) \
|
||||
--emulator $(VERILATOR_EMU) \
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// retroSoC is licensed under Mulan PSL v2.
|
||||
// You can use this software according to the terms and conditions of 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 FIT FOR A PARTICULAR PURPOSE.
|
||||
// See the Mulan PSL v2 for more details.
|
||||
|
||||
// Pin-compatible functional model for the GF180 512x8 bit-write SRAM macro.
|
||||
/* verilator lint_off DECLFILENAME */
|
||||
module gf180mcu_fd_ip_sram__sram512x8m8wm1 (
|
||||
// verilog_format: off -- preserve the PDK memory interface columns
|
||||
input logic CLK,
|
||||
input logic CEN,
|
||||
input logic GWEN,
|
||||
input logic [7:0] WEN,
|
||||
input logic [8:0] A,
|
||||
input logic [7:0] D,
|
||||
output logic [7:0] Q,
|
||||
inout wire VDD,
|
||||
inout wire VSS
|
||||
// verilog_format: on
|
||||
);
|
||||
logic [7:0] s_storage_q[0:511];
|
||||
|
||||
always_ff @(posedge CLK) begin
|
||||
if (!CEN && (VDD !== 1'b0) && (VSS !== 1'b1)) begin
|
||||
if (GWEN) begin
|
||||
Q <= s_storage_q[A];
|
||||
end else begin
|
||||
for (int unsigned bit_index = 0; bit_index < 8; bit_index++) begin
|
||||
if (!WEN[bit_index]) begin
|
||||
s_storage_q[A][bit_index] <= D[bit_index];
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
/* verilator lint_on DECLFILENAME */
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// retroSoC is licensed under Mulan PSL v2.
|
||||
// You can use this software according to the terms and conditions of 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 FIT FOR A PARTICULAR PURPOSE.
|
||||
// See the Mulan PSL v2 for more details.
|
||||
|
||||
// Liberty-compatible fast model for the OpenRAM-generated SKY130 1024x32 macro.
|
||||
/* verilator lint_off DECLFILENAME */
|
||||
module sky130_sram_4kbyte_1rw_32x1024_8 (
|
||||
// verilog_format: off -- preserve the OpenRAM memory interface columns
|
||||
`ifdef USE_POWER_PINS
|
||||
inout wire vccd1,
|
||||
inout wire vssd1,
|
||||
`endif
|
||||
input logic clk0,
|
||||
input logic csb0,
|
||||
input logic web0,
|
||||
input logic [ 3:0] wmask0,
|
||||
input logic [10:0] addr0,
|
||||
input logic [31:0] din0,
|
||||
output logic [31:0] dout0
|
||||
// verilog_format: on
|
||||
);
|
||||
logic s_disable;
|
||||
|
||||
`ifdef USE_POWER_PINS
|
||||
assign s_disable = csb0 || !vccd1 || vssd1;
|
||||
`else
|
||||
assign s_disable = csb0;
|
||||
`endif
|
||||
|
||||
tech_ram_bm #(
|
||||
.BIT_WIDTH (32),
|
||||
.WORD_DEPTH(1024)
|
||||
) u_tech_ram_bm (
|
||||
.clk_i (clk0),
|
||||
.en_i (s_disable),
|
||||
.wen_i (web0),
|
||||
.bm_i (~wmask0),
|
||||
.addr_i(addr0[9:0]),
|
||||
.dat_i (din0),
|
||||
.dat_o (dout0)
|
||||
);
|
||||
endmodule
|
||||
/* verilator lint_on DECLFILENAME */
|
||||
+86
-17
@@ -9,6 +9,7 @@
|
||||
// See the Mulan PSL v2 for more details.
|
||||
|
||||
module tc_sram_1024x32 (
|
||||
// verilog_format: off -- preserve the technology memory interface columns
|
||||
input logic clk_i,
|
||||
input logic cs_i,
|
||||
input logic [ 9:0] addr_i,
|
||||
@@ -16,23 +17,24 @@ module tc_sram_1024x32 (
|
||||
input logic [ 3:0] mask_i,
|
||||
input logic wren_i,
|
||||
output logic [31:0] data_o
|
||||
// verilog_format: on
|
||||
);
|
||||
|
||||
`ifdef PDK_BEHAV
|
||||
logic [31:0] r_data;
|
||||
logic [31:0] mem [0:1023];
|
||||
logic [31:0] s_data_q;
|
||||
logic [31:0] s_storage_q[0:1023];
|
||||
|
||||
assign data_o = r_data;
|
||||
assign data_o = s_data_q;
|
||||
always_ff @(posedge clk_i) begin
|
||||
if (cs_i) begin
|
||||
if (!wren_i) begin
|
||||
r_data <= mem[addr_i];
|
||||
s_data_q <= s_storage_q[addr_i];
|
||||
end else begin
|
||||
if (mask_i[0]) mem[addr_i][7:0] <= data_i[7:0];
|
||||
if (mask_i[1]) mem[addr_i][15:8] <= data_i[15:8];
|
||||
if (mask_i[2]) mem[addr_i][23:16] <= data_i[23:16];
|
||||
if (mask_i[3]) mem[addr_i][31:24] <= data_i[31:24];
|
||||
r_data <= 32'bx;
|
||||
if (mask_i[0]) s_storage_q[addr_i][7:0] <= data_i[7:0];
|
||||
if (mask_i[1]) s_storage_q[addr_i][15:8] <= data_i[15:8];
|
||||
if (mask_i[2]) s_storage_q[addr_i][23:16] <= data_i[23:16];
|
||||
if (mask_i[3]) s_storage_q[addr_i][31:24] <= data_i[31:24];
|
||||
s_data_q <= 32'bx;
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -48,14 +50,81 @@ module tc_sram_1024x32 (
|
||||
.A_DIN (data_i),
|
||||
.A_DOUT (data_o),
|
||||
.A_DLY (1'b1),
|
||||
.A_BIST_CLK ('0),
|
||||
.A_BIST_EN ('0),
|
||||
.A_BIST_MEN ('0),
|
||||
.A_BIST_WEN ('0),
|
||||
.A_BIST_REN ('0),
|
||||
.A_BIST_ADDR('0),
|
||||
.A_BIST_DIN ('0),
|
||||
.A_BIST_BM ('0)
|
||||
.A_BIST_CLK (1'b0),
|
||||
.A_BIST_EN (1'b0),
|
||||
.A_BIST_MEN (1'b0),
|
||||
.A_BIST_WEN (1'b0),
|
||||
.A_BIST_REN (1'b0),
|
||||
.A_BIST_ADDR(10'b0),
|
||||
.A_BIST_DIN (32'b0),
|
||||
.A_BIST_BM (32'b0)
|
||||
);
|
||||
`endif
|
||||
`elsif PDK_GF180
|
||||
`ifdef HAVE_SRAM_MACRO
|
||||
logic s_read_depth_q;
|
||||
logic [1:0][3:0][7:0] s_macro_data_o;
|
||||
`ifndef SYNTHESIS
|
||||
wire s_vdd = 1'b1;
|
||||
wire s_vss = 1'b0;
|
||||
`endif
|
||||
|
||||
dffl #(
|
||||
.DATA_WIDTH(1)
|
||||
) u_read_depth_dffl (
|
||||
.clk_i(clk_i),
|
||||
.en_i (cs_i && !wren_i),
|
||||
.dat_i(addr_i[9]),
|
||||
.dat_o(s_read_depth_q)
|
||||
);
|
||||
|
||||
for (genvar depth = 0; depth < 2; depth++) begin : gen_depth
|
||||
for (genvar byte_index = 0; byte_index < 4; byte_index++) begin : gen_byte
|
||||
// verilog_format: off -- preserve conditional PDK power-pin connections
|
||||
gf180mcu_fd_ip_sram__sram512x8m8wm1 u_sram (
|
||||
.CLK (clk_i),
|
||||
.CEN (~(cs_i && (addr_i[9] == 1'(depth)))),
|
||||
.GWEN(~wren_i),
|
||||
.WEN (~{8{mask_i[byte_index]}}),
|
||||
.A (addr_i[8:0]),
|
||||
.D (data_i[byte_index*8+:8]),
|
||||
`ifndef SYNTHESIS
|
||||
.Q (s_macro_data_o[depth][byte_index]),
|
||||
.VDD (s_vdd),
|
||||
.VSS (s_vss)
|
||||
`else
|
||||
.Q (s_macro_data_o[depth][byte_index])
|
||||
`endif
|
||||
);
|
||||
// verilog_format: on
|
||||
end
|
||||
end
|
||||
|
||||
assign data_o = {
|
||||
s_macro_data_o[s_read_depth_q][3],
|
||||
s_macro_data_o[s_read_depth_q][2],
|
||||
s_macro_data_o[s_read_depth_q][1],
|
||||
s_macro_data_o[s_read_depth_q][0]
|
||||
};
|
||||
`endif
|
||||
`elsif PDK_SKY130
|
||||
`ifdef HAVE_SRAM_MACRO
|
||||
`ifdef USE_POWER_PINS
|
||||
wire s_vccd1 = 1'b1;
|
||||
wire s_vssd1 = 1'b0;
|
||||
`endif
|
||||
sky130_sram_4kbyte_1rw_32x1024_8 u_sram (
|
||||
`ifdef USE_POWER_PINS
|
||||
.vccd1 (s_vccd1),
|
||||
.vssd1 (s_vssd1),
|
||||
`endif
|
||||
.clk0 (clk_i),
|
||||
.csb0 (~cs_i),
|
||||
.web0 (~wren_i),
|
||||
.wmask0(mask_i),
|
||||
.addr0 ({1'b0, addr_i}),
|
||||
.din0 (data_i),
|
||||
.dout0 (data_o)
|
||||
);
|
||||
`endif
|
||||
`elsif PDK_S110
|
||||
|
||||
@@ -23,6 +23,7 @@ def parse_args() -> argparse.Namespace:
|
||||
parser.add_argument("--synth", required=True)
|
||||
parser.add_argument("--sta", required=True)
|
||||
parser.add_argument("--pdk", required=True)
|
||||
parser.add_argument("--have-sram-macro", choices=("YES", "NO"), default="NO")
|
||||
parser.add_argument("--formal", choices=("YES", "NO"), default="NO")
|
||||
parser.add_argument("--require-debug-tools", action="store_true")
|
||||
parser.add_argument("--lock", type=Path, default=DEFAULT_LOCK)
|
||||
@@ -81,6 +82,8 @@ def main() -> int:
|
||||
if args.pdk in pdk_names:
|
||||
source_names.append(pdk_names[args.pdk])
|
||||
paths = {name: root / lock["sources"][name]["destination"] for name in source_names}
|
||||
if args.pdk == "SKY130" and args.have_sram_macro == "YES":
|
||||
paths["sky130_openram_sram"] = root / ".cache/retrosoc/pdk/sky130/openram"
|
||||
tool_results = {
|
||||
tool: {"path": shutil.which(tool), "version": version(tool)}
|
||||
for tool in dict.fromkeys(tools)
|
||||
|
||||
@@ -53,10 +53,32 @@ module tc_sram_1024x32_tb;
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic expect_read_hold(input logic [9:0] idle_address, input logic [31:0] expected);
|
||||
begin
|
||||
@(negedge clk_i);
|
||||
cs_i = 1'b0;
|
||||
addr_i = idle_address;
|
||||
@(posedge clk_i);
|
||||
@(negedge clk_i);
|
||||
if (data_o !== expected) begin
|
||||
$fatal(1, "1024x32 SRAM held data=%08x expected=%08x", data_o, expected);
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
initial begin
|
||||
write_word(10'h000, 32'hCAFE_BABE, 4'hF);
|
||||
write_word(10'h155, 32'h1122_3344, 4'hF);
|
||||
write_word(10'h155, 32'hAABB_CCDD, 4'b0101);
|
||||
write_word(10'h1FF, 32'h0102_0304, 4'hF);
|
||||
write_word(10'h200, 32'h1122_3344, 4'hF);
|
||||
write_word(10'h3FF, 32'hA5A5_5A5A, 4'hF);
|
||||
read_word(10'h000, 32'hCAFE_BABE);
|
||||
read_word(10'h155, 32'h11BB_33DD);
|
||||
read_word(10'h1FF, 32'h0102_0304);
|
||||
expect_read_hold(10'h200, 32'h0102_0304);
|
||||
read_word(10'h200, 32'h1122_3344);
|
||||
read_word(10'h3FF, 32'hA5A5_5A5A);
|
||||
$display("1024x32 SRAM wrapper test passed");
|
||||
$finish;
|
||||
end
|
||||
|
||||
@@ -61,6 +61,7 @@ def test_onchip_ram_axi4_capacity_protocol_and_performance(
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/apb4_if.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/axi4_addr_gen.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/register.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/tech/ram.sv"),
|
||||
str(ROOT / "rtl/tech/tc_sram.sv"),
|
||||
str(ROOT / "rtl/mini/top/onchip_ram_reg.sv"),
|
||||
str(ROOT / "rtl/mini/top/onchip_ram.sv"),
|
||||
@@ -122,6 +123,7 @@ def test_absent_onchip_ram_reports_capability_and_decode_errors(tmp_path: Path)
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/apb4_if.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/axi4_addr_gen.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/register.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/tech/ram.sv"),
|
||||
str(ROOT / "rtl/tech/tc_sram.sv"),
|
||||
str(ROOT / "rtl/mini/top/onchip_ram_reg.sv"),
|
||||
str(ROOT / "rtl/mini/top/onchip_ram.sv"),
|
||||
@@ -235,6 +237,58 @@ def test_ics55_wrapper_preserves_active_low_controls_and_byte_masks(tmp_path: Pa
|
||||
assert "1024x32 SRAM wrapper test passed" in result.stdout
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("pdk", "model"),
|
||||
(
|
||||
("GF180", "gf180_sram_sim_cells.sv"),
|
||||
("SKY130", "sky130_sram_sim_cells.sv"),
|
||||
),
|
||||
)
|
||||
def test_open_pdk_sram_wrappers_preserve_depth_and_byte_masks(
|
||||
tmp_path: Path, pdk: str, model: str
|
||||
) -> None:
|
||||
verilator = shutil.which("verilator")
|
||||
if verilator is None:
|
||||
return
|
||||
|
||||
output = tmp_path / f"tc_sram_{pdk.lower()}"
|
||||
ccache_tmp = tmp_path / f"ccache-{pdk.lower()}"
|
||||
ccache_tmp.mkdir()
|
||||
subprocess.run(
|
||||
[
|
||||
verilator,
|
||||
"--binary",
|
||||
"--timing",
|
||||
"-Wno-fatal",
|
||||
"--top-module",
|
||||
"tc_sram_1024x32_tb",
|
||||
f"+define+PDK_{pdk}",
|
||||
"+define+HAVE_SRAM_MACRO",
|
||||
"+define+SV_ASSRT_DISABLE",
|
||||
"-I" + str(ROOT / "rtl/managed/clusterip/common/rtl"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/register.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/tech/ram.sv"),
|
||||
str(ROOT / "rtl/tech" / model),
|
||||
str(ROOT / "rtl/tech/tc_sram.sv"),
|
||||
str(ROOT / "tests/rtl/tc_sram_1024x32_tb.sv"),
|
||||
"-Mdir",
|
||||
str(tmp_path / f"obj-{pdk.lower()}"),
|
||||
"-o",
|
||||
str(output),
|
||||
],
|
||||
check=True,
|
||||
text=True,
|
||||
capture_output=True,
|
||||
env={
|
||||
**os.environ,
|
||||
"CCACHE_DIR": str(ccache_tmp),
|
||||
"CCACHE_TEMPDIR": str(ccache_tmp),
|
||||
},
|
||||
)
|
||||
result = subprocess.run([output], check=True, text=True, capture_output=True)
|
||||
assert "1024x32 SRAM wrapper test passed" in result.stdout
|
||||
|
||||
|
||||
def test_native_axi4_burst_reaches_peak_and_removes_bridge_overhead(tmp_path: Path) -> None:
|
||||
verilator = shutil.which("verilator")
|
||||
if verilator is None:
|
||||
@@ -280,6 +334,7 @@ def test_native_axi4_burst_reaches_peak_and_removes_bridge_overhead(tmp_path: Pa
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/register.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/xchecker.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/spill_register.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/tech/ram.sv"),
|
||||
str(ROOT / "rtl/tech/tc_sram.sv"),
|
||||
str(ROOT / "rtl/mini/top/axi42ram.sv"),
|
||||
str(ROOT / "rtl/mini/top/onchip_ram_reg.sv"),
|
||||
|
||||
@@ -1025,10 +1025,27 @@ def test_benchmark_profile_uses_functional_sram_and_reserved_data() -> None:
|
||||
assert "PDK_BEHAV HAVE_SVA" in makefile
|
||||
assert "PDK_BEHAV=YES is for functional simulation" in makefile
|
||||
assert re.search(r"^HAVE_SRAM_MACRO\s*:= YES$", profile, re.MULTILINE)
|
||||
assert re.search(r"^SRAM_SIZE_KIB\s*:= 128$", profile, re.MULTILINE)
|
||||
assert re.search(r"^PDK_BEHAV\s*:= YES$", profile, re.MULTILINE)
|
||||
assert "RS_BENCHMARK_SRAM_OFFSET UINT32_C(0x10000)" in benchmark
|
||||
|
||||
|
||||
def test_open_pdk_profiles_enable_32kib_macro_sram_and_ics55_stays_absent() -> None:
|
||||
for pdk in ("ihp130", "gf180", "sky130"):
|
||||
profile = (ROOT / f"configs/ci/{pdk}.mk").read_text(encoding="utf-8")
|
||||
assert re.search(r"^HAVE_SRAM_IF\s*:= YES$", profile, re.MULTILINE)
|
||||
assert re.search(r"^HAVE_SRAM_MACRO\s*:= YES$", profile, re.MULTILINE)
|
||||
assert re.search(r"^SRAM_SIZE_KIB\s*:= 32$", profile, re.MULTILINE)
|
||||
|
||||
ics55 = (ROOT / "configs/ci/ics55.mk").read_text(encoding="utf-8")
|
||||
assert re.search(r"^HAVE_SRAM_IF\s*:= NO$", ics55, re.MULTILINE)
|
||||
assert re.search(r"^HAVE_SRAM_MACRO\s*:= NO$", ics55, re.MULTILINE)
|
||||
|
||||
for name in ("ihp130-hazard3", "ihp130-hazard3-coremark"):
|
||||
benchmark = (ROOT / f"configs/benchmark/{name}.mk").read_text(encoding="utf-8")
|
||||
assert re.search(r"^SRAM_SIZE_KIB\s*:= 128$", benchmark, re.MULTILINE)
|
||||
|
||||
|
||||
def test_smoke_regression_uses_ihp130_behavioral_coverage_only() -> None:
|
||||
commands, profiles = select_regression("smoke", "IHP130")
|
||||
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
"""Tests for the locked SKY130 OpenRAM SRAM setup path."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import io
|
||||
import json
|
||||
import tarfile
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from physical.pdk.prepare_sky130_sram import (
|
||||
EXPECTED_CORNERS,
|
||||
EXPECTED_GEOMETRY,
|
||||
INPUT_CONFIG_SHA256,
|
||||
MACRO,
|
||||
OPENRAM_COMMIT,
|
||||
REQUIRED_FILES,
|
||||
SKY130_BUILDSPACE_REVISION,
|
||||
SKY130_CIEL_REVISION,
|
||||
prepare,
|
||||
)
|
||||
|
||||
|
||||
def make_archive(path: Path, *, corners: list[str] | None = None) -> str:
|
||||
payloads = {
|
||||
name: f"generated {name}\n".encode()
|
||||
for name in REQUIRED_FILES
|
||||
if name not in {"manifest.json", "SHA256SUMS"}
|
||||
}
|
||||
manifest = {
|
||||
"schema_version": 1,
|
||||
"macro": MACRO,
|
||||
"geometry": EXPECTED_GEOMETRY,
|
||||
"corners": EXPECTED_CORNERS if corners is None else corners,
|
||||
"openram_commit": OPENRAM_COMMIT,
|
||||
"input_config_sha256": INPUT_CONFIG_SHA256,
|
||||
"sky130_ciel_revision": SKY130_CIEL_REVISION,
|
||||
"sky130_buildspace_revision": SKY130_BUILDSPACE_REVISION,
|
||||
"analytical_characterization": True,
|
||||
"drc_lvs_checked": False,
|
||||
"files": {
|
||||
name: hashlib.sha256(content).hexdigest() for name, content in payloads.items()
|
||||
},
|
||||
}
|
||||
payloads["manifest.json"] = (json.dumps(manifest) + "\n").encode()
|
||||
payloads["SHA256SUMS"] = b"fixture checksums\n"
|
||||
with tarfile.open(path, "w:gz") as archive:
|
||||
for name, content in payloads.items():
|
||||
member = tarfile.TarInfo(name)
|
||||
member.size = len(content)
|
||||
archive.addfile(member, io.BytesIO(content))
|
||||
return hashlib.sha256(path.read_bytes()).hexdigest()
|
||||
|
||||
|
||||
def test_prepare_sky130_sram_is_verified_and_idempotent(tmp_path: Path) -> None:
|
||||
archive = tmp_path / "sram.tar.gz"
|
||||
digest = make_archive(archive)
|
||||
output = tmp_path / "openram"
|
||||
|
||||
prepare(archive, output, digest)
|
||||
first_mtime = (output / ".complete").stat().st_mtime_ns
|
||||
prepare(archive, output, digest)
|
||||
|
||||
assert (output / f"{MACRO}.v").is_file()
|
||||
assert (output / ".complete").read_text(encoding="utf-8").strip() == digest
|
||||
assert (output / ".complete").stat().st_mtime_ns == first_mtime
|
||||
|
||||
|
||||
def test_prepare_sky130_sram_rejects_wrong_corners(tmp_path: Path) -> None:
|
||||
archive = tmp_path / "sram.tar.gz"
|
||||
digest = make_archive(archive, corners=["TT_1p8V_25C"])
|
||||
|
||||
with pytest.raises(RuntimeError, match="corners"):
|
||||
prepare(archive, tmp_path / "openram", digest)
|
||||
@@ -93,6 +93,16 @@ def test_ihp130_core_sta_loads_usb2_packet_ram_liberties() -> None:
|
||||
assert "OPENSTA_SRAM_LIBS := $(IHP130_USB2_SRAM_LIBS)" in makefile
|
||||
|
||||
|
||||
def test_open_pdk_core_sta_uses_matching_sram_corners() -> None:
|
||||
makefile = PDK_TIMING_MAKEFILE.read_text(encoding="utf-8")
|
||||
opensta = OPENSTA_MAKEFILE.read_text(encoding="utf-8")
|
||||
|
||||
assert "gf180mcu_fd_ip_sram__sram512x8m8wm1__ss_125C_4v50.lib" in makefile
|
||||
assert "sky130_sram_4kbyte_1rw_32x1024_8_SS_1p4V_100C.lib" in makefile
|
||||
assert "HAVE_SRAM_MACRO=$(HAVE_SRAM_MACRO)" in opensta
|
||||
assert "SRAM_SIZE_KIB=$(SRAM_SIZE_KIB)" in opensta
|
||||
|
||||
|
||||
def test_core_sdc_rejects_pads_missing_from_the_pin_map(tmp_path: Path) -> None:
|
||||
document = json.loads(DOMAINS.read_text(encoding="utf-8"))
|
||||
document["domains"][3]["sta"]["source_port"] = "missing_pad"
|
||||
|
||||
Reference in new issue
Block a user